feat(mobile): shared album activities (#20714)

* feat(mobile): shared album activities

* add like buttons and fix behavior of unliking

* fix: conditionally show activity button and fix title truncations

* fix(mobile): newest/oldest album sort (#20743)

* fix(mobile): newest/oldest album sort

* chore: use sqlite to determine album asset timestamps

* Fix missing future

Co-authored-by: Alex <alex.tran1502@gmail.com>

* fix: async handling of sort

* chore: tests

* chore: code review changes

* fix: use created at for newest asset

* fix: use localDateTime for sorting

* chore: cleanup

* chore: use final

* feat: loading indicator

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
Brandon Wees 2025-08-14 17:50:56 -05:00 committed by GitHub
parent 4d5975b717
commit 1926c90780
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 392 additions and 18 deletions

View file

@ -0,0 +1,63 @@
import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/models/activities/activity.model.dart';
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
import 'package:immich_mobile/providers/activity.provider.dart';
import 'package:immich_mobile/providers/infrastructure/asset_viewer/current_asset.provider.dart';
import 'package:immich_mobile/providers/infrastructure/current_album.provider.dart';
import 'package:immich_mobile/providers/user.provider.dart';
class LikeActivityActionButton extends ConsumerWidget {
const LikeActivityActionButton({super.key, this.menuItem = false});
final bool menuItem;
@override
Widget build(BuildContext context, WidgetRef ref) {
final album = ref.watch(currentRemoteAlbumProvider);
final asset = ref.watch(currentAssetNotifier) as RemoteAsset?;
final user = ref.watch(currentUserProvider);
final activities = ref.watch(albumActivityProvider(album?.id ?? "", asset?.id));
onTap(Activity? liked) async {
if (user == null) {
return;
}
if (liked != null) {
await ref.read(albumActivityProvider(album?.id ?? "", asset?.id).notifier).removeActivity(liked.id);
} else {
await ref.read(albumActivityProvider(album?.id ?? "", asset?.id).notifier).addLike();
}
ref.invalidate(albumActivityProvider(album?.id ?? "", asset?.id));
}
return activities.when(
data: (data) {
final liked = data.firstWhereOrNull(
(a) => a.type == ActivityType.like && a.user.id == user?.id && a.assetId == asset?.id,
);
return BaseActionButton(
iconData: liked != null ? Icons.favorite : Icons.favorite_border,
label: "like".t(context: context),
onPressed: () => onTap(liked),
menuItem: menuItem,
);
},
// default to empty heart during loading
loading: () => BaseActionButton(
iconData: Icons.favorite_border,
label: "like".t(context: context),
menuItem: menuItem,
),
error: (error, stack) => Text("Error: $error"),
);
}
}