import 'package:flutter/material.dart'; import 'package:flutter_riverpod/flutter_riverpod.dart'; import 'package:relationship_saver/core/config/app_theme.dart'; import 'package:relationship_saver/features/local/local_models.dart'; import 'package:relationship_saver/features/local/local_repository.dart'; import 'package:relationship_saver/features/shared/frosted_card.dart'; class SelectedPersonIdNotifier extends Notifier { @override String? build() => null; void select(String id) { state = id; } } final NotifierProvider selectedPersonIdProvider = NotifierProvider( SelectedPersonIdNotifier.new, ); class PeopleView extends ConsumerWidget { const PeopleView({super.key}); @override Widget build(BuildContext context, WidgetRef ref) { final List people = ref .watch(localRepositoryProvider) .people(); final String selectedId = ref.watch(selectedPersonIdProvider) ?? people.first.id; final PersonProfile selected = people.firstWhere( (PersonProfile person) => person.id == selectedId, orElse: () => people.first, ); return Padding( padding: const EdgeInsets.fromLTRB(28, 24, 28, 28), child: Row( children: [ Expanded( flex: 5, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'People', style: Theme.of(context).textTheme.headlineMedium, ), const SizedBox(height: 6), Text( 'Track what matters to each relationship and follow through.', style: Theme.of(context).textTheme.bodyLarge?.copyWith( color: AppTheme.textSecondary, ), ), const SizedBox(height: 20), Expanded( child: ListView.separated( itemCount: people.length, separatorBuilder: (_, _) => const SizedBox(height: 12), itemBuilder: (BuildContext context, int index) { final PersonProfile person = people[index]; final bool isSelected = person.id == selected.id; return InkWell( onTap: () { ref .read(selectedPersonIdProvider.notifier) .select(person.id); }, borderRadius: BorderRadius.circular(20), child: FrostedCard( padding: const EdgeInsets.all(16), child: Row( children: [ _AvatarSeed(name: person.name), const SizedBox(width: 14), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( person.name, style: Theme.of( context, ).textTheme.titleMedium, ), const SizedBox(height: 4), Text( person.relationship, style: Theme.of(context) .textTheme .bodyMedium ?.copyWith( color: AppTheme.textSecondary, ), ), ], ), ), _ScorePill(score: person.affinityScore), if (isSelected) const Padding( padding: EdgeInsets.only(left: 10), child: Icon( Icons.check_circle, color: Color(0xFF1AB6C8), ), ), ], ), ), ); }, ), ), ], ), ), const SizedBox(width: 18), Expanded( flex: 6, child: FrostedCard(child: _PersonDetail(person: selected)), ), ], ), ); } } class _PersonDetail extends StatelessWidget { const _PersonDetail({required this.person}); final PersonProfile person; @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ _AvatarSeed(name: person.name, size: 64), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( person.name, style: Theme.of(context).textTheme.titleLarge, ), const SizedBox(height: 4), Text( person.relationship, style: Theme.of(context).textTheme.bodyLarge?.copyWith( color: AppTheme.textSecondary, ), ), ], ), ), _ScorePill(score: person.affinityScore), ], ), const SizedBox(height: 22), Text('Next moment', style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 8), _DetailTag( label: '${person.nextMoment.year}-${person.nextMoment.month.toString().padLeft(2, '0')}-${person.nextMoment.day.toString().padLeft(2, '0')} ${person.nextMoment.hour.toString().padLeft(2, '0')}:${person.nextMoment.minute.toString().padLeft(2, '0')}', ), const SizedBox(height: 18), Text('Preferences', style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 8), Wrap( spacing: 8, runSpacing: 8, children: person.tags .map((String tag) => _DetailTag(label: tag)) .toList(), ), const SizedBox(height: 18), Text('Notes', style: Theme.of(context).textTheme.titleMedium), const SizedBox(height: 8), Text( person.notes, style: Theme.of( context, ).textTheme.bodyLarge?.copyWith(color: AppTheme.textSecondary), ), ], ); } } class _DetailTag extends StatelessWidget { const _DetailTag({required this.label}); final String label; @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: const Color(0xFFF2F8FA), borderRadius: BorderRadius.circular(99), ), child: Text(label, style: Theme.of(context).textTheme.bodyMedium), ); } } class _AvatarSeed extends StatelessWidget { const _AvatarSeed({required this.name, this.size = 48}); final String name; final double size; @override Widget build(BuildContext context) { final String initials = name .split(' ') .where((String part) => part.isNotEmpty) .take(2) .map((String part) => part[0].toUpperCase()) .join(); return Container( width: size, height: size, decoration: BoxDecoration( borderRadius: BorderRadius.circular(size / 2), gradient: const LinearGradient( colors: [Color(0xFF1AB6C8), Color(0xFF2274E0)], ), ), alignment: Alignment.center, child: Text( initials, style: Theme.of(context).textTheme.titleMedium?.copyWith( color: Colors.white, fontWeight: FontWeight.w700, ), ), ); } } class _ScorePill extends StatelessWidget { const _ScorePill({required this.score}); final int score; @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), decoration: BoxDecoration( color: const Color(0xFFEEF7F3), borderRadius: BorderRadius.circular(99), ), child: Text( '$score%', style: Theme.of(context).textTheme.labelLarge?.copyWith( color: const Color(0xFF1D9C66), fontWeight: FontWeight.w700, ), ), ); } }