💄 Optimized reaction sheet

This commit is contained in:
2025-07-31 22:27:25 +08:00
parent 9be6fea2e0
commit d04b06089c
4 changed files with 86 additions and 25 deletions

View File

@@ -710,5 +710,16 @@
"fileIdHint": "The file ID is the ID you get after upload the file via the Solar Network Drive.", "fileIdHint": "The file ID is the ID you get after upload the file via the Solar Network Drive.",
"translate": "Translate", "translate": "Translate",
"translating": "Translating", "translating": "Translating",
"translated": "Translated" "translated": "Translated",
"reactionThumbUp": "Thumbs Up",
"reactionThumbDown": "Thumbs Down",
"reactionJustOkay": "Just Okay",
"reactionCry": "Cry",
"reactionConfuse": "Confused",
"reactionClap": "Clap",
"reactionLaugh": "Laugh",
"reactionAngry": "Angry",
"reactionParty": "Party",
"reactionPray": "Pray",
"reactionHeart": "Heart"
} }

View File

@@ -78,6 +78,13 @@ sealed class SnSubscriptionStatus with _$SnSubscriptionStatus {
sealed class ReactInfo with _$ReactInfo { sealed class ReactInfo with _$ReactInfo {
const factory ReactInfo({required String icon, required int attitude}) = const factory ReactInfo({required String icon, required int attitude}) =
_ReactInfo; _ReactInfo;
static String getTranslationKey(String templateKey) {
final parts = templateKey.split('_');
final camelCase =
parts.map((p) => p[0].toUpperCase() + p.substring(1)).join();
return 'reaction$camelCase';
}
} }
const Map<String, ReactInfo> kReactionTemplates = { const Map<String, ReactInfo> kReactionTemplates = {

View File

@@ -383,6 +383,7 @@ class PostItem extends HookConsumerWidget {
builder: (BuildContext context) { builder: (BuildContext context) {
return _PostReactionSheet( return _PostReactionSheet(
reactionsCount: item.reactionsCount, reactionsCount: item.reactionsCount,
reactionsMade: item.reactionsMade,
onReact: (symbol, attitude) { onReact: (symbol, attitude) {
reactPost(symbol, attitude); reactPost(symbol, attitude);
}, },
@@ -701,12 +702,14 @@ Widget _buildReferencePost(
class PostReactionList extends HookConsumerWidget { class PostReactionList extends HookConsumerWidget {
final String parentId; final String parentId;
final Map<String, int> reactions; final Map<String, int> reactions;
final Map<String, bool> reactionsMade;
final Function(String symbol, int attitude, int delta)? onReact; final Function(String symbol, int attitude, int delta)? onReact;
final EdgeInsets? padding; final EdgeInsets? padding;
const PostReactionList({ const PostReactionList({
super.key, super.key,
required this.parentId, required this.parentId,
required this.reactions, required this.reactions,
required this.reactionsMade,
this.padding, this.padding,
this.onReact, this.onReact,
}); });
@@ -760,6 +763,7 @@ class PostReactionList extends HookConsumerWidget {
builder: (BuildContext context) { builder: (BuildContext context) {
return _PostReactionSheet( return _PostReactionSheet(
reactionsCount: reactions, reactionsCount: reactions,
reactionsMade: reactionsMade,
onReact: (symbol, attitude) { onReact: (symbol, attitude) {
reactPost(symbol, attitude); reactPost(symbol, attitude);
}, },
@@ -804,9 +808,11 @@ class PostReactionList extends HookConsumerWidget {
class _PostReactionSheet extends StatelessWidget { class _PostReactionSheet extends StatelessWidget {
final Map<String, int> reactionsCount; final Map<String, int> reactionsCount;
final Map<String, bool> reactionsMade;
final Function(String symbol, int attitude) onReact; final Function(String symbol, int attitude) onReact;
const _PostReactionSheet({ const _PostReactionSheet({
required this.reactionsCount, required this.reactionsCount,
required this.reactionsMade,
required this.onReact, required this.onReact,
}); });
@@ -843,9 +849,24 @@ class _PostReactionSheet extends StatelessWidget {
Expanded( Expanded(
child: ListView( child: ListView(
children: [ children: [
_buildReactionSection(context, 'Positive Reactions', 0), _buildReactionSection(
_buildReactionSection(context, 'Neutral Reactions', 1), context,
_buildReactionSection(context, 'Negative Reactions', 2), Symbols.mood,
'reactionPositive'.tr(),
0,
),
_buildReactionSection(
context,
Symbols.sentiment_neutral,
'reactionNeutral'.tr(),
1,
),
_buildReactionSection(
context,
Symbols.mood_bad,
'reactionNegative'.tr(),
2,
),
], ],
), ),
), ),
@@ -855,6 +876,7 @@ class _PostReactionSheet extends StatelessWidget {
Widget _buildReactionSection( Widget _buildReactionSection(
BuildContext context, BuildContext context,
IconData icon,
String title, String title,
int attitude, int attitude,
) { ) {
@@ -867,38 +889,58 @@ class _PostReactionSheet extends StatelessWidget {
return Column( return Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text(title).fontSize(20).bold().padding(horizontal: 20, vertical: 12), Row(
crossAxisAlignment: CrossAxisAlignment.center,
spacing: 8,
children: [Icon(icon), Text(title).fontSize(17).bold()],
).padding(horizontal: 24, top: 16, bottom: 6),
SizedBox( SizedBox(
height: 84, height: 120,
child: GridView.builder( child: GridView.builder(
scrollDirection: Axis.horizontal, scrollDirection: Axis.horizontal,
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount( gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 1, crossAxisCount: 1,
mainAxisExtent: 100, mainAxisExtent: 120,
mainAxisSpacing: 8.0, mainAxisSpacing: 8.0,
crossAxisSpacing: 8.0, crossAxisSpacing: 8.0,
childAspectRatio: 2.0, childAspectRatio: 1.0,
), ),
padding: EdgeInsets.symmetric(horizontal: 16),
itemCount: allReactions.length, itemCount: allReactions.length,
itemBuilder: (context, index) { itemBuilder: (context, index) {
final symbol = allReactions[index]; final symbol = allReactions[index];
final count = reactionsCount[symbol] ?? 0; final count = reactionsCount[symbol] ?? 0;
return InkWell( return Card(
onTap: () { margin: EdgeInsets.symmetric(vertical: 4),
onReact(symbol, attitude); color:
Navigator.pop(context); (reactionsMade[symbol] ?? false)
}, ? Theme.of(context).colorScheme.primaryContainer
child: GridTile( : Theme.of(context).colorScheme.surfaceContainerLowest,
header: Text( child: InkWell(
kReactionTemplates[symbol]?.icon ?? '', borderRadius: BorderRadius.all(Radius.circular(8)),
textAlign: TextAlign.center, onTap: () {
).fontSize(24), onReact(symbol, attitude);
footer: Text( Navigator.pop(context);
count > 0 ? 'x$count' : '', },
textAlign: TextAlign.center, child: Column(
).bold().padding(bottom: 12), mainAxisAlignment: MainAxisAlignment.center,
child: Center( children: [
child: Text(symbol, textAlign: TextAlign.center), Text(
kReactionTemplates[symbol]?.icon ?? '',
textAlign: TextAlign.center,
).fontSize(24),
Text(
ReactInfo.getTranslationKey(symbol),
textAlign: TextAlign.center,
).tr(),
if (count > 0)
Text(
'x$count',
textAlign: TextAlign.center,
).bold().padding(bottom: 4)
else
const Gap(20),
],
), ),
), ),
); );

View File

@@ -370,6 +370,7 @@ class PostItemCreator extends HookConsumerWidget {
PostReactionList( PostReactionList(
parentId: item.id, parentId: item.id,
reactions: item.reactionsCount, reactions: item.reactionsCount,
reactionsMade: item.reactionsMade,
padding: EdgeInsets.zero, padding: EdgeInsets.zero,
), ),
const Gap(16), const Gap(16),