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