-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: show all reactions in ReactionUsersSheet (#446)
* feat: show all reactions in ReactionUsersSheet * test: add test for NoteFooter * refactor: split buttons in NoteFooter into widgets * feat: show reacted users on long press add or remove reaction button
- Loading branch information
1 parent
8fbfe5e
commit 15e19dc
Showing
7 changed files
with
1,920 additions
and
514 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,98 +1,192 @@ | ||
import 'package:collection/collection.dart'; | ||
import 'package:flutter/material.dart'; | ||
import 'package:flutter_hooks/flutter_hooks.dart'; | ||
import 'package:go_router/go_router.dart'; | ||
import 'package:hooks_riverpod/hooks_riverpod.dart'; | ||
import 'package:misskey_dart/misskey_dart.dart'; | ||
|
||
import '../../extension/text_style_extension.dart'; | ||
import '../../i18n/strings.g.dart'; | ||
import '../../model/account.dart'; | ||
import '../../provider/api/reactions_notifier_provider.dart'; | ||
import '../../provider/misskey_colors_provider.dart'; | ||
import '../../provider/note_provider.dart'; | ||
import 'emoji_sheet.dart'; | ||
import 'emoji_widget.dart'; | ||
import 'paginated_list_view.dart'; | ||
import 'user_preview.dart'; | ||
import 'user_sheet.dart'; | ||
|
||
class ReactionUsersSheet extends ConsumerWidget { | ||
class ReactionUsersSheet extends HookConsumerWidget { | ||
const ReactionUsersSheet({ | ||
required this.account, | ||
required this.noteId, | ||
required this.reaction, | ||
this.initialReaction, | ||
}); | ||
|
||
final Account account; | ||
final String noteId; | ||
final String reaction; | ||
final String? initialReaction; | ||
|
||
@override | ||
Widget build(BuildContext context, WidgetRef ref) { | ||
final note = ref.watch(noteProvider(account, noteId)); | ||
final reactions = | ||
ref.watch(reactionsNotifierProvider(account, noteId, reaction)); | ||
final likeOnly = ref.watch( | ||
noteProvider(account, noteId).select( | ||
(note) => note?.reactionAcceptance == ReactionAcceptance.likeOnly, | ||
), | ||
); | ||
final emojis = ref.watch( | ||
noteProvider(account, noteId) | ||
.select((note) => {...?note?.emojis, ...?note?.reactionEmojis}), | ||
); | ||
final reactions = ref.watch( | ||
noteProvider(account, noteId).select( | ||
(note) => note?.reactions.entries | ||
.sortedBy<num>((e) => -e.value) | ||
.map((e) => e.key), | ||
), | ||
); | ||
final reaction = useState(initialReaction); | ||
final colors = | ||
ref.watch(misskeyColorsProvider(Theme.of(context).brightness)); | ||
final style = DefaultTextStyle.of(context).style; | ||
|
||
return DraggableScrollableSheet( | ||
minChildSize: 0.5, | ||
maxChildSize: 0.8, | ||
expand: false, | ||
builder: (context, scrollController) => Column( | ||
crossAxisAlignment: CrossAxisAlignment.start, | ||
children: [ | ||
Padding( | ||
padding: const EdgeInsets.all(12.0), | ||
child: Align( | ||
alignment: Alignment.centerLeft, | ||
child: Column( | ||
crossAxisAlignment: CrossAxisAlignment.start, | ||
const SizedBox(height: 12.0), | ||
if (!likeOnly) ...[ | ||
SizedBox( | ||
height: style.lineHeight * 1.8, | ||
child: ListView( | ||
scrollDirection: Axis.horizontal, | ||
children: [ | ||
EmojiWidget( | ||
account: account, | ||
emoji: reaction, | ||
style: DefaultTextStyle.of(context) | ||
.style | ||
.apply(fontSizeFactor: 1.5), | ||
emojis: {...?note?.emojis, ...?note?.reactionEmojis}, | ||
onTap: () => showModalBottomSheet<void>( | ||
context: context, | ||
builder: (context) => EmojiSheet( | ||
account: account, | ||
emoji: reaction, | ||
targetNote: note, | ||
const SizedBox(width: 12.0), | ||
...?reactions?.map( | ||
(emoji) => Padding( | ||
padding: const EdgeInsets.all(2.0), | ||
child: ElevatedButton( | ||
onPressed: () => reaction.value = emoji, | ||
style: ElevatedButton.styleFrom( | ||
padding: const EdgeInsets.symmetric( | ||
vertical: 2.0, | ||
horizontal: 4.0, | ||
), | ||
minimumSize: Size.zero, | ||
tapTargetSize: MaterialTapTargetSize.shrinkWrap, | ||
shape: RoundedRectangleBorder( | ||
borderRadius: BorderRadius.circular(4.0), | ||
), | ||
backgroundColor: emoji == reaction.value | ||
? colors.accent.withOpacity(0.5) | ||
: colors.buttonBg, | ||
elevation: 0.0, | ||
), | ||
child: ConstrainedBox( | ||
constraints: | ||
BoxConstraints(minHeight: style.lineHeight), | ||
child: EmojiWidget( | ||
style: style, | ||
account: account, | ||
emoji: emoji, | ||
emojis: emojis, | ||
), | ||
), | ||
), | ||
), | ||
), | ||
if (reaction.startsWith(':')) Text(reaction), | ||
const SizedBox(width: 12.0), | ||
], | ||
), | ||
), | ||
), | ||
Expanded( | ||
child: PaginatedListView( | ||
controller: scrollController, | ||
paginationState: reactions, | ||
itemBuilder: (context, reaction) => UserPreview( | ||
const Divider(), | ||
], | ||
if (reaction.value case final reaction?) ...[ | ||
Padding( | ||
padding: const EdgeInsets.symmetric(horizontal: 12.0), | ||
child: EmojiWidget( | ||
account: account, | ||
user: reaction.user, | ||
avatarSize: 50.0, | ||
onTap: () => | ||
context.push('/$account/users/${reaction.user.id}'), | ||
onLongPress: () => showUserSheet( | ||
emoji: reaction, | ||
style: style.apply(fontSizeFactor: 1.5), | ||
emojis: emojis, | ||
onTap: () => showModalBottomSheet<void>( | ||
context: context, | ||
account: account, | ||
userId: reaction.user.id, | ||
builder: (context) => EmojiSheet( | ||
account: account, | ||
emoji: reaction, | ||
targetNote: ref.read(noteProvider(account, noteId)), | ||
), | ||
), | ||
), | ||
onRefresh: () => ref.refresh( | ||
reactionsNotifierProvider(account, noteId, reaction).future, | ||
), | ||
if (reaction.startsWith(':')) ...[ | ||
const SizedBox(height: 2.0), | ||
Padding( | ||
padding: const EdgeInsets.symmetric(horizontal: 12.0), | ||
child: Text(reaction.replaceFirst('@.', '')), | ||
), | ||
], | ||
const SizedBox(height: 4.0), | ||
Expanded( | ||
child: _ReactionUsers( | ||
account: account, | ||
noteId: noteId, | ||
reaction: reaction, | ||
controller: scrollController, | ||
), | ||
loadMore: (skipError) => ref | ||
.read( | ||
reactionsNotifierProvider(account, noteId, reaction) | ||
.notifier, | ||
) | ||
.loadMore(skipError: skipError), | ||
noItemsLabel: t.misskey.noUsers, | ||
), | ||
), | ||
], | ||
], | ||
), | ||
); | ||
} | ||
} | ||
|
||
class _ReactionUsers extends ConsumerWidget { | ||
const _ReactionUsers({ | ||
required this.account, | ||
required this.noteId, | ||
required this.reaction, | ||
this.controller, | ||
}); | ||
|
||
final Account account; | ||
final String noteId; | ||
final String reaction; | ||
final ScrollController? controller; | ||
|
||
@override | ||
Widget build(BuildContext context, WidgetRef ref) { | ||
final reactions = | ||
ref.watch(reactionsNotifierProvider(account, noteId, reaction)); | ||
|
||
return PaginatedListView( | ||
controller: controller, | ||
paginationState: reactions, | ||
itemBuilder: (context, reaction) => UserPreview( | ||
account: account, | ||
user: reaction.user, | ||
avatarSize: 50.0, | ||
onTap: () => context.push('/$account/users/${reaction.user.id}'), | ||
onLongPress: () => showUserSheet( | ||
context: context, | ||
account: account, | ||
userId: reaction.user.id, | ||
), | ||
), | ||
onRefresh: () => ref.refresh( | ||
reactionsNotifierProvider(account, noteId, reaction).future, | ||
), | ||
loadMore: (skipError) => ref | ||
.read( | ||
reactionsNotifierProvider(account, noteId, reaction).notifier, | ||
) | ||
.loadMore(skipError: skipError), | ||
noItemsLabel: t.misskey.noUsers, | ||
); | ||
} | ||
} |
Oops, something went wrong.