feat(mobile): Change the UI of asset activity list to bottom sheet (#23075)

* init of activities bottom sheet

* reverse list order, padding bottom...

* chore: remove scrolling

* chore: clean up

* chore

---------

Co-authored-by: Alex <alex.tran1502@gmail.com>
This commit is contained in:
idubnori
2025-10-21 03:35:52 +09:00
committed by GitHub
parent 05f174a180
commit becb56e1b1
8 changed files with 243 additions and 27 deletions
@@ -0,0 +1,92 @@
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/asyncvalue_extensions.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/presentation/widgets/album/drift_activity_text_field.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';
import 'package:immich_mobile/widgets/activities/activity_tile.dart';
import 'package:immich_mobile/widgets/activities/dismissible_activity.dart';
import 'base_bottom_sheet.widget.dart';
class ActivitiesBottomSheet extends HookConsumerWidget {
final DraggableScrollableController controller;
final double initialChildSize;
final bool scrollToBottomInitially;
const ActivitiesBottomSheet({
required this.controller,
this.initialChildSize = 0.35,
this.scrollToBottomInitially = true,
super.key,
});
@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 activityNotifier = ref.read(albumActivityProvider(album.id, asset?.id).notifier);
final activities = ref.watch(albumActivityProvider(album.id, asset?.id));
Future<void> onAddComment(String comment) async {
await activityNotifier.addComment(comment);
}
Widget buildActivitiesSliver() {
return activities.widgetWhen(
onLoading: () => const SliverToBoxAdapter(child: SizedBox.shrink()),
onData: (data) {
return SliverList(
delegate: SliverChildBuilderDelegate((context, index) {
if (index == data.length) {
// return const SizedBox(height: 5);
return const SizedBox.shrink();
}
final activity = data[index];
final canDelete = activity.user.id == user?.id || album.ownerId == user?.id;
return Padding(
padding: const EdgeInsets.symmetric(vertical: 1),
child: DismissibleActivity(
activity.id,
ActivityTile(activity),
onDismiss: canDelete
? (activityId) async => await activityNotifier.removeActivity(activity.id)
: null,
),
);
}, childCount: data.length + 1),
);
},
);
}
return BaseBottomSheet(
actions: [],
slivers: [buildActivitiesSliver()],
footer: Column(
children: [
const Divider(indent: 16, endIndent: 16),
DriftActivityTextField(
isEnabled: album.isActivityEnabled,
isBottomSheet: true,
// likeId: likedId,
onSubmit: onAddComment,
),
],
),
controller: controller,
initialChildSize: initialChildSize,
minChildSize: 0.1,
maxChildSize: 0.88,
expand: false,
shouldCloseOnMinExtent: false,
resizeOnScroll: false,
backgroundColor: context.isDarkTheme ? Colors.black : Colors.white,
);
}
}
@@ -8,6 +8,7 @@ class BaseBottomSheet extends ConsumerStatefulWidget {
final List<Widget> actions;
final DraggableScrollableController? controller;
final List<Widget>? slivers;
final Widget? footer;
final double initialChildSize;
final double minChildSize;
final double maxChildSize;
@@ -20,6 +21,7 @@ class BaseBottomSheet extends ConsumerStatefulWidget {
super.key,
required this.actions,
this.slivers,
this.footer,
this.controller,
this.initialChildSize = 0.35,
double? minChildSize,
@@ -73,24 +75,35 @@ class _BaseDraggableScrollableSheetState extends ConsumerState<BaseBottomSheet>
elevation: 3.0,
shape: const RoundedRectangleBorder(borderRadius: BorderRadius.vertical(top: Radius.circular(18))),
margin: const EdgeInsets.symmetric(horizontal: 0),
child: CustomScrollView(
controller: scrollController,
slivers: [
const SliverPersistentHeader(delegate: _DragHandleDelegate(), pinned: true),
if (widget.actions.isNotEmpty)
SliverToBoxAdapter(
child: Column(
children: [
SizedBox(
height: 115,
child: ListView(shrinkWrap: true, scrollDirection: Axis.horizontal, children: widget.actions),
child: Column(
children: [
Expanded(
child: CustomScrollView(
controller: scrollController,
slivers: [
const SliverPersistentHeader(delegate: _DragHandleDelegate(), pinned: true),
if (widget.actions.isNotEmpty)
SliverToBoxAdapter(
child: Column(
children: [
SizedBox(
height: 115,
child: ListView(
shrinkWrap: true,
scrollDirection: Axis.horizontal,
children: widget.actions,
),
),
const Divider(indent: 16, endIndent: 16),
const SizedBox(height: 16),
],
),
),
const Divider(indent: 16, endIndent: 16),
const SizedBox(height: 16),
],
),
if (widget.slivers != null) ...widget.slivers!,
],
),
if (widget.slivers != null) ...widget.slivers!,
),
if (widget.footer != null) widget.footer!,
],
),
);