Add saved payout destination UX and service contracts (#54)
This commit is contained in:
1 parent
a5689876ff
commit
24af794112
49 files changed
+4687
-62
No files matched your search
@@ -0,0 +1,161 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:provider/provider.dart';
|
||||
|
||||
import 'package:sxchnge_wallet/sxchnge_wallet.dart';
|
||||
|
||||
import 'copy.dart';
|
||||
import 'details.dart';
|
||||
import 'form.dart';
|
||||
import 'nickname.dart';
|
||||
|
||||
import '../generated/i18n/app_localizations.dart';
|
||||
|
||||
class DestinationDetailPage extends StatefulWidget {
|
||||
const DestinationDetailPage({super.key, required this.destination});
|
||||
final SavedDestination destination;
|
||||
@override
|
||||
State<DestinationDetailPage> createState() => _DestinationDetailPageState();
|
||||
}
|
||||
|
||||
class _DestinationDetailPageState extends State<DestinationDetailPage> {
|
||||
late final p = DestinationManagementProvider(
|
||||
context.read<DestinationsProvider>().service,
|
||||
widget.destination,
|
||||
);
|
||||
late final nickname = TextEditingController(
|
||||
text: widget.destination.nickname,
|
||||
);
|
||||
Future<void> remove() async {
|
||||
final l = AppLocalizations.of(context)!;
|
||||
final confirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: Text(l.dRemoveTitle),
|
||||
content: Text(l.dRemoveHelp),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: () => Navigator.pop(context, false),
|
||||
child: Text(l.wStay),
|
||||
),
|
||||
FilledButton(
|
||||
onPressed: () => Navigator.pop(context, true),
|
||||
child: Text(l.dRemove),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
if (!mounted || confirmed != true) return;
|
||||
await p.remove();
|
||||
if (mounted && p.removed) Navigator.pop(context);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
p.dispose();
|
||||
nickname.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final l = AppLocalizations.of(context)!;
|
||||
return ListenableBuilder(
|
||||
listenable: p,
|
||||
builder: (context, _) => Scaffold(
|
||||
appBar: AppBar(title: Text(l.dDetails)),
|
||||
body: SingleChildScrollView(
|
||||
padding: const EdgeInsets.fromLTRB(24, 24, 24, 120),
|
||||
child: Center(
|
||||
child: ConstrainedBox(
|
||||
constraints: const BoxConstraints(maxWidth: 720),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
DestinationDetailsView(details: p.destination.details),
|
||||
const SizedBox(height: 24),
|
||||
DestinationNickname(
|
||||
controller: nickname,
|
||||
enabled: !p.busy,
|
||||
onChanged: (_) {},
|
||||
),
|
||||
if (p.busy) const LinearProgressIndicator(),
|
||||
if (p.error != null) ...[
|
||||
Semantics(
|
||||
liveRegion: true,
|
||||
child: Text(destinationIssue(l, p.error!)),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: p.busy ? null : p.refresh,
|
||||
child: Text(l.dReload),
|
||||
),
|
||||
],
|
||||
const SizedBox(height: 16),
|
||||
FilledButton(
|
||||
onPressed: p.busy
|
||||
? null
|
||||
: () async {
|
||||
await p.rename(nickname.text);
|
||||
if (context.mounted && p.error == null) {
|
||||
ScaffoldMessenger.of(
|
||||
context,
|
||||
).showSnackBar(SnackBar(content: Text(l.dSaved)));
|
||||
}
|
||||
},
|
||||
child: Text(l.dRename),
|
||||
),
|
||||
if (p.destination.details is CardDestination &&
|
||||
context
|
||||
.read<DestinationsProvider>()
|
||||
.capabilities
|
||||
?.cardRecovery ==
|
||||
true)
|
||||
OutlinedButton(
|
||||
onPressed: p.busy
|
||||
? null
|
||||
: () async {
|
||||
final restored =
|
||||
await Navigator.push<DestinationInput>(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => DestinationFormPage(
|
||||
initial: p.destination.details,
|
||||
restoring: p.destination.input,
|
||||
),
|
||||
),
|
||||
);
|
||||
if (mounted && restored != null) {
|
||||
await p.refresh();
|
||||
}
|
||||
},
|
||||
child: Text(l.dUpdateAuthorization),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: p.busy
|
||||
? null
|
||||
: () async {
|
||||
await Navigator.push<DestinationInput>(
|
||||
context,
|
||||
MaterialPageRoute(
|
||||
builder: (_) => DestinationFormPage(
|
||||
initial: p.destination.details,
|
||||
replacing: p.destination.id,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Text(l.dReplace),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: p.busy ? null : remove,
|
||||
child: Text(l.dRemove),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user