[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
import 'dart:ui';
import 'package:convert/convert.dart';
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:repertory/constants.dart' as constants;
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;
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/mount.dart';
import 'package:repertory/models/mount_list.dart';
import 'package:repertory/models/settings.dart';
import 'package:repertory/types/mount_config.dart';
import 'package:repertory/widgets/aurora_sweep.dart';
import 'package:repertory/widgets/mount_settings.dart';
class AddMountScreen extends StatefulWidget {
@@ -46,367 +44,273 @@ class _AddMountScreenState extends State<AddMountScreen> {
final scheme = Theme.of(context).colorScheme;
final textTheme = Theme.of(context).textTheme;
Widget glassTile({required Widget child, EdgeInsets? padding}) {
return Container(
decoration: BoxDecoration(
color: scheme.primary.withValues(alpha: constants.primaryAlpha),
borderRadius: BorderRadius.circular(constants.borderRadius),
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(
return createCommonScaffold(
Padding(
padding: const EdgeInsets.all(constants.padding),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
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, _) {
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(
// Header
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,
),
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();
},
);
},
),
),
border: Border.all(
color: scheme.outlineVariant.withValues(alpha: 0.08),
width: 1,
),
),
],
),
const SizedBox(height: constants.padding),
glassTile(
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,
),
),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.22),
blurRadius: constants.borderRadius,
offset: Offset(0, constants.borderRadius),
),
],
),
child: const Icon(Icons.arrow_back),
),
],
if (_mount != null) ...[
const SizedBox(height: constants.padding),
Expanded(
child: glassTile(
padding: EdgeInsets.zero,
child: Padding(
padding: const EdgeInsets.all(constants.padding),
child: MountSettingsWidget(
isAdd: true,
mount: _mount!,
settings: _settings[_mountType]!,
showAdvanced: false,
),
),
),
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, _) => IconButton(
tooltip: 'Log out',
icon: const Icon(Icons.logout),
onPressed: auth.logoff,
),
),
),
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);
},
),
),
],
),
),
],
),
const SizedBox(height: constants.padding),
DropdownButtonFormField<String>(
initialValue: _mountType.isEmpty ? null : _mountType,
decoration: createCommonDecoration(
scheme,
'Provider Type',
Icons.cloud_outlined,
),
isExpanded: true,
items: constants.providerTypeList
.map<DropdownMenuItem<String>>(
(item) => DropdownMenuItem<String>(
value: item,
child: Text(item),
),
],
],
)
.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 {
if (_mount == null) {
return;
}
if (_mount == null) return;
final success = await _mount!.test();
if (!mounted) {
return;
}
if (!mounted) return;
displayErrorMessage(
context,
@@ -457,9 +357,7 @@ class _AddMountScreenState extends State<AddMountScreen> {
@override
void setState(VoidCallback fn) {
if (!mounted) {
return;
}
if (!mounted) return;
super.setState(fn);
}
}

View File

@@ -4,6 +4,7 @@ import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:repertory/constants.dart' as constants;
import 'package:repertory/helpers.dart';
import 'package:repertory/models/auth.dart';
import 'package:repertory/models/settings.dart';
import 'package:repertory/widgets/aurora_sweep.dart';
@@ -35,22 +36,6 @@ class _AuthScreenState extends State<AuthScreen> {
Widget build(BuildContext context) {
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 {
if (!_enabled) {
return;
@@ -99,9 +84,8 @@ class _AuthScreenState extends State<AuthScreen> {
),
),
Consumer<Settings>(
builder: (_, settings, _) {
return AuroraSweep(enabled: settings.enableAnimations);
},
builder: (_, settings, _) =>
AuroraSweep(enabled: settings.enableAnimations),
),
Positioned.fill(
child: BackdropFilter(
@@ -246,7 +230,8 @@ class _AuthScreenState extends State<AuthScreen> {
autofocus: true,
controller: _userController,
textInputAction: TextInputAction.next,
decoration: decoration(
decoration: createCommonDecoration(
scheme,
'Username',
Icons.person,
),
@@ -267,7 +252,8 @@ class _AuthScreenState extends State<AuthScreen> {
obscureText: _obscure,
textInputAction: TextInputAction.go,
decoration:
decoration(
createCommonDecoration(
scheme,
'Password',
Icons.lock,
).copyWith(

View File

@@ -1,15 +1,13 @@
// edit_mount_screen.dart
import 'dart:convert';
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:repertory/constants.dart' as constants;
import 'package:repertory/helpers.dart';
import 'package:repertory/models/auth.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';
class EditMountScreen extends StatefulWidget {
@@ -29,258 +27,200 @@ class _EditMountScreenState extends State<EditMountScreen> {
final scheme = Theme.of(context).colorScheme;
final textTheme = Theme.of(context).textTheme;
return 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, _) {
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,
return createCommonScaffold(
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(height: constants.padding),
Padding(
padding: const EdgeInsets.symmetric(horizontal: constants.padding),
child: Row(
children: [
const SizedBox(height: constants.padding),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: constants.padding,
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),
),
),
child: 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(
),
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: 10),
decoration: BoxDecoration(
color: scheme.surface.withValues(alpha: 0.40),
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: 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;
});
},
),
],
),
),
border: Border.all(
color: scheme.outlineVariant.withValues(alpha: 0.08),
width: 1,
),
),
const SizedBox(width: constants.padding),
ClipRRect(
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),
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,
),
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();
},
);
},
),
),
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),
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),
),
],
),
),
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(
borderRadius: BorderRadius.circular(
constants.borderRadius,
),
child: MountSettingsWidget(
mount: widget.mount,
settings: jsonDecode(
jsonEncode(widget.mount.mountConfig.settings),
),
showAdvanced: _showAdvanced,
),
child: ClipRRect(
borderRadius: BorderRadius.circular(constants.borderRadius),
child: Padding(
padding: const EdgeInsets.all(constants.padding),
child: MountSettingsWidget(
mount: widget.mount,
settings: jsonDecode(
jsonEncode(widget.mount.mountConfig.settings),
),
showAdvanced: _showAdvanced,
),
),
),
),
const SizedBox(height: constants.padding),
],
),
),
],
),
),
const SizedBox(height: constants.padding),
],
),
);
}
@override
void setState(VoidCallback fn) {
if (!mounted) {
return;
}
if (!mounted) return;
super.setState(fn);
}
}

View File

@@ -9,8 +9,6 @@ import 'package:provider/provider.dart';
import 'package:repertory/constants.dart' as constants;
import 'package:repertory/helpers.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';
class EditSettingsScreen extends StatefulWidget {
@@ -27,198 +25,154 @@ class _EditSettingsScreenState extends State<EditSettingsScreen> {
final scheme = Theme.of(context).colorScheme;
final textTheme = Theme.of(context).textTheme;
return 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, _) {
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,
return createCommonScaffold(
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(height: constants.padding),
Padding(
padding: const EdgeInsets.symmetric(horizontal: constants.padding),
child: Row(
children: [
const SizedBox(height: constants.padding),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: constants.padding,
),
child: 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(
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,
),
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();
},
);
},
),
),
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(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),
),
],
),
),
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(
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(),
);
}
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(
origSettings: jsonDecode(
jsonEncode(snapshot.requireData),
),
settings: snapshot.requireData,
showAdvanced: false,
);
},
return UISettingsWidget(
origSettings: jsonDecode(
jsonEncode(snapshot.requireData),
),
),
),
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:provider/provider.dart';
import 'package:repertory/constants.dart' as constants;
import 'package:repertory/helpers.dart';
import 'package:repertory/models/auth.dart';
import 'package:repertory/models/settings.dart';
import 'package:repertory/widgets/mount_list_widget.dart';
import 'package:repertory/widgets/aurora_sweep.dart';
class HomeScreen extends StatefulWidget {
final String title;
@@ -23,156 +23,119 @@ class _HomeScreeState extends State<HomeScreen> {
final scheme = Theme.of(context).colorScheme;
final textTheme = Theme.of(context).textTheme;
return 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, _) {
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,
return createCommonScaffold(
Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
const SizedBox(height: constants.padding),
Padding(
padding: const EdgeInsets.symmetric(horizontal: constants.padding),
child: Row(
children: [
const SizedBox(height: constants.padding),
Padding(
padding: const EdgeInsets.symmetric(
horizontal: constants.padding,
SizedBox(
width: 40,
height: 40,
child: Image.asset(
'assets/images/repertory.png',
fit: BoxFit.contain,
errorBuilder: (_, _, _) {
return Icon(
Icons.folder,
color: scheme.primary,
size: 32,
);
},
),
child: Row(
children: [
SizedBox(
width: 48,
height: 48,
child: Image.asset(
'assets/images/repertory.png',
fit: BoxFit.contain,
errorBuilder: (_, _, _) {
return Icon(
Icons.folder,
color: scheme.primary,
size: 40,
);
},
),
),
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(
),
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,
),
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: 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();
},
);
},
),
],
),
),
border: Border.all(
color: scheme.outlineVariant.withValues(alpha: 0.08),
width: 1,
),
),
],
),
),
const SizedBox(height: constants.padding),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: constants.padding,
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: const MountListWidget(),
),
),
],
),
],
),
),
const SizedBox(height: constants.padding),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: constants.padding,
),
child: const MountListWidget(),
),
),
],
),
floatingActionButton: Padding(
padding: const EdgeInsets.all(constants.padding),

View File

@@ -39,10 +39,11 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
// Theme SettingsList to your glass aesthetic (consistent with UISettingsWidget)
final theme = SettingsThemeData(
settingsListBackground: Colors.transparent,
settingsSectionBackground: scheme.surface.withValues(alpha: 0.30),
settingsSectionBackground: scheme.primary.withValues(
alpha: constants.primaryAlpha,
),
titleTextColor: scheme.onSurface.withValues(alpha: 0.96),
trailingTextColor: scheme.onSurface.withValues(alpha: 0.80),
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(
shrinkWrap: false,
platform: DevicePlatform.device,
@@ -402,38 +407,48 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
sections: [
if (encryptConfigSettings.isNotEmpty)
SettingsSection(
margin: sectionMargin,
title: const Text('Encrypt Config'),
tiles: encryptConfigSettings,
),
if (hostConfigSettings.isNotEmpty)
SettingsSection(
margin: sectionMargin,
title: const Text('Host Config'),
tiles: hostConfigSettings,
),
if (remoteConfigSettings.isNotEmpty)
SettingsSection(
margin: sectionMargin,
title: const Text('Remote Config'),
tiles: remoteConfigSettings,
),
if (s3ConfigSettings.isNotEmpty)
SettingsSection(
margin: sectionMargin,
title: const Text('S3 Config'),
tiles: s3ConfigSettings,
),
if (siaConfigSettings.isNotEmpty)
SettingsSection(
margin: sectionMargin,
title: const Text('Sia Config'),
tiles: siaConfigSettings,
),
if (remoteMountSettings.isNotEmpty)
SettingsSection(
margin: sectionMargin,
title: const Text('Remote Mount'),
tiles: (widget.settings['RemoteMount']['Enable'] as bool)
? remoteMountSettings
: [remoteMountSettings[0]],
),
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;
}
mount.setValue(key, value);
});
});
}
}
super.dispose();
}
@override
void setState(VoidCallback fn) {
if (!mounted) {
return;
}
if (widget.onChanged != null) {
widget.onChanged!();
}
if (!mounted) return;
if (widget.onChanged != null) widget.onChanged!();
super.setState(fn);
}
}

View File

@@ -272,7 +272,6 @@ class _MountWidgetState extends State<MountWidget> {
return location;
}
// ignore: use_build_context_synchronously
return editMountLocation(context, await mount.getAvailableLocations());
}

View File

@@ -39,18 +39,17 @@ class _UISettingsWidgetState extends State<UISettingsWidget> {
Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme;
// Theme the SettingsList to align with your glass look
final theme = SettingsThemeData(
settingsListBackground: Colors.transparent,
tileDescriptionTextColor: scheme.onSurface.withValues(alpha: 0.68),
settingsSectionBackground: scheme.surface.withValues(
alpha: 0.30,
), // slight glass base
tileHighlightColor: scheme.primary.withValues(alpha: 0.08),
settingsSectionBackground: scheme.primary.withValues(
alpha: constants.primaryAlpha,
),
titleTextColor: scheme.onSurface.withValues(alpha: 0.96),
trailingTextColor: scheme.onSurface.withValues(alpha: 0.80),
tileDescriptionTextColor: scheme.onSurface.withValues(alpha: 0.68),
leadingIconsColor: scheme.onSurface.withValues(alpha: 0.90),
dividerColor: scheme.outlineVariant.withValues(alpha: 0.10),
tileHighlightColor: scheme.primary.withValues(alpha: 0.08),
);
List<SettingsTile> commonSettings = [];