Add reaction picker for selecting emoji reactions

- Create ReactionPicker component with 24 common emoji options
- Show emoji grid in dialog with proper styling
- Update PostActions to show picker instead of default heart
- Add _showReactionPicker method with showDialog
- Update ReactionStrip onAdd callback to use picker
- Maintain full reaction functionality with user choice
- Add proper styling with borders and shadows to picker
This commit is contained in:
Patrick Britton 2026-02-01 14:07:39 -06:00
parent fb9748c795
commit 6cb19b056d
2 changed files with 141 additions and 1 deletions

View file

@ -8,6 +8,7 @@ import '../../providers/api_provider.dart';
import '../../theme/app_theme.dart';
import '../sojorn_snackbar.dart';
import '../reactions/reaction_strip.dart';
import '../reactions/reaction_picker.dart';
/// Post actions with a vibrant, clear, and energetic design.
///
@ -137,6 +138,20 @@ class _PostActionsState extends ConsumerState<PostActions> {
}
}
void _showReactionPicker() {
showDialog(
context: context,
builder: (context) => ReactionPicker(
onReactionSelected: (emoji) {
_toggleReaction(emoji);
},
onClosed: () {
// Optional: Handle picker closed without selection
},
),
);
}
Future<void> _toggleReaction(String emoji) async {
final previousCounts = Map<String, int>.from(_reactionCounts);
final previousMine = Set<String>.from(_myReactions);
@ -219,7 +234,7 @@ class _PostActionsState extends ConsumerState<PostActions> {
myReactions: _myReactions,
reactionUsers: {},
onToggle: (emoji) => _toggleReaction(emoji),
onAdd: () => _toggleReaction('❤️'), // Default to heart for now
onAdd: _showReactionPicker, // Show picker instead of default heart
),
const SizedBox(height: 16),
// Actions row - left aligned

View file

@ -0,0 +1,125 @@
import 'package:flutter/material.dart';
import 'package:google_fonts/google_fonts.dart';
import '../../theme/app_theme.dart';
class ReactionPicker extends StatefulWidget {
final Function(String) onReactionSelected;
final VoidCallback? onClosed;
const ReactionPicker({
super.key,
required this.onReactionSelected,
this.onClosed,
});
@override
State<ReactionPicker> createState() => _ReactionPickerState();
}
class _ReactionPickerState extends State<ReactionPicker> {
static const List<String> _commonReactions = [
'❤️', '👍', '😂', '😮', '😢', '😡',
'🎉', '🔥', '👏', '🙏', '💯', '🤔',
'😍', '🤣', '😊', '👌', '🙌', '💪',
'🎯', '', '', '🌟', '💫', '☀️',
];
@override
Widget build(BuildContext context) {
return Dialog(
backgroundColor: Colors.transparent,
child: Container(
padding: const EdgeInsets.all(20),
decoration: BoxDecoration(
color: AppTheme.cardSurface,
borderRadius: BorderRadius.circular(20),
border: Border.all(
color: AppTheme.navyBlue.withValues(alpha: 0.2),
width: 1,
),
boxShadow: [
BoxShadow(
color: Colors.black.withValues(alpha: 0.2),
blurRadius: 20,
offset: const Offset(0, 10),
),
],
),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// Header
Row(
children: [
Text(
'Add Reaction',
style: GoogleFonts.inter(
color: AppTheme.navyBlue,
fontSize: 16,
fontWeight: FontWeight.w600,
),
),
const Spacer(),
IconButton(
onPressed: () {
Navigator.of(context).pop();
widget.onClosed?.call();
},
icon: Icon(
Icons.close,
color: AppTheme.textSecondary,
size: 20,
),
),
],
),
const SizedBox(height: 16),
// Emoji grid
GridView.builder(
shrinkWrap: true,
physics: const NeverScrollableScrollPhysics(),
gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
crossAxisCount: 6,
crossAxisSpacing: 8,
mainAxisSpacing: 8,
childAspectRatio: 1,
),
itemCount: _commonReactions.length,
itemBuilder: (context, index) {
final emoji = _commonReactions[index];
return Material(
color: Colors.transparent,
child: InkWell(
onTap: () {
Navigator.of(context).pop();
widget.onReactionSelected(emoji);
},
borderRadius: BorderRadius.circular(12),
child: Container(
decoration: BoxDecoration(
color: AppTheme.navyBlue.withValues(alpha: 0.05),
borderRadius: BorderRadius.circular(12),
border: Border.all(
color: AppTheme.navyBlue.withValues(alpha: 0.1),
width: 1,
),
),
child: Center(
child: Text(
emoji,
style: const TextStyle(fontSize: 24),
),
),
),
),
);
},
),
const SizedBox(height: 16),
],
),
),
);
}
}