Files

246 lines
8.0 KiB
Dart

import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart';
import 'package:sxchnge_wallet/sxchnge_wallet.dart';
import 'activity.dart';
import 'copy.dart';
import '../generated/i18n/app_localizations.dart';
class AccountsPage extends StatelessWidget {
const AccountsPage({super.key, this.accountId});
final String? accountId;
@override
Widget build(BuildContext context) {
final p = context.watch<WalletProvider>();
final l = AppLocalizations.of(context)!;
final t = Theme.of(context);
final c = t.colorScheme;
final accounts = p.data?.accounts ?? [];
final selected = accountId == null
? accounts.firstOrNull
: p.account(accountId);
return SingleChildScrollView(
padding: const EdgeInsets.all(24),
child: Center(
child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 1120),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Expanded(
child: Text(l.wHeadline, style: t.textTheme.displayMedium),
),
IconButton(
tooltip: l.wRefresh,
onPressed: p.loading ? null : p.refresh,
icon: const Icon(Icons.refresh),
),
],
),
const SizedBox(height: 12),
Text(l.wSubheading, style: t.textTheme.bodyLarge),
const SizedBox(height: 28),
if (p.loading) const LinearProgressIndicator(),
if (p.failed)
Padding(
padding: const EdgeInsets.symmetric(vertical: 16),
child: Text(l.wUnavailable, style: TextStyle(color: c.error)),
),
if (!p.loading && accounts.isEmpty) Text(l.wEmptyAccounts),
if (accountId != null &&
p.account(accountId) == null &&
!p.loading)
Text(l.wNotFound),
if (selected != null) ...[
const SizedBox(height: 24),
Text(selected.currency, style: t.textTheme.titleLarge),
const SizedBox(height: 12),
Wrap(
spacing: 12,
runSpacing: 12,
children: [
for (final kind in TransferKind.values)
_action(
context,
kind,
selected,
primary:
kind ==
(selected.available == 0
? TransferKind.topUp
: TransferKind.exchange),
),
],
),
],
const SizedBox(height: 24),
LayoutBuilder(
builder: (context, box) {
final width = box.maxWidth >= 660
? (box.maxWidth - 32) / 3
: box.maxWidth;
return Wrap(
spacing: 16,
runSpacing: 16,
children: [
for (var i = 0; i < accounts.length; i++)
SizedBox(
width: width,
child: _AccountCard(
account: accounts[i],
selected: accounts[i].id == selected?.id,
index: i,
),
),
],
);
},
),
const SizedBox(height: 36),
Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(l.wRecent, style: t.textTheme.headlineSmall),
TextButton(
onPressed: () => context.go('/activity'),
child: Text(l.wSeeAll),
),
],
),
const SizedBox(height: 12),
...?p.data?.operations
.where(
(o) =>
accountId == null ||
o.quote.request.source == accountId ||
o.quote.request.destination == accountId,
)
.take(5)
.map((o) => OperationTile(operation: o)),
if (!(p.data?.operations.any(
(o) =>
accountId == null ||
o.quote.request.source == accountId ||
o.quote.request.destination == accountId,
) ??
false))
Container(
padding: const EdgeInsets.all(28),
decoration: BoxDecoration(
color: c.surfaceContainer,
borderRadius: BorderRadius.circular(24),
),
child: Text(l.wEmptyActivity),
),
],
),
),
),
);
}
Widget _action(
BuildContext context,
TransferKind kind,
CurrencyAccount a, {
required bool primary,
}) {
final l = AppLocalizations.of(context)!;
void go() => context.go(
'/${kind.name == "topUp" ? "top-up" : kind.name}',
extra: a.id,
);
return primary
? FilledButton.icon(
key: ValueKey('${kind.name}-${a.id}'),
onPressed: go,
icon: Icon(kindIcon(kind)),
label: Text(kindText(l, kind)),
)
: FilledButton.tonalIcon(
key: ValueKey('${kind.name}-${a.id}'),
onPressed: go,
icon: Icon(kindIcon(kind)),
label: Text(kindText(l, kind)),
);
}
}
class _AccountCard extends StatelessWidget {
const _AccountCard({
required this.account,
required this.selected,
required this.index,
});
final CurrencyAccount account;
final bool selected;
final int index;
@override
Widget build(BuildContext context) {
final l = AppLocalizations.of(context)!;
final t = Theme.of(context);
final c = t.colorScheme;
final bg = selected
? c.primary
: index == 1
? c.tertiaryContainer
: c.primaryContainer;
final fg = selected
? c.onPrimary
: index == 1
? c.onTertiaryContainer
: c.onPrimaryContainer;
return Semantics(
selected: selected,
child: Material(
color: bg,
borderRadius: BorderRadius.circular(28),
child: InkWell(
key: ValueKey('account-${account.id}'),
borderRadius: BorderRadius.circular(28),
onTap: () => context.go('/accounts/${account.id}'),
child: Padding(
padding: const EdgeInsets.all(24),
child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
Row(
children: [
Text(
account.currency,
style: t.textTheme.titleLarge?.copyWith(color: fg),
),
const Spacer(),
Icon(
selected
? Icons.check_circle_outline
: Icons.arrow_outward_rounded,
color: fg,
),
],
),
const SizedBox(height: 32),
Text(l.wAvailable, style: TextStyle(color: fg)),
const SizedBox(height: 8),
Text(
money(context, account, account.available),
key: ValueKey('balance-${account.id}'),
style: t.textTheme.headlineMedium?.copyWith(color: fg),
),
],
),
),
),
),
);
}
}