import 'package:flutter/material.dart'; import 'package:flutter_lucide/flutter_lucide.dart'; import 'package:cached_network_image/cached_network_image.dart'; import '../../core/api/api_config.dart'; import '../../core/api/services/user_api.dart'; import '../../core/auth/auth_service.dart'; import '../../core/theme/app_colors.dart'; import '../../core/user/user_state.dart'; import '../../core/theme/app_spacing.dart'; import '../../core/theme/app_typography.dart'; /// Profile screen - matches Pencil KXeow class ProfileScreen extends StatefulWidget { const ProfileScreen({super.key, required this.isActive}); final bool isActive; @override State createState() => _ProfileScreenState(); } class _ProfileScreenState extends State { @override void initState() { super.initState(); if (widget.isActive) _fetchAccount(); } @override void didUpdateWidget(covariant ProfileScreen oldWidget) { super.didUpdateWidget(oldWidget); if (widget.isActive && !oldWidget.isActive) { _fetchAccount(); } } Future _fetchAccount() async { final uid = UserState.userId.value; if (uid == null || uid.isEmpty) return; try { await AuthService.loginComplete; final res = await UserApi.getAccount( sentinel: ApiConfig.appId, asset: uid, ); if (!mounted) return; if (res.isSuccess && res.data != null) { final data = res.data as Map?; final credits = data?['reveal'] as int?; if (credits != null) UserState.setCredits(credits); final avatarUrl = data?['realm'] as String?; UserState.setAvatar( avatarUrl != null && avatarUrl.isNotEmpty ? avatarUrl : null); final name = data?['terminal'] as String?; UserState.setUserName( name != null && name.isNotEmpty ? name : null); } } catch (_) {} } @override Widget build(BuildContext context) { return Scaffold( backgroundColor: AppColors.background, body: SingleChildScrollView( padding: const EdgeInsets.fromLTRB( AppSpacing.screenPadding, AppSpacing.xxl, AppSpacing.screenPadding, AppSpacing.screenPaddingLarge, ), child: Column( children: [ ValueListenableBuilder( valueListenable: UserState.avatar, builder: (_, avatarUrl, __) { return ValueListenableBuilder( valueListenable: UserState.userName, builder: (_, userName, __) { return ValueListenableBuilder( valueListenable: UserState.userId, builder: (_, userId, __) { return _ProfileHeader( avatarUrl: avatarUrl, userName: userName, uid: userId, ); }, ); }, ); }, ), const SizedBox(height: AppSpacing.xl), _BalanceCard( balance: UserCreditsData.of(context)?.creditsDisplay ?? '--', onRecharge: () => Navigator.of(context).pushNamed('/recharge'), ), const SizedBox(height: AppSpacing.xxl), _MenuSection( items: [ _MenuItem( title: 'Credit Store', icon: LucideIcons.chevron_right, onTap: () => Navigator.of(context).pushNamed('/recharge'), ), _MenuItem( title: 'Settings', icon: LucideIcons.chevron_right, onTap: () {}, ), ], ), ], ), ), ); } } class _ProfileHeader extends StatelessWidget { const _ProfileHeader({ this.avatarUrl, this.userName, this.uid, }); final String? avatarUrl; final String? userName; final String? uid; @override Widget build(BuildContext context) { return Container( height: 220, alignment: Alignment.center, child: Column( mainAxisAlignment: MainAxisAlignment.center, children: [ Container( width: 80, height: 80, decoration: BoxDecoration( color: AppColors.border, borderRadius: BorderRadius.circular(40), border: Border.all( color: AppColors.primaryLight, width: 2, ), ), clipBehavior: Clip.antiAlias, child: avatarUrl != null && avatarUrl!.isNotEmpty ? CachedNetworkImage( imageUrl: avatarUrl!, fit: BoxFit.cover, placeholder: (_, __) => Icon( LucideIcons.user, size: 40, color: AppColors.textSecondary, ), errorWidget: (_, __, ___) => Icon( LucideIcons.user, size: 40, color: AppColors.textSecondary, ), ) : Icon( LucideIcons.user, size: 40, color: AppColors.textSecondary, ), ), const SizedBox(height: AppSpacing.lg), Text( userName ?? 'Guest', style: AppTypography.bodyLarge.copyWith( color: AppColors.textPrimary, ), ), const SizedBox(height: AppSpacing.lg), Container( padding: const EdgeInsets.symmetric( horizontal: AppSpacing.lg, vertical: AppSpacing.sm, ), decoration: BoxDecoration( color: AppColors.surfaceAlt, borderRadius: BorderRadius.circular(16), border: Border.all(color: AppColors.border), ), child: Text( uid != null && uid!.isNotEmpty ? 'UID $uid' : 'UID --', style: AppTypography.caption.copyWith( color: AppColors.textSecondary, ), ), ), ], ), ); } } class _BalanceCard extends StatelessWidget { const _BalanceCard({ required this.balance, required this.onRecharge, }); final String balance; final VoidCallback onRecharge; @override Widget build(BuildContext context) { return Container( padding: const EdgeInsets.symmetric( horizontal: AppSpacing.xxl, vertical: AppSpacing.xl, ), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(16), boxShadow: [ BoxShadow( color: AppColors.shadowLight, blurRadius: 8, offset: const Offset(0, 2), ), ], ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'AVAILABLE BALANCE', style: AppTypography.label.copyWith( color: AppColors.textSecondary, ), ), const SizedBox(height: AppSpacing.sm), Text( balance, style: AppTypography.bodyLarge.copyWith( fontSize: 24, fontWeight: FontWeight.w700, color: AppColors.primary, ), ), ], ), GestureDetector( onTap: onRecharge, child: Container( padding: const EdgeInsets.symmetric( horizontal: 14, vertical: AppSpacing.md, ), decoration: BoxDecoration( color: AppColors.primary, borderRadius: BorderRadius.circular(12), ), child: Text( 'Recharge', style: AppTypography.bodyRegular.copyWith( color: AppColors.surface, fontWeight: FontWeight.w600, ), ), ), ), ], ), ); } } class _MenuSection extends StatelessWidget { const _MenuSection({required this.items}); final List<_MenuItem> items; @override Widget build(BuildContext context) { return Column( children: items .map( (item) => Padding( padding: const EdgeInsets.only(bottom: AppSpacing.md), child: _MenuItem( title: item.title, icon: item.icon, onTap: item.onTap, ), ), ) .toList(), ); } } class _MenuItem extends StatelessWidget { const _MenuItem({ required this.title, required this.icon, required this.onTap, }); final String title; final IconData icon; final VoidCallback onTap; @override Widget build(BuildContext context) { return GestureDetector( onTap: onTap, child: Container( padding: const EdgeInsets.symmetric( horizontal: AppSpacing.xl, vertical: 14, ), decoration: BoxDecoration( color: AppColors.surface, borderRadius: BorderRadius.circular(12), boxShadow: [ BoxShadow( color: AppColors.shadowLight, blurRadius: 6, offset: const Offset(0, 2), ), ], ), child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Text( title, style: AppTypography.bodyRegular.copyWith( color: AppColors.textPrimary, ), ), Icon(icon, size: 20, color: AppColors.textMuted), ], ), ), ); } }