import 'package:finger_print_verification/theme/app_theme.dart'; import 'package:flutter/material.dart'; import '../models/auth_result_ui_model.dart'; /// ───────────────────────────────────────────────────────────────────────── /// Shared, public building blocks for rendering an [AuthResultUiModel]. /// /// These used to live as private widgets inside `auth_result_screen.dart`. /// They're now public and standalone so the SAME widgets can be reused: /// • full-screen, on phones, via [AuthResultScreen] (pushed route) /// • inline, on tablets, embedded directly in [FingerprintView]'s result /// pane — no navigation needed, the result just appears next to the form. /// ───────────────────────────────────────────────────────────────────────── class ResultStatusBanner extends StatelessWidget { final AuthResultUiModel result; const ResultStatusBanner({super.key, required this.result}); @override Widget build(BuildContext context) { final accent = result.isSuccess ? AppTheme.saudiGreen : AppTheme.redAlert; final message = result.statusMessage.isEmpty ? (result.isSuccess ? 'Authentication successful!' : 'Authentication failed') : result.statusMessage; return GlowPanel( glowColor: accent, padding: const EdgeInsets.all(20), child: Row( children: [ Container( width: 52, height: 52, alignment: Alignment.center, decoration: BoxDecoration( shape: BoxShape.circle, color: accent.withValues(alpha: 0.12), border: Border.all(color: accent.withValues(alpha: 0.4)), ), child: Icon( result.isSuccess ? Icons.check_circle_outline : Icons.cancel_outlined, color: accent, size: 28, ), ), const SizedBox(width: 16), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'STATUS', style: TextStyle( color: AppTheme.textMuted, fontSize: 11, fontWeight: FontWeight.w700, letterSpacing: 1.1, ), ), const SizedBox(height: 4), Text( message, style: TextStyle(color: accent, fontWeight: FontWeight.w700, fontSize: 16), ), ], ), ), ], ), ); } } class ResultPersonInfoPanel extends StatelessWidget { final AuthResultUiModel result; final bool twoColumn; const ResultPersonInfoPanel({super.key, required this.result, this.twoColumn = false}); @override Widget build(BuildContext context) { final fullName = [result.firstName, result.lastName].where((s) => s.isNotEmpty).join(' '); final rows = [ ResultDetailRow(label: 'Father', value: result.fatherName, icon: Icons.man_outlined), ResultDetailRow(label: 'Grandfather', value: result.grandfatherName, icon: Icons.elderly_outlined), ResultDetailRow(label: 'Occupation', value: result.occupation, icon: Icons.work_outline), ResultDetailRow(label: 'Gender', value: result.gender, icon: Icons.wc_outlined), ResultDetailRow(label: 'Sponsor', value: result.sponsor, icon: Icons.shield_outlined), ResultDetailRow(label: 'ID Number', value: result.idNumber, icon: Icons.badge_outlined), ResultDetailRow(label: 'Birth Date', value: result.birthDate, icon: Icons.cake_outlined), ResultDetailRow(label: 'Nationality', value: result.nationality, icon: Icons.flag_outlined), ]; return GlowPanel( glowColor: AppTheme.saudiGreen, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( width: 44, height: 44, alignment: Alignment.center, decoration: BoxDecoration( shape: BoxShape.circle, color: AppTheme.saudiGreen.withValues(alpha: 0.12), border: Border.all(color: AppTheme.saudiGreen.withValues(alpha: 0.4)), ), child: const Icon(Icons.person_outline, color: AppTheme.saudiGreen, size: 22), ), const SizedBox(width: 12), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ const Text( 'PERSON INFORMATION', style: TextStyle( color: AppTheme.saudiGreen, fontSize: 12, fontWeight: FontWeight.w700, letterSpacing: 1.0, ), ), const SizedBox(height: 2), Text( fullName.isEmpty ? '—' : fullName, style: const TextStyle( color: AppTheme.textPrimary, fontSize: 18, fontWeight: FontWeight.w700, ), ), ], ), ), ], ), const SizedBox(height: 8), const Divider(height: 1), const SizedBox(height: 8), if (twoColumn) GridView.count( crossAxisCount: 2, shrinkWrap: true, physics: const NeverScrollableScrollPhysics(), mainAxisSpacing: 4, crossAxisSpacing: 16, childAspectRatio: 5.4, children: rows, ) else Column(children: rows), ], ), ); } } class ResultErrorPanel extends StatelessWidget { final AuthResultUiModel result; const ResultErrorPanel({super.key, required this.result}); @override Widget build(BuildContext context) { return GlowPanel( glowColor: AppTheme.redAlert, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Row( children: [ Container( width: 44, height: 44, alignment: Alignment.center, decoration: BoxDecoration( shape: BoxShape.circle, color: AppTheme.redAlert.withValues(alpha: 0.12), border: Border.all(color: AppTheme.redAlert.withValues(alpha: 0.4)), ), child: const Icon(Icons.error_outline, color: AppTheme.redAlert, size: 22), ), const SizedBox(width: 12), const Text( 'ERROR DETAILS', style: TextStyle( color: AppTheme.redAlert, fontSize: 12, fontWeight: FontWeight.w700, letterSpacing: 1.0, ), ), ], ), const SizedBox(height: 8), const Divider(height: 1), const SizedBox(height: 8), ResultDetailRow(label: 'Type', value: result.errorType ?? '', icon: Icons.category_outlined), ResultDetailRow(label: 'Message', value: result.errorMessage ?? '', icon: Icons.notes_outlined), ], ), ); } } /// Reusable detail row (icon + label + value). class ResultDetailRow extends StatelessWidget { final String label; final String value; final IconData icon; const ResultDetailRow({super.key, required this.label, required this.value, required this.icon}); @override Widget build(BuildContext context) { return Padding( padding: const EdgeInsets.symmetric(vertical: 8), child: Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Icon(icon, size: 16, color: AppTheme.textMuted), const SizedBox(width: 10), Expanded( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( label, style: const TextStyle( fontSize: 11, fontWeight: FontWeight.w700, color: AppTheme.textMuted, letterSpacing: 0.4, ), ), const SizedBox(height: 2), Text( value.isEmpty ? '—' : value, style: const TextStyle( fontSize: 14, color: AppTheme.textPrimary, fontWeight: FontWeight.w600, ), overflow: TextOverflow.ellipsis, ), ], ), ), ], ), ); } } /// Full result body (banner + person-info-or-error), used by both the /// pushed phone route and the inline tablet pane. class ResultBody extends StatelessWidget { final AuthResultUiModel result; final bool twoColumn; const ResultBody({super.key, required this.result, this.twoColumn = false}); @override Widget build(BuildContext context) { return Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ ResultStatusBanner(result: result), const SizedBox(height: 16), if (result.isSuccess) ResultPersonInfoPanel(result: result, twoColumn: twoColumn), if (!result.isSuccess) ResultErrorPanel(result: result), ], ); } }