theme changes
This commit is contained in:
1 parent
539ad84cf3
commit
a8715c8ec4
21 files changed
+487
-248
No files matched your search
@@ -11,6 +11,8 @@
|
|||||||
### Changes from v2.0.7-release
|
### Changes from v2.0.7-release
|
||||||
|
|
||||||
* Fixed Windows setup icon location
|
* Fixed Windows setup icon location
|
||||||
|
* Upgraded `cpp-build-system` to v2.0.1
|
||||||
|
* Updated theme colors and layout
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -1,49 +1,157 @@
|
|||||||
// constants.dart
|
// constants.dart
|
||||||
|
|
||||||
import 'package:flutter/material.dart' show GlobalKey, NavigatorState, Color;
|
import 'package:flutter/material.dart';
|
||||||
import 'package:sodium_libs/sodium_libs.dart';
|
import 'package:sodium_libs/sodium_libs.dart';
|
||||||
|
|
||||||
const accentBlue = Color(0xFF1050A0);
|
// ---------------------------------------------------------------------------
|
||||||
const addMountTitle = 'Add New Mount';
|
// App strings
|
||||||
const appLogonTitle = 'Repertory Portal Login';
|
// Window/screen titles shown in the UI.
|
||||||
const appSettingsTitle = 'Portal Settings';
|
// ---------------------------------------------------------------------------
|
||||||
const appTitle = 'Repertory Management Portal';
|
const addMountTitle = 'Add New Mount'; // Title for the add-mount dialog.
|
||||||
const borderRadius = 16.0;
|
const appLogonTitle = 'Repertory Portal Login'; // Title for the login screen.
|
||||||
const borderRadiusSmall = borderRadius / 2.0;
|
const appSettingsTitle = 'Portal Settings'; // Title for the settings dialog.
|
||||||
const borderRadiusTiny = borderRadiusSmall / 2.0;
|
const appTitle = 'Repertory Management Portal'; // App/home screen title.
|
||||||
const boxShadowAlpha = 0.20;
|
|
||||||
const databaseTypeList = ['rocksdb', 'sqlite'];
|
|
||||||
const dialogAlpha = 0.95;
|
|
||||||
const downloadTypeList = ['default', 'direct', 'ring_buffer'];
|
|
||||||
const dropDownAlpha = 99.0;
|
|
||||||
const eventLevelList = ['critical', 'error', 'warn', 'info', 'debug', 'trace'];
|
|
||||||
const gradientColors = [Color(0xFF0A0F1F), Color(0xFF1B1C1F)];
|
|
||||||
const gradientColors2 = [Color(0x07FFFFFF), Color(0x00000000)];
|
|
||||||
const highlightAlpha = 0.10;
|
|
||||||
const largeIconSize = 32.0;
|
|
||||||
const loginIconSize = 54.0;
|
|
||||||
const logonWidth = 420.0;
|
|
||||||
const outlineAlpha = 0.15;
|
|
||||||
const padding = 16.0;
|
|
||||||
const paddingLarge = padding * 2.0;
|
|
||||||
const paddingMedium = 12.0;
|
|
||||||
const paddingSmall = padding / 2.0;
|
|
||||||
const primaryAlpha = 0.12;
|
|
||||||
const primarySurfaceAlpha = 92.0;
|
|
||||||
const protocolTypeList = ['http', 'https'];
|
|
||||||
const providerTypeList = ['Encrypt', 'Remote', 'S3', 'Sia'];
|
|
||||||
const ringBufferSizeList = ['128', '256', '512', '1024', '2048'];
|
|
||||||
const secondaryAlpha = 0.45;
|
|
||||||
const secondarySurfaceAlpha = 70.0;
|
|
||||||
const smallIconSize = 18.0;
|
|
||||||
const surfaceContainerLowDark = Color(0xFF292A2D);
|
|
||||||
const surfaceDark = Color(0xFF202124);
|
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Palette
|
||||||
|
// Seed/accent blue, muted dark-theme primary, dark grey surfaces, error red.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
const accentBlue = Color(0xFF1050A0); // Seed color the ColorScheme is built from.
|
||||||
|
const primaryBlue = Color(0xFF6E95C9); // Muted primary accent used in dark mode.
|
||||||
|
const surfaceDark = Color(0xFF1E2127); // Scaffold/base surface (blue-tinted grey).
|
||||||
|
const surfaceContainerLowDark = Color(0xFF272B33); // Elevated surface (cards/dialogs).
|
||||||
|
const errorRed = Color(0xFFD98A86); // Muted error red for validation/error text.
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Gradients
|
||||||
|
// Full-screen background and the subtle FAB sheen overlay.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
const gradientColors = [Color(0xFF0A0F1F), Color(0xFF1B1C1F)]; // App background gradient.
|
||||||
|
const gradientColors2 = [Color(0x07FFFFFF), Color(0x00000000)]; // Faint top-down FAB sheen.
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Alpha tints
|
||||||
|
// Translucency applied over primary/surface/outline colors.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
const boxShadowAlpha = 0.20; // Opacity of drop shadows.
|
||||||
|
const dialogTintAlpha = 0.06; // Accent tint blended onto dialog/dropdown surfaces.
|
||||||
|
const highlightAlpha = 0.10; // Subtle highlight/border tint.
|
||||||
|
const outlineAlpha = 0.15; // Outline/border and scrim tint.
|
||||||
|
const primaryAlpha = 0.12; // Primary fill tint for cards/fields.
|
||||||
|
const primarySurfaceAlpha = 92.0; // Near-opaque primary surface text/icon tint.
|
||||||
|
const secondaryAlpha = 0.45; // Medium primary tint for buttons/toggles.
|
||||||
|
const secondarySurfaceAlpha = 70.0; // Dimmer surface text tint (descriptions).
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Corner radii
|
||||||
|
// Shared rounding scale for cards, buttons, and dialogs.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
const borderRadius = 16.0; // Base corner radius.
|
||||||
|
const borderRadiusSmall = borderRadius / 2.0; // Half radius for cards/fields (8).
|
||||||
|
const borderRadiusTiny = borderRadiusSmall / 2.0; // Quarter radius for small chips (4).
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Border widths
|
||||||
|
// Default hairline and the thicker focused-input border.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
const borderWidth = 1.0; // Standard hairline border for bevels.
|
||||||
|
const focusBorderWidth = 2.0; // Emphasized border for focused inputs.
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Elevations
|
||||||
|
// Card drop shadow and the stronger floating-element shadow.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
const cardElevation = 4.0; // Subtle shadow for content cards.
|
||||||
|
const fabElevation = 12.0; // Stronger shadow for the floating action button.
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Spacing
|
||||||
|
// Shared padding scale used across layouts.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
const padding = 16.0; // Base padding/gap unit.
|
||||||
|
const paddingLarge = padding * 2.0; // Double padding for larger gaps (32).
|
||||||
|
const paddingMedium = 12.0; // Medium padding between base and small.
|
||||||
|
const paddingSmall = padding / 2.0; // Half padding for tight gaps (8).
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Icon sizes
|
||||||
|
// Shared scale for iconography.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
const largeIconSize = 32.0; // Large icons (FAB, prominent actions).
|
||||||
|
const loginIconSize = 54.0; // Oversized icon on the login screen.
|
||||||
|
const smallIconSize = 18.0; // Small inline icons.
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Icons
|
||||||
|
// Shared iconography reused across the UI (actions, toggles, fields).
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
const iconAdd = Icons.add; // Add / create actions (FAB, add mount).
|
||||||
|
const iconAutoMount = Icons.auto_mode; // Auto-mount indicator.
|
||||||
|
const iconBack = Icons.arrow_back; // Back navigation.
|
||||||
|
const iconClose = Icons.close; // Close/dismiss (dialogs).
|
||||||
|
const iconDelete = Icons.delete; // Delete/remove actions.
|
||||||
|
const iconEdit = Icons.edit; // Edit actions.
|
||||||
|
const iconFolder = Icons.folder; // Folder/path and app logo fallback.
|
||||||
|
const iconLock = Icons.lock; // Password/lock fields.
|
||||||
|
const iconPassword = Icons.password; // Password-style settings.
|
||||||
|
const iconRename = Icons.drive_file_rename_outline; // Rename/config-name field.
|
||||||
|
const iconRemoteMount = Icons.lan; // Remote mount (networking).
|
||||||
|
const iconSettings = Icons.settings; // Settings/gear actions.
|
||||||
|
const iconTest = Icons.check; // Test/confirm actions.
|
||||||
|
const iconToggleOff = Icons.toggle_off; // Toggle (off state).
|
||||||
|
const iconToggleOn = Icons.toggle_on; // Toggle (on state).
|
||||||
|
const iconUser = Icons.person; // User/username fields.
|
||||||
|
const iconVisibility = Icons.visibility; // Reveal password.
|
||||||
|
const iconVisibilityOff = Icons.visibility_off; // Hide password.
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Control sizes
|
||||||
|
// Fixed dimensions for buttons, framed controls, and the FAB.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
const buttonHeight = 40.0; // Minimum height of primary action buttons.
|
||||||
|
const fabInnerSize = 56.0; // Inner tappable square of the add-mount FAB.
|
||||||
|
const framedControlSize = 46.0; // Bordered icon buttons on mount cards.
|
||||||
|
const headerControlSize = 40.0; // App-bar logo/back box.
|
||||||
|
const mountCardMinHeight = 120.0; // Minimum height of a mount list card.
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Layout widths/factors
|
||||||
|
// Fixed widths and viewport-fraction sizing.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
const logonWidth = 420.0; // Fixed width of the login card.
|
||||||
|
const snackBarWidthFactor = 0.50; // Snackbar width as a fraction of the viewport.
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Dialog sizing
|
||||||
|
// Viewport-fraction width/height with absolute pixel clamps.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
const dialogMinWidthFactor = 0.40; // Min dialog width as a viewport fraction.
|
||||||
|
const dialogMaxWidthFactor = 0.70; // Max dialog width as a viewport fraction.
|
||||||
|
const dialogMaxHeightFactor = 0.85; // Max dialog height before it scrolls.
|
||||||
|
const dialogMinWidth = 360.0; // Absolute minimum dialog width (px).
|
||||||
|
const dialogMaxWidth = 820.0; // Absolute maximum dialog width (px).
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Option lists
|
||||||
|
// Selectable values for configuration dropdowns.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
const databaseTypeList = ['rocksdb', 'sqlite']; // Database backend options.
|
||||||
|
const downloadTypeList = ['default', 'direct', 'ring_buffer']; // Download strategy options.
|
||||||
|
const eventLevelList = ['critical', 'error', 'warn', 'info', 'debug', 'trace']; // Log level options.
|
||||||
|
const protocolTypeList = ['http', 'https']; // Connection protocol options.
|
||||||
|
const providerTypeList = ['Encrypt', 'Remote', 'S3', 'Sia']; // Mount provider options.
|
||||||
|
const ringBufferSizeList = ['128', '256', '512', '1024', '2048']; // Ring-buffer size options (MiB).
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Runtime globals
|
||||||
|
// Navigator key and lazily-initialized libsodium instance.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// Enables navigation/context access from outside the widget tree.
|
||||||
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||||
|
|
||||||
Sodium? _sodium;
|
Sodium? _sodium; // Backing store for the libsodium instance.
|
||||||
void setSodium(Sodium sodium) {
|
void setSodium(Sodium sodium) {
|
||||||
_sodium = sodium;
|
_sodium = sodium; // Set once during app initialization.
|
||||||
}
|
}
|
||||||
|
|
||||||
Sodium get sodium => _sodium!;
|
Sodium get sodium => _sodium!; // Access the initialized libsodium instance.
|
||||||
@@ -18,10 +18,14 @@ Future doShowDialog(BuildContext context, Widget child) => showDialog(
|
|||||||
return Theme(
|
return Theme(
|
||||||
data: theme.copyWith(
|
data: theme.copyWith(
|
||||||
dialogTheme: DialogThemeData(
|
dialogTheme: DialogThemeData(
|
||||||
backgroundColor: darken(
|
// Elevated surface: slightly lighter than the scaffold background
|
||||||
scheme.primary,
|
// (surfaceDark) with a faint accent tint so the popup reads as part
|
||||||
0.95,
|
// of the dark theme rather than a near-black panel. The backdrop blur
|
||||||
).withValues(alpha: constants.dropDownAlpha),
|
// and barrier scrim already provide separation, so keep it opaque.
|
||||||
|
backgroundColor: Color.alphaBlend(
|
||||||
|
scheme.primary.withValues(alpha: constants.dialogTintAlpha),
|
||||||
|
constants.surfaceContainerLowDark,
|
||||||
|
),
|
||||||
surfaceTintColor: Colors.transparent,
|
surfaceTintColor: Colors.transparent,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(constants.borderRadius),
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
@@ -29,7 +33,7 @@ Future doShowDialog(BuildContext context, Widget child) => showDialog(
|
|||||||
color: scheme.outlineVariant.withValues(
|
color: scheme.outlineVariant.withValues(
|
||||||
alpha: constants.outlineAlpha,
|
alpha: constants.outlineAlpha,
|
||||||
),
|
),
|
||||||
width: 1,
|
width: constants.borderWidth,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -90,8 +94,8 @@ final Validator portIsValid = (value) {
|
|||||||
// ignore: prefer_function_declarations_over_variables
|
// ignore: prefer_function_declarations_over_variables
|
||||||
final Validator trimNotEmptyValidator = (value) => value.trim().isNotEmpty;
|
final Validator trimNotEmptyValidator = (value) => value.trim().isNotEmpty;
|
||||||
|
|
||||||
createUriValidator<Validator>({host, port}) {
|
Validator createUriValidator({Object? host, Object? port}) {
|
||||||
return (value) =>
|
return (String value) =>
|
||||||
Uri.tryParse('http://${host ?? value}:${port ?? value}/') != null;
|
Uri.tryParse('http://${host ?? value}:${port ?? value}/') != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,14 +452,39 @@ InputDecoration createCommonDecoration(
|
|||||||
filled: filled,
|
filled: filled,
|
||||||
fillColor: colorScheme.primary.withValues(alpha: constants.primaryAlpha),
|
fillColor: colorScheme.primary.withValues(alpha: constants.primaryAlpha),
|
||||||
hintText: hintText,
|
hintText: hintText,
|
||||||
|
// Keep label and prefix/suffix icons neutral so the error state does not
|
||||||
|
// flood the whole field with red; the error signal stays on the border and
|
||||||
|
// helper text only.
|
||||||
|
labelStyle: TextStyle(color: colorScheme.onSurface),
|
||||||
|
floatingLabelStyle: TextStyle(color: colorScheme.onSurface),
|
||||||
|
prefixIconColor: colorScheme.onSurface,
|
||||||
|
suffixIconColor: colorScheme.onSurface,
|
||||||
border: OutlineInputBorder(
|
border: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(constants.borderRadiusSmall),
|
borderRadius: BorderRadius.circular(constants.borderRadiusSmall),
|
||||||
borderSide: BorderSide.none,
|
borderSide: BorderSide.none,
|
||||||
),
|
),
|
||||||
focusedBorder: OutlineInputBorder(
|
focusedBorder: OutlineInputBorder(
|
||||||
borderRadius: BorderRadius.circular(constants.borderRadiusSmall),
|
borderRadius: BorderRadius.circular(constants.borderRadiusSmall),
|
||||||
borderSide: BorderSide(color: colorScheme.primary, width: 2),
|
borderSide: BorderSide(
|
||||||
|
color: colorScheme.primary,
|
||||||
|
width: constants.focusBorderWidth,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
|
errorBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(constants.borderRadiusSmall),
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: colorScheme.error,
|
||||||
|
width: constants.borderWidth,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
focusedErrorBorder: OutlineInputBorder(
|
||||||
|
borderRadius: BorderRadius.circular(constants.borderRadiusSmall),
|
||||||
|
borderSide: BorderSide(
|
||||||
|
color: colorScheme.error,
|
||||||
|
width: constants.focusBorderWidth,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
errorStyle: TextStyle(color: colorScheme.error),
|
||||||
contentPadding: const EdgeInsets.all(constants.paddingSmall),
|
contentPadding: const EdgeInsets.all(constants.paddingSmall),
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -504,3 +533,4 @@ Color darken(Color color, [double percentage = 0.1]) {
|
|||||||
);
|
);
|
||||||
return hslDark.toColor();
|
return hslDark.toColor();
|
||||||
}
|
}
|
||||||
|
|
||||||
+33
-41
@@ -3,15 +3,10 @@
|
|||||||
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_list.dart';
|
import 'package:repertory/models/mount_list.dart';
|
||||||
import 'package:repertory/models/settings.dart';
|
import 'package:repertory/models/settings.dart';
|
||||||
import 'package:repertory/screens/add_mount_screen.dart';
|
|
||||||
import 'package:repertory/screens/auth_screen.dart';
|
import 'package:repertory/screens/auth_screen.dart';
|
||||||
import 'package:repertory/screens/edit_mount_screen.dart';
|
|
||||||
import 'package:repertory/screens/edit_settings_screen.dart';
|
|
||||||
import 'package:repertory/screens/home_screen.dart';
|
import 'package:repertory/screens/home_screen.dart';
|
||||||
import 'package:repertory/widgets/auth_check.dart';
|
import 'package:repertory/widgets/auth_check.dart';
|
||||||
import 'package:sodium_libs/sodium_libs.dart' show SodiumInit;
|
import 'package:sodium_libs/sodium_libs.dart' show SodiumInit;
|
||||||
@@ -47,36 +42,57 @@ class _MyAppState extends State<MyApp> {
|
|||||||
@override
|
@override
|
||||||
Widget build(context) {
|
Widget build(context) {
|
||||||
final snackBarTheme = SnackBarThemeData(
|
final snackBarTheme = SnackBarThemeData(
|
||||||
width: MediaQuery.of(context).size.width * 0.50,
|
width:
|
||||||
|
MediaQuery.of(context).size.width * constants.snackBarWidthFactor,
|
||||||
behavior: SnackBarBehavior.floating,
|
behavior: SnackBarBehavior.floating,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
final colorScheme = ColorScheme.fromSeed(
|
||||||
|
brightness: Brightness.dark,
|
||||||
|
seedColor: constants.accentBlue,
|
||||||
|
primary: constants.primaryBlue,
|
||||||
|
error: constants.errorRed,
|
||||||
|
onSurface: Colors.white70,
|
||||||
|
surface: constants.surfaceDark,
|
||||||
|
surfaceContainerLow: constants.surfaceContainerLowDark,
|
||||||
|
);
|
||||||
|
|
||||||
return MaterialApp(
|
return MaterialApp(
|
||||||
navigatorKey: constants.navigatorKey,
|
navigatorKey: constants.navigatorKey,
|
||||||
themeMode: ThemeMode.dark,
|
themeMode: ThemeMode.dark,
|
||||||
darkTheme: ThemeData(
|
darkTheme: ThemeData(
|
||||||
useMaterial3: true,
|
useMaterial3: true,
|
||||||
brightness: Brightness.dark,
|
brightness: Brightness.dark,
|
||||||
colorScheme: ColorScheme.fromSeed(
|
colorScheme: colorScheme,
|
||||||
brightness: Brightness.dark,
|
|
||||||
seedColor: constants.accentBlue,
|
|
||||||
onSurface: Colors.white70,
|
|
||||||
surface: constants.surfaceDark,
|
|
||||||
surfaceContainerLow: constants.surfaceContainerLowDark,
|
|
||||||
),
|
|
||||||
scaffoldBackgroundColor: constants.surfaceDark,
|
scaffoldBackgroundColor: constants.surfaceDark,
|
||||||
snackBarTheme: snackBarTheme,
|
snackBarTheme: snackBarTheme,
|
||||||
appBarTheme: const AppBarTheme(scrolledUnderElevation: 0),
|
appBarTheme: const AppBarTheme(scrolledUnderElevation: 0),
|
||||||
inputDecorationTheme: const InputDecorationTheme(
|
cardTheme: CardThemeData(
|
||||||
focusedBorder: UnderlineInputBorder(borderSide: BorderSide(width: 2)),
|
elevation: constants.cardElevation,
|
||||||
|
shape: RoundedRectangleBorder(
|
||||||
|
borderRadius: BorderRadius.circular(constants.borderRadiusSmall),
|
||||||
|
side: BorderSide(
|
||||||
|
color: colorScheme.outlineVariant.withValues(
|
||||||
|
alpha: constants.highlightAlpha,
|
||||||
|
),
|
||||||
|
width: constants.borderWidth,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
inputDecorationTheme: InputDecorationTheme(
|
||||||
|
focusedBorder: UnderlineInputBorder(
|
||||||
|
borderSide: BorderSide(width: constants.focusBorderWidth),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
elevatedButtonTheme: ElevatedButtonThemeData(
|
elevatedButtonTheme: ElevatedButtonThemeData(
|
||||||
style: ElevatedButton.styleFrom(
|
style: ElevatedButton.styleFrom(
|
||||||
minimumSize: const Size.fromHeight(40),
|
minimumSize: const Size.fromHeight(constants.buttonHeight),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
filledButtonTheme: FilledButtonThemeData(
|
filledButtonTheme: FilledButtonThemeData(
|
||||||
style: FilledButton.styleFrom(minimumSize: const Size.fromHeight(40)),
|
style: FilledButton.styleFrom(
|
||||||
|
minimumSize: const Size.fromHeight(constants.buttonHeight),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
dividerTheme: const DividerThemeData(thickness: 0.6, space: 0),
|
dividerTheme: const DividerThemeData(thickness: 0.6, space: 0),
|
||||||
),
|
),
|
||||||
@@ -85,31 +101,7 @@ class _MyAppState extends State<MyApp> {
|
|||||||
routes: {
|
routes: {
|
||||||
'/': (context) =>
|
'/': (context) =>
|
||||||
const AuthCheck(child: HomeScreen(title: constants.appTitle)),
|
const AuthCheck(child: HomeScreen(title: constants.appTitle)),
|
||||||
'/add': (context) => const AuthCheck(
|
|
||||||
child: AddMountScreen(title: constants.addMountTitle),
|
|
||||||
),
|
|
||||||
'/auth': (context) => const AuthScreen(title: constants.appTitle),
|
'/auth': (context) => const AuthScreen(title: constants.appTitle),
|
||||||
'/settings': (context) => const AuthCheck(
|
|
||||||
child: EditSettingsScreen(title: constants.appSettingsTitle),
|
|
||||||
),
|
|
||||||
},
|
|
||||||
onGenerateRoute: (settings) {
|
|
||||||
if (settings.name != '/edit') {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final mount = settings.arguments as Mount;
|
|
||||||
return MaterialPageRoute(
|
|
||||||
builder: (context) {
|
|
||||||
return AuthCheck(
|
|
||||||
child: EditMountScreen(
|
|
||||||
mount: mount,
|
|
||||||
title:
|
|
||||||
'${mount.provider} Settings • ${formatMountName(mount.type, mount.name)}',
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -125,7 +125,7 @@ class Mount with ChangeNotifier {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return refresh();
|
return await refresh();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('$e');
|
debugPrint('$e');
|
||||||
}
|
}
|
||||||
@@ -154,7 +154,7 @@ class Mount with ChangeNotifier {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return refresh();
|
return await refresh();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('$e');
|
debugPrint('$e');
|
||||||
}
|
}
|
||||||
@@ -330,7 +330,7 @@ class Mount with ChangeNotifier {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return refresh();
|
return await refresh();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
debugPrint('$e');
|
debugPrint('$e');
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,21 +10,31 @@ import 'package:repertory/models/mount.dart';
|
|||||||
import 'package:repertory/models/mount_list.dart';
|
import 'package:repertory/models/mount_list.dart';
|
||||||
import 'package:repertory/types/mount_config.dart';
|
import 'package:repertory/types/mount_config.dart';
|
||||||
import 'package:repertory/utils/safe_set_state_mixin.dart';
|
import 'package:repertory/utils/safe_set_state_mixin.dart';
|
||||||
|
import 'package:repertory/widgets/app_dialog.dart';
|
||||||
import 'package:repertory/widgets/app_dropdown.dart';
|
import 'package:repertory/widgets/app_dropdown.dart';
|
||||||
import 'package:repertory/widgets/app_outlined_icon_button.dart';
|
import 'package:repertory/widgets/app_outlined_icon_button.dart';
|
||||||
import 'package:repertory/widgets/app_scaffold.dart';
|
|
||||||
import 'package:repertory/widgets/mount_settings.dart';
|
import 'package:repertory/widgets/mount_settings.dart';
|
||||||
|
|
||||||
class AddMountScreen extends StatefulWidget {
|
/// Opens the "Add New Mount" modal dialog.
|
||||||
final String title;
|
Future<void> showAddMountDialog(BuildContext context) {
|
||||||
const AddMountScreen({super.key, required this.title});
|
return doShowDialog(
|
||||||
|
context,
|
||||||
@override
|
const AppDialog(
|
||||||
State<AddMountScreen> createState() => _AddMountScreenState();
|
title: constants.addMountTitle,
|
||||||
|
child: AddMountContent(),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
class _AddMountScreenState extends State<AddMountScreen>
|
class AddMountContent extends StatefulWidget {
|
||||||
with SafeSetState<AddMountScreen> {
|
const AddMountContent({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<AddMountContent> createState() => _AddMountContentState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _AddMountContentState extends State<AddMountContent>
|
||||||
|
with SafeSetState<AddMountContent> {
|
||||||
Mount? _mount;
|
Mount? _mount;
|
||||||
final _mountNameController = TextEditingController();
|
final _mountNameController = TextEditingController();
|
||||||
String _mountType = "";
|
String _mountType = "";
|
||||||
@@ -48,9 +58,9 @@ class _AddMountScreenState extends State<AddMountScreen>
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final scheme = Theme.of(context).colorScheme;
|
final scheme = Theme.of(context).colorScheme;
|
||||||
|
|
||||||
return AppScaffold(
|
return Column(
|
||||||
title: widget.title,
|
mainAxisSize: MainAxisSize.min,
|
||||||
showBack: true,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
children: [
|
children: [
|
||||||
AppDropdown<String>(
|
AppDropdown<String>(
|
||||||
constrainToIntrinsic: true,
|
constrainToIntrinsic: true,
|
||||||
@@ -83,26 +93,19 @@ class _AddMountScreenState extends State<AddMountScreen>
|
|||||||
scheme,
|
scheme,
|
||||||
'Configuration Name',
|
'Configuration Name',
|
||||||
hintText: 'Enter a unique name',
|
hintText: 'Enter a unique name',
|
||||||
icon: Icons.drive_file_rename_outline,
|
icon: constants.iconRename,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
if (_mount != null) ...[
|
if (_mount != null) ...[
|
||||||
const SizedBox(height: constants.padding),
|
const SizedBox(height: constants.padding),
|
||||||
Expanded(
|
ClipRRect(
|
||||||
child: Padding(
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
padding: const EdgeInsets.symmetric(
|
child: MountSettingsWidget(
|
||||||
horizontal: constants.padding,
|
isAdd: true,
|
||||||
),
|
mount: _mount!,
|
||||||
child: ClipRRect(
|
settings: _settings[_mountType]!,
|
||||||
borderRadius: BorderRadius.circular(constants.borderRadius),
|
showAdvanced: false,
|
||||||
child: MountSettingsWidget(
|
|
||||||
isAdd: true,
|
|
||||||
mount: _mount!,
|
|
||||||
settings: _settings[_mountType]!,
|
|
||||||
showAdvanced: false,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const SizedBox(height: constants.padding),
|
const SizedBox(height: constants.padding),
|
||||||
@@ -111,7 +114,7 @@ class _AddMountScreenState extends State<AddMountScreen>
|
|||||||
IntrinsicWidth(
|
IntrinsicWidth(
|
||||||
child: AppOutlinedIconButton(
|
child: AppOutlinedIconButton(
|
||||||
enabled: _enabled,
|
enabled: _enabled,
|
||||||
icon: Icons.check,
|
icon: constants.iconTest,
|
||||||
text: 'Test',
|
text: 'Test',
|
||||||
onPressed: _handleProviderTest,
|
onPressed: _handleProviderTest,
|
||||||
),
|
),
|
||||||
@@ -120,7 +123,7 @@ class _AddMountScreenState extends State<AddMountScreen>
|
|||||||
IntrinsicWidth(
|
IntrinsicWidth(
|
||||||
child: AppOutlinedIconButton(
|
child: AppOutlinedIconButton(
|
||||||
enabled: _enabled,
|
enabled: _enabled,
|
||||||
icon: Icons.add,
|
icon: constants.iconAdd,
|
||||||
text: 'Add',
|
text: 'Add',
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|||||||
@@ -198,7 +198,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
errorBuilder: (_, _, _) {
|
errorBuilder: (_, _, _) {
|
||||||
return Icon(
|
return Icon(
|
||||||
Icons.folder,
|
constants.iconFolder,
|
||||||
color: scheme.primary,
|
color: scheme.primary,
|
||||||
size: constants.loginIconSize,
|
size: constants.loginIconSize,
|
||||||
);
|
);
|
||||||
@@ -234,7 +234,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
AppTextField(
|
AppTextField(
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
controller: _userController,
|
controller: _userController,
|
||||||
icon: Icons.person,
|
icon: constants.iconUser,
|
||||||
labelText: 'Username',
|
labelText: 'Username',
|
||||||
textInputAction: TextInputAction.next,
|
textInputAction: TextInputAction.next,
|
||||||
validator: (v) {
|
validator: (v) {
|
||||||
@@ -250,7 +250,7 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
const SizedBox(height: constants.padding),
|
const SizedBox(height: constants.padding),
|
||||||
AppTextField(
|
AppTextField(
|
||||||
controller: _passwordController,
|
controller: _passwordController,
|
||||||
icon: Icons.lock,
|
icon: constants.iconLock,
|
||||||
labelText: 'Password',
|
labelText: 'Password',
|
||||||
obscureText: _obscure,
|
obscureText: _obscure,
|
||||||
suffixIcon: IconButton(
|
suffixIcon: IconButton(
|
||||||
@@ -259,8 +259,8 @@ class _AuthScreenState extends State<AuthScreen> {
|
|||||||
: 'Hide password',
|
: 'Hide password',
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
_obscure
|
_obscure
|
||||||
? Icons.visibility
|
? constants.iconVisibility
|
||||||
: Icons.visibility_off,
|
: constants.iconVisibilityOff,
|
||||||
),
|
),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
setState(() {
|
setState(() {
|
||||||
|
|||||||
@@ -3,32 +3,38 @@
|
|||||||
import 'dart:convert';
|
import 'dart:convert';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:repertory/constants.dart' as constants;
|
import 'package:repertory/constants.dart' as constants;
|
||||||
|
import 'package:repertory/helpers.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/app_scaffold.dart';
|
import 'package:repertory/widgets/app_dialog.dart';
|
||||||
import 'package:repertory/widgets/mount_settings.dart';
|
import 'package:repertory/widgets/mount_settings.dart';
|
||||||
|
|
||||||
class EditMountScreen extends StatefulWidget {
|
/// Opens the "Edit Mount" modal dialog for the given [mount].
|
||||||
final Mount mount;
|
Future<void> showEditMountDialog(BuildContext context, Mount mount) {
|
||||||
final String title;
|
return doShowDialog(context, EditMountContent(mount: mount));
|
||||||
const EditMountScreen({super.key, required this.mount, required this.title});
|
|
||||||
|
|
||||||
@override
|
|
||||||
State<EditMountScreen> createState() => _EditMountScreenState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EditMountScreenState extends State<EditMountScreen>
|
class EditMountContent extends StatefulWidget {
|
||||||
with SafeSetState<EditMountScreen> {
|
final Mount mount;
|
||||||
|
const EditMountContent({super.key, required this.mount});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<EditMountContent> createState() => _EditMountContentState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _EditMountContentState extends State<EditMountContent>
|
||||||
|
with SafeSetState<EditMountContent> {
|
||||||
bool _showAdvanced = false;
|
bool _showAdvanced = false;
|
||||||
|
|
||||||
@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;
|
final textTheme = Theme.of(context).textTheme;
|
||||||
return AppScaffold(
|
|
||||||
title: widget.title,
|
return AppDialog(
|
||||||
showBack: true,
|
title:
|
||||||
advancedWidget: Row(
|
'${widget.mount.provider} Settings • ${formatMountName(widget.mount.type, widget.mount.name)}',
|
||||||
|
trailing: Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
@@ -38,22 +44,19 @@ class _EditMountScreenState extends State<EditMountScreen>
|
|||||||
const SizedBox(width: 6),
|
const SizedBox(width: 6),
|
||||||
IconButton(
|
IconButton(
|
||||||
tooltip: _showAdvanced ? 'Hide advanced' : 'Show advanced',
|
tooltip: _showAdvanced ? 'Hide advanced' : 'Show advanced',
|
||||||
icon: Icon(_showAdvanced ? Icons.toggle_on : Icons.toggle_off),
|
icon: Icon(
|
||||||
|
_showAdvanced ? constants.iconToggleOn : constants.iconToggleOff,
|
||||||
|
),
|
||||||
color: _showAdvanced ? scheme.primary : scheme.onSurface,
|
color: _showAdvanced ? scheme.primary : scheme.onSurface,
|
||||||
onPressed: () => setState(() => _showAdvanced = !_showAdvanced),
|
onPressed: () => setState(() => _showAdvanced = !_showAdvanced),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
children: [
|
child: MountSettingsWidget(
|
||||||
Expanded(
|
mount: widget.mount,
|
||||||
child: MountSettingsWidget(
|
settings: jsonDecode(jsonEncode(widget.mount.mountConfig.settings)),
|
||||||
mount: widget.mount,
|
showAdvanced: _showAdvanced,
|
||||||
settings: jsonDecode(jsonEncode(widget.mount.mountConfig.settings)),
|
),
|
||||||
showAdvanced: _showAdvanced,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(height: constants.padding),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9,45 +9,42 @@ 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/utils/safe_set_state_mixin.dart';
|
import 'package:repertory/utils/safe_set_state_mixin.dart';
|
||||||
import 'package:repertory/widgets/app_scaffold.dart';
|
import 'package:repertory/widgets/app_dialog.dart';
|
||||||
import 'package:repertory/widgets/ui_settings.dart';
|
import 'package:repertory/widgets/ui_settings.dart';
|
||||||
|
|
||||||
class EditSettingsScreen extends StatefulWidget {
|
/// Opens the "Portal Settings" modal dialog.
|
||||||
final String title;
|
Future<void> showPortalSettingsDialog(BuildContext context) {
|
||||||
const EditSettingsScreen({super.key, required this.title});
|
return doShowDialog(context, const PortalSettingsContent());
|
||||||
|
|
||||||
@override
|
|
||||||
State<EditSettingsScreen> createState() => _EditSettingsScreenState();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _EditSettingsScreenState extends State<EditSettingsScreen>
|
class PortalSettingsContent extends StatefulWidget {
|
||||||
with SafeSetState<EditSettingsScreen> {
|
const PortalSettingsContent({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<PortalSettingsContent> createState() => _PortalSettingsContentState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _PortalSettingsContentState extends State<PortalSettingsContent>
|
||||||
|
with SafeSetState<PortalSettingsContent> {
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return AppScaffold(
|
return AppDialog(
|
||||||
title: widget.title,
|
title: constants.appSettingsTitle,
|
||||||
showBack: true,
|
child: FutureBuilder<Map<String, dynamic>>(
|
||||||
showUISettings: true,
|
future: _grabSettings(),
|
||||||
children: [
|
initialData: const <String, dynamic>{},
|
||||||
Expanded(
|
builder: (context, snapshot) {
|
||||||
child: FutureBuilder<Map<String, dynamic>>(
|
if (!snapshot.hasData) {
|
||||||
future: _grabSettings(),
|
return const Center(child: CircularProgressIndicator());
|
||||||
initialData: const <String, dynamic>{},
|
}
|
||||||
builder: (context, snapshot) {
|
|
||||||
if (!snapshot.hasData) {
|
|
||||||
return const Center(child: CircularProgressIndicator());
|
|
||||||
}
|
|
||||||
|
|
||||||
return UISettingsWidget(
|
return UISettingsWidget(
|
||||||
origSettings: jsonDecode(jsonEncode(snapshot.requireData)),
|
origSettings: jsonDecode(jsonEncode(snapshot.requireData)),
|
||||||
settings: snapshot.requireData,
|
settings: snapshot.requireData,
|
||||||
showAdvanced: false,
|
showAdvanced: false,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
|
||||||
const SizedBox(height: constants.padding),
|
|
||||||
],
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:repertory/constants.dart' as constants;
|
import 'package:repertory/constants.dart' as constants;
|
||||||
|
import 'package:repertory/screens/add_mount_screen.dart';
|
||||||
import 'package:repertory/widgets/app_scaffold.dart';
|
import 'package:repertory/widgets/app_scaffold.dart';
|
||||||
import 'package:repertory/widgets/mount_list_widget.dart';
|
import 'package:repertory/widgets/mount_list_widget.dart';
|
||||||
|
|
||||||
@@ -26,7 +27,7 @@ class _HomeScreeState extends State<HomeScreen> {
|
|||||||
tag: 'add_mount_fab',
|
tag: 'add_mount_fab',
|
||||||
child: Material(
|
child: Material(
|
||||||
color: scheme.primary.withValues(alpha: constants.secondaryAlpha),
|
color: scheme.primary.withValues(alpha: constants.secondaryAlpha),
|
||||||
elevation: 12,
|
elevation: constants.fabElevation,
|
||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(constants.borderRadius),
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
),
|
),
|
||||||
@@ -37,7 +38,7 @@ class _HomeScreeState extends State<HomeScreen> {
|
|||||||
color: scheme.outlineVariant.withValues(
|
color: scheme.outlineVariant.withValues(
|
||||||
alpha: constants.outlineAlpha,
|
alpha: constants.outlineAlpha,
|
||||||
),
|
),
|
||||||
width: 1,
|
width: constants.borderWidth,
|
||||||
),
|
),
|
||||||
gradient: const LinearGradient(
|
gradient: const LinearGradient(
|
||||||
begin: Alignment.topCenter,
|
begin: Alignment.topCenter,
|
||||||
@@ -57,13 +58,13 @@ class _HomeScreeState extends State<HomeScreen> {
|
|||||||
child: InkWell(
|
child: InkWell(
|
||||||
borderRadius: BorderRadius.circular(constants.borderRadius),
|
borderRadius: BorderRadius.circular(constants.borderRadius),
|
||||||
onTap: () {
|
onTap: () {
|
||||||
Navigator.pushNamed(context, '/add');
|
showAddMountDialog(context);
|
||||||
},
|
},
|
||||||
child: const SizedBox(
|
child: const SizedBox(
|
||||||
width: 56,
|
width: constants.fabInnerSize,
|
||||||
height: 56,
|
height: constants.fabInnerSize,
|
||||||
child: Center(
|
child: Center(
|
||||||
child: Icon(Icons.add, size: constants.largeIconSize),
|
child: Icon(constants.iconAdd, size: constants.largeIconSize),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ void createBooleanSetting(
|
|||||||
widget,
|
widget,
|
||||||
Function setState, {
|
Function setState, {
|
||||||
String? description,
|
String? description,
|
||||||
IconData icon = Icons.quiz,
|
IconData icon = constants.iconToggleOn,
|
||||||
}) {
|
}) {
|
||||||
if (!isAdvanced || showAdvanced) {
|
if (!isAdvanced || showAdvanced) {
|
||||||
list.add(
|
list.add(
|
||||||
@@ -149,7 +149,7 @@ void createPasswordSetting(
|
|||||||
widget,
|
widget,
|
||||||
Function setState, {
|
Function setState, {
|
||||||
String? description,
|
String? description,
|
||||||
IconData icon = Icons.password,
|
IconData icon = constants.iconPassword,
|
||||||
List<Validator> validators = const [],
|
List<Validator> validators = const [],
|
||||||
}) {
|
}) {
|
||||||
if (!isAdvanced || widget.showAdvanced) {
|
if (!isAdvanced || widget.showAdvanced) {
|
||||||
@@ -222,8 +222,8 @@ void createPasswordSetting(
|
|||||||
),
|
),
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
hidePassword1
|
hidePassword1
|
||||||
? Icons.visibility
|
? constants.iconVisibility
|
||||||
: Icons.visibility_off,
|
: constants.iconVisibilityOff,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -0,0 +1,105 @@
|
|||||||
|
// app_dialog.dart
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:repertory/constants.dart' as constants;
|
||||||
|
|
||||||
|
/// A themed modal dialog shell that sizes to its content.
|
||||||
|
///
|
||||||
|
/// The width is sized between [constants.dialogMinWidthFactor] and
|
||||||
|
/// [constants.dialogMaxWidthFactor] of the viewport (clamped to the absolute
|
||||||
|
/// pixel bounds in [constants]). The dialog hugs its content vertically and
|
||||||
|
/// only begins scrolling once the content would exceed
|
||||||
|
/// [constants.dialogMaxHeightFactor] of the viewport. For this to work, the
|
||||||
|
/// content ([child]) must size itself to its intrinsic height (e.g. settings
|
||||||
|
/// lists built with `shrinkWrap: true`) rather than expanding to fill.
|
||||||
|
///
|
||||||
|
/// A fixed header row (title, optional [trailing] widget, close button) stays
|
||||||
|
/// pinned above the scrollable content.
|
||||||
|
class AppDialog extends StatelessWidget {
|
||||||
|
const AppDialog({
|
||||||
|
super.key,
|
||||||
|
required this.title,
|
||||||
|
required this.child,
|
||||||
|
this.trailing,
|
||||||
|
});
|
||||||
|
|
||||||
|
final String title;
|
||||||
|
final Widget child;
|
||||||
|
final Widget? trailing;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final scheme = Theme.of(context).colorScheme;
|
||||||
|
final textTheme = Theme.of(context).textTheme;
|
||||||
|
final media = MediaQuery.of(context).size;
|
||||||
|
|
||||||
|
final maxWidth = (media.width * constants.dialogMaxWidthFactor).clamp(
|
||||||
|
constants.dialogMinWidth,
|
||||||
|
constants.dialogMaxWidth,
|
||||||
|
);
|
||||||
|
final minWidth = (media.width * constants.dialogMinWidthFactor).clamp(
|
||||||
|
constants.dialogMinWidth,
|
||||||
|
maxWidth,
|
||||||
|
);
|
||||||
|
final maxHeight = media.height * constants.dialogMaxHeightFactor;
|
||||||
|
|
||||||
|
final header = Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
child: Text(
|
||||||
|
title,
|
||||||
|
maxLines: 1,
|
||||||
|
overflow: TextOverflow.ellipsis,
|
||||||
|
style: textTheme.titleLarge?.copyWith(
|
||||||
|
fontWeight: FontWeight.w700,
|
||||||
|
color: scheme.primary,
|
||||||
|
letterSpacing: 0.2,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
if (trailing != null) ...[
|
||||||
|
const SizedBox(width: constants.padding),
|
||||||
|
trailing!,
|
||||||
|
],
|
||||||
|
const SizedBox(width: constants.paddingSmall),
|
||||||
|
IconButton(
|
||||||
|
tooltip: 'Close',
|
||||||
|
icon: const Icon(constants.iconClose),
|
||||||
|
onPressed: () => Navigator.of(context).pop(),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
return Dialog(
|
||||||
|
insetPadding: const EdgeInsets.all(constants.padding),
|
||||||
|
child: ConstrainedBox(
|
||||||
|
constraints: BoxConstraints(
|
||||||
|
minWidth: minWidth,
|
||||||
|
maxWidth: maxWidth,
|
||||||
|
maxHeight: maxHeight,
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
// Tighter top/bottom than left/right so the dialog does not look
|
||||||
|
// vertically empty around the settings list.
|
||||||
|
padding: const EdgeInsets.symmetric(
|
||||||
|
horizontal: constants.padding,
|
||||||
|
vertical: constants.paddingSmall,
|
||||||
|
),
|
||||||
|
child: Column(
|
||||||
|
mainAxisSize: MainAxisSize.min,
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
|
children: [
|
||||||
|
header,
|
||||||
|
const SizedBox(height: constants.paddingSmall),
|
||||||
|
// Hug the content height; scroll only once it would exceed the
|
||||||
|
// dialog's max height.
|
||||||
|
Flexible(
|
||||||
|
child: SingleChildScrollView(child: child),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -94,7 +94,10 @@ class AppDropdown<T> extends StatelessWidget {
|
|||||||
|
|
||||||
final effectiveFill =
|
final effectiveFill =
|
||||||
fillColor ??
|
fillColor ??
|
||||||
darken(scheme.primary, 0.95).withValues(alpha: constants.dropDownAlpha);
|
Color.alphaBlend(
|
||||||
|
scheme.primary.withValues(alpha: constants.dialogTintAlpha),
|
||||||
|
constants.surfaceContainerLowDark,
|
||||||
|
);
|
||||||
|
|
||||||
final effectiveTextStyle =
|
final effectiveTextStyle =
|
||||||
textStyle ??
|
textStyle ??
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ class AppIconButtonFramed extends StatelessWidget {
|
|||||||
onTap: onPressed,
|
onTap: onPressed,
|
||||||
borderRadius: radius,
|
borderRadius: radius,
|
||||||
child: Ink(
|
child: Ink(
|
||||||
width: 46,
|
width: constants.framedControlSize,
|
||||||
height: 46,
|
height: constants.framedControlSize,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: scheme.primary.withValues(alpha: constants.outlineAlpha),
|
color: scheme.primary.withValues(alpha: constants.outlineAlpha),
|
||||||
borderRadius: radius,
|
borderRadius: radius,
|
||||||
@@ -35,7 +35,7 @@ class AppIconButtonFramed extends StatelessWidget {
|
|||||||
color: scheme.outlineVariant.withValues(
|
color: scheme.outlineVariant.withValues(
|
||||||
alpha: constants.outlineAlpha,
|
alpha: constants.outlineAlpha,
|
||||||
),
|
),
|
||||||
width: 1,
|
width: constants.borderWidth,
|
||||||
),
|
),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ 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/models/settings.dart';
|
||||||
|
import 'package:repertory/screens/edit_settings_screen.dart';
|
||||||
import 'package:repertory/widgets/aurora_sweep.dart';
|
import 'package:repertory/widgets/aurora_sweep.dart';
|
||||||
|
|
||||||
class AppScaffold extends StatelessWidget {
|
class AppScaffold extends StatelessWidget {
|
||||||
@@ -67,14 +68,14 @@ class AppScaffold extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
if (!showBack) ...[
|
if (!showBack) ...[
|
||||||
SizedBox(
|
SizedBox(
|
||||||
width: 40,
|
width: constants.headerControlSize,
|
||||||
height: 40,
|
height: constants.headerControlSize,
|
||||||
child: Image.asset(
|
child: Image.asset(
|
||||||
'assets/images/repertory.png',
|
'assets/images/repertory.png',
|
||||||
fit: BoxFit.contain,
|
fit: BoxFit.contain,
|
||||||
errorBuilder: (_, _, _) {
|
errorBuilder: (_, _, _) {
|
||||||
return Icon(
|
return Icon(
|
||||||
Icons.folder,
|
constants.iconFolder,
|
||||||
color: scheme.primary,
|
color: scheme.primary,
|
||||||
size: constants.largeIconSize,
|
size: constants.largeIconSize,
|
||||||
);
|
);
|
||||||
@@ -92,8 +93,8 @@ class AppScaffold extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
onTap: () => Navigator.of(context).pop(),
|
onTap: () => Navigator.of(context).pop(),
|
||||||
child: Ink(
|
child: Ink(
|
||||||
width: 40,
|
width: constants.headerControlSize,
|
||||||
height: 40,
|
height: constants.headerControlSize,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: scheme.surface.withValues(
|
color: scheme.surface.withValues(
|
||||||
alpha: constants.secondaryAlpha,
|
alpha: constants.secondaryAlpha,
|
||||||
@@ -105,7 +106,7 @@ class AppScaffold extends StatelessWidget {
|
|||||||
color: scheme.outlineVariant.withValues(
|
color: scheme.outlineVariant.withValues(
|
||||||
alpha: constants.highlightAlpha,
|
alpha: constants.highlightAlpha,
|
||||||
),
|
),
|
||||||
width: 1,
|
width: constants.borderWidth,
|
||||||
),
|
),
|
||||||
boxShadow: [
|
boxShadow: [
|
||||||
BoxShadow(
|
BoxShadow(
|
||||||
@@ -117,7 +118,7 @@ class AppScaffold extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
child: const Icon(Icons.arrow_back),
|
child: Icon(constants.iconBack),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@@ -141,8 +142,8 @@ class AppScaffold extends StatelessWidget {
|
|||||||
builder: (context, settings, _) => IconButton(
|
builder: (context, settings, _) => IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
settings.enableAnimations
|
settings.enableAnimations
|
||||||
? Icons.toggle_on
|
? constants.iconToggleOn
|
||||||
: Icons.toggle_off,
|
: constants.iconToggleOff,
|
||||||
),
|
),
|
||||||
color: settings.enableAnimations
|
color: settings.enableAnimations
|
||||||
? scheme.primary
|
? scheme.primary
|
||||||
@@ -157,8 +158,8 @@ class AppScaffold extends StatelessWidget {
|
|||||||
builder: (context, settings, _) => IconButton(
|
builder: (context, settings, _) => IconButton(
|
||||||
icon: Icon(
|
icon: Icon(
|
||||||
settings.autoStart
|
settings.autoStart
|
||||||
? Icons.toggle_on
|
? constants.iconToggleOn
|
||||||
: Icons.toggle_off,
|
: constants.iconToggleOff,
|
||||||
),
|
),
|
||||||
color: settings.autoStart
|
color: settings.autoStart
|
||||||
? scheme.primary
|
? scheme.primary
|
||||||
@@ -175,7 +176,7 @@ class AppScaffold extends StatelessWidget {
|
|||||||
tooltip: 'Settings',
|
tooltip: 'Settings',
|
||||||
icon: const Icon(Icons.settings),
|
icon: const Icon(Icons.settings),
|
||||||
onPressed: () {
|
onPressed: () {
|
||||||
Navigator.pushNamed(context, '/settings');
|
showPortalSettingsDialog(context);
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
const SizedBox(width: constants.padding),
|
const SizedBox(width: constants.padding),
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
// app_toggle_button_framed.dart
|
// app_toggle_button_framed.dart
|
||||||
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:repertory/constants.dart' as constants;
|
||||||
import 'package:repertory/widgets/app_icon_button_framed.dart';
|
import 'package:repertory/widgets/app_icon_button_framed.dart';
|
||||||
|
|
||||||
class AppToggleButtonFramed extends StatelessWidget {
|
class AppToggleButtonFramed extends StatelessWidget {
|
||||||
@@ -22,7 +23,7 @@ class AppToggleButtonFramed extends StatelessWidget {
|
|||||||
Color iconColor = scheme.onSurface;
|
Color iconColor = scheme.onSurface;
|
||||||
|
|
||||||
if (mounted != null) {
|
if (mounted != null) {
|
||||||
icon = isOn ? Icons.toggle_on : Icons.toggle_off;
|
icon = isOn ? constants.iconToggleOn : constants.iconToggleOff;
|
||||||
iconColor = isOn ? scheme.primary : scheme.onSurface;
|
iconColor = isOn ? scheme.primary : scheme.onSurface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
|
|||||||
widget.settings,
|
widget.settings,
|
||||||
key,
|
key,
|
||||||
value,
|
value,
|
||||||
Icons.person,
|
constants.iconUser,
|
||||||
true,
|
true,
|
||||||
widget.showAdvanced,
|
widget.showAdvanced,
|
||||||
widget,
|
widget,
|
||||||
@@ -389,11 +389,11 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
|
|||||||
|
|
||||||
final titleStyle = theme.textTheme.titleLarge?.copyWith(
|
final titleStyle = theme.textTheme.titleLarge?.copyWith(
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w700,
|
||||||
color: scheme.onSurface,
|
color: scheme.primary,
|
||||||
);
|
);
|
||||||
|
|
||||||
return SettingsList(
|
return SettingsList(
|
||||||
shrinkWrap: false,
|
shrinkWrap: true,
|
||||||
platform: DevicePlatform.web,
|
platform: DevicePlatform.web,
|
||||||
lightTheme: settingsTheme,
|
lightTheme: settingsTheme,
|
||||||
darkTheme: settingsTheme,
|
darkTheme: settingsTheme,
|
||||||
@@ -840,6 +840,7 @@ class _MountSettingsWidgetState extends State<MountSettingsWidget> {
|
|||||||
widget,
|
widget,
|
||||||
setState,
|
setState,
|
||||||
description: getSettingDescription('$key.$subKey'),
|
description: getSettingDescription('$key.$subKey'),
|
||||||
|
icon: constants.iconRemoteMount,
|
||||||
);
|
);
|
||||||
remoteMountSettings.insertAll(0, tempSettings);
|
remoteMountSettings.insertAll(0, tempSettings);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ 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/mount.dart';
|
import 'package:repertory/models/mount.dart';
|
||||||
|
import 'package:repertory/screens/edit_mount_screen.dart';
|
||||||
import 'package:repertory/utils/safe_set_state_mixin.dart';
|
import 'package:repertory/utils/safe_set_state_mixin.dart';
|
||||||
import 'package:repertory/widgets/app_outlined_icon_button.dart';
|
import 'package:repertory/widgets/app_outlined_icon_button.dart';
|
||||||
import 'package:repertory/widgets/app_icon_button_framed.dart';
|
import 'package:repertory/widgets/app_icon_button_framed.dart';
|
||||||
@@ -40,20 +41,10 @@ class _MountWidgetState extends State<MountWidget>
|
|||||||
);
|
);
|
||||||
|
|
||||||
return ConstrainedBox(
|
return ConstrainedBox(
|
||||||
constraints: const BoxConstraints(minHeight: 120),
|
constraints: const BoxConstraints(minHeight: constants.mountCardMinHeight),
|
||||||
child: Card(
|
child: Card(
|
||||||
margin: const EdgeInsets.all(0.0),
|
margin: const EdgeInsets.all(0.0),
|
||||||
elevation: 12,
|
|
||||||
color: scheme.primary.withValues(alpha: constants.primaryAlpha),
|
color: scheme.primary.withValues(alpha: constants.primaryAlpha),
|
||||||
shape: RoundedRectangleBorder(
|
|
||||||
borderRadius: BorderRadius.circular(constants.borderRadiusSmall),
|
|
||||||
side: BorderSide(
|
|
||||||
color: scheme.outlineVariant.withValues(
|
|
||||||
alpha: constants.outlineAlpha,
|
|
||||||
),
|
|
||||||
width: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
child: Padding(
|
child: Padding(
|
||||||
padding: const EdgeInsets.all(constants.padding),
|
padding: const EdgeInsets.all(constants.padding),
|
||||||
child: Consumer<Mount>(
|
child: Consumer<Mount>(
|
||||||
@@ -66,12 +57,8 @@ class _MountWidgetState extends State<MountWidget>
|
|||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
children: [
|
children: [
|
||||||
AppIconButtonFramed(
|
AppIconButtonFramed(
|
||||||
icon: Icons.settings,
|
icon: constants.iconSettings,
|
||||||
onPressed: () => Navigator.pushNamed(
|
onPressed: () => showEditMountDialog(context, mount),
|
||||||
context,
|
|
||||||
'/edit',
|
|
||||||
arguments: mount,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
const SizedBox(width: constants.padding),
|
const SizedBox(width: constants.padding),
|
||||||
Expanded(
|
Expanded(
|
||||||
@@ -88,13 +75,13 @@ class _MountWidgetState extends State<MountWidget>
|
|||||||
),
|
),
|
||||||
if (mount.mounted == false) ...[
|
if (mount.mounted == false) ...[
|
||||||
AppIconButtonFramed(
|
AppIconButtonFramed(
|
||||||
icon: Icons.delete,
|
icon: constants.iconDelete,
|
||||||
onPressed: _enabled
|
onPressed: _enabled
|
||||||
? () async {
|
? () {
|
||||||
setState(() {
|
setState(() {
|
||||||
_enabled = false;
|
_enabled = false;
|
||||||
});
|
});
|
||||||
return doShowDialog(
|
doShowDialog(
|
||||||
context,
|
context,
|
||||||
AlertDialog(
|
AlertDialog(
|
||||||
actions: [
|
actions: [
|
||||||
@@ -102,6 +89,9 @@ class _MountWidgetState extends State<MountWidget>
|
|||||||
child: const Text('Yes'),
|
child: const Text('Yes'),
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
await mount.remove();
|
await mount.remove();
|
||||||
|
if (!context.mounted) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
setState(() {
|
setState(() {
|
||||||
_enabled = true;
|
_enabled = true;
|
||||||
});
|
});
|
||||||
@@ -140,7 +130,7 @@ class _MountWidgetState extends State<MountWidget>
|
|||||||
children: [
|
children: [
|
||||||
AppOutlinedIconButton(
|
AppOutlinedIconButton(
|
||||||
text: 'Edit path',
|
text: 'Edit path',
|
||||||
icon: Icons.edit,
|
icon: constants.iconEdit,
|
||||||
enabled: _enabled && mount.mounted == false,
|
enabled: _enabled && mount.mounted == false,
|
||||||
onPressed: () async {
|
onPressed: () async {
|
||||||
setState(() {
|
setState(() {
|
||||||
@@ -211,7 +201,7 @@ class _MountWidgetState extends State<MountWidget>
|
|||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: MainAxisSize.min,
|
||||||
children: const [
|
children: const [
|
||||||
Icon(
|
Icon(
|
||||||
Icons.auto_mode,
|
constants.iconAutoMount,
|
||||||
size: constants.smallIconSize,
|
size: constants.smallIconSize,
|
||||||
),
|
),
|
||||||
SizedBox(width: constants.paddingSmall),
|
SizedBox(width: constants.paddingSmall),
|
||||||
|
|||||||
@@ -1,11 +1,13 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_settings_ui/src/sections/abstract_settings_section.dart';
|
import 'package:flutter_settings_ui/flutter_settings_ui.dart';
|
||||||
import 'package:flutter_settings_ui/src/sections/platforms/android_settings_section.dart';
|
|
||||||
import 'package:flutter_settings_ui/src/sections/platforms/ios_settings_section.dart';
|
|
||||||
import 'package:repertory/widgets/settings/web_settings_section.dart';
|
import 'package:repertory/widgets/settings/web_settings_section.dart';
|
||||||
import 'package:flutter_settings_ui/src/tiles/abstract_settings_tile.dart';
|
// These platform section widgets are not re-exported by the public barrel, so
|
||||||
import 'package:flutter_settings_ui/src/utils/platform_utils.dart';
|
// they must be imported directly. They are only reached on non-web platforms;
|
||||||
import 'package:flutter_settings_ui/src/utils/settings_theme.dart';
|
// this app targets web, but the switch below handles them for completeness.
|
||||||
|
// ignore: implementation_imports
|
||||||
|
import 'package:flutter_settings_ui/src/sections/platforms/android_settings_section.dart';
|
||||||
|
// ignore: implementation_imports
|
||||||
|
import 'package:flutter_settings_ui/src/sections/platforms/ios_settings_section.dart';
|
||||||
|
|
||||||
class SettingsSection extends AbstractSettingsSection {
|
class SettingsSection extends AbstractSettingsSection {
|
||||||
const SettingsSection({
|
const SettingsSection({
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_settings_ui/flutter_settings_ui.dart';
|
import 'package:flutter_settings_ui/flutter_settings_ui.dart';
|
||||||
|
import 'package:repertory/constants.dart' as constants;
|
||||||
|
|
||||||
// Container(
|
// Container(
|
||||||
// height: 65 * scaleFactor,
|
// height: 65 * scaleFactor,
|
||||||
@@ -30,7 +31,6 @@ class WebSettingsSection extends StatelessWidget {
|
|||||||
|
|
||||||
Widget buildSectionBody(BuildContext context) {
|
Widget buildSectionBody(BuildContext context) {
|
||||||
final theme = SettingsTheme.of(context);
|
final theme = SettingsTheme.of(context);
|
||||||
final scaleFactor = MediaQuery.textScalerOf(context).scale(1);
|
|
||||||
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: margin ?? EdgeInsets.zero,
|
padding: margin ?? EdgeInsets.zero,
|
||||||
@@ -39,10 +39,10 @@ class WebSettingsSection extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
if (title != null)
|
if (title != null)
|
||||||
Padding(
|
Padding(
|
||||||
padding: EdgeInsetsDirectional.only(
|
padding: const EdgeInsetsDirectional.only(
|
||||||
bottom: 5 * scaleFactor,
|
bottom: constants.paddingSmall,
|
||||||
start: 6,
|
start: 6,
|
||||||
top: 20 * scaleFactor,
|
top: constants.paddingSmall,
|
||||||
),
|
),
|
||||||
child: title!,
|
child: title!,
|
||||||
),
|
),
|
||||||
@@ -50,7 +50,7 @@ class WebSettingsSection extends StatelessWidget {
|
|||||||
shape: RoundedRectangleBorder(
|
shape: RoundedRectangleBorder(
|
||||||
borderRadius: BorderRadius.circular(10),
|
borderRadius: BorderRadius.circular(10),
|
||||||
),
|
),
|
||||||
elevation: 4,
|
elevation: constants.cardElevation,
|
||||||
color: theme.themeData.settingsSectionBackground,
|
color: theme.themeData.settingsSectionBackground,
|
||||||
child: buildTileList(),
|
child: buildTileList(),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -94,7 +94,7 @@ class _UISettingsWidgetState extends State<UISettingsWidget>
|
|||||||
widget.settings,
|
widget.settings,
|
||||||
key,
|
key,
|
||||||
value,
|
value,
|
||||||
Icons.person,
|
constants.iconUser,
|
||||||
false,
|
false,
|
||||||
widget.showAdvanced,
|
widget.showAdvanced,
|
||||||
widget,
|
widget,
|
||||||
@@ -109,11 +109,11 @@ class _UISettingsWidgetState extends State<UISettingsWidget>
|
|||||||
|
|
||||||
final titleStyle = theme.textTheme.titleLarge?.copyWith(
|
final titleStyle = theme.textTheme.titleLarge?.copyWith(
|
||||||
fontWeight: FontWeight.w700,
|
fontWeight: FontWeight.w700,
|
||||||
color: scheme.onSurface,
|
color: scheme.primary,
|
||||||
);
|
);
|
||||||
|
|
||||||
return SettingsList(
|
return SettingsList(
|
||||||
shrinkWrap: false,
|
shrinkWrap: true,
|
||||||
platform: DevicePlatform.web,
|
platform: DevicePlatform.web,
|
||||||
lightTheme: settingsTheme,
|
lightTheme: settingsTheme,
|
||||||
darkTheme: settingsTheme,
|
darkTheme: settingsTheme,
|
||||||
|
|||||||
Reference in new issue
Block a user