MotorSignal-App/lib/features/social/social_hub_screen.dart

332 lines
13 KiB
Dart

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../core/responsive/responsive_layout.dart';
import '../../core/theme/app_typography.dart';
import '../../core/theme/theme_extensions.dart';
import '../../services/auth/auth_providers.dart';
import '../../services/social/social_providers.dart';
import 'widgets/avatar_badge.dart';
/// The authoritative landing screen for MotorSignal Social & Community.
///
/// Unifies Rider Profile, Friends, and Group Rides under a dedicated,
/// restrained automotive social home completely decoupled from Settings.
class SocialHubScreen extends ConsumerWidget {
const SocialHubScreen({super.key});
@override
Widget build(BuildContext context, WidgetRef ref) {
final colors = context.motorColors;
final user = ref.watch(currentUserProvider);
final profileAsync = ref.watch(myRiderProfileProvider);
final requestsAsync = ref.watch(myIncomingRequestsProvider);
final pendingCount = requestsAsync.value?.length ?? 0;
return Scaffold(
appBar: AppBar(
title: const Text(
'Social',
style: TextStyle(fontWeight: FontWeight.w700),
),
),
body: SafeArea(
child: ResponsiveLayout(
builder: (context, responsive) {
final isWide = responsive.isExpanded || (responsive.isMedium && responsive.isLandscape);
return SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 16.0, vertical: 12.0),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 800),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// Rider Identity Header Card
_buildRiderHeroCard(context, profileAsync.value, user, colors),
const SizedBox(height: 20),
// Section 1: Rider Network
Text(
'Rider Network',
style: TextStyle(
fontFamily: AppTypography.fontHeadline,
fontSize: 13,
fontWeight: FontWeight.w700,
letterSpacing: 0.2,
color: colors.cyberCyan,
),
),
const SizedBox(height: 10),
if (isWide) ...[
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: _buildNavigationCard(
context,
key: const ValueKey('social_card_friends'),
icon: Icons.people_outline,
title: 'Friends',
subtitle: 'Find fellow riders, manage requests & connections',
badgeCount: pendingCount,
colors: colors,
onTap: () => context.push('/social/friends'),
),
),
const SizedBox(width: 14),
Expanded(
child: _buildNavigationCard(
context,
key: const ValueKey('social_card_clubs'),
icon: Icons.shield_outlined,
title: 'Clubs',
subtitle: 'Discover motorcycle clubs, riding communities & member groups',
colors: colors,
onTap: () => context.push('/social/clubs'),
),
),
],
),
] else ...[
_buildNavigationCard(
context,
key: const ValueKey('social_card_friends'),
icon: Icons.people_outline,
title: 'Friends',
subtitle: 'Find fellow riders, manage requests & connections',
badgeCount: pendingCount,
colors: colors,
onTap: () => context.push('/social/friends'),
),
const SizedBox(height: 12),
_buildNavigationCard(
context,
key: const ValueKey('social_card_clubs'),
icon: Icons.shield_outlined,
title: 'Clubs',
subtitle: 'Discover motorcycle clubs, riding communities & member groups',
colors: colors,
onTap: () => context.push('/social/clubs'),
),
],
const SizedBox(height: 20),
// Section 2: Motorcycle Activities
Text(
'Motorcycle Activities',
style: TextStyle(
fontFamily: AppTypography.fontHeadline,
fontSize: 13,
fontWeight: FontWeight.w700,
letterSpacing: 0.2,
color: colors.cyberCyan,
),
),
const SizedBox(height: 10),
_buildNavigationCard(
context,
key: const ValueKey('social_card_group_rides'),
icon: Icons.groups_outlined,
title: 'Group Rides',
subtitle: 'Join active sessions, explore local pack rides & track group telemetry',
colors: colors,
onTap: () => context.push('/group-rides'),
),
const SizedBox(height: 24),
],
),
),
),
);
},
),
),
);
}
Widget _buildRiderHeroCard(
BuildContext context,
dynamic profile,
dynamic user,
MotorSignalThemeColors colors,
) {
final hasProfile = profile != null;
final displayName = hasProfile ? profile.displayName : (user?.displayLabel ?? 'Rider');
final handle = hasProfile ? '@${profile.handle}' : 'Tap to setup rider profile';
final avatarPreset = hasProfile ? profile.avatarPreset : null;
return Container(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
decoration: BoxDecoration(
color: colors.surfaceContainer,
borderRadius: BorderRadius.circular(14),
border: Border.all(color: colors.outlineVariant, width: 0.8),
),
child: Row(
children: [
AvatarBadge(
avatarPreset: avatarPreset,
displayName: displayName,
radius: 22,
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
displayName,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontFamily: AppTypography.fontHeadline,
fontSize: 15,
fontWeight: FontWeight.w700,
),
),
const SizedBox(height: 2),
Text(
handle,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontFamily: AppTypography.fontBody,
fontSize: 11.5,
fontWeight: FontWeight.w500,
color: colors.cyberCyan,
),
),
],
),
),
const SizedBox(width: 8),
OutlinedButton(
style: OutlinedButton.styleFrom(
visualDensity: VisualDensity.compact,
side: BorderSide(color: colors.outlineVariant, width: 0.8),
shape: RoundedRectangleBorder(borderRadius: BorderRadius.circular(8)),
padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
),
onPressed: () => context.push('/social/profile'),
child: const Text(
'Edit',
style: TextStyle(
fontFamily: AppTypography.fontHeadline,
fontSize: 12,
fontWeight: FontWeight.w600,
),
),
),
],
),
);
}
Widget _buildNavigationCard(
BuildContext context, {
required Key key,
required IconData icon,
required String title,
required String subtitle,
required MotorSignalThemeColors colors,
required VoidCallback onTap,
int badgeCount = 0,
}) {
return Container(
key: key,
decoration: BoxDecoration(
color: colors.surfaceContainer,
borderRadius: BorderRadius.circular(14),
border: Border.all(color: colors.outlineVariant, width: 0.8),
),
child: Material(
color: Colors.transparent,
child: InkWell(
borderRadius: BorderRadius.circular(14),
onTap: onTap,
child: Padding(
padding: const EdgeInsets.all(16.0),
child: Row(
children: [
Container(
width: 40,
height: 40,
decoration: BoxDecoration(
color: colors.cyberCyan.withValues(alpha: 0.10),
borderRadius: BorderRadius.circular(10),
),
child: Icon(icon, color: colors.cyberCyan, size: 22),
),
const SizedBox(width: 14),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: Text(
title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: const TextStyle(
fontFamily: AppTypography.fontHeadline,
fontSize: 14,
fontWeight: FontWeight.w600,
),
),
),
if (badgeCount > 0) ...[
const SizedBox(width: 8),
Container(
padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 2),
decoration: BoxDecoration(
color: colors.cyberCyan,
borderRadius: BorderRadius.circular(10),
),
child: Text(
'$badgeCount',
style: const TextStyle(
fontFamily: AppTypography.fontTelemetry,
fontSize: 10,
fontWeight: FontWeight.w800,
color: Colors.black,
),
),
),
],
],
),
const SizedBox(height: 3),
Text(
subtitle,
style: TextStyle(
fontFamily: AppTypography.fontBody,
fontSize: 12,
color: Theme.of(context).colorScheme.onSurfaceVariant,
height: 1.3,
),
),
],
),
),
const SizedBox(width: 8),
Icon(
Icons.chevron_right,
color: Theme.of(context).colorScheme.onSurfaceVariant.withValues(alpha: 0.6),
size: 20,
),
],
),
),
),
),
);
}
}