merge main

This commit is contained in:
Alex 2025-08-04 17:26:54 -05:00
commit 17e6ca962a
No known key found for this signature in database
GPG Key ID: 53CD082B3A5E1082
12 changed files with 34 additions and 21 deletions

View File

@ -37,7 +37,7 @@ class BackgroundSyncManager {
this.onHashingError, this.onHashingError,
}); });
Future<void> cancel() { Future<void> cancel() async {
final futures = <Future>[]; final futures = <Future>[];
if (_syncTask != null) { if (_syncTask != null) {
@ -52,7 +52,11 @@ class BackgroundSyncManager {
_syncWebsocketTask?.cancel(); _syncWebsocketTask?.cancel();
_syncWebsocketTask = null; _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 // No need to cancel the task, as it can also be run when the user logs out

View File

@ -83,7 +83,6 @@ Future<void> initApp() async {
}; };
PlatformDispatcher.instance.onError = (error, stack) { PlatformDispatcher.instance.onError = (error, stack) {
debugPrint("FlutterError - Catch all: $error \n $stack");
log.severe('PlatformDispatcher - Catch all', error, stack); log.severe('PlatformDispatcher - Catch all', error, stack);
return true; return true;
}; };

View File

@ -21,17 +21,16 @@ class MainTimelinePage extends ConsumerWidget {
return memoryLaneProvider.maybeWhen( return memoryLaneProvider.maybeWhen(
data: (memories) { data: (memories) {
return memories.isEmpty || !memoriesEnabled return memories.isEmpty || !memoriesEnabled
? const Timeline(showStorageIndicator: true) ? const Timeline()
: Timeline( : Timeline(
topSliverWidget: SliverToBoxAdapter( topSliverWidget: SliverToBoxAdapter(
key: Key('memory-lane-${memories.first.assets.first.id}'), key: Key('memory-lane-${memories.first.assets.first.id}'),
child: DriftMemoryLane(memories: memories), child: DriftMemoryLane(memories: memories),
), ),
topSliverWidgetHeight: 200, topSliverWidgetHeight: 200,
showStorageIndicator: true,
); );
}, },
orElse: () => const Timeline(showStorageIndicator: true), orElse: () => const Timeline(),
); );
} }
} }

View File

@ -28,7 +28,6 @@ class DriftTrashPage extends StatelessWidget {
}), }),
], ],
child: Timeline( child: Timeline(
showStorageIndicator: true,
appBar: SliverAppBar( appBar: SliverAppBar(
title: Text('trash'.t(context: context)), title: Text('trash'.t(context: context)),
floating: true, floating: true,

View File

@ -26,7 +26,6 @@ class LocalTimelinePage extends StatelessWidget {
child: Timeline( child: Timeline(
appBar: MesmerizingSliverAppBar(title: album.name), appBar: MesmerizingSliverAppBar(title: album.name),
bottomSheet: const LocalAlbumBottomSheet(), bottomSheet: const LocalAlbumBottomSheet(),
showStorageIndicator: true,
), ),
); );
} }

View File

@ -2,10 +2,12 @@ import 'package:auto_route/auto_route.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.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/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/build_context_extensions.dart';
import 'package:immich_mobile/extensions/duration_extensions.dart'; import 'package:immich_mobile/extensions/duration_extensions.dart';
import 'package:immich_mobile/extensions/theme_extensions.dart'; import 'package:immich_mobile/extensions/theme_extensions.dart';
import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget.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'; import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
class ThumbnailTile extends ConsumerWidget { class ThumbnailTile extends ConsumerWidget {
@ -13,7 +15,7 @@ class ThumbnailTile extends ConsumerWidget {
this.asset, { this.asset, {
this.size = const Size.square(256), this.size = const Size.square(256),
this.fit = BoxFit.cover, this.fit = BoxFit.cover,
this.showStorageIndicator = true, this.showStorageIndicator,
this.lockSelection = false, this.lockSelection = false,
this.heroOffset, this.heroOffset,
super.key, super.key,
@ -22,7 +24,7 @@ class ThumbnailTile extends ConsumerWidget {
final BaseAsset asset; final BaseAsset asset;
final Size size; final Size size;
final BoxFit fit; final BoxFit fit;
final bool showStorageIndicator; final bool? showStorageIndicator;
final bool lockSelection; final bool lockSelection;
final int? heroOffset; final int? heroOffset;
@ -52,6 +54,9 @@ class ThumbnailTile extends ConsumerWidget {
final hasStack = asset is RemoteAsset && (asset as RemoteAsset).stackId != null; 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( return Stack(
children: [ children: [
AnimatedContainer( AnimatedContainer(
@ -86,7 +91,7 @@ class ThumbnailTile extends ConsumerWidget {
child: _VideoIndicator(asset.duration), child: _VideoIndicator(asset.duration),
), ),
), ),
if (showStorageIndicator) if (storageIndicator)
switch (asset.storage) { switch (asset.storage) {
AssetState.local => const Align( AssetState.local => const Align(
alignment: Alignment.bottomRight, alignment: Alignment.bottomRight,

View File

@ -14,7 +14,7 @@ class TimelineArgs {
final double maxHeight; final double maxHeight;
final double spacing; final double spacing;
final int columnCount; final int columnCount;
final bool showStorageIndicator; final bool? showStorageIndicator;
final bool withStack; final bool withStack;
final GroupAssetsBy? groupBy; final GroupAssetsBy? groupBy;
@ -23,7 +23,7 @@ class TimelineArgs {
required this.maxHeight, required this.maxHeight,
this.spacing = kTimelineSpacing, this.spacing = kTimelineSpacing,
this.columnCount = kTimelineColumnCount, this.columnCount = kTimelineColumnCount,
this.showStorageIndicator = false, this.showStorageIndicator,
this.withStack = false, this.withStack = false,
this.groupBy, this.groupBy,
}); });

View File

@ -31,7 +31,7 @@ class Timeline extends StatelessWidget {
super.key, super.key,
this.topSliverWidget, this.topSliverWidget,
this.topSliverWidgetHeight, this.topSliverWidgetHeight,
this.showStorageIndicator = false, this.showStorageIndicator,
this.withStack = false, this.withStack = false,
this.appBar = const ImmichSliverAppBar(floating: true, pinned: false, snap: false), this.appBar = const ImmichSliverAppBar(floating: true, pinned: false, snap: false),
this.bottomSheet = const GeneralBottomSheet(), this.bottomSheet = const GeneralBottomSheet(),
@ -40,7 +40,7 @@ class Timeline extends StatelessWidget {
final Widget? topSliverWidget; final Widget? topSliverWidget;
final double? topSliverWidgetHeight; final double? topSliverWidgetHeight;
final bool showStorageIndicator; final bool? showStorageIndicator;
final Widget? appBar; final Widget? appBar;
final Widget? bottomSheet; final Widget? bottomSheet;
final bool withStack; final bool withStack;

View File

@ -86,11 +86,12 @@ class AppLifeCycleNotifier extends StateNotifier<AppLifeCycleEnum> {
// Ensure proper cleanup before starting new background tasks // Ensure proper cleanup before starting new background tasks
try { try {
await Future.wait([ await Future.wait([
backgroundManager.syncLocal().then((_) { Future(() async {
await backgroundManager.syncLocal();
Logger("AppLifeCycleNotifier").fine("Hashing assets after syncLocal"); Logger("AppLifeCycleNotifier").fine("Hashing assets after syncLocal");
// Check if app is still active before hashing // Check if app is still active before hashing
if (state == AppLifeCycleEnum.resumed) { if ([AppLifeCycleEnum.resumed, AppLifeCycleEnum.active].contains(state)) {
backgroundManager.hashAssets(); await backgroundManager.hashAssets();
} }
}), }),
backgroundManager.syncRemote(), backgroundManager.syncRemote(),

View File

@ -25,6 +25,8 @@ class AuthApiRepository extends ApiRepository {
} }
Future<void> logout() async { Future<void> logout() async {
if (_apiService.apiClient.basePath.isEmpty) return;
await _apiService.authenticationApi.logout().timeout(const Duration(seconds: 7)); await _apiService.authenticationApi.logout().timeout(const Duration(seconds: 7));
} }

View File

@ -2,11 +2,13 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart'; import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/providers/app_settings.provider.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/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/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_sub_page_scaffold.dart';
import 'package:immich_mobile/widgets/settings/settings_switch_list_tile.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'; import 'asset_list_layout_settings.dart';
class AssetListSettings extends HookConsumerWidget { class AssetListSettings extends HookConsumerWidget {
@ -20,7 +22,10 @@ class AssetListSettings extends HookConsumerWidget {
SettingsSwitchListTile( SettingsSwitchListTile(
valueNotifier: showStorageIndicator, valueNotifier: showStorageIndicator,
title: 'theme_setting_asset_list_storage_indicator_title'.tr(), title: 'theme_setting_asset_list_storage_indicator_title'.tr(),
onChanged: (_) => ref.invalidate(appSettingsServiceProvider), onChanged: (_) {
ref.invalidate(appSettingsServiceProvider);
ref.invalidate(settingsProvider);
},
), ),
const LayoutSettings(), const LayoutSettings(),
const GroupSettings(), const GroupSettings(),

View File

@ -97,7 +97,7 @@
{@render children?.()} {@render children?.()}
</div> </div>
<div class="me-4 flex place-items-center gap-1 justify-self-end"> <div class="max-[350px]:me-0 max-[350px]:gap-0 me-4 flex place-items-center gap-1 justify-self-end">
{@render trailing?.()} {@render trailing?.()}
</div> </div>
</nav> </nav>