import 'package:flutter/material.dart'; import 'package:provider/provider.dart'; import 'package:sxchnge_wallet/sxchnge_wallet.dart'; import 'copy.dart'; import 'detail.dart'; import 'form.dart'; import '../generated/i18n/app_localizations.dart'; class DestinationsPage extends StatefulWidget { const DestinationsPage({super.key, this.payoutContext}); final PayoutContext? payoutContext; @override State createState() => _DestinationsPageState(); } class _DestinationsPageState extends State { String query = ''; late final selection = DestinationSelectionProvider( context.read().service, widget.payoutContext ?? const PayoutContext(''), ); Future refresh() async { final p = context.read(); await p.refresh(); if (!mounted) return; await selection.assess(p.methods); } @override void initState() { super.initState(); WidgetsBinding.instance.addPostFrameCallback((_) { if (mounted) refresh(); }); } Future add() async { final result = await Navigator.push( context, MaterialPageRoute( builder: (_) => DestinationFormPage(payoutContext: widget.payoutContext), ), ); if (!mounted) return; if (result != null && widget.payoutContext != null) { Navigator.pop(context, result); } else { await refresh(); } } Future choose(SavedDestination d) async { if (widget.payoutContext == null) { await Navigator.push( context, MaterialPageRoute( builder: (_) => DestinationDetailPage(destination: d), ), ); if (mounted) await refresh(); } else { final ref = await selection.select(d); if (mounted && ref != null) Navigator.pop(context, ref); } } @override void dispose() { selection.dispose(); super.dispose(); } @override Widget build(BuildContext context) { final l = AppLocalizations.of(context)!; final p = context.watch(); return Scaffold( appBar: AppBar( title: Text(widget.payoutContext == null ? l.dTitle : l.dChoose), actions: [ IconButton( tooltip: l.dReload, onPressed: p.loading ? null : refresh, icon: const Icon(Icons.refresh), ), ], ), body: ListenableBuilder( listenable: selection, builder: (context, _) => ListView( padding: const EdgeInsets.all(24), children: [ if (p.capabilities?.simulated == true) ...[ Text(l.dDemo), const SizedBox(height: 16), ], FilledButton.icon( onPressed: p.loading || (p.capabilities?.types.isEmpty ?? true) ? null : add, icon: const Icon(Icons.add), label: Text(widget.payoutContext == null ? l.dAdd : l.dNew), ), if (p.capabilities?.types.isEmpty == true) Text(l.dManagementUnavailable), const SizedBox(height: 20), TextField( decoration: InputDecoration( labelText: l.dSearch, prefixIcon: const Icon(Icons.search), ), onChanged: (v) => setState(() => query = v), ), if (p.loading || selection.busy) const LinearProgressIndicator(), if (p.failed) Text(l.dUnavailable), if (selection.error != null) Semantics( liveRegion: true, child: Text(destinationIssue(l, selection.error!)), ), if (widget.payoutContext != null && !p.loading && p.methods.isNotEmpty && !selection.assessments.values.any((a) => a.eligible)) Text(l.dNoEligible), for (final type in p.capabilities?.types ?? []) ...[ const SizedBox(height: 24), Text( destinationType(l, type), style: Theme.of(context).textTheme.titleLarge, ), const SizedBox(height: 8), if (p.search(query, type).isEmpty && !p.loading && !p.failed) Text(query.isEmpty ? l.dEmpty : l.dNoMatches), for (final d in p.search(query, type)) Card( child: ListTile( contentPadding: const EdgeInsets.all(16), title: Text(d.label), subtitle: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (d.nickname.isNotEmpty) Text(d.details.display), if (selection.assessments[d.id] case final PayoutEligibility e) Text(eligibilityText(l, e)), ], ), trailing: const Icon(Icons.chevron_right), onTap: selection.busy ? null : () => choose(d), ), ), ], ], ), ), ); } }