diff --git a/mobile/lib/domain/utils/background_sync.dart b/mobile/lib/domain/utils/background_sync.dart index 1944591c93..cbf4030788 100644 --- a/mobile/lib/domain/utils/background_sync.dart +++ b/mobile/lib/domain/utils/background_sync.dart @@ -37,7 +37,7 @@ class BackgroundSyncManager { this.onHashingError, }); - Future cancel() { + Future cancel() async { final futures = []; if (_syncTask != null) { @@ -52,7 +52,11 @@ class BackgroundSyncManager { _syncWebsocketTask?.cancel(); _syncWebsocketTask = null; - return Future.wait(futures); + try { + await Future.wait(futures); + } on CanceledError { + // Ignore cancellation errors + } } // No need to cancel the task, as it can also be run when the user logs out diff --git a/mobile/lib/main.dart b/mobile/lib/main.dart index d1f415a304..0bac282694 100644 --- a/mobile/lib/main.dart +++ b/mobile/lib/main.dart @@ -83,7 +83,6 @@ Future initApp() async { }; PlatformDispatcher.instance.onError = (error, stack) { - debugPrint("FlutterError - Catch all: $error \n $stack"); log.severe('PlatformDispatcher - Catch all', error, stack); return true; }; diff --git a/mobile/lib/presentation/pages/dev/main_timeline.page.dart b/mobile/lib/presentation/pages/dev/main_timeline.page.dart index dfa53ae7d9..3764443566 100644 --- a/mobile/lib/presentation/pages/dev/main_timeline.page.dart +++ b/mobile/lib/presentation/pages/dev/main_timeline.page.dart @@ -21,17 +21,16 @@ class MainTimelinePage extends ConsumerWidget { return memoryLaneProvider.maybeWhen( data: (memories) { return memories.isEmpty || !memoriesEnabled - ? const Timeline(showStorageIndicator: true) + ? const Timeline() : Timeline( topSliverWidget: SliverToBoxAdapter( key: Key('memory-lane-${memories.first.assets.first.id}'), child: DriftMemoryLane(memories: memories), ), topSliverWidgetHeight: 200, - showStorageIndicator: true, ); }, - orElse: () => const Timeline(showStorageIndicator: true), + orElse: () => const Timeline(), ); } } diff --git a/mobile/lib/presentation/pages/drift_trash.page.dart b/mobile/lib/presentation/pages/drift_trash.page.dart index 4d18d12d01..43e9217cdf 100644 --- a/mobile/lib/presentation/pages/drift_trash.page.dart +++ b/mobile/lib/presentation/pages/drift_trash.page.dart @@ -28,7 +28,6 @@ class DriftTrashPage extends StatelessWidget { }), ], child: Timeline( - showStorageIndicator: true, appBar: SliverAppBar( title: Text('trash'.t(context: context)), floating: true, diff --git a/mobile/lib/presentation/pages/local_timeline.page.dart b/mobile/lib/presentation/pages/local_timeline.page.dart index 67bc17cb37..c53b18d9e7 100644 --- a/mobile/lib/presentation/pages/local_timeline.page.dart +++ b/mobile/lib/presentation/pages/local_timeline.page.dart @@ -26,7 +26,6 @@ class LocalTimelinePage extends StatelessWidget { child: Timeline( appBar: MesmerizingSliverAppBar(title: album.name), bottomSheet: const LocalAlbumBottomSheet(), - showStorageIndicator: true, ), ); } diff --git a/mobile/lib/presentation/widgets/images/thumbnail_tile.widget.dart b/mobile/lib/presentation/widgets/images/thumbnail_tile.widget.dart index b9ef1ca45a..37743c5e86 100644 --- a/mobile/lib/presentation/widgets/images/thumbnail_tile.widget.dart +++ b/mobile/lib/presentation/widgets/images/thumbnail_tile.widget.dart @@ -2,10 +2,12 @@ import 'package:auto_route/auto_route.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/domain/models/asset/base_asset.model.dart'; +import 'package:immich_mobile/domain/models/setting.model.dart'; import 'package:immich_mobile/extensions/build_context_extensions.dart'; import 'package:immich_mobile/extensions/duration_extensions.dart'; import 'package:immich_mobile/extensions/theme_extensions.dart'; import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget.dart'; +import 'package:immich_mobile/providers/infrastructure/setting.provider.dart'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart'; class ThumbnailTile extends ConsumerWidget { @@ -13,7 +15,7 @@ class ThumbnailTile extends ConsumerWidget { this.asset, { this.size = const Size.square(256), this.fit = BoxFit.cover, - this.showStorageIndicator = true, + this.showStorageIndicator, this.lockSelection = false, this.heroOffset, super.key, @@ -22,7 +24,7 @@ class ThumbnailTile extends ConsumerWidget { final BaseAsset asset; final Size size; final BoxFit fit; - final bool showStorageIndicator; + final bool? showStorageIndicator; final bool lockSelection; final int? heroOffset; @@ -52,6 +54,9 @@ class ThumbnailTile extends ConsumerWidget { final hasStack = asset is RemoteAsset && (asset as RemoteAsset).stackId != null; + final bool storageIndicator = + showStorageIndicator ?? ref.watch(settingsProvider.select((s) => s.get(Setting.showStorageIndicator))); + return Stack( children: [ AnimatedContainer( @@ -86,7 +91,7 @@ class ThumbnailTile extends ConsumerWidget { child: _VideoIndicator(asset.duration), ), ), - if (showStorageIndicator) + if (storageIndicator) switch (asset.storage) { AssetState.local => const Align( alignment: Alignment.bottomRight, diff --git a/mobile/lib/presentation/widgets/timeline/timeline.state.dart b/mobile/lib/presentation/widgets/timeline/timeline.state.dart index ad3ae3ccf6..da1f7fcc9d 100644 --- a/mobile/lib/presentation/widgets/timeline/timeline.state.dart +++ b/mobile/lib/presentation/widgets/timeline/timeline.state.dart @@ -14,7 +14,7 @@ class TimelineArgs { final double maxHeight; final double spacing; final int columnCount; - final bool showStorageIndicator; + final bool? showStorageIndicator; final bool withStack; final GroupAssetsBy? groupBy; @@ -23,7 +23,7 @@ class TimelineArgs { required this.maxHeight, this.spacing = kTimelineSpacing, this.columnCount = kTimelineColumnCount, - this.showStorageIndicator = false, + this.showStorageIndicator, this.withStack = false, this.groupBy, }); diff --git a/mobile/lib/presentation/widgets/timeline/timeline.widget.dart b/mobile/lib/presentation/widgets/timeline/timeline.widget.dart index b0886f020e..94e13c4e9f 100644 --- a/mobile/lib/presentation/widgets/timeline/timeline.widget.dart +++ b/mobile/lib/presentation/widgets/timeline/timeline.widget.dart @@ -31,7 +31,7 @@ class Timeline extends StatelessWidget { super.key, this.topSliverWidget, this.topSliverWidgetHeight, - this.showStorageIndicator = false, + this.showStorageIndicator, this.withStack = false, this.appBar = const ImmichSliverAppBar(floating: true, pinned: false, snap: false), this.bottomSheet = const GeneralBottomSheet(), @@ -40,7 +40,7 @@ class Timeline extends StatelessWidget { final Widget? topSliverWidget; final double? topSliverWidgetHeight; - final bool showStorageIndicator; + final bool? showStorageIndicator; final Widget? appBar; final Widget? bottomSheet; final bool withStack; diff --git a/mobile/lib/providers/app_life_cycle.provider.dart b/mobile/lib/providers/app_life_cycle.provider.dart index 31342bf23e..0696a8d7f1 100644 --- a/mobile/lib/providers/app_life_cycle.provider.dart +++ b/mobile/lib/providers/app_life_cycle.provider.dart @@ -86,11 +86,12 @@ class AppLifeCycleNotifier extends StateNotifier { // Ensure proper cleanup before starting new background tasks try { await Future.wait([ - backgroundManager.syncLocal().then((_) { + Future(() async { + await backgroundManager.syncLocal(); Logger("AppLifeCycleNotifier").fine("Hashing assets after syncLocal"); // Check if app is still active before hashing - if (state == AppLifeCycleEnum.resumed) { - backgroundManager.hashAssets(); + if ([AppLifeCycleEnum.resumed, AppLifeCycleEnum.active].contains(state)) { + await backgroundManager.hashAssets(); } }), backgroundManager.syncRemote(), diff --git a/mobile/lib/repositories/auth_api.repository.dart b/mobile/lib/repositories/auth_api.repository.dart index e488f69578..4b0880ddcf 100644 --- a/mobile/lib/repositories/auth_api.repository.dart +++ b/mobile/lib/repositories/auth_api.repository.dart @@ -25,6 +25,8 @@ class AuthApiRepository extends ApiRepository { } Future logout() async { + if (_apiService.apiClient.basePath.isEmpty) return; + await _apiService.authenticationApi.logout().timeout(const Duration(seconds: 7)); } diff --git a/mobile/lib/widgets/settings/asset_list_settings/asset_list_settings.dart b/mobile/lib/widgets/settings/asset_list_settings/asset_list_settings.dart index 9f0ed0aa87..907cd19843 100644 --- a/mobile/lib/widgets/settings/asset_list_settings/asset_list_settings.dart +++ b/mobile/lib/widgets/settings/asset_list_settings/asset_list_settings.dart @@ -2,11 +2,13 @@ import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:immich_mobile/providers/app_settings.provider.dart'; +import 'package:immich_mobile/providers/infrastructure/setting.provider.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/asset_list_settings/asset_list_group_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_mobile/utils/hooks/app_settings_update_hook.dart'; + import 'asset_list_layout_settings.dart'; class AssetListSettings extends HookConsumerWidget { @@ -20,7 +22,10 @@ class AssetListSettings extends HookConsumerWidget { SettingsSwitchListTile( valueNotifier: showStorageIndicator, title: 'theme_setting_asset_list_storage_indicator_title'.tr(), - onChanged: (_) => ref.invalidate(appSettingsServiceProvider), + onChanged: (_) { + ref.invalidate(appSettingsServiceProvider); + ref.invalidate(settingsProvider); + }, ), const LayoutSettings(), const GroupSettings(), diff --git a/web/src/lib/components/shared-components/control-app-bar.svelte b/web/src/lib/components/shared-components/control-app-bar.svelte index a28dfd45cf..ef4e26e849 100644 --- a/web/src/lib/components/shared-components/control-app-bar.svelte +++ b/web/src/lib/components/shared-components/control-app-bar.svelte @@ -97,7 +97,7 @@ {@render children?.()} -
+
{@render trailing?.()}