cyberhybridhub/lib/screens/home_screen.dart
2026-05-20 10:22:58 -05:00

200 lines
6.8 KiB
Dart

import 'package:flutter/material.dart';
import '../models/app_user.dart';
import '../models/sync_result.dart';
import '../models/user_profile.dart';
import '../repositories/user_profile_repository.dart';
import '../services/auth_service.dart';
import '../theme/app_theme.dart';
class HomeScreen extends StatelessWidget {
const HomeScreen({
super.key,
required this.user,
this.profile,
this.syncStatus = ProfileSyncStatus.idle,
});
final AppUser user;
final UserProfile? profile;
final ProfileSyncStatus syncStatus;
@override
Widget build(BuildContext context) {
final String? photoUrl = profile?.photoUrl ?? user.photoUrl;
final String displayName =
profile?.displayName ?? user.displayName ?? 'there';
final String? email = profile?.email ?? user.email;
return Scaffold(
appBar: AppBar(
backgroundColor: Colors.transparent,
title: const Text('Cyber Hybrid Hub'),
actions: <Widget>[
IconButton(
onPressed: () => UserProfileRepository.instance.sync(),
tooltip: 'Sync profile',
icon: const Icon(Icons.sync),
),
IconButton(
onPressed: () => AuthService.instance.signOut(),
tooltip: 'Sign out',
icon: const Icon(Icons.logout),
),
],
),
body: DecoratedBox(
decoration: const BoxDecoration(
gradient: LinearGradient(
begin: Alignment.topCenter,
end: Alignment.bottomCenter,
colors: <Color>[AppColors.background, AppColors.surface],
),
),
child: SafeArea(
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: <Widget>[
Container(
padding: const EdgeInsets.all(24),
decoration: BoxDecoration(
color: AppColors.surfaceElevated,
borderRadius: BorderRadius.circular(16),
border: Border.all(
color: AppColors.accent.withValues(alpha: 0.2),
),
),
child: Column(
children: <Widget>[
if (photoUrl != null)
CircleAvatar(
radius: 36,
backgroundImage: NetworkImage(photoUrl),
)
else
const CircleAvatar(
radius: 36,
child: Icon(Icons.person, size: 36),
),
const SizedBox(height: 16),
Text(
'Welcome, $displayName',
style: Theme.of(context).textTheme.headlineMedium,
textAlign: TextAlign.center,
),
if (email != null) ...<Widget>[
const SizedBox(height: 8),
Text(
email,
style: Theme.of(context).textTheme.bodyLarge,
textAlign: TextAlign.center,
),
],
const SizedBox(height: 12),
_SyncStatusChip(status: syncStatus),
const SizedBox(height: 20),
const Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Icon(
Icons.check_circle,
color: AppColors.success,
size: 20,
),
SizedBox(width: 8),
Text(
'You\'re signed in',
style: TextStyle(
color: AppColors.success,
fontWeight: FontWeight.w600,
),
),
],
),
],
),
),
const SizedBox(height: 24),
Text(
profile?.dirty == true
? 'Profile saved locally. Will sync when online.'
: 'Profile synced with your account.',
style: Theme.of(context).textTheme.bodyLarge,
textAlign: TextAlign.center,
),
if (UserProfileRepository.instance.usesLocalStore) ...<Widget>[
const SizedBox(height: 16),
OutlinedButton.icon(
onPressed: profile == null
? null
: () async {
final UserProfile current = profile!;
await UserProfileRepository.instance.updateProfile(
current.copyWith(
onboardingCompleted:
!current.onboardingCompleted,
),
);
},
icon: const Icon(Icons.toggle_on_outlined),
label: Text(
profile?.onboardingCompleted == true
? 'Mark onboarding incomplete'
: 'Mark onboarding complete',
),
),
],
],
),
),
),
),
);
}
}
class _SyncStatusChip extends StatelessWidget {
const _SyncStatusChip({required this.status});
final ProfileSyncStatus status;
@override
Widget build(BuildContext context) {
final ({String label, Color color, IconData icon}) style = switch (status) {
ProfileSyncStatus.syncing => (
label: 'Syncing…',
color: AppColors.accent,
icon: Icons.sync,
),
ProfileSyncStatus.synced => (
label: 'Synced',
color: AppColors.success,
icon: Icons.cloud_done_outlined,
),
ProfileSyncStatus.offline => (
label: 'Offline',
color: Colors.orange,
icon: Icons.cloud_off_outlined,
),
ProfileSyncStatus.error => (
label: 'Sync error',
color: Colors.redAccent,
icon: Icons.error_outline,
),
ProfileSyncStatus.idle => (
label: 'Ready',
color: AppColors.accent,
icon: Icons.cloud_queue_outlined,
),
};
return Chip(
avatar: Icon(style.icon, size: 18, color: style.color),
label: Text(style.label),
side: BorderSide(color: style.color.withValues(alpha: 0.4)),
);
}
}