mirror of
https://github.com/immich-app/immich.git
synced 2025-07-31 15:08:44 -04:00
fix: reduce asset_viewer reloads (#20083)
* fix: reduce asset_viewer reloads * limit the result of watch asset to one * fix null reference in map thumbnail * bump hash file limit to 256 --------- Co-authored-by: shenlong-tanwen <139912620+shalong-tanwen@users.noreply.github.com> Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
parent
aa344a3989
commit
ab61bcfcc8
@ -10,7 +10,7 @@ const int kSyncEventBatchSize = 5000;
|
|||||||
const int kFetchLocalAssetsBatchSize = 40000;
|
const int kFetchLocalAssetsBatchSize = 40000;
|
||||||
|
|
||||||
// Hash batch limits
|
// Hash batch limits
|
||||||
const int kBatchHashFileLimit = 128;
|
const int kBatchHashFileLimit = 256;
|
||||||
const int kBatchHashSizeLimit = 1024 * 1024 * 1024; // 1GB
|
const int kBatchHashSizeLimit = 1024 * 1024 * 1024; // 1GB
|
||||||
|
|
||||||
// Secure storage keys
|
// Secure storage keys
|
||||||
|
@ -62,7 +62,8 @@ class RemoteAssetRepository extends DriftDatabaseRepository {
|
|||||||
_db.remoteAssetEntity.id,
|
_db.remoteAssetEntity.id,
|
||||||
_db.localAssetEntity.id,
|
_db.localAssetEntity.id,
|
||||||
_db.stackEntity.primaryAssetId,
|
_db.stackEntity.primaryAssetId,
|
||||||
]);
|
])
|
||||||
|
..limit(1);
|
||||||
|
|
||||||
return query.map((row) {
|
return query.map((row) {
|
||||||
final asset = row.readTable(_db.remoteAssetEntity).toDto();
|
final asset = row.readTable(_db.remoteAssetEntity).toDto();
|
||||||
|
@ -2,8 +2,10 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
|
import 'package:immich_mobile/domain/utils/event_stream.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_viewer.state.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
||||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
||||||
@ -21,6 +23,10 @@ class ArchiveActionButton extends ConsumerWidget {
|
|||||||
final result = await ref.read(actionProvider.notifier).archive(source);
|
final result = await ref.read(actionProvider.notifier).archive(source);
|
||||||
ref.read(multiSelectProvider.notifier).reset();
|
ref.read(multiSelectProvider.notifier).reset();
|
||||||
|
|
||||||
|
if (source == ActionSource.viewer) {
|
||||||
|
EventStream.shared.emit(const ViewerReloadAssetEvent());
|
||||||
|
}
|
||||||
|
|
||||||
final successMessage = 'archive_action_prompt'.t(
|
final successMessage = 'archive_action_prompt'.t(
|
||||||
context: context,
|
context: context,
|
||||||
args: {'count': result.count.toString()},
|
args: {'count': result.count.toString()},
|
||||||
|
@ -2,8 +2,10 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
|
import 'package:immich_mobile/domain/utils/event_stream.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_viewer.state.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
||||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
||||||
@ -21,6 +23,10 @@ class DeleteLocalActionButton extends ConsumerWidget {
|
|||||||
final result = await ref.read(actionProvider.notifier).deleteLocal(source);
|
final result = await ref.read(actionProvider.notifier).deleteLocal(source);
|
||||||
ref.read(multiSelectProvider.notifier).reset();
|
ref.read(multiSelectProvider.notifier).reset();
|
||||||
|
|
||||||
|
if (source == ActionSource.viewer) {
|
||||||
|
EventStream.shared.emit(const ViewerReloadAssetEvent());
|
||||||
|
}
|
||||||
|
|
||||||
final successMessage = 'delete_local_action_prompt'.t(
|
final successMessage = 'delete_local_action_prompt'.t(
|
||||||
context: context,
|
context: context,
|
||||||
args: {'count': result.count.toString()},
|
args: {'count': result.count.toString()},
|
||||||
|
@ -2,8 +2,10 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
|
import 'package:immich_mobile/domain/utils/event_stream.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_viewer.state.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
||||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
||||||
@ -22,6 +24,10 @@ class DeletePermanentActionButton extends ConsumerWidget {
|
|||||||
await ref.read(actionProvider.notifier).deleteRemoteAndLocal(source);
|
await ref.read(actionProvider.notifier).deleteRemoteAndLocal(source);
|
||||||
ref.read(multiSelectProvider.notifier).reset();
|
ref.read(multiSelectProvider.notifier).reset();
|
||||||
|
|
||||||
|
if (source == ActionSource.viewer) {
|
||||||
|
EventStream.shared.emit(const ViewerReloadAssetEvent());
|
||||||
|
}
|
||||||
|
|
||||||
final successMessage = 'delete_action_prompt'.t(
|
final successMessage = 'delete_action_prompt'.t(
|
||||||
context: context,
|
context: context,
|
||||||
args: {'count': result.count.toString()},
|
args: {'count': result.count.toString()},
|
||||||
|
@ -2,8 +2,10 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
|
import 'package:immich_mobile/domain/utils/event_stream.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_viewer.state.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
||||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
||||||
@ -22,6 +24,10 @@ class MoveToLockFolderActionButton extends ConsumerWidget {
|
|||||||
await ref.read(actionProvider.notifier).moveToLockFolder(source);
|
await ref.read(actionProvider.notifier).moveToLockFolder(source);
|
||||||
ref.read(multiSelectProvider.notifier).reset();
|
ref.read(multiSelectProvider.notifier).reset();
|
||||||
|
|
||||||
|
if (source == ActionSource.viewer) {
|
||||||
|
EventStream.shared.emit(const ViewerReloadAssetEvent());
|
||||||
|
}
|
||||||
|
|
||||||
final successMessage = 'move_to_lock_folder_action_prompt'.t(
|
final successMessage = 'move_to_lock_folder_action_prompt'.t(
|
||||||
context: context,
|
context: context,
|
||||||
args: {'count': result.count.toString()},
|
args: {'count': result.count.toString()},
|
||||||
|
@ -2,8 +2,10 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:fluttertoast/fluttertoast.dart';
|
import 'package:fluttertoast/fluttertoast.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
import 'package:immich_mobile/constants/enums.dart';
|
import 'package:immich_mobile/constants/enums.dart';
|
||||||
|
import 'package:immich_mobile/domain/utils/event_stream.dart';
|
||||||
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/asset_viewer/asset_viewer.state.dart';
|
||||||
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
import 'package:immich_mobile/providers/infrastructure/action.provider.dart';
|
||||||
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
import 'package:immich_mobile/widgets/common/immich_toast.dart';
|
||||||
@ -21,6 +23,10 @@ class TrashActionButton extends ConsumerWidget {
|
|||||||
final result = await ref.read(actionProvider.notifier).trash(source);
|
final result = await ref.read(actionProvider.notifier).trash(source);
|
||||||
ref.read(multiSelectProvider.notifier).reset();
|
ref.read(multiSelectProvider.notifier).reset();
|
||||||
|
|
||||||
|
if (source == ActionSource.viewer) {
|
||||||
|
EventStream.shared.emit(const ViewerReloadAssetEvent());
|
||||||
|
}
|
||||||
|
|
||||||
final successMessage = 'trash_action_prompt'.t(
|
final successMessage = 'trash_action_prompt'.t(
|
||||||
context: context,
|
context: context,
|
||||||
args: {'count': result.count.toString()},
|
args: {'count': result.count.toString()},
|
||||||
|
@ -85,6 +85,7 @@ class _AssetViewerState extends ConsumerState<AssetViewer> {
|
|||||||
bool blockGestures = false;
|
bool blockGestures = false;
|
||||||
bool dragInProgress = false;
|
bool dragInProgress = false;
|
||||||
bool shouldPopOnDrag = false;
|
bool shouldPopOnDrag = false;
|
||||||
|
bool assetReloadRequested = false;
|
||||||
double? initialScale;
|
double? initialScale;
|
||||||
double previousExtent = _kBottomSheetMinimumExtent;
|
double previousExtent = _kBottomSheetMinimumExtent;
|
||||||
Offset dragDownPosition = Offset.zero;
|
Offset dragDownPosition = Offset.zero;
|
||||||
@ -404,7 +405,12 @@ class _AssetViewerState extends ConsumerState<AssetViewer> {
|
|||||||
|
|
||||||
void _onEvent(Event event) {
|
void _onEvent(Event event) {
|
||||||
if (event is TimelineReloadEvent) {
|
if (event is TimelineReloadEvent) {
|
||||||
_onTimelineReload(event);
|
_onTimelineReloadEvent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (event is ViewerReloadAssetEvent) {
|
||||||
|
assetReloadRequested = true;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -417,14 +423,22 @@ class _AssetViewerState extends ConsumerState<AssetViewer> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void _onTimelineReload(_) {
|
void _onTimelineReloadEvent() {
|
||||||
setState(() {
|
totalAssets = ref.read(timelineServiceProvider).totalAssets;
|
||||||
totalAssets = ref.read(timelineServiceProvider).totalAssets;
|
if (totalAssets == 0) {
|
||||||
if (totalAssets == 0) {
|
context.maybePop();
|
||||||
context.maybePop();
|
return;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
if (assetReloadRequested) {
|
||||||
|
assetReloadRequested = false;
|
||||||
|
_onAssetReloadEvent();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _onAssetReloadEvent() {
|
||||||
|
setState(() {
|
||||||
final index = pageController.page?.round() ?? 0;
|
final index = pageController.page?.round() ?? 0;
|
||||||
final newAsset = ref.read(timelineServiceProvider).getAsset(index);
|
final newAsset = ref.read(timelineServiceProvider).getAsset(index);
|
||||||
final currentAsset = ref.read(currentAssetNotifier);
|
final currentAsset = ref.read(currentAssetNotifier);
|
||||||
|
@ -7,6 +7,10 @@ class ViewerOpenBottomSheetEvent extends Event {
|
|||||||
const ViewerOpenBottomSheetEvent();
|
const ViewerOpenBottomSheetEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ViewerReloadAssetEvent extends Event {
|
||||||
|
const ViewerReloadAssetEvent();
|
||||||
|
}
|
||||||
|
|
||||||
class AssetViewerState {
|
class AssetViewerState {
|
||||||
final int backgroundOpacity;
|
final int backgroundOpacity;
|
||||||
final bool showingBottomSheet;
|
final bool showingBottomSheet;
|
||||||
|
@ -113,13 +113,14 @@ class MapThumbnail extends HookConsumerWidget {
|
|||||||
),
|
),
|
||||||
ValueListenableBuilder(
|
ValueListenableBuilder(
|
||||||
valueListenable: position,
|
valueListenable: position,
|
||||||
builder: (_, value, __) => value != null
|
builder: (_, value, __) =>
|
||||||
? PositionedAssetMarkerIcon(
|
value != null && assetMarkerRemoteId != null
|
||||||
size: height / 2,
|
? PositionedAssetMarkerIcon(
|
||||||
point: value,
|
size: height / 2,
|
||||||
assetRemoteId: assetMarkerRemoteId!,
|
point: value,
|
||||||
)
|
assetRemoteId: assetMarkerRemoteId!,
|
||||||
: const SizedBox.shrink(),
|
)
|
||||||
|
: const SizedBox.shrink(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
Loading…
x
Reference in New Issue
Block a user