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:
shenlong
2024-01-05 05:20:55 +00:00
committed by GitHub
parent d1e16025cf
commit af32183728
108 changed files with 2847 additions and 826 deletions
@@ -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",