mirror of
https://github.com/immich-app/immich.git
synced 2026-02-14 21:08:15 +03:00
refactoring...
This commit is contained in:
@@ -1,11 +1,11 @@
|
||||
import 'package:auto_route/auto_route.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_hooks/flutter_hooks.dart' hide Store;
|
||||
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/extensions/datetime_extensions.dart';
|
||||
import 'package:immich_mobile/models/activities/activity.model.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/action_buttons/like_activity_action_button.widget.dart';
|
||||
import 'package:immich_mobile/presentation/widgets/album/drift_activity_text_field.dart';
|
||||
@@ -13,8 +13,8 @@ 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';
|
||||
// activity_tile and dismissible_activity are no longer used in this page
|
||||
import 'package:immich_mobile/widgets/common/user_circle_avatar.dart';
|
||||
import 'package:immich_mobile/widgets/common/confirm_dialog.dart';
|
||||
import 'package:immich_mobile/providers/image/immich_remote_thumbnail_provider.dart';
|
||||
@@ -28,7 +28,7 @@ class DriftActivitiesPage extends HookConsumerWidget {
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final album = ref.watch(currentRemoteAlbumProvider)!;
|
||||
final asset = ref.read(currentAssetNotifier) as RemoteAsset?;
|
||||
final user = ref.watch(currentUserProvider);
|
||||
// final user = ref.watch(currentUserProvider);
|
||||
|
||||
final activityNotifier = ref.read(albumActivityProvider(album.id, asset?.id).notifier);
|
||||
final activities = ref.watch(albumActivityProvider(album.id, asset?.id));
|
||||
@@ -55,150 +55,22 @@ class DriftActivitiesPage extends HookConsumerWidget {
|
||||
),
|
||||
body: activities.widgetWhen(
|
||||
onData: (data) {
|
||||
final liked = data.firstWhereOrNull(
|
||||
(a) => a.type == ActivityType.like && a.user.id == user?.id && a.assetId == asset?.id,
|
||||
);
|
||||
|
||||
// チャット風レイアウト: 日付セパレータを削除し、ActivityTile をバブルに置換(コメント+画像は引用風)
|
||||
final List<Widget> activityWidgets = [];
|
||||
|
||||
for (final activity in data) {
|
||||
final isOwn = activity.user.id == user?.id;
|
||||
final canDelete = isOwn || album.ownerId == user?.id;
|
||||
|
||||
// Like: 自分の like はコメントと同じ青背景バブルで日時表示、他人の like は他人の comment と同形式にする
|
||||
if (activity.type == ActivityType.like) {
|
||||
final bubble = Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
child: _CommentBubble(
|
||||
activity: activity,
|
||||
isOwn: isOwn,
|
||||
showAssetImage: true,
|
||||
showHeart: true,
|
||||
onDelete: canDelete ? () async => await activityNotifier.removeActivity(activity.id) : null,
|
||||
),
|
||||
);
|
||||
|
||||
if (canDelete) {
|
||||
activityWidgets.add(
|
||||
Dismissible(
|
||||
key: Key(activity.id),
|
||||
dismissThresholds: const {DismissDirection.horizontal: 0.7},
|
||||
direction: DismissDirection.horizontal,
|
||||
confirmDismiss: (direction) => showDialog(
|
||||
context: context,
|
||||
builder: (context) => ConfirmDialog(
|
||||
onOk: () {},
|
||||
title: "shared_album_activity_remove_title",
|
||||
content: "shared_album_activity_remove_content",
|
||||
ok: "delete",
|
||||
),
|
||||
),
|
||||
onDismissed: (_) async => await activityNotifier.removeActivity(activity.id),
|
||||
background: Container(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
color: Colors.red[400],
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(15),
|
||||
child: Icon(Icons.delete_sweep_rounded, color: Colors.black),
|
||||
),
|
||||
),
|
||||
secondaryBackground: Container(
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
color: Colors.red[400],
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(15),
|
||||
child: Icon(Icons.delete_sweep_rounded, color: Colors.black),
|
||||
),
|
||||
),
|
||||
child: bubble,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
activityWidgets.add(bubble);
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// コメント(テキストまたは画像付き)はバブルで表示。ActivityTile は使わない
|
||||
if (activity.comment != null && activity.comment!.isNotEmpty) {
|
||||
// 画像がある場合は引用風: 画像のみを右寄せに表示する場合は isOwn で左右揃え
|
||||
final bubble = Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
child: _CommentBubble(
|
||||
activity: activity,
|
||||
isOwn: isOwn,
|
||||
showAssetImage: activity.assetId != null,
|
||||
onDelete: canDelete ? () async => await activityNotifier.removeActivity(activity.id) : null,
|
||||
),
|
||||
);
|
||||
|
||||
if (canDelete) {
|
||||
activityWidgets.add(
|
||||
Dismissible(
|
||||
key: Key(activity.id),
|
||||
dismissThresholds: const {DismissDirection.horizontal: 0.7},
|
||||
direction: DismissDirection.horizontal,
|
||||
confirmDismiss: (direction) => showDialog(
|
||||
context: context,
|
||||
builder: (context) => ConfirmDialog(
|
||||
onOk: () {},
|
||||
title: "shared_album_activity_remove_title",
|
||||
content: "shared_album_activity_remove_content",
|
||||
ok: "delete",
|
||||
),
|
||||
),
|
||||
onDismissed: (_) async => await activityNotifier.removeActivity(activity.id),
|
||||
background: Container(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
color: Colors.red[400],
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(15),
|
||||
child: Icon(Icons.delete_sweep_rounded, color: Colors.black),
|
||||
),
|
||||
),
|
||||
secondaryBackground: Container(
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
color: Colors.red[400],
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(15),
|
||||
child: Icon(Icons.delete_sweep_rounded, color: Colors.black),
|
||||
),
|
||||
),
|
||||
child: bubble,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
activityWidgets.add(bubble);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// その他(例: plain like without asset or system messages) - フォールバックで既存タイル表示
|
||||
activityWidgets.add(
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
|
||||
child: DismissibleActivity(
|
||||
activity.id,
|
||||
ActivityTile(activity),
|
||||
onDismiss: canDelete
|
||||
? (activityId) async => await activityNotifier.removeActivity(activity.id)
|
||||
: null,
|
||||
),
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
|
||||
child: _CommentBubble(activity: activity),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// 下部余白確保
|
||||
activityWidgets.add(const SizedBox(height: 80));
|
||||
|
||||
return SafeArea(
|
||||
child: Stack(
|
||||
children: [
|
||||
ListView(
|
||||
controller: listViewScrollController,
|
||||
padding: const EdgeInsets.only(top: 8, bottom: 0),
|
||||
padding: const EdgeInsets.only(top: 8, bottom: 80),
|
||||
children: activityWidgets,
|
||||
),
|
||||
Align(
|
||||
@@ -208,11 +80,7 @@ class DriftActivitiesPage extends HookConsumerWidget {
|
||||
color: context.scaffoldBackgroundColor,
|
||||
border: Border(top: BorderSide(color: context.colorScheme.secondaryContainer, width: 1)),
|
||||
),
|
||||
child: DriftActivityTextField(
|
||||
isEnabled: album.isActivityEnabled,
|
||||
likeId: liked?.id,
|
||||
onSubmit: onAddComment,
|
||||
),
|
||||
child: DriftActivityTextField(isEnabled: album.isActivityEnabled, onSubmit: onAddComment),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -225,168 +93,173 @@ class DriftActivitiesPage extends HookConsumerWidget {
|
||||
}
|
||||
}
|
||||
|
||||
// 日付フォーマット関数は現時点では不要
|
||||
|
||||
// _QuotedImage は使用しなくなったため削除。
|
||||
|
||||
class _CommentBubble extends ConsumerWidget {
|
||||
final Activity activity;
|
||||
final bool isOwn;
|
||||
final bool showAssetImage;
|
||||
final bool showHeart;
|
||||
final VoidCallback? onDelete;
|
||||
|
||||
const _CommentBubble({
|
||||
required this.activity,
|
||||
required this.isOwn,
|
||||
required this.showAssetImage,
|
||||
this.showHeart = false,
|
||||
this.onDelete,
|
||||
});
|
||||
const _CommentBubble({required this.activity});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
final bg = isOwn ? context.colorScheme.primaryContainer : context.colorScheme.surfaceContainer;
|
||||
return Align(
|
||||
alignment: isOwn ? Alignment.centerRight : Alignment.centerLeft,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.86),
|
||||
child: Container(
|
||||
margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 10),
|
||||
padding: const EdgeInsets.all(12),
|
||||
// decoration: BoxDecoration(color: bg, borderRadius: BorderRadius.circular(12)),
|
||||
child: Column(
|
||||
crossAxisAlignment: isOwn ? CrossAxisAlignment.end : CrossAxisAlignment.start,
|
||||
children: [
|
||||
// 名前やアイコンは不要(仕様)
|
||||
if (showAssetImage && activity.assetId != null)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8.0),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (!isOwn) ...[
|
||||
UserCircleAvatar(user: activity.user, size: 28, radius: 14),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 150, maxHeight: 150),
|
||||
child: Stack(
|
||||
children: [
|
||||
// Make thumbnail tappable to open asset viewer
|
||||
GestureDetector(
|
||||
onTap: () async {
|
||||
final activityService = ref.read(activityServiceProvider);
|
||||
if (activity.assetId == null) return;
|
||||
final route = await activityService.buildAssetViewerRoute(activity.assetId!, ref);
|
||||
if (route != null) {
|
||||
await context.pushRoute(route);
|
||||
}
|
||||
},
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(8),
|
||||
child: Image(
|
||||
image: ImmichRemoteThumbnailProvider(assetId: activity.assetId!),
|
||||
fit: BoxFit.contain,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (showHeart)
|
||||
Positioned(
|
||||
right: 6,
|
||||
bottom: 6,
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.white.withOpacity(0.9),
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Icon(Icons.favorite, color: Colors.red[600], size: 18),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// asset がない like の場合はバブル内にハートを表示
|
||||
if (showHeart && (activity.assetId == null || activity.assetId!.isEmpty))
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8.0),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if (!isOwn) ...[
|
||||
UserCircleAvatar(user: activity.user, size: 28, radius: 14),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
// For own like-only, push to right by wrapping with Align when parent is right-aligned.
|
||||
Container(
|
||||
padding: const EdgeInsets.all(6),
|
||||
decoration: BoxDecoration(color: Colors.white.withOpacity(0.9), shape: BoxShape.circle),
|
||||
child: Icon(Icons.favorite, color: Colors.red[600], size: 18),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
// コメント本文: コメントが存在する場合のみ表示(showAssetImage の有無でレイアウトを切替)
|
||||
if (activity.comment != null && activity.comment!.isNotEmpty) ...[
|
||||
if (!showAssetImage) ...[
|
||||
// コメントのみの表示: 自分の投稿は右寄せかつ本文幅に最小化、他人の投稿はアイコン表示とともに最小化
|
||||
Row(
|
||||
crossAxisAlignment: isOwn ? CrossAxisAlignment.end : CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (!isOwn) ...[
|
||||
UserCircleAvatar(user: activity.user, size: 28, radius: 14),
|
||||
const SizedBox(width: 8),
|
||||
],
|
||||
// For both own and non-own comment-only: minimize width to content, up to 50% of screen width.
|
||||
Expanded(
|
||||
child: Align(
|
||||
alignment: isOwn ? Alignment.centerRight : Alignment.centerLeft,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.5),
|
||||
child: IntrinsicWidth(
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(color: bg, borderRadius: BorderRadius.circular(12)),
|
||||
child: Text(
|
||||
activity.comment ?? '',
|
||||
style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurface),
|
||||
softWrap: true,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
] else ...[
|
||||
Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(color: bg, borderRadius: BorderRadius.circular(12)),
|
||||
child: Text(
|
||||
activity.comment ?? '',
|
||||
style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurface),
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
Text(
|
||||
// ユーザー名・日付と時間を表示
|
||||
'${activity.user.name} ・ ${activity.createdAt.year}/${activity.createdAt.month.toString().padLeft(2, '0')}/${activity.createdAt.day.toString().padLeft(2, '0')} '
|
||||
'${activity.createdAt.toLocal().toString().substring(11, 16)}',
|
||||
style: context.textTheme.labelSmall?.copyWith(
|
||||
color: context.colorScheme.onSurface.withValues(alpha: 0.6),
|
||||
final user = ref.watch(currentUserProvider);
|
||||
final album = ref.watch(currentRemoteAlbumProvider)!;
|
||||
final isOwn = activity.user.id == user?.id;
|
||||
final canDelete = isOwn || album.ownerId == user?.id;
|
||||
final hasAsset = activity.assetId != null && activity.assetId!.isNotEmpty;
|
||||
final isLike = activity.type == ActivityType.like;
|
||||
final bgColor = isOwn ? context.colorScheme.primaryContainer : context.colorScheme.surfaceContainer;
|
||||
|
||||
final activityNotifier = ref.read(albumActivityProvider(album.id, activity.assetId).notifier);
|
||||
|
||||
Future<void> openAssetViewer() async {
|
||||
final activityService = ref.read(activityServiceProvider);
|
||||
final route = await activityService.buildAssetViewerRoute(activity.assetId!, ref);
|
||||
if (route != null) await context.pushRoute(route);
|
||||
}
|
||||
|
||||
// avatar (hidden for own messages)
|
||||
Widget avatar() => isOwn ? const SizedBox.shrink() : UserCircleAvatar(user: activity.user, size: 28, radius: 14);
|
||||
|
||||
// Thumbnail with tappable behavior and optional heart overlay
|
||||
Widget? thumbnail() {
|
||||
if (!hasAsset) return null;
|
||||
return ConstrainedBox(
|
||||
// constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.5, maxHeight: 200),
|
||||
constraints: const BoxConstraints(maxWidth: 150, maxHeight: 150),
|
||||
child: Stack(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: openAssetViewer,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(10),
|
||||
child: Image(
|
||||
image: ImmichRemoteThumbnailProvider(assetId: activity.assetId!),
|
||||
fit: BoxFit.cover,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (isLike)
|
||||
Positioned(
|
||||
right: 6,
|
||||
bottom: 6,
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(4),
|
||||
decoration: BoxDecoration(color: Colors.white.withValues(alpha: 0.7), shape: BoxShape.circle),
|
||||
child: Icon(Icons.favorite, color: Colors.red[600], size: 18),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Heart-only widget (for likes without asset)
|
||||
Widget? likedToAlbum() {
|
||||
if (!isLike || hasAsset) return null;
|
||||
return Container(
|
||||
padding: const EdgeInsets.all(8),
|
||||
decoration: BoxDecoration(color: Colors.white.withValues(alpha: 0.7), shape: BoxShape.circle),
|
||||
child: Icon(Icons.favorite, color: Colors.red[600], size: 18),
|
||||
);
|
||||
}
|
||||
|
||||
// Comment bubble; for comment-only we constrain width to ~50%.
|
||||
Widget? commentBubble() {
|
||||
if (activity.comment == null || activity.comment!.isEmpty) return null;
|
||||
return ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.5),
|
||||
child: Container(
|
||||
padding: const EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(color: bgColor, borderRadius: BorderRadius.circular(12)),
|
||||
child: Text(
|
||||
activity.comment ?? '',
|
||||
style: context.textTheme.bodyMedium?.copyWith(color: context.colorScheme.onSurface),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
// Combined content: optional thumbnail, optional heart-only, optional comment
|
||||
final List<Widget> contentChildren = [thumbnail(), likedToAlbum(), commentBubble()].whereType<Widget>().toList();
|
||||
|
||||
return DismissibleActivity(
|
||||
onDismiss: canDelete ? (id) async => await activityNotifier.removeActivity(id) : null,
|
||||
activity.id,
|
||||
Align(
|
||||
alignment: isOwn ? Alignment.centerRight : Alignment.centerLeft,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(maxWidth: MediaQuery.of(context).size.width * 0.86),
|
||||
child: Container(
|
||||
margin: const EdgeInsets.symmetric(vertical: 6, horizontal: 10),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (!isOwn) ...[avatar(), const SizedBox(width: 8)],
|
||||
// Content column
|
||||
Column(
|
||||
crossAxisAlignment: isOwn ? CrossAxisAlignment.end : CrossAxisAlignment.start,
|
||||
children: [
|
||||
...contentChildren.map((w) => Padding(padding: const EdgeInsets.only(bottom: 8.0), child: w)),
|
||||
Text(
|
||||
'${activity.user.name} • ${activity.createdAt.timeAgo()}',
|
||||
style: context.textTheme.labelSmall?.copyWith(
|
||||
color: context.colorScheme.onSurface.withValues(alpha: 0.6),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (isOwn) const SizedBox(width: 8),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _DismissibleWrapper extends StatelessWidget {
|
||||
final String activityId;
|
||||
final VoidCallback? onDelete;
|
||||
final Widget child;
|
||||
|
||||
const _DismissibleWrapper({required this.activityId, required this.child, this.onDelete});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (onDelete == null) return child;
|
||||
|
||||
return Dismissible(
|
||||
key: Key(activityId),
|
||||
dismissThresholds: const {DismissDirection.horizontal: 0.7},
|
||||
direction: DismissDirection.horizontal,
|
||||
confirmDismiss: (direction) => showDialog(
|
||||
context: context,
|
||||
builder: (context) => ConfirmDialog(
|
||||
onOk: () {},
|
||||
title: "shared_album_activity_remove_title",
|
||||
content: "shared_album_activity_remove_content",
|
||||
ok: "delete",
|
||||
),
|
||||
),
|
||||
onDismissed: (_) async => onDelete?.call(),
|
||||
background: Container(
|
||||
alignment: AlignmentDirectional.centerStart,
|
||||
color: Colors.red[400],
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(15),
|
||||
child: Icon(Icons.delete_sweep_rounded, color: Colors.black),
|
||||
),
|
||||
),
|
||||
secondaryBackground: Container(
|
||||
alignment: AlignmentDirectional.centerEnd,
|
||||
color: Colors.red[400],
|
||||
child: const Padding(
|
||||
padding: EdgeInsets.all(15),
|
||||
child: Icon(Icons.delete_sweep_rounded, color: Colors.black),
|
||||
),
|
||||
),
|
||||
child: child,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,17 @@ import 'package:immich_mobile/widgets/common/confirm_dialog.dart';
|
||||
/// Wraps an [ActivityTile] and makes it dismissible
|
||||
class DismissibleActivity extends StatelessWidget {
|
||||
final String activityId;
|
||||
final ActivityTile body;
|
||||
final Widget body;
|
||||
final Function(String)? onDismiss;
|
||||
|
||||
const DismissibleActivity(this.activityId, this.body, {this.onDismiss, super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (onDismiss == null) {
|
||||
return body;
|
||||
}
|
||||
|
||||
return Dismissible(
|
||||
key: Key(activityId),
|
||||
dismissThresholds: const {DismissDirection.horizontal: 0.7},
|
||||
|
||||
Reference in New Issue
Block a user