Skip to content

Commit

Permalink
feat: add account & select assets (#467)
Browse files Browse the repository at this point in the history
* feat: select asset

* feat: add account flow

* fix: analyze

* fix: code review

---------

Co-authored-by: Egor Komarov <[email protected]>
  • Loading branch information
Odrin and Egor Komarov authored Sep 4, 2024
1 parent 3c188cd commit 5bf8f9a
Show file tree
Hide file tree
Showing 37 changed files with 1,311 additions and 253 deletions.
1 change: 1 addition & 0 deletions analysis_options.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@ include: package:broxus_flutter_analysis/analysis_options.yaml
analyzer:
exclude:
- lib/di/di.config.dart
- "**.reflectable.dart"
plugins:
- custom_lint
5 changes: 5 additions & 0 deletions assets/images/token_default_icon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
37 changes: 33 additions & 4 deletions assets/translations/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,10 @@
"manageAssets": "Manage assets",
"searchWord": "Search",
"customToken": "Custom token",
"enterAssetName": "Enter the asset name",
"saveWord": "Save",
"enterAssetName": "Enter asset name",
"saveChanges": "Save changes",
"selectNewAssets": "Select new assets",
"sorryNoAssetsFound": "Sorry, we didn't find anything for your request",
"sorryNoAssetsFound": "No results found for your request",
"rootTokenContract": "Root token contract",
"proceedWord": "Proceed",
"invalidRootTokenContract": "Invalid root token contract",
Expand Down Expand Up @@ -521,5 +521,34 @@
"viewInExplorer": "View in Explorer",
"hideAccount": "Hide account",
"advancedSettings": "Advanced settings",
"backToSettings": "Back to Settings"
"backToSettings": "Back to Settings",
"createNewAccount": "Create new account",
"addExternalAccount": "Add an external account",
"confirmAction": "Confirm action",
"enterYourPassword": "Enter your password",
"useFaceID": "Use Face ID",
"useFingerprint": "Use Fingerprint",
"accountName": "Account name",
"defaultWord": "Default",
"multisignatureWord": "Multisignature",
"forExperiencedUsers": "For experienced users",
"walletDescriptionSurfWallet": "Wallet contract used in Surf. Requires deployment.",
"walletDescriptionWalletV3": "Small legacy contract with one custodian. Deploys automatically.",
"walletDescriptionSafeMultisigWallet": "Multisig contract without upgradable code. Requires deployment.",
"walletDescriptionSafeMultisigWallet24h": "Multisig contract without upgradable code. Pending transactions lifetime extended to 24 hours. Requires deployment.",
"walletDescriptionSetcodeMultisigWallet": "Multisig contract with upgradable code. Requires deployment.",
"walletDescriptionSetcodeMultisigWallet24h": "Multisig contract with upgradable code. Pending transactions lifetime extended to 24 hours. Requires deployment.",
"walletDescriptionBridgeMultisigWallet": "Modified multisig. Requires deployment.",
"walletDescriptionHighloadWalletV2": "Small legacy contract with one custodian and advanced replay protection. Deploys automatically.",
"walletDescriptionMultisig2": "Multisig contract with upgradable code. Requires deployment.",
"walletDescriptionMultisig2_1": "For experienced users",
"walletDescriptionEverWallet": "Recommended",
"deprecatedTypes": "Deprecated types",
"deprecatedTypesHint": "We do not recommend using old contract types to create new accounts",
"newAccount": "New account",
"createAccountError": "Error occurred during creating account",
"accountAddedSheetTitle": "New account has been added successfully",
"accountAddedSheetSubtitle": "When adding a new account, a new public key was also added. They were connected with each other.",
"accountAddedSheetSwitch": "Switch to this account",
"accountAddedSheetContinue": "Continue without switching"
}
37 changes: 33 additions & 4 deletions assets/translations/ko.json
Original file line number Diff line number Diff line change
Expand Up @@ -252,10 +252,10 @@
"manageAssets": "Manage assets",
"searchWord": "Search",
"customToken": "Custom token",
"enterAssetName": "Enter the asset name",
"saveWord": "Save",
"enterAssetName": "Enter asset name",
"saveChanges": "Save changes",
"selectNewAssets": "Select new assets",
"sorryNoAssetsFound": "Sorry, we didn't find anything for your request",
"sorryNoAssetsFound": "No results found for your request",
"rootTokenContract": "Root token contract",
"proceedWord": "Proceed",
"invalidRootTokenContract": "Invalid root token contract",
Expand Down Expand Up @@ -521,5 +521,34 @@
"viewInExplorer": "View in Explorer",
"hideAccount": "Hide account",
"advancedSettings": "Advanced settings",
"backToSettings": "Back to Settings"
"backToSettings": "Back to Settings",
"createNewAccount": "Create new account",
"addExternalAccount": "Add an external account",
"confirmAction": "Confirm action",
"enterYourPassword": "Enter your password",
"useFaceID": "Use Face ID",
"useFingerprint": "Use Fingerprint",
"accountName": "Account name",
"defaultWord": "Default",
"multisignatureWord": "Multisignature",
"forExperiencedUsers": "For experienced users",
"walletDescriptionSurfWallet": "Wallet contract used in Surf. Requires deployment.",
"walletDescriptionWalletV3": "Small legacy contract with one custodian. Deploys automatically.",
"walletDescriptionSafeMultisigWallet": "Multisig contract without upgradable code. Requires deployment.",
"walletDescriptionSafeMultisigWallet24h": "Multisig contract without upgradable code. Pending transactions lifetime extended to 24 hours. Requires deployment.",
"walletDescriptionSetcodeMultisigWallet": "Multisig contract with upgradable code. Requires deployment.",
"walletDescriptionSetcodeMultisigWallet24h": "Multisig contract with upgradable code. Pending transactions lifetime extended to 24 hours. Requires deployment.",
"walletDescriptionBridgeMultisigWallet": "Modified multisig. Requires deployment.",
"walletDescriptionHighloadWalletV2": "Small legacy contract with one custodian and advanced replay protection. Deploys automatically.",
"walletDescriptionMultisig2": "Multisig contract with upgradable code. Requires deployment.",
"walletDescriptionMultisig2.1": "For experienced users",
"walletDescriptionEverWallet": "Recommended",
"deprecatedTypes": "Deprecated types",
"deprecatedTypesHint": "We do not recommend using old contract types to create new accounts",
"newAccount": "New account",
"createAccountError": "Error occurred during creating account",
"accountAddedSheetTitle": "New account has been added successfully",
"accountAddedSheetSubtitle": "When adding a new account, a new public key was also added. They were connected with each other.",
"accountAddedSheetSwitch": "Switch to this account",
"accountAddedSheetContinue": "Continue without switching"
}
4 changes: 4 additions & 0 deletions lib/app/router/app_route.dart
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,10 @@ enum AppRoute {
'',
'walletCancelUnstaking', // all data in query
),
walletAddAccount(
'',
'walletAddAccount', // all data in query
),

/// Browser section
browser(
Expand Down
13 changes: 13 additions & 0 deletions lib/app/router/routs/wallet/wallet.dart
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import 'package:app/data/models/models.dart';
import 'package:app/feature/add_seed/add_seed_enable_biometry/add_seed_enable_biometry.dart';
import 'package:app/feature/add_seed/add_seed_enable_biometry/view/add_seed_enable_biometry_page.dart';
import 'package:app/feature/network/network.dart';
import 'package:app/feature/wallet/add_account/add_account.dart';
import 'package:app/feature/wallet/wallet.dart';
import 'package:app/feature/wallet/widgets/account_asset_tab/select_new_asset/select_new_asset.dart';
import 'package:go_router/go_router.dart';
Expand Down Expand Up @@ -71,6 +72,9 @@ const walletCancelUnstakingStakingCurrencyCodeQueryParam =
const walletCancelUnstakingAttachedFeeQueryParam =
'walletCancelUnstakingStakingAttachedFee';

const walletCreatePublicKeyQueryParam = 'walletCreatePublicKey';
const walletCreatePasswordQueryParam = 'walletCreatePassword';

/// Branch that is root for wallet.
StatefulShellBranch get walletBranch {
return StatefulShellBranch(
Expand All @@ -92,6 +96,15 @@ StatefulShellBranch get walletBranch {
),
),
),
GoRoute(
path: AppRoute.walletAddAccount.path,
builder: (_, state) => AddAccountPage(
publicKey:
state.uri.queryParameters[walletCreatePublicKeyQueryParam]!,
password:
state.uri.queryParameters[walletCreatePasswordQueryParam]!,
),
),
addSeedNamedRoute,
tonWalletDetailsRoute,
tokenWalletDetailsRoute,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,14 @@ String getDefaultAccountName(WalletType walletType) => walletType.when(
case MultisigType.bridgeMultisigWallet:
return 'BridgeMultisig';
case MultisigType.surfWallet:
return 'Surf';
return 'Surf wallet';
case MultisigType.multisig2:
return 'Multisig2';
case MultisigType.multisig2_1:
return 'Multisig2.1';
}
},
everWallet: () => 'EVER Wallet',
walletV3: () => 'WalletV3',
walletV3: () => 'Wallet V3',
highloadWalletV2: () => 'HighloadWalletV2',
);
Original file line number Diff line number Diff line change
Expand Up @@ -168,15 +168,7 @@ class _ConfirmPermissionsWidget extends StatelessWidget {
style: theme.textStyles.labelSmall,
),
const Spacer(),
// TODO(Komarov): custom switch.
Switch(
activeColor: theme.colors.primaryA,
activeTrackColor: theme.colors.accent,
inactiveThumbColor: theme.colors.primaryA,
inactiveTrackColor:
theme.colors.backgroundAlpha,
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
value: basic ?? false,
onChanged: (value) => wm.onPermissionSwitch(
permission: Permission.basic,
Expand All @@ -192,15 +184,7 @@ class _ConfirmPermissionsWidget extends StatelessWidget {
style: theme.textStyles.labelSmall,
),
const Spacer(),
// TODO(Komarov): custom switch.
Switch(
activeColor: theme.colors.primaryA,
activeTrackColor: theme.colors.accent,
inactiveThumbColor: theme.colors.primaryA,
inactiveTrackColor:
theme.colors.backgroundAlpha,
materialTapTargetSize:
MaterialTapTargetSize.shrinkWrap,
value: accountInteraction ?? false,
onChanged: (value) => wm.onPermissionSwitch(
permission: Permission.accountInteraction,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
// ignore_for_file: no-magic-number

import 'package:app/data/models/models.dart';
import 'package:app/generated/generated.dart';

class BrowserCard {
BrowserCard({
Expand Down
2 changes: 1 addition & 1 deletion lib/feature/network/edit_network/edit_network_view.dart
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ class _EditNetworkViewState extends State<EditNetworkView> {
style: StyleRes.secondaryBold,
),
),
CommonSwitchInput(
Switch(
value: _isLocal,
onChanged: (value) => onLocalChanged(value: value),
),
Expand Down
5 changes: 5 additions & 0 deletions lib/feature/wallet/add_account/add_account.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export 'add_account_confirm/add_new_account_confirm_sheet.dart';
export 'add_account_page.dart';
export 'add_account_result/add_account_result_sheet.dart';
export 'add_account_type/add_account_type_widget.dart';
export 'add_new_account_sheet.dart';
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
import 'package:app/app/service/service.dart';
import 'package:app/generated/generated.dart';
import 'package:elementary/elementary.dart';
import 'package:local_auth/local_auth.dart';
import 'package:nekoton_repository/nekoton_repository.dart' hide Message;

class AddAccountConfirmModel extends ElementaryModel {
AddAccountConfirmModel(
ErrorHandler errorHandler,
this._biometryService,
this._messengerService,
this._nekotonRepository,
) : super(errorHandler: errorHandler);

final BiometryService _biometryService;
final MessengerService _messengerService;
final NekotonRepository _nekotonRepository;

Future<List<BiometricType>> getAvailableBiometry(PublicKey publicKey) async {
final isBiometryEnabled = _biometryService.enabled;
final hasKeyPassword = await _biometryService.hasKeyPassword(publicKey);

if (isBiometryEnabled && hasKeyPassword) {
return _biometryService.getAvailableBiometry();
}

return [];
}

Future<String?> requestBiometry(PublicKey publicKey) async {
try {
final password = await _biometryService.getKeyPassword(
publicKey: publicKey,
localizedReason: LocaleKeys.biometryAuthReason.tr(),
);

return password;
} catch (_) {
return null;
}
}

Future<bool> checkPassword({
required String password,
required PublicKey publicKey,
}) async {
if (password.isEmpty) return false;

final list = _nekotonRepository.seedList;

final correct = await list.checkKeyPassword(
publicKey: publicKey,
password: password,
signatureId:
await _nekotonRepository.currentTransport.transport.getSignatureId(),
);

if (_biometryService.enabled && correct) {
await _biometryService.setKeyPassword(
publicKey: publicKey,
password: password,
);
}

return correct;
}

void showWrongPassword() {
_messengerService.show(
Message.error(message: LocaleKeys.passwordIsWrong.tr()),
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import 'package:app/feature/wallet/add_account/add_account_confirm/add_account_confirm_wm.dart';
import 'package:app/generated/generated.dart';
import 'package:elementary/elementary.dart';
import 'package:elementary_helper/elementary_helper.dart';
import 'package:flutter/material.dart';
import 'package:local_auth/local_auth.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 AddAccountConfirmWidget
extends ElementaryWidget<AddAccountConfirmWidgetModel> {
const AddAccountConfirmWidget({
required this.publicKey,
Key? key,
WidgetModelFactory wmFactory = defaultAddAccountConfirmWidgetModelFactory,
}) : super(wmFactory, key: key);

final PublicKey publicKey;

@override
Widget build(AddAccountConfirmWidgetModel wm) {
return SeparatedColumn(
separatorSize: DimensSizeV2.d28,
mainAxisSize: MainAxisSize.min,
children: [
SecureTextField(
textEditingController: wm.controller,
hintText: LocaleKeys.enterYourPassword.tr(),
isAutofocus: true,
onSubmit: (_) => wm.onPasswordSubmit(),
),
Column(
mainAxisSize: MainAxisSize.min,
children: [
AccentButton(
buttonShape: ButtonShape.pill,
title: LocaleKeys.confirm.tr(),
onPressed: wm.onPasswordSubmit,
),
StateNotifierBuilder(
listenableState: wm.availableBiometry,
builder: (_, value) {
if (value?.contains(BiometricType.face) ?? false) {
return Padding(
padding: const EdgeInsets.only(top: DimensSizeV2.d8),
child: PrimaryButton(
buttonShape: ButtonShape.pill,
title: LocaleKeys.useFaceID.tr(),
icon: LucideIcons.scanFace,
onPressed: wm.onUseBiometry,
),
);
}

if (value?.contains(BiometricType.fingerprint) ?? false) {
return Padding(
padding: const EdgeInsets.only(top: DimensSizeV2.d8),
child: PrimaryButton(
buttonShape: ButtonShape.pill,
title: LocaleKeys.useFingerprint.tr(),
icon: LucideIcons.fingerprint,
onPressed: wm.onUseBiometry,
),
);
}

return const SizedBox.shrink();
},
),
],
),
],
);
}
}
Loading

0 comments on commit 5bf8f9a

Please sign in to comment.