[ui] UI theme should match repertory blue #61
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good

This commit is contained in:
2025-09-04 10:59:36 -05:00
parent 58451858fd
commit d1183c00af
9 changed files with 750 additions and 944 deletions

View File

@@ -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),
);

View File

@@ -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);
} }
} }

View File

@@ -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(

View File

@@ -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);
} }
} }

View File

@@ -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),
],
), ),
); );
} }

View File

@@ -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),

View File

@@ -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);
} }
} }

View File

@@ -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());
} }

View File

@@ -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 = [];