refactor ui
All checks were successful
BlockStorage/repertory/pipeline/head This commit looks good

This commit is contained in:
2025-09-05 09:27:32 -05:00
parent f16f6b808e
commit f5df53f781
10 changed files with 380 additions and 694 deletions

View File

@@ -96,7 +96,7 @@ createUriValidator<Validator>({host, port}) {
Uri.tryParse('http://${host ?? value}:${port ?? value}/') != null; Uri.tryParse('http://${host ?? value}:${port ?? value}/') != null;
} }
createHostNameOrIpValidators() => <Validator>[ List<Validator> createHostNameOrIpValidators() => <Validator>[
trimNotEmptyValidator, trimNotEmptyValidator,
createUriValidator(port: 9000), createUriValidator(port: 9000),
]; ];
@@ -153,7 +153,11 @@ void displayAuthError(Auth auth) {
); );
} }
void displayErrorMessage(context, String text, {bool clear = false}) { void displayErrorMessage(
BuildContext context,
String text, {
bool clear = false,
}) {
if (!context.mounted) { if (!context.mounted) {
return; return;
} }
@@ -431,39 +435,166 @@ Future<String?> editMountLocation(
} }
Scaffold createCommonScaffold( Scaffold createCommonScaffold(
BuildContext context,
String title,
List<Widget> children, { List<Widget> children, {
Widget? advancedWidget,
Widget? floatingActionButton, Widget? floatingActionButton,
}) => Scaffold( bool showBack = false,
body: SafeArea( }) {
child: Stack( final scheme = Theme.of(context).colorScheme;
children: [ final textTheme = Theme.of(context).textTheme;
Container(
width: double.infinity, return Scaffold(
height: double.infinity, body: SafeArea(
decoration: const BoxDecoration( child: Stack(
gradient: LinearGradient( children: [
begin: Alignment.topLeft, Container(
end: Alignment.bottomRight, width: double.infinity,
colors: constants.gradientColors, height: double.infinity,
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topLeft,
end: Alignment.bottomRight,
colors: constants.gradientColors,
),
), ),
), ),
), Consumer<Settings>(
Consumer<Settings>( builder: (_, settings, _) =>
builder: (_, settings, _) => AuroraSweep(enabled: settings.enableAnimations),
AuroraSweep(enabled: settings.enableAnimations),
),
Positioned.fill(
child: BackdropFilter(
filter: ImageFilter.blur(sigmaX: 6, sigmaY: 6),
child: Container(color: Colors.black.withValues(alpha: 0.06)),
), ),
), Positioned.fill(
...children, 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: [
if (!showBack) ...[
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,
);
},
),
),
const SizedBox(width: constants.padding),
],
if (showBack) ...[
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(
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),
if (!showBack) ...[
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');
},
),
const SizedBox(width: constants.padding),
],
if (showBack && advancedWidget != null) ...[
advancedWidget,
const SizedBox(width: constants.padding),
],
Consumer<Auth>(
builder: (context, auth, _) => IconButton(
tooltip: 'Log out',
icon: const Icon(Icons.logout),
onPressed: auth.logoff,
),
),
],
),
const SizedBox(height: constants.padding),
...children,
],
),
),
],
),
), ),
), floatingActionButton: floatingActionButton,
floatingActionButton: floatingActionButton, );
); }
InputDecoration createCommonDecoration( InputDecoration createCommonDecoration(
ColorScheme colorScheme, ColorScheme colorScheme,

View File

@@ -38,9 +38,9 @@ class MountList with ChangeNotifier {
return (excludeName == null return (excludeName == null
? list ? list
: list.whereNot( : list.whereNot(
(item) => (item) =>
item.name.toLowerCase() == excludeName.toLowerCase(), item.name.toLowerCase() == excludeName.toLowerCase(),
)) ))
.firstWhereOrNull((Mount item) { .firstWhereOrNull((Mount item) {
return item.bucket != null && return item.bucket != null &&
item.bucket!.toLowerCase() == bucket.toLowerCase(); item.bucket!.toLowerCase() == bucket.toLowerCase();
@@ -98,7 +98,7 @@ class MountList with ChangeNotifier {
} }
} }
void _sort(list) { void _sort(List list) {
list.sort((a, b) { list.sort((a, b) {
final res = a.type.compareTo(b.type); final res = a.type.compareTo(b.type);
if (res != 0) { if (res != 0) {

View File

@@ -8,7 +8,7 @@ import 'package:repertory/models/auth.dart';
class Settings with ChangeNotifier { class Settings with ChangeNotifier {
final Auth _auth; final Auth _auth;
bool _autoStart = false; bool _autoStart = false;
bool _enableAnimations = true; bool _enableAnimations = false;
Settings(this._auth) { Settings(this._auth) {
_auth.addListener(() { _auth.addListener(() {

View File

@@ -1,6 +1,5 @@
// add_mount_screen.dart // add_mount_screen.dart
import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@@ -45,248 +44,149 @@ class _AddMountScreenState extends State<AddMountScreen>
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme; final scheme = Theme.of(context).colorScheme;
final textTheme = Theme.of(context).textTheme;
return createCommonScaffold([ return createCommonScaffold(context, widget.title, [
Padding( AppDropdownFormField<String>(
padding: const EdgeInsets.all(constants.padding), constrainToIntrinsic: true,
child: Column( isExpanded: false,
crossAxisAlignment: CrossAxisAlignment.stretch, labelOf: (s) => s,
labelText: 'Provider Type',
onChanged: (mountType) {
_handleChange(
Provider.of<Auth>(context, listen: false),
mountType ?? '',
);
},
prefixIcon: Icons.miscellaneous_services,
value: _mountType.isEmpty ? null : _mountType,
values: constants.providerTypeList,
widthMultiplier: 2.0,
),
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',
hintText: 'Enter a unique name',
icon: Icons.drive_file_rename_outline,
),
),
],
if (_mount != null) ...[
const SizedBox(height: constants.padding),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: constants.padding),
child: ClipRRect(
borderRadius: BorderRadius.circular(constants.borderRadius),
child: MountSettingsWidget(
isAdd: true,
mount: _mount!,
settings: _settings[_mountType]!,
showAdvanced: false,
),
),
),
),
const SizedBox(height: constants.padding),
Row(
children: [ children: [
Row( IntrinsicWidth(
children: [ child: ElevatedButton.icon(
Material( label: const Text('Test'),
color: Colors.transparent, icon: const Icon(Icons.check),
child: InkWell( style: ElevatedButton.styleFrom(
backgroundColor: scheme.primary.withValues(alpha: 0.18),
foregroundColor: scheme.primary,
elevation: 0,
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(constants.borderRadius), borderRadius: BorderRadius.circular(constants.borderRadius),
onTap: () => Navigator.of(context).pop(), side: BorderSide(
child: Ink( color: scheme.outlineVariant.withValues(alpha: 0.15),
width: 40, width: 1,
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), onPressed: _handleProviderTest,
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),
AppDropdownFormField<String>(
constrainToIntrinsic: true,
isExpanded: false,
labelOf: (s) => s,
labelText: 'Provider Type',
onChanged: (mountType) {
_handleChange(
Provider.of<Auth>(context, listen: false),
mountType ?? '',
);
},
prefixIcon: Icons.miscellaneous_services,
value: _mountType.isEmpty ? null : _mountType,
values: constants.providerTypeList,
widthMultiplier: 2.0,
),
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',
hintText: 'Enter a unique name',
icon: Icons.drive_file_rename_outline,
),
), ),
], ),
if (_mount != null) ...[ const SizedBox(width: constants.padding),
const SizedBox(height: constants.padding), IntrinsicWidth(
Expanded( child: ElevatedButton.icon(
child: Padding( label: const Text('Add'),
padding: const EdgeInsets.symmetric( icon: const Icon(Icons.add),
horizontal: constants.padding, style: ElevatedButton.styleFrom(
), backgroundColor: scheme.primary,
child: ClipRRect( foregroundColor: scheme.onPrimary,
elevation: 8,
shadowColor: scheme.primary.withValues(alpha: 0.45),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(constants.borderRadius), borderRadius: BorderRadius.circular(constants.borderRadius),
child: MountSettingsWidget(
isAdd: true,
mount: _mount!,
settings: _settings[_mountType]!,
showAdvanced: false,
),
), ),
), ),
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), ),
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);
},
),
),
],
),
],
], ],
), ),
), ],
]); ], showBack: true);
} }
void _handleChange(Auth auth, String mountType) { void _handleChange(Auth auth, String mountType) {

View File

@@ -1,12 +1,9 @@
// edit_mount_screen.dart // edit_mount_screen.dart
import 'dart:convert'; import 'dart:convert';
import 'dart:ui';
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/helpers.dart'; import 'package:repertory/helpers.dart';
import 'package:repertory/models/auth.dart';
import 'package:repertory/models/mount.dart'; import 'package:repertory/models/mount.dart';
import 'package:repertory/utils/safe_set_state_mixin.dart'; import 'package:repertory/utils/safe_set_state_mixin.dart';
import 'package:repertory/widgets/mount_settings.dart'; import 'package:repertory/widgets/mount_settings.dart';
@@ -28,164 +25,48 @@ class _EditMountScreenState extends State<EditMountScreen>
Widget build(BuildContext context) { Widget build(BuildContext context) {
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 createCommonScaffold(
return createCommonScaffold([ context,
Column( widget.title,
crossAxisAlignment: CrossAxisAlignment.stretch, [
children: [ Expanded(
const SizedBox(height: constants.padding), child: Padding(
Padding(
padding: const EdgeInsets.symmetric(horizontal: constants.padding), padding: const EdgeInsets.symmetric(horizontal: constants.padding),
child: Row( child: ClipRRect(
children: [ borderRadius: BorderRadius.circular(constants.borderRadius),
Material( child: MountSettingsWidget(
color: Colors.transparent, mount: widget.mount,
child: InkWell( settings: jsonDecode(
borderRadius: BorderRadius.circular(constants.borderRadius), jsonEncode(widget.mount.mountConfig.settings),
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(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),
),
],
),
),
),
),
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),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: constants.padding,
),
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),
],
showBack: true,
advancedWidget: 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),
),
], ],
), ),
]); );
} }
} }

View File

@@ -2,7 +2,6 @@
import 'dart:convert' show jsonDecode, jsonEncode; import 'dart:convert' show jsonDecode, jsonEncode;
import 'dart:ui';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:http/http.dart' as http; import 'package:http/http.dart' as http;
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
@@ -24,132 +23,32 @@ class _EditSettingsScreenState extends State<EditSettingsScreen>
with SafeSetState<EditSettingsScreen> { with SafeSetState<EditSettingsScreen> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final scheme = Theme.of(context).colorScheme; return createCommonScaffold(context, widget.title, [
final textTheme = Theme.of(context).textTheme; Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: constants.padding),
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 createCommonScaffold([ return UISettingsWidget(
Column( origSettings: jsonDecode(jsonEncode(snapshot.requireData)),
crossAxisAlignment: CrossAxisAlignment.stretch, settings: snapshot.requireData,
children: [ showAdvanced: false,
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(
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: 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,
);
},
),
),
),
),
const SizedBox(height: constants.padding),
],
), ),
]); const SizedBox(height: constants.padding),
], showBack: true);
} }
Future<Map<String, dynamic>> _grabSettings() async { Future<Map<String, dynamic>> _grabSettings() async {

View File

@@ -1,12 +1,8 @@
// home_screen.dart // home_screen.dart
import 'dart:ui';
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/helpers.dart'; 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/mount_list_widget.dart';
class HomeScreen extends StatefulWidget { class HomeScreen extends StatefulWidget {
@@ -21,129 +17,16 @@ class _HomeScreeState extends State<HomeScreen> {
@override @override
Widget build(context) { Widget build(context) {
final scheme = Theme.of(context).colorScheme; final scheme = Theme.of(context).colorScheme;
final textTheme = Theme.of(context).textTheme;
return createCommonScaffold( return createCommonScaffold(
context,
widget.title,
[ [
Column( Expanded(
crossAxisAlignment: CrossAxisAlignment.stretch, child: Padding(
children: [ padding: const EdgeInsets.symmetric(horizontal: constants.padding),
const SizedBox(height: constants.padding), child: const MountListWidget(),
Padding( ),
padding: const EdgeInsets.symmetric(
horizontal: constants.padding,
),
child: Row(
children: [
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,
);
},
),
),
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: 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();
},
);
},
),
],
),
),
),
),
],
),
),
const SizedBox(height: constants.padding),
Expanded(
child: Padding(
padding: const EdgeInsets.symmetric(
horizontal: constants.padding,
),
child: const MountListWidget(),
),
),
],
), ),
], ],
floatingActionButton: Padding( floatingActionButton: Padding(

View File

@@ -10,7 +10,7 @@ import 'package:repertory/widgets/app_dropdown.dart';
import 'package:settings_ui/settings_ui.dart'; import 'package:settings_ui/settings_ui.dart';
void createBooleanSetting( void createBooleanSetting(
context, BuildContext context,
List<Widget> list, List<Widget> list,
Map<String, dynamic> settings, Map<String, dynamic> settings,
String key, String key,
@@ -38,7 +38,7 @@ void createBooleanSetting(
} }
void createIntListSetting( void createIntListSetting(
context, BuildContext context,
List<Widget> list, List<Widget> list,
Map<String, dynamic> settings, Map<String, dynamic> settings,
String key, String key,
@@ -76,7 +76,7 @@ void createIntListSetting(
} }
void createIntSetting( void createIntSetting(
context, BuildContext context,
List<Widget> list, List<Widget> list,
Map<String, dynamic> settings, Map<String, dynamic> settings,
String key, String key,
@@ -139,7 +139,7 @@ void createIntSetting(
} }
void createPasswordSetting( void createPasswordSetting(
context, BuildContext context,
List<Widget> list, List<Widget> list,
Map<String, dynamic> settings, Map<String, dynamic> settings,
String key, String key,
@@ -267,7 +267,11 @@ void createPasswordSetting(
} }
} }
Widget createSettingTitle(context, String key, String? description) { Widget createSettingTitle(
BuildContext context,
String key,
String? description,
) {
if (description == null) { if (description == null) {
return Text(key); return Text(key);
} }
@@ -288,7 +292,7 @@ Widget createSettingTitle(context, String key, String? description) {
} }
void createStringListSetting( void createStringListSetting(
context, BuildContext context,
List<Widget> list, List<Widget> list,
Map<String, dynamic> settings, Map<String, dynamic> settings,
String key, String key,
@@ -319,7 +323,7 @@ void createStringListSetting(
} }
void createStringSetting( void createStringSetting(
context, BuildContext context,
List<Widget> list, List<Widget> list,
Map<String, dynamic> settings, Map<String, dynamic> settings,
String key, String key,

View File

@@ -7,9 +7,12 @@ class MountConfig {
String path = ''; String path = '';
Map<String, dynamic> _settings = {}; Map<String, dynamic> _settings = {};
final String _type; final String _type;
MountConfig({required name, required type, Map<String, dynamic>? settings}) MountConfig({
: _name = name, required String name,
_type = type { required String type,
Map<String, dynamic>? settings,
}) : _name = name,
_type = type {
if (settings != null) { if (settings != null) {
_settings = settings; _settings = settings;
} }

View File

@@ -190,16 +190,6 @@ class _MountWidgetState extends State<MountWidget>
); );
} }
String _formatType(String type) {
if (type.toUpperCase() == 'S3') {
return 'S3';
}
if (type.isEmpty) {
return type;
}
return type[0].toUpperCase() + type.substring(1).toLowerCase();
}
String _prettyPath(Mount mount) { String _prettyPath(Mount mount) {
if (mount.path.isEmpty && mount.mounted == null) { if (mount.path.isEmpty && mount.mounted == null) {
return 'loading...'; return 'loading...';
@@ -271,6 +261,7 @@ 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());
} }
@@ -294,14 +285,8 @@ class _FramedBox extends StatelessWidget {
final IconData icon; final IconData icon;
final VoidCallback? onTap; final VoidCallback? onTap;
final Color? iconColor; final Color? iconColor;
final double iconSize;
const _FramedBox({ const _FramedBox({required this.icon, this.onTap, this.iconColor});
required this.icon,
this.onTap,
this.iconColor,
this.iconSize = 32,
});
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@@ -337,7 +322,7 @@ class _FramedBox extends StatelessWidget {
child: Icon( child: Icon(
icon, icon,
color: iconColor ?? scheme.onSurface.withValues(alpha: 0.92), color: iconColor ?? scheme.onSurface.withValues(alpha: 0.92),
size: iconSize, size: 32.0,
), ),
), ),
), ),