Remove 'Dashboard View' text and implement 3-per-row grid layout

- Remove unnecessary 'Dashboard View' badge from header
- Replace vertical list with GridView (3 columns)
- Update reply cards for compact grid layout:
  - Smaller avatars (24x24) with initials
  - More compact text sizes and spacing
  - Reduced padding and margins
  - Simplified reactions display (just count)
  - Shorter 'View' button instead of 'View Thread'
- Adjust childAspectRatio for better card proportions
- Faster staggered animations (50ms vs 100ms)
- Scale animation instead of slide for grid items
This commit is contained in:
Patrick Britton 2026-02-01 13:53:58 -06:00
parent ad11183ddc
commit 2d5323a310

View file

@ -732,32 +732,26 @@ class _ThreadedConversationScreenState extends ConsumerState<ThreadedConversatio
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
), ),
const Spacer(),
Container(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 6),
decoration: BoxDecoration(
color: AppTheme.brightNavy.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(20),
),
child: Text(
'Dashboard View',
style: GoogleFonts.inter(
color: AppTheme.brightNavy,
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
], ],
), ),
), ),
const SizedBox(height: 16), const SizedBox(height: 16),
// Reply chains as dashboard items // Reply chains as grid (3 per row)
...children.asMap().entries.map((entry) { GridView.builder(
final index = entry.key; shrinkWrap: true,
final post = entry.value; physics: const NeverScrollableScrollPhysics(),
return _buildDashboardReplyItem(post, index); gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount(
}).toList(), crossAxisCount: 3,
crossAxisSpacing: 12,
mainAxisSpacing: 12,
childAspectRatio: 0.8,
),
itemCount: children.length,
itemBuilder: (context, index) {
final post = children[index];
return _buildDashboardReplyItem(post, index);
},
),
], ],
), ),
), ),
@ -767,10 +761,9 @@ class _ThreadedConversationScreenState extends ConsumerState<ThreadedConversatio
Widget _buildDashboardReplyItem(Post post, int index) { Widget _buildDashboardReplyItem(Post post, int index) {
return Container( return Container(
margin: const EdgeInsets.only(bottom: 12),
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppTheme.cardSurface, color: AppTheme.cardSurface,
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(12),
border: Border.all( border: Border.all(
color: AppTheme.navyBlue.withValues(alpha: 0.08), color: AppTheme.navyBlue.withValues(alpha: 0.08),
width: 1, width: 1,
@ -778,7 +771,7 @@ class _ThreadedConversationScreenState extends ConsumerState<ThreadedConversatio
boxShadow: [ boxShadow: [
BoxShadow( BoxShadow(
color: AppTheme.navyBlue.withValues(alpha: 0.04), color: AppTheme.navyBlue.withValues(alpha: 0.04),
blurRadius: 8, blurRadius: 6,
offset: const Offset(0, 2), offset: const Offset(0, 2),
), ),
], ],
@ -787,17 +780,36 @@ class _ThreadedConversationScreenState extends ConsumerState<ThreadedConversatio
color: Colors.transparent, color: Colors.transparent,
child: InkWell( child: InkWell(
onTap: () => _navigateToPost(post.id), onTap: () => _navigateToPost(post.id),
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(12),
child: Padding( child: Padding(
padding: const EdgeInsets.all(16), padding: const EdgeInsets.all(12),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
// Reply header with menu button // Reply header with menu button
Row( Row(
children: [ children: [
_buildCompactAvatar(post), Container(
const SizedBox(width: 12), width: 24,
height: 24,
decoration: BoxDecoration(
color: AppTheme.brightNavy.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(6),
),
child: Center(
child: Text(
(post.author?.displayName?.isNotEmpty == true)
? post.author!.displayName.characters.first.toUpperCase()
: 'A',
style: GoogleFonts.inter(
color: AppTheme.brightNavy,
fontSize: 10,
fontWeight: FontWeight.w700,
),
),
),
),
const SizedBox(width: 8),
Expanded( Expanded(
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -806,15 +818,17 @@ class _ThreadedConversationScreenState extends ConsumerState<ThreadedConversatio
post.author?.displayName ?? 'Anonymous', post.author?.displayName ?? 'Anonymous',
style: GoogleFonts.inter( style: GoogleFonts.inter(
color: AppTheme.navyBlue, color: AppTheme.navyBlue,
fontSize: 14, fontSize: 11,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
maxLines: 1,
overflow: TextOverflow.ellipsis,
), ),
Text( Text(
timeago.format(post.createdAt), timeago.format(post.createdAt),
style: GoogleFonts.inter( style: GoogleFonts.inter(
color: AppTheme.textSecondary, color: AppTheme.textSecondary,
fontSize: 11, fontSize: 9,
), ),
), ),
], ],
@ -822,54 +836,65 @@ class _ThreadedConversationScreenState extends ConsumerState<ThreadedConversatio
), ),
// Menu button // Menu button
Container( Container(
padding: const EdgeInsets.all(6), padding: const EdgeInsets.all(4),
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppTheme.navyBlue.withValues(alpha: 0.05), color: AppTheme.navyBlue.withValues(alpha: 0.05),
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(6),
), ),
child: Icon( child: Icon(
Icons.more_horiz, Icons.more_horiz,
size: 16, size: 14,
color: AppTheme.textSecondary, color: AppTheme.textSecondary,
), ),
), ),
], ],
), ),
const SizedBox(height: 12), const SizedBox(height: 8),
// Reply content // Reply content
Text( Expanded(
post.body, child: Text(
style: GoogleFonts.inter( post.body,
color: AppTheme.navyText, style: GoogleFonts.inter(
fontSize: 14, color: AppTheme.navyText,
height: 1.4, fontSize: 11,
height: 1.3,
),
maxLines: 4,
overflow: TextOverflow.ellipsis,
), ),
maxLines: 3,
overflow: TextOverflow.ellipsis,
), ),
const SizedBox(height: 12), const SizedBox(height: 8),
// Reply actions // Reply actions
Row( Row(
children: [ children: [
ReactionStrip( // Compact reactions display
reactions: _reactionCountsFor(post), if (_reactionCountsFor(post).isNotEmpty) ...[
myReactions: _myReactionsFor(post), Icon(
reactionUsers: _reactionUsersFor(post), Icons.favorite_border,
onToggle: (emoji) => _toggleReaction(post.id, emoji), size: 12,
onAdd: () => _openReactionPicker(post.id), color: AppTheme.textSecondary,
), ),
const SizedBox(width: 4),
Text(
'${_reactionCountsFor(post).values.reduce((a, b) => a + b)}',
style: GoogleFonts.inter(
color: AppTheme.textSecondary,
fontSize: 10,
),
),
],
const Spacer(), const Spacer(),
Container( Container(
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4), padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration( decoration: BoxDecoration(
color: AppTheme.brightNavy.withValues(alpha: 0.1), color: AppTheme.brightNavy.withValues(alpha: 0.1),
borderRadius: BorderRadius.circular(12), borderRadius: BorderRadius.circular(8),
), ),
child: Text( child: Text(
'View Thread', 'View',
style: GoogleFonts.inter( style: GoogleFonts.inter(
color: AppTheme.brightNavy, color: AppTheme.brightNavy,
fontSize: 11, fontSize: 9,
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
), ),
), ),
@ -881,9 +906,9 @@ class _ThreadedConversationScreenState extends ConsumerState<ThreadedConversatio
), ),
), ),
), ),
).animate(delay: (index * 100).ms) ).animate(delay: (index * 50).ms)
.fadeIn(duration: 300.ms, curve: Curves.easeOutCubic) .fadeIn(duration: 300.ms, curve: Curves.easeOutCubic)
.slideY(begin: 0.04, end: 0, curve: Curves.easeOutBack); .scale(begin: const Offset(0.95, 0.95), end: const Offset(1, 1));
} }
void _toggleReaction(String postId, String emoji) { void _toggleReaction(String postId, String emoji) {