Skip to content

Commit

Permalink
feat(EWM-264): account balances (#474)
Browse files Browse the repository at this point in the history
Co-authored-by: Egor Komarov <egor.komarov@bf.rocks>
  • Loading branch information
Odrin and Egor Komarov authored Sep 5, 2024
1 parent c2563c0 commit 07652f5
Show file tree
Hide file tree
Showing 10 changed files with 174 additions and 133 deletions.
Original file line number Diff line number Diff line change
@@ -1,56 +1,34 @@
import 'package:app/feature/browser/approvals_listener/actions/request_permissions/account_list_item/account_list_item_wm.dart';
import 'package:app/generated/generated.dart';
import 'package:elementary/elementary.dart';
import 'package:app/utils/utils.dart';
import 'package:elementary_helper/elementary_helper.dart';
import 'package:flutter/material.dart';
import 'package:lucide_icons_flutter/lucide_icons.dart';
import 'package:nekoton_repository/nekoton_repository.dart';
import 'package:ui_components_lib/ui_components_lib.dart';
import 'package:ui_components_lib/v2/ui_components_lib_v2.dart';

class AccountListItemWidget
extends ElementaryWidget<AccountListItemWidgetModel> {
const AccountListItemWidget({
class AccountListItem extends StatelessWidget {
const AccountListItem({
required this.account,
required this.onTap,
this.active = false,
Key? key,
WidgetModelFactory wmFactory = defaultAccountListItemWidgetModelFactory,
}) : super(wmFactory, key: key);

final KeyAccount account;
final bool active;
final VoidCallback onTap;

@override
Widget build(AccountListItemWidgetModel wm) => DoubleSourceBuilder(
firstSource: wm.balance,
secondSource: wm.active,
builder: (_, balance, active) => _AccountListItem(
name: account.name,
balance: balance,
active: active ?? false,
onTap: onTap,
),
);
}

class _AccountListItem extends StatelessWidget {
const _AccountListItem({
required this.name,
required this.balance,
required this.onTap,
required this.active,
super.key,
});

final String name;
final Money? balance;
final KeyAccount account;
final ListenableState<Money> balance;
final bool active;
final VoidCallback onTap;

@override
Widget build(BuildContext context) {
final theme = context.themeStyleV2;
final address = account.address.toEllipseString();
final pk = account.publicKey.toEllipseString();
final textStyle = theme.textStyles.labelXSmall.copyWith(
color: theme.colors.content3,
);

return GestureDetector(
onTap: onTap,
Expand All @@ -69,21 +47,36 @@ class _AccountListItem extends StatelessWidget {
child: SeparatedColumn(
separatorSize: DimensSizeV2.d2,
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
name,
account.name,
style: theme.textStyles.labelMedium,
overflow: TextOverflow.ellipsis,
softWrap: false,
maxLines: 1,
),
if (balance != null)
AmountWidget.fromMoney(
amount: balance!,
style: theme.textStyles.labelXSmall.copyWith(
color: theme.colors.content3,
Row(
children: [
Text('$address • $pk • ', style: textStyle),
StateNotifierBuilder(
listenableState: balance,
builder: (_, balance) =>
balance?.let(
(value) => Expanded(
child: AmountWidget.fromMoney(
amount: balance,
style: textStyle,
),
),
) ??
ProgressIndicatorWidget(
size: DimensSizeV2.d16,
color: theme.colors.content3,
),
),
),
],
),
],
),
),
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,51 @@ import 'package:nekoton_repository/nekoton_repository.dart';
class RequestPermissionsModel extends ElementaryModel {
RequestPermissionsModel(
ErrorHandler errorHandler,
this._currentAccountsService,
this._nekotonRepository,
this._permissionsService,
) : super(errorHandler: errorHandler);

final CurrentAccountsService _currentAccountsService;
final NekotonRepository _nekotonRepository;
final PermissionsService _permissionsService;

List<KeyAccount> get accounts =>
_currentAccountsService.currentAccounts?.allAccounts ?? [];
String get symbol => currentTransport.nativeTokenTicker;

List<KeyAccount> get accounts => _nekotonRepository.seedList.seeds
.expand(
(seed) => seed.allKeys.expand(
(key) => key.accountList.allAccounts,
),
)
.where((account) => !account.isHidden)
.toList();

TransportStrategy get currentTransport => _nekotonRepository.currentTransport;

Future<void> setPermissions(Uri origin, Permissions permissions) =>
_permissionsService.setPermissions(url: origin, permissions: permissions);

Future<Money?> getBalance(KeyAccount account) async {
final wallet = _nekotonRepository.walletsMap[account.address]?.wallet ??
await _getWallet(account);

return Money.fromBigIntWithCurrency(
wallet.contractState.balance,
Currencies()[currentTransport.nativeTokenTicker]!,
);
}

Future<TonWallet> _getWallet(KeyAccount account) async {
TonWallet? wallet;
try {
wallet = await TonWallet.subscribe(
transport: currentTransport.transport,
workchainId: account.workchain,
publicKey: account.publicKey,
walletType: account.account.tonWallet.contract,
);
} finally {
wallet?.dispose();
}
return wallet;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import 'package:app/data/models/models.dart';
import 'package:app/feature/browser/approvals_listener/actions/request_permissions/account_list_item/account_list_item.dart';
import 'package:app/feature/browser/approvals_listener/actions/request_permissions/account_list_item.dart';
import 'package:app/feature/browser/approvals_listener/actions/request_permissions/request_permissions_wm.dart';
import 'package:app/feature/browser/approvals_listener/actions/widgets/widgets.dart';
import 'package:app/feature/wallet/wallet.dart';
Expand Down Expand Up @@ -79,15 +79,15 @@ class _SelectAccountWidget extends StatelessWidget {
firstSource: wm.accounts,
secondSource: wm.selected,
builder: (_, accounts, selected) => ListView.separated(
shrinkWrap: true,
itemCount: accounts?.length ?? 0,
itemBuilder: (_, index) {
final account = accounts?[index];
return account == null
? const SizedBox.shrink()
: AccountListItemWidget(
: AccountListItem(
key: ValueKey(account.address),
account: account,
balance: wm.getBalanceEntity(account),
active: account.address == selected?.address,
onTap: () => wm.onSelectedChanged(account),
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import 'package:app/app/service/service.dart';
import 'package:app/core/error_handler_factory.dart';
import 'package:app/core/wm/custom_wm.dart';
import 'package:app/data/models/models.dart';
Expand Down Expand Up @@ -36,6 +37,12 @@ class RequestPermissionsWidgetModel extends CustomWidgetModel<
late final _selected = createNotifier(_initialSelectedAccount);
late final _accounts = createNotifier(model.accounts);
late final _permissions = createNotifier(widget.permissions.toSet());
late final _zeroBalance = Money.fromBigIntWithCurrency(
BigInt.zero,
Currencies()[model.symbol] ??
Currency.create(model.symbol, 0, pattern: moneyPattern(0)),
);
final _balances = <Address, ListenableState<Money>>{};

ValueListenable<RequestPermissionsStep> get step => _step;

Expand Down Expand Up @@ -117,4 +124,19 @@ class RequestPermissionsWidgetModel extends CustomWidgetModel<
model.setPermissions(origin, result);
Navigator.of(context).pop(result);
}

ListenableState<Money> getBalanceEntity(KeyAccount account) {
var entity = _balances[account.address];

if (entity == null) {
final notifier = createNotifier<Money>();
entity = _balances[account.address] = notifier;

model
.getBalance(account)
.then((value) => notifier.accept(value ?? _zeroBalance));
}

return entity;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,37 @@ class SelectAccountModel extends ElementaryModel {
(value) => value?.$2,
);

String get symbol => currentTransport.nativeTokenTicker;

TransportStrategy get currentTransport => _nekotonRepository.currentTransport;

Future<void> changeCurrentAccount(KeyAccount account) async {
await _currentKeyService.changeCurrentKey(account.publicKey);
_currentAccountsService.changeCurrentActiveAccount(account);
}

Future<Money?> getBalance(KeyAccount account) async {
final wallet = _nekotonRepository.walletsMap[account.address]?.wallet ??
await _getWallet(account);

return Money.fromBigIntWithCurrency(
wallet.contractState.balance,
Currencies()[currentTransport.nativeTokenTicker]!,
);
}

Future<TonWallet> _getWallet(KeyAccount account) async {
TonWallet? wallet;
try {
wallet = await TonWallet.subscribe(
transport: currentTransport.transport,
workchainId: account.workchain,
publicKey: account.publicKey,
walletType: account.account.tonWallet.contract,
);
} finally {
wallet?.dispose();
}
return wallet;
}
}
Loading

0 comments on commit 07652f5

Please sign in to comment.