refactor(mobile): Activities (#5990)
* refactor: autoroutex pushroute * refactor: autoroutex popRoute * refactor: autoroutex navigate and replace * chore: add doc comments for extension methods * refactor: Add LoggerMixin and refactor Album activities to use mixin * refactor: Activity page * chore: activity user from user constructor * fix: update current asset after build method * refactor: tests with similar structure as lib * chore: remove avoid-declaring-call-method rule from dcm analysis * test: fix proper expect order * test: activity_statistics_provider_test * test: activity_provider_test * test: use proper matchers * test: activity_text_field_test & dismissible_activity_test added * test: add http mock to return transparent image * test: download isar core libs during test * test: add widget tags to widget test cases * test: activity_tile_test * build: currentAlbumProvider to generator * movie add / remove like to activity input tile * test: activities_page_test.dart * chore: better error logs * chore: dismissibleactivity as statelesswidget --------- Co-authored-by: shalong-tanwen <139912620+shalong-tanwen@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,15 @@
|
||||
import 'package:immich_mobile/shared/models/asset.dart';
|
||||
import 'package:riverpod_annotation/riverpod_annotation.dart';
|
||||
|
||||
part 'current_asset.provider.g.dart';
|
||||
|
||||
@riverpod
|
||||
class CurrentAsset extends _$CurrentAsset {
|
||||
@override
|
||||
Asset? build() => null;
|
||||
|
||||
void set(Asset? a) => state = a;
|
||||
}
|
||||
|
||||
/// Mock class for testing
|
||||
abstract class CurrentAssetInternal extends _$CurrentAsset {}
|
||||
@@ -0,0 +1,25 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'current_asset.provider.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// RiverpodGenerator
|
||||
// **************************************************************************
|
||||
|
||||
String _$currentAssetHash() => r'018d9f936991c48f06c11bf7e72130bba25806e2';
|
||||
|
||||
/// See also [CurrentAsset].
|
||||
@ProviderFor(CurrentAsset)
|
||||
final currentAssetProvider =
|
||||
AutoDisposeNotifierProvider<CurrentAsset, Asset?>.internal(
|
||||
CurrentAsset.new,
|
||||
name: r'currentAssetProvider',
|
||||
debugGetCreateSourceHash:
|
||||
const bool.fromEnvironment('dart.vm.product') ? null : _$currentAssetHash,
|
||||
dependencies: null,
|
||||
allTransitiveDependencies: null,
|
||||
);
|
||||
|
||||
typedef _$CurrentAsset = AutoDisposeNotifier<Asset?>;
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/modules/activities/providers/activity.provider.dart';
|
||||
import 'package:immich_mobile/modules/activities/providers/activity_statistics.provider.dart';
|
||||
import 'package:immich_mobile/modules/album/providers/current_album.provider.dart';
|
||||
import 'package:immich_mobile/shared/models/asset.dart';
|
||||
import 'package:immich_mobile/shared/providers/asset.provider.dart';
|
||||
@@ -39,12 +39,8 @@ class TopControlAppBar extends HookConsumerWidget {
|
||||
const double iconSize = 22.0;
|
||||
final a = ref.watch(assetWatcher(asset)).value ?? asset;
|
||||
final album = ref.watch(currentAlbumProvider);
|
||||
final comments = album != null && album.remoteId != null
|
||||
? ref.watch(
|
||||
activityStatisticsStateProvider(
|
||||
(albumId: album.remoteId!, assetId: asset.remoteId),
|
||||
),
|
||||
)
|
||||
final comments = album != null
|
||||
? ref.watch(activityStatisticsProvider(album.remoteId!, asset.remoteId))
|
||||
: 0;
|
||||
|
||||
Widget buildFavoriteButton(a) {
|
||||
@@ -149,7 +145,7 @@ class TopControlAppBar extends HookConsumerWidget {
|
||||
Widget buildBackButton() {
|
||||
return IconButton(
|
||||
onPressed: () {
|
||||
context.autoPop();
|
||||
context.popRoute();
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.arrow_back_ios_new_rounded,
|
||||
|
||||
@@ -11,6 +11,7 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||
import 'package:immich_mobile/extensions/build_context_extensions.dart';
|
||||
import 'package:immich_mobile/modules/album/providers/current_album.provider.dart';
|
||||
import 'package:immich_mobile/modules/asset_viewer/providers/asset_stack.provider.dart';
|
||||
import 'package:immich_mobile/modules/asset_viewer/providers/current_asset.provider.dart';
|
||||
import 'package:immich_mobile/modules/asset_viewer/providers/show_controls.provider.dart';
|
||||
import 'package:immich_mobile/modules/asset_viewer/providers/video_player_controls_provider.dart';
|
||||
import 'package:immich_mobile/modules/album/ui/add_to_album_bottom_sheet.dart';
|
||||
@@ -106,6 +107,19 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
|
||||
bool isParent = stackIndex.value == -1 || stackIndex.value == 0;
|
||||
|
||||
// Listen provider to prevent autoDispose when navigating to other routes from within the gallery page
|
||||
ref.listen(currentAssetProvider, (_, __) {});
|
||||
useEffect(
|
||||
() {
|
||||
// Delay state update to after the execution of build method
|
||||
Future.microtask(
|
||||
() => ref.read(currentAssetProvider.notifier).set(asset()),
|
||||
);
|
||||
return null;
|
||||
},
|
||||
[asset()],
|
||||
);
|
||||
|
||||
useEffect(
|
||||
() {
|
||||
isLoadPreview.value =
|
||||
@@ -214,7 +228,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
if (isDeleted && isParent) {
|
||||
if (totalAssets == 1) {
|
||||
// Handle only one asset
|
||||
context.autoPop();
|
||||
context.popRoute();
|
||||
} else {
|
||||
// Go to next page otherwise
|
||||
controller.nextPage(
|
||||
@@ -298,7 +312,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
|
||||
final ratio = d.dy / max(d.dx.abs(), 1);
|
||||
if (d.dy > sensitivity && ratio > ratioThreshold) {
|
||||
context.autoPop();
|
||||
context.popRoute();
|
||||
} else if (d.dy < -sensitivity && ratio < -ratioThreshold) {
|
||||
showInfo();
|
||||
}
|
||||
@@ -311,7 +325,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
handleArchive(Asset asset) {
|
||||
ref.watch(assetProvider.notifier).toggleArchive([asset]);
|
||||
if (isParent) {
|
||||
context.autoPop();
|
||||
context.popRoute();
|
||||
return;
|
||||
}
|
||||
removeAssetFromStack();
|
||||
@@ -334,14 +348,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
|
||||
handleActivities() {
|
||||
if (album != null && album.shared && album.remoteId != null) {
|
||||
context.autoPush(
|
||||
ActivitiesRoute(
|
||||
albumId: album.remoteId!,
|
||||
assetId: asset().remoteId,
|
||||
withAssetThumbs: false,
|
||||
isOwner: isOwner,
|
||||
),
|
||||
);
|
||||
context.pushRoute(const ActivitiesRoute());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -517,7 +524,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
stackElements.elementAt(stackIndex.value),
|
||||
);
|
||||
ctx.pop();
|
||||
context.autoPop();
|
||||
context.popRoute();
|
||||
},
|
||||
title: const Text(
|
||||
"viewer_stack_use_as_main_asset",
|
||||
@@ -544,7 +551,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
childrenToRemove: [currentAsset],
|
||||
);
|
||||
ctx.pop();
|
||||
context.autoPop();
|
||||
context.popRoute();
|
||||
} else {
|
||||
await ref.read(assetStackServiceProvider).updateStack(
|
||||
currentAsset,
|
||||
@@ -572,7 +579,7 @@ class GalleryViewerPage extends HookConsumerWidget {
|
||||
childrenToRemove: stack,
|
||||
);
|
||||
ctx.pop();
|
||||
context.autoPop();
|
||||
context.popRoute();
|
||||
},
|
||||
title: const Text(
|
||||
"viewer_unstack",
|
||||
|
||||
Reference in New Issue
Block a user