refactor(mobile): services and providers (#9232)

* refactor(mobile): services and provider

* providers
This commit is contained in:
Alex 2024-05-02 15:59:14 -05:00 committed by GitHub
parent ec4eb7cd19
commit c1253663b7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
242 changed files with 497 additions and 503 deletions

View file

@ -1,67 +0,0 @@
import 'package:immich_mobile/models/activities/activity.model.dart';
import 'package:immich_mobile/modules/activities/providers/activity_service.provider.dart';
import 'package:immich_mobile/modules/activities/providers/activity_statistics.provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'activity.provider.g.dart';
/// Maintains the current list of all activities for <share-album-id, asset>
@riverpod
class AlbumActivity extends _$AlbumActivity {
@override
Future<List<Activity>> build(String albumId, [String? assetId]) async {
return ref
.watch(activityServiceProvider)
.getAllActivities(albumId, assetId: assetId);
}
Future<void> removeActivity(String id) async {
if (await ref.watch(activityServiceProvider).removeActivity(id)) {
final activities = state.valueOrNull ?? [];
final removedActivity = activities.firstWhere((a) => a.id == id);
activities.remove(removedActivity);
state = AsyncData(activities);
// Decrement activity count only for comments
if (removedActivity.type == ActivityType.comment) {
ref
.watch(activityStatisticsProvider(albumId, assetId).notifier)
.removeActivity();
}
}
}
Future<void> addLike() async {
final activity = await ref
.watch(activityServiceProvider)
.addActivity(albumId, ActivityType.like, assetId: assetId);
if (activity.hasValue) {
final activities = state.asData?.value ?? [];
state = AsyncData([...activities, activity.requireValue]);
}
}
Future<void> addComment(String comment) async {
final activity = await ref.watch(activityServiceProvider).addActivity(
albumId,
ActivityType.comment,
assetId: assetId,
comment: comment,
);
if (activity.hasValue) {
final activities = state.valueOrNull ?? [];
state = AsyncData([...activities, activity.requireValue]);
ref
.watch(activityStatisticsProvider(albumId, assetId).notifier)
.addActivity();
// The previous addActivity call would increase the count of an asset if assetId != null
// To also increase the activity count of the album, calling it once again with assetId set to null
if (assetId != null) {
ref.watch(activityStatisticsProvider(albumId).notifier).addActivity();
}
}
}
}
/// Mock class for testing
abstract class AlbumActivityInternal extends _$AlbumActivity {}

View file

@ -1,209 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'activity.provider.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$albumActivityHash() => r'3b0d7acee4d41c84b3f220784c3b904c83f836e6';
/// Copied from Dart SDK
class _SystemHash {
_SystemHash._();
static int combine(int hash, int value) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + value);
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(int hash) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
abstract class _$AlbumActivity
extends BuildlessAutoDisposeAsyncNotifier<List<Activity>> {
late final String albumId;
late final String? assetId;
FutureOr<List<Activity>> build(
String albumId, [
String? assetId,
]);
}
/// Maintains the current list of all activities for <share-album-id, asset>
///
/// Copied from [AlbumActivity].
@ProviderFor(AlbumActivity)
const albumActivityProvider = AlbumActivityFamily();
/// Maintains the current list of all activities for <share-album-id, asset>
///
/// Copied from [AlbumActivity].
class AlbumActivityFamily extends Family<AsyncValue<List<Activity>>> {
/// Maintains the current list of all activities for <share-album-id, asset>
///
/// Copied from [AlbumActivity].
const AlbumActivityFamily();
/// Maintains the current list of all activities for <share-album-id, asset>
///
/// Copied from [AlbumActivity].
AlbumActivityProvider call(
String albumId, [
String? assetId,
]) {
return AlbumActivityProvider(
albumId,
assetId,
);
}
@override
AlbumActivityProvider getProviderOverride(
covariant AlbumActivityProvider provider,
) {
return call(
provider.albumId,
provider.assetId,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'albumActivityProvider';
}
/// Maintains the current list of all activities for <share-album-id, asset>
///
/// Copied from [AlbumActivity].
class AlbumActivityProvider extends AutoDisposeAsyncNotifierProviderImpl<
AlbumActivity, List<Activity>> {
/// Maintains the current list of all activities for <share-album-id, asset>
///
/// Copied from [AlbumActivity].
AlbumActivityProvider(
String albumId, [
String? assetId,
]) : this._internal(
() => AlbumActivity()
..albumId = albumId
..assetId = assetId,
from: albumActivityProvider,
name: r'albumActivityProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$albumActivityHash,
dependencies: AlbumActivityFamily._dependencies,
allTransitiveDependencies:
AlbumActivityFamily._allTransitiveDependencies,
albumId: albumId,
assetId: assetId,
);
AlbumActivityProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.albumId,
required this.assetId,
}) : super.internal();
final String albumId;
final String? assetId;
@override
FutureOr<List<Activity>> runNotifierBuild(
covariant AlbumActivity notifier,
) {
return notifier.build(
albumId,
assetId,
);
}
@override
Override overrideWith(AlbumActivity Function() create) {
return ProviderOverride(
origin: this,
override: AlbumActivityProvider._internal(
() => create()
..albumId = albumId
..assetId = assetId,
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
albumId: albumId,
assetId: assetId,
),
);
}
@override
AutoDisposeAsyncNotifierProviderElement<AlbumActivity, List<Activity>>
createElement() {
return _AlbumActivityProviderElement(this);
}
@override
bool operator ==(Object other) {
return other is AlbumActivityProvider &&
other.albumId == albumId &&
other.assetId == assetId;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, albumId.hashCode);
hash = _SystemHash.combine(hash, assetId.hashCode);
return _SystemHash.finish(hash);
}
}
mixin AlbumActivityRef on AutoDisposeAsyncNotifierProviderRef<List<Activity>> {
/// The parameter `albumId` of this provider.
String get albumId;
/// The parameter `assetId` of this provider.
String? get assetId;
}
class _AlbumActivityProviderElement
extends AutoDisposeAsyncNotifierProviderElement<AlbumActivity,
List<Activity>> with AlbumActivityRef {
_AlbumActivityProviderElement(super.provider);
@override
String get albumId => (origin as AlbumActivityProvider).albumId;
@override
String? get assetId => (origin as AlbumActivityProvider).assetId;
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View file

@ -1,9 +0,0 @@
import 'package:immich_mobile/modules/activities/services/activity.service.dart';
import 'package:immich_mobile/shared/providers/api.provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'activity_service.provider.g.dart';
@riverpod
ActivityService activityService(ActivityServiceRef ref) =>
ActivityService(ref.watch(apiServiceProvider));

View file

@ -1,25 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'activity_service.provider.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$activityServiceHash() => r'5dd4955d14f5bf01c00d7f8750d07e7ace7cc4b0';
/// See also [activityService].
@ProviderFor(activityService)
final activityServiceProvider = AutoDisposeProvider<ActivityService>.internal(
activityService,
name: r'activityServiceProvider',
debugGetCreateSourceHash: const bool.fromEnvironment('dart.vm.product')
? null
: _$activityServiceHash,
dependencies: null,
allTransitiveDependencies: null,
);
typedef ActivityServiceRef = AutoDisposeProviderRef<ActivityService>;
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View file

@ -1,24 +0,0 @@
import 'package:immich_mobile/modules/activities/providers/activity_service.provider.dart';
import 'package:riverpod_annotation/riverpod_annotation.dart';
part 'activity_statistics.provider.g.dart';
/// Maintains the current number of comments by <shared-album, asset>
@riverpod
class ActivityStatistics extends _$ActivityStatistics {
@override
int build(String albumId, [String? assetId]) {
ref
.watch(activityServiceProvider)
.getStatistics(albumId, assetId: assetId)
.then((comments) => state = comments);
return 0;
}
void addActivity() => state = state + 1;
void removeActivity() => state = state - 1;
}
/// Mock class for testing
abstract class ActivityStatisticsInternal extends _$ActivityStatistics {}

View file

@ -1,208 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'activity_statistics.provider.dart';
// **************************************************************************
// RiverpodGenerator
// **************************************************************************
String _$activityStatisticsHash() =>
r'a5f7bbee1891c33b72919a34e632ca9ef9cd8dbf';
/// Copied from Dart SDK
class _SystemHash {
_SystemHash._();
static int combine(int hash, int value) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + value);
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x0007ffff & hash) << 10));
return hash ^ (hash >> 6);
}
static int finish(int hash) {
// ignore: parameter_assignments
hash = 0x1fffffff & (hash + ((0x03ffffff & hash) << 3));
// ignore: parameter_assignments
hash = hash ^ (hash >> 11);
return 0x1fffffff & (hash + ((0x00003fff & hash) << 15));
}
}
abstract class _$ActivityStatistics extends BuildlessAutoDisposeNotifier<int> {
late final String albumId;
late final String? assetId;
int build(
String albumId, [
String? assetId,
]);
}
/// Maintains the current number of comments by <shared-album, asset>
///
/// Copied from [ActivityStatistics].
@ProviderFor(ActivityStatistics)
const activityStatisticsProvider = ActivityStatisticsFamily();
/// Maintains the current number of comments by <shared-album, asset>
///
/// Copied from [ActivityStatistics].
class ActivityStatisticsFamily extends Family<int> {
/// Maintains the current number of comments by <shared-album, asset>
///
/// Copied from [ActivityStatistics].
const ActivityStatisticsFamily();
/// Maintains the current number of comments by <shared-album, asset>
///
/// Copied from [ActivityStatistics].
ActivityStatisticsProvider call(
String albumId, [
String? assetId,
]) {
return ActivityStatisticsProvider(
albumId,
assetId,
);
}
@override
ActivityStatisticsProvider getProviderOverride(
covariant ActivityStatisticsProvider provider,
) {
return call(
provider.albumId,
provider.assetId,
);
}
static const Iterable<ProviderOrFamily>? _dependencies = null;
@override
Iterable<ProviderOrFamily>? get dependencies => _dependencies;
static const Iterable<ProviderOrFamily>? _allTransitiveDependencies = null;
@override
Iterable<ProviderOrFamily>? get allTransitiveDependencies =>
_allTransitiveDependencies;
@override
String? get name => r'activityStatisticsProvider';
}
/// Maintains the current number of comments by <shared-album, asset>
///
/// Copied from [ActivityStatistics].
class ActivityStatisticsProvider
extends AutoDisposeNotifierProviderImpl<ActivityStatistics, int> {
/// Maintains the current number of comments by <shared-album, asset>
///
/// Copied from [ActivityStatistics].
ActivityStatisticsProvider(
String albumId, [
String? assetId,
]) : this._internal(
() => ActivityStatistics()
..albumId = albumId
..assetId = assetId,
from: activityStatisticsProvider,
name: r'activityStatisticsProvider',
debugGetCreateSourceHash:
const bool.fromEnvironment('dart.vm.product')
? null
: _$activityStatisticsHash,
dependencies: ActivityStatisticsFamily._dependencies,
allTransitiveDependencies:
ActivityStatisticsFamily._allTransitiveDependencies,
albumId: albumId,
assetId: assetId,
);
ActivityStatisticsProvider._internal(
super._createNotifier, {
required super.name,
required super.dependencies,
required super.allTransitiveDependencies,
required super.debugGetCreateSourceHash,
required super.from,
required this.albumId,
required this.assetId,
}) : super.internal();
final String albumId;
final String? assetId;
@override
int runNotifierBuild(
covariant ActivityStatistics notifier,
) {
return notifier.build(
albumId,
assetId,
);
}
@override
Override overrideWith(ActivityStatistics Function() create) {
return ProviderOverride(
origin: this,
override: ActivityStatisticsProvider._internal(
() => create()
..albumId = albumId
..assetId = assetId,
from: from,
name: null,
dependencies: null,
allTransitiveDependencies: null,
debugGetCreateSourceHash: null,
albumId: albumId,
assetId: assetId,
),
);
}
@override
AutoDisposeNotifierProviderElement<ActivityStatistics, int> createElement() {
return _ActivityStatisticsProviderElement(this);
}
@override
bool operator ==(Object other) {
return other is ActivityStatisticsProvider &&
other.albumId == albumId &&
other.assetId == assetId;
}
@override
int get hashCode {
var hash = _SystemHash.combine(0, runtimeType.hashCode);
hash = _SystemHash.combine(hash, albumId.hashCode);
hash = _SystemHash.combine(hash, assetId.hashCode);
return _SystemHash.finish(hash);
}
}
mixin ActivityStatisticsRef on AutoDisposeNotifierProviderRef<int> {
/// The parameter `albumId` of this provider.
String get albumId;
/// The parameter `assetId` of this provider.
String? get assetId;
}
class _ActivityStatisticsProviderElement
extends AutoDisposeNotifierProviderElement<ActivityStatistics, int>
with ActivityStatisticsRef {
_ActivityStatisticsProviderElement(super.provider);
@override
String get albumId => (origin as ActivityStatisticsProvider).albumId;
@override
String? get assetId => (origin as ActivityStatisticsProvider).assetId;
}
// ignore_for_file: type=lint
// ignore_for_file: subtype_of_sealed_class, invalid_use_of_internal_member, invalid_use_of_visible_for_testing_member

View file

@ -1,80 +0,0 @@
import 'package:immich_mobile/constants/errors.dart';
import 'package:immich_mobile/mixins/error_logger.mixin.dart';
import 'package:immich_mobile/models/activities/activity.model.dart';
import 'package:immich_mobile/shared/services/api.service.dart';
import 'package:logging/logging.dart';
import 'package:openapi/api.dart';
class ActivityService with ErrorLoggerMixin {
final ApiService _apiService;
@override
final Logger logger = Logger("ActivityService");
ActivityService(this._apiService);
Future<List<Activity>> getAllActivities(
String albumId, {
String? assetId,
}) async {
return logError(
() async {
final list = await _apiService.activityApi
.getActivities(albumId, assetId: assetId);
return list != null ? list.map(Activity.fromDto).toList() : [];
},
defaultValue: [],
errorMessage: "Failed to get all activities for album $albumId",
);
}
Future<int> getStatistics(String albumId, {String? assetId}) async {
return logError(
() async {
final dto = await _apiService.activityApi
.getActivityStatistics(albumId, assetId: assetId);
return dto?.comments ?? 0;
},
defaultValue: 0,
errorMessage: "Failed to statistics for album $albumId",
);
}
Future<bool> removeActivity(String id) async {
return logError(
() async {
await _apiService.activityApi.deleteActivity(id);
return true;
},
defaultValue: false,
errorMessage: "Failed to delete activity",
);
}
AsyncFuture<Activity> addActivity(
String albumId,
ActivityType type, {
String? assetId,
String? comment,
}) async {
return guardError(
() async {
final dto = await _apiService.activityApi.createActivity(
ActivityCreateDto(
albumId: albumId,
type: type == ActivityType.comment
? ReactionType.comment
: ReactionType.like,
assetId: assetId,
comment: comment,
),
);
if (dto != null) {
return Activity.fromDto(dto);
}
throw NoResponseDtoError();
},
errorMessage: "Failed to create $type for album $albumId",
);
}
}

View file

@ -6,13 +6,13 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/asyncvalue_extensions.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/models/activities/activity.model.dart';
import 'package:immich_mobile/modules/activities/providers/activity.provider.dart';
import 'package:immich_mobile/providers/activity.provider.dart';
import 'package:immich_mobile/modules/activities/widgets/activity_text_field.dart';
import 'package:immich_mobile/modules/activities/widgets/activity_tile.dart';
import 'package:immich_mobile/modules/activities/widgets/dismissible_activity.dart';
import 'package:immich_mobile/modules/album/providers/current_album.provider.dart';
import 'package:immich_mobile/modules/asset_viewer/providers/current_asset.provider.dart';
import 'package:immich_mobile/shared/providers/user.provider.dart';
import 'package:immich_mobile/providers/album/current_album.provider.dart';
import 'package:immich_mobile/providers/asset_viewer/current_asset.provider.dart';
import 'package:immich_mobile/providers/user.provider.dart';
@RoutePage()
class ActivitiesPage extends HookConsumerWidget {

View file

@ -2,10 +2,10 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/modules/activities/providers/activity.provider.dart';
import 'package:immich_mobile/modules/album/providers/current_album.provider.dart';
import 'package:immich_mobile/modules/asset_viewer/providers/current_asset.provider.dart';
import 'package:immich_mobile/shared/providers/user.provider.dart';
import 'package:immich_mobile/providers/activity.provider.dart';
import 'package:immich_mobile/providers/album/current_album.provider.dart';
import 'package:immich_mobile/providers/asset_viewer/current_asset.provider.dart';
import 'package:immich_mobile/providers/user.provider.dart';
import 'package:immich_mobile/shared/ui/user_circle_avatar.dart';
class ActivityTextField extends HookConsumerWidget {

View file

@ -3,8 +3,8 @@ import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/datetime_extensions.dart';
import 'package:immich_mobile/models/activities/activity.model.dart';
import 'package:immich_mobile/modules/asset_viewer/image_providers/immich_remote_thumbnail_provider.dart';
import 'package:immich_mobile/modules/asset_viewer/providers/current_asset.provider.dart';
import 'package:immich_mobile/providers/image/immich_remote_thumbnail_provider.dart';
import 'package:immich_mobile/providers/asset_viewer/current_asset.provider.dart';
import 'package:immich_mobile/shared/ui/user_circle_avatar.dart';
class ActivityTile extends HookConsumerWidget {