[ui] UI theme should match repertory blue #61
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good
This commit is contained in:
@@ -1,11 +1,16 @@
|
|||||||
// helpers.dart
|
// helpers.dart
|
||||||
|
|
||||||
|
import 'dart:ui';
|
||||||
|
|
||||||
import 'package:convert/convert.dart';
|
import 'package:convert/convert.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:provider/provider.dart';
|
||||||
import 'package:repertory/constants.dart' as constants;
|
import 'package:repertory/constants.dart' as constants;
|
||||||
import 'package:repertory/models/auth.dart';
|
import 'package:repertory/models/auth.dart';
|
||||||
|
import 'package:repertory/models/settings.dart';
|
||||||
|
import 'package:repertory/widgets/aurora_sweep.dart';
|
||||||
import 'package:sodium_libs/sodium_libs.dart' show SecureKey, StringX;
|
import 'package:sodium_libs/sodium_libs.dart' show SecureKey, StringX;
|
||||||
|
|
||||||
Future doShowDialog(BuildContext context, Widget child) => showDialog(
|
Future doShowDialog(BuildContext context, Widget child) => showDialog(
|
||||||
@@ -426,3 +431,56 @@ Future<String?> editMountLocation(
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Scaffold createCommonScaffold(Widget child, {Widget? floatingActionButton}) =>
|
||||||
|
Scaffold(
|
||||||
|
body: SafeArea(
|
||||||
|
child: Stack(
|
||||||
|
children: [
|
||||||
|
Container(
|
||||||
|
width: double.infinity,
|
||||||
|
height: double.infinity,
|
||||||
|
decoration: const BoxDecoration(
|
||||||
|
gradient: LinearGradient(
|
||||||
|
begin: Alignment.topLeft,
|
||||||
|
end: Alignment.bottomRight,
|
||||||
|
colors: constants.gradientColors,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Consumer<Settings>(
|
||||||
|
builder: (_, settings, _) =>
|
||||||
|
AuroraSweep(enabled: settings.enableAnimations),
|
||||||
|
),
|
||||||
|
Positioned.fill(
|
||||||
|
child: BackdropFilter(
|
||||||
|
filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6),
|
||||||
|
child: Container(color: Colors.black.withValues(alpha: 0.06)),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child,
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
floatingActionButton: floatingActionButton,
|
||||||
|
);
|
||||||
|
|
||||||
|
InputDecoration createCommonDecoration(
|
||||||
|
ColorScheme colorScheme,
|
||||||
|
String label,
|
||||||
|
IconData icon,
|
||||||
|
) => InputDecoration(
|
||||||
|
labelText: label,
|
||||||
|
prefixIcon: Icon(icon),
|
||||||
|
filled: true,
|
||||||
|
fillColor: colorScheme.primary.withValues(alpha: constants.primaryAlpha),
|
||||||
|
border: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(constants.borderRadiusSmall),
|
||||||
|
borderSide: BorderSide.none,
|
||||||
|
),
|
||||||
|
focusedBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(constants.borderRadiusSmall),
|
||||||
|
borderSide: BorderSide(color: colorScheme.primary, width: 2),
|
||||||
|
),
|
||||||
|
contentPadding: const EdgeInsets.all(constants.paddingSmall),
|
||||||
|
);
|
||||||
|
@@ -9,9 +9,7 @@ import 'package:repertory/helpers.dart';
|
|||||||
import 'package:repertory/models/auth.dart';
|
import 'package:repertory/models/auth.dart';
|
||||||
import 'package:repertory/models/mount.dart';
|
import 'package:repertory/models/mount.dart';
|
||||||
import 'package:repertory/models/mount_list.dart';
|
import 'package:repertory/models/mount_list.dart';
|
||||||
import 'package:repertory/models/settings.dart';
|
|
||||||
import 'package:repertory/types/mount_config.dart';
|
import 'package:repertory/types/mount_config.dart';
|
||||||
import 'package:repertory/widgets/aurora_sweep.dart';
|
|
||||||
import 'package:repertory/widgets/mount_settings.dart';
|
import 'package:repertory/widgets/mount_settings.dart';
|
||||||
|
|
||||||
class AddMountScreen extends StatefulWidget {
|
class AddMountScreen extends StatefulWidget {
|
||||||
@@ -46,367 +44,273 @@ class _AddMountScreenState extends State<AddMountScreen> {
|
|||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
final textTheme = Theme.of(context).textTheme;
|
final textTheme = Theme.of(context).textTheme;
|
||||||
|
|
||||||
Widget glassTile({required Widget child, EdgeInsets? padding}) {
|
return createCommonScaffold(
|
||||||
return Container(
|
Padding(
|
||||||
decoration: BoxDecoration(
|
padding: const EdgeInsets.all(constants.padding),
|
||||||
color: scheme.primary.withValues(alpha: constants.primaryAlpha),
|
child: Column(
|
||||||
borderRadius: BorderRadius.circular(constants.borderRadius),
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
border: Border.all(
|
|
||||||
color: scheme.outlineVariant.withValues(alpha: 0.08),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
gradient: const LinearGradient(
|
|
||||||
begin: Alignment.topCenter,
|
|
||||||
end: Alignment.bottomCenter,
|
|
||||||
colors: constants.gradientColors2,
|
|
||||||
),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.black.withValues(alpha: 0.22),
|
|
||||||
blurRadius: constants.borderRadius,
|
|
||||||
offset: Offset(0, constants.borderRadius),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(constants.borderRadius),
|
|
||||||
child: Padding(
|
|
||||||
padding: padding ?? const EdgeInsets.all(constants.padding),
|
|
||||||
child: child,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return Scaffold(
|
|
||||||
body: SafeArea(
|
|
||||||
child: Stack(
|
|
||||||
children: [
|
children: [
|
||||||
Container(
|
// Header
|
||||||
width: double.infinity,
|
Row(
|
||||||
height: double.infinity,
|
children: [
|
||||||
decoration: const BoxDecoration(
|
Material(
|
||||||
gradient: LinearGradient(
|
color: Colors.transparent,
|
||||||
begin: Alignment.topLeft,
|
child: InkWell(
|
||||||
end: Alignment.bottomRight,
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
colors: constants.gradientColors,
|
onTap: () => Navigator.of(context).pop(),
|
||||||
),
|
child: Ink(
|
||||||
),
|
width: 40,
|
||||||
),
|
height: 40,
|
||||||
Consumer<Settings>(
|
decoration: BoxDecoration(
|
||||||
builder: (_, settings, _) {
|
color: scheme.surface.withValues(alpha: 0.40),
|
||||||
return AuroraSweep(enabled: settings.enableAnimations);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Positioned.fill(
|
|
||||||
child: BackdropFilter(
|
|
||||||
filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6),
|
|
||||||
child: Container(color: Colors.black.withValues(alpha: 0.06)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Padding(
|
|
||||||
padding: const EdgeInsets.all(constants.padding),
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
children: [
|
|
||||||
Material(
|
|
||||||
color: Colors.transparent,
|
|
||||||
child: InkWell(
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
constants.borderRadius,
|
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
child: Ink(
|
|
||||||
width: 40,
|
|
||||||
height: 40,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: scheme.surface.withValues(alpha: 0.40),
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
constants.borderRadius,
|
|
||||||
),
|
|
||||||
border: Border.all(
|
|
||||||
color: scheme.outlineVariant.withValues(
|
|
||||||
alpha: 0.08,
|
|
||||||
),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.black.withValues(alpha: 0.22),
|
|
||||||
blurRadius: constants.borderRadius,
|
|
||||||
offset: Offset(0, constants.borderRadius),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: const Icon(Icons.arrow_back),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: constants.padding),
|
|
||||||
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
widget.title,
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: textTheme.headlineSmall?.copyWith(
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
letterSpacing: 0.2,
|
|
||||||
color: scheme.onSurface.withValues(alpha: 0.96),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: constants.padding),
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(
|
||||||
constants.borderRadius,
|
constants.borderRadius,
|
||||||
),
|
),
|
||||||
child: BackdropFilter(
|
border: Border.all(
|
||||||
filter: ImageFilter.blur(
|
color: scheme.outlineVariant.withValues(alpha: 0.08),
|
||||||
sigmaX: constants.borderRadius,
|
width: 1,
|
||||||
sigmaY: constants.borderRadius,
|
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
height: 40,
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 6),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: scheme.surface.withValues(alpha: 0.40),
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
constants.borderRadius,
|
|
||||||
),
|
|
||||||
border: Border.all(
|
|
||||||
color: scheme.outlineVariant.withValues(
|
|
||||||
alpha: 0.08,
|
|
||||||
),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Consumer<Auth>(
|
|
||||||
builder: (context, auth, _) {
|
|
||||||
return IconButton(
|
|
||||||
tooltip: 'Log out',
|
|
||||||
icon: const Icon(Icons.logout),
|
|
||||||
onPressed: () {
|
|
||||||
auth.logoff();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
boxShadow: [
|
||||||
],
|
BoxShadow(
|
||||||
),
|
color: Colors.black.withValues(alpha: 0.22),
|
||||||
const SizedBox(height: constants.padding),
|
blurRadius: constants.borderRadius,
|
||||||
glassTile(
|
offset: Offset(0, constants.borderRadius),
|
||||||
child: Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Provider Type',
|
|
||||||
style: textTheme.titleMedium?.copyWith(
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: constants.padding),
|
|
||||||
DropdownButton<String>(
|
|
||||||
value: _mountType.isEmpty ? null : _mountType,
|
|
||||||
autofocus: true,
|
|
||||||
underline: const SizedBox.shrink(),
|
|
||||||
onChanged: (mountType) {
|
|
||||||
_handleChange(
|
|
||||||
Provider.of<Auth>(context, listen: false),
|
|
||||||
mountType ?? '',
|
|
||||||
);
|
|
||||||
},
|
|
||||||
items: constants.providerTypeList
|
|
||||||
.map<DropdownMenuItem<String>>((item) {
|
|
||||||
return DropdownMenuItem<String>(
|
|
||||||
value: item,
|
|
||||||
child: Text(item),
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.toList(),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
if (_mountType.isNotEmpty && _mountType != 'Remote') ...[
|
|
||||||
const SizedBox(height: constants.padding),
|
|
||||||
glassTile(
|
|
||||||
child: Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
'Configuration Name',
|
|
||||||
style: textTheme.titleMedium?.copyWith(
|
|
||||||
fontWeight: FontWeight.w600,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: 8),
|
|
||||||
TextField(
|
|
||||||
autofocus: true,
|
|
||||||
controller: _mountNameController,
|
|
||||||
keyboardType: TextInputType.text,
|
|
||||||
inputFormatters: [
|
|
||||||
FilteringTextInputFormatter.deny(RegExp(r'\s')),
|
|
||||||
],
|
|
||||||
onChanged: (_) => _handleChange(
|
|
||||||
Provider.of<Auth>(context, listen: false),
|
|
||||||
_mountType,
|
|
||||||
),
|
|
||||||
decoration: InputDecoration(
|
|
||||||
hintText: 'Enter a unique name',
|
|
||||||
filled: true,
|
|
||||||
fillColor: scheme.surface.withValues(alpha: 0.30),
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
constants.borderRadius,
|
|
||||||
),
|
|
||||||
borderSide: BorderSide.none,
|
|
||||||
),
|
|
||||||
contentPadding: const EdgeInsets.symmetric(
|
|
||||||
horizontal: 12,
|
|
||||||
vertical: 12,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
child: const Icon(Icons.arrow_back),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
if (_mount != null) ...[
|
),
|
||||||
const SizedBox(height: constants.padding),
|
const SizedBox(width: constants.padding),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: glassTile(
|
child: Text(
|
||||||
padding: EdgeInsets.zero,
|
widget.title,
|
||||||
child: Padding(
|
maxLines: 1,
|
||||||
padding: const EdgeInsets.all(constants.padding),
|
overflow: TextOverflow.ellipsis,
|
||||||
child: MountSettingsWidget(
|
style: textTheme.headlineSmall?.copyWith(
|
||||||
isAdd: true,
|
fontWeight: FontWeight.w700,
|
||||||
mount: _mount!,
|
letterSpacing: 0.2,
|
||||||
settings: _settings[_mountType]!,
|
color: scheme.onSurface.withValues(alpha: 0.96),
|
||||||
showAdvanced: false,
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: constants.padding),
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
|
child: BackdropFilter(
|
||||||
|
filter: ImageFilter.blur(
|
||||||
|
sigmaX: constants.borderRadius,
|
||||||
|
sigmaY: constants.borderRadius,
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
height: 40,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 6),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: scheme.surface.withValues(alpha: 0.40),
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
constants.borderRadius,
|
||||||
|
),
|
||||||
|
border: Border.all(
|
||||||
|
color: scheme.outlineVariant.withValues(alpha: 0.08),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Consumer<Auth>(
|
||||||
|
builder: (context, auth, _) => IconButton(
|
||||||
|
tooltip: 'Log out',
|
||||||
|
icon: const Icon(Icons.logout),
|
||||||
|
onPressed: auth.logoff,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: constants.padding),
|
),
|
||||||
Row(
|
),
|
||||||
children: [
|
],
|
||||||
IntrinsicWidth(
|
),
|
||||||
child: ElevatedButton.icon(
|
const SizedBox(height: constants.padding),
|
||||||
label: const Text('Test'),
|
DropdownButtonFormField<String>(
|
||||||
icon: const Icon(Icons.check),
|
initialValue: _mountType.isEmpty ? null : _mountType,
|
||||||
style: ElevatedButton.styleFrom(
|
decoration: createCommonDecoration(
|
||||||
backgroundColor: scheme.primary.withValues(
|
scheme,
|
||||||
alpha: 0.18,
|
'Provider Type',
|
||||||
),
|
Icons.cloud_outlined,
|
||||||
foregroundColor: scheme.primary,
|
),
|
||||||
elevation: 0,
|
isExpanded: true,
|
||||||
shape: RoundedRectangleBorder(
|
items: constants.providerTypeList
|
||||||
borderRadius: BorderRadius.circular(
|
.map<DropdownMenuItem<String>>(
|
||||||
constants.borderRadius,
|
(item) => DropdownMenuItem<String>(
|
||||||
),
|
value: item,
|
||||||
side: BorderSide(
|
child: Text(item),
|
||||||
color: scheme.outlineVariant.withValues(
|
|
||||||
alpha: 0.15,
|
|
||||||
),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onPressed: _handleProviderTest,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: constants.padding),
|
|
||||||
IntrinsicWidth(
|
|
||||||
child: ElevatedButton.icon(
|
|
||||||
label: const Text('Add'),
|
|
||||||
icon: const Icon(Icons.add),
|
|
||||||
style: ElevatedButton.styleFrom(
|
|
||||||
backgroundColor: scheme.primary,
|
|
||||||
foregroundColor: scheme.onPrimary,
|
|
||||||
elevation: 8,
|
|
||||||
shadowColor: scheme.primary.withValues(
|
|
||||||
alpha: 0.45,
|
|
||||||
),
|
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
constants.borderRadius,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
onPressed: () async {
|
|
||||||
final mountList = Provider.of<MountList>(
|
|
||||||
context,
|
|
||||||
listen: false,
|
|
||||||
);
|
|
||||||
|
|
||||||
List<String> failed = [];
|
|
||||||
if (!validateSettings(
|
|
||||||
_settings[_mountType]!,
|
|
||||||
failed,
|
|
||||||
)) {
|
|
||||||
for (var key in failed) {
|
|
||||||
displayErrorMessage(
|
|
||||||
context,
|
|
||||||
"Setting '$key' is not valid",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mountList.hasConfigName(
|
|
||||||
_mountNameController.text,
|
|
||||||
)) {
|
|
||||||
return displayErrorMessage(
|
|
||||||
context,
|
|
||||||
"Configuration name '${_mountNameController.text}' already exists",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_mountType == "Sia" || _mountType == "S3") {
|
|
||||||
final bucket =
|
|
||||||
_settings[_mountType]!["${_mountType}Config"]["Bucket"]
|
|
||||||
as String;
|
|
||||||
if (mountList.hasBucketName(
|
|
||||||
_mountType,
|
|
||||||
bucket,
|
|
||||||
)) {
|
|
||||||
return displayErrorMessage(
|
|
||||||
context,
|
|
||||||
"Bucket '$bucket' already exists",
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
final success = await mountList.add(
|
|
||||||
_mountType,
|
|
||||||
_mountType == 'Remote'
|
|
||||||
? '${_settings[_mountType]!['RemoteConfig']['HostNameOrIp']}_${_settings[_mountType]!['RemoteConfig']['ApiPort']}'
|
|
||||||
: _mountNameController.text,
|
|
||||||
_settings[_mountType]!,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!success || !context.mounted) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Navigator.pop(context);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
)
|
||||||
],
|
.toList(),
|
||||||
|
onChanged: (mountType) => _handleChange(
|
||||||
|
Provider.of<Auth>(context, listen: false),
|
||||||
|
mountType ?? '',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
|
// Configuration name (only when not Remote)
|
||||||
|
if (_mountType.isNotEmpty && _mountType != 'Remote') ...[
|
||||||
|
const SizedBox(height: constants.padding),
|
||||||
|
TextField(
|
||||||
|
autofocus: true,
|
||||||
|
controller: _mountNameController,
|
||||||
|
keyboardType: TextInputType.text,
|
||||||
|
inputFormatters: [
|
||||||
|
FilteringTextInputFormatter.deny(RegExp(r'\s')),
|
||||||
|
],
|
||||||
|
onChanged: (_) => _handleChange(
|
||||||
|
Provider.of<Auth>(context, listen: false),
|
||||||
|
_mountType,
|
||||||
|
),
|
||||||
|
decoration: createCommonDecoration(
|
||||||
|
scheme,
|
||||||
|
'Configuration Name',
|
||||||
|
Icons.drive_file_rename_outline,
|
||||||
|
).copyWith(hintText: 'Enter a unique name'),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
|
||||||
|
// Settings + Actions
|
||||||
|
if (_mount != null) ...[
|
||||||
|
const SizedBox(height: constants.padding),
|
||||||
|
Expanded(
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: scheme.primary.withValues(
|
||||||
|
alpha: constants.primaryAlpha,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
|
border: Border.all(
|
||||||
|
color: scheme.outlineVariant.withValues(alpha: 0.06),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
gradient: const LinearGradient(
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
colors: constants.gradientColors2,
|
||||||
|
),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withValues(alpha: 0.22),
|
||||||
|
blurRadius: constants.borderRadius,
|
||||||
|
offset: Offset(0, constants.borderRadius),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(constants.padding),
|
||||||
|
child: MountSettingsWidget(
|
||||||
|
isAdd: true,
|
||||||
|
mount: _mount!,
|
||||||
|
settings: _settings[_mountType]!,
|
||||||
|
showAdvanced: false,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: constants.padding),
|
||||||
|
Row(
|
||||||
|
children: [
|
||||||
|
IntrinsicWidth(
|
||||||
|
child: ElevatedButton.icon(
|
||||||
|
label: const Text('Test'),
|
||||||
|
icon: const Icon(Icons.check),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: scheme.primary.withValues(alpha: 0.18),
|
||||||
|
foregroundColor: scheme.primary,
|
||||||
|
elevation: 0,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
constants.borderRadius,
|
||||||
|
),
|
||||||
|
side: BorderSide(
|
||||||
|
color: scheme.outlineVariant.withValues(
|
||||||
|
alpha: 0.15,
|
||||||
|
),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onPressed: _handleProviderTest,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: constants.padding),
|
||||||
|
IntrinsicWidth(
|
||||||
|
child: ElevatedButton.icon(
|
||||||
|
label: const Text('Add'),
|
||||||
|
icon: const Icon(Icons.add),
|
||||||
|
style: ElevatedButton.styleFrom(
|
||||||
|
backgroundColor: scheme.primary,
|
||||||
|
foregroundColor: scheme.onPrimary,
|
||||||
|
elevation: 8,
|
||||||
|
shadowColor: scheme.primary.withValues(alpha: 0.45),
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
constants.borderRadius,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
onPressed: () async {
|
||||||
|
final mountList = Provider.of<MountList>(
|
||||||
|
context,
|
||||||
|
listen: false,
|
||||||
|
);
|
||||||
|
|
||||||
|
List<String> failed = [];
|
||||||
|
if (!validateSettings(_settings[_mountType]!, failed)) {
|
||||||
|
for (var key in failed) {
|
||||||
|
displayErrorMessage(
|
||||||
|
context,
|
||||||
|
"Setting '$key' is not valid",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mountList.hasConfigName(
|
||||||
|
_mountNameController.text,
|
||||||
|
)) {
|
||||||
|
return displayErrorMessage(
|
||||||
|
context,
|
||||||
|
"Configuration name '${_mountNameController.text}' already exists",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_mountType == "Sia" || _mountType == "S3") {
|
||||||
|
final bucket =
|
||||||
|
_settings[_mountType]!["${_mountType}Config"]["Bucket"]
|
||||||
|
as String;
|
||||||
|
if (mountList.hasBucketName(_mountType, bucket)) {
|
||||||
|
return displayErrorMessage(
|
||||||
|
context,
|
||||||
|
"Bucket '$bucket' already exists",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
final success = await mountList.add(
|
||||||
|
_mountType,
|
||||||
|
_mountType == 'Remote'
|
||||||
|
? '${_settings[_mountType]!['RemoteConfig']['HostNameOrIp']}_${_settings[_mountType]!['RemoteConfig']['ApiPort']}'
|
||||||
|
: _mountNameController.text,
|
||||||
|
_settings[_mountType]!,
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!success || !context.mounted) return;
|
||||||
|
|
||||||
|
Navigator.pop(context);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -440,14 +344,10 @@ class _AddMountScreenState extends State<AddMountScreen> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _handleProviderTest() async {
|
Future<void> _handleProviderTest() async {
|
||||||
if (_mount == null) {
|
if (_mount == null) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
final success = await _mount!.test();
|
final success = await _mount!.test();
|
||||||
if (!mounted) {
|
if (!mounted) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
displayErrorMessage(
|
displayErrorMessage(
|
||||||
context,
|
context,
|
||||||
@@ -457,9 +357,7 @@ class _AddMountScreenState extends State<AddMountScreen> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void setState(VoidCallback fn) {
|
void setState(VoidCallback fn) {
|
||||||
if (!mounted) {
|
if (!mounted) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
super.setState(fn);
|
super.setState(fn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -4,6 +4,7 @@ import 'dart:ui';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:repertory/constants.dart' as constants;
|
import 'package:repertory/constants.dart' as constants;
|
||||||
|
import 'package:repertory/helpers.dart';
|
||||||
import 'package:repertory/models/auth.dart';
|
import 'package:repertory/models/auth.dart';
|
||||||
import 'package:repertory/models/settings.dart';
|
import 'package:repertory/models/settings.dart';
|
||||||
import 'package:repertory/widgets/aurora_sweep.dart';
|
import 'package:repertory/widgets/aurora_sweep.dart';
|
||||||
@@ -35,22 +36,6 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
InputDecoration decoration(String label, IconData icon) => InputDecoration(
|
|
||||||
labelText: label,
|
|
||||||
prefixIcon: Icon(icon),
|
|
||||||
filled: true,
|
|
||||||
fillColor: scheme.primary.withValues(alpha: constants.primaryAlpha),
|
|
||||||
border: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(constants.borderRadiusSmall),
|
|
||||||
borderSide: BorderSide.none,
|
|
||||||
),
|
|
||||||
focusedBorder: OutlineInputBorder(
|
|
||||||
borderRadius: BorderRadius.circular(constants.borderRadiusSmall),
|
|
||||||
borderSide: BorderSide(color: scheme.primary, width: 2),
|
|
||||||
),
|
|
||||||
contentPadding: const EdgeInsets.all(constants.paddingSmall),
|
|
||||||
);
|
|
||||||
|
|
||||||
Future<void> doLogin(Auth auth) async {
|
Future<void> doLogin(Auth auth) async {
|
||||||
if (!_enabled) {
|
if (!_enabled) {
|
||||||
return;
|
return;
|
||||||
@@ -99,9 +84,8 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
Consumer<Settings>(
|
Consumer<Settings>(
|
||||||
builder: (_, settings, _) {
|
builder: (_, settings, _) =>
|
||||||
return AuroraSweep(enabled: settings.enableAnimations);
|
AuroraSweep(enabled: settings.enableAnimations),
|
||||||
},
|
|
||||||
),
|
),
|
||||||
Positioned.fill(
|
Positioned.fill(
|
||||||
child: BackdropFilter(
|
child: BackdropFilter(
|
||||||
@@ -246,7 +230,8 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
autofocus: true,
|
autofocus: true,
|
||||||
controller: _userController,
|
controller: _userController,
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
decoration: decoration(
|
decoration: createCommonDecoration(
|
||||||
|
scheme,
|
||||||
'Username',
|
'Username',
|
||||||
Icons.person,
|
Icons.person,
|
||||||
),
|
),
|
||||||
@@ -267,7 +252,8 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
obscureText: _obscure,
|
obscureText: _obscure,
|
||||||
textInputAction: TextInputAction.go,
|
textInputAction: TextInputAction.go,
|
||||||
decoration:
|
decoration:
|
||||||
decoration(
|
createCommonDecoration(
|
||||||
|
scheme,
|
||||||
'Password',
|
'Password',
|
||||||
Icons.lock,
|
Icons.lock,
|
||||||
).copyWith(
|
).copyWith(
|
||||||
|
@@ -1,15 +1,13 @@
|
|||||||
// edit_mount_screen.dart
|
// edit_mount_screen.dart
|
||||||
|
|
||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
|
|
||||||
import 'dart:ui';
|
import 'dart:ui';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:repertory/constants.dart' as constants;
|
import 'package:repertory/constants.dart' as constants;
|
||||||
|
import 'package:repertory/helpers.dart';
|
||||||
import 'package:repertory/models/auth.dart';
|
import 'package:repertory/models/auth.dart';
|
||||||
import 'package:repertory/models/mount.dart';
|
import 'package:repertory/models/mount.dart';
|
||||||
import 'package:repertory/models/settings.dart';
|
|
||||||
import 'package:repertory/widgets/aurora_sweep.dart';
|
|
||||||
import 'package:repertory/widgets/mount_settings.dart';
|
import 'package:repertory/widgets/mount_settings.dart';
|
||||||
|
|
||||||
class EditMountScreen extends StatefulWidget {
|
class EditMountScreen extends StatefulWidget {
|
||||||
@@ -29,258 +27,200 @@ class _EditMountScreenState extends State<EditMountScreen> {
|
|||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
final textTheme = Theme.of(context).textTheme;
|
final textTheme = Theme.of(context).textTheme;
|
||||||
|
|
||||||
return Scaffold(
|
return createCommonScaffold(
|
||||||
body: SafeArea(
|
Column(
|
||||||
child: Stack(
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
const SizedBox(height: constants.padding),
|
||||||
width: double.infinity,
|
Padding(
|
||||||
height: double.infinity,
|
padding: const EdgeInsets.symmetric(horizontal: constants.padding),
|
||||||
decoration: const BoxDecoration(
|
child: Row(
|
||||||
gradient: LinearGradient(
|
|
||||||
begin: Alignment.topLeft,
|
|
||||||
end: Alignment.bottomRight,
|
|
||||||
colors: constants.gradientColors,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Consumer<Settings>(
|
|
||||||
builder: (_, settings, _) {
|
|
||||||
return AuroraSweep(enabled: settings.enableAnimations);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Positioned.fill(
|
|
||||||
child: BackdropFilter(
|
|
||||||
filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6),
|
|
||||||
child: Container(color: Colors.black.withValues(alpha: 0.06)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: constants.padding),
|
Material(
|
||||||
Padding(
|
color: Colors.transparent,
|
||||||
padding: const EdgeInsets.symmetric(
|
child: InkWell(
|
||||||
horizontal: constants.padding,
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
|
onTap: () => Navigator.of(context).pop(),
|
||||||
|
child: Ink(
|
||||||
|
width: 40,
|
||||||
|
height: 40,
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: scheme.surface.withValues(alpha: 0.40),
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
constants.borderRadius,
|
||||||
|
),
|
||||||
|
border: Border.all(
|
||||||
|
color: scheme.outlineVariant.withValues(alpha: 0.08),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withValues(alpha: 0.22),
|
||||||
|
blurRadius: constants.borderRadius,
|
||||||
|
offset: Offset(0, constants.borderRadius),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: const Icon(Icons.arrow_back),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: Row(
|
),
|
||||||
children: [
|
const SizedBox(width: constants.padding),
|
||||||
Material(
|
Expanded(
|
||||||
color: Colors.transparent,
|
child: Text(
|
||||||
child: InkWell(
|
widget.title,
|
||||||
borderRadius: BorderRadius.circular(
|
maxLines: 1,
|
||||||
constants.borderRadius,
|
overflow: TextOverflow.ellipsis,
|
||||||
),
|
style: textTheme.headlineSmall?.copyWith(
|
||||||
onTap: () {
|
fontWeight: FontWeight.w700,
|
||||||
Navigator.of(context).pop();
|
letterSpacing: 0.2,
|
||||||
},
|
color: scheme.onSurface.withValues(alpha: 0.96),
|
||||||
child: Ink(
|
),
|
||||||
width: 40,
|
),
|
||||||
height: 40,
|
),
|
||||||
decoration: BoxDecoration(
|
const SizedBox(width: constants.padding),
|
||||||
color: scheme.surface.withValues(alpha: 0.40),
|
ClipRRect(
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
constants.borderRadius,
|
child: BackdropFilter(
|
||||||
),
|
filter: ImageFilter.blur(
|
||||||
border: Border.all(
|
sigmaX: constants.borderRadius,
|
||||||
color: scheme.outlineVariant.withValues(
|
sigmaY: constants.borderRadius,
|
||||||
alpha: 0.08,
|
),
|
||||||
),
|
child: Container(
|
||||||
width: 1,
|
height: 40,
|
||||||
),
|
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||||
boxShadow: [
|
decoration: BoxDecoration(
|
||||||
BoxShadow(
|
color: scheme.surface.withValues(alpha: 0.40),
|
||||||
color: Colors.black.withValues(alpha: 0.22),
|
|
||||||
blurRadius: constants.borderRadius,
|
|
||||||
offset: Offset(0, constants.borderRadius),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: const Icon(Icons.arrow_back),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: constants.padding),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
widget.title,
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: textTheme.headlineSmall?.copyWith(
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
letterSpacing: 0.2,
|
|
||||||
color: scheme.onSurface.withValues(alpha: 0.96),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: constants.padding),
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(
|
||||||
constants.borderRadius,
|
constants.borderRadius,
|
||||||
),
|
),
|
||||||
child: BackdropFilter(
|
border: Border.all(
|
||||||
filter: ImageFilter.blur(
|
color: scheme.outlineVariant.withValues(alpha: 0.08),
|
||||||
sigmaX: constants.borderRadius,
|
width: 1,
|
||||||
sigmaY: constants.borderRadius,
|
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
height: 40,
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: scheme.surface.withValues(alpha: 0.40),
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
constants.borderRadius,
|
|
||||||
),
|
|
||||||
border: Border.all(
|
|
||||||
color: scheme.outlineVariant.withValues(
|
|
||||||
alpha: 0.08,
|
|
||||||
),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
mainAxisSize: MainAxisSize.min,
|
|
||||||
children: [
|
|
||||||
Text(
|
|
||||||
"Advanced",
|
|
||||||
style: textTheme.labelLarge?.copyWith(
|
|
||||||
color: scheme.onSurface.withValues(
|
|
||||||
alpha: 0.90,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 6),
|
|
||||||
IconButton(
|
|
||||||
tooltip: _showAdvanced
|
|
||||||
? 'Hide advanced'
|
|
||||||
: 'Show advanced',
|
|
||||||
icon: Icon(
|
|
||||||
_showAdvanced
|
|
||||||
? Icons.toggle_on
|
|
||||||
: Icons.toggle_off,
|
|
||||||
),
|
|
||||||
color: _showAdvanced
|
|
||||||
? scheme.primary
|
|
||||||
: scheme.onSurface.withValues(
|
|
||||||
alpha: 0.70,
|
|
||||||
),
|
|
||||||
onPressed: () {
|
|
||||||
setState(() {
|
|
||||||
_showAdvanced = !_showAdvanced;
|
|
||||||
});
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(width: constants.padding),
|
child: Row(
|
||||||
ClipRRect(
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
children: [
|
||||||
|
Text(
|
||||||
|
"Advanced",
|
||||||
|
style: textTheme.labelLarge?.copyWith(
|
||||||
|
color: scheme.onSurface.withValues(alpha: 0.90),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 6),
|
||||||
|
IconButton(
|
||||||
|
tooltip: _showAdvanced
|
||||||
|
? 'Hide advanced'
|
||||||
|
: 'Show advanced',
|
||||||
|
icon: Icon(
|
||||||
|
_showAdvanced
|
||||||
|
? Icons.toggle_on
|
||||||
|
: Icons.toggle_off,
|
||||||
|
),
|
||||||
|
color: _showAdvanced
|
||||||
|
? scheme.primary
|
||||||
|
: scheme.onSurface.withValues(alpha: 0.70),
|
||||||
|
onPressed: () =>
|
||||||
|
setState(() => _showAdvanced = !_showAdvanced),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: constants.padding),
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
|
child: BackdropFilter(
|
||||||
|
filter: ImageFilter.blur(
|
||||||
|
sigmaX: constants.borderRadius,
|
||||||
|
sigmaY: constants.borderRadius,
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
height: 40,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 6),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: scheme.surface.withValues(alpha: 0.40),
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(
|
||||||
constants.borderRadius,
|
constants.borderRadius,
|
||||||
),
|
),
|
||||||
child: BackdropFilter(
|
border: Border.all(
|
||||||
filter: ImageFilter.blur(
|
color: scheme.outlineVariant.withValues(alpha: 0.08),
|
||||||
sigmaX: constants.borderRadius,
|
width: 1,
|
||||||
sigmaY: constants.borderRadius,
|
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
height: 40,
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 6),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: scheme.surface.withValues(alpha: 0.40),
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
constants.borderRadius,
|
|
||||||
),
|
|
||||||
border: Border.all(
|
|
||||||
color: scheme.outlineVariant.withValues(
|
|
||||||
alpha: 0.08,
|
|
||||||
),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Consumer<Auth>(
|
|
||||||
builder: (context, auth, _) {
|
|
||||||
return IconButton(
|
|
||||||
tooltip: 'Log out',
|
|
||||||
icon: const Icon(Icons.logout),
|
|
||||||
onPressed: () {
|
|
||||||
auth.logoff();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
child: Consumer<Auth>(
|
||||||
|
builder: (context, auth, _) => IconButton(
|
||||||
|
tooltip: 'Log out',
|
||||||
|
icon: const Icon(Icons.logout),
|
||||||
|
onPressed: auth.logoff,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: constants.padding),
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: constants.padding,
|
||||||
|
),
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: scheme.primary.withValues(
|
||||||
|
alpha: constants.primaryAlpha,
|
||||||
|
),
|
||||||
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
|
border: Border.all(
|
||||||
|
color: scheme.outlineVariant.withValues(alpha: 0.06),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
gradient: const LinearGradient(
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
colors: constants.gradientColors2,
|
||||||
|
),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withValues(alpha: 0.22),
|
||||||
|
blurRadius: constants.borderRadius,
|
||||||
|
offset: Offset(0, constants.borderRadius),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
child: ClipRRect(
|
||||||
const SizedBox(height: constants.padding),
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
Expanded(
|
child: Padding(
|
||||||
child: Padding(
|
padding: const EdgeInsets.all(constants.padding),
|
||||||
padding: const EdgeInsets.symmetric(
|
child: MountSettingsWidget(
|
||||||
horizontal: constants.padding,
|
mount: widget.mount,
|
||||||
),
|
settings: jsonDecode(
|
||||||
child: Material(
|
jsonEncode(widget.mount.mountConfig.settings),
|
||||||
color: Colors.transparent,
|
|
||||||
child: Container(
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: scheme.surface.withValues(alpha: 0.40),
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
constants.borderRadius,
|
|
||||||
),
|
|
||||||
border: Border.all(
|
|
||||||
color: scheme.outlineVariant.withValues(
|
|
||||||
alpha: 0.06,
|
|
||||||
),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
gradient: const LinearGradient(
|
|
||||||
begin: Alignment.topCenter,
|
|
||||||
end: Alignment.bottomCenter,
|
|
||||||
colors: constants.gradientColors2,
|
|
||||||
),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.black.withValues(alpha: 0.22),
|
|
||||||
blurRadius: constants.borderRadius,
|
|
||||||
offset: Offset(0, constants.borderRadius),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
constants.borderRadius,
|
|
||||||
),
|
|
||||||
child: MountSettingsWidget(
|
|
||||||
mount: widget.mount,
|
|
||||||
settings: jsonDecode(
|
|
||||||
jsonEncode(widget.mount.mountConfig.settings),
|
|
||||||
),
|
|
||||||
showAdvanced: _showAdvanced,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
showAdvanced: _showAdvanced,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
),
|
||||||
const SizedBox(height: constants.padding),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
|
||||||
|
const SizedBox(height: constants.padding),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void setState(VoidCallback fn) {
|
void setState(VoidCallback fn) {
|
||||||
if (!mounted) {
|
if (!mounted) return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
super.setState(fn);
|
super.setState(fn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,8 +9,6 @@ import 'package:provider/provider.dart';
|
|||||||
import 'package:repertory/constants.dart' as constants;
|
import 'package:repertory/constants.dart' as constants;
|
||||||
import 'package:repertory/helpers.dart';
|
import 'package:repertory/helpers.dart';
|
||||||
import 'package:repertory/models/auth.dart';
|
import 'package:repertory/models/auth.dart';
|
||||||
import 'package:repertory/models/settings.dart';
|
|
||||||
import 'package:repertory/widgets/aurora_sweep.dart';
|
|
||||||
import 'package:repertory/widgets/ui_settings.dart';
|
import 'package:repertory/widgets/ui_settings.dart';
|
||||||
|
|
||||||
class EditSettingsScreen extends StatefulWidget {
|
class EditSettingsScreen extends StatefulWidget {
|
||||||
@@ -27,198 +25,154 @@ class _EditSettingsScreenState extends State<EditSettingsScreen> {
|
|||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
final textTheme = Theme.of(context).textTheme;
|
final textTheme = Theme.of(context).textTheme;
|
||||||
|
|
||||||
return Scaffold(
|
return createCommonScaffold(
|
||||||
body: SafeArea(
|
Column(
|
||||||
child: Stack(
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
const SizedBox(height: constants.padding),
|
||||||
width: double.infinity,
|
Padding(
|
||||||
height: double.infinity,
|
padding: const EdgeInsets.symmetric(horizontal: constants.padding),
|
||||||
decoration: const BoxDecoration(
|
child: Row(
|
||||||
gradient: LinearGradient(
|
|
||||||
begin: Alignment.topLeft,
|
|
||||||
end: Alignment.bottomRight,
|
|
||||||
colors: constants.gradientColors,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Consumer<Settings>(
|
|
||||||
builder: (_, settings, _) {
|
|
||||||
return AuroraSweep(enabled: settings.enableAnimations);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Positioned.fill(
|
|
||||||
child: BackdropFilter(
|
|
||||||
filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6),
|
|
||||||
child: Container(color: Colors.black.withValues(alpha: 0.06)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: constants.padding),
|
Material(
|
||||||
Padding(
|
color: Colors.transparent,
|
||||||
padding: const EdgeInsets.symmetric(
|
child: InkWell(
|
||||||
horizontal: constants.padding,
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
),
|
onTap: () {
|
||||||
child: Row(
|
Navigator.of(context).pop();
|
||||||
children: [
|
},
|
||||||
Material(
|
child: Ink(
|
||||||
color: Colors.transparent,
|
width: 40,
|
||||||
child: InkWell(
|
height: 40,
|
||||||
borderRadius: BorderRadius.circular(
|
decoration: BoxDecoration(
|
||||||
constants.borderRadius,
|
color: scheme.surface.withValues(alpha: 0.40),
|
||||||
),
|
|
||||||
onTap: () {
|
|
||||||
Navigator.of(context).pop();
|
|
||||||
},
|
|
||||||
child: Ink(
|
|
||||||
width: 40,
|
|
||||||
height: 40,
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: scheme.surface.withValues(alpha: 0.40),
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
constants.borderRadius,
|
|
||||||
),
|
|
||||||
border: Border.all(
|
|
||||||
color: scheme.outlineVariant.withValues(
|
|
||||||
alpha: 0.08,
|
|
||||||
),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.black.withValues(alpha: 0.22),
|
|
||||||
blurRadius: constants.borderRadius,
|
|
||||||
offset: Offset(0, constants.borderRadius),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: const Icon(Icons.arrow_back),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: constants.padding),
|
|
||||||
Expanded(
|
|
||||||
child: Text(
|
|
||||||
widget.title,
|
|
||||||
maxLines: 1,
|
|
||||||
overflow: TextOverflow.ellipsis,
|
|
||||||
style: textTheme.headlineSmall?.copyWith(
|
|
||||||
fontWeight: FontWeight.w700,
|
|
||||||
letterSpacing: 0.2,
|
|
||||||
color: scheme.onSurface.withValues(alpha: 0.96),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: constants.padding),
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(
|
||||||
constants.borderRadius,
|
constants.borderRadius,
|
||||||
),
|
),
|
||||||
child: BackdropFilter(
|
border: Border.all(
|
||||||
filter: ImageFilter.blur(
|
color: scheme.outlineVariant.withValues(alpha: 0.08),
|
||||||
sigmaX: constants.borderRadius,
|
width: 1,
|
||||||
sigmaY: constants.borderRadius,
|
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
height: 40,
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 6),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: scheme.surface.withValues(alpha: 0.40),
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
constants.borderRadius,
|
|
||||||
),
|
|
||||||
border: Border.all(
|
|
||||||
color: scheme.outlineVariant.withValues(
|
|
||||||
alpha: 0.08,
|
|
||||||
),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Consumer<Auth>(
|
|
||||||
builder: (context, auth, _) {
|
|
||||||
return IconButton(
|
|
||||||
tooltip: 'Log out',
|
|
||||||
icon: const Icon(Icons.logout),
|
|
||||||
onPressed: () {
|
|
||||||
auth.logoff();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withValues(alpha: 0.22),
|
||||||
|
blurRadius: constants.borderRadius,
|
||||||
|
offset: Offset(0, constants.borderRadius),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: const Icon(Icons.arrow_back),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: constants.padding),
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
widget.title,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: textTheme.headlineSmall?.copyWith(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
letterSpacing: 0.2,
|
||||||
|
color: scheme.onSurface.withValues(alpha: 0.96),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: constants.padding),
|
||||||
|
ClipRRect(
|
||||||
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
|
child: BackdropFilter(
|
||||||
|
filter: ImageFilter.blur(
|
||||||
|
sigmaX: constants.borderRadius,
|
||||||
|
sigmaY: constants.borderRadius,
|
||||||
|
),
|
||||||
|
child: Container(
|
||||||
|
height: 40,
|
||||||
|
padding: const EdgeInsets.symmetric(horizontal: 6),
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: scheme.surface.withValues(alpha: 0.40),
|
||||||
|
borderRadius: BorderRadius.circular(
|
||||||
|
constants.borderRadius,
|
||||||
|
),
|
||||||
|
border: Border.all(
|
||||||
|
color: scheme.outlineVariant.withValues(alpha: 0.08),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
child: Consumer<Auth>(
|
||||||
|
builder: (context, auth, _) {
|
||||||
|
return IconButton(
|
||||||
|
tooltip: 'Log out',
|
||||||
|
icon: const Icon(Icons.logout),
|
||||||
|
onPressed: () {
|
||||||
|
auth.logoff();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(height: constants.padding),
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: constants.padding,
|
||||||
|
),
|
||||||
|
child: Material(
|
||||||
|
color: Colors.transparent,
|
||||||
|
child: Container(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: scheme.surface.withValues(alpha: 0.40),
|
||||||
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
|
border: Border.all(
|
||||||
|
color: scheme.outlineVariant.withValues(alpha: 0.06),
|
||||||
|
width: 1,
|
||||||
|
),
|
||||||
|
gradient: const LinearGradient(
|
||||||
|
begin: Alignment.topCenter,
|
||||||
|
end: Alignment.bottomCenter,
|
||||||
|
colors: constants.gradientColors2,
|
||||||
|
),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withValues(alpha: 0.22),
|
||||||
|
blurRadius: constants.borderRadius,
|
||||||
|
offset: Offset(0, constants.borderRadius),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
child: ClipRRect(
|
||||||
const SizedBox(height: constants.padding),
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
Expanded(
|
child: FutureBuilder<Map<String, dynamic>>(
|
||||||
child: Padding(
|
future: _grabSettings(),
|
||||||
padding: const EdgeInsets.symmetric(
|
initialData: const <String, dynamic>{},
|
||||||
horizontal: constants.padding,
|
builder: (context, snapshot) {
|
||||||
),
|
if (!snapshot.hasData) {
|
||||||
child: Material(
|
return const Center(
|
||||||
color: Colors.transparent,
|
child: CircularProgressIndicator(),
|
||||||
child: Container(
|
);
|
||||||
decoration: BoxDecoration(
|
}
|
||||||
color: scheme.surface.withValues(alpha: 0.40),
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
constants.borderRadius,
|
|
||||||
),
|
|
||||||
border: Border.all(
|
|
||||||
color: scheme.outlineVariant.withValues(
|
|
||||||
alpha: 0.06,
|
|
||||||
),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
gradient: const LinearGradient(
|
|
||||||
begin: Alignment.topCenter,
|
|
||||||
end: Alignment.bottomCenter,
|
|
||||||
colors: constants.gradientColors2,
|
|
||||||
),
|
|
||||||
boxShadow: [
|
|
||||||
BoxShadow(
|
|
||||||
color: Colors.black.withValues(alpha: 0.22),
|
|
||||||
blurRadius: constants.borderRadius,
|
|
||||||
offset: Offset(0, constants.borderRadius),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
child: ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
constants.borderRadius,
|
|
||||||
),
|
|
||||||
child: FutureBuilder<Map<String, dynamic>>(
|
|
||||||
future: _grabSettings(),
|
|
||||||
initialData: const <String, dynamic>{},
|
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (!snapshot.hasData) {
|
|
||||||
return const Center(
|
|
||||||
child: CircularProgressIndicator(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
return UISettingsWidget(
|
return UISettingsWidget(
|
||||||
origSettings: jsonDecode(
|
origSettings: jsonDecode(
|
||||||
jsonEncode(snapshot.requireData),
|
jsonEncode(snapshot.requireData),
|
||||||
),
|
|
||||||
settings: snapshot.requireData,
|
|
||||||
showAdvanced: false,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
),
|
||||||
),
|
settings: snapshot.requireData,
|
||||||
),
|
showAdvanced: false,
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: constants.padding),
|
),
|
||||||
],
|
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
const SizedBox(height: constants.padding),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@@ -4,10 +4,10 @@ import 'dart:ui';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:repertory/constants.dart' as constants;
|
import 'package:repertory/constants.dart' as constants;
|
||||||
|
import 'package:repertory/helpers.dart';
|
||||||
import 'package:repertory/models/auth.dart';
|
import 'package:repertory/models/auth.dart';
|
||||||
import 'package:repertory/models/settings.dart';
|
import 'package:repertory/models/settings.dart';
|
||||||
import 'package:repertory/widgets/mount_list_widget.dart';
|
import 'package:repertory/widgets/mount_list_widget.dart';
|
||||||
import 'package:repertory/widgets/aurora_sweep.dart';
|
|
||||||
|
|
||||||
class HomeScreen extends StatefulWidget {
|
class HomeScreen extends StatefulWidget {
|
||||||
final String title;
|
final String title;
|
||||||
@@ -23,156 +23,119 @@ class _HomeScreeState extends State<HomeScreen> {
|
|||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
final textTheme = Theme.of(context).textTheme;
|
final textTheme = Theme.of(context).textTheme;
|
||||||
|
|
||||||
return Scaffold(
|
return createCommonScaffold(
|
||||||
body: SafeArea(
|
Column(
|
||||||
child: Stack(
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
Container(
|
const SizedBox(height: constants.padding),
|
||||||
width: double.infinity,
|
Padding(
|
||||||
height: double.infinity,
|
padding: const EdgeInsets.symmetric(horizontal: constants.padding),
|
||||||
decoration: const BoxDecoration(
|
child: Row(
|
||||||
gradient: LinearGradient(
|
|
||||||
begin: Alignment.topLeft,
|
|
||||||
end: Alignment.bottomRight,
|
|
||||||
colors: constants.gradientColors,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Consumer<Settings>(
|
|
||||||
builder: (_, settings, _) {
|
|
||||||
return AuroraSweep(enabled: settings.enableAnimations);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Positioned.fill(
|
|
||||||
child: BackdropFilter(
|
|
||||||
filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6),
|
|
||||||
child: Container(color: Colors.black.withValues(alpha: 0.06)),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Column(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
|
||||||
children: [
|
children: [
|
||||||
const SizedBox(height: constants.padding),
|
SizedBox(
|
||||||
Padding(
|
width: 40,
|
||||||
padding: const EdgeInsets.symmetric(
|
height: 40,
|
||||||
horizontal: constants.padding,
|
child: Image.asset(
|
||||||
|
'assets/images/repertory.png',
|
||||||
|
fit: BoxFit.contain,
|
||||||
|
errorBuilder: (_, _, _) {
|
||||||
|
return Icon(
|
||||||
|
Icons.folder,
|
||||||
|
color: scheme.primary,
|
||||||
|
size: 32,
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
child: Row(
|
),
|
||||||
children: [
|
const SizedBox(width: constants.padding),
|
||||||
SizedBox(
|
Expanded(
|
||||||
width: 48,
|
child: Text(
|
||||||
height: 48,
|
widget.title,
|
||||||
child: Image.asset(
|
maxLines: 1,
|
||||||
'assets/images/repertory.png',
|
overflow: TextOverflow.ellipsis,
|
||||||
fit: BoxFit.contain,
|
style: textTheme.headlineSmall?.copyWith(
|
||||||
errorBuilder: (_, _, _) {
|
fontWeight: FontWeight.w700,
|
||||||
return Icon(
|
letterSpacing: 0.2,
|
||||||
Icons.folder,
|
color: scheme.onSurface.withValues(alpha: 0.96),
|
||||||
color: scheme.primary,
|
),
|
||||||
size: 40,
|
),
|
||||||
);
|
),
|
||||||
},
|
const SizedBox(width: constants.padding),
|
||||||
),
|
ClipRRect(
|
||||||
),
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
const SizedBox(width: constants.padding),
|
child: BackdropFilter(
|
||||||
Expanded(
|
filter: ImageFilter.blur(
|
||||||
child: Text(
|
sigmaX: constants.borderRadius,
|
||||||
widget.title,
|
sigmaY: constants.borderRadius,
|
||||||
maxLines: 1,
|
),
|
||||||
overflow: TextOverflow.ellipsis,
|
child: Container(
|
||||||
style: textTheme.headlineSmall?.copyWith(
|
height: 40,
|
||||||
fontWeight: FontWeight.w700,
|
padding: const EdgeInsets.symmetric(horizontal: 6),
|
||||||
letterSpacing: 0.2,
|
decoration: BoxDecoration(
|
||||||
color: scheme.onSurface.withValues(alpha: 0.96),
|
color: scheme.surface.withValues(alpha: 0.40),
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: constants.padding),
|
|
||||||
ClipRRect(
|
|
||||||
borderRadius: BorderRadius.circular(
|
borderRadius: BorderRadius.circular(
|
||||||
constants.borderRadius,
|
constants.borderRadius,
|
||||||
),
|
),
|
||||||
child: BackdropFilter(
|
border: Border.all(
|
||||||
filter: ImageFilter.blur(
|
color: scheme.outlineVariant.withValues(alpha: 0.08),
|
||||||
sigmaX: constants.borderRadius,
|
width: 1,
|
||||||
sigmaY: constants.borderRadius,
|
|
||||||
),
|
|
||||||
child: Container(
|
|
||||||
height: 40,
|
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 6),
|
|
||||||
decoration: BoxDecoration(
|
|
||||||
color: scheme.surface.withValues(alpha: 0.40),
|
|
||||||
borderRadius: BorderRadius.circular(
|
|
||||||
constants.borderRadius,
|
|
||||||
),
|
|
||||||
border: Border.all(
|
|
||||||
color: scheme.outlineVariant.withValues(
|
|
||||||
alpha: 0.08,
|
|
||||||
),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Row(
|
|
||||||
children: [
|
|
||||||
const Text("Auto-start"),
|
|
||||||
Consumer<Settings>(
|
|
||||||
builder: (context, settings, _) {
|
|
||||||
return IconButton(
|
|
||||||
icon: Icon(
|
|
||||||
settings.autoStart
|
|
||||||
? Icons.toggle_on
|
|
||||||
: Icons.toggle_off,
|
|
||||||
),
|
|
||||||
color: settings.autoStart
|
|
||||||
? scheme.primary
|
|
||||||
: scheme.onSurface.withValues(
|
|
||||||
alpha: 0.70,
|
|
||||||
),
|
|
||||||
onPressed: () => settings.setAutoStart(
|
|
||||||
!settings.autoStart,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
IconButton(
|
|
||||||
tooltip: 'Settings',
|
|
||||||
icon: const Icon(Icons.settings),
|
|
||||||
onPressed: () {
|
|
||||||
Navigator.pushNamed(context, '/settings');
|
|
||||||
},
|
|
||||||
),
|
|
||||||
Consumer<Auth>(
|
|
||||||
builder: (context, auth, _) {
|
|
||||||
return IconButton(
|
|
||||||
tooltip: 'Log out',
|
|
||||||
icon: const Icon(Icons.logout),
|
|
||||||
onPressed: () {
|
|
||||||
auth.logoff();
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
child: Row(
|
||||||
),
|
children: [
|
||||||
),
|
const Text("Auto-start"),
|
||||||
const SizedBox(height: constants.padding),
|
Consumer<Settings>(
|
||||||
Expanded(
|
builder: (context, settings, _) {
|
||||||
child: Padding(
|
return IconButton(
|
||||||
padding: const EdgeInsets.symmetric(
|
icon: Icon(
|
||||||
horizontal: constants.padding,
|
settings.autoStart
|
||||||
|
? Icons.toggle_on
|
||||||
|
: Icons.toggle_off,
|
||||||
|
),
|
||||||
|
color: settings.autoStart
|
||||||
|
? scheme.primary
|
||||||
|
: scheme.onSurface.withValues(alpha: 0.70),
|
||||||
|
onPressed: () =>
|
||||||
|
settings.setAutoStart(!settings.autoStart),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
IconButton(
|
||||||
|
tooltip: 'Settings',
|
||||||
|
icon: const Icon(Icons.settings),
|
||||||
|
onPressed: () {
|
||||||
|
Navigator.pushNamed(context, '/settings');
|
||||||
|
},
|
||||||
|
),
|
||||||
|
Consumer<Auth>(
|
||||||
|
builder: (context, auth, _) {
|
||||||
|
return IconButton(
|
||||||
|
tooltip: 'Log out',
|
||||||
|
icon: const Icon(Icons.logout),
|
||||||
|
onPressed: () {
|
||||||
|
auth.logoff();
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
child: const MountListWidget(),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
),
|
const SizedBox(height: constants.padding),
|
||||||
|
Expanded(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: constants.padding,
|
||||||
|
),
|
||||||
|
child: const MountListWidget(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
),
|
),
|
||||||
floatingActionButton: Padding(
|
floatingActionButton: Padding(
|
||||||
padding: const EdgeInsets.all(constants.padding),
|
padding: const EdgeInsets.all(constants.padding),
|
||||||
|
@@ -39,10 +39,11 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
// Theme SettingsList to your glass aesthetic (consistent with UISettingsWidget)
|
|
||||||
final theme = SettingsThemeData(
|
final theme = SettingsThemeData(
|
||||||
settingsListBackground: Colors.transparent,
|
settingsListBackground: Colors.transparent,
|
||||||
settingsSectionBackground: scheme.surface.withValues(alpha: 0.30),
|
settingsSectionBackground: scheme.primary.withValues(
|
||||||
|
alpha: constants.primaryAlpha,
|
||||||
|
),
|
||||||
titleTextColor: scheme.onSurface.withValues(alpha: 0.96),
|
titleTextColor: scheme.onSurface.withValues(alpha: 0.96),
|
||||||
trailingTextColor: scheme.onSurface.withValues(alpha: 0.80),
|
trailingTextColor: scheme.onSurface.withValues(alpha: 0.80),
|
||||||
tileDescriptionTextColor: scheme.onSurface.withValues(alpha: 0.68),
|
tileDescriptionTextColor: scheme.onSurface.withValues(alpha: 0.68),
|
||||||
@@ -394,6 +395,10 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const sectionMargin = EdgeInsetsDirectional.symmetric(
|
||||||
|
vertical: constants.padding / 2,
|
||||||
|
);
|
||||||
|
|
||||||
return SettingsList(
|
return SettingsList(
|
||||||
shrinkWrap: false,
|
shrinkWrap: false,
|
||||||
platform: DevicePlatform.device,
|
platform: DevicePlatform.device,
|
||||||
@@ -402,38 +407,48 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
|
|||||||
sections: [
|
sections: [
|
||||||
if (encryptConfigSettings.isNotEmpty)
|
if (encryptConfigSettings.isNotEmpty)
|
||||||
SettingsSection(
|
SettingsSection(
|
||||||
|
margin: sectionMargin,
|
||||||
title: const Text('Encrypt Config'),
|
title: const Text('Encrypt Config'),
|
||||||
tiles: encryptConfigSettings,
|
tiles: encryptConfigSettings,
|
||||||
),
|
),
|
||||||
if (hostConfigSettings.isNotEmpty)
|
if (hostConfigSettings.isNotEmpty)
|
||||||
SettingsSection(
|
SettingsSection(
|
||||||
|
margin: sectionMargin,
|
||||||
title: const Text('Host Config'),
|
title: const Text('Host Config'),
|
||||||
tiles: hostConfigSettings,
|
tiles: hostConfigSettings,
|
||||||
),
|
),
|
||||||
if (remoteConfigSettings.isNotEmpty)
|
if (remoteConfigSettings.isNotEmpty)
|
||||||
SettingsSection(
|
SettingsSection(
|
||||||
|
margin: sectionMargin,
|
||||||
title: const Text('Remote Config'),
|
title: const Text('Remote Config'),
|
||||||
tiles: remoteConfigSettings,
|
tiles: remoteConfigSettings,
|
||||||
),
|
),
|
||||||
if (s3ConfigSettings.isNotEmpty)
|
if (s3ConfigSettings.isNotEmpty)
|
||||||
SettingsSection(
|
SettingsSection(
|
||||||
|
margin: sectionMargin,
|
||||||
title: const Text('S3 Config'),
|
title: const Text('S3 Config'),
|
||||||
tiles: s3ConfigSettings,
|
tiles: s3ConfigSettings,
|
||||||
),
|
),
|
||||||
if (siaConfigSettings.isNotEmpty)
|
if (siaConfigSettings.isNotEmpty)
|
||||||
SettingsSection(
|
SettingsSection(
|
||||||
|
margin: sectionMargin,
|
||||||
title: const Text('Sia Config'),
|
title: const Text('Sia Config'),
|
||||||
tiles: siaConfigSettings,
|
tiles: siaConfigSettings,
|
||||||
),
|
),
|
||||||
if (remoteMountSettings.isNotEmpty)
|
if (remoteMountSettings.isNotEmpty)
|
||||||
SettingsSection(
|
SettingsSection(
|
||||||
|
margin: sectionMargin,
|
||||||
title: const Text('Remote Mount'),
|
title: const Text('Remote Mount'),
|
||||||
tiles: (widget.settings['RemoteMount']['Enable'] as bool)
|
tiles: (widget.settings['RemoteMount']['Enable'] as bool)
|
||||||
? remoteMountSettings
|
? remoteMountSettings
|
||||||
: [remoteMountSettings[0]],
|
: [remoteMountSettings[0]],
|
||||||
),
|
),
|
||||||
if (commonSettings.isNotEmpty)
|
if (commonSettings.isNotEmpty)
|
||||||
SettingsSection(title: const Text('Settings'), tiles: commonSettings),
|
SettingsSection(
|
||||||
|
margin: sectionMargin,
|
||||||
|
title: const Text('Settings'),
|
||||||
|
tiles: commonSettings,
|
||||||
|
),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1017,24 +1032,18 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
|
|||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mount.setValue(key, value);
|
mount.setValue(key, value);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void setState(VoidCallback fn) {
|
void setState(VoidCallback fn) {
|
||||||
if (!mounted) {
|
if (!mounted) return;
|
||||||
return;
|
if (widget.onChanged != null) widget.onChanged!();
|
||||||
}
|
|
||||||
if (widget.onChanged != null) {
|
|
||||||
widget.onChanged!();
|
|
||||||
}
|
|
||||||
super.setState(fn);
|
super.setState(fn);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -272,7 +272,6 @@ class _MountWidgetState extends State<MountWidget> {
|
|||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ignore: use_build_context_synchronously
|
|
||||||
return editMountLocation(context, await mount.getAvailableLocations());
|
return editMountLocation(context, await mount.getAvailableLocations());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -39,18 +39,17 @@ class _UISettingsWidgetState extends State<UISettingsWidget> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
// Theme the SettingsList to align with your glass look
|
|
||||||
final theme = SettingsThemeData(
|
final theme = SettingsThemeData(
|
||||||
settingsListBackground: Colors.transparent,
|
settingsListBackground: Colors.transparent,
|
||||||
tileDescriptionTextColor: scheme.onSurface.withValues(alpha: 0.68),
|
settingsSectionBackground: scheme.primary.withValues(
|
||||||
settingsSectionBackground: scheme.surface.withValues(
|
alpha: constants.primaryAlpha,
|
||||||
alpha: 0.30,
|
),
|
||||||
), // slight glass base
|
|
||||||
tileHighlightColor: scheme.primary.withValues(alpha: 0.08),
|
|
||||||
titleTextColor: scheme.onSurface.withValues(alpha: 0.96),
|
titleTextColor: scheme.onSurface.withValues(alpha: 0.96),
|
||||||
trailingTextColor: scheme.onSurface.withValues(alpha: 0.80),
|
trailingTextColor: scheme.onSurface.withValues(alpha: 0.80),
|
||||||
|
tileDescriptionTextColor: scheme.onSurface.withValues(alpha: 0.68),
|
||||||
leadingIconsColor: scheme.onSurface.withValues(alpha: 0.90),
|
leadingIconsColor: scheme.onSurface.withValues(alpha: 0.90),
|
||||||
dividerColor: scheme.outlineVariant.withValues(alpha: 0.10),
|
dividerColor: scheme.outlineVariant.withValues(alpha: 0.10),
|
||||||
|
tileHighlightColor: scheme.primary.withValues(alpha: 0.08),
|
||||||
);
|
);
|
||||||
|
|
||||||
List<SettingsTile> commonSettings = [];
|
List<SettingsTile> commonSettings = [];
|
||||||
|
Reference in New Issue
Block a user