Wallet update for correct name and symbol appearance

This commit is contained in:
Arseni
2025-12-16 19:37:28 +03:00
parent 67b52af150
commit 9a90e6a03b
12 changed files with 111 additions and 117 deletions

View File

@@ -2,6 +2,7 @@ import 'package:pshared/data/dto/wallet/balance.dart';
import 'package:pshared/data/dto/wallet/wallet.dart'; import 'package:pshared/data/dto/wallet/wallet.dart';
import 'package:pshared/data/mapper/wallet/balance.dart'; import 'package:pshared/data/mapper/wallet/balance.dart';
import 'package:pshared/data/mapper/wallet/money.dart'; import 'package:pshared/data/mapper/wallet/money.dart';
import 'package:pshared/models/describable.dart';
import 'package:pshared/models/wallet/wallet.dart'; import 'package:pshared/models/wallet/wallet.dart';
@@ -22,5 +23,9 @@ extension WalletDTOMapper on WalletDTO {
updatedAt: (updatedAt == null || updatedAt!.isEmpty) ? null : DateTime.tryParse(updatedAt!), updatedAt: (updatedAt == null || updatedAt!.isEmpty) ? null : DateTime.tryParse(updatedAt!),
balance: balance?.toDomain(), balance: balance?.toDomain(),
availableMoney: balance?.available?.toDomain(), availableMoney: balance?.available?.toDomain(),
describable: newDescribable(
name: metadata?['name'] ?? 'Crypto Wallet',
description: metadata?['description'],
),
); );
} }

View File

@@ -1,5 +1,6 @@
import 'package:pshared/models/wallet/balance.dart'; import 'package:pshared/models/wallet/balance.dart';
import 'package:pshared/models/wallet/money.dart'; import 'package:pshared/models/wallet/money.dart';
import 'package:pshared/models/describable.dart';
class WalletAsset { class WalletAsset {
@@ -14,7 +15,7 @@ class WalletAsset {
}); });
} }
class WalletModel { class WalletModel implements Describable {
final String walletRef; final String walletRef;
final String organizationRef; final String organizationRef;
final String ownerRef; final String ownerRef;
@@ -26,6 +27,13 @@ class WalletModel {
final DateTime? updatedAt; final DateTime? updatedAt;
final WalletBalance? balance; final WalletBalance? balance;
final WalletMoney? availableMoney; final WalletMoney? availableMoney;
final Describable describable;
@override
String get name => describable.name;
@override
String? get description => describable.description;
const WalletModel({ const WalletModel({
required this.walletRef, required this.walletRef,
@@ -39,11 +47,13 @@ class WalletModel {
this.updatedAt, this.updatedAt,
this.balance, this.balance,
this.availableMoney, this.availableMoney,
required this.describable,
}); });
WalletModel copyWith({ WalletModel copyWith({
WalletBalance? balance, WalletBalance? balance,
WalletMoney? availableMoney, WalletMoney? availableMoney,
Describable? describable,
}) { }) {
return WalletModel( return WalletModel(
walletRef: walletRef, walletRef: walletRef,
@@ -57,6 +67,7 @@ class WalletModel {
updatedAt: updatedAt, updatedAt: updatedAt,
balance: balance ?? this.balance, balance: balance ?? this.balance,
availableMoney: availableMoney ?? this.availableMoney, availableMoney: availableMoney ?? this.availableMoney,
describable: describable ?? this.describable,
); );
} }
} }

View File

@@ -1,6 +1,7 @@
import 'package:pshared/models/wallet/wallet.dart' as domain; import 'package:pshared/models/wallet/wallet.dart' as domain;
import 'package:pshared/models/currency.dart'; import 'package:pshared/models/currency.dart';
import 'package:pshared/models/describable.dart';
import 'package:pweb/models/wallet.dart'; import 'package:pweb/models/wallet.dart';
@@ -17,7 +18,6 @@ extension WalletUiMapper on domain.WalletModel {
return Wallet( return Wallet(
id: walletRef, id: walletRef,
walletUserID: walletRef, walletUserID: walletRef,
name: metadata?['name'] ?? walletRef,
balance: parsedAmount, balance: parsedAmount,
currency: currency, currency: currency,
isHidden: true, isHidden: true,
@@ -26,6 +26,10 @@ extension WalletUiMapper on domain.WalletModel {
network: asset.chain, network: asset.chain,
tokenSymbol: asset.tokenSymbol, tokenSymbol: asset.tokenSymbol,
contractAddress: asset.contractAddress, contractAddress: asset.contractAddress,
describable: newDescribable(
name: metadata?['name'] ?? 'Crypto Wallet',
description: metadata?['description'],
),
); );
} }
} }

View File

@@ -311,6 +311,7 @@
"paymentTypeBankAccount": "Russian Bank Account", "paymentTypeBankAccount": "Russian Bank Account",
"paymentTypeIban": "IBAN", "paymentTypeIban": "IBAN",
"paymentTypeWallet": "Wallet", "paymentTypeWallet": "Wallet",
"paymentTypeCryptoWallet": "Crypto Wallet",
"paymentTypeCryptoAddress": "Crypto address", "paymentTypeCryptoAddress": "Crypto address",
"paymentTypeLedger": "Ledger account", "paymentTypeLedger": "Ledger account",
"paymentTypeManagedWallet": "Managed wallet", "paymentTypeManagedWallet": "Managed wallet",

View File

@@ -311,6 +311,7 @@
"paymentTypeBankAccount": "Российский банковский счет", "paymentTypeBankAccount": "Российский банковский счет",
"paymentTypeIban": "IBAN", "paymentTypeIban": "IBAN",
"paymentTypeWallet": "Кошелек", "paymentTypeWallet": "Кошелек",
"paymentTypeCryptoWallet": "Криптокошелек",
"paymentTypeCryptoAddress": "Крипто-адрес", "paymentTypeCryptoAddress": "Крипто-адрес",
"paymentTypeLedger": "Леджер счет", "paymentTypeLedger": "Леджер счет",
"paymentTypeManagedWallet": "Управляемый кошелек", "paymentTypeManagedWallet": "Управляемый кошелек",

View File

@@ -1,10 +1,10 @@
import 'package:pshared/models/currency.dart'; import 'package:pshared/models/currency.dart';
import 'package:pshared/models/describable.dart';
class Wallet { class Wallet implements Describable {
final String id; final String id;
final String walletUserID; // ID or number that we show the user final String walletUserID; // ID or number that we show the user
final String name;
final double balance; final double balance;
final Currency currency; final Currency currency;
final bool isHidden; final bool isHidden;
@@ -13,14 +13,21 @@ class Wallet {
final String? network; final String? network;
final String? tokenSymbol; final String? tokenSymbol;
final String? contractAddress; final String? contractAddress;
final Describable describable;
@override
String get name => describable.name;
@override
String? get description => describable.description;
Wallet({ Wallet({
required this.id, required this.id,
required this.walletUserID, required this.walletUserID,
required this.name,
required this.balance, required this.balance,
required this.currency, required this.currency,
required this.calculatedAt, required this.calculatedAt,
required this.describable,
this.isHidden = true, this.isHidden = true,
this.depositAddress, this.depositAddress,
this.network, this.network,
@@ -30,7 +37,6 @@ class Wallet {
Wallet copyWith({ Wallet copyWith({
String? id, String? id,
String? name,
double? balance, double? balance,
Currency? currency, Currency? currency,
String? walletUserID, String? walletUserID,
@@ -39,9 +45,11 @@ class Wallet {
String? network, String? network,
String? tokenSymbol, String? tokenSymbol,
String? contractAddress, String? contractAddress,
Describable? describable,
String? name,
String? Function()? description,
}) => Wallet( }) => Wallet(
id: id ?? this.id, id: id ?? this.id,
name: name ?? this.name,
balance: balance ?? this.balance, balance: balance ?? this.balance,
currency: currency ?? this.currency, currency: currency ?? this.currency,
walletUserID: walletUserID ?? this.walletUserID, walletUserID: walletUserID ?? this.walletUserID,
@@ -51,5 +59,9 @@ class Wallet {
network: network ?? this.network, network: network ?? this.network,
tokenSymbol: tokenSymbol ?? this.tokenSymbol, tokenSymbol: tokenSymbol ?? this.tokenSymbol,
contractAddress: contractAddress ?? this.contractAddress, contractAddress: contractAddress ?? this.contractAddress,
describable: describable
?? (name != null || description != null
? this.describable.copyWith(name: name, description: description)
: this.describable),
); );
} }

View File

@@ -34,8 +34,8 @@ class WalletCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
BalanceHeader( BalanceHeader(
walletName: wallet.name, walletNetwork: wallet.network,
walletId: wallet.walletUserID, tokenSymbol: wallet.tokenSymbol,
), ),
BalanceAmount( BalanceAmount(
wallet: wallet, wallet: wallet,

View File

@@ -2,37 +2,46 @@ import 'package:flutter/material.dart';
class BalanceHeader extends StatelessWidget { class BalanceHeader extends StatelessWidget {
final String walletName; final String? walletNetwork;
final String walletId; final String? tokenSymbol;
const BalanceHeader({ const BalanceHeader({
super.key, super.key,
required this.walletName, this.walletNetwork,
required this.walletId, this.tokenSymbol,
}); });
static const double _spacing = 8.0;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final textTheme = Theme.of(context).textTheme; final textTheme = Theme.of(context).textTheme;
final colorScheme = Theme.of(context).colorScheme; final colorScheme = Theme.of(context).colorScheme;
final symbol = tokenSymbol?.trim();
return Row( return Row(
children: [ children: [
Text( Text(
walletName, 'Crypto Wallet',
style: textTheme.titleMedium?.copyWith( style: textTheme.titleMedium?.copyWith(
color: colorScheme.onSurface, color: colorScheme.onSurface,
), ),
), ),
const SizedBox(width: _spacing), if (symbol != null && symbol.isNotEmpty) ...[
Text( const SizedBox(width: 8),
walletId, Container(
style: textTheme.bodySmall?.copyWith( padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
color: colorScheme.onSurface, decoration: BoxDecoration(
color: colorScheme.primaryContainer,
borderRadius: BorderRadius.circular(999),
),
child: Text(
symbol,
style: textTheme.bodyMedium?.copyWith(
color: colorScheme.onPrimaryContainer,
fontWeight: FontWeight.w600,
), ),
), ),
),
],
], ],
); );
} }

View File

@@ -3,6 +3,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pshared/utils/currency.dart'; import 'package:pshared/utils/currency.dart';
import 'package:pweb/generated/i18n/app_localizations.dart';
import 'package:pweb/models/wallet.dart'; import 'package:pweb/models/wallet.dart';
import 'package:pweb/pages/dashboard/buttons/balance/amount.dart'; import 'package:pweb/pages/dashboard/buttons/balance/amount.dart';
@@ -48,9 +49,21 @@ class WalletCard extends StatelessWidget {
}, },
), ),
Text( Text(
wallet.name, AppLocalizations.of(context)!.paymentTypeCryptoWallet,
style: theme.textTheme.bodyLarge!.copyWith(fontWeight: FontWeight.w500), style: theme.textTheme.bodyLarge!.copyWith(
fontWeight: FontWeight.w600,
color: theme.colorScheme.onSurface,
), ),
),
if (wallet.tokenSymbol != null) ...[
const SizedBox(height: 4),
Text(
wallet.tokenSymbol!,
style: theme.textTheme.bodyMedium?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
),
),
],
], ],
), ),
), ),

View File

@@ -3,111 +3,43 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pweb/providers/wallets.dart'; import 'package:pweb/providers/wallets.dart';
import 'package:pweb/widgets/error/snackbar.dart';
import 'package:pweb/generated/i18n/app_localizations.dart';
class WalletEditHeader extends StatefulWidget { class WalletEditHeader extends StatelessWidget {
const WalletEditHeader({super.key}); const WalletEditHeader({super.key});
@override
State<WalletEditHeader> createState() => _WalletEditHeaderState();
}
class _WalletEditHeaderState extends State<WalletEditHeader> {
bool _isEditing = false;
late TextEditingController _controller;
@override
void initState() {
super.initState();
_controller = TextEditingController();
}
@override
void dispose() {
_controller.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final provider = context.watch<WalletsProvider>(); final provider = context.watch<WalletsProvider>();
final wallet = provider.selectedWallet; final wallet = provider.selectedWallet;
final loc = AppLocalizations.of(context)!;
if (wallet == null) { if (wallet == null) {
return SizedBox.shrink(); return const SizedBox.shrink();
} }
final theme = Theme.of(context); final theme = Theme.of(context);
if (!_isEditing) {
_controller.text = wallet.name;
}
return Row( return Row(
spacing: 8, spacing: 8,
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
Expanded( Expanded(
child: !_isEditing child: Column(
? Row( crossAxisAlignment: CrossAxisAlignment.start,
spacing: 4,
children: [ children: [
Expanded( Text(
child: Text( 'Crypto Wallet',
wallet.name,
style: theme.textTheme.headlineMedium!.copyWith( style: theme.textTheme.headlineMedium!.copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
), ),
), ),
if (wallet.tokenSymbol != null)
Text(
wallet.tokenSymbol!,
style: theme.textTheme.bodyMedium?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
), ),
IconButton(
icon: const Icon(Icons.edit),
onPressed: () {
setState(() {
_isEditing = true;
});
},
),
],
)
: Row(
children: [
Expanded(
child: TextFormField(
controller: _controller,
decoration: InputDecoration(
border: OutlineInputBorder(),
isDense: true,
hintText: loc.walletName,
),
),
),
IconButton(
icon: const Icon(Icons.check),
color: theme.colorScheme.primary,
onPressed: () async {
await executeActionWithNotification(
context: context,
action: () async => await provider.updateWallet(wallet.copyWith(name: _controller.text)),
errorMessage: loc.walletNameUpdateFailed,
successMessage: loc.walletNameSaved,
);
setState(() {
_isEditing = false;
});
},
),
IconButton(
icon: const Icon(Icons.close),
onPressed: () {
_controller.text = wallet.name;
setState(() {
_isEditing = false;
});
},
), ),
], ],
), ),

View File

@@ -46,7 +46,7 @@ class WalletTopUpContent extends StatelessWidget {
children: [ children: [
WalletTopUpHeader( WalletTopUpHeader(
onBack: onBack, onBack: onBack,
walletName: wallet.name, tokenSymbol: assetLabel,
), ),
SizedBox(height: dimensions.paddingLarge), SizedBox(height: dimensions.paddingLarge),
WalletTopUpMeta( WalletTopUpMeta(

View File

@@ -5,18 +5,24 @@ import 'package:pweb/generated/i18n/app_localizations.dart';
class WalletTopUpHeader extends StatelessWidget { class WalletTopUpHeader extends StatelessWidget {
final VoidCallback onBack; final VoidCallback onBack;
final String walletName; final String? tokenSymbol;
const WalletTopUpHeader({ const WalletTopUpHeader({
super.key, super.key,
required this.onBack, required this.onBack,
required this.walletName, this.tokenSymbol,
}); });
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final theme = Theme.of(context); final theme = Theme.of(context);
final loc = AppLocalizations.of(context)!; final loc = AppLocalizations.of(context)!;
final symbol = tokenSymbol?.trim();
final subtitle = [
'Crypto Wallet',
if (symbol != null && symbol.isNotEmpty) symbol,
].join(' · ');
return Row( return Row(
children: [ children: [
@@ -34,7 +40,7 @@ class WalletTopUpHeader extends StatelessWidget {
), ),
const SizedBox(height: 4), const SizedBox(height: 4),
Text( Text(
walletName, subtitle,
style: theme.textTheme.bodyMedium?.copyWith( style: theme.textTheme.bodyMedium?.copyWith(
color: theme.colorScheme.onSurfaceVariant, color: theme.colorScheme.onSurfaceVariant,
), ),