chore(mobile): move settings components to UI package (#31272)

This commit is contained in:
Adam Gastineau
2026-09-04 12:06:01 -07:00
committed by GitHub
parent a6d43828f6
commit 4c7b30c18b
34 changed files with 134 additions and 147 deletions
@@ -1,67 +1,2 @@
import 'package:flutter/material.dart';
extension ContextHelper on BuildContext {
// Returns the current padding from MediaQuery
EdgeInsets get padding => MediaQuery.paddingOf(this);
// Returns the current view insets from MediaQuery
EdgeInsets get viewInsets => MediaQuery.viewInsetsOf(this);
// Returns the current width from MediaQuery
double get width => MediaQuery.sizeOf(this).width;
// Returns the current height from MediaQuery
double get height => MediaQuery.sizeOf(this).height;
// Returns the current size from MediaQuery
Size get sizeData => MediaQuery.sizeOf(this);
// Returns true if the app is running on a mobile device (!tablets)
bool get isMobile => width < 550;
// Returns the current device pixel ratio from MediaQuery
double get devicePixelRatio => MediaQuery.devicePixelRatioOf(this);
// Returns the current orientation from MediaQuery
Orientation get orientation => MediaQuery.orientationOf(this);
// Returns the current platform brightness from MediaQuery
Brightness get platformBrightness => MediaQuery.platformBrightnessOf(this);
// Returns the current ThemeData
ThemeData get themeData => Theme.of(this);
// Returns true if the app is using a dark theme
bool get isDarkTheme => themeData.brightness == Brightness.dark;
// Returns the current Primary color of the Theme
Color get primaryColor => themeData.colorScheme.primary;
Color get logoYellow => const Color.fromARGB(255, 255, 184, 0);
Color get logoRed => const Color.fromARGB(255, 230, 65, 30);
Color get logoPink => const Color.fromARGB(255, 222, 127, 179);
Color get logoGreen => const Color.fromARGB(255, 49, 164, 82);
// Returns the Scaffold background color of the Theme
Color get scaffoldBackgroundColor => colorScheme.surface;
// Returns the current TextTheme
TextTheme get textTheme => themeData.textTheme;
// Current ColorScheme used
ColorScheme get colorScheme => themeData.colorScheme;
// Navigate by pushing or popping routes from the current context
NavigatorState get navigator => Navigator.of(this);
// Showing material banners from the current context
ScaffoldMessengerState get scaffoldMessenger => ScaffoldMessenger.of(this);
// Pop-out from the current context with optional result
void pop<T>([T? result]) => Navigator.of(this).pop(result);
// Managing focus within the widget tree from the current context
FocusScopeNode get focusScope => FocusScope.of(this);
// Show SnackBars from the current context
void showSnackBar(SnackBar snackBar) => ScaffoldMessenger.of(this).showSnackBar(snackBar);
}
// TODO: Remove
export 'package:immich_ui/extensions/build_context_extensions.dart';
+2 -16
View File
@@ -1,16 +1,2 @@
import 'package:flutter/material.dart';
extension ImmichColorSchemeExtensions on ColorScheme {
bool get _isDarkMode => brightness == Brightness.dark;
Color get onSurfaceSecondary => _isDarkMode ? onSurface.darken(amount: .3) : onSurface.lighten(amount: .3);
}
extension ColorExtensions on Color {
Color lighten({double amount = 0.1}) {
return Color.alphaBlend(Colors.white.withValues(alpha: amount), this);
}
Color darken({double amount = 0.1}) {
return Color.alphaBlend(Colors.black.withValues(alpha: amount), this);
}
}
// TODO: Remove
export 'package:immich_ui/extensions/theme_extensions.dart';
+4 -4
View File
@@ -14,7 +14,7 @@ import 'package:immich_mobile/widgets/settings/language_settings.dart';
import 'package:immich_mobile/widgets/settings/networking_settings/networking_settings.dart';
import 'package:immich_mobile/widgets/settings/notification_setting.dart';
import 'package:immich_mobile/widgets/settings/preference_settings/preference_setting.dart';
import 'package:immich_mobile/widgets/settings/settings_card.dart';
import 'package:immich_ui/immich_ui.dart';
enum SettingSection {
advanced(Icons.build_outlined),
@@ -97,7 +97,7 @@ class _MobileLayout extends StatelessWidget {
icon: Icons.sync_outlined,
title: context.t.sync_status,
subtitle: context.t.sync_status_subtitle,
settingRoute: const SyncStatusRoute(),
onTap: () => context.pushRoute(const SyncStatusRoute()),
),
]
: [
@@ -105,7 +105,7 @@ class _MobileLayout extends StatelessWidget {
title: setting.title(context.t),
subtitle: setting.subtitle(context.t),
icon: setting.icon,
settingRoute: SettingsSubRoute(section: setting),
onTap: () => context.pushRoute(SettingsSubRoute(section: setting)),
),
],
)
@@ -115,7 +115,7 @@ class _MobileLayout extends StatelessWidget {
icon: Icons.auto_awesome_outlined,
title: context.t.whats_new,
subtitle: context.t.whats_new_settings_subtitle,
settingRoute: const WhatsNewRoute(),
onTap: () => context.pushRoute(const WhatsNewRoute()),
),
);
return ListView(padding: const EdgeInsets.only(top: 10.0, bottom: 60), children: [...settings]);
@@ -16,11 +16,8 @@ import 'package:immich_mobile/services/app_settings.service.dart';
import 'package:immich_mobile/utils/bytes_units.dart';
import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart';
import 'package:immich_mobile/widgets/settings/custom_proxy_headers_settings/custom_proxy_headers_settings.dart';
import 'package:immich_mobile/widgets/settings/settings_action_tile.dart';
import 'package:immich_mobile/widgets/settings/settings_slider_list_tile.dart';
import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart';
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
import 'package:immich_mobile/widgets/settings/ssl_client_cert_settings.dart';
import 'package:immich_ui/immich_ui.dart';
import 'package:logging/logging.dart';
class AdvancedSettings extends HookConsumerWidget {
@@ -8,8 +8,7 @@ import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/providers/app_settings.provider.dart';
import 'package:immich_mobile/providers/infrastructure/settings.provider.dart';
import 'package:immich_mobile/providers/infrastructure/timeline.provider.dart';
import 'package:immich_mobile/widgets/settings/setting_group_title.dart';
import 'package:immich_mobile/widgets/settings/settings_radio_list_tile.dart';
import 'package:immich_ui/immich_ui.dart';
class GroupSettings extends HookConsumerWidget {
const GroupSettings({super.key});
@@ -6,8 +6,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/providers/app_settings.provider.dart';
import 'package:immich_mobile/providers/infrastructure/settings.provider.dart';
import 'package:immich_mobile/widgets/settings/setting_group_title.dart';
import 'package:immich_mobile/widgets/settings/settings_slider_list_tile.dart';
import 'package:immich_ui/immich_ui.dart';
class LayoutSettings extends HookConsumerWidget {
const LayoutSettings({super.key});
@@ -8,8 +8,7 @@ import 'package:immich_mobile/providers/app_settings.provider.dart';
import 'package:immich_mobile/providers/infrastructure/settings.provider.dart';
import 'package:immich_mobile/widgets/settings/asset_list_settings/asset_list_group_settings.dart';
import 'package:immich_mobile/widgets/settings/asset_list_settings/asset_list_layout_settings.dart';
import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart';
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
import 'package:immich_ui/immich_ui.dart';
class AssetListSettings extends HookConsumerWidget {
const AssetListSettings({super.key});
@@ -3,7 +3,7 @@ import 'package:immich_mobile/widgets/settings/asset_viewer_settings/image_viewe
import 'package:immich_mobile/widgets/settings/asset_viewer_settings/image_viewer_tap_to_navigate_setting.dart';
import 'package:immich_mobile/widgets/settings/asset_viewer_settings/slideshow_settings.dart';
import 'package:immich_mobile/widgets/settings/asset_viewer_settings/video_viewer_settings.dart';
import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart';
import 'package:immich_ui/immich_ui.dart';
class AssetViewerSettings extends StatelessWidget {
const AssetViewerSettings({super.key});
@@ -6,8 +6,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/providers/app_settings.provider.dart';
import 'package:immich_mobile/providers/infrastructure/settings.provider.dart';
import 'package:immich_mobile/widgets/settings/setting_group_title.dart';
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
import 'package:immich_ui/immich_ui.dart';
class ImageViewerQualitySetting extends HookConsumerWidget {
const ImageViewerQualitySetting({super.key});
@@ -5,8 +5,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/providers/infrastructure/settings.provider.dart';
import 'package:immich_mobile/widgets/settings/settings_sub_title.dart';
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
import 'package:immich_ui/immich_ui.dart';
class ImageViewerTapToNavigateSetting extends HookConsumerWidget {
const ImageViewerTapToNavigateSetting({super.key});
@@ -6,11 +6,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/constants/enums.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/providers/infrastructure/settings.provider.dart';
import 'package:immich_mobile/widgets/settings/setting_group_title.dart';
import 'package:immich_mobile/widgets/settings/settings_radio_list_tile.dart';
import 'package:immich_mobile/widgets/settings/settings_slider_list_tile.dart';
import 'package:immich_mobile/widgets/settings/settings_sub_title.dart';
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
import 'package:immich_ui/immich_ui.dart';
class SlideshowSettings extends HookConsumerWidget {
const SlideshowSettings({super.key});
@@ -5,8 +5,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/providers/infrastructure/settings.provider.dart';
import 'package:immich_mobile/widgets/settings/setting_group_title.dart';
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
import 'package:immich_ui/immich_ui.dart';
class VideoViewerSettings extends HookConsumerWidget {
const VideoViewerSettings({super.key});
@@ -14,9 +14,7 @@ import 'package:immich_mobile/providers/backup/backup_album.provider.dart';
import 'package:immich_mobile/providers/infrastructure/platform.provider.dart';
import 'package:immich_mobile/providers/infrastructure/settings.provider.dart';
import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/widgets/settings/setting_group_title.dart';
import 'package:immich_mobile/widgets/settings/setting_list_tile.dart';
import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart';
import 'package:immich_ui/immich_ui.dart';
class BackupSettings extends StatelessWidget {
const BackupSettings({super.key});
@@ -20,8 +20,7 @@ import 'package:immich_mobile/providers/server_info.provider.dart';
import 'package:immich_mobile/providers/sync_status.provider.dart';
import 'package:immich_mobile/services/app_settings.service.dart';
import 'package:immich_mobile/widgets/settings/beta_sync_settings/entity_count_tile.dart';
import 'package:immich_mobile/widgets/settings/setting_group_title.dart';
import 'package:immich_mobile/widgets/settings/setting_list_tile.dart';
import 'package:immich_ui/immich_ui.dart';
import 'package:path/path.dart' as path;
import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart';
@@ -11,8 +11,7 @@ import 'package:immich_mobile/providers/network.provider.dart';
import 'package:immich_mobile/utils/url_helper.dart';
import 'package:immich_mobile/widgets/settings/networking_settings/external_network_preference.dart';
import 'package:immich_mobile/widgets/settings/networking_settings/local_network_preference.dart';
import 'package:immich_mobile/widgets/settings/setting_group_title.dart';
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
import 'package:immich_ui/immich_ui.dart';
class NetworkingSettings extends HookConsumerWidget {
const NetworkingSettings({super.key});
@@ -5,8 +5,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/providers/permission.provider.dart';
import 'package:immich_mobile/widgets/settings/settings_button_list_tile.dart';
import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart';
import 'package:immich_ui/immich_ui.dart';
import 'package:permission_handler/permission_handler.dart';
class NotificationSetting extends HookConsumerWidget {
@@ -3,8 +3,7 @@ import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/services/app_settings.service.dart';
import 'package:immich_mobile/utils/hooks/app_settings_update_hook.dart';
import 'package:immich_mobile/widgets/settings/setting_group_title.dart';
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
import 'package:immich_ui/immich_ui.dart';
class HapticSetting extends HookWidget {
const HapticSetting({super.key});
@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:immich_mobile/widgets/settings/preference_settings/haptic_setting.dart';
import 'package:immich_mobile/widgets/settings/preference_settings/share_setting.dart';
import 'package:immich_mobile/widgets/settings/preference_settings/theme_setting.dart';
import 'package:immich_mobile/widgets/settings/settings_sub_page_scaffold.dart';
import 'package:immich_ui/immich_ui.dart';
class PreferenceSetting extends StatelessWidget {
const PreferenceSetting({super.key});
@@ -8,8 +8,7 @@ import 'package:immich_mobile/domain/models/settings_key.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/providers/infrastructure/settings.provider.dart';
import 'package:immich_mobile/widgets/settings/setting_group_title.dart';
import 'package:immich_mobile/widgets/settings/settings_radio_list_tile.dart';
import 'package:immich_ui/immich_ui.dart';
class ShareSetting extends HookConsumerWidget {
const ShareSetting({super.key});
@@ -7,8 +7,7 @@ import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/generated/translations.g.dart';
import 'package:immich_mobile/providers/infrastructure/settings.provider.dart';
import 'package:immich_mobile/widgets/settings/preference_settings/primary_color_setting.dart';
import 'package:immich_mobile/widgets/settings/setting_group_title.dart';
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.dart';
import 'package:immich_ui/immich_ui.dart';
class ThemeSetting extends HookConsumerWidget {
const ThemeSetting({super.key});
@@ -0,0 +1,67 @@
import 'package:flutter/material.dart';
extension ContextHelper on BuildContext {
// Returns the current padding from MediaQuery
EdgeInsets get padding => MediaQuery.paddingOf(this);
// Returns the current view insets from MediaQuery
EdgeInsets get viewInsets => MediaQuery.viewInsetsOf(this);
// Returns the current width from MediaQuery
double get width => MediaQuery.sizeOf(this).width;
// Returns the current height from MediaQuery
double get height => MediaQuery.sizeOf(this).height;
// Returns the current size from MediaQuery
Size get sizeData => MediaQuery.sizeOf(this);
// Returns true if the app is running on a mobile device (!tablets)
bool get isMobile => width < 550;
// Returns the current device pixel ratio from MediaQuery
double get devicePixelRatio => MediaQuery.devicePixelRatioOf(this);
// Returns the current orientation from MediaQuery
Orientation get orientation => MediaQuery.orientationOf(this);
// Returns the current platform brightness from MediaQuery
Brightness get platformBrightness => MediaQuery.platformBrightnessOf(this);
// Returns the current ThemeData
ThemeData get themeData => Theme.of(this);
// Returns true if the app is using a dark theme
bool get isDarkTheme => themeData.brightness == Brightness.dark;
// Returns the current Primary color of the Theme
Color get primaryColor => themeData.colorScheme.primary;
Color get logoYellow => const Color.fromARGB(255, 255, 184, 0);
Color get logoRed => const Color.fromARGB(255, 230, 65, 30);
Color get logoPink => const Color.fromARGB(255, 222, 127, 179);
Color get logoGreen => const Color.fromARGB(255, 49, 164, 82);
// Returns the Scaffold background color of the Theme
Color get scaffoldBackgroundColor => colorScheme.surface;
// Returns the current TextTheme
TextTheme get textTheme => themeData.textTheme;
// Current ColorScheme used
ColorScheme get colorScheme => themeData.colorScheme;
// Navigate by pushing or popping routes from the current context
NavigatorState get navigator => Navigator.of(this);
// Showing material banners from the current context
ScaffoldMessengerState get scaffoldMessenger => ScaffoldMessenger.of(this);
// Pop-out from the current context with optional result
void pop<T>([T? result]) => Navigator.of(this).pop(result);
// Managing focus within the widget tree from the current context
FocusScopeNode get focusScope => FocusScope.of(this);
// Show SnackBars from the current context
void showSnackBar(SnackBar snackBar) => ScaffoldMessenger.of(this).showSnackBar(snackBar);
}
@@ -0,0 +1,16 @@
import 'package:flutter/material.dart';
extension ImmichColorSchemeExtensions on ColorScheme {
bool get _isDarkMode => brightness == Brightness.dark;
Color get onSurfaceSecondary => _isDarkMode ? onSurface.darken(amount: .3) : onSurface.lighten(amount: .3);
}
extension ColorExtensions on Color {
Color lighten({double amount = 0.1}) {
return Color.alphaBlend(Colors.white.withValues(alpha: amount), this);
}
Color darken({double amount = 0.1}) {
return Color.alphaBlend(Colors.black.withValues(alpha: amount), this);
}
}
+1
View File
@@ -7,6 +7,7 @@ export 'src/components/formatted_text.dart';
export 'src/components/icon_button.dart';
export 'src/components/menu_item.dart';
export 'src/components/password_input.dart';
export 'src/components/settings/settings.dart';
export 'src/components/text_button.dart';
export 'src/components/text_input.dart';
export 'src/components/url_input.dart';
@@ -1,6 +1,6 @@
import 'package:flutter/widgets.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_ui/extensions/build_context_extensions.dart';
import 'package:immich_ui/extensions/theme_extensions.dart';
class SettingGroupTitle extends StatelessWidget {
final String title;
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_ui/extensions/build_context_extensions.dart';
class SettingListTile extends StatelessWidget {
final String title;
@@ -0,0 +1,10 @@
export 'setting_group_title.dart';
export 'setting_list_tile.dart';
export 'settings_action_tile.dart';
export 'settings_button_list_tile.dart';
export 'settings_card.dart';
export 'settings_radio_list_tile.dart';
export 'settings_slider_list_tile.dart';
export 'settings_sub_page_scaffold.dart';
export 'settings_sub_title.dart';
export 'settings_switch_list_tile.dart';
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_ui/extensions/theme_extensions.dart';
class SettingsActionTile extends StatelessWidget {
const SettingsActionTile({
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_ui/extensions/build_context_extensions.dart';
import 'package:immich_ui/extensions/theme_extensions.dart';
class SettingsButtonListTile extends StatelessWidget {
final IconData icon;
@@ -1,20 +1,13 @@
import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_ui/extensions/build_context_extensions.dart';
class SettingsCard extends StatelessWidget {
const SettingsCard({
super.key,
required this.icon,
required this.title,
required this.subtitle,
required this.settingRoute,
});
const SettingsCard({super.key, required this.icon, required this.title, required this.subtitle, required this.onTap});
final IconData icon;
final String title;
final String subtitle;
final PageRouteInfo settingRoute;
final Function() onTap;
@override
Widget build(BuildContext context) {
@@ -38,7 +31,7 @@ class SettingsCard extends StatelessWidget {
),
title: Text(title, style: context.textTheme.titleMedium!.copyWith(color: context.primaryColor)),
subtitle: Text(subtitle, style: context.textTheme.bodyMedium),
onTap: () => context.pushRoute(settingRoute),
onTap: onTap,
),
),
);
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_ui/extensions/build_context_extensions.dart';
class SettingsRadioGroup<T> {
final String title;
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_ui/extensions/build_context_extensions.dart';
class SettingsSliderListTile extends StatelessWidget {
final ValueNotifier<int> valueNotifier;
@@ -1,5 +1,5 @@
import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_ui/extensions/build_context_extensions.dart';
class SettingsSubTitle extends StatelessWidget {
final String title;
@@ -1,6 +1,6 @@
import 'package:flutter/material.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_ui/extensions/build_context_extensions.dart';
import 'package:immich_ui/extensions/theme_extensions.dart';
class SettingsSwitchListTile extends StatelessWidget {
final ValueNotifier<bool> valueNotifier;