chore: simplify timeline switcher toggle (#21864)

chore: timeline switcher option simplify
This commit is contained in:
Alex 2025-09-12 22:32:15 -05:00 committed by GitHub
parent 994a770921
commit 913b3789cc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 66 additions and 235 deletions

View file

@ -12,7 +12,6 @@ import 'package:immich_mobile/widgets/settings/asset_viewer_settings/asset_viewe
import 'package:immich_mobile/widgets/settings/backup_settings/backup_settings.dart'; import 'package:immich_mobile/widgets/settings/backup_settings/backup_settings.dart';
import 'package:immich_mobile/widgets/settings/backup_settings/drift_backup_settings.dart'; import 'package:immich_mobile/widgets/settings/backup_settings/drift_backup_settings.dart';
import 'package:immich_mobile/widgets/settings/beta_sync_settings/sync_status_and_actions.dart'; import 'package:immich_mobile/widgets/settings/beta_sync_settings/sync_status_and_actions.dart';
import 'package:immich_mobile/widgets/settings/beta_timeline_list_tile.dart';
import 'package:immich_mobile/widgets/settings/language_settings.dart'; 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/networking_settings/networking_settings.dart';
import 'package:immich_mobile/widgets/settings/notification_setting.dart'; import 'package:immich_mobile/widgets/settings/notification_setting.dart';
@ -20,7 +19,6 @@ import 'package:immich_mobile/widgets/settings/preference_settings/preference_se
import 'package:immich_mobile/widgets/settings/settings_card.dart'; import 'package:immich_mobile/widgets/settings/settings_card.dart';
enum SettingSection { enum SettingSection {
beta('sync_status', Icons.sync_outlined, "sync_status_subtitle"),
advanced('advanced', Icons.build_outlined, "advanced_settings_tile_subtitle"), advanced('advanced', Icons.build_outlined, "advanced_settings_tile_subtitle"),
assetViewer('asset_viewer_settings_title', Icons.image_outlined, "asset_viewer_settings_subtitle"), assetViewer('asset_viewer_settings_title', Icons.image_outlined, "asset_viewer_settings_subtitle"),
backup('backup', Icons.cloud_upload_outlined, "backup_settings_subtitle"), backup('backup', Icons.cloud_upload_outlined, "backup_settings_subtitle"),
@ -28,14 +26,14 @@ enum SettingSection {
networking('networking_settings', Icons.wifi, "networking_subtitle"), networking('networking_settings', Icons.wifi, "networking_subtitle"),
notifications('notifications', Icons.notifications_none_rounded, "setting_notifications_subtitle"), notifications('notifications', Icons.notifications_none_rounded, "setting_notifications_subtitle"),
preferences('preferences_settings_title', Icons.interests_outlined, "preferences_settings_subtitle"), preferences('preferences_settings_title', Icons.interests_outlined, "preferences_settings_subtitle"),
timeline('asset_list_settings_title', Icons.auto_awesome_mosaic_outlined, "asset_list_settings_subtitle"); timeline('asset_list_settings_title', Icons.auto_awesome_mosaic_outlined, "asset_list_settings_subtitle"),
beta('sync_status', Icons.sync_outlined, "sync_status_subtitle");
final String title; final String title;
final String subtitle; final String subtitle;
final IconData icon; final IconData icon;
Widget get widget => switch (this) { Widget get widget => switch (this) {
SettingSection.beta => const _BetaLandscapeToggle(),
SettingSection.advanced => const AdvancedSettings(), SettingSection.advanced => const AdvancedSettings(),
SettingSection.assetViewer => const AssetViewerSettings(), SettingSection.assetViewer => const AssetViewerSettings(),
SettingSection.backup => SettingSection.backup =>
@ -45,6 +43,7 @@ enum SettingSection {
SettingSection.notifications => const NotificationSetting(), SettingSection.notifications => const NotificationSetting(),
SettingSection.preferences => const PreferenceSetting(), SettingSection.preferences => const PreferenceSetting(),
SettingSection.timeline => const AssetListSettings(), SettingSection.timeline => const AssetListSettings(),
SettingSection.beta => const SyncStatusAndActions(),
}; };
const SettingSection(this.title, this.icon, this.subtitle); const SettingSection(this.title, this.icon, this.subtitle);
@ -59,7 +58,7 @@ class SettingsPage extends StatelessWidget {
context.locale; context.locale;
return Scaffold( return Scaffold(
appBar: AppBar(centerTitle: false, title: const Text('settings').tr()), appBar: AppBar(centerTitle: false, title: const Text('settings').tr()),
body: context.isMobile ? const _MobileLayout() : const _TabletLayout(), body: context.isMobile ? const SafeArea(child: _MobileLayout()) : const SafeArea(child: _TabletLayout()),
); );
} }
} }
@ -72,7 +71,6 @@ class _MobileLayout extends StatelessWidget {
.expand( .expand(
(setting) => setting == SettingSection.beta (setting) => setting == SettingSection.beta
? [ ? [
const BetaTimelineListTile(),
if (Store.isBetaTimelineEnabled) if (Store.isBetaTimelineEnabled)
SettingsCard( SettingsCard(
icon: Icons.sync_outlined, icon: Icons.sync_outlined,
@ -93,7 +91,7 @@ class _MobileLayout extends StatelessWidget {
.toList(); .toList();
return ListView( return ListView(
physics: const ClampingScrollPhysics(), physics: const ClampingScrollPhysics(),
padding: const EdgeInsets.only(top: 10.0, bottom: 56), padding: const EdgeInsets.only(top: 10.0, bottom: 16),
children: [...settings], children: [...settings],
); );
} }
@ -134,21 +132,6 @@ class _TabletLayout extends HookWidget {
} }
} }
class _BetaLandscapeToggle extends HookWidget {
const _BetaLandscapeToggle();
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
const SizedBox(height: 100, child: BetaTimelineListTile()),
if (Store.isBetaTimelineEnabled) const Expanded(child: SyncStatusAndActions()),
],
);
}
}
@RoutePage() @RoutePage()
class SettingsSubPage extends StatelessWidget { class SettingsSubPage extends StatelessWidget {
const SettingsSubPage(this.section, {super.key}); const SettingsSubPage(this.section, {super.key});
@ -158,9 +141,14 @@ class SettingsSubPage extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
context.locale; context.locale;
return Scaffold( return SafeArea(
appBar: AppBar(centerTitle: false, title: Text(section.title).tr()), bottom: true,
body: section.widget, top: false,
right: true,
child: Scaffold(
appBar: AppBar(centerTitle: false, title: Text(section.title).tr()),
body: section.widget,
),
); );
} }
} }

View file

@ -14,6 +14,7 @@ import 'package:immich_mobile/repositories/local_files_manager.repository.dart';
import 'package:immich_mobile/services/app_settings.service.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/utils/hooks/app_settings_update_hook.dart';
import 'package:immich_mobile/utils/http_ssl_options.dart'; import 'package:immich_mobile/utils/http_ssl_options.dart';
import 'package:immich_mobile/widgets/settings/beta_timeline_list_tile.dart';
import 'package:immich_mobile/widgets/settings/custom_proxy_headers_settings/custome_proxy_headers_settings.dart'; import 'package:immich_mobile/widgets/settings/custom_proxy_headers_settings/custome_proxy_headers_settings.dart';
import 'package:immich_mobile/widgets/settings/local_storage_settings.dart'; import 'package:immich_mobile/widgets/settings/local_storage_settings.dart';
import 'package:immich_mobile/widgets/settings/settings_slider_list_tile.dart'; import 'package:immich_mobile/widgets/settings/settings_slider_list_tile.dart';
@ -91,7 +92,7 @@ class AdvancedSettings extends HookConsumerWidget {
title: "advanced_settings_prefer_remote_title".tr(), title: "advanced_settings_prefer_remote_title".tr(),
subtitle: "advanced_settings_prefer_remote_subtitle".tr(), subtitle: "advanced_settings_prefer_remote_subtitle".tr(),
), ),
const LocalStorageSettings(), if (!Store.isBetaTimelineEnabled) const LocalStorageSettings(),
SettingsSwitchListTile( SettingsSwitchListTile(
enabled: !isLoggedIn, enabled: !isLoggedIn,
valueNotifier: allowSelfSignedSSLCert, valueNotifier: allowSelfSignedSSLCert,
@ -101,12 +102,13 @@ class AdvancedSettings extends HookConsumerWidget {
), ),
const CustomeProxyHeaderSettings(), const CustomeProxyHeaderSettings(),
SslClientCertSettings(isLoggedIn: ref.read(currentUserProvider) != null), SslClientCertSettings(isLoggedIn: ref.read(currentUserProvider) != null),
SettingsSwitchListTile( if (!Store.isBetaTimelineEnabled)
valueNotifier: useAlternatePMFilter, SettingsSwitchListTile(
title: "advanced_settings_enable_alternate_media_filter_title".tr(), valueNotifier: useAlternatePMFilter,
subtitle: "advanced_settings_enable_alternate_media_filter_subtitle".tr(), title: "advanced_settings_enable_alternate_media_filter_title".tr(),
), subtitle: "advanced_settings_enable_alternate_media_filter_subtitle".tr(),
// TODO: Remove this check when beta timeline goes stable ),
const BetaTimelineListTile(),
if (Store.isBetaTimelineEnabled) if (Store.isBetaTimelineEnabled)
SettingsSwitchListTile( SettingsSwitchListTile(
valueNotifier: readonlyModeEnabled, valueNotifier: readonlyModeEnabled,

View file

@ -1,5 +1,3 @@
import 'dart:math' as math;
import 'package:auto_route/auto_route.dart'; import 'package:auto_route/auto_route.dart';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
@ -12,50 +10,11 @@ import 'package:immich_mobile/providers/server_info.provider.dart';
import 'package:immich_mobile/routing/router.dart'; import 'package:immich_mobile/routing/router.dart';
import 'package:immich_mobile/services/app_settings.service.dart'; import 'package:immich_mobile/services/app_settings.service.dart';
class BetaTimelineListTile extends ConsumerStatefulWidget { class BetaTimelineListTile extends ConsumerWidget {
const BetaTimelineListTile({super.key}); const BetaTimelineListTile({super.key});
@override @override
ConsumerState<BetaTimelineListTile> createState() => _BetaTimelineListTileState(); Widget build(BuildContext context, WidgetRef ref) {
}
class _BetaTimelineListTileState extends ConsumerState<BetaTimelineListTile> with SingleTickerProviderStateMixin {
late AnimationController _animationController;
late Animation<double> _rotationAnimation;
late Animation<double> _pulseAnimation;
late Animation<double> _gradientAnimation;
@override
void initState() {
super.initState();
_animationController = AnimationController(duration: const Duration(seconds: 3), vsync: this);
_rotationAnimation = Tween<double>(
begin: 0,
end: 2 * math.pi,
).animate(CurvedAnimation(parent: _animationController, curve: Curves.linear));
_pulseAnimation = Tween<double>(
begin: 1,
end: 1.1,
).animate(CurvedAnimation(parent: _animationController, curve: Curves.easeInOut));
_gradientAnimation = Tween<double>(
begin: 0,
end: 1,
).animate(CurvedAnimation(parent: _animationController, curve: Curves.easeInOut));
_animationController.repeat(reverse: true);
}
@override
void dispose() {
_animationController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) {
final betaTimelineValue = ref.watch(appSettingsServiceProvider).getSetting<bool>(AppSettingsEnum.betaTimeline); final betaTimelineValue = ref.watch(appSettingsServiceProvider).getSetting<bool>(AppSettingsEnum.betaTimeline);
final serverInfo = ref.watch(serverInfoProvider); final serverInfo = ref.watch(serverInfoProvider);
final auth = ref.watch(authProvider); final auth = ref.watch(authProvider);
@ -64,168 +23,50 @@ class _BetaTimelineListTileState extends ConsumerState<BetaTimelineListTile> wit
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
return AnimatedBuilder( void onSwitchChanged(bool value) {
animation: _animationController, showDialog(
builder: (context, child) { context: context,
void onSwitchChanged(bool value) { builder: (context) {
showDialog( return AlertDialog(
context: context, title: value ? const Text("Enable Beta Timeline") : const Text("Disable Beta Timeline"),
builder: (context) { content: value
return AlertDialog( ? const Text("Are you sure you want to enable the beta timeline?")
title: value ? const Text("Enable Beta Timeline") : const Text("Disable Beta Timeline"), : const Text("Are you sure you want to disable the beta timeline?"),
content: value actions: [
? const Text("Are you sure you want to enable the beta timeline?") TextButton(
: const Text("Are you sure you want to disable the beta timeline?"), onPressed: () {
actions: [ context.pop();
TextButton( },
onPressed: () { child: Text(
context.pop(); "cancel".t(context: context),
}, style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: context.colorScheme.outline),
child: Text(
"cancel".t(context: context),
style: TextStyle(fontSize: 16, fontWeight: FontWeight.w500, color: context.colorScheme.outline),
),
),
ElevatedButton(
onPressed: () async {
Navigator.of(context).pop();
context.router.replaceAll([ChangeExperienceRoute(switchingToBeta: value)]);
},
child: Text("ok".t(context: context)),
),
],
);
},
);
}
final gradientColors = [
Color.lerp(
context.primaryColor.withValues(alpha: 0.5),
context.primaryColor.withValues(alpha: 0.3),
_gradientAnimation.value,
)!,
Color.lerp(
context.logoPink.withValues(alpha: 0.2),
context.logoPink.withValues(alpha: 0.4),
_gradientAnimation.value,
)!,
Color.lerp(
context.logoRed.withValues(alpha: 0.3),
context.logoRed.withValues(alpha: 0.5),
_gradientAnimation.value,
)!,
];
return Container(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(12)),
gradient: LinearGradient(
colors: gradientColors,
stops: const [0.0, 0.5, 1.0],
begin: Alignment.topLeft,
end: Alignment.bottomRight,
transform: GradientRotation(_rotationAnimation.value * 0.5),
),
boxShadow: [
BoxShadow(color: context.primaryColor.withValues(alpha: 0.1), blurRadius: 8, offset: const Offset(0, 2)),
],
),
child: Container(
margin: const EdgeInsets.all(2),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(10.5)),
color: context.scaffoldBackgroundColor,
),
child: Material(
borderRadius: const BorderRadius.all(Radius.circular(10.5)),
child: InkWell(
borderRadius: const BorderRadius.all(Radius.circular(10.5)),
onTap: () => onSwitchChanged(!betaTimelineValue),
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 16),
child: Row(
children: [
Transform.scale(
scale: _pulseAnimation.value,
child: Transform.rotate(
angle: _rotationAnimation.value * 0.02,
child: Container(
padding: const EdgeInsets.all(8),
decoration: BoxDecoration(
shape: BoxShape.circle,
gradient: LinearGradient(
colors: [
context.primaryColor.withValues(alpha: 0.2),
context.primaryColor.withValues(alpha: 0.1),
],
),
),
child: Icon(Icons.auto_awesome, color: context.primaryColor, size: 20),
),
),
),
const SizedBox(width: 28),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
"advanced_settings_beta_timeline_title".t(context: context),
style: context.textTheme.titleMedium?.copyWith(fontWeight: FontWeight.w600),
),
const SizedBox(width: 8),
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
borderRadius: const BorderRadius.all(Radius.circular(8)),
gradient: LinearGradient(
colors: [
context.primaryColor.withValues(alpha: 0.8),
context.primaryColor.withValues(alpha: 0.6),
],
),
),
child: Text(
'NEW',
style: context.textTheme.labelSmall?.copyWith(
color: Colors.white,
fontWeight: FontWeight.bold,
fontSize: 10,
height: 1.2,
),
),
),
],
),
const SizedBox(height: 4),
Text(
"advanced_settings_beta_timeline_subtitle".t(context: context),
style: context.textTheme.labelLarge?.copyWith(
color: context.textTheme.labelLarge?.color?.withValues(alpha: 0.9),
),
maxLines: 2,
),
],
),
),
Switch.adaptive(
value: betaTimelineValue,
onChanged: onSwitchChanged,
activeColor: context.primaryColor,
),
],
),
), ),
), ),
), ElevatedButton(
), onPressed: () async {
); Navigator.of(context).pop();
}, context.router.replaceAll([ChangeExperienceRoute(switchingToBeta: value)]);
},
child: Text("ok".t(context: context)),
),
],
);
},
);
}
return Padding(
padding: const EdgeInsets.only(left: 4.0),
child: ListTile(
title: Text("advanced_settings_beta_timeline_title".t(context: context)),
subtitle: Text("advanced_settings_beta_timeline_subtitle".t(context: context)),
trailing: Switch.adaptive(
value: betaTimelineValue,
onChanged: onSwitchChanged,
activeColor: context.primaryColor,
),
onTap: () => onSwitchChanged(!betaTimelineValue),
),
); );
} }
} }