Merge pull request 'Fixed compilation' (#300) from ledger-299 into main
All checks were successful
ci/woodpecker/push/billing_fees Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/bff Pipeline was successful
ci/woodpecker/push/discovery Pipeline was successful
ci/woodpecker/push/fx_ingestor Pipeline was successful
ci/woodpecker/push/fx_oracle Pipeline was successful
ci/woodpecker/push/frontend Pipeline was successful
ci/woodpecker/push/gateway_mntx Pipeline was successful
ci/woodpecker/push/gateway_chain Pipeline was successful
ci/woodpecker/push/gateway_tgsettle Pipeline was successful
ci/woodpecker/push/nats Pipeline was successful
ci/woodpecker/push/ledger Pipeline was successful
ci/woodpecker/push/notification Pipeline was successful
ci/woodpecker/push/payments_orchestrator Pipeline was successful

Reviewed-on: #300
This commit was merged in pull request #300.
This commit is contained in:
2026-01-22 13:15:35 +00:00
41 changed files with 549 additions and 190 deletions

View File

@@ -0,0 +1,129 @@
import 'package:collection/collection.dart';
import 'package:flutter/foundation.dart';
import 'package:pshared/models/payment/wallet.dart';
import 'package:pshared/provider/payment/wallets.dart';
class WalletsController with ChangeNotifier {
late WalletsProvider _wallets;
// If you want per-org isolation, we reset when org changes.
String? _orgRef;
// Visibility is UI-only: store hidden wallet ids here.
final Set<String> _hiddenWalletIds = <String>{};
String? _selectedWalletId;
bool get isLoading => _wallets.isLoading;
Exception? get error => _wallets.error;
/// Inject / update dependency (use ProxyProvider).
void update(WalletsProvider wallets) {
_wallets = wallets;
final nextOrgRef = wallets.organizationId;
final orgChanged = nextOrgRef != _orgRef;
if (orgChanged) {
_orgRef = nextOrgRef;
_hiddenWalletIds.clear();
_selectedWalletId = null;
}
// Prune hidden ids for wallets that no longer exist.
final ids = wallets.wallets.map((w) => w.id).toSet();
final beforeHiddenLen = _hiddenWalletIds.length;
_hiddenWalletIds.removeWhere((id) => !ids.contains(id));
// Ensure selection is valid.
final beforeSelected = _selectedWalletId;
_selectedWalletId = _resolveSelectedId(
currentId: _selectedWalletId,
wallets: wallets.wallets,
hiddenIds: _hiddenWalletIds,
);
final selectionChanged = beforeSelected != _selectedWalletId;
final hiddenChanged = beforeHiddenLen != _hiddenWalletIds.length;
if (orgChanged || selectionChanged || hiddenChanged) {
notifyListeners();
}
}
List<Wallet> get wallets => _wallets.wallets;
bool isHidden(String walletId) => _hiddenWalletIds.contains(walletId);
List<Wallet> get visibleWallets =>
wallets.where((w) => !_hiddenWalletIds.contains(w.id)).toList(growable: false);
Wallet? get selectedWallet {
final id = _selectedWalletId;
if (id == null) return null;
return wallets.firstWhereOrNull((w) => w.id == id);
}
String? get selectedWalletId => _selectedWalletId;
void selectWallet(Wallet wallet) => selectWalletId(wallet.id);
void selectWalletId(String walletId) {
if (_selectedWalletId == walletId) return;
// Allow selecting hidden wallet if you want; if not, block it:
// if (isHidden(walletId)) return;
_selectedWalletId = walletId;
notifyListeners();
}
void toggleVisibility(String walletId) {
final existed = _hiddenWalletIds.remove(walletId);
if (!existed) _hiddenWalletIds.add(walletId);
// If we hid the selected wallet, move selection to next visible.
_selectedWalletId = _resolveSelectedId(
currentId: _selectedWalletId,
wallets: wallets,
hiddenIds: _hiddenWalletIds,
);
notifyListeners();
}
void showAll() {
if (_hiddenWalletIds.isEmpty) return;
_hiddenWalletIds.clear();
_selectedWalletId = _resolveSelectedId(
currentId: _selectedWalletId,
wallets: wallets,
hiddenIds: _hiddenWalletIds,
);
notifyListeners();
}
String? _resolveSelectedId({
required String? currentId,
required List<Wallet> wallets,
required Set<String> hiddenIds,
}) {
if (wallets.isEmpty) return null;
// Keep current if exists and is not hidden.
if (currentId != null) {
final exists = wallets.any((w) => w.id == currentId);
if (exists && !hiddenIds.contains(currentId)) return currentId;
}
// Pick first visible.
final firstVisible = wallets.firstWhereOrNull((w) => !hiddenIds.contains(w.id));
if (firstVisible != null) return firstVisible.id;
// All hidden: fall back to first wallet id (or return null if you prefer).
return wallets.first.id;
}
}

View File

@@ -0,0 +1,47 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:pshared/data/dto/describable.dart';
import 'package:pshared/data/dto/ledger/balance.dart';
part 'account.g.dart';
@JsonSerializable(includeIfNull: false, explicitToJson: true)
class LedgerAccountDTO {
final String ledgerAccountRef;
final String organizationRef;
final String? ownerRef;
final String accountCode;
final String accountType;
final String currency;
final String status;
final bool allowNegative;
final bool isSettlement;
final Map<String, String>? metadata;
final DateTime? createdAt;
final DateTime? updatedAt;
final DescribableDTO describable;
final LedgerBalanceDTO? balance;
const LedgerAccountDTO({
required this.ledgerAccountRef,
required this.organizationRef,
this.ownerRef,
required this.accountCode,
required this.accountType,
required this.currency,
required this.status,
required this.allowNegative,
required this.isSettlement,
this.metadata,
this.createdAt,
this.updatedAt,
required this.describable,
this.balance,
});
factory LedgerAccountDTO.fromJson(Map<String, dynamic> json) => _$LedgerAccountDTOFromJson(json);
Map<String, dynamic> toJson() => _$LedgerAccountDTOToJson(this);
}

View File

@@ -0,0 +1,27 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:pshared/data/dto/money.dart';
part 'balance.g.dart';
@JsonSerializable(
includeIfNull: false, // <- omitempty behavior
explicitToJson: true, // <- nested DTOs call toJson()
)
class LedgerBalanceDTO {
final String ledgerAccountRef;
final MoneyDTO? balance;
final int version;
final DateTime? lastUpdated;
const LedgerBalanceDTO({
required this.ledgerAccountRef,
this.balance,
required this.version,
this.lastUpdated,
});
factory LedgerBalanceDTO.fromJson(Map<String, dynamic> json) => _$LedgerBalanceDTOFromJson(json);
Map<String, dynamic> toJson() => _$LedgerBalanceDTOToJson(this);
}

View File

@@ -1,6 +1,6 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'package:pshared/data/dto/payment/money.dart'; import 'package:pshared/data/dto/money.dart';
part 'fee_line.g.dart'; part 'fee_line.g.dart';

View File

@@ -1,6 +1,6 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'package:pshared/data/dto/payment/money.dart'; import 'package:pshared/data/dto/money.dart';
part 'fx_quote.g.dart'; part 'fx_quote.g.dart';

View File

@@ -3,7 +3,7 @@ import 'package:json_annotation/json_annotation.dart';
import 'package:pshared/data/dto/payment/endpoint.dart'; import 'package:pshared/data/dto/payment/endpoint.dart';
import 'package:pshared/data/dto/payment/intent/customer.dart'; import 'package:pshared/data/dto/payment/intent/customer.dart';
import 'package:pshared/data/dto/payment/intent/fx.dart'; import 'package:pshared/data/dto/payment/intent/fx.dart';
import 'package:pshared/data/dto/payment/money.dart'; import 'package:pshared/data/dto/money.dart';
part 'payment.g.dart'; part 'payment.g.dart';

View File

@@ -1,6 +1,6 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'package:pshared/data/dto/payment/money.dart'; import 'package:pshared/data/dto/money.dart';
part 'network_fee.g.dart'; part 'network_fee.g.dart';

View File

@@ -2,7 +2,7 @@ import 'package:json_annotation/json_annotation.dart';
import 'package:pshared/data/dto/payment/fee_line.dart'; import 'package:pshared/data/dto/payment/fee_line.dart';
import 'package:pshared/data/dto/payment/fx_quote.dart'; import 'package:pshared/data/dto/payment/fx_quote.dart';
import 'package:pshared/data/dto/payment/money.dart'; import 'package:pshared/data/dto/money.dart';
import 'package:pshared/data/dto/payment/network_fee.dart'; import 'package:pshared/data/dto/payment/network_fee.dart';
part 'payment_quote.g.dart'; part 'payment_quote.g.dart';

View File

@@ -1,6 +1,6 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'package:pshared/data/dto/payment/money.dart'; import 'package:pshared/data/dto/money.dart';
part 'quote_aggregate.g.dart'; part 'quote_aggregate.g.dart';

View File

@@ -0,0 +1,43 @@
import 'package:pshared/data/dto/ledger/account.dart';
import 'package:pshared/data/mapper/describable.dart';
import 'package:pshared/data/mapper/ledger/balance.dart';
import 'package:pshared/models/ledger/account.dart';
extension LedgerAccountDtoMapper on LedgerAccountDTO {
LedgerAccount toModel() => LedgerAccount(
ledgerAccountRef: ledgerAccountRef,
organizationRef: organizationRef,
ownerRef: ownerRef,
accountCode: accountCode,
accountType: accountType,
currency: currency,
status: status,
allowNegative: allowNegative,
isSettlement: isSettlement,
metadata: metadata,
createdAt: createdAt,
updatedAt: updatedAt,
describable: describable.toDomain(),
balance: balance?.toDomain(),
);
}
extension LedgerAccountModelMapper on LedgerAccount {
LedgerAccountDTO toDTO() => LedgerAccountDTO(
ledgerAccountRef: ledgerAccountRef,
organizationRef: organizationRef,
ownerRef: ownerRef,
accountCode: accountCode,
accountType: accountType,
currency: currency,
status: status,
allowNegative: allowNegative,
isSettlement: isSettlement,
metadata: metadata,
createdAt: createdAt,
updatedAt: updatedAt,
describable: describable.toDTO(),
balance: balance?.toDTO(),
);
}

View File

@@ -0,0 +1,22 @@
import 'package:pshared/data/dto/ledger/balance.dart';
import 'package:pshared/data/mapper/money.dart';
import 'package:pshared/models/ledger/balance.dart';
extension LedgerBalanceDtoMapper on LedgerBalanceDTO {
LedgerBalance toDomain() => LedgerBalance(
ledgerAccountRef: ledgerAccountRef,
balance: balance?.toDomain(),
version: version,
lastUpdated: lastUpdated,
);
}
extension LedgerBalanceModelMapper on LedgerBalance {
LedgerBalanceDTO toDTO() => LedgerBalanceDTO(
ledgerAccountRef: ledgerAccountRef,
balance: balance?.toDTO(),
version: version,
lastUpdated: lastUpdated,
);
}

View File

@@ -1,4 +1,4 @@
import 'package:pshared/data/dto/payment/money.dart'; import 'package:pshared/data/dto/money.dart';
import 'package:pshared/models/money.dart'; import 'package:pshared/models/money.dart';

View File

@@ -1,5 +1,5 @@
import 'package:pshared/data/dto/payment/fee_line.dart'; import 'package:pshared/data/dto/payment/fee_line.dart';
import 'package:pshared/data/mapper/payment/money.dart'; import 'package:pshared/data/mapper/money.dart';
import 'package:pshared/models/payment/fees/line.dart'; import 'package:pshared/models/payment/fees/line.dart';

View File

@@ -1,5 +1,5 @@
import 'package:pshared/data/dto/payment/fx_quote.dart'; import 'package:pshared/data/dto/payment/fx_quote.dart';
import 'package:pshared/data/mapper/payment/money.dart'; import 'package:pshared/data/mapper/money.dart';
import 'package:pshared/models/payment/fx/quote.dart'; import 'package:pshared/models/payment/fx/quote.dart';

View File

@@ -3,7 +3,7 @@ import 'package:pshared/data/mapper/payment/payment.dart';
import 'package:pshared/data/mapper/payment/enums.dart'; import 'package:pshared/data/mapper/payment/enums.dart';
import 'package:pshared/data/mapper/payment/intent/customer.dart'; import 'package:pshared/data/mapper/payment/intent/customer.dart';
import 'package:pshared/data/mapper/payment/intent/fx.dart'; import 'package:pshared/data/mapper/payment/intent/fx.dart';
import 'package:pshared/data/mapper/payment/money.dart'; import 'package:pshared/data/mapper/money.dart';
import 'package:pshared/models/payment/intent.dart'; import 'package:pshared/models/payment/intent.dart';

View File

@@ -1,5 +1,5 @@
import 'package:pshared/data/dto/payment/network_fee.dart'; import 'package:pshared/data/dto/payment/network_fee.dart';
import 'package:pshared/data/mapper/payment/money.dart'; import 'package:pshared/data/mapper/money.dart';
import 'package:pshared/models/payment/fees/network.dart'; import 'package:pshared/models/payment/fees/network.dart';

View File

@@ -1,7 +1,7 @@
import 'package:pshared/data/dto/payment/payment_quote.dart'; import 'package:pshared/data/dto/payment/payment_quote.dart';
import 'package:pshared/data/mapper/payment/fee_line.dart'; import 'package:pshared/data/mapper/payment/fee_line.dart';
import 'package:pshared/data/mapper/payment/fx_quote.dart'; import 'package:pshared/data/mapper/payment/fx_quote.dart';
import 'package:pshared/data/mapper/payment/money.dart'; import 'package:pshared/data/mapper/money.dart';
import 'package:pshared/data/mapper/payment/network_fee.dart'; import 'package:pshared/data/mapper/payment/network_fee.dart';
import 'package:pshared/models/payment/quote/quote.dart'; import 'package:pshared/models/payment/quote/quote.dart';

View File

@@ -1,5 +1,5 @@
import 'package:pshared/data/dto/payment/quote_aggregate.dart'; import 'package:pshared/data/dto/payment/quote_aggregate.dart';
import 'package:pshared/data/mapper/payment/money.dart'; import 'package:pshared/data/mapper/money.dart';
import 'package:pshared/models/payment/quote/aggregate.dart'; import 'package:pshared/models/payment/quote/aggregate.dart';

View File

@@ -9,7 +9,6 @@ extension WalletUiMapper on domain.WalletModel {
walletUserID: walletRef, walletUserID: walletRef,
balance: double.tryParse(availableMoney?.amount ?? balance?.available?.amount ?? '0') ?? 0, balance: double.tryParse(availableMoney?.amount ?? balance?.available?.amount ?? '0') ?? 0,
currency: currencyStringToCode(asset.tokenSymbol), currency: currencyStringToCode(asset.tokenSymbol),
isHidden: true,
calculatedAt: balance?.calculatedAt ?? DateTime.now(), calculatedAt: balance?.calculatedAt ?? DateTime.now(),
depositAddress: depositAddress, depositAddress: depositAddress,
network: asset.chain, network: asset.chain,

View File

@@ -1,4 +1,5 @@
import 'package:pshared/models/describable.dart'; import 'package:pshared/models/describable.dart';
import 'package:pshared/models/ledger/balance.dart';
class LedgerAccount implements Describable { class LedgerAccount implements Describable {
@@ -15,6 +16,7 @@ class LedgerAccount implements Describable {
final DateTime? createdAt; final DateTime? createdAt;
final DateTime? updatedAt; final DateTime? updatedAt;
final Describable describable; final Describable describable;
final LedgerBalance? balance;
@override @override
String get name => describable.name; String get name => describable.name;
@@ -36,6 +38,7 @@ class LedgerAccount implements Describable {
this.createdAt, this.createdAt,
this.updatedAt, this.updatedAt,
required this.describable, required this.describable,
this.balance,
}); });
LedgerAccount copyWith({ LedgerAccount copyWith({
@@ -54,5 +57,6 @@ class LedgerAccount implements Describable {
createdAt: createdAt, createdAt: createdAt,
updatedAt: updatedAt, updatedAt: updatedAt,
describable: describable ?? this.describable, describable: describable ?? this.describable,
balance: balance,
); );
} }

View File

@@ -0,0 +1,16 @@
import 'package:pshared/models/money.dart';
class LedgerBalance {
final String ledgerAccountRef;
final Money? balance;
final int version;
final DateTime? lastUpdated;
const LedgerBalance({
required this.ledgerAccountRef,
this.balance,
required this.version,
this.lastUpdated,
});
}

View File

@@ -8,7 +8,6 @@ class Wallet implements Describable {
final String walletUserID; // ID or number that we show the user final String walletUserID; // ID or number that we show the user
final double balance; final double balance;
final Currency currency; final Currency currency;
final bool isHidden;
final DateTime calculatedAt; final DateTime calculatedAt;
final String? depositAddress; final String? depositAddress;
final ChainNetwork? network; final ChainNetwork? network;
@@ -29,7 +28,6 @@ class Wallet implements Describable {
required this.currency, required this.currency,
required this.calculatedAt, required this.calculatedAt,
required this.describable, required this.describable,
this.isHidden = true,
this.depositAddress, this.depositAddress,
this.network, this.network,
this.tokenSymbol, this.tokenSymbol,
@@ -37,32 +35,18 @@ class Wallet implements Describable {
}); });
Wallet copyWith({ Wallet copyWith({
String? id,
double? balance,
Currency? currency,
String? walletUserID,
bool? isHidden,
String? depositAddress,
ChainNetwork? network,
String? tokenSymbol,
String? contractAddress,
Describable? describable, Describable? describable,
String? name, double? balance,
String? Function()? description,
}) => Wallet( }) => Wallet(
id: id ?? this.id, id: id,
balance: balance ?? this.balance, balance: balance ?? this.balance,
currency: currency ?? this.currency, currency: currency,
walletUserID: walletUserID ?? this.walletUserID, walletUserID: walletUserID,
isHidden: isHidden ?? this.isHidden,
calculatedAt: calculatedAt, calculatedAt: calculatedAt,
depositAddress: depositAddress ?? this.depositAddress, depositAddress: depositAddress,
network: network ?? this.network, network: network,
tokenSymbol: tokenSymbol ?? this.tokenSymbol, tokenSymbol: tokenSymbol,
contractAddress: contractAddress ?? this.contractAddress, contractAddress: contractAddress,
describable: describable describable: describable ?? this.describable,
?? (name != null || description != null
? this.describable.copyWith(name: name, description: description)
: this.describable),
); );
} }

View File

@@ -1,5 +1,6 @@
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:pshared/controllers/wallets.dart';
import 'package:pshared/models/payment/currency_pair.dart'; import 'package:pshared/models/payment/currency_pair.dart';
import 'package:pshared/models/payment/customer.dart'; import 'package:pshared/models/payment/customer.dart';
import 'package:pshared/models/payment/fx/intent.dart'; import 'package:pshared/models/payment/fx/intent.dart';
@@ -13,7 +14,6 @@ import 'package:pshared/models/payment/intent.dart';
import 'package:pshared/models/recipient/recipient.dart'; import 'package:pshared/models/recipient/recipient.dart';
import 'package:pshared/provider/payment/amount.dart'; import 'package:pshared/provider/payment/amount.dart';
import 'package:pshared/provider/payment/flow.dart'; import 'package:pshared/provider/payment/flow.dart';
import 'package:pshared/provider/payment/wallets.dart';
import 'package:pshared/provider/recipient/provider.dart'; import 'package:pshared/provider/recipient/provider.dart';
import 'package:pshared/provider/recipient/pmethods.dart'; import 'package:pshared/provider/recipient/pmethods.dart';
import 'package:pshared/utils/currency.dart'; import 'package:pshared/utils/currency.dart';
@@ -22,7 +22,7 @@ import 'package:pshared/utils/currency.dart';
class QuotationIntentBuilder { class QuotationIntentBuilder {
PaymentIntent? build({ PaymentIntent? build({
required PaymentAmountProvider payment, required PaymentAmountProvider payment,
required WalletsProvider wallets, required WalletsController wallets,
required PaymentFlowProvider flow, required PaymentFlowProvider flow,
required RecipientsProvider recipients, required RecipientsProvider recipients,
required PaymentMethodsProvider methods, required PaymentMethodsProvider methods,

View File

@@ -1,11 +1,13 @@
import 'dart:convert';
import 'package:flutter/foundation.dart'; import 'package:flutter/foundation.dart';
import 'package:logging/logging.dart'; import 'package:logging/logging.dart';
import 'dart:convert';
import 'package:uuid/uuid.dart'; import 'package:uuid/uuid.dart';
import 'package:pshared/api/requests/payment/quote.dart'; import 'package:pshared/api/requests/payment/quote.dart';
import 'package:pshared/controllers/wallets.dart';
import 'package:pshared/data/mapper/payment/intent/payment.dart'; import 'package:pshared/data/mapper/payment/intent/payment.dart';
import 'package:pshared/models/asset.dart'; import 'package:pshared/models/asset.dart';
import 'package:pshared/models/payment/intent.dart'; import 'package:pshared/models/payment/intent.dart';
@@ -14,7 +16,6 @@ import 'package:pshared/models/money.dart';
import 'package:pshared/provider/organizations.dart'; import 'package:pshared/provider/organizations.dart';
import 'package:pshared/provider/payment/amount.dart'; import 'package:pshared/provider/payment/amount.dart';
import 'package:pshared/provider/payment/flow.dart'; import 'package:pshared/provider/payment/flow.dart';
import 'package:pshared/provider/payment/wallets.dart';
import 'package:pshared/provider/recipient/provider.dart'; import 'package:pshared/provider/recipient/provider.dart';
import 'package:pshared/provider/recipient/pmethods.dart'; import 'package:pshared/provider/recipient/pmethods.dart';
import 'package:pshared/provider/resource.dart'; import 'package:pshared/provider/resource.dart';
@@ -34,7 +35,7 @@ class QuotationProvider extends ChangeNotifier {
void update( void update(
OrganizationsProvider venue, OrganizationsProvider venue,
PaymentAmountProvider payment, PaymentAmountProvider payment,
WalletsProvider wallets, WalletsController wallets,
PaymentFlowProvider flow, PaymentFlowProvider flow,
RecipientsProvider recipients, RecipientsProvider recipients,
PaymentMethodsProvider methods, PaymentMethodsProvider methods,

View File

@@ -1,5 +1,9 @@
import 'dart:async';
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:pshared/models/payment/wallet.dart'; import 'package:pshared/models/payment/wallet.dart';
import 'package:pshared/provider/organizations.dart'; import 'package:pshared/provider/organizations.dart';
@@ -8,10 +12,9 @@ import 'package:pshared/service/payment/wallets.dart';
import 'package:pshared/utils/exception.dart'; import 'package:pshared/utils/exception.dart';
class WalletsProvider with ChangeNotifier { class WalletsProvider with ChangeNotifier {
final WalletsService _service; final WalletsService _service;
late OrganizationsProvider _organizations; OrganizationsProvider? _organizations;
WalletsProvider(this._service); WalletsProvider(this._service);
@@ -22,126 +25,204 @@ class WalletsProvider with ChangeNotifier {
bool get isLoading => _resource.isLoading; bool get isLoading => _resource.isLoading;
Exception? get error => _resource.error; Exception? get error => _resource.error;
Wallet? _selectedWallet;
Wallet? get selectedWallet => _selectedWallet;
final bool _isHidden = true;
bool get isHidden => _isHidden;
bool _isRefreshingBalances = false; bool _isRefreshingBalances = false;
bool get isRefreshingBalances => _isRefreshingBalances; bool get isRefreshingBalances => _isRefreshingBalances;
final Set<String> _refreshingWallets = <String>{}; final Set<String> _refreshingWallets = <String>{};
bool isWalletRefreshing(String walletId) => _refreshingWallets.contains(walletId); bool isWalletRefreshing(String walletId) => _refreshingWallets.contains(walletId);
// Expose current org id so UI controller can reset per-org state if needed.
String? get organizationId =>
(_organizations?.isOrganizationSet ?? false) ? _organizations!.current.id : null;
// Used to ignore stale async results (org changes / overlapping requests).
int _opSeq = 0;
// Per-wallet refresh sequence guard.
final Map<String, int> _walletSeq = <String, int>{};
// Keep modest concurrency to avoid hammering the backend.
static const int _balanceConcurrency = 6;
void update(OrganizationsProvider organizations) { void update(OrganizationsProvider organizations) {
_organizations = organizations; _organizations = organizations;
if (_organizations.isOrganizationSet) loadWalletsWithBalances(); if (organizations.isOrganizationSet) {
unawaited(loadWalletsWithBalances());
}
} }
Future<Wallet> updateWallet(Wallet newWallet) { Future<Wallet> updateWallet(Wallet newWallet) {
throw Exception('update wallet is not implemented'); throw Exception('update wallet is not implemented');
} }
void selectWallet(Wallet wallet) => _setSelectedWallet(wallet);
Future<void> loadWalletsWithBalances() async { Future<void> loadWalletsWithBalances() async {
_setResource(_resource.copyWith(isLoading: true, error: null)); final org = _organizations;
if (org == null || !org.isOrganizationSet) return;
final orgId = org.current.id;
final seq = ++_opSeq;
_isRefreshingBalances = false;
_refreshingWallets.clear();
_applyResource(_resource.copyWith(isLoading: true, error: null), notify: true);
try { try {
final base = await _service.getWallets(_organizations.current.id); final base = await _service.getWallets(orgId);
final withBalances = <Wallet>[];
for (final wallet in base) { final result = await _withBalances(orgId, base);
try { if (seq != _opSeq) return;
final balance = await _service.getBalance(_organizations.current.id, wallet.id);
withBalances.add(wallet.copyWith(balance: balance)); _applyResource(
Resource<List<Wallet>>(
data: result.wallets,
isLoading: false,
error: result.error,
),
notify: true,
);
} catch (e) { } catch (e) {
_setResource(_resource.copyWith(error: toException(e))); if (seq != _opSeq) return;
withBalances.add(wallet);
} _applyResource(
} _resource.copyWith(isLoading: false, error: toException(e)),
_setResource(Resource(data: withBalances, isLoading: false, error: _resource.error)); notify: true,
} catch (e) { );
_setResource(_resource.copyWith(isLoading: false, error: toException(e)));
} }
} }
Future<void> refreshBalances() async { Future<void> refreshBalances() async {
final org = _organizations;
if (org == null || !org.isOrganizationSet) return;
if (wallets.isEmpty) return; if (wallets.isEmpty) return;
final orgId = org.current.id;
final seq = ++_opSeq;
_isRefreshingBalances = true; _isRefreshingBalances = true;
_applyResource(_resource.copyWith(error: null), notify: false);
notifyListeners(); notifyListeners();
try { try {
final updated = <Wallet>[]; final result = await _withBalances(orgId, wallets);
for (final wallet in wallets) { if (seq != _opSeq) return;
final balance = await _service.getBalance(_organizations.current.id, wallet.id);
updated.add(wallet.copyWith(balance: balance)); _applyResource(
} _resource.copyWith(data: result.wallets, error: result.error),
_setResource(_resource.copyWith(data: updated)); notify: false,
);
} catch (e) { } catch (e) {
_setResource(_resource.copyWith(error: toException(e))); if (seq != _opSeq) return;
_applyResource(_resource.copyWith(error: toException(e)), notify: false);
} finally { } finally {
if (seq == _opSeq) {
_isRefreshingBalances = false; _isRefreshingBalances = false;
notifyListeners(); notifyListeners();
} }
} }
}
Future<void> refreshBalance(String walletId) async { Future<void> refreshBalance(String walletId) async {
final org = _organizations;
if (org == null || !org.isOrganizationSet) return;
if (_refreshingWallets.contains(walletId)) return; if (_refreshingWallets.contains(walletId)) return;
final wallet = wallets.firstWhereOrNull((w) => w.id == walletId);
if (wallet == null) return; final existing = wallets.firstWhereOrNull((w) => w.id == walletId);
if (existing == null) return;
final orgId = org.current.id;
final seq = (_walletSeq[walletId] ?? 0) + 1;
_walletSeq[walletId] = seq;
_refreshingWallets.add(walletId); _refreshingWallets.add(walletId);
notifyListeners(); notifyListeners();
try { try {
final balance = await _service.getBalance(_organizations.current.id, walletId); final balance = await _service.getBalance(orgId, walletId);
final updatedWallet = wallet.copyWith(balance: balance); if ((_walletSeq[walletId] ?? 0) != seq) return;
final next = List<Wallet>.from(wallets);
final idx = next.indexWhere((w) => w.id == walletId); final next = _replaceWallet(walletId, (w) => w.copyWith(balance: balance));
if (idx >= 0) { if (next == null) return;
next[idx] = updatedWallet;
_setResource(_resource.copyWith(data: next)); _applyResource(_resource.copyWith(data: next), notify: false);
}
} catch (e) { } catch (e) {
_setResource(_resource.copyWith(error: toException(e))); if ((_walletSeq[walletId] ?? 0) != seq) return;
_applyResource(_resource.copyWith(error: toException(e)), notify: false);
} finally { } finally {
if ((_walletSeq[walletId] ?? 0) == seq) {
_refreshingWallets.remove(walletId); _refreshingWallets.remove(walletId);
notifyListeners(); notifyListeners();
} }
} }
void toggleVisibility(String walletId) {
final index = wallets.indexWhere((w) => w.id == walletId);
if (index < 0) return;
final wallet = wallets[index];
final updated = wallet.copyWith(isHidden: !wallet.isHidden);
final next = List<Wallet>.from(wallets);
next[index] = updated;
_setResource(_resource.copyWith(data: next));
if (_selectedWallet?.id == walletId) {
_selectedWallet = updated;
}
} }
void _setResource(Resource<List<Wallet>> newResource) { // ---------- internals ----------
void _applyResource(Resource<List<Wallet>> newResource, {required bool notify}) {
_resource = newResource; _resource = newResource;
_selectedWallet = _resolveSelectedWallet(_selectedWallet, wallets); if (notify) notifyListeners();
notifyListeners();
} }
Wallet? _resolveSelectedWallet(Wallet? current, List<Wallet> available) { List<Wallet>? _replaceWallet(String walletId, Wallet Function(Wallet) updater) {
if (available.isEmpty) return null; final idx = wallets.indexWhere((w) => w.id == walletId);
final currentId = current?.id; if (idx < 0) return null;
if (currentId != null) {
final existing = available.firstWhereOrNull((wallet) => wallet.id == currentId); final next = List<Wallet>.from(wallets);
if (existing != null) return existing; next[idx] = updater(next[idx]);
} return next;
return available.firstWhereOrNull((wallet) => !wallet.isHidden) ?? available.first;
} }
void _setSelectedWallet(Wallet wallet) { Future<_WalletLoadResult> _withBalances(String orgId, List<Wallet> base) async {
if (_selectedWallet?.id == wallet.id && _selectedWallet?.isHidden == wallet.isHidden) { Exception? firstError;
return;
final withBalances = await _mapConcurrent<Wallet, Wallet>(
base,
_balanceConcurrency,
(wallet) async {
try {
final balance = await _service.getBalance(orgId, wallet.id);
return wallet.copyWith(balance: balance);
} catch (e) {
firstError ??= toException(e);
return wallet;
} }
_selectedWallet = wallet; },
notifyListeners(); );
return _WalletLoadResult(withBalances, firstError);
}
static Future<List<R>> _mapConcurrent<T, R>(
List<T> items,
int concurrency,
Future<R> Function(T) fn,
) async {
if (items.isEmpty) return <R>[];
final results = List<R?>.filled(items.length, null);
var nextIndex = 0;
Future<void> worker() async {
while (true) {
final i = nextIndex++;
if (i >= items.length) return;
results[i] = await fn(items[i]);
} }
} }
final workers = List.generate(min(concurrency, items.length), (_) => worker());
await Future.wait(workers);
return results.cast<R>();
}
}
class _WalletLoadResult {
final List<Wallet> wallets;
final Exception? error;
const _WalletLoadResult(this.wallets, this.error);
}

View File

@@ -4,6 +4,7 @@ import 'package:go_router/go_router.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pshared/controllers/wallets.dart';
import 'package:pshared/models/payment/type.dart'; import 'package:pshared/models/payment/type.dart';
import 'package:pshared/models/recipient/recipient.dart'; import 'package:pshared/models/recipient/recipient.dart';
import 'package:pshared/provider/organizations.dart'; import 'package:pshared/provider/organizations.dart';
@@ -28,7 +29,6 @@ import 'package:pweb/pages/payout_page/wallet/edit/page.dart';
import 'package:pweb/pages/report/page.dart'; import 'package:pweb/pages/report/page.dart';
import 'package:pweb/pages/settings/profile/page.dart'; import 'package:pweb/pages/settings/profile/page.dart';
import 'package:pweb/pages/wallet_top_up/page.dart'; import 'package:pweb/pages/wallet_top_up/page.dart';
import 'package:pshared/provider/payment/wallets.dart';
import 'package:pweb/widgets/error/snackbar.dart'; import 'package:pweb/widgets/error/snackbar.dart';
import 'package:pweb/widgets/sidebar/destinations.dart'; import 'package:pweb/widgets/sidebar/destinations.dart';
import 'package:pweb/widgets/sidebar/page.dart'; import 'package:pweb/widgets/sidebar/page.dart';
@@ -53,7 +53,7 @@ RouteBase payoutShellRoute() => ShellRoute(
ChangeNotifierProvider( ChangeNotifierProvider(
create: (_) => PaymentAmountProvider(), create: (_) => PaymentAmountProvider(),
), ),
ChangeNotifierProxyProvider6<OrganizationsProvider, PaymentAmountProvider, WalletsProvider, PaymentFlowProvider, RecipientsProvider, PaymentMethodsProvider, QuotationProvider>( ChangeNotifierProxyProvider6<OrganizationsProvider, PaymentAmountProvider, WalletsController, PaymentFlowProvider, RecipientsProvider, PaymentMethodsProvider, QuotationProvider>(
create: (_) => QuotationProvider(), create: (_) => QuotationProvider(),
update: (_, organization, payment, wallet, flow, recipients, methods, provider) => update: (_, organization, payment, wallet, flow, recipients, methods, provider) =>
provider!..update(organization, payment, wallet, flow, recipients, methods), provider!..update(organization, payment, wallet, flow, recipients, methods),
@@ -217,7 +217,7 @@ RouteBase payoutShellRoute() => ShellRoute(
name: PayoutRoutes.editWallet, name: PayoutRoutes.editWallet,
path: PayoutRoutes.editWalletPath, path: PayoutRoutes.editWalletPath,
pageBuilder: (context, state) { pageBuilder: (context, state) {
final walletsProvider = context.read<WalletsProvider>(); final walletsProvider = context.read<WalletsController>();
final wallet = walletsProvider.selectedWallet; final wallet = walletsProvider.selectedWallet;
final loc = AppLocalizations.of(context)!; final loc = AppLocalizations.of(context)!;
final fallbackDestination = PayoutRoutes.fallbackFromState( final fallbackDestination = PayoutRoutes.fallbackFromState(
@@ -279,7 +279,7 @@ void _openWalletEdit(
Wallet wallet, { Wallet wallet, {
required PayoutDestination returnTo, required PayoutDestination returnTo,
}) { }) {
context.read<WalletsProvider>().selectWallet(wallet); context.read<WalletsController>().selectWallet(wallet);
context.pushToEditWallet(returnTo: returnTo); context.pushToEditWallet(returnTo: returnTo);
} }
@@ -288,7 +288,7 @@ void _openWalletTopUp(
Wallet wallet, { Wallet wallet, {
required PayoutDestination returnTo, required PayoutDestination returnTo,
}) { }) {
context.read<WalletsProvider>().selectWallet(wallet); context.read<WalletsController>().selectWallet(wallet);
context.pushToWalletTopUp(returnTo: returnTo); context.pushToWalletTopUp(returnTo: returnTo);
} }

View File

@@ -20,6 +20,7 @@ import 'package:pshared/provider/invitations.dart';
import 'package:pshared/service/payment/wallets.dart'; import 'package:pshared/service/payment/wallets.dart';
import 'package:pweb/app/app.dart'; import 'package:pweb/app/app.dart';
import 'package:pshared/controllers/wallets.dart';
import 'package:pweb/pages/invitations/widgets/list/view_model.dart'; import 'package:pweb/pages/invitations/widgets/list/view_model.dart';
import 'package:pweb/app/timeago.dart'; import 'package:pweb/app/timeago.dart';
import 'package:pweb/providers/carousel.dart'; import 'package:pweb/providers/carousel.dart';
@@ -98,6 +99,10 @@ void main() async {
create: (_) => WalletsProvider(ApiWalletsService()), create: (_) => WalletsProvider(ApiWalletsService()),
update: (context, organizations, provider) => provider!..update(organizations), update: (context, organizations, provider) => provider!..update(organizations),
), ),
ChangeNotifierProxyProvider<WalletsProvider, WalletsController>(
create: (_) => WalletsController(),
update: (_, wallets, controller) => controller!..update(wallets),
),
ChangeNotifierProvider( ChangeNotifierProvider(
create: (_) => WalletTransactionsProvider(MockWalletTransactionsService())..load(), create: (_) => WalletTransactionsProvider(MockWalletTransactionsService())..load(),
), ),

View File

@@ -1,4 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:pshared/controllers/wallets.dart';
import 'package:pshared/utils/currency.dart'; import 'package:pshared/utils/currency.dart';
@@ -23,11 +25,13 @@ class BalanceAmount extends StatelessWidget {
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 currencyBalance = currencyCodeToSymbol(wallet.currency); final currencyBalance = currencyCodeToSymbol(wallet.currency);
final wallets = context.read<WalletsController>();
return Row( return Row(
children: [ children: [
Text( Text(
wallet.isHidden ? '•••• $currencyBalance' : '${amountToString(wallet.balance)} $currencyBalance',
wallets.isHidden(wallet.id) ? '•••• $currencyBalance' : '${amountToString(wallet.balance)} $currencyBalance',
style: textTheme.headlineSmall?.copyWith( style: textTheme.headlineSmall?.copyWith(
fontWeight: FontWeight.bold, fontWeight: FontWeight.bold,
color: colorScheme.onSurface, color: colorScheme.onSurface,
@@ -37,7 +41,7 @@ class BalanceAmount extends StatelessWidget {
GestureDetector( GestureDetector(
onTap: onToggleVisibility, onTap: onToggleVisibility,
child: Icon( child: Icon(
wallet.isHidden ? Icons.visibility_off : Icons.visibility, wallets.isHidden(wallet.id) ? Icons.visibility_off : Icons.visibility,
size: _iconSize, size: _iconSize,
color: colorScheme.onSurface, color: colorScheme.onSurface,
), ),

View File

@@ -2,9 +2,10 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pshared/controllers/wallets.dart';
import 'package:pshared/models/payment/wallet.dart'; import 'package:pshared/models/payment/wallet.dart';
import 'package:pweb/pages/dashboard/buttons/balance/carousel.dart'; import 'package:pweb/pages/dashboard/buttons/balance/carousel.dart';
import 'package:pshared/provider/payment/wallets.dart';
import 'package:pweb/generated/i18n/app_localizations.dart'; import 'package:pweb/generated/i18n/app_localizations.dart';
@@ -16,23 +17,22 @@ class BalanceWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final walletsProvider = context.watch<WalletsProvider>(); final walletsController = context.watch<WalletsController>();
final loc = AppLocalizations.of(context)!; final loc = AppLocalizations.of(context)!;
if (walletsProvider.isLoading) { if (walletsController.isLoading) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} }
final wallets = walletsProvider.wallets; final wallets = walletsController.wallets;
if (wallets.isEmpty) { if (wallets.isEmpty) {
return Center(child: Text(loc.noWalletsAvailable)); return Center(child: Text(loc.noWalletsAvailable));
} }
return return WalletCarousel(
WalletCarousel(
wallets: wallets, wallets: wallets,
onWalletChanged: walletsProvider.selectWallet, onWalletChanged: walletsController.selectWallet,
onTopUp: onTopUp, onTopUp: onTopUp,
); );
} }

View File

@@ -2,12 +2,13 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pshared/controllers/wallets.dart';
import 'package:pshared/models/payment/wallet.dart'; import 'package:pshared/models/payment/wallet.dart';
import 'package:pweb/pages/dashboard/buttons/balance/add_funds.dart'; import 'package:pweb/pages/dashboard/buttons/balance/add_funds.dart';
import 'package:pweb/pages/dashboard/buttons/balance/amount.dart'; import 'package:pweb/pages/dashboard/buttons/balance/amount.dart';
import 'package:pweb/pages/dashboard/buttons/balance/config.dart'; import 'package:pweb/pages/dashboard/buttons/balance/config.dart';
import 'package:pweb/pages/dashboard/buttons/balance/header.dart'; import 'package:pweb/pages/dashboard/buttons/balance/header.dart';
import 'package:pshared/provider/payment/wallets.dart';
import 'package:pweb/widgets/wallet_balance_refresh_button.dart'; import 'package:pweb/widgets/wallet_balance_refresh_button.dart';
@@ -43,7 +44,7 @@ class WalletCard extends StatelessWidget {
BalanceAmount( BalanceAmount(
wallet: wallet, wallet: wallet,
onToggleVisibility: () { onToggleVisibility: () {
context.read<WalletsProvider>().toggleVisibility(wallet.id); context.read<WalletsController>().toggleVisibility(wallet.id);
}, },
), ),
WalletBalanceRefreshButton( WalletBalanceRefreshButton(

View File

@@ -2,13 +2,13 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pshared/controllers/wallets.dart';
import 'package:pshared/utils/currency.dart'; import 'package:pshared/utils/currency.dart';
import 'package:pweb/pages/dashboard/payouts/summary/fee.dart'; import 'package:pweb/pages/dashboard/payouts/summary/fee.dart';
import 'package:pweb/pages/dashboard/payouts/summary/recipient_receives.dart'; import 'package:pweb/pages/dashboard/payouts/summary/recipient_receives.dart';
import 'package:pweb/pages/dashboard/payouts/summary/sent_amount.dart'; import 'package:pweb/pages/dashboard/payouts/summary/sent_amount.dart';
import 'package:pweb/pages/dashboard/payouts/summary/total.dart'; import 'package:pweb/pages/dashboard/payouts/summary/total.dart';
import 'package:pshared/provider/payment/wallets.dart';
class PaymentSummary extends StatelessWidget { class PaymentSummary extends StatelessWidget {
@@ -22,7 +22,7 @@ class PaymentSummary extends StatelessWidget {
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.stretch, crossAxisAlignment: CrossAxisAlignment.stretch,
children: [ children: [
PaymentSentAmountRow(currency: currencyStringToCode(context.read<WalletsProvider>().selectedWallet?.tokenSymbol ?? 'USDT')), PaymentSentAmountRow(currency: currencyStringToCode(context.read<WalletsController>().selectedWallet?.tokenSymbol ?? 'USDT')),
const PaymentFeeRow(), const PaymentFeeRow(),
const PaymentRecipientReceivesRow(), const PaymentRecipientReceivesRow(),
SizedBox(height: spacing), SizedBox(height: spacing),

View File

@@ -2,13 +2,13 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pshared/controllers/wallets.dart';
import 'package:pshared/models/payment/type.dart'; import 'package:pshared/models/payment/type.dart';
import 'package:pshared/models/recipient/recipient.dart'; import 'package:pshared/models/recipient/recipient.dart';
import 'package:pshared/provider/payment/flow.dart'; import 'package:pshared/provider/payment/flow.dart';
import 'package:pshared/provider/payment/provider.dart'; import 'package:pshared/provider/payment/provider.dart';
import 'package:pshared/provider/recipient/pmethods.dart'; import 'package:pshared/provider/recipient/pmethods.dart';
import 'package:pshared/provider/recipient/provider.dart'; import 'package:pshared/provider/recipient/provider.dart';
import 'package:pshared/provider/payment/wallets.dart';
import 'package:pweb/pages/payment_methods/payment_page/body.dart'; import 'package:pweb/pages/payment_methods/payment_page/body.dart';
import 'package:pweb/widgets/sidebar/destinations.dart'; import 'package:pweb/widgets/sidebar/destinations.dart';
@@ -108,7 +108,7 @@ class _PaymentPageState extends State<PaymentPage> {
recipient: recipient, recipient: recipient,
recipientProvider: recipientProvider, recipientProvider: recipientProvider,
methodsProvider: methodsProvider, methodsProvider: methodsProvider,
onWalletSelected: context.read<WalletsProvider>().selectWallet, onWalletSelected: context.read<WalletsController>().selectWallet,
searchController: _searchController, searchController: _searchController,
searchFocusNode: _searchFocusNode, searchFocusNode: _searchFocusNode,
onSearchChanged: _handleSearchChanged, onSearchChanged: _handleSearchChanged,

View File

@@ -2,9 +2,9 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pshared/controllers/wallets.dart';
import 'package:pshared/models/payment/wallet.dart'; import 'package:pshared/models/payment/wallet.dart';
import 'package:pshared/models/recipient/recipient.dart'; import 'package:pshared/models/recipient/recipient.dart';
import 'package:pshared/provider/payment/wallets.dart';
import 'package:pshared/provider/recipient/provider.dart'; import 'package:pshared/provider/recipient/provider.dart';
import 'package:pweb/pages/payment_methods/payment_page/back_button.dart'; import 'package:pweb/pages/payment_methods/payment_page/back_button.dart';
@@ -81,7 +81,7 @@ class PaymentPageContent extends StatelessWidget {
Row( Row(
children: [ children: [
Expanded(child: SectionTitle(loc.sourceOfFunds)), Expanded(child: SectionTitle(loc.sourceOfFunds)),
Consumer<WalletsProvider>( Consumer<WalletsController>(
builder: (context, provider, _) { builder: (context, provider, _) {
final selectedWalletId = provider.selectedWallet?.id; final selectedWalletId = provider.selectedWallet?.id;
if (selectedWalletId == null) { if (selectedWalletId == null) {

View File

@@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pshared/controllers/wallets.dart';
import 'package:pshared/models/payment/wallet.dart'; import 'package:pshared/models/payment/wallet.dart';
import 'package:pshared/provider/payment/wallets.dart';
import 'package:pweb/utils/payment/dropdown.dart'; import 'package:pweb/utils/payment/dropdown.dart';
@@ -17,7 +17,7 @@ class PaymentMethodSelector extends StatelessWidget {
}); });
@override @override
Widget build(BuildContext context) => Consumer<WalletsProvider>( Widget build(BuildContext context) => Consumer<WalletsController>(
builder: (context, provider, _) => PaymentMethodDropdown( builder: (context, provider, _) => PaymentMethodDropdown(
methods: provider.wallets, methods: provider.wallets,
selectedMethod: provider.selectedWallet, selectedMethod: provider.selectedWallet,

View File

@@ -2,11 +2,11 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pshared/controllers/wallets.dart';
import 'package:pshared/utils/currency.dart'; import 'package:pshared/utils/currency.dart';
import 'package:pshared/models/payment/wallet.dart'; import 'package:pshared/models/payment/wallet.dart';
import 'package:pshared/provider/payment/wallets.dart';
import 'package:pweb/models/visibility.dart';
import 'package:pweb/models/visibility.dart';
import 'package:pweb/pages/dashboard/buttons/balance/amount.dart'; import 'package:pweb/pages/dashboard/buttons/balance/amount.dart';
import 'package:pweb/widgets/wallet_balance_refresh_button.dart'; import 'package:pweb/widgets/wallet_balance_refresh_button.dart';
@@ -51,7 +51,7 @@ class WalletCard extends StatelessWidget {
BalanceAmount( BalanceAmount(
wallet: wallet, wallet: wallet,
onToggleVisibility: () { onToggleVisibility: () {
context.read<WalletsProvider>().toggleVisibility(wallet.id); context.read<WalletsController>().toggleVisibility(wallet.id);
}, },
), ),
WalletBalanceRefreshButton( WalletBalanceRefreshButton(

View File

@@ -2,8 +2,8 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pshared/controllers/wallets.dart';
import 'package:pshared/models/payment/type.dart'; import 'package:pshared/models/payment/type.dart';
import 'package:pshared/provider/payment/wallets.dart';
import 'package:pweb/app/router/payout_routes.dart'; import 'package:pweb/app/router/payout_routes.dart';
import 'package:pweb/widgets/sidebar/destinations.dart'; import 'package:pweb/widgets/sidebar/destinations.dart';
@@ -23,8 +23,8 @@ class SendPayoutButton extends StatelessWidget {
elevation: 0, elevation: 0,
), ),
onPressed: () { onPressed: () {
final walletsProvider = context.read<WalletsProvider>(); final wallets = context.read<WalletsController>();
final wallet = walletsProvider.selectedWallet; final wallet = wallets.selectedWallet;
if (wallet != null) { if (wallet != null) {
context.pushToPayment( context.pushToPayment(

View File

@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pshared/provider/payment/wallets.dart'; import 'package:pshared/controllers/wallets.dart';
import 'package:pweb/app/router/payout_routes.dart'; import 'package:pweb/app/router/payout_routes.dart';
import 'package:pweb/widgets/sidebar/destinations.dart'; import 'package:pweb/widgets/sidebar/destinations.dart';
@@ -22,7 +22,7 @@ class TopUpButton extends StatelessWidget{
elevation: 0, elevation: 0,
), ),
onPressed: () { onPressed: () {
final wallet = context.read<WalletsProvider>().selectedWallet; final wallet = context.read<WalletsController>().selectedWallet;
if (wallet == null) { if (wallet == null) {
ScaffoldMessenger.of(context).showSnackBar( ScaffoldMessenger.of(context).showSnackBar(
SnackBar(content: Text(loc.noWalletSelected)), SnackBar(content: Text(loc.noWalletSelected)),

View File

@@ -3,7 +3,7 @@ import 'package:flutter/services.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pshared/provider/payment/wallets.dart'; import 'package:pshared/controllers/wallets.dart';
import 'package:pweb/pages/dashboard/buttons/balance/amount.dart'; import 'package:pweb/pages/dashboard/buttons/balance/amount.dart';
import 'package:pweb/widgets/wallet_balance_refresh_button.dart'; import 'package:pweb/widgets/wallet_balance_refresh_button.dart';
@@ -14,9 +14,9 @@ class WalletEditFields extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Consumer<WalletsProvider>( return Consumer<WalletsController>(
builder: (context, provider, child) { builder: (context, controller, _) {
final wallet = provider.selectedWallet; final wallet = controller.selectedWallet;
if (wallet == null) { if (wallet == null) {
return SizedBox.shrink(); return SizedBox.shrink();
@@ -30,9 +30,7 @@ class WalletEditFields extends StatelessWidget {
Expanded( Expanded(
child: BalanceAmount( child: BalanceAmount(
wallet: wallet, wallet: wallet,
onToggleVisibility: () { onToggleVisibility: () => controller.toggleVisibility(wallet.id),
context.read<WalletsProvider>().toggleVisibility(wallet.id);
},
), ),
), ),
WalletBalanceRefreshButton(walletId: wallet.id), WalletBalanceRefreshButton(walletId: wallet.id),

View File

@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pshared/provider/payment/wallets.dart'; import 'package:pshared/controllers/wallets.dart';
import 'package:pweb/generated/i18n/app_localizations.dart'; import 'package:pweb/generated/i18n/app_localizations.dart';
@@ -12,8 +12,8 @@ class WalletEditHeader extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final provider = context.watch<WalletsProvider>(); final controller = context.watch<WalletsController>();
final wallet = provider.selectedWallet; final wallet = controller.selectedWallet;
final loc = AppLocalizations.of(context)!; final loc = AppLocalizations.of(context)!;
if (wallet == null) { if (wallet == null) {

View File

@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pshared/provider/payment/wallets.dart'; import 'package:pshared/controllers/wallets.dart';
import 'package:pweb/pages/payout_page/wallet/edit/buttons/buttons.dart'; import 'package:pweb/pages/payout_page/wallet/edit/buttons/buttons.dart';
import 'package:pweb/pages/payout_page/wallet/edit/fields.dart'; import 'package:pweb/pages/payout_page/wallet/edit/fields.dart';
@@ -23,9 +23,9 @@ class WalletEditPage extends StatelessWidget {
final dimensions = AppDimensions(); final dimensions = AppDimensions();
final loc = AppLocalizations.of(context)!; final loc = AppLocalizations.of(context)!;
return Consumer<WalletsProvider>( return Consumer<WalletsController>(
builder: (context, provider, child) { builder: (context, controller, child) {
final wallet = provider.selectedWallet; final wallet = controller.selectedWallet;
if (wallet == null) { if (wallet == null) {
return Center(child: Text(loc.noWalletSelected)); return Center(child: Text(loc.noWalletSelected));

View File

@@ -2,7 +2,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:pshared/provider/payment/wallets.dart'; import 'package:pshared/controllers/wallets.dart';
import 'package:pweb/pages/wallet_top_up/content.dart'; import 'package:pweb/pages/wallet_top_up/content.dart';
@@ -18,8 +18,7 @@ class WalletTopUpPage extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final loc = AppLocalizations.of(context)!; final loc = AppLocalizations.of(context)!;
return Consumer<WalletsProvider>( return Consumer<WalletsController>(builder: (context, provider, child) {
builder: (context, provider, child) {
if (provider.isLoading) { if (provider.isLoading) {
return const Center(child: CircularProgressIndicator()); return const Center(child: CircularProgressIndicator());
} }
@@ -39,7 +38,6 @@ class WalletTopUpPage extends StatelessWidget {
wallet: wallet, wallet: wallet,
onBack: onBack, onBack: onBack,
); );
}, });
);
} }
} }