CW-1513/CW-1610: Add account archival and UI improvements (#3600)

* add ability to hide accounts

* remove import

* merge

* merge

* fix loading accounts when styleSettings are not saved yet

* merge

* auto-reformat

* small fixes

* proper reload on card unhide

* block hiding last card

* fixup

* revert formatting-only changes

* liner fixes

* fix overflows

* card layout as separate class to prevent index errors

* fix mini card on addresses page

* block opening customizers if wallet is syncing

* switch to BlocProvider.value to prevent auto dispose

* imports

* fix fiat balance

* Improve homescreen layout and account access

* Add homescreen layout regression tests

* improve account management w/ education + archival flows

* reorganize wallet-specific settings

* preserve account archival during dismissal

* fix: align account visuals with design feedback

* minor account & archival visual corrections

* simplify wallet settings + account UI state

* generalise education carousel & dismissal tracking

* refactor account UI flows + minor improvements

* minor refactors and improvement

* pass account balances as Money and format at display

* use fresh full balance for account archival check

* refactor BalanceCard w/ MoneyText + cleanup

* minor card_customizer cleanup

* rework card customizer flow

---------

Co-authored-by: Robert Malikowski <malikowskirobert@gmail.com>
Co-authored-by: Omar Hatem <omarh.ismail1@gmail.com>
This commit is contained in:
Patrick
2026-10-10 02:07:41 +02:00
committed by GitHub
co-authored by Robert Malikowski Omar Hatem
parent 9f1f82fdd4
commit 20f1ceb651
108 changed files with 6632 additions and 1392 deletions
+3
View File
@@ -579,6 +579,9 @@ abstract class ElectrumWalletBase
@override
bool get hasSilentPaymentsScanning => type == WalletType.bitcoin && keys.privateKey.isNotEmpty;
@override
bool get hasCoinControl => true;
@override
bool get hasAccountsSupport =>
type == WalletType.bitcoin &&
+125
View File
@@ -0,0 +1,125 @@
import "package:cw_core/balance_card_style_settings.dart";
class BalanceCardLayout {
BalanceCardLayout._(
this._settings, {
required List<int> visible,
required List<int> hidden,
required this.needsRepair,
}) : visible = List<int>.unmodifiable(visible),
hidden = List<int>.unmodifiable(hidden);
factory BalanceCardLayout.resolve({
required List<int> accountIndices,
required List<BalanceCardStyleSettings> settings,
}) {
final List<int> accounts = [];
for (final accountIndex in accountIndices) {
if (!accounts.contains(accountIndex)) {
accounts.add(accountIndex);
}
}
final settingsByAccount = <int, BalanceCardStyleSettings>{};
for (final setting in settings) {
if (accounts.contains(setting.accountIndex)) {
settingsByAccount.putIfAbsent(setting.accountIndex, () => setting);
}
}
final hidden = [
for (final accountIndex in accounts)
if (settingsByAccount[accountIndex]?.hidden ?? false) accountIndex,
]..sort();
final visible = [
for (final accountIndex in accounts)
if (!hidden.contains(accountIndex)) accountIndex,
];
visible.sort((a, b) => _compareStackPosition(a, b, settingsByAccount));
var needsRepair = false;
for (var position = 0; position < visible.length; position++) {
final stored = settingsByAccount[visible[position]];
if (stored != null && stored.cardOrder != position) {
needsRepair = true;
}
}
return BalanceCardLayout._(
settingsByAccount,
visible: visible,
hidden: hidden,
needsRepair: needsRepair,
);
}
final Map<int, BalanceCardStyleSettings> _settings;
final List<int> visible;
final List<int> hidden;
// flag when db order is broken
final bool needsRepair;
List<int> get designOrder => designOrderOf(visible);
static List<int> stackFromOrder(Map<int, int> cardOrder, {bool forceSingleCard = false}) {
final positions = cardOrder.keys.toList()..sort();
final accountIndices = [for (final position in positions) cardOrder[position]!];
if (accountIndices.isEmpty || !forceSingleCard) {
return accountIndices;
}
return [accountIndices.first];
}
static List<int> designOrderOf(Iterable<int> accountIndices) =>
List<int>.of(accountIndices)..sort();
Map<int, int> get orders =>
{for (var position = 0; position < visible.length; position++) visible[position]: position};
BalanceCardStyleSettings? settingFor(int accountIndex) => _settings[accountIndex];
BalanceCardLayout unhiding(int accountIndex) {
if (!hidden.contains(accountIndex)) {
return this;
}
return BalanceCardLayout._(
_settings,
visible: [...visible, accountIndex],
hidden: [
for (final hiddenAccount in hidden)
if (hiddenAccount != accountIndex) hiddenAccount,
],
needsRepair: true,
);
}
static int _compareStackPosition(
int a,
int b,
Map<int, BalanceCardStyleSettings> settingsByAccount,
) {
final orderA = _storedOrder(settingsByAccount[a]);
final orderB = _storedOrder(settingsByAccount[b]);
if (orderA != orderB) {
if (orderA == null) {
return 1;
}
if (orderB == null) {
return -1;
}
return orderA.compareTo(orderB);
}
return a.compareTo(b);
}
static int? _storedOrder(BalanceCardStyleSettings? setting) =>
setting == null || setting.cardOrder < 0 ? null : setting.cardOrder;
}
@@ -7,6 +7,7 @@ class BalanceCardStyleSettings {
final int accountIndex;
final int gradientIndex;
final bool useSpecialDesign;
final bool hidden;
final String backgroundImagePath;
final int iconStyleIndex;
final bool isGradientOnly;
@@ -17,6 +18,7 @@ class BalanceCardStyleSettings {
required this.accountIndex,
required this.gradientIndex,
required this.useSpecialDesign,
required this.hidden,
required this.backgroundImagePath,
this.iconStyleIndex = 0,
this.isGradientOnly = false,
@@ -29,6 +31,7 @@ class BalanceCardStyleSettings {
"walletInfoId": walletInfoId,
"accountIndex": accountIndex,
"gradientIndex": gradientIndex,
"hidden": hidden ? 1 : 0,
"useSpecialDesign": useSpecialDesign ? 1 : 0,
"backgroundImagePath": backgroundImagePath,
"iconStyleIndex": iconStyleIndex,
@@ -42,6 +45,7 @@ class BalanceCardStyleSettings {
return BalanceCardStyleSettings(
walletInfoId: json["walletInfoId"] as int,
accountIndex: json["accountIndex"] as int,
hidden: json["hidden"] == 1,
gradientIndex: json["gradientIndex"] as int,
useSpecialDesign: json["useSpecialDesign"] == 1,
backgroundImagePath: json["backgroundImagePath"] as String? ?? "",
@@ -51,6 +55,30 @@ class BalanceCardStyleSettings {
);
}
BalanceCardStyleSettings copyWith({
int? walletInfoId,
int? accountIndex,
int? gradientIndex,
int? iconStyleIndex,
bool? isGradientOnly,
bool? useSpecialDesign,
bool? hidden,
String? backgroundImagePath,
int? cardOrder,
}) {
return BalanceCardStyleSettings(
walletInfoId: walletInfoId ?? this.walletInfoId,
accountIndex: accountIndex ?? this.accountIndex,
gradientIndex: gradientIndex ?? this.gradientIndex,
useSpecialDesign: useSpecialDesign ?? this.useSpecialDesign,
hidden: hidden ?? this.hidden,
backgroundImagePath: backgroundImagePath ?? this.backgroundImagePath,
cardOrder: cardOrder ?? this.cardOrder,
iconStyleIndex: iconStyleIndex ?? this.iconStyleIndex,
isGradientOnly: isGradientOnly ?? this.isGradientOnly
);
}
static BalanceCardStyleSettings fromCardDesign({
required int walletInfoId,
required int accountIndex,
@@ -58,6 +86,7 @@ class BalanceCardStyleSettings {
required CardDesign design,
int iconStyleIndex = 0,
int? gradientIndexOverride,
bool hidden = false
}) {
final int gradientIndex =
gradientIndexOverride ?? CardDesign.allGradients.indexOf(design.gradient);
@@ -66,6 +95,7 @@ class BalanceCardStyleSettings {
accountIndex: accountIndex,
gradientIndex: gradientIndex,
useSpecialDesign: design.backgroundType == CardDesignBackgroundTypes.svgFull,
hidden: hidden,
backgroundImagePath:
design.backgroundType == CardDesignBackgroundTypes.image ? design.imagePath : "",
iconStyleIndex: iconStyleIndex,
@@ -100,4 +130,56 @@ class BalanceCardStyleSettings {
Future<void> insert() async {
await db!.insert(tableName, toJson(), conflictAlgorithm: ConflictAlgorithm.replace);
}
static Future<void> setVisibleOrder(int walletInfoId, Map<int, int> orderByAccountIndex) =>
_setOrder(walletInfoId, orderByAccountIndex, unhide: true);
static Future<void> setOrder(int walletInfoId, Map<int, int> orderByAccountIndex) =>
_setOrder(walletInfoId, orderByAccountIndex, unhide: false);
static Future<void> _setOrder(
int walletInfoId,
Map<int, int> orderByAccountIndex, {
required bool unhide,
}) async {
if (orderByAccountIndex.isEmpty) {
return;
}
final entries = orderByAccountIndex.entries.toList();
final batch = db!.batch();
for (final entry in entries) {
batch.update(
tableName,
{"cardOrder": entry.value, if (unhide) "hidden": 0},
where: "walletInfoId = ? AND accountIndex = ?",
whereArgs: [walletInfoId, entry.key],
);
}
final updatedRowCounts = await batch.commit();
for (int i = 0; i < entries.length; i++) {
if (updatedRowCounts[i] == 0) {
await db!.insert(
tableName,
positionOnly(walletInfoId, entries[i].key, entries[i].value).toJson(),
conflictAlgorithm: ConflictAlgorithm.ignore,
);
}
}
}
static BalanceCardStyleSettings positionOnly(
int walletInfoId, int accountIndex, int cardOrder) =>
BalanceCardStyleSettings(
walletInfoId: walletInfoId,
accountIndex: accountIndex,
gradientIndex: -1,
useSpecialDesign: true,
hidden: false,
backgroundImagePath: "",
cardOrder: cardOrder,
);
}
+11 -2
View File
@@ -66,7 +66,7 @@ Future<void> _initDb({String? pathOverride}) async {
await db?.close();
db = await openDatabase(
dbFile.path,
version: 14,
version: 15,
onUpgrade: (db, oldVersion, newVersion) async {
printV("migrating: $oldVersion, $newVersion");
if (oldVersion <= 1) {
@@ -193,6 +193,14 @@ CREATE TABLE IF NOT EXISTS BalanceCardStyleSettings (
await _migrateBitcoinCardStylesForAccounts(db);
}
if(oldVersion <= 14) {
await _addColumnIfNotExists(
db,
table: "BalanceCardStyleSettings",
column: "hidden",
definition: "BOOLEAN DEFAULT FALSE",
);
}
},
onCreate: (Database db, int version) async {
await db.execute('''
@@ -286,6 +294,7 @@ CREATE TABLE BalanceCardStyleSettings (
iconStyleIndex INTEGER DEFAULT 0,
isGradientOnly BOOLEAN DEFAULT FALSE,
cardOrder INTEGER DEFAULT 0,
hidden BOOLEAN DEFAULT FALSE,
PRIMARY KEY (walletInfoId, accountIndex),
FOREIGN KEY (walletInfoId) REFERENCES WalletInfo(walletInfoId)
);
@@ -311,7 +320,7 @@ CREATE TABLE PriceData (
timestamp INTEGER NOT NULL,
price TEXT NOT NULL,
PRIMARY KEY (fromCurrency, toCurrency, timestamp)
);
);
""");
await db.execute("""
CREATE TABLE ChartsAssets (
+1
View File
@@ -142,6 +142,7 @@ abstract class WalletBase<BalanceType extends Balance, HistoryType extends Trans
bool get hasLightningSupport => false;
bool get hasSilentPaymentsScanning => false;
bool get hasCoinControl => false;
bool get hasAccountsSupport => false;
bool get hasNativeAccounts => false;
bool get canToggleMultiAccounts => hasAccountsSupport && !hasNativeAccounts;
+3
View File
@@ -543,6 +543,9 @@ abstract class DecredWalletBase
@override
bool get hasRescan => walletBirthdayBlockHeight() != -1;
@override
bool get hasCoinControl => true;
@override
Future<void> rescan({required int height}) async {
// The required height is not used. A birthday time is recorded in the
+3
View File
@@ -120,6 +120,9 @@ abstract class MoneroWalletBase
@override
bool get hasRescan => true;
@override
bool get hasCoinControl => true;
@override
bool get hasAccountsSupport => true;
+3
View File
@@ -137,6 +137,9 @@ abstract class WowneroWalletBase
@override
bool get hasRescan => true;
@override
bool get hasCoinControl => true;
@override
bool get hasAccountsSupport => true;
+31 -13
View File
@@ -295,7 +295,6 @@ import 'dogecoin/dogecoin.dart';
import 'new-ui/viewmodels/card_customizer/card_customizer_bloc.dart';
import 'new-ui/widgets/addresses_page/address_info.dart';
import 'src/screens/buy/buy_sell_page.dart';
import "src/screens/settings/widgets/account_creation_modal.dart";
final getIt = GetIt.instance;
@@ -561,14 +560,15 @@ Future<void> setup({
sharedPreferences: getIt.get<SharedPreferences>(),
keyService: getIt.get<KeyService>()));
getIt.registerFactoryParam<CardCustomizerBloc, bool, BitcoinAmountDisplayMode?>(
(lightningMode, displayMode) {
getIt.registerFactoryParam<CardCustomizerBloc, CardCustomizerBlocParams, void>(
(params, _) {
final wallet = getIt.get<AppStore>().wallet!;
return CardCustomizerBloc(wallet,
lightningMode: lightningMode,
canHide: params.canHide,
lightningMode: params.lightningMode,
displaySats: wallet.type == WalletType.bitcoin &&
(displayMode == BitcoinAmountDisplayMode.satoshi ||
(displayMode == BitcoinAmountDisplayMode.satoshiForLightning && lightningMode)));
(params.amountDisplayMode == BitcoinAmountDisplayMode.satoshi ||
(params.amountDisplayMode == BitcoinAmountDisplayMode.satoshiForLightning && params.lightningMode)));
});
getIt.registerLazySingleton<PriceStore>(() => PriceStore(settingsStore: getIt.get<SettingsStore>()));
@@ -896,7 +896,7 @@ Future<void> setup({
if (wallet.type == WalletType.monero ||
wallet.type == WalletType.wownero ||
wallet.type == WalletType.haven) {
return MoneroAccountListViewModel(wallet, getIt.get<SettingsStore>());
return MoneroAccountListViewModel(wallet);
}
throw Exception(
'Unexpected wallet type: ${wallet.type} for generate Monero AccountListViewModel');
@@ -905,7 +905,7 @@ Future<void> setup({
getIt.registerFactory<BitcoinAccountListViewModel>(() {
final wallet = getIt.get<AppStore>().wallet!;
if (wallet.type == WalletType.bitcoin) {
return BitcoinAccountListViewModel(wallet, getIt.get<SettingsStore>());
return BitcoinAccountListViewModel(wallet);
}
throw Exception(
'Unexpected wallet type: ${wallet.type} for generate Bitcoin AccountListViewModel');
@@ -927,11 +927,29 @@ Future<void> setup({
});
getIt.registerFactoryParam<MoneroAccountEditOrCreateViewModel, AccountListItem?, void>(
(AccountListItem? account, _) => MoneroAccountEditOrCreateViewModel(
monero!.getAccountList(getIt.get<AppStore>().wallet!),
wownero?.getAccountList(getIt.get<AppStore>().wallet!),
wallet: getIt.get<AppStore>().wallet!,
accountListItem: account));
(AccountListItem? account, _) {
final wallet = getIt.get<AppStore>().wallet!;
if (wallet.type == WalletType.monero) {
return MoneroAccountEditOrCreateViewModel(
monero!.getAccountList(wallet),
null,
wallet: wallet,
accountListItem: account,
);
}
if (wallet.type == WalletType.wownero) {
return MoneroAccountEditOrCreateViewModel(
null,
wownero!.getAccountList(wallet),
wallet: wallet,
accountListItem: account,
);
}
throw StateError("Account creation is unavailable for ${wallet.type}");
});
getIt.registerFactory<BitcoinAccountEditOrCreateViewModel>(
() => BitcoinAccountEditOrCreateViewModel(
+2
View File
@@ -3,6 +3,8 @@ import "package:cw_core/wallet_type.dart";
class PreferencesKey {
static const currentWalletType = 'current_wallet_type';
static const currentWalletName = 'current_wallet_name';
static const accountsHomePromoDismissed = 'accounts_home_promo_dismissed';
static String educationDismissed(String educationId) => "education_dismissed_$educationId";
static const currentNodeIdKey = 'current_node_id';
static const currentBitcoinElectrumSererIdKey = 'current_node_id_btc';
static const currentLitecoinElectrumSererIdKey = 'current_node_id_ltc';
+4
View File
@@ -146,6 +146,10 @@ class CWMonero extends Monero {
@override
MoneroAccountList getAccountList(Object wallet) => CWMoneroAccountList(wallet);
@override
Money getAccountFullBalance(int accountIndex) =>
monero_wallet_api.getFullBalance(accountIndex: accountIndex);
@override
MoneroSubaddressList getSubaddressList(Object wallet) => CWMoneroSubaddressList(wallet);
@@ -0,0 +1,128 @@
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/new-ui/pages/education_page.dart";
import "package:cake_wallet/src/widgets/cake_image_widget.dart";
import "package:flutter/material.dart";
class AccountEducationPage extends EducationPage {
const AccountEducationPage({required super.settingsStore, super.key});
@override
String get educationId => "accounts";
@override
String get title => S.current.accounts;
@override
String get iconPath => "assets/new-ui/settings_row_icons/accounts.svg";
@override
String get completionLabel => S.current.accounts_education_understand_continue;
@override
String progressLabel(int current, int total) =>
S.current.accounts_education_progress("$current", "$total");
@override
List<EducationSlide> get slides => <EducationSlide>[
EducationSlide(
distributeChildren: true,
children: [
EducationText(text: S.current.accounts_education_organize_title),
const CakeImageWidget(
imageUrl: "assets/new-ui/account_education/accounts_overview.svg",
key: ValueKey("accounts-education-overview-image"),
width: 133,
height: 324,
fit: BoxFit.contain,
),
EducationText(
text: S.current.accounts_education_organize_description,
secondary: true,
),
],
),
EducationSlide(
children: [
const CakeImageWidget(
imageUrl: "assets/new-ui/account_education/recovery_shield.svg",
key: ValueKey("accounts-education-recovery-image"),
width: 213,
height: 213,
fit: BoxFit.contain,
),
const SizedBox(height: 25.5),
EducationText(
text: S.current.accounts_education_recovery_title,
highlightedText: S.current.accounts_education_recovery_highlight,
),
const SizedBox(height: 25.5),
EducationText(
text: S.current.accounts_education_recovery_description,
secondary: true,
),
],
),
EducationSlide(
children: [
const CakeImageWidget(
imageUrl: "assets/new-ui/account_education/account_order.svg",
key: ValueKey("accounts-education-order-image"),
width: 309,
height: 48,
fit: BoxFit.contain,
),
const SizedBox(height: 51),
EducationText(text: S.current.accounts_education_order_title),
const SizedBox(height: 51),
const CakeImageWidget(
imageUrl: "assets/new-ui/account_education/ordered_account.svg",
key: ValueKey("accounts-education-ordered-account-image"),
width: 160,
height: 99,
fit: BoxFit.contain,
),
const SizedBox(height: 51),
Column(
mainAxisSize: MainAxisSize.min,
children: [
EducationText(
text: S.current.accounts_education_order_description,
highlightedText: S.current.accounts_education_order_highlight,
),
const SizedBox(height: 25.5),
EducationText(
text: S.current.accounts_education_order_restore_description,
secondary: true,
),
],
),
],
),
EducationSlide(
children: [
const CakeImageWidget(
imageUrl: "assets/new-ui/account_education/archive_warning.svg",
key: ValueKey("accounts-education-archive-image"),
width: 232,
height: 101,
fit: BoxFit.contain,
),
const SizedBox(height: 51),
Column(
mainAxisSize: MainAxisSize.min,
children: [
EducationText(
text: S.current.accounts_education_archive_title,
warning: true,
),
const SizedBox(height: 13),
EducationText(
text: S.current.accounts_education_archive_description,
secondary: true,
),
],
),
],
),
];
}
+19 -8
View File
@@ -2,7 +2,6 @@ import 'dart:ui';
import 'package:cake_wallet/di.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/new-ui/widgets/long_press_menu/long_press_popup.dart';
import 'package:cake_wallet/new-ui/widgets/addresses_page/address_info.dart';
import 'package:cake_wallet/new-ui/widgets/addresses_page/address_label_input.dart';
@@ -16,7 +15,6 @@ import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_item.dart';
import 'package:cake_wallet/view_model/wallet_address_list/wallet_address_list_view_model.dart';
import 'package:cake_wallet/wownero/wownero.dart';
import 'package:cw_core/card_design.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
@@ -69,6 +67,7 @@ class _NewAddressesPageState extends State<NewAddressesPage> {
late final TextEditingController _searchController;
CardDesign? design;
ReactionDisposer? _cardDesignsDisposer;
void updateItems() {
setState(() {
@@ -86,20 +85,32 @@ class _NewAddressesPageState extends State<NewAddressesPage> {
setState(() {});
});
loadCardDesign();
WidgetsBinding.instance.addPostFrameCallback((_) {
reaction((_) {
final index = widget.dashboardViewModel.accountListViewModel?.selectedAccount?.id ?? 0;
final designs = widget.dashboardViewModel.cardDesigns;
return (index >= 0 && index < designs.length) ? designs[index] : null;
}, (value) {
if (!mounted) return;
_cardDesignsDisposer = reaction((_) => widget.dashboardViewModel.currentCardDesign, (value) {
if (!mounted) return;
setState(() {
design = value;
design = widget.dashboardViewModel.currentCardDesign;
});
});
});
}
Future<void> loadCardDesign() async {
await widget.dashboardViewModel.loadCardDesigns();
if (!mounted) return;
setState(() {
design = widget.dashboardViewModel.currentCardDesign;
});
}
@override
void dispose() {
_cardDesignsDisposer?.call();
super.dispose();
}
@override
Widget build(BuildContext context) {
final filteredItems = items.where((item) {
+407 -292
View File
@@ -1,75 +1,96 @@
import "dart:async";
import "dart:math";
import "package:cake_wallet/di.dart";
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/new-ui/modal_navigator.dart";
import "package:modal_bottom_sheet/modal_bottom_sheet.dart";
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/new-ui/viewmodels/card_customizer/card_customizer_bloc.dart";
import "package:cake_wallet/new-ui/widgets/account_confirmation_content.dart";
import "package:cake_wallet/new-ui/widgets/coins_page/cards/balance_card.dart";
import "package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart";
import "package:cake_wallet/src/widgets/alert_with_two_actions.dart";
import "package:cake_wallet/src/widgets/base_alert_dialog.dart";
import "package:cake_wallet/src/widgets/cake_image_widget.dart";
import "package:cake_wallet/src/widgets/new_list_row/list_Item_style_wrapper.dart";
import "package:cake_wallet/utils/show_pop_up.dart";
import "package:cake_wallet/view_model/dashboard/dashboard_view_model.dart";
import "package:cake_wallet/view_model/wallet_account_list/account_list_item.dart";
import "package:cw_core/card_design.dart";
import "package:flutter/cupertino.dart";
import "package:flutter/material.dart";
import "package:flutter_bloc/flutter_bloc.dart";
import "package:modal_bottom_sheet/modal_bottom_sheet.dart";
class CardCustomizer extends StatefulWidget {
const CardCustomizer({required this.cryptoTitle, required this.cryptoName, super.key});
const CardCustomizer({
required this.cryptoTitle,
required this.cryptoName,
this.account,
this.fiatBalance,
super.key,
});
final String cryptoTitle;
final String cryptoName;
final AccountListItem? account;
final String? fiatBalance;
static Future<void> show({
static Future<bool> show({
required BuildContext context,
required DashboardViewModel dashboardViewModel,
required bool lightningMode,
bool asModalSheet = true,
VoidCallback? onSaved,
required AccountListItem? account,
bool lightningMode = false,
bool canHide = false,
bool asPage = false,
}) async {
final bloc = getIt.get<CardCustomizerBloc>(
param1: lightningMode,
param2: dashboardViewModel.settingsStore.displayAmountsInSatoshi,
param1: CardCustomizerBlocParams(
lightningMode: lightningMode,
amountDisplayMode: dashboardViewModel.settingsStore.displayAmountsInSatoshi,
canHide: canHide,
),
);
final customizer = BlocProvider(
create: (_) => bloc,
if (bloc.state is CardCustomizerNotLoaded) {
await bloc.stream.firstWhere((state) => state is! CardCustomizerNotLoaded);
}
if (!context.mounted) {
await bloc.close();
return false;
}
final balanceViewModel = dashboardViewModel.balanceViewModel;
final customizer = BlocProvider.value(
value: bloc,
child: Material(
child: CardCustomizer(
cryptoTitle: dashboardViewModel.wallet.currency.fullName ??
dashboardViewModel.wallet.currency.name,
cryptoName: dashboardViewModel.wallet.currency.name,
account: account,
fiatBalance: account == null ? null : balanceViewModel.accountFiatBalance(account),
),
),
);
if (asModalSheet) {
await CupertinoScaffold.showCupertinoModalBottomSheet(
barrierColor: Colors.black.withAlpha(60),
context: context,
builder: (context) => ModalNavigator(
parentContext: context,
heightMode: ModalHeightModes.fullScreen,
rootPage: customizer,
),
);
} else {
await Navigator.of(context).push(
MaterialPageRoute<void>(builder: (_) => customizer),
);
}
final archived = await (asPage
? Navigator.of(context).push<bool>(CupertinoPageRoute(builder: (_) => customizer))
: CupertinoScaffold.showCupertinoModalBottomSheet<bool>(
barrierColor: Colors.black.withAlpha(60),
context: context,
builder: (context) => ModalNavigator(
parentContext: context,
heightMode: ModalHeightModes.fullScreen,
rootPage: customizer,
),
));
// Save edits before AccountHidden writes the hidden state.
bloc.add(DesignSaved());
await bloc.stream.firstWhere(
(state) => state is CardCustomizerSaved,
orElse: () => bloc.state,
);
await dashboardViewModel.loadCardDesigns();
await dashboardViewModel.accountListViewModel?.reload();
onSaved?.call();
await bloc.stream.firstWhere((state) => state is CardCustomizerSaved);
if (archived == true) {
bloc.add(AccountHidden());
await bloc.stream.firstWhere((state) => state is CardCustomizerSaved);
}
await bloc.close();
return archived == true;
}
@override
@@ -78,9 +99,10 @@ class CardCustomizer extends StatefulWidget {
class _CardCustomizerState extends State<CardCustomizer> {
final accountNameController = TextEditingController();
bool editEnabled = false;
late final CardCustomizerBloc bloc;
bool get _isAccount => widget.account != null;
@override
void initState() {
super.initState();
@@ -88,18 +110,7 @@ class _CardCustomizerState extends State<CardCustomizer> {
bloc = context.read<CardCustomizerBloc>();
if (bloc.state is! CardCustomizerNotLoaded) {
editEnabled = bloc.state.accountName.isNotEmpty;
accountNameController.text = bloc.state.accountName;
} else {
late final StreamSubscription sub;
sub = bloc.stream.listen((state) {
if (state is! CardCustomizerNotLoaded) {
setState(() {
editEnabled = state.accountName.isNotEmpty;
});
sub.cancel();
}
});
}
}
@@ -118,6 +129,46 @@ class _CardCustomizerState extends State<CardCustomizer> {
return design;
}
Future<void> _requestArchive() async {
final account = AccountListItem(
id: widget.account!.id,
label: bloc.state.accountName,
balance: widget.account!.balance,
);
final isFunded = account.isFunded;
final confirmed = await showPopUp<bool>(
context: context,
barrierDismissible: false,
builder: (dialogContext) => AlertWithTwoActions(
alertTitle: isFunded
? S.of(dialogContext).archive_account_confirmation_title
: S.of(dialogContext).archive_account_title,
alertContent: "",
alertContentTextWidget: ArchiveConfirmationContent(
account: account,
fiatBalance: widget.fiatBalance,
isFunded: isFunded,
),
leftButtonText: S.of(dialogContext).cancel,
rightButtonText: S.of(dialogContext).continue_text,
leftAlertButtonStyle: AlertButtonStyle.primary(dialogContext),
rightAlertButtonStyle: AlertButtonStyle.secondary(dialogContext),
actionLeftButton: () => Navigator.of(dialogContext).pop(false),
actionRightButton: () => Navigator.of(dialogContext).pop(true),
),
);
if (confirmed != true || !mounted) {
return;
}
Navigator.of(context).pop(true);
}
@override
void dispose() {
accountNameController.dispose();
super.dispose();
}
@override
Widget build(BuildContext context) => BlocListener<CardCustomizerBloc, CardCustomizerState>(
listenWhen: (previous, current) => previous.accountName != current.accountName,
@@ -128,288 +179,352 @@ class _CardCustomizerState extends State<CardCustomizer> {
},
child: BlocBuilder<CardCustomizerBloc, CardCustomizerState>(
builder: (context, state) {
if (state is CardCustomizerNotLoaded) return SizedBox.shrink();
if (state is CardCustomizerNotLoaded) {
return const SizedBox.shrink();
}
return PopScope(
child: SingleChildScrollView(
child: SafeArea(
child: Column(
spacing: 25.0,
spacing: 25,
mainAxisSize: MainAxisSize.min,
children: [
ModalTopBar(
title: editEnabled ? S.of(context).edit_account : S.of(context).edit_card,
leadingIcon: Icon(Icons.close),
leadingSemanticLabel: S.of(context).close,
// trailingIcon: editEnabled ? Icon(Icons.delete_forever) : null,
title: _isAccount ? S.of(context).edit_account : S.of(context).edit_card,
subtitle: _isAccount ? "#${widget.account!.id + 1}" : null,
leadingIcon:
Icon(_isAccount ? Icons.arrow_back_ios_new : Icons.close, size: 18),
leadingSemanticLabel:
_isAccount ? S.of(context).seed_alert_back : S.of(context).close,
onLeadingPressed: () => Navigator.of(context).maybePop(),
// onTrailingPressed: () {},
),
if (editEnabled)
BalanceCard(
width: min(MediaQuery.of(context).size.width * 0.87, 768),
selected: true,
designSwitchDuration: const Duration(milliseconds: 300),
accountIndex: _isAccount ? widget.account!.id + 1 : null,
accountName: !_isAccount
? ""
: state.accountName.trim().isEmpty
? S.of(context).unnamed_account
: state.accountName,
accountBalance: widget.account?.balance,
balance: _isAccount ? "" : "0.00",
fiatBalance: widget.fiatBalance ?? "",
assetName: state.displaySats ? "sats" : widget.cryptoName,
capitalizeAssetName: !state.displaySats,
design: state.selectedDesign,
),
if (_isAccount)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 18.0),
padding: const EdgeInsets.symmetric(horizontal: 18),
child: Column(
spacing: 8.0,
spacing: 8,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(S.of(context).account_name),
TextField(
maxLength: 32,
decoration: InputDecoration(counterText: ""),
decoration: const InputDecoration(counterText: ""),
onChanged: (value) {
context.read<CardCustomizerBloc>().add(AccountNameChanged(value));
},
controller: accountNameController,
)
),
],
),
),
BalanceCard(
width: min(MediaQuery.of(context).size.width * 0.87, 768),
selected: true,
designSwitchDuration: Duration(milliseconds: 300),
accountName: editEnabled ? state.accountName : "",
balance: "0.00",
assetName: state.displaySats ? "sats" : widget.cryptoName,
capitalizeAssetName: !state.displaySats,
design: state.selectedDesign,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 18.0),
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(12.0),
child: Column(
spacing: 8.0,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(S.of(context).card_style),
SizedBox(
height: 63,
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: state.availableDesigns.length,
separatorBuilder: (context, index) =>
const SizedBox(width: 8),
itemBuilder: (context, index) => GestureDetector(
onTap: () {
context
.read<CardCustomizerBloc>()
.add(CardDesignSelected(index));
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
decoration: ShapeDecoration(
shape: RoundedSuperellipseBorder(
side: BorderSide(
color: ((index ==
state.selectedDesignIndex)
padding: const EdgeInsets.symmetric(horizontal: 18),
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(16),
),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Padding(
padding: const EdgeInsets.all(12),
child: Column(
spacing: 8,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(S.of(context).card_style),
SizedBox(
height: 63,
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: state.availableDesigns.length,
separatorBuilder: (context, index) =>
const SizedBox(width: 8),
itemBuilder: (context, index) => GestureDetector(
onTap: () {
context
.read<CardCustomizerBloc>()
.add(CardDesignSelected(index));
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 300),
decoration: ShapeDecoration(
shape: RoundedSuperellipseBorder(
side: BorderSide(
color: ((index == state.selectedDesignIndex)
? Theme.of(context).colorScheme.onSurface
: Colors.transparent),
width: 1,
),
borderRadius: BorderRadiusGeometry.circular(12),
),
),
child: AnimatedScale(
duration: const Duration(milliseconds: 200),
scale: index == state.selectedDesignIndex ? 0.94 : 1,
child: BalanceCard(
width: 96,
borderRadius: 10,
selected: false,
designSwitchDuration:
const Duration(milliseconds: 300),
design: _cardStylePreviewDesign(state, index),
),
),
),
),
),
),
],
),
),
AnimatedSwitcher(
duration: const Duration(milliseconds: 350),
switchInCurve: Curves.easeOut,
switchOutCurve: Curves.easeIn,
transitionBuilder: (child, animation) => FadeTransition(
opacity: animation,
child: SizeTransition(
sizeFactor: animation,
axisAlignment: -1,
child: child,
),
),
child: _showIconStylePanel(state)
? Column(
key: const ValueKey("icon_style_panel"),
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 8),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Column(
spacing: 8,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(S.of(context).icon_style),
SizedBox(
height: 48,
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: state.availableIconPaths.length,
separatorBuilder: (context, _) =>
const SizedBox(width: 8),
itemBuilder: (context, index) {
final icon = state.availableIconPaths[index];
final isSelected =
index == state.selectedIconIndex;
return GestureDetector(
onTap: () {
context
.read<CardCustomizerBloc>()
.add(IconStyleSelected(index));
},
child: AnimatedContainer(
duration:
const Duration(milliseconds: 200),
width: 48,
height: 48,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(18),
color: Theme.of(context).brightness ==
Brightness.light
? Theme.of(context)
.colorScheme
.onSurfaceVariant
.withAlpha(64)
: Theme.of(context)
.colorScheme
.surfaceContainerHigh,
border: Border.all(
color: isSelected
? Theme.of(context)
.colorScheme
.onSurface
: Colors.transparent),
width: 1),
borderRadius:
BorderRadiusGeometry.circular(12),
),
),
child: AnimatedScale(
duration: const Duration(milliseconds: 200),
scale: index == state.selectedDesignIndex
? 0.94
: 1,
child: BalanceCard(
width: 96,
borderRadius: 10,
selected: false,
designSwitchDuration:
const Duration(milliseconds: 300),
design:
_cardStylePreviewDesign(state, index),
),
),
),
)),
),
],
)),
AnimatedSwitcher(
duration: const Duration(milliseconds: 350),
switchInCurve: Curves.easeOut,
switchOutCurve: Curves.easeIn,
transitionBuilder: (child, Animation<double> animation) =>
FadeTransition(
opacity: animation,
child: SizeTransition(
sizeFactor: animation,
axisAlignment: -1,
child: child,
),
),
child: _showIconStylePanel(state)
? Column(
key: const ValueKey("icon_style_panel"),
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 8),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 12.0),
child: Column(
spacing: 8.0,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(S.of(context).icon_style),
SizedBox(
height: 48,
child: ListView.separated(
scrollDirection: Axis.horizontal,
itemCount: state.availableIconPaths.length,
separatorBuilder: (context, _) =>
const SizedBox(width: 8.0),
itemBuilder: (context, index) {
final icon =
state.availableIconPaths[index];
final isSelected =
index == state.selectedIconIndex;
return GestureDetector(
onTap: () {
context
.read<CardCustomizerBloc>()
.add(IconStyleSelected(index));
},
child: AnimatedContainer(
duration:
const Duration(milliseconds: 200),
width: 48,
height: 48,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(18),
color: Theme.of(context).brightness ==
Brightness.light
? Theme.of(context)
.colorScheme
.onSurfaceVariant
.withAlpha(64)
: Theme.of(context)
.colorScheme
.surfaceContainerHigh,
border: Border.all(
color: isSelected
? Theme.of(context)
.colorScheme
.onSurface
: Colors.transparent,
width: 2,
),
),
child: Padding(
padding: const EdgeInsets.all(10.0),
child: CakeImageWidget(
imageUrl: icon.path),
: Colors.transparent,
width: 2,
),
),
);
},
),
child: Padding(
padding: const EdgeInsets.all(10),
child: CakeImageWidget(
imageUrl: icon.path,
),
),
),
);
},
),
],
),
],
),
),
],
)
: const SizedBox.shrink(key: ValueKey("icon_style_hidden")),
),
const SizedBox(height: 8),
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHigh,
borderRadius: BorderRadius.circular(16),
),
child: Padding(
padding: const EdgeInsets.all(12),
child: Column(
spacing: 8,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(S.of(context).color),
SizedBox(
width: double.infinity,
child: Wrap(
direction: Axis.horizontal,
spacing: 4,
runSpacing: 8,
children: List.generate(
state.availableColors.length,
(index) => Material(
borderRadius: BorderRadius.circular(999999999),
child: InkWell(
borderRadius: BorderRadius.circular(999999999),
onTap: () {
context
.read<CardCustomizerBloc>()
.add(ColorSelected(index));
},
child: Stack(
children: [
AnimatedOpacity(
duration: const Duration(milliseconds: 200),
opacity:
index == state.selectedColorIndex ? 1 : 0,
child: Container(
width: 32,
height: 32,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(99999999),
border: Border.all(
color: Theme.of(context)
.colorScheme
.onSurface,
),
),
),
),
AnimatedScale(
duration: const Duration(milliseconds: 200),
scale: index == state.selectedColorIndex
? 0.8
: 1,
child: Container(
width: 32,
height: 32,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(99999999),
gradient: state.availableColors[index],
),
),
),
],
),
),
),
],
)
: const SizedBox.shrink(key: ValueKey("icon_style_hidden")),
),
),
),
],
),
),
const SizedBox(height: 8),
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHigh,
borderRadius: BorderRadius.circular(16)),
child: Padding(
padding: const EdgeInsets.all(12.0),
),
],
),
),
),
if (bloc.canHide)
Padding(
padding: const EdgeInsets.fromLTRB(18, 0, 18, 24),
child: ListItemStyleWrapper(
isFirstInSection: true,
isLastInSection: true,
onTap: _requestArchive,
builder: (context, textStyle, labelStyle) => ConstrainedBox(
constraints: const BoxConstraints(minHeight: 40),
child: Row(
children: [
Padding(
padding: const EdgeInsets.all(2.5),
child: CakeImageWidget(
imageUrl: "assets/new-ui/archived.svg",
width: 19,
height: 19,
color: Theme.of(context).colorScheme.primary,
),
),
const SizedBox(width: 12),
Expanded(
child: Column(
spacing: 8.0,
crossAxisAlignment: CrossAxisAlignment.start,
spacing: 4,
children: [
Text(S.of(context).color),
Container(
width: double.infinity,
child: Wrap(
direction: Axis.horizontal,
spacing: 4, // space between items in a row
runSpacing: 8,
children: List.generate(
state.availableColors.length,
(index) => Material(
borderRadius:
BorderRadius.circular(999999999),
child: InkWell(
borderRadius:
BorderRadius.circular(999999999),
onTap: () {
context
.read<CardCustomizerBloc>()
.add(ColorSelected(index));
},
child: Stack(
children: [
AnimatedOpacity(
duration: const Duration(
milliseconds: 200),
opacity: index ==
state.selectedColorIndex
? 1
: 0,
child: Container(
width: 32,
height: 32,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(
99999999),
border: Border.all(
color: Theme.of(context)
.colorScheme
.onSurface))),
),
AnimatedScale(
duration: const Duration(
milliseconds: 200),
scale: index ==
state.selectedColorIndex
? 0.8
: 1,
child: Container(
width: 32,
height: 32,
decoration: BoxDecoration(
borderRadius:
BorderRadius.circular(
99999999,
),
gradient: state
.availableColors[index]),
),
),
],
),
),
)),
)),
Text(
S.of(context).archive_account,
style: textStyle.copyWith(
height: 18 / 14,
letterSpacing: -0.07,
),
),
Text(
S.of(context).archive_account_reversible,
style: labelStyle.copyWith(
fontSize: 12,
fontWeight: FontWeight.w400,
height: 15 / 12,
letterSpacing: -0.06,
),
),
],
),
),
)
],
const SizedBox(width: 8),
SizedBox.square(
dimension: 16,
child: Align(
alignment: Alignment.centerRight,
child: CakeImageWidget(
imageUrl: "assets/new-ui/arrow_right.svg",
width: 7,
height: 12,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
),
],
),
),
)),
),
),
],
),
),
+246
View File
@@ -0,0 +1,246 @@
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/new-ui/widgets/modern_button.dart";
import "package:cake_wallet/new-ui/widgets/new_primary_button.dart";
import "package:cake_wallet/src/widgets/cake_image_widget.dart";
import "package:cake_wallet/store/settings_store.dart";
import "package:cake_wallet/themes/core/theme_extension.dart";
import "package:flutter/material.dart";
import "package:modal_bottom_sheet/modal_bottom_sheet.dart";
abstract class EducationPage extends StatefulWidget {
const EducationPage({required this.settingsStore, super.key});
final SettingsStore settingsStore;
String get educationId;
String get title;
String get iconPath;
String get completionLabel;
List<EducationSlide> get slides;
String progressLabel(int current, int total);
bool get isDismissed => settingsStore.isEducationDismissed(educationId);
Future<void> show(BuildContext context) async {
await showCupertinoModalBottomSheet<void>(
useRootNavigator: true,
context: context,
backgroundColor: Colors.transparent,
builder: (_) => this,
);
await settingsStore.dismissEducation(educationId);
}
@override
State<EducationPage> createState() => _EducationPageState();
}
class _EducationPageState extends State<EducationPage> {
final PageController _pageController = PageController();
int _currentPage = 0;
bool _isCompleting = false;
@override
void dispose() {
_pageController.dispose();
super.dispose();
}
void _complete() {
if (_isCompleting) {
return;
}
_isCompleting = true;
Navigator.of(context).pop();
}
Future<void> _continue(int pageCount) async {
if (_currentPage == pageCount - 1) {
_complete();
return;
}
await _pageController.nextPage(
duration: const Duration(milliseconds: 250),
curve: Curves.easeOutCubic,
);
}
@override
Widget build(BuildContext context) {
final pages = widget.slides;
return Material(
color: Colors.transparent,
child: Container(
clipBehavior: Clip.antiAlias,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.vertical(top: Radius.circular(30)),
),
child: SafeArea(
top: false,
child: Column(
children: [
Padding(
padding: const EdgeInsets.all(18),
child: Row(
children: [
CakeImageWidget(
imageUrl: widget.iconPath,
width: 24,
height: 24,
),
const SizedBox(width: 8),
Text(widget.title, style: Theme.of(context).textTheme.headlineMedium),
const Spacer(),
ModernButton(
size: 36,
icon: const Icon(Icons.close),
semanticLabel: S.of(context).close,
onPressed: _complete,
),
],
),
),
Expanded(
child: PageView(
controller: _pageController,
onPageChanged: (page) => setState(() => _currentPage = page),
children: pages,
),
),
Semantics(
label: widget.progressLabel(_currentPage + 1, pages.length),
child: ExcludeSemantics(
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: List.generate(
pages.length,
(index) => AnimatedContainer(
key: ValueKey("education-dot-$index"),
duration: const Duration(milliseconds: 200),
width: 8,
height: 8,
margin: const EdgeInsets.symmetric(horizontal: 4),
decoration: BoxDecoration(
color: index == _currentPage
? Theme.of(context).colorScheme.primary
: Theme.of(context).colorScheme.surfaceContainerHighest,
shape: BoxShape.circle,
),
),
),
),
),
),
const SizedBox(height: 24),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 18),
child: NewPrimaryButton(
onPressed: () => _continue(pages.length),
text: _currentPage == pages.length - 1
? widget.completionLabel
: S.of(context).continue_text,
color: Theme.of(context).colorScheme.primary,
textColor: Theme.of(context).colorScheme.onPrimary,
),
),
const SizedBox(height: 12),
],
),
),
),
);
}
}
class EducationSlide extends StatelessWidget {
const EducationSlide({
required this.children,
super.key,
this.distributeChildren = false,
});
final List<Widget> children;
final bool distributeChildren;
@override
Widget build(BuildContext context) => LayoutBuilder(
builder: (context, constraints) => SingleChildScrollView(
padding: const EdgeInsets.symmetric(horizontal: 28, vertical: 8),
child: ConstrainedBox(
constraints: BoxConstraints(minHeight: constraints.maxHeight - 16),
child: distributeChildren
? IntrinsicHeight(
child: Column(
children: [
for (var index = 0; index < children.length; index++) ...[
children[index],
if (index < children.length - 1) ...[
const SizedBox(height: 24),
const Spacer(),
],
],
],
),
)
: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: children,
),
),
),
);
}
class EducationText extends StatelessWidget {
const EducationText({
required this.text,
super.key,
this.highlightedText,
this.secondary = false,
this.warning = false,
});
final String text;
final String? highlightedText;
final bool secondary;
final bool warning;
@override
Widget build(BuildContext context) {
final style = Theme.of(context).textTheme.bodyLarge?.copyWith(
fontSize: 14,
fontWeight: FontWeight.w400,
color: warning
? context.customColors.warningOutlineColor
: secondary
? Theme.of(context).colorScheme.onSurfaceVariant
: Theme.of(context).colorScheme.onSurface,
);
final highlight = highlightedText;
final highlightStart = highlight == null ? -1 : text.indexOf(highlight);
if (highlight == null || highlightStart < 0) {
return Text(text, textAlign: TextAlign.center, style: style);
}
final highlightEnd = highlightStart + highlight.length;
return Text.rich(
TextSpan(
style: style,
children: [
TextSpan(text: text.substring(0, highlightStart)),
TextSpan(
text: text.substring(highlightStart, highlightEnd),
style: TextStyle(color: Theme.of(context).colorScheme.primary),
),
TextSpan(text: text.substring(highlightEnd)),
],
),
textAlign: TextAlign.center,
);
}
}
+480
View File
@@ -0,0 +1,480 @@
import "dart:async";
import "package:cake_wallet/core/utilities.dart";
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/new-ui/widgets/account_confirmation_content.dart";
import "package:cake_wallet/new-ui/widgets/modal_page_wrapper.dart";
import "package:cake_wallet/new-ui/widgets/money/money_text.dart";
import "package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart";
import "package:cake_wallet/src/widgets/alert_with_two_actions.dart";
import "package:cake_wallet/src/widgets/base_alert_dialog.dart";
import "package:cake_wallet/src/widgets/cake_image_widget.dart";
import "package:cake_wallet/utils/show_pop_up.dart";
import "package:cake_wallet/view_model/dashboard/dashboard_view_model.dart";
import "package:cake_wallet/view_model/wallet_account_list/account_list_item.dart";
import "package:cake_wallet/view_model/wallet_account_list/wallet_account_list_view_model.dart";
import "package:cw_core/balance_card_layout.dart";
import "package:cw_core/balance_card_style_settings.dart";
import "package:flutter/cupertino.dart";
import "package:flutter/material.dart";
import "package:flutter_mobx/flutter_mobx.dart";
class HiddenAccountsPage extends StatefulWidget {
const HiddenAccountsPage({
required this.accountListViewModel,
required this.dashboardViewModel,
super.key,
});
final WalletAccountListViewModel accountListViewModel;
final DashboardViewModel dashboardViewModel;
@override
State<HiddenAccountsPage> createState() => _HiddenAccountsPageState();
}
class _HiddenAccountsPageState extends State<HiddenAccountsPage> {
final List<AccountListItem> _items = [];
final Set<int> _accountsBeingRestored = <int>{};
bool _isLoading = true;
int get _walletInfoId => widget.dashboardViewModel.wallet.walletInfo.internalId;
@override
void initState() {
super.initState();
unawaited(_loadAccounts());
}
Future<BalanceCardLayout> _layout() async => BalanceCardLayout.resolve(
accountIndices: widget.accountListViewModel.accounts.map((account) => account.id).toList(),
settings: await BalanceCardStyleSettings.getAll(_walletInfoId),
);
Future<void> _loadAccounts() async {
final accounts = widget.accountListViewModel.accounts;
final layout = await _layout();
final hiddenAccounts = <AccountListItem>[];
for (final accountIndex in layout.hidden) {
final account = accounts.firstWhereOrNull((account) => account.id == accountIndex);
if (account != null) {
hiddenAccounts.add(account);
}
}
if (!mounted) {
return;
}
setState(() {
_items
..clear()
..addAll(hiddenAccounts);
_isLoading = false;
});
}
Future<bool> _confirmUnarchival(AccountListItem account) async {
final isFunded = account.isFunded;
final result = await showPopUp<bool>(
context: context,
barrierDismissible: false,
builder: (dialogContext) => AlertWithTwoActions(
alertTitle: S.of(dialogContext).unarchive_account_title,
alertContent: "",
alertContentTextWidget: Column(
mainAxisSize: MainAxisSize.min,
children: [
AccountSummary(account: account),
const SizedBox(height: 20),
Text(
isFunded
? S.of(dialogContext).unarchive_account_funds_description
: S.of(dialogContext).unarchive_account_description,
textAlign: TextAlign.center,
style: Theme.of(dialogContext).textTheme.bodyMedium,
),
if (isFunded) ...[
const SizedBox(height: 20),
AccountFundsSummary(
account: account,
fiatBalance: widget.dashboardViewModel.balanceViewModel.accountFiatBalance(account),
borderColor: Theme.of(dialogContext).colorScheme.primary,
),
],
],
),
leftButtonText: S.of(dialogContext).cancel,
rightButtonText: S.of(dialogContext).continue_text,
leftAlertButtonStyle: AlertButtonStyle.secondary(dialogContext),
rightAlertButtonStyle: AlertButtonStyle.primary(dialogContext),
actionLeftButton: () => Navigator.of(dialogContext).pop(false),
actionRightButton: () => Navigator.of(dialogContext).pop(true),
),
);
return result ?? false;
}
Future<void> _unarchive(AccountListItem account) async {
final accountForConfirmation =
widget.accountListViewModel.accounts.firstWhereOrNull((item) => item.id == account.id) ??
account;
final confirmed = await _confirmUnarchival(accountForConfirmation);
if (!confirmed || !mounted) {
return;
}
setState(() => _accountsBeingRestored.add(account.id));
try {
final restored = (await _layout()).unhiding(account.id);
await BalanceCardStyleSettings.setVisibleOrder(_walletInfoId, restored.orders);
final latestAccount =
widget.accountListViewModel.accounts.firstWhereOrNull((item) => item.id == account.id) ??
account;
await widget.accountListViewModel.select(latestAccount);
await widget.dashboardViewModel.loadCardDesigns();
await _loadAccounts();
} finally {
if (mounted) {
setState(() => _accountsBeingRestored.remove(account.id));
}
}
}
@override
Widget build(BuildContext context) => ModalPageWrapper(
topBar: ModalTopBar(
title: S.of(context).archived_accounts,
leadingIcon: const Icon(Icons.arrow_back_ios_new, size: 18),
leadingSemanticLabel: S.of(context).seed_alert_back,
onLeadingPressed: Navigator.of(context).pop,
),
content: _isLoading
? const SizedBox(
height: 320,
child: Center(child: CupertinoActivityIndicator()),
)
: _items.isEmpty
? const _EmptyArchiveView()
: _PopulatedArchiveView(
accounts: _items,
accountsBeingRestored: _accountsBeingRestored,
dashboardViewModel: widget.dashboardViewModel,
onUnarchive: _unarchive,
),
);
}
class _EmptyArchiveView extends StatelessWidget {
const _EmptyArchiveView();
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return SizedBox(
height: MediaQuery.sizeOf(context).height - 180,
child: Center(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
_ArchiveIcon(size: 50, color: theme.colorScheme.onSurfaceVariant),
const SizedBox(height: 12),
Text(
S.of(context).no_archived_accounts,
textAlign: TextAlign.center,
style: theme.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w500),
),
const SizedBox(height: 12),
Text(
S.of(context).no_archived_accounts_description,
textAlign: TextAlign.center,
style: theme.textTheme.bodyMedium?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
),
),
],
),
),
),
);
}
}
class _PopulatedArchiveView extends StatelessWidget {
const _PopulatedArchiveView({
required this.accounts,
required this.accountsBeingRestored,
required this.dashboardViewModel,
required this.onUnarchive,
});
final List<AccountListItem> accounts;
final Set<int> accountsBeingRestored;
final DashboardViewModel dashboardViewModel;
final Future<void> Function(AccountListItem account) onUnarchive;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final fundedAccounts = accounts.where((account) => account.isFunded).toList(growable: false);
final emptyAccounts =
accounts.where((account) => !account.isFunded).toList(growable: false);
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
_ArchiveIcon(size: 50, color: theme.colorScheme.primary),
const SizedBox(height: 12),
Padding(
padding: const EdgeInsets.fromLTRB(12, 0, 12, 36),
child: Text(
S.of(context).select_account_to_unarchive,
textAlign: TextAlign.center,
style: theme.textTheme.bodyMedium?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
),
),
),
if (fundedAccounts.isNotEmpty) ...[
_ArchiveSectionHeader(
title: S.of(context).funded_accounts,
description: S.of(context).funded_accounts_description,
),
const SizedBox(height: 12),
_accountRows(context, fundedAccounts),
],
if (fundedAccounts.isNotEmpty && emptyAccounts.isNotEmpty) const SizedBox(height: 28),
if (emptyAccounts.isNotEmpty) ...[
_ArchiveSectionHeader(title: S.of(context).empty_accounts),
const SizedBox(height: 12),
_accountRows(context, emptyAccounts),
],
],
);
}
Widget _accountRows(BuildContext context, List<AccountListItem> sectionAccounts) => Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(18),
),
clipBehavior: Clip.antiAlias,
child: Column(
children: [
for (var index = 0; index < sectionAccounts.length; index++) ...[
_ArchivedAccountRow(
account: sectionAccounts[index],
dashboardViewModel: dashboardViewModel,
isBusy: accountsBeingRestored.contains(sectionAccounts[index].id),
onTap: accountsBeingRestored.contains(sectionAccounts[index].id)
? null
: () => onUnarchive(sectionAccounts[index]),
),
if (index < sectionAccounts.length - 1)
Divider(
height: 1,
indent: 48,
color: Theme.of(context).colorScheme.outlineVariant,
),
],
],
),
);
}
class _ArchivedAccountRow extends StatelessWidget {
const _ArchivedAccountRow({
required this.account,
required this.dashboardViewModel,
required this.isBusy,
required this.onTap,
});
final AccountListItem account;
final DashboardViewModel dashboardViewModel;
final bool isBusy;
final VoidCallback? onTap;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final label = account.label.trim();
return Material(
color: theme.colorScheme.surfaceContainer,
child: Semantics(
button: true,
child: InkWell(
onTap: onTap,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
child: Row(
children: [
CakeImageWidget(
imageUrl: "assets/new-ui/account.svg",
width: 24,
height: 24,
color: theme.colorScheme.onSurfaceVariant,
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text.rich(
TextSpan(
children: [
TextSpan(
text: "${account.id + 1}. ",
style: TextStyle(color: theme.colorScheme.primary),
),
TextSpan(
text: label.isEmpty ? S.of(context).unnamed_account : label,
),
],
),
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: theme.textTheme.bodyMedium,
),
],
),
),
const SizedBox(width: 8),
_AccountBalanceTrailing(
account: account,
dashboardViewModel: dashboardViewModel,
isBusy: isBusy,
),
],
),
),
),
),
);
}
}
class _ArchiveSectionHeader extends StatelessWidget {
const _ArchiveSectionHeader({required this.title, this.description});
final String title;
final String? description;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
title,
style: theme.textTheme.titleSmall?.copyWith(fontWeight: FontWeight.w600),
),
if (description != null) ...[
const SizedBox(height: 4),
Text(
description!,
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
),
),
],
],
),
);
}
}
class _AccountBalanceTrailing extends StatelessWidget {
const _AccountBalanceTrailing({
required this.account,
required this.dashboardViewModel,
required this.isBusy,
});
final AccountListItem account;
final DashboardViewModel dashboardViewModel;
final bool isBusy;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
if (isBusy) {
return const CupertinoActivityIndicator(radius: 10);
}
return Row(
mainAxisSize: MainAxisSize.min,
children: [
if (account.isFunded) ...[
ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 142),
child: Observer(
builder: (_) {
final fiatBalance = dashboardViewModel.balanceViewModel.accountFiatBalance(account);
return Column(
crossAxisAlignment: CrossAxisAlignment.end,
children: [
MoneyText(
account.balance,
fractionalDigits: account.balance.decimals,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: theme.textTheme.bodySmall,
),
if (fiatBalance != null) ...[
const SizedBox(height: 2),
Text(
fiatBalance,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: theme.textTheme.bodySmall?.copyWith(
color: theme.colorScheme.onSurfaceVariant,
),
),
],
],
);
},
),
),
const SizedBox(width: 8),
],
Icon(
Icons.arrow_forward_ios_rounded,
size: 14,
color: theme.colorScheme.onSurfaceVariant,
),
],
);
}
}
class _ArchiveIcon extends StatelessWidget {
const _ArchiveIcon({required this.size, required this.color});
final double size;
final Color color;
@override
Widget build(BuildContext context) => SizedBox.square(
dimension: size,
child: Center(
child: CakeImageWidget(
imageUrl: "assets/new-ui/archived.svg",
width: size * 19 / 24,
height: size * 19 / 24,
color: color,
),
),
);
}
+49 -2
View File
@@ -7,6 +7,10 @@ import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/main.dart";
import "package:cake_wallet/new-ui/modal_navigator.dart";
import "package:cake_wallet/new-ui/pages/card_customizer.dart";
import "package:cake_wallet/new-ui/pages/account_education_page.dart";
import "package:cake_wallet/new-ui/widgets/coins_page/accounts_promo.dart";
import "package:cake_wallet/src/widgets/alert_with_one_action.dart";
import "package:cw_core/sync_status.dart";
import "package:cake_wallet/new-ui/pages/seed/seed_backup_reminder_page.dart";
import "package:cake_wallet/new-ui/pages/send_page.dart";
import "package:cake_wallet/new-ui/pages/settings_page.dart";
@@ -214,6 +218,14 @@ class _NewHomePageState extends State<NewHomePage> with RouteAware {
),
],
),
if (AccountsPromo.supportsWallet(widget.dashboardViewModel.wallet.type) &&
widget.dashboardViewModel.accountListViewModel != null &&
!_lightningMode)
AccountsPromo(
settingsStore: widget.dashboardViewModel.settingsStore,
walletName: walletTypeToString(widget.dashboardViewModel.wallet.type),
onTap: _openAccountsFromPromo,
),
Column(
children: [
CoinActionRow(
@@ -264,11 +276,18 @@ class _NewHomePageState extends State<NewHomePage> with RouteAware {
);
Future<void> openCardCustomizer() async {
if (!_checkReadyToManage()) return;
await CardCustomizer.show(
context: context,
dashboardViewModel: widget.dashboardViewModel,
account: !widget.dashboardViewModel.lightningMode &&
widget.dashboardViewModel.isMultiAccountsEnabled
? widget.dashboardViewModel.accountListViewModel?.selectedAccount
: null,
lightningMode: widget.dashboardViewModel.lightningMode,
);
await widget.dashboardViewModel.accountListViewModel?.reload();
await widget.dashboardViewModel.loadCardDesigns();
}
void openSeedBackupReminder() {
@@ -283,7 +302,9 @@ class _NewHomePageState extends State<NewHomePage> with RouteAware {
}
Future<void> openAccountCustomizer() async {
if (widget.dashboardViewModel.accountListViewModel == null) return;
if (widget.dashboardViewModel.accountListViewModel == null || !_checkReadyToManage()) return;
final page = getIt.get<WalletAccountsPage>(param1: widget.dashboardViewModel);
await CupertinoScaffold.showCupertinoModalBottomSheet(
barrierColor: Colors.black.withAlpha(60),
@@ -292,10 +313,36 @@ class _NewHomePageState extends State<NewHomePage> with RouteAware {
parentContext: context,
heightMode: ModalHeightModes.fullScreen,
rootPage: Material(
child: getIt.get<WalletAccountsPage>(param1: widget.dashboardViewModel),
child: page,
),
),
);
await widget.dashboardViewModel.loadCardDesigns();
}
Future<void> _openAccountsFromPromo() async {
if (!AccountsPromo.supportsWallet(widget.dashboardViewModel.wallet.type) ||
widget.dashboardViewModel.accountListViewModel == null || !_checkReadyToManage()) return;
await AccountEducationPage(
settingsStore: widget.dashboardViewModel.settingsStore,
).show(context);
if (mounted) await openAccountCustomizer();
}
bool _checkReadyToManage() {
if (widget.dashboardViewModel.status is! SyncedSyncStatus) {
showDialog(
context: context,
builder: (context) => AlertWithOneAction(
alertTitle: S.of(context).wallet_is_syncing,
alertContent: S.of(context).cannot_manage_accounts_during_sync,
buttonText: S.of(context).ok,
buttonAction: Navigator.of(context).pop,
),
);
return false;
}
return true;
}
}
+403 -144
View File
@@ -1,30 +1,33 @@
import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item.dart';
import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/new-ui/modal_navigator.dart';
import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
import 'package:cw_core/wallet_info.dart';
import "package:cake_wallet/core/auth_service.dart";
import "package:cake_wallet/entities/new_ui_entities/list_item/list_item.dart";
import "package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart";
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/new-ui/modal_navigator.dart";
import "package:cake_wallet/new-ui/pages/coin_control_page.dart";
import "package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart";
import "package:cake_wallet/routes.dart";
import "package:cake_wallet/src/widgets/cake_image_widget.dart";
import "package:cake_wallet/src/widgets/new_list_row/new_list_section.dart";
import "package:cake_wallet/view_model/dashboard/dashboard_view_model.dart";
import "package:cw_core/wallet_info.dart";
import "package:cw_core/wallet_type.dart";
import 'package:flutter/material.dart';
import 'package:modal_bottom_sheet/modal_bottom_sheet.dart';
import "package:flutter/material.dart";
import "package:modal_bottom_sheet/modal_bottom_sheet.dart";
bool _trueFunc(DashboardViewModel _) => true;
bool _falseFunc(DashboardViewModel _) => false;
bool _isBtc(DashboardViewModel vm) => vm.wallet.type == WalletType.bitcoin;
bool _alwaysVisible(DashboardViewModel _) => true;
bool _hasLightning(DashboardViewModel vm) => vm.hasLightning;
bool _hasSilentPayments(DashboardViewModel vm) => vm.hasSilentPayments;
bool _hasMweb(DashboardViewModel vm) => vm.hasMweb;
bool _hasWalletConnect(DashboardViewModel vm) => vm.hasWalletConnect;
bool _hasAccounts(DashboardViewModel vm) => vm.wallet.hasAccountsSupport;
bool _hasCoinControl(DashboardViewModel vm) => vm.wallet.hasCoinControl;
bool _requiresKeyImageSync(DashboardViewModel vm) =>
vm.wallet.type == WalletType.monero &&
[HardwareWalletType.cupcake, HardwareWalletType.trezor].contains(vm.wallet.hardwareWalletType);
@@ -34,16 +37,20 @@ class SettingsListItem {
this.iconPath,
this.title,
this.route, {
this.isCore = false,
this.requireAuth = false,
this.use2fa = _falseFunc,
this.condition = _trueFunc,
this.use2fa = _neverUse2fa,
this.condition = _alwaysVisible,
this.routeArgs,
this.routeArgsBuilder,
});
static bool _neverUse2fa(DashboardViewModel _) => false;
final String iconPath;
final String title;
final String route;
final bool isCore;
final Object? routeArgs;
final Object? Function(DashboardViewModel)? routeArgsBuilder;
final bool requireAuth;
@@ -52,72 +59,165 @@ class SettingsListItem {
}
class SettingsSectionData {
const SettingsSectionData(this.title, this.titleIconPath, this.items);
const SettingsSectionData(
this.title,
this.titleIconPath,
this.groups, {
this.titleColor,
this.headerSpacing = 16,
});
final String title;
final String titleIconPath;
final List<SettingsListItem> items;
final Map<String, List<ListItem>> groups;
final Color? titleColor;
final double headerSpacing;
}
static SettingsSectionData walletSettings =
SettingsSectionData(S.current.wallet_settings, "assets/new-ui/wallet-setting.svg", [
SettingsListItem(
"assets/new-ui/settings_row_icons/accounts.svg",
S.current.accounts,
Routes.walletAccountsPage,
condition: (vm) => vm.wallet.hasAccountsSupport,
routeArgsBuilder: (vm) => vm,
),
SettingsListItem(
"assets/new-ui/settings_row_icons/nodes.svg", S.current.nodes, Routes.manageNodes),
SettingsListItem(
"assets/new-ui/settings_row_icons/privacy.svg", S.current.privacy, Routes.privacyPage),
SettingsListItem("assets/new-ui/settings_row_icons/seed.svg", S.current.recovery_and_keys,
Routes.showKeysDisclaimer),
SettingsListItem("assets/new-ui/settings_row_icons/lightning_username.svg",
"Lightning ${S.current.username}", Routes.lightningUsernamePage,
condition: _hasLightning),
SettingsListItem("assets/new-ui/settings_row_icons/wc.svg", S.current.walletConnect,
class WalletSettingsResolver {
const WalletSettingsResolver();
String titleFor(WalletType walletType, S strings) =>
'${walletTypeToString(walletType)} ${strings.settings_title}'.trim();
String iconPathFor(WalletType walletType) =>
walletType == WalletType.robinhood
? "assets/new-ui/crypto_full_icons/robinhood.svg"
: "assets/new-ui/network_icons/${walletType.name.toLowerCase()}.svg";
List<List<SettingsListItem>> resolveSections(DashboardViewModel viewModel) {
final visibleItems = <SettingsListItem>[
SettingsListItem(
"assets/new-ui/settings_row_icons/accounts.svg",
viewModel.wallet.type == WalletType.bitcoin ? S.current.accounts_onchain : S.current.accounts,
Routes.walletAccountsPage,
isCore: true,
condition: _hasAccounts,
routeArgsBuilder: (vm) => vm,
),
SettingsListItem(
"assets/new-ui/settings_row_icons/nodes.svg",
S.current.nodes,
Routes.manageNodes,
isCore: true,
),
SettingsListItem(
"assets/new-ui/settings_row_icons/coin-control.svg",
S.current.coin_control_settings,
Routes.unspentCoinsList,
isCore: true,
condition: _hasCoinControl,
routeArgs: const CoinControlPageArgs(canEdit: false),
),
SettingsListItem(
"assets/new-ui/settings_row_icons/lightning_username.svg",
"Lightning ${S.current.username}",
Routes.lightningUsernamePage,
condition: _hasLightning,
),
SettingsListItem(
"assets/new-ui/settings_row_icons/silent-payments.svg",
S.current.silent_payments,
Routes.silentPaymentsSettings,
condition: _hasSilentPayments,
),
SettingsListItem(
"assets/new-ui/settings_row_icons/mweb.svg",
S.current.litecoin_mweb,
Routes.mwebSettings,
condition: _hasMweb,
),
SettingsListItem(
"assets/new-ui/settings_row_icons/wc.svg",
S.current.walletConnect,
Routes.walletConnectConnectionsListing,
condition: _hasWalletConnect),
//SettingsListItem("assets/new-ui/settings_row_icons/silent-payments.svg", S.current.silent_payments_settings, Routes.silentPaymentsSettings, condition: _isBtc),
//SettingsListItem("assets/new-ui/settings_row_icons/mweb.svg", S.current.litecoin_mweb_settings, Routes.mwebSettings, condition: _hasMweb),
SettingsListItem(
"assets/new-ui/settings_row_icons/sync-balance.svg",
S.current.resync_device,
Routes.syncKeyImagesDevices,
routeArgs: {'export-outputs': 'export-outputs'},
condition: _requiresKeyImageSync,
),
SettingsListItem(
"assets/new-ui/settings_row_icons/other.svg", S.current.other, Routes.otherSettingsPage),
]);
condition: _hasWalletConnect,
),
SettingsListItem(
"assets/new-ui/settings_row_icons/sync-balance.svg",
S.current.resync_device,
Routes.syncKeyImagesDevices,
routeArgs: const {"export-outputs": "export-outputs"},
condition: _requiresKeyImageSync,
),
].where((item) => item.condition(viewModel)).toList();
static SettingsSectionData appSettings =
SettingsSectionData(S.current.app_settings, "assets/new-ui/cake-setting.svg", [
SettingsListItem("assets/new-ui/settings_row_icons/connections.svg", S.current.connections,
Routes.connectionSync),
// SettingsListItem("assets/new-ui/settings_row_icons/defaults.svg", "Defaults", ""),
SettingsListItem("assets/new-ui/settings_row_icons/display.svg", S.current.display,
Routes.displaySettingsPage),
SettingsListItem("assets/new-ui/settings_row_icons/security.svg", S.current.security,
Routes.securityBackupPage),
SettingsListItem("assets/new-ui/settings_row_icons/backup.svg", S.current.backup, Routes.backup,
requireAuth: true,
use2fa: (vm) => vm.settingsStore.shouldRequireTOTP2FAForAllSecurityAndBackupSettings),
]);
final coreItems = visibleItems.where((item) => item.isCore).toList();
final featureItems = visibleItems.where((item) => !item.isCore).toList();
static SettingsSectionData otherSettings = SettingsSectionData("", "", [
SettingsListItem(
"assets/new-ui/settings_row_icons/support.svg", S.current.settings_support, Routes.support),
SettingsListItem(
"assets/new-ui/settings_row_icons/info.svg", S.current.about, Routes.aboutPage),
]);
return [
if (coreItems.isNotEmpty) coreItems,
if (featureItems.isNotEmpty) featureItems,
];
}
}
static List<SettingsSectionData> all = [walletSettings, appSettings, otherSettings];
class SettingsPageSectionsResolver {
const SettingsPageSectionsResolver();
List<SettingsListItem> walletGeneral(S strings) => [
SettingsListItem(
'assets/new-ui/settings_row_icons/privacy.svg',
strings.privacy,
Routes.privacyPage,
),
SettingsListItem(
'assets/new-ui/settings_row_icons/seed.svg',
strings.recovery_and_keys,
Routes.showKeysDisclaimer,
),
SettingsListItem(
'assets/new-ui/settings_row_icons/other.svg',
strings.other,
Routes.otherSettingsPage,
),
];
List<SettingsListItem> appSettings() => [
SettingsListItem(
"assets/new-ui/settings_row_icons/connections.svg",
S.current.connections,
Routes.connectionSync,
),
SettingsListItem(
"assets/new-ui/settings_row_icons/display.svg",
S.current.display,
Routes.displaySettingsPage,
),
SettingsListItem(
"assets/new-ui/settings_row_icons/security.svg",
S.current.security,
Routes.securityBackupPage,
),
SettingsListItem(
"assets/new-ui/settings_row_icons/backup.svg",
S.current.backup,
Routes.backup,
requireAuth: true,
use2fa: (vm) => vm.settingsStore.shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
),
];
List<SettingsListItem> supportAndAbout(S strings) => [
SettingsListItem(
'assets/new-ui/settings_row_icons/support.svg',
strings.settings_support,
Routes.support,
),
SettingsListItem(
'assets/new-ui/settings_row_icons/info.svg',
strings.about,
Routes.aboutPage,
),
];
}
class NewSettingsPage extends StatelessWidget {
const NewSettingsPage({super.key, required this.dashboardViewModel, required this.authService});
const NewSettingsPage({
super.key,
required this.dashboardViewModel,
required this.authService,
});
final DashboardViewModel dashboardViewModel;
final AuthService authService;
@@ -125,89 +225,248 @@ class NewSettingsPage extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ModalNavigator(
parentContext: context,
rootPage: SettingsMainPage(
dashboardViewModel: dashboardViewModel,
authService: authService,
));
parentContext: context,
rootPage: SettingsMainPage(
dashboardViewModel: dashboardViewModel,
authService: authService,
),
);
}
}
class SettingsMainPage extends StatelessWidget {
const SettingsMainPage({super.key, required this.dashboardViewModel, required this.authService});
const SettingsMainPage({
super.key,
required this.dashboardViewModel,
required this.authService,
});
static const _walletSettingsResolver = WalletSettingsResolver();
static const _sectionsResolver = SettingsPageSectionsResolver();
final DashboardViewModel dashboardViewModel;
final AuthService authService;
@override
Widget build(BuildContext context) => Container(
color: Theme.of(context).colorScheme.surface,
child: Column(
children: [
ModalTopBar(
title: S.of(context).settings_title,
leadingIcon: const Icon(Icons.close),
leadingSemanticLabel: S.of(context).close,
onLeadingPressed: Navigator.of(context, rootNavigator: true).pop,
),
Expanded(
child: ListView(
controller: ModalScrollController.of(context),
padding: const EdgeInsets.fromLTRB(18, 0, 18, 32),
children: [
for (final (index, section) in _sections(context).indexed) ...[
if (index > 0) ...[
const SizedBox(height: 24),
Divider(color: Theme.of(context).colorScheme.surfaceContainerHighest),
const SizedBox(height: 24),
],
_SettingsSectionHeader(
iconPath: section.titleIconPath,
title: section.title,
foregroundColor: section.titleColor,
),
SizedBox(height: section.headerSpacing),
for (final (groupIndex, group) in section.groups.entries.indexed) ...[
if (groupIndex > 0) const SizedBox(height: 24),
NewListSections(sections: {group.key: group.value}),
],
],
],
),
),
],
),
);
List<SettingsSectionData> _sections(BuildContext context) => [
SettingsSectionData(
dashboardViewModel.wallet.name,
"assets/new-ui/wallet-setting.svg",
{
"wallet_type_settings": [
ListItemRegularRow(
keyValue: "wallet_type_settings",
label: _walletSettingsResolver.titleFor(
dashboardViewModel.wallet.type,
S.of(context),
),
iconPath: _walletSettingsResolver.iconPathFor(dashboardViewModel.wallet.type),
onTap: () => Navigator.of(context).push(
MaterialPageRoute<void>(
builder: (_) => WalletSettingsPage(
dashboardViewModel: dashboardViewModel,
authService: authService,
),
),
),
),
],
"wallet_general": _buildRows(context, _sectionsResolver.walletGeneral(S.of(context))),
},
titleColor: Theme.of(context).colorScheme.primary,
headerSpacing: 20,
),
SettingsSectionData(
S.of(context).app_settings,
"assets/new-ui/cake-setting.svg",
{
"app_settings": _buildRows(context, _sectionsResolver.appSettings()),
"support_and_about":
_buildRows(context, _sectionsResolver.supportAndAbout(S.of(context))),
},
),
];
List<ListItem> _buildRows(BuildContext context, List<SettingsListItem> items) => items
.where((item) => item.condition(dashboardViewModel))
.map((item) => _buildRow(context, item))
.toList();
ListItemRegularRow _buildRow(BuildContext context, SettingsListItem item) => ListItemRegularRow(
keyValue: item.route,
label: item.title,
iconPath: item.iconPath,
onTap: () => _openItem(context, item),
);
Future<void> _openItem(BuildContext context, SettingsListItem item) async {
final arguments = item.routeArgsBuilder?.call(dashboardViewModel) ?? item.routeArgs;
if (item.requireAuth) {
await authService.authenticateAction(
context,
conditionToDetermineIfToUse2FA: item.use2fa(dashboardViewModel),
route: item.route,
arguments: arguments,
);
return;
}
await Navigator.of(context).pushNamed(item.route, arguments: arguments);
}
}
class WalletSettingsPage extends StatelessWidget {
const WalletSettingsPage({
super.key,
required this.dashboardViewModel,
required this.authService,
});
static const _resolver = WalletSettingsResolver();
final DashboardViewModel dashboardViewModel;
final AuthService authService;
@override
Widget build(BuildContext context) {
List<ListItem> buildItems(SettingsSectionData section) => section.items
.map((item) => item.condition(dashboardViewModel)
? ListItemRegularRow(
keyValue: item.route,
label: item.title,
iconPath: item.iconPath,
onTap: () {
if (item.route.isNotEmpty) {
if (item.requireAuth) {
authService.authenticateAction(context,
conditionToDetermineIfToUse2FA: item.use2fa(dashboardViewModel),
route: item.route);
} else {
Navigator.of(context).pushNamed(
item.route,
arguments:
item.routeArgsBuilder?.call(dashboardViewModel) ?? item.routeArgs,
);
}
}
})
: null)
.whereType<ListItem>()
.toList();
final strings = S.of(context);
final sections = _resolver.resolveSections(dashboardViewModel);
return Container(
color: Theme.of(context).colorScheme.surface,
child: Column(children: [
ModalTopBar(
title: S.of(context).settings_title,
leadingIcon: Icon(Icons.close),
leadingSemanticLabel: S.of(context).close,
onLeadingPressed: Navigator.of(context, rootNavigator: true).pop,
onTrailingPressed: () {},
),
Expanded(
child: ListView(controller: ModalScrollController.of(context), children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 20.0),
child: Column(
spacing: 16,
children: SettingsSectionData.all.expand((section) {
return [
if (section.titleIconPath.isNotEmpty)
Padding(
padding: const EdgeInsets.only(top: 8.0),
child: Row(
spacing: 8,
children: [
CakeImageWidget(
imageUrl: section.titleIconPath,
colorFilter: ColorFilter.mode(
Theme.of(context).colorScheme.onSurfaceVariant,
BlendMode.srcIn,
)),
Text(section.title, style: Theme.of(context).textTheme.titleMedium),
],
),
),
NewListSections(sections: {section.title: buildItems(section)}),
];
}).toList(),
),
child: Column(
children: [
ModalTopBar(
title: _resolver.titleFor(dashboardViewModel.wallet.type, strings),
titleLeadingWidget: CakeImageWidget(
imageUrl: _resolver.iconPathFor(dashboardViewModel.wallet.type),
width: 24,
height: 24,
),
]),
),
]),
leadingIcon: const Icon(Icons.arrow_back_ios_new),
leadingSemanticLabel: strings.seed_alert_back,
onLeadingPressed: Navigator.of(context).pop,
),
Expanded(
child: ListView(
controller: ModalScrollController.of(context),
padding: const EdgeInsets.fromLTRB(18, 0, 18, 32),
children: [
for (var index = 0; index < sections.length; index++) ...[
if (index > 0) const SizedBox(height: 24),
NewListSections(
sections: {
'wallet_settings_$index': sections[index]
.map(
(item) => ListItemRegularRow(
keyValue: item.route,
label: item.title,
iconPath: item.iconPath,
onTap: () => _openItem(context, item),
),
)
.toList(),
},
),
],
],
),
),
],
),
);
}
Future<void> _openItem(BuildContext context, SettingsListItem item) async {
final arguments = item.routeArgsBuilder?.call(dashboardViewModel) ?? item.routeArgs;
if (item.requireAuth) {
await authService.authenticateAction(
context,
conditionToDetermineIfToUse2FA: item.use2fa(dashboardViewModel),
route: item.route,
arguments: arguments,
);
return;
}
await Navigator.of(context).pushNamed(item.route, arguments: arguments);
}
}
class _SettingsSectionHeader extends StatelessWidget {
const _SettingsSectionHeader({
required this.iconPath,
required this.title,
this.foregroundColor,
});
final String iconPath;
final String title;
final Color? foregroundColor;
@override
Widget build(BuildContext context) {
final color = foregroundColor ?? Theme.of(context).colorScheme.onSurfaceVariant;
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 12),
child: Row(
children: [
CakeImageWidget(
imageUrl: iconPath,
height: 20,
width: 20,
colorFilter: ColorFilter.mode(color, BlendMode.srcIn),
),
const SizedBox(width: 8),
Expanded(
child: Text(
title,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.titleMedium?.copyWith(color: color),
),
),
],
),
);
}
}
+393 -416
View File
@@ -1,41 +1,45 @@
import "dart:async";
import "dart:math";
import "dart:ui";
import "package:cake_wallet/di.dart";
import "package:cake_wallet/core/utilities.dart";
import "package:cake_wallet/core/amount_parsing_proxy.dart";
import "package:cake_wallet/entities/bitcoin_amount_display_mode.dart";
import "package:cake_wallet/entities/new_ui_entities/list_item/list_item_toggle.dart";
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/new-ui/pages/card_customizer.dart";
import "package:cake_wallet/new-ui/widgets/coins_page/cards/balance_card.dart";
import "package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart";
import "package:cake_wallet/src/screens/settings/widgets/account_creation_modal.dart";
import "package:cake_wallet/src/widgets/alert_with_one_action.dart";
import "package:cake_wallet/src/widgets/alert_with_two_actions.dart";
import "package:cake_wallet/src/widgets/new_list_row/new_list_section.dart";
import "package:cake_wallet/utils/show_pop_up.dart";
import "package:cake_wallet/src/screens/settings/widgets/account_creation_modal.dart";
import "package:cw_core/wallet_type.dart";
import "package:mobx/mobx.dart";
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/new-ui/pages/account_education_page.dart";
import "package:cake_wallet/new-ui/pages/card_customizer.dart";
import "package:cake_wallet/new-ui/pages/hidden_accounts.dart";
import "package:cake_wallet/new-ui/widgets/coins_page/cards/balance_card.dart";
import "package:cake_wallet/new-ui/widgets/modern_button.dart";
import "package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart";
import "package:cake_wallet/src/widgets/alert_with_one_action.dart";
import "package:cake_wallet/view_model/dashboard/dashboard_view_model.dart";
import "package:cake_wallet/view_model/wallet_account_list/account_edit_or_create_view_model.dart";
import "package:cake_wallet/view_model/wallet_account_list/account_list_item.dart";
import "package:cake_wallet/view_model/wallet_account_list/account_edit_or_create_view_model.dart";
import "package:cake_wallet/view_model/wallet_account_list/wallet_account_list_view_model.dart";
import "package:cw_core/balance_card_layout.dart";
import "package:cw_core/balance_card_style_settings.dart";
import "package:cw_core/card_design.dart";
import "package:cw_core/sync_status.dart";
import "package:cw_core/utils/print_verbose.dart";
import "package:cw_core/wallet_type.dart";
import "package:flutter/cupertino.dart";
import "package:flutter/material.dart";
import "package:mobx/mobx.dart";
import "package:modal_bottom_sheet/modal_bottom_sheet.dart";
class AccountCustomizerListItem {
AccountCustomizerListItem({
const AccountCustomizerListItem({
required this.card,
required this.order,
required this.accountListItem,
required this.settings,
});
final BalanceCard card;
final int order;
final AccountListItem accountListItem;
final BalanceCardStyleSettings? settings;
}
class WalletAccountsPage extends StatefulWidget {
@@ -55,315 +59,229 @@ class WalletAccountsPage extends StatefulWidget {
}
class _WalletAccountsPageState extends State<WalletAccountsPage> {
static const double _kStackVisibleFactor = 0.2;
late final double cardWidth = MediaQuery.of(context).size.width * 0.9;
final List<AccountCustomizerListItem> _items = [];
bool _hasArchivedAccounts = false;
bool _loading = true;
ReactionDisposer? _accountsReaction;
WalletAccountListViewModel get accountListViewModel =>
widget.dashboardViewModel.accountListViewModel ?? widget.accountListViewModel;
bool get _isMultiAccountsEnabled =>
widget.dashboardViewModel.isMultiAccountsEnabled;
String get _assetName => widget.dashboardViewModel.appStore.amountParsingProxy
.getCryptoSymbol(accountListViewModel.currency);
bool get _isMultiAccountsEnabled => widget.dashboardViewModel.isMultiAccountsEnabled;
String get _assetName => AmountParsingProxy(
widget.dashboardViewModel.settingsStore.displayAmountsInSatoshi,
).getCryptoSymbol(widget.accountListViewModel.currency);
bool get _capitalizeAssetName =>
widget.dashboardViewModel.wallet.type != WalletType.bitcoin ||
widget.dashboardViewModel.settingsStore.displayAmountsInSatoshi !=
BitcoinAmountDisplayMode.satoshi;
widget.dashboardViewModel.settingsStore.displayAmountsInSatoshi !=
BitcoinAmountDisplayMode.satoshi;
double get cardWidth => min(MediaQuery.sizeOf(context).width * 0.9, 768);
@override
void initState() {
super.initState();
_accountsReaction = reaction(
(_) => accountListViewModel.accounts
(_) => widget.accountListViewModel.accounts
.map((account) => "${account.id}:${account.label}:${account.balance}")
.join(","),
(_) {
if (!mounted) return;
loadCards();
if (mounted) unawaited(loadCards());
},
);
WidgetsBinding.instance.addPostFrameCallback((_) => unawaited(_initialize()));
}
WidgetsBinding.instance.addPostFrameCallback((_) async {
await widget.dashboardViewModel.loadCardDesigns();
if (!mounted) return;
loadCards();
Future<void> _initialize() async {
await widget.dashboardViewModel.loadCardDesigns();
if (!mounted) return;
await _bringActiveAccountToFront();
if (!mounted || !_isMultiAccountsEnabled || _items.isEmpty) {
return;
}
if (!_isMultiAccountsEnabled) return;
final activeId = accountListViewModel.selectedAccount?.id;
for (int i = 0; i < _items.length - 1; i++) {
if (activeId != null && _items[i].accountListItem.id == activeId) {
final lastIndex = _items.length - 1;
final temp = _items[i];
_items[i] = _items[lastIndex];
_items[lastIndex] = temp;
await saveCardOrder();
await widget.dashboardViewModel.loadCardDesigns();
loadCards();
break;
}
}
});
final educationPage = AccountEducationPage(
settingsStore: widget.dashboardViewModel.settingsStore,
);
if (!educationPage.isDismissed) {
await educationPage.show(context);
}
}
@override
void dispose() {
_accountsReaction?.call();
accountListViewModel.reload();
saveCardOrder().then((value) => widget.dashboardViewModel.loadCardDesigns());
super.dispose();
}
void loadCards() {
final allAccounts = accountListViewModel.accounts;
final visible = widget.dashboardViewModel.visibleAccounts;
int get _walletInfoId => widget.dashboardViewModel.wallet.walletInfo.internalId;
if (visible.isEmpty && _items.isNotEmpty) return;
Future<void> _bringActiveAccountToFront() async {
await loadCards();
_items.clear();
if (!_isMultiAccountsEnabled) {
if (visible.isNotEmpty) {
final account = visible.first;
final realIndex = allAccounts.indexWhere((a) => a.id == account.id);
final design = (realIndex >= 0 &&
realIndex < widget.dashboardViewModel.cardDesigns.length)
? widget.dashboardViewModel.cardDesigns[realIndex]
: CardDesign.genericDefault;
_items.add(AccountCustomizerListItem(
card: BalanceCard(
accountName: account.label,
accountIndex: account.id,
balance: account.balance ?? "0.00",
accountBalance: account.balance ?? "0.00",
designSwitchDuration: Duration.zero,
assetName: _assetName,
capitalizeAssetName: _capitalizeAssetName,
selected: true,
width: cardWidth,
design: design,
),
order: realIndex >= 0 ? realIndex : 0,
accountListItem: account,
));
}
if (mounted) setState(() {});
final activeAccount =
widget.accountListViewModel.accounts.firstWhereOrNull((account) => account.isSelected);
if (activeAccount == null || _items.isEmpty) {
return;
}
for (int i = 0; i < allAccounts.length; i++) {
final realIndex = widget.dashboardViewModel.cardOrder[i];
final index = _items.indexWhere((item) => item.accountListItem.id == activeAccount.id);
if (index == -1 || index == _items.length - 1 || !mounted) {
return;
}
if (realIndex == null || realIndex < 0 || realIndex >= allAccounts.length) {
// db order broken.
reset();
break;
reorder(index, _items.length);
await saveCardOrder();
await widget.dashboardViewModel.loadCardDesigns();
}
Future<void> loadCards() async {
if (!mounted) return;
final accounts = widget.accountListViewModel.accounts;
final unnamedAccount = S.of(context).unnamed_account;
final resolvedCardWidth = cardWidth;
final walletCurrency = widget.dashboardViewModel.wallet.currency;
final styleSettings = await BalanceCardStyleSettings.getAll(_walletInfoId);
final layout = BalanceCardLayout.resolve(
accountIndices: accounts.map((account) => account.id).toList(),
settings: styleSettings,
);
final List<AccountCustomizerListItem> newItems = [];
for (int position = 0; position < layout.visible.length; position++) {
final accountIndex = layout.visible[position];
final account = accounts.firstWhereOrNull((item) => item.id == accountIndex);
if (account == null) {
continue;
}
_items.add(AccountCustomizerListItem(
final setting = layout.settingFor(accountIndex);
final isFrontCard = position == layout.visible.length - 1;
final accountLabel = account.label.trim().isEmpty ? unnamedAccount : account.label;
newItems.add(
AccountCustomizerListItem(
card: BalanceCard(
accountName: allAccounts[realIndex].label,
accountIndex: allAccounts[realIndex].id,
balance: allAccounts[realIndex].balance ?? "0.00",
accountBalance: allAccounts[realIndex].balance ?? "0.00",
accountName: "${account.id + 1}. $accountLabel",
accountBalance: account.balance,
fiatBalance:
widget.dashboardViewModel.balanceViewModel.accountFiatBalance(account) ?? "",
designSwitchDuration: Duration.zero,
assetName: _assetName,
capitalizeAssetName: _capitalizeAssetName,
selected: i == allAccounts.length - 1,
width: cardWidth,
design: widget.dashboardViewModel.cardDesigns[realIndex],
onCustomizeTapped: isFrontCard ? _openCardCustomizer : null,
selected: isFrontCard,
width: resolvedCardWidth,
design: CardDesign.fromStyleSettings(setting, walletCurrency),
),
order: realIndex,
accountListItem: allAccounts[realIndex]));
accountListItem: account,
settings: setting,
),
);
}
if (mounted) {
setState(() {});
setState(() {
_items
..clear()
..addAll(newItems);
_hasArchivedAccounts = layout.hidden.isNotEmpty;
_loading = false;
});
}
if (layout.needsRepair) {
await BalanceCardStyleSettings.setVisibleOrder(_walletInfoId, layout.orders);
}
}
@override
Widget build(BuildContext context) {
final showResetButton = _isMultiAccountsEnabled && _items.length > 1;
final showAccountsToggle = widget.dashboardViewModel.canToggleMultiAccounts;
final isToggleEnabled = widget.dashboardViewModel.isMultiAccountsEnabled;
if (_items.isEmpty && !showAccountsToggle) return const SizedBox.shrink();
return Container(
decoration: BoxDecoration(
Widget build(BuildContext context) => Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.vertical(top: Radius.circular(24))),
child: Column(
children: [
ModalTopBar(
title: S.of(context).wallet_accounts,
leadingIcon: const Icon(Icons.close),
leadingSemanticLabel: S.of(context).close,
onLeadingPressed: Navigator.of(context).maybePop,
trailingIcon: showResetButton ? const Icon(Icons.refresh) : null,
trailingSemanticLabel: S.of(context).reset,
onTrailingPressed: showResetDialog,
),
const SizedBox(height: 24),
if (showAccountsToggle)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: NewListSections(
sections: {
"": [
ListItemToggle(
keyValue: S.of(context).multiple_accounts,
label: S.of(context).multiple_accounts,
value: isToggleEnabled,
onChanged: (val) async {
await widget.dashboardViewModel.setMultiAccountsEnabled(val);
if (!mounted) return;
loadCards();
}),
],
},
),
),
if (_isMultiAccountsEnabled && _items.isNotEmpty)
Expanded(
child: Column(
borderRadius: const BorderRadius.vertical(top: Radius.circular(24)),
),
child: Column(
children: [
ModalTopBar(
title: S.of(context).accounts,
leadingIcon: const Icon(Icons.close),
leadingSemanticLabel: S.of(context).close,
onLeadingPressed: Navigator.of(context).maybePop,
trailingWidget: Row(
mainAxisSize: MainAxisSize.min,
spacing: 8,
children: [
Padding(
padding: const EdgeInsets.symmetric(vertical: 24.0),
child: Text(
S.of(context).account_customizer_desc,
style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
),
ModernButton(
semanticLabel: S.of(context).accounts_help,
icon: const Icon(Icons.question_mark),
size: 36,
iconSize: 19,
onPressed: () => AccountEducationPage(
settingsStore: widget.dashboardViewModel.settingsStore,
).show(context),
),
Expanded(
child: Stack(
children: [
ReorderableListView.builder(
padding: const EdgeInsets.only(bottom: 196),
scrollController: ModalScrollController.of(context),
onReorder: reorder,
proxyDecorator: (child, index, animation) => AnimatedBuilder(
animation: animation,
builder: (context, _) {
final animValue = Curves.easeOutCubic.transform(animation.value);
final scale = lerpDouble(1, 1.05, animValue)!;
return Opacity(
opacity: 1 - animValue.clamp(0.0, 0.1),
child: Center(
child: SizedBox(
width: cardWidth,
child: Transform.scale(
scale: scale,
child: child,
),
),
),
);
},
child: _items[index].card,
),
itemCount: _items.length,
itemBuilder: (context, int index) {
final card = _items[index].card;
final selectedItemIndex = _items.length - 1;
return Container(
key: ValueKey(index),
child: Semantics(
button: true,
selected: selectedItemIndex == index,
label: _items[index].accountListItem.label,
onTap: () => reorder(index, _items.length),
child: GestureDetector(
excludeFromSemantics: true,
onTap: () => reorder(index, _items.length),
child: Align(
alignment: Alignment.topCenter,
heightFactor: _kStackVisibleFactor,
child: card,
),
),
),
);
},
),
SafeArea(
child: Padding(
padding: const EdgeInsets.only(bottom: 50),
child: Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Material(
color: Colors.transparent,
child: MergeSemantics(
child: Semantics(
button: true,
child: InkWell(
borderRadius: BorderRadius.circular(999999),
onTap: _showAddAccountModal,
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(999999),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 18),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 8,
children: [
Icon(
Icons.add,
size: 28,
color: Theme.of(context).colorScheme.primary,
),
Text(
S.of(context).add_account,
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.w500,
),
)
],
),
),
),
),
),
),
),
),
),
),
),
],
if (_isMultiAccountsEnabled)
ModernButton.svg(
semanticLabel: S.of(context).archived_accounts,
svgPath: "assets/new-ui/archived.svg",
size: 36,
iconSize: 19,
backgroundColor:
_hasArchivedAccounts ? Theme.of(context).colorScheme.primary : null,
iconColor:
_hasArchivedAccounts ? Theme.of(context).colorScheme.onPrimary : null,
onPressed: _openArchivedAccounts,
),
),
],
),
),
],
),
);
}
if (widget.dashboardViewModel.canToggleMultiAccounts)
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: NewListSections(sections: {
"": [
ListItemToggle(
keyValue: S.of(context).multiple_accounts,
label: S.of(context).multiple_accounts,
value: _isMultiAccountsEnabled,
onChanged: (value) async {
await widget.dashboardViewModel.setMultiAccountsEnabled(value);
if (mounted) await _initialize();
},
),
],
}),
),
if (_isMultiAccountsEnabled)
Padding(
padding: const EdgeInsets.symmetric(vertical: 24, horizontal: 18),
child: Text(
S.of(context).account_customizer_desc,
textAlign: TextAlign.center,
style: TextStyle(color: Theme.of(context).colorScheme.onSurfaceVariant),
),
),
Expanded(
child: !_isMultiAccountsEnabled
? const SizedBox.shrink()
: _loading
? const Center(child: CupertinoActivityIndicator())
: _items.isEmpty
? const SizedBox.shrink()
: _AccountCards(
items: _items,
cardWidth: cardWidth,
onReorder: reorder,
onAddAccount: _showAddAccountModal,
),
),
],
),
);
bool _checkReadyToManage() {
if (widget.dashboardViewModel.wallet.type == WalletType.bitcoin) {
return true;
}
if (widget.dashboardViewModel.status is! SyncedSyncStatus) {
showDialog(
context: context,
@@ -380,33 +298,48 @@ class _WalletAccountsPageState extends State<WalletAccountsPage> {
}
Future<void> _showAddAccountModal() async {
if (!_checkReadyToManage()) return;
final createViewModel = getIt.get<WalletAccountEditOrCreateViewModel>();
final res = await showCupertinoModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
builder: (context) => Material(
child: AccountCreationModal(
viewModel: createViewModel,
),
));
if (res != null && res is bool && res == true) {
await accountListViewModel.reload();
await Future<void>.delayed(Duration.zero);
final accounts = accountListViewModel.accounts;
if (accounts.isNotEmpty) {
final newestAccount = accounts.reduce((a, b) => a.id > b.id ? a : b);
await accountListViewModel.select(newestAccount);
}
await widget.dashboardViewModel.loadCardDesigns();
loadCards();
if (mounted) setState(() {});
if (!_checkReadyToManage()) {
return;
}
final modal = AccountCreationModal(viewModel: widget.accountEditOrCreateViewModel);
final res = await showCupertinoModalBottomSheet(
context: context,
backgroundColor: Colors.transparent,
expand: true,
enableDrag: false,
builder: (_) => Material(child: modal),
);
if (res == true && mounted) {
await widget.accountListViewModel.reload();
final accounts = widget.accountListViewModel.accounts;
if (accounts.isNotEmpty) {
await widget.accountListViewModel.select(
accounts.reduce((a, b) => a.id > b.id ? a : b),
);
}
await widget.dashboardViewModel.loadCardDesigns();
await loadCards();
await saveCardOrder();
}
}
Future<void> _openArchivedAccounts() async {
await Navigator.of(context).push<void>(
CupertinoPageRoute(
builder: (context) => Material(
child: HiddenAccountsPage(
accountListViewModel: widget.accountListViewModel,
dashboardViewModel: widget.dashboardViewModel,
),
),
),
);
if (!mounted) {
return;
}
await widget.dashboardViewModel.loadCardDesigns();
await loadCards();
}
Future<void> _openCardCustomizer() async {
@@ -414,49 +347,34 @@ class _WalletAccountsPageState extends State<WalletAccountsPage> {
return;
}
await CardCustomizer.show(
final account = _items.last.accountListItem;
await widget.accountListViewModel.select(account);
if (!mounted) return;
final archived = await CardCustomizer.show(
context: context,
dashboardViewModel: widget.dashboardViewModel,
lightningMode: widget.dashboardViewModel.lightningMode,
asModalSheet: false,
onSaved: _reloadAccountsAndCards,
account: account,
canHide: _items.length > 1,
asPage: true,
);
}
Future<void> _reloadAccountsAndCards() async {
await accountListViewModel.reload();
if (archived && _items.length > 1) {
final nextAccount = _items[_items.length - 2].accountListItem;
await widget.accountListViewModel.select(
widget.accountListViewModel.accounts
.firstWhereOrNull((item) => item.id == nextAccount.id) ??
nextAccount,
);
}
await widget.accountListViewModel.reload();
await widget.dashboardViewModel.loadCardDesigns();
if (!mounted) return;
loadCards();
}
void _onCardsReordered(int oldRealIndex, int newRealIndex) {
final accounts = accountListViewModel.accounts;
if (oldRealIndex < 0 ||
newRealIndex < 0 ||
oldRealIndex >= accounts.length ||
newRealIndex >= accounts.length) {
if (!mounted) {
return;
}
final oldAccountId = accounts[oldRealIndex].id;
final newAccountId = accounts[newRealIndex].id;
final from = _items.indexWhere((item) => item.accountListItem.id == oldAccountId);
final to = _items.indexWhere((item) => item.accountListItem.id == newAccountId);
if (from < 0 || to < 0 || from == to) return;
final insertIndex = from < to ? to + 1 : to;
reorder(from, insertIndex);
saveCardOrder().then((_) {
if (!mounted) return;
widget.dashboardViewModel.loadCardDesigns();
});
await loadCards();
}
void reorder(int oldIndex, int newIndex) {
if (!_isMultiAccountsEnabled) return;
setState(() {
if (oldIndex < newIndex) {
newIndex -= 1;
@@ -468,100 +386,159 @@ class _WalletAccountsPageState extends State<WalletAccountsPage> {
// necessary to copy all this to keep constant constructor for BalanceCard
for (int i = 0; i < _items.length; i++) {
_items[i] = AccountCustomizerListItem(
card: BalanceCard(
accountName: _items[i].card.accountName,
balance: _items[i].card.balance,
accountIndex: _items[i].card.accountIndex,
accountBalance: _items[i].card.accountBalance,
assetName: _items[i].card.assetName,
capitalizeAssetName: _items[i].card.capitalizeAssetName,
designSwitchDuration: _items[i].card.designSwitchDuration,
onCustomizeTapped: (i == _items.length - 1) ? _openCardCustomizer : null,
selected: i == _items.length - 1,
width: _items[i].card.width,
design: _items[i].card.design,
),
order: i,
accountListItem: _items[i].accountListItem);
card: BalanceCard(
accountName: _items[i].card.accountName,
balance: _items[i].card.balance,
accountIndex: _items[i].card.accountIndex,
accountBalance: _items[i].card.accountBalance,
fiatBalance: _items[i].card.fiatBalance,
assetName: _items[i].card.assetName,
capitalizeAssetName: _items[i].card.capitalizeAssetName,
designSwitchDuration: _items[i].card.designSwitchDuration,
onCustomizeTapped: (i == _items.length - 1) ? _openCardCustomizer : null,
selected: i == _items.length - 1,
width: _items[i].card.width,
design: _items[i].card.design,
),
accountListItem: _items[i].accountListItem,
settings: _items[i].settings,
);
}
if (newIndex == _items.length - 1 || oldIndex == _items.length - 1) {
accountListViewModel.select(_items[_items.length - 1].accountListItem);
widget.accountListViewModel.select(_items[_items.length - 1].accountListItem);
}
}
Future<void> saveCardOrder() async {
if (!_isMultiAccountsEnabled) return;
for (int orderIndex = 0; orderIndex < _items.length; orderIndex++) {
final item = _items[orderIndex];
printV("${item.accountListItem.id}: $orderIndex");
final existing = await BalanceCardStyleSettings.get(
widget.dashboardViewModel.wallet.walletInfo.internalId,
item.accountListItem.id,
);
await BalanceCardStyleSettings.fromCardDesign(
walletInfoId: widget.dashboardViewModel.wallet.walletInfo.internalId,
accountIndex: item.accountListItem.id,
cardOrder: orderIndex,
design: item.card.design,
iconStyleIndex: existing?.iconStyleIndex ?? 0,
gradientIndexOverride: existing?.gradientIndex)
.insert();
}
}
Future<void> showResetDialog() async {
final res = await showPopUp(
context: context,
builder: (context) => AlertWithTwoActions(
alertTitle: S.of(context).reset,
alertContent: S.of(context).card_order_reset_desc,
leftButtonText: S.of(context).yes,
rightButtonText: S.of(context).no,
actionLeftButton: () {
Navigator.of(context).pop(true);
},
actionRightButton: Navigator.of(context).pop));
if (res != null && res is bool && res) {
reset();
}
}
Future<void> reset() async {
_items.clear();
final accounts = accountListViewModel.accounts;
for (int i = 0; i < accounts.length; i++) {
_items.add(AccountCustomizerListItem(
card: BalanceCard(
accountName: accounts[i].label,
accountIndex: accounts[i].id,
balance: accounts[i].balance ?? "0.00",
accountBalance: accounts[i].balance ?? "0.00",
assetName: _assetName,
capitalizeAssetName: _capitalizeAssetName,
selected: i == accounts.length - 1,
designSwitchDuration: const Duration(milliseconds: 200),
width: cardWidth,
design: i >= widget.dashboardViewModel.cardDesigns.length
? CardDesign.genericDefault
: widget.dashboardViewModel.cardDesigns[i],
),
order: i,
accountListItem: accounts[i]));
}
await saveCardOrder();
if (accounts.isNotEmpty) {
await accountListViewModel.select(accounts.last);
}
await widget.dashboardViewModel.loadCardDesigns();
if (mounted) setState(() {});
await BalanceCardStyleSettings.setOrder(_walletInfoId, {
for (int position = 0; position < _items.length; position++)
_items[position].accountListItem.id: position,
});
}
}
class _AccountCards extends StatelessWidget {
const _AccountCards({
required this.items,
required this.cardWidth,
required this.onReorder,
required this.onAddAccount,
});
static const double _kStackVisibleFactor = 0.2;
final List<AccountCustomizerListItem> items;
final double cardWidth;
final ReorderCallback onReorder;
final VoidCallback onAddAccount;
@override
Widget build(BuildContext context) => Stack(
children: [
ReorderableListView.builder(
padding: const EdgeInsets.only(bottom: 196),
scrollController: ModalScrollController.of(context),
onReorder: onReorder,
proxyDecorator: (child, index, animation) => AnimatedBuilder(
animation: animation,
builder: (context, _) {
final animValue = Curves.easeOutCubic.transform(animation.value);
final scale = lerpDouble(1, 1.05, animValue)!;
return Opacity(
opacity: 1 - animValue.clamp(0.0, 0.1),
child: Center(
child: SizedBox(
width: cardWidth,
child: Transform.scale(
scale: scale,
child: child,
),
),
),
);
},
child: items[index].card,
),
itemCount: items.length,
itemBuilder: (context, index) {
final selectedItemIndex = items.length - 1;
return Container(
key: ValueKey(items[index].accountListItem.id),
child: Semantics(
button: true,
selected: selectedItemIndex == index,
label: "${items[index].accountListItem.id + 1}. "
"${items[index].accountListItem.label.trim().isEmpty ? S.of(context).unnamed_account : items[index].accountListItem.label}",
onTap: () => onReorder(index, items.length),
child: GestureDetector(
excludeFromSemantics: true,
onTap: () {
onReorder(index, items.length);
},
child: Align(
alignment: Alignment.topCenter,
heightFactor: _kStackVisibleFactor,
child: items[index].card,
),
),
),
);
},
),
SafeArea(
child: Padding(
padding: const EdgeInsets.only(bottom: 50),
child: Align(
alignment: Alignment.bottomCenter,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 24),
child: Material(
color: Colors.transparent,
child: MergeSemantics(
child: Semantics(
button: true,
child: InkWell(
borderRadius: BorderRadius.circular(999999),
onTap: onAddAccount,
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(999999),
),
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 18),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
spacing: 8,
children: [
Icon(
Icons.add,
size: 28,
color: Theme.of(context).colorScheme.primary,
),
Text(
S.of(context).add_account,
style: TextStyle(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.w500,
),
),
],
),
),
),
),
),
),
),
),
),
),
),
],
);
}
@@ -1,38 +1,50 @@
import 'package:bloc/bloc.dart';
import "package:bloc/bloc.dart";
import "package:cake_wallet/entities/bitcoin_amount_display_mode.dart";
import "package:cake_wallet/bitcoin/bitcoin.dart";
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/wownero/wownero.dart';
import "package:cake_wallet/monero/monero.dart";
import "package:cake_wallet/wownero/wownero.dart" as wow;
import "package:cw_core/balance_card_style_settings.dart";
import 'package:cw_core/card_design.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/wallet_base.dart';
import "package:cw_core/card_design.dart";
import "package:cw_core/crypto_currency.dart";
import "package:cw_core/wallet_base.dart";
import "package:cw_core/wallet_type.dart";
import 'package:flutter/src/painting/gradient.dart';
import 'package:meta/meta.dart';
import "package:flutter/src/painting/gradient.dart";
import "package:meta/meta.dart";
part 'card_customizer_event.dart';
part 'card_customizer_state.dart';
part "card_customizer_event.dart";
part "card_customizer_state.dart";
class CardCustomizerBlocParams {
CardCustomizerBlocParams({required this.lightningMode, required this.canHide, this.amountDisplayMode});
final bool lightningMode;
final BitcoinAmountDisplayMode? amountDisplayMode;
final bool canHide;
}
class CardCustomizerBloc extends Bloc<CardCustomizerEvent, CardCustomizerState> {
final WalletBase _wallet;
final bool lightningMode;
final bool displaySats;
CardCustomizerBloc(this._wallet, {this.lightningMode = false, this.displaySats = false})
CardCustomizerBloc(this._wallet, {this.lightningMode = false, this.displaySats = false, this.canHide = false})
: super(CardCustomizerNotLoaded(
0, 0, [CardDesign.genericDefault], [], "", -1, displaySats, 0)) {
0, 0, [CardDesign.genericDefault], [], "", -1, displaySats, 0,),) {
on<_Init>(_init);
on<CardDesignSelected>(_onDesignSelected);
on<ColorSelected>(_onColorSelected);
on<IconStyleSelected>(_onIconStyleSelected);
on<DesignSaved>(_onDesignSaved);
on<AccountHidden>(_onAccountHidden);
on<AccountNameChanged>(_onAccountNameChanged);
add(_Init());
}
bool get _accountNameEnabled =>
!lightningMode && _wallet.walletInfo.isMultiAccountsEnabled == true;
final WalletBase _wallet;
final bool lightningMode;
final bool displaySats;
final bool canHide;
bool get _accountNameEnabled => !lightningMode &&
(_wallet.hasNativeAccounts || _wallet.walletInfo.isMultiAccountsEnabled == true);
List<Gradient> _updateAvailableColors(CardDesign currentDesign) {
final list = List<Gradient>.from(CardDesign.allGradients, growable: true);
@@ -42,8 +54,21 @@ class CardCustomizerBloc extends Bloc<CardCustomizerEvent, CardCustomizerState>
return list;
}
Future<BalanceCardStyleSettings?> _loadCurrentDesignSettings(int accountIndex) async {
return (await BalanceCardStyleSettings.get(_wallet.walletInfo.internalId, accountIndex));
Future<BalanceCardStyleSettings?> _loadCurrentDesignSettings(int accountIndex) =>
BalanceCardStyleSettings.get(_wallet.walletInfo.internalId, accountIndex);
Future<int> _cardOrderFor(BalanceCardStyleSettings? currentDesignSettings) async {
if (currentDesignSettings != null) {
return currentDesignSettings.cardOrder;
}
var highest = -1;
for (final setting in await BalanceCardStyleSettings.getAll(_wallet.walletInfo.internalId)) {
if (setting.cardOrder > highest) {
highest = setting.cardOrder;
}
}
return highest + 1;
}
List<CardDesign> _initAvailableDesigns({bool lightningMode = false}) {
@@ -53,8 +78,9 @@ class CardCustomizerBloc extends Bloc<CardCustomizerEvent, CardCustomizerState>
ret.add(CardDesign.gradientOnlyDesign);
ret.add(CardDesign.forCurrencyIcon(curr));
if (CardDesign.specialDesignsForCurrencies[curr] != null)
if (CardDesign.specialDesignsForCurrencies[curr] != null) {
ret.add(CardDesign.forCurrencySpecial(curr));
}
return ret;
}
@@ -76,8 +102,12 @@ class CardCustomizerBloc extends Bloc<CardCustomizerEvent, CardCustomizerState>
BalanceCardStyleSettings? settings,
List<CardIconPath> availableIconPaths,
) {
if (settings == null || availableIconPaths.isEmpty) return 0;
if (settings.iconStyleIndex >= availableIconPaths.length) return 0;
if (settings == null || availableIconPaths.isEmpty) {
return 0;
}
if (settings.iconStyleIndex >= availableIconPaths.length) {
return 0;
}
return settings.iconStyleIndex;
}
@@ -86,7 +116,7 @@ class CardCustomizerBloc extends Bloc<CardCustomizerEvent, CardCustomizerState>
return ret == -1 ? CardDesign.allGradients.length : ret;
}
void _init(_Init event, Emitter<CardCustomizerState> emit) async {
Future<void> _init(_Init event, Emitter<CardCustomizerState> emit) async {
final accountInfo = await _getCurrentAccountInfo();
final accountName = accountInfo.accountName;
final accountIndex = accountInfo.accountIndex;
@@ -108,9 +138,9 @@ class CardCustomizerBloc extends Bloc<CardCustomizerEvent, CardCustomizerState>
accountName,
accountIndex,
displaySats,
currentDesignSettings?.cardOrder ?? 0,
await _cardOrderFor(currentDesignSettings),
availableIconPaths: availableIconPaths,
selectedIconIndex: selectedIconIndex));
selectedIconIndex: selectedIconIndex,),);
}
Future<({String accountName, int accountIndex})> _getCurrentAccountInfo() async {
@@ -134,7 +164,7 @@ class CardCustomizerBloc extends Bloc<CardCustomizerEvent, CardCustomizerState>
}
if (_wallet.type == WalletType.wownero) {
final account = wownero!.getCurrentAccount(_wallet);
final account = wow.wownero!.getCurrentAccount(_wallet);
return (accountName: account.label, accountIndex: account.id);
}
@@ -160,7 +190,7 @@ class CardCustomizerBloc extends Bloc<CardCustomizerEvent, CardCustomizerState>
emit(state.copyWith(
selectedDesignIndex: event.newDesignIndex,
availableColors: newColors,
selectedColorIndex: newColorIndex));
selectedColorIndex: newColorIndex,),);
}
void _onColorSelected(ColorSelected event, Emitter<CardCustomizerState> emit) {
@@ -176,18 +206,20 @@ class CardCustomizerBloc extends Bloc<CardCustomizerEvent, CardCustomizerState>
}
Future<void> _onDesignSaved(DesignSaved event, Emitter<CardCustomizerState> emit) async {
final currentSettings = await _loadCurrentDesignSettings(state.accountIndex);
await BalanceCardStyleSettings.fromCardDesign(
walletInfoId: _wallet.walletInfo.internalId,
accountIndex: state.accountIndex,
cardOrder: state.cardOrder,
design: state.selectedDesign,
iconStyleIndex: state.selectedIconIndex,
gradientIndexOverride: state.selectedColorIndex)
.insert();
walletInfoId: _wallet.walletInfo.internalId,
accountIndex: state.accountIndex,
cardOrder: state.cardOrder,
design: state.selectedDesign,
iconStyleIndex: state.selectedIconIndex,
gradientIndexOverride: state.selectedColorIndex,
hidden: currentSettings?.hidden ?? false,
).insert();
await saveAccountName();
emit(CardCustomizerSaved(
emit(
CardCustomizerSaved(
state.selectedDesignIndex,
state.selectedColorIndex,
state.availableDesigns,
@@ -197,7 +229,34 @@ class CardCustomizerBloc extends Bloc<CardCustomizerEvent, CardCustomizerState>
state.displaySats,
state.cardOrder,
availableIconPaths: state.availableIconPaths,
selectedIconIndex: state.selectedIconIndex));
selectedIconIndex: state.selectedIconIndex,
),
);
}
Future<void> _onAccountHidden(AccountHidden event, Emitter<CardCustomizerState> emit) async {
await BalanceCardStyleSettings.fromCardDesign(
walletInfoId: _wallet.walletInfo.internalId,
accountIndex: state.accountIndex,
cardOrder: state.cardOrder,
design: state.selectedDesign,
iconStyleIndex: state.selectedIconIndex,
gradientIndexOverride: state.selectedColorIndex,
hidden: true,
).insert();
emit(
CardCustomizerSaved(
state.selectedDesignIndex,
state.selectedColorIndex,
state.availableDesigns,
state.availableColors,
state.accountName,
state.accountIndex,
state.displaySats,
state.cardOrder,
),
);
}
Future<void> saveAccountName() async {
@@ -205,12 +264,9 @@ class CardCustomizerBloc extends Bloc<CardCustomizerEvent, CardCustomizerState>
if (_wallet.type == WalletType.monero) {
await saveMoneroAccountName();
}
if (_wallet.type == WalletType.wownero) {
} else if (_wallet.type == WalletType.wownero) {
await saveWowneroAccountName();
}
if (_wallet.type == WalletType.bitcoin && !lightningMode) {
} else if (_wallet.type == WalletType.bitcoin) {
await saveBitcoinAccountName();
}
}
@@ -218,19 +274,21 @@ class CardCustomizerBloc extends Bloc<CardCustomizerEvent, CardCustomizerState>
Future<void> saveMoneroAccountName() async {
final MoneroAccountList moneroAccountList = monero!.getAccountList(_wallet);
await moneroAccountList.setLabelAccount(_wallet,
accountIndex: state.accountIndex, label: state.accountName);
accountIndex: state.accountIndex, label: state.accountName,);
await _wallet.save();
}
Future<void> saveWowneroAccountName() async {
final WowneroAccountList wowneroAccountList = wownero!.getAccountList(_wallet);
await wowneroAccountList.setLabelAccount(_wallet,
accountIndex: state.accountIndex, label: state.accountName);
final accountList = wow.wownero!.getAccountList(_wallet);
await accountList.setLabelAccount(
_wallet,
accountIndex: state.accountIndex,
label: state.accountName,
);
await _wallet.save();
}
Future<void> saveBitcoinAccountName() async {
await _wallet.walletInfo.renameAccount(
accountIndex: state.accountIndex,
@@ -1,4 +1,4 @@
part of 'card_customizer_bloc.dart';
part of "card_customizer_bloc.dart";
@immutable
sealed class CardCustomizerEvent {}
@@ -6,27 +6,29 @@ sealed class CardCustomizerEvent {}
class _Init extends CardCustomizerEvent {}
class CardDesignSelected extends CardCustomizerEvent {
final int newDesignIndex;
CardDesignSelected(this.newDesignIndex);
final int newDesignIndex;
}
class ColorSelected extends CardCustomizerEvent {
final int newColorIndex;
ColorSelected(this.newColorIndex);
final int newColorIndex;
}
class AccountNameChanged extends CardCustomizerEvent {
final String newAccountName;
AccountNameChanged(this.newAccountName);
final String newAccountName;
}
class DesignSaved extends CardCustomizerEvent {}
class IconStyleSelected extends CardCustomizerEvent {
final int iconIndex;
IconStyleSelected(this.iconIndex);
final int iconIndex;
}
class AccountHidden extends CardCustomizerEvent {}
@@ -0,0 +1,174 @@
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/new-ui/widgets/money/money_text.dart";
import "package:cake_wallet/src/widgets/cake_image_widget.dart";
import "package:cake_wallet/themes/core/theme_extension.dart";
import "package:cake_wallet/view_model/wallet_account_list/account_list_item.dart";
import "package:flutter/material.dart";
class ArchiveConfirmationContent extends StatelessWidget {
const ArchiveConfirmationContent({
required this.account,
required this.fiatBalance,
required this.isFunded,
});
final AccountListItem account;
final String? fiatBalance;
final bool isFunded;
@override
Widget build(BuildContext context) => Column(
mainAxisSize: MainAxisSize.min,
children: [
if (isFunded) ...[
Text(
S.of(context).archive_account_funds_title,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: context.customColors.warningOutlineColor,
),
),
const SizedBox(height: 20),
AccountFundsSummary(
account: account,
fiatBalance: fiatBalance,
borderColor: context.customColors.warningOutlineColor,
),
const SizedBox(height: 24),
Text(
S.of(context).archive_account_move_funds,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: context.customColors.warningOutlineColor,
),
),
const SizedBox(height: 20),
Text(
S.of(context).archive_account_funded_disclaimer,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
] else ...[
AccountSummary(account: account),
const SizedBox(height: 24),
Text(
S.of(context).archive_account_empty_disclaimer,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium,
),
const SizedBox(height: 12),
Text(
S.of(context).archive_account_restore_hint,
textAlign: TextAlign.center,
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],
],
);
}
class AccountSummary extends StatelessWidget {
const AccountSummary({required this.account});
final AccountListItem account;
@override
Widget build(BuildContext context) {
final label = account.label.trim();
return Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(18),
),
child: Row(
children: [
CakeImageWidget(
imageUrl: "assets/new-ui/account.svg",
width: 24,
height: 24,
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
const SizedBox(width: 12),
Expanded(
child: Text.rich(
TextSpan(
children: [
TextSpan(
text: "${account.id + 1}. ",
style: TextStyle(color: Theme.of(context).colorScheme.primary),
),
TextSpan(
text: label.isEmpty ? S.of(context).unnamed_account : label,
),
],
),
style: Theme.of(context).textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w500),
),
),
],
),
);
}
}
class AccountFundsSummary extends StatelessWidget {
const AccountFundsSummary({
required this.account,
required this.fiatBalance,
required this.borderColor,
});
final AccountListItem account;
final String? fiatBalance;
final Color borderColor;
@override
Widget build(BuildContext context) => Container(
width: double.infinity,
padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 12),
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainer,
border: Border.all(color: borderColor),
borderRadius: BorderRadius.circular(18),
),
child: Row(
children: [
CakeImageWidget(
imageUrl: account.balance.currency.iconPath ??
"assets/new-ui/crypto_full_icons/${account.balance.currency.name.toLowerCase()}.svg",
width: 24,
height: 24,
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
MoneyText(
account.balance,
fractionalDigits: account.balance.decimals,
style: Theme.of(context).textTheme.bodyMedium,
),
if (fiatBalance != null) ...[
const SizedBox(height: 2),
Text(
fiatBalance!,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],
],
),
),
],
),
);
}
@@ -0,0 +1,109 @@
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/src/widgets/cake_image_widget.dart";
import "package:cake_wallet/store/settings_store.dart";
import "package:cw_core/wallet_type.dart";
import "package:flutter/material.dart";
import "package:flutter_mobx/flutter_mobx.dart";
class AccountsPromo extends StatelessWidget {
const AccountsPromo({
required this.settingsStore,
required this.walletName,
required this.onTap,
super.key,
});
final SettingsStore settingsStore;
final String walletName;
final VoidCallback onTap;
static bool supportsWallet(WalletType walletType) => walletType == WalletType.bitcoin;
@override
Widget build(BuildContext context) => Observer(
builder: (_) {
if (settingsStore.accountsHomePromoDismissed) {
return const SizedBox.shrink();
}
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Column(
children: [
Material(
color: Theme.of(context).colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(18),
child: InkWell(
borderRadius: BorderRadius.circular(18),
onTap: onTap,
child: Container(
constraints: const BoxConstraints(minHeight: 64),
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10),
decoration: BoxDecoration(
border: Border.all(color: Theme.of(context).colorScheme.outlineVariant),
borderRadius: BorderRadius.circular(18),
),
child: Row(
children: [
const CakeImageWidget(
imageUrl: "assets/new-ui/settings_row_icons/accounts.svg",
width: 24,
height: 24,
),
const SizedBox(width: 12),
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
Text(
S.of(context).accounts_home_promo_title(walletName),
style: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontWeight: FontWeight.w500,
),
),
const SizedBox(height: 2),
Text(
S.of(context).accounts_home_promo_description,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Theme.of(context).colorScheme.onSurfaceVariant,
),
),
],
),
),
const SizedBox(width: 8),
Icon(
Icons.arrow_forward_ios,
size: 16,
color: Theme.of(context).colorScheme.primary,
),
],
),
),
),
),
const SizedBox(height: 12),
Semantics(
button: true,
child: InkWell(
borderRadius: BorderRadius.circular(8),
onTap: () => settingsStore.accountsHomePromoDismissed = true,
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
child: Text(
S.of(context).do_not_show_anymore,
style: Theme.of(context).textTheme.bodySmall?.copyWith(
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.w500,
),
),
),
),
),
],
),
);
},
);
}
@@ -1,7 +1,9 @@
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/src/widgets/cake_image_widget.dart';
import 'package:cw_core/card_design.dart';
import 'package:flutter/material.dart';
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/new-ui/widgets/money/money_text.dart";
import "package:cake_wallet/src/widgets/cake_image_widget.dart";
import "package:cw_core/amount/money.dart";
import "package:cw_core/card_design.dart";
import "package:flutter/material.dart";
class BalanceCardAction {
final String label;
@@ -22,7 +24,7 @@ class BalanceCard extends StatelessWidget {
this.borderRadius = 20,
this.selected = false,
this.accountName = "",
this.accountBalance = "",
this.accountBalance,
this.balance = "",
this.fiatBalance = "",
this.assetName = "",
@@ -37,7 +39,7 @@ class BalanceCard extends StatelessWidget {
final double width;
final double borderRadius;
final Gradient? gradient;
final String accountBalance;
final Money? accountBalance;
final String accountName;
final String balance;
final String fiatBalance;
@@ -62,7 +64,7 @@ class BalanceCard extends StatelessWidget {
final leadText = fiatFirst ? S.of(context).wallet_balance : accountName;
final bool showText = accountBalance.isNotEmpty ||
final bool showText = accountBalance != null ||
leadText.isNotEmpty ||
balance.isNotEmpty ||
fiatBalance.isNotEmpty ||
@@ -102,7 +104,7 @@ class BalanceCard extends StatelessWidget {
),
)
: const SizedBox.shrink(
key: ValueKey('svgFullOff'),
key: ValueKey("svgFullOff"),
),
),
Padding(
@@ -117,7 +119,7 @@ class BalanceCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.max,
children: [
if (leadText.isNotEmpty || accountBalance.isNotEmpty)
if (leadText.isNotEmpty || accountBalance != null)
Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -153,8 +155,10 @@ class BalanceCard extends StatelessWidget {
// readers, so drop it while it is invisible.
child: ExcludeSemantics(
excluding: selected,
child: Text(
child: MoneyText.optional(
accountBalance,
fractionalDigits: accountBalance?.decimals ?? 8,
showSymbol: false,
style: TextStyle(color: design.colors.textColor, fontSize: 14),
),
),
@@ -190,7 +194,13 @@ class BalanceCard extends StatelessWidget {
fontSize: 28,
fontWeight: FontWeight.w500,
letterSpacing: -0.4),
child: Text(fiatFirst ? fiatBalance : balance),
child: !fiatFirst && balance.isEmpty
? MoneyText.optional(
accountBalance,
fractionalDigits: accountBalance?.decimals ?? 8,
showSymbol: false,
)
: Text(fiatFirst ? fiatBalance : balance),
),
AnimatedDefaultTextStyle(
duration: designSwitchDuration,
@@ -270,7 +280,7 @@ class BalanceCard extends StatelessWidget {
child: _CornerSvgIcon(design: design, iconWidth: iconWidth),
)
: const SizedBox.shrink(
key: ValueKey('svgIconOff'),
key: ValueKey("svgIconOff"),
),
),
],
@@ -1,4 +1,6 @@
import 'dart:math';
import 'package:cake_wallet/core/utilities.dart';
import 'package:cw_core/balance_card_layout.dart';
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/di.dart';
@@ -9,7 +11,6 @@ import 'package:cake_wallet/new-ui/modal_navigator.dart';
import 'package:cake_wallet/new-ui/pages/send_page.dart';
import 'package:cake_wallet/new-ui/widgets/buy_sell/buy_sell_selector_modal.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/utils/feature_flag.dart';
import 'package:cake_wallet/utils/payment_request.dart';
import 'package:cake_wallet/utils/responsive_layout_util.dart';
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
@@ -60,9 +61,9 @@ class _CardsViewState extends State<CardsView> {
_selectedIndex = _fallbackSelectedIndex;
_cardOrderReaction = reaction(
(_) => widget.dashboardViewModel.cardOrder.values.toList(),
(_) => setState(() {
_selectedIndex = _fallbackSelectedIndex;
}),
(_) {
if (mounted) setState(() => _selectedIndex = _fallbackSelectedIndex);
},
);
}
@@ -96,20 +97,18 @@ class _CardsViewState extends State<CardsView> {
final isSelected = _selectedIndex == visualIndex;
final accounts = widget.accountListViewModel?.accounts;
final cardLabel = (!_hideAccountInfo && accounts != null && realIndex < accounts.length)
? accounts[realIndex].label
: S.of(context).balance;
final account = accounts?.firstWhereOrNull((account) => account.id == realIndex);
final cardLabel = !_hideAccountInfo && account != null ? account.label : S.of(context).balance;
void onCardTap() {
Future<void> onCardTap() async {
// printV(visualIndex);
if (compactMode && visualIndex != 0) {
widget.onCompactModeBackgroundCardsTapped();
} else if (!compactMode) {
setState(() {
if (widget.accountListViewModel != null && !widget.lightningMode)
widget.accountListViewModel!.select(widget.accountListViewModel!.accounts[realIndex]);
_selectedIndex = visualIndex;
});
if (account != null && !_hideAccountInfo) {
await widget.accountListViewModel!.select(account);
}
if (mounted) setState(() => _selectedIndex = visualIndex);
}
}
@@ -149,10 +148,8 @@ class _CardsViewState extends State<CardsView> {
onTap: onCardTap,
onLongPress: onCardLongPress,
child: Observer(builder: (_) {
if (realIndex >= (widget.accountListViewModel?.accounts.length ?? 1)) {
return Container();
}
final account = widget.accountListViewModel?.accounts[realIndex];
final account = widget.accountListViewModel?.accounts
.firstWhereOrNull((account) => account.id == realIndex);
// The second balance should always be the lightning balance
// printV(widget.dashboardViewModel.balanceViewModel.formattedBalances.first.availableBalance);
@@ -180,25 +177,17 @@ class _CardsViewState extends State<CardsView> {
// the card designs is empty if widget gets built before it loads.
// should get populated before user sees anything
final CardDesign cardDesign;
if (widget.dashboardViewModel.cardDesigns.isEmpty ||
realIndex >= widget.dashboardViewModel.cardDesigns.length)
cardDesign = CardDesign.genericDefault;
else if (widget.lightningMode)
// the lightning design is always the last one (after all bitcoin accounts)
cardDesign = widget.dashboardViewModel.cardDesigns.last;
else
cardDesign = widget.dashboardViewModel.cardDesigns[realIndex];
final designIndex = widget.dashboardViewModel.cardAccountIndices.indexOf(
widget.lightningMode ? -2 : realIndex,
);
final cardDesign = designIndex < 0 ||
designIndex >= widget.dashboardViewModel.cardDesigns.length
? CardDesign.genericDefault
: widget.dashboardViewModel.cardDesigns[designIndex];
final String accountName;
final String accountBalance;
if (account == null || _hideAccountInfo) {
accountName = "";
accountBalance = "";
} else {
accountName = account.label;
accountBalance = account.balance ?? "0.00";
}
final showAccount = account != null && !_hideAccountInfo;
final accountName = showAccount ? account.label : "";
final accountBalance = showAccount ? account.balance : null;
final assetName = widget.dashboardViewModel.balanceViewModel.showCombinedBalance
? ""
@@ -288,28 +277,13 @@ class _CardsViewState extends State<CardsView> {
}
int _visibleCardsCount() {
if (widget.dashboardViewModel.wallet.type != WalletType.bitcoin) {
return widget.dashboardViewModel.cardDesigns.length;
}
if (widget.lightningMode || !widget.dashboardViewModel.isMultiAccountsEnabled) {
return 1;
}
return widget.accountListViewModel?.accounts.length ?? 1;
}
int? _visualIndexForSelectedAccount(Map<int, int> order) {
final vm = widget.accountListViewModel;
if (vm == null || _hideAccountInfo) return null;
final selectedId = vm.selectedAccount?.id;
final realIndex = vm.accounts.indexWhere((a) => a.id == selectedId);
if (realIndex < 0) return null;
for (final entry in order.entries) {
if (entry.value == realIndex) return entry.key;
if (entry.value == selectedId) return entry.key;
}
return null;
}
@@ -319,27 +293,15 @@ class _CardsViewState extends State<CardsView> {
final parentWidth = MediaQuery.of(context).size.width;
final children = <Widget>[];
int numCards = _visibleCardsCount();
if (numCards == 0) numCards = 1;
if (_selectedIndex >= numCards) {
_selectedIndex = 0;
}
Map<int, int> order = widget.dashboardViewModel.cardOrder.length != numCards
? Map<int, int>.fromEntries(
List.generate(numCards, (i) => MapEntry(i, i)),
)
: widget.dashboardViewModel.cardOrder;
for (int i = min(numCards - 1, maxCards); i >= 0; i--) {
int visualIndex = (_selectedIndex - i + numCards) % numCards;
if (order[visualIndex] == null) {
order = Map<int, int>.fromEntries(
List.generate(numCards, (i) => MapEntry(i, i)),
);
}
final stack = _hideAccountInfo
? const [0]
: BalanceCardLayout.stackFromOrder(widget.dashboardViewModel.cardOrder);
if (stack.isEmpty) return const SizedBox.shrink();
final numCards = stack.length;
if (_selectedIndex < 0 || _selectedIndex >= numCards) {
_selectedIndex = numCards - 1;
}
final order = {for (int i = 0; i < stack.length; i++) i: stack[i]};
final followIndex = _visualIndexForSelectedAccount(order);
if (followIndex != null) _selectedIndex = followIndex;
@@ -461,4 +423,4 @@ class _CardsViewState extends State<CardsView> {
);
}
}
}
}
@@ -16,6 +16,7 @@ class ModalTopBar extends StatelessWidget {
this.bottomText,
this.leadingWidget,
this.trailingWidget,
this.titleLeadingWidget,
this.leadingSemanticLabel,
this.trailingSemanticLabel}) {
if (leadingIcon != null && leadingWidget != null) {
@@ -36,6 +37,7 @@ class ModalTopBar extends StatelessWidget {
final Widget? trailingIcon;
final Widget? leadingWidget;
final Widget? trailingWidget;
final Widget? titleLeadingWidget;
/// Accessible name for the leading chrome button. Required (and must be
/// non-empty) whenever a [leadingIcon] is supplied, because the icon alone
@@ -53,6 +55,51 @@ class ModalTopBar extends StatelessWidget {
@override
Widget build(BuildContext context) {
final hasBottomText = bottomText != null && bottomText!.isNotEmpty;
final titleContent = Column(
mainAxisSize: MainAxisSize.min,
children: [
AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
child: Semantics(
key: ValueKey(title),
header: title.isNotEmpty,
// Android reads the heading from headingLevel since the
// Flutter 3.41 engine; header: alone only covers iOS.
headingLevel: title.isNotEmpty ? 1 : null,
child: titleLeadingWidget == null
? Text(
title,
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
fontSize: hasBottomText ? 16 : 18,
),
)
: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
spacing: 12,
children: [
ExcludeSemantics(child: titleLeadingWidget),
Flexible(
child: Text(
title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: Theme.of(context).textTheme.headlineMedium?.copyWith(
fontSize: hasBottomText ? 16 : 18,
),
),
),
],
),
),
),
if (hasBottomText)
Text(
bottomText!,
style: TextStyle(fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant),
),
],
);
return Padding(
padding: padding ?? EdgeInsets.all(18),
child: Stack(
@@ -60,36 +107,14 @@ class ModalTopBar extends StatelessWidget {
children: [
Positioned(
top: hasBottomText ? -4 : 6,
left: titleLeadingWidget == null ? null : buttonSize + 8,
right: titleLeadingWidget == null ? null : buttonSize + 8,
child: Row(
mainAxisSize: MainAxisSize.max,
mainAxisAlignment: MainAxisAlignment.center,
spacing: 4,
children: [
Column(
children: [
AnimatedSwitcher(
duration: const Duration(milliseconds: 200),
child: Semantics(
key: ValueKey(title),
header: title.isNotEmpty,
// Android reads the heading from headingLevel since the
// Flutter 3.41 engine; header: alone only covers iOS.
headingLevel: title.isNotEmpty ? 1 : null,
child: Text(
title,
style: TextStyle(
fontSize: hasBottomText ? 16 : 18, fontWeight: FontWeight.w600),
),
),
),
if (hasBottomText)
Text(
bottomText!,
style: TextStyle(
fontSize: 12, color: Theme.of(context).colorScheme.onSurfaceVariant),
),
],
),
if (titleLeadingWidget == null) titleContent else Expanded(child: titleContent),
if (subtitle != null && subtitle!.isNotEmpty)
Text(subtitle!,
style: Theme.of(context)
+2 -5
View File
@@ -129,7 +129,6 @@ import "package:cake_wallet/view_model/dashboard/nft_send_view_model.dart";
import 'package:cake_wallet/view_model/dashboard/nft_view_model.dart';
import 'package:cake_wallet/view_model/dashboard/sign_view_model.dart';
import 'package:cake_wallet/view_model/hardware_wallet/hardware_wallet_view_model.dart';
import 'package:cake_wallet/view_model/wallet_account_list/account_list_item.dart';
import 'package:cake_wallet/view_model/hardware_wallet/trezor_connect_view_model.dart';
import 'package:cake_wallet/view_model/node_list/node_create_or_edit_view_model.dart';
import 'package:cake_wallet/view_model/wallet_groups_display_view_model.dart';
@@ -138,7 +137,6 @@ import 'package:cake_wallet/view_model/wallet_hardware_restore_view_model.dart';
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
import 'package:cake_wallet/wallet_types.g.dart';
import 'package:cw_core/nano_account.dart';
import 'package:cw_core/node.dart';
import 'package:cw_core/transaction_info.dart';
import 'package:cw_core/unspent_coin_type.dart';
@@ -848,9 +846,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
case Routes.walletAccountsPage:
final dashboardViewModel = settings.arguments as DashboardViewModel;
return handleRouteWithPlatformAwareness(
(_) => getIt.get<WalletAccountsPage>(param1: dashboardViewModel),
);
final page = getIt.get<WalletAccountsPage>(param1: dashboardViewModel);
return handleRouteWithPlatformAwareness((_) => page);
case Routes.managePowNodes:
return MaterialPageRoute<void>(builder: (_) => getIt.get<ManageNodesPage>(param1: true));
@@ -1,11 +1,8 @@
import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_regular_row.dart';
import 'package:cake_wallet/entities/new_ui_entities/list_item/list_item_toggle.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/new-ui/pages/coin_control_page.dart';
import 'package:cake_wallet/new-ui/widgets/modal_header.dart';
import 'package:cake_wallet/new-ui/widgets/modal_page_wrapper.dart';
import 'package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart';
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/src/screens/base_page.dart';
import 'package:cake_wallet/src/widgets/new_list_row/new_list_section.dart';
import 'package:cake_wallet/view_model/settings/privacy_settings_view_model.dart';
@@ -75,29 +72,6 @@ class PrivacyPage extends BasePage {
_privacySettingsViewModel.setUseLightning(val);
}),
],
"": [
if (_privacySettingsViewModel.hasSilentPaymentsScanning)
ListItemRegularRow(
iconPath: "assets/new-ui/settings_row_icons/silent-payments.svg",
keyValue: "silent_payments",
label: S.of(context).silent_payments,
onTap: () =>
Navigator.of(context).pushNamed(Routes.silentPaymentsSettings)),
if (_privacySettingsViewModel.hasMWEB)
ListItemRegularRow(
iconPath: "assets/new-ui/settings_row_icons/mweb.svg",
keyValue: "mweb",
label: "MWEB",
onTap: () => Navigator.of(context).pushNamed(Routes.mwebSettings)),
if (_privacySettingsViewModel.hasCoinControl)
ListItemRegularRow(
iconPath: "assets/new-ui/settings_row_icons/coin-control.svg",
keyValue: "coin_control",
label: "Coin Control",
onTap: () => Navigator.of(context).pushNamed(Routes.unspentCoinsList,
arguments:
CoinControlPageArgs(canEdit: false, coinTypeToSpendFrom: null))),
],
}),
],
);
@@ -1,20 +1,16 @@
import "package:cake_wallet/core/execution_state.dart";
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/new-ui/widgets/modal_grab_handle.dart";
import "package:cake_wallet/new-ui/widgets/new_primary_button.dart";
import "package:cake_wallet/new-ui/widgets/receive_page/receive_top_bar.dart";
import "package:cake_wallet/src/widgets/alert_with_one_action.dart";
import "package:cake_wallet/src/widgets/cake_image_widget.dart";
import "package:cake_wallet/view_model/wallet_account_list/account_edit_or_create_view_model.dart";
import "package:cw_core/generate_name.dart";
import "package:flutter/material.dart";
import "package:flutter/services.dart";
import "package:flutter_mobx/flutter_mobx.dart";
class AccountCreationModal extends StatefulWidget {
const AccountCreationModal({
required this.viewModel,
super.key,
});
const AccountCreationModal({required this.viewModel, super.key});
final WalletAccountEditOrCreateViewModel viewModel;
@@ -26,14 +22,59 @@ class _AccountCreationModalState extends State<AccountCreationModal> {
static const int maxAccountNameLength = 25;
final TextEditingController _controller = TextEditingController();
bool _loading = false;
@override
void initState() {
super.initState();
_controller.text = widget.viewModel.label;
_controller.addListener(() {
widget.viewModel.label = _controller.text;
});
bool get _canContinue =>
_controller.text.trim().isNotEmpty && _controller.text.length <= maxAccountNameLength;
Future<void> _generateAccountName() async {
final generatedName = await generateName();
if (!mounted) {
return;
}
setState(() => _controller.text = generatedName.length > maxAccountNameLength
? generatedName.substring(0, maxAccountNameLength)
: generatedName);
}
Future<void> _save() async {
if (_loading || !_canContinue) {
return;
}
setState(() => _loading = true);
widget.viewModel.label = _controller.text;
late final String errorMessage;
try {
await widget.viewModel.save();
if (!mounted) {
return;
}
final state = widget.viewModel.state;
if (state is ExecutedSuccessfullyState) {
Navigator.of(context).pop(true);
return;
}
errorMessage = state is FailureState ? state.error : S.of(context).error_while_processing;
} catch (error) {
errorMessage = error.toString();
}
if (!mounted) {
return;
}
setState(() => _loading = false);
await showDialog<void>(
context: context,
builder: (dialogContext) => AlertWithOneAction(
alertTitle: S.of(dialogContext).error,
alertContent: errorMessage,
buttonText: S.of(dialogContext).ok,
buttonAction: Navigator.of(dialogContext).pop,
),
);
}
@override
@@ -42,105 +83,117 @@ class _AccountCreationModalState extends State<AccountCreationModal> {
super.dispose();
}
Future<void> _onSubmit() async {
if (widget.viewModel.state is IsExecutingState) return;
if (_controller.text.trim().isEmpty || _controller.text.length > maxAccountNameLength) return;
await widget.viewModel.save();
if (!mounted) return;
if (widget.viewModel.state is ExecutedSuccessfullyState) {
Navigator.of(context).pop(true);
}
}
@override
Widget build(BuildContext context) => Container(
Widget build(BuildContext context) => PopScope(
canPop: !_loading,
child: _buildContent(context),
);
Widget _buildContent(BuildContext context) => Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.vertical(top: Radius.circular(30))),
color: Theme.of(context).colorScheme.surface,
borderRadius: const BorderRadius.vertical(top: Radius.circular(30)),
),
child: SafeArea(
top: false,
child: Padding(
padding: EdgeInsets.only(bottom: MediaQuery.of(context).viewInsets.bottom),
padding: EdgeInsets.only(bottom: MediaQuery.viewInsetsOf(context).bottom),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
const ModalGrabHandle(),
ModalTopBar(
title: widget.viewModel.isEdit
? S.of(context).edit_account
: S.of(context).create_account,
title: S.of(context).create_account,
trailingIcon: const Icon(Icons.close),
trailingSemanticLabel: S.of(context).close,
onTrailingPressed: Navigator.of(context).maybePop,
),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 18),
child: Column(
spacing: 50,
children: [
const SizedBox(),
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(16),
Expanded(
child: SingleChildScrollView(
padding: const EdgeInsets.fromLTRB(18, 32, 18, 24),
child: Column(
spacing: 24,
children: [
const CakeImageWidget(
imageUrl: "assets/new-ui/account_education/create_account.svg",
width: 125,
height: 125,
),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
maxLength: maxAccountNameLength,
inputFormatters: [
LengthLimitingTextInputFormatter(maxAccountNameLength),
],
decoration: InputDecoration(
hintText: S.of(context).account_name,
counterText: "",
),
),
),
Padding(
padding: const EdgeInsets.all(12),
child: GestureDetector(
onTap: () async {
final generated = await generateName();
_controller.text = generated.length > maxAccountNameLength
? generated.substring(0, maxAccountNameLength)
: generated;
},
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHigh,
borderRadius: BorderRadius.circular(5)),
child: CakeImageWidget(
imageUrl: "assets/new-ui/randomize.svg",
colorFilter: ColorFilter.mode(
Theme.of(context).colorScheme.primary, BlendMode.srcIn),
Text(
S.of(context).account_creation_description,
textAlign: TextAlign.center,
style: TextStyle(
color: Theme.of(context).colorScheme.onSurfaceVariant,
fontSize: 14,
),
),
Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainer,
borderRadius: BorderRadius.circular(16),
),
child: Row(
children: [
Expanded(
child: TextField(
controller: _controller,
maxLength: maxAccountNameLength,
inputFormatters: [
LengthLimitingTextInputFormatter(maxAccountNameLength)
],
textInputAction: TextInputAction.done,
onChanged: (_) => setState(() {}),
decoration: InputDecoration(
hintText: S.of(context).account_name,
counterText: "",
),
),
),
)
],
),
),
ValueListenableBuilder<TextEditingValue>(
valueListenable: _controller,
builder: (context, value, _) => Observer(
builder: (_) => NewPrimaryButton(
onPressed: _onSubmit,
text: S.of(context).continue_text,
color: Theme.of(context).colorScheme.primary,
textColor: Theme.of(context).colorScheme.onPrimary,
disabled: value.text.trim().isEmpty ||
value.text.length > maxAccountNameLength,
isLoading: widget.viewModel.state is IsExecutingState,
Padding(
padding: const EdgeInsets.all(12),
child: Semantics(
button: true,
label: S.of(context).generate_name,
onTap: _generateAccountName,
child: ExcludeSemantics(
child: GestureDetector(
onTap: _generateAccountName,
child: Container(
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.surfaceContainerHigh,
borderRadius: BorderRadius.circular(5),
),
child: CakeImageWidget(
imageUrl: "assets/new-ui/randomize.svg",
colorFilter: ColorFilter.mode(
Theme.of(context).colorScheme.primary,
BlendMode.srcIn,
),
),
),
),
),
),
),
],
),
),
),
const SizedBox(),
],
],
),
),
)
),
Padding(
padding: const EdgeInsets.fromLTRB(18, 0, 18, 12),
child: SizedBox(
width: double.infinity,
child: NewPrimaryButton(
onPressed: _save,
text: S.of(context).continue_text,
color: Theme.of(context).colorScheme.primary,
textColor: Theme.of(context).colorScheme.onPrimary,
isLoading: _loading,
disabled: !_canContinue,
),
),
),
],
),
),
+17
View File
@@ -153,6 +153,7 @@ abstract class SettingsStoreBase with Store {
required this.hasEnabledMwebBefore,
required this.mwebNodeUri,
required this.mwebAdDismissed,
required this.accountsHomePromoDismissed,
required this.balanceHideCounter,
required this.zcashMigrationModalViewed,
required bool initialEnableAutomaticNodeSwitching,
@@ -313,6 +314,9 @@ abstract class SettingsStoreBase with Store {
reaction((_) => mwebAdDismissed,
(val) => sharedPreferences.setBool(PreferencesKey.mwebAdDismissed, val));
reaction((_) => accountsHomePromoDismissed,
(val) => sharedPreferences.setBool(PreferencesKey.accountsHomePromoDismissed, val));
priority.observe((change) {
final String? key;
switch (change.key) {
@@ -1105,6 +1109,9 @@ abstract class SettingsStoreBase with Store {
@observable
bool mwebAdDismissed;
@observable
bool accountsHomePromoDismissed;
@observable
bool zcashMigrationModalViewed;
@@ -1191,6 +1198,12 @@ abstract class SettingsStoreBase with Store {
Future<void> setShouldShowReceiveWarning(bool value) async =>
_sharedPreferences.setBool(PreferencesKey.shouldShowReceiveWarning, value);
bool isEducationDismissed(String educationId) =>
_sharedPreferences.getBool(PreferencesKey.educationDismissed(educationId)) ?? false;
Future<void> dismissEducation(String educationId) =>
_sharedPreferences.setBool(PreferencesKey.educationDismissed(educationId), true);
static Future<SettingsStore> load(
{required bool isBitcoinBuyEnabled,
FiatCurrency initialFiatCurrency = FiatCurrency.usd,
@@ -1692,6 +1705,9 @@ abstract class SettingsStoreBase with Store {
final mwebAdDismissed =
await sharedPreferences.getBool(PreferencesKey.mwebAdDismissed) ?? false;
final accountsHomePromoDismissed =
sharedPreferences.getBool(PreferencesKey.accountsHomePromoDismissed) ?? false;
final balanceHideCounter =
await sharedPreferences.getInt(PreferencesKey.balanceHideCounter) ?? 0;
@@ -1815,6 +1831,7 @@ abstract class SettingsStoreBase with Store {
shouldShowRepWarning: shouldShowRepWarning,
initialBuiltinTor: builtinTor,
mwebAdDismissed: mwebAdDismissed,
accountsHomePromoDismissed: accountsHomePromoDismissed,
balanceHideCounter: balanceHideCounter,
zcashMigrationModalViewed: zcashMigrationModalViewed
);
@@ -11,6 +11,7 @@ import 'package:cake_wallet/evm/evm.dart';
import 'package:cake_wallet/solana/solana.dart';
import 'package:cake_wallet/tron/tron.dart';
import 'package:cake_wallet/zano/zano.dart';
import 'package:cake_wallet/view_model/wallet_account_list/account_list_item.dart';
import 'package:cw_core/amount/money.dart';
import 'package:cw_core/crypto_amount_format.dart';
import 'package:cw_core/transaction_history.dart';
@@ -546,6 +547,21 @@ abstract class BalanceViewModelBase with Store {
}
}
String? accountFiatBalance(AccountListItem account) {
if (isFiatDisabled) {
return null;
}
final fiat = settingsStore.fiatCurrency.title;
final value = savedDisplayMode == BalanceDisplayMode.hiddenBalance
? "●●●●●"
: calculateFiatAmount(
price: price,
cryptoAmount: account.balance.toString(),
).withLocalSeperator(settingsStore.languageCode);
return "$value $fiat";
}
String _getFiatBalance({required double price, Money? cryptoAmount}) {
if (cryptoAmount == null) {
return '0.00';
@@ -9,6 +9,7 @@ import 'package:cake_wallet/view_model/wallet_account_list/wallet_account_list_v
import 'package:cake_wallet/view_model/wallet_account_list/account_list_item.dart';
import 'package:cw_core/account.dart';
import 'package:cake_wallet/view_model/dashboard/date_section_item.dart';
import "package:cw_core/balance_card_layout.dart";
import "package:cw_core/balance_card_style_settings.dart";
import 'package:cake_wallet/core/trade_monitor.dart';
import 'package:cake_wallet/entities/auto_generate_subaddress_status.dart';
@@ -110,7 +111,8 @@ abstract class DashboardViewModelBase with Store {
showDecredInfoCard = wallet.type == WalletType.decred &&
(sharedPreferences.getBool(PreferencesKey.showDecredInfoCard) ?? true);
showSeedBackupReminder = wallet.walletInfo.showSeedBackupReminder;
isMultiAccountsEnabled = wallet.walletInfo.isMultiAccountsEnabled == true;
isMultiAccountsEnabled =
wallet.hasNativeAccounts || wallet.walletInfo.isMultiAccountsEnabled == true;
name = wallet.name;
type = wallet.type;
isShowFirstYatIntroduction = false;
@@ -426,72 +428,86 @@ abstract class DashboardViewModelBase with Store {
}
}
List<int> get cardAccountIndices {
if (wallet.type == WalletType.monero) {
return monero!.getAccountList(wallet).accounts.map((account) => account.id).toList();
}
if (wallet.type == WalletType.wownero) {
return wow.wownero!.getAccountList(wallet).accounts.map((account) => account.id).toList();
}
if (wallet.type == WalletType.bitcoin) {
final accounts = accountListViewModel?.accounts;
return [
if (accounts == null || accounts.isEmpty) 0 else ...accounts.map((account) => account.id),
-2,
];
}
return const [-1];
}
@action
Future<void> loadCardDesigns() async {
final walletCardStyleSettings =
await BalanceCardStyleSettings.getAll(wallet.walletInfo.internalId);
final btcAccounts =
wallet.type == WalletType.bitcoin ? await wallet.walletInfo.getAccounts() : null;
final lightningCardIndex = btcAccounts?.length;
if (wallet.type == WalletType.bitcoin) {
await accountListViewModel?.reload();
}
final accountIndices = cardAccountIndices;
final settings = await BalanceCardStyleSettings.getAll(wallet.walletInfo.internalId);
if (wallet.type != WalletType.bitcoin && accountIndices.contains(0) &&
!settings.any((setting) => setting.accountIndex == 0)) {
final primarySettings = settings.where((setting) => setting.accountIndex == -1)
.firstOrNull?.copyWith(accountIndex: 0);
if (primarySettings != null) {
await primarySettings.insert();
settings.add(primarySettings);
}
}
final layout = BalanceCardLayout.resolve(
accountIndices: accountIndices.where((index) => index != -2).toList(),
settings: settings,
);
int numAccounts = 1;
cardDesigns
..clear()
..addAll(accountIndices.map((accountIndex) => CardDesign.fromStyleSettings(
settings.where((setting) => setting.accountIndex == accountIndex).firstOrNull,
accountIndex == -2 ? CryptoCurrency.btcln : wallet.currency,
)));
cardOrder = {
for (int position = 0; position < layout.visible.length; position++)
position: layout.visible[position],
}.asObservable();
if (layout.needsRepair) {
await BalanceCardStyleSettings.setVisibleOrder(wallet.walletInfo.internalId, layout.orders);
}
if (isMultiAccountsEnabled && !lightningMode && layout.visible.isNotEmpty &&
!layout.visible.contains(accountListViewModel?.selectedAccount?.id)) {
final visibleAccount = accountListViewModel?.accounts
.where((account) => account.id == layout.visible.last).firstOrNull;
if (visibleAccount != null) {
await accountListViewModel!.select(visibleAccount);
}
}
}
int get currentCardAccountIndex {
if (wallet.type == WalletType.monero) {
numAccounts = monero!.getAccountList(wallet).accounts.length;
} else if (wallet.type == WalletType.wownero) {
numAccounts = wow.wownero!.getAccountList(wallet).accounts.length;
} else if (wallet.type == WalletType.bitcoin) {
numAccounts = btcAccounts!.length + 1; // adding 1 for the lightning account
return monero!.getCurrentAccount(wallet).id;
}
final usesAccountIndices = wallet.type == WalletType.bitcoin || balanceViewModel.hasAccounts;
cardDesigns.clear();
final newOrder = <int, int>{};
final orderableCount = (wallet.type == WalletType.bitcoin) ? numAccounts - 1 : numAccounts;
for (int i = 0; i < numAccounts; i++) {
late final int index;
final isLightning = wallet.type == WalletType.bitcoin && i == lightningCardIndex;
if (isLightning) {
index = -2;
} else if (usesAccountIndices) {
index = i;
} else {
index = -1;
}
final setting = walletCardStyleSettings.where((e) => e.accountIndex == index).firstOrNull ??
(index == 0 && wallet.type != WalletType.bitcoin
? walletCardStyleSettings.where((e) => e.accountIndex == -1).firstOrNull
: null);
final curr = isLightning ? CryptoCurrency.btcln : wallet.currency;
cardDesigns.add(CardDesign.fromStyleSettings(setting, curr));
if (isLightning) {
continue;
}
if (setting?.cardOrder != null &&
setting!.cardOrder >= 0 &&
setting.cardOrder < orderableCount) {
newOrder[setting.cardOrder] = i;
}
if (wallet.type == WalletType.wownero) {
return wow.wownero!.getCurrentAccount(wallet).id;
}
// making sure ALL accounts have numbers, even the ones that existed before this feature was a thing
for (int i = 0; i < orderableCount; i++) {
if (!newOrder.containsValue(i)) {
int free = 0;
while (newOrder.containsKey(free)) {
free++;
}
newOrder[free] = i;
}
if (wallet.type == WalletType.bitcoin) {
return lightningMode ? -2 : wallet.walletInfo.currentAccountIndex;
}
cardOrder = newOrder.asObservable();
return -1;
}
CardDesign get currentCardDesign {
final designIndex = cardAccountIndices.indexOf(currentCardAccountIndex);
return cardDesigns.isEmpty || designIndex >= cardDesigns.length
? CardDesign.fromStyleSettings(null, wallet.currency)
: cardDesigns[designIndex == -1 ? 0 : designIndex];
}
void _transactionDisposerCallback(int _) async {
@@ -925,7 +941,9 @@ abstract class DashboardViewModelBase with Store {
List<AccountListItem> get visibleAccounts {
final all = accountListViewModel?.accounts;
if (all == null || all.isEmpty) return const <AccountListItem>[];
if (isMultiAccountsEnabled) return all.toList(growable: false);
if (isMultiAccountsEnabled) {
return all.where((account) => cardOrder.containsValue(account.id)).toList(growable: false);
}
final primary = all.where((a) => a.id == 0).firstOrNull ?? all.first;
return <AccountListItem>[primary];
}
@@ -1353,7 +1371,13 @@ abstract class DashboardViewModelBase with Store {
// Lightning belongs to the primary account only
if (lightningMode) {
unawaited(_selectPrimaryAccount());
unawaited(_selectPrimaryAccount().then((_) async {
if (!lightningMode && isMultiAccountsEnabled) {
await loadCardDesigns();
}
}));
} else {
unawaited(loadCardDesigns());
}
}
@@ -1382,7 +1406,8 @@ abstract class DashboardViewModelBase with Store {
this.wallet = wallet;
type = wallet.type;
name = wallet.name;
isMultiAccountsEnabled = wallet.walletInfo.isMultiAccountsEnabled == true;
isMultiAccountsEnabled =
wallet.hasNativeAccounts || wallet.walletInfo.isMultiAccountsEnabled == true;
_onAccountChangeReaction?.reaction.dispose();
_onAccountChangeReaction = null;
+1 -10
View File
@@ -444,16 +444,7 @@ abstract class SendViewModelBase extends WalletChangeListenerViewModel with Stor
@computed
bool get hasCoinControl =>
[
WalletType.bitcoin,
WalletType.litecoin,
WalletType.monero,
WalletType.wownero,
WalletType.decred,
WalletType.bitcoinCash,
WalletType.dogecoin
].contains(wallet.type) &&
coinTypeToSpendFrom != UnspentCoinType.lightning;
wallet.hasCoinControl && coinTypeToSpendFrom != UnspentCoinType.lightning;
@computed
bool get hasFees => feesViewModel.hasFees && coinTypeToSpendFrom != UnspentCoinType.lightning;
@@ -54,15 +54,7 @@ abstract class PrivacySettingsViewModelBase with Store {
].contains(_wallet.type);
@computed
bool get hasCoinControl => [
WalletType.bitcoin,
WalletType.litecoin,
WalletType.monero,
WalletType.wownero,
WalletType.decred,
WalletType.bitcoinCash,
WalletType.dogecoin
].contains(_wallet.type);
bool get hasCoinControl => _wallet.hasCoinControl;
bool get isMoneroWallet => _wallet.type == WalletType.monero;
@@ -1,8 +1,17 @@
import "package:cw_core/amount/money.dart";
class AccountListItem {
AccountListItem({required this.label, required this.id, this.balance, this.isSelected = false});
AccountListItem({
required this.label,
required this.id,
required this.balance,
this.isSelected = false,
});
final String label;
final int id;
final bool isSelected;
final String? balance;
final Money balance;
bool get isFunded => balance.sign > 0;
}
@@ -1,24 +1,22 @@
import 'dart:async';
import "dart:async";
import 'package:cake_wallet/bitcoin/bitcoin.dart';
import 'package:cake_wallet/core/amount_parsing_proxy.dart';
import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/view_model/wallet_account_list/account_list_item.dart';
import 'package:cake_wallet/view_model/wallet_account_list/wallet_account_list_view_model.dart';
import 'package:collection/collection.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:mobx/mobx.dart';
import "package:cake_wallet/bitcoin/bitcoin.dart";
import "package:cake_wallet/view_model/wallet_account_list/account_list_item.dart";
import "package:cake_wallet/view_model/wallet_account_list/wallet_account_list_view_model.dart";
import "package:collection/collection.dart";
import "package:cw_core/amount/money.dart";
import "package:cw_core/crypto_currency.dart";
import "package:cw_core/wallet_base.dart";
import "package:cw_core/wallet_info.dart";
import "package:mobx/mobx.dart";
part 'bitcoin_account_list_view_model.g.dart';
part "bitcoin_account_list_view_model.g.dart";
class BitcoinAccountListViewModel = BitcoinAccountListViewModelBase
with _$BitcoinAccountListViewModel;
abstract class BitcoinAccountListViewModelBase with Store implements WalletAccountListViewModel {
BitcoinAccountListViewModelBase(this._wallet, this.settingsStore) {
BitcoinAccountListViewModelBase(this._wallet) {
unawaited(_loadAccounts());
reaction(
@@ -26,14 +24,8 @@ abstract class BitcoinAccountListViewModelBase with Store implements WalletAccou
(snapshot) => unawaited(_refreshBalances(snapshot)),
equals: const MapEquality<int, Object>().equals,
);
reaction(
(_) => settingsStore.balanceDisplayMode,
(_) => unawaited(_recomputeBalanceStrings()),
);
}
final SettingsStore settingsStore;
final WalletBase _wallet;
List<WalletInfoAccount>? _cachedStoredAccounts;
@@ -71,14 +63,6 @@ abstract class BitcoinAccountListViewModelBase with Store implements WalletAccou
return _runLoad(() async => cached);
}
@action
Future<void> _recomputeBalanceStrings() {
final cached = _cachedStoredAccounts;
if (cached == null) return _loadAccounts();
return _runLoad(() async => cached);
}
Future<void> _runLoad(Future<List<WalletInfoAccount>> Function() fetch) {
final inProgress = _loadAccountsFuture;
if (inProgress != null) {
@@ -99,7 +83,7 @@ abstract class BitcoinAccountListViewModelBase with Store implements WalletAccou
.map((account) => AccountListItem(
id: account.accountIndex,
label: account.label,
balance: _balanceForAccount(account.accountIndex),
balance: _fullBalance(account.accountIndex),
isSelected: account.accountIndex == currentAccountIndex,
))
.toList();
@@ -115,16 +99,12 @@ abstract class BitcoinAccountListViewModelBase with Store implements WalletAccou
});
}
Money _fullBalance(int accountIndex) {
final balance = bitcoin!.balanceForAccount(_wallet, accountIndex);
return balance.confirmed + balance.unconfirmed;
}
@override
@action
Future<void> reload() => _loadAccounts();
String _balanceForAccount(int accountIndex) {
if (settingsStore.balanceDisplayMode == BalanceDisplayMode.hiddenBalance) {
return '●●●●●●';
}
final balance = bitcoin!.balanceForAccount(_wallet, accountIndex);
return AmountParsingProxy(settingsStore.displayAmountsInSatoshi).asDisplayString(balance.available);
}
}
@@ -2,6 +2,7 @@ import 'dart:math';
import 'package:cake_wallet/view_model/wallet_account_list/account_edit_or_create_view_model.dart';
import 'package:cake_wallet/wownero/wownero.dart';
import 'package:cw_core/balance_card_layout.dart';
import 'package:cw_core/balance_card_style_settings.dart';
import 'package:cw_core/card_design.dart';
import 'package:cw_core/wallet_base.dart';
@@ -36,7 +37,7 @@ abstract class MoneroAccountEditOrCreateViewModelBase
@observable
String label;
final MoneroAccountList _moneroAccountList;
final MoneroAccountList? _moneroAccountList;
final WowneroAccountList? _wowneroAccountList;
final AccountListItem? _accountListItem;
final WalletBase _wallet;
@@ -51,13 +52,22 @@ abstract class MoneroAccountEditOrCreateViewModelBase
return ret.isNotEmpty ? ret : CardDesign.allGradients;
}
Future<void> _saveRandomCardDesign() async {
Future<void> _saveRandomCardDesign(int accountIndex) async {
final gradients = await _getUsableCardGradients();
final accountIndices = _wallet.type == WalletType.monero
? _moneroAccountList!.accounts.map((account) => account.id).toList()
: _wowneroAccountList!.accounts.map((account) => account.id).toList();
final layout = BalanceCardLayout.resolve(
accountIndices: accountIndices,
settings: await BalanceCardStyleSettings.getAll(_wallet.walletInfo.internalId),
);
await BalanceCardStyleSettings.fromCardDesign(
walletInfoId: _wallet.walletInfo.internalId,
accountIndex: _moneroAccountList.accounts.length,
cardOrder: _moneroAccountList.accounts.length,
accountIndex: accountIndex,
cardOrder: layout.visible.length,
design: CardDesign.specialDesignsForCurrencies[_wallet.currency]!
.withGradient(gradients[Random().nextInt(gradients.length)]))
.insert();
@@ -67,7 +77,11 @@ abstract class MoneroAccountEditOrCreateViewModelBase
try {
state = IsExecutingState();
if (!isEdit) await _saveRandomCardDesign();
if (!isEdit) {
await _saveRandomCardDesign(_wallet.type == WalletType.monero
? _moneroAccountList!.accounts.length
: _wowneroAccountList!.accounts.length);
}
if (_wallet.type == WalletType.monero) {
await saveMonero();
@@ -84,13 +98,13 @@ abstract class MoneroAccountEditOrCreateViewModelBase
Future<void> saveMonero() async {
if (_accountListItem != null) {
await _moneroAccountList.setLabelAccount(
await _moneroAccountList!.setLabelAccount(
_wallet,
accountIndex: _accountListItem.id,
label: label,
);
} else {
await _moneroAccountList.addAccount(
await _moneroAccountList!.addAccount(
_wallet,
label: label,
);
@@ -1,22 +1,18 @@
import 'package:cake_wallet/entities/balance_display_mode.dart';
import 'package:cake_wallet/store/settings_store.dart';
import 'package:cake_wallet/view_model/wallet_account_list/wallet_account_list_view_model.dart';
import 'package:cake_wallet/wownero/wownero.dart';
import 'package:cw_core/crypto_currency.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:mobx/mobx.dart';
import 'package:cw_core/wallet_base.dart';
import 'package:cake_wallet/view_model/wallet_account_list/account_list_item.dart';
import 'package:cake_wallet/monero/monero.dart';
import "package:cake_wallet/monero/monero.dart";
import "package:cake_wallet/view_model/wallet_account_list/account_list_item.dart";
import "package:cake_wallet/view_model/wallet_account_list/wallet_account_list_view_model.dart";
import "package:cake_wallet/wownero/wownero.dart";
import "package:cw_core/crypto_currency.dart";
import "package:cw_core/wallet_base.dart";
import "package:cw_core/wallet_type.dart";
import "package:mobx/mobx.dart";
part 'monero_account_list_view_model.g.dart';
part "monero_account_list_view_model.g.dart";
class MoneroAccountListViewModel = MoneroAccountListViewModelBase with _$MoneroAccountListViewModel;
abstract class MoneroAccountListViewModelBase with Store implements WalletAccountListViewModel {
MoneroAccountListViewModelBase(this._wallet, this.settingsStore);
final SettingsStore settingsStore;
MoneroAccountListViewModelBase(this._wallet);
@override
AccountListItem? get selectedAccount => selected;
@@ -25,7 +21,6 @@ abstract class MoneroAccountListViewModelBase with Store implements WalletAccoun
@computed
List<AccountListItem> get accounts {
final hideBalance = settingsStore.balanceDisplayMode == BalanceDisplayMode.hiddenBalance;
if (_wallet.type == WalletType.monero) {
return monero!
.getAccountList(_wallet)
@@ -33,7 +28,7 @@ abstract class MoneroAccountListViewModelBase with Store implements WalletAccoun
.map((acc) => AccountListItem(
label: acc.label,
id: acc.id,
balance: hideBalance ? '●●●●●●' : acc.balance,
balance: monero!.getAccountFullBalance(acc.id),
isSelected: acc.id == monero!.getCurrentAccount(_wallet).id))
.toList();
}
@@ -45,19 +40,16 @@ abstract class MoneroAccountListViewModelBase with Store implements WalletAccoun
.map((acc) => AccountListItem(
label: acc.label,
id: acc.id,
balance: hideBalance ? '●●●●●●' : acc.balance,
balance: wownero!.getAccountFullBalance(acc.id),
isSelected: acc.id == wownero!.getCurrentAccount(_wallet).id))
.toList();
}
throw Exception('Unexpected wallet type: ${_wallet.type} for monero');
throw Exception("Unexpected wallet type: ${_wallet.type} for monero");
}
@computed
AccountListItem get selected {
final currentId = monero!.getCurrentAccount(_wallet).id;
return accounts.firstWhere((item) => item.id == currentId);
}
AccountListItem get selected => accounts.firstWhere((item) => item.isSelected);
final WalletBase _wallet;
@@ -71,7 +63,7 @@ abstract class MoneroAccountListViewModelBase with Store implements WalletAccoun
_wallet,
item.id,
item.label,
item.balance,
item.balance.toString(),
);
}
@@ -80,7 +72,7 @@ abstract class MoneroAccountListViewModelBase with Store implements WalletAccoun
_wallet,
item.id,
item.label,
item.balance,
item.balance.toString(),
);
}
}
@@ -1,5 +1,5 @@
import 'package:cake_wallet/view_model/wallet_account_list/account_list_item.dart';
import 'package:cw_core/crypto_currency.dart';
import "package:cake_wallet/view_model/wallet_account_list/account_list_item.dart";
import "package:cw_core/crypto_currency.dart";
abstract class WalletAccountListViewModel {
List<AccountListItem> get accounts;
+6
View File
@@ -136,6 +136,12 @@ class CWWownero extends Wownero {
@override
WowneroAccountList getAccountList(Object wallet) => CWWowneroAccountList(wallet);
@override
Money getAccountFullBalance(int accountIndex) => Money.fromInt(
wownero_wallet_api.getFullBalance(accountIndex: accountIndex),
CryptoCurrency.wow,
);
@override
WowneroSubaddressList getSubaddressList(Object wallet) => CWWowneroSubaddressList(wallet);
+2
View File
@@ -292,8 +292,10 @@ flutter:
- assets/faq/
- assets/animation/
- assets/new-ui/
- assets/new-ui/account_education/
- assets/new-ui/icons/
- assets/new-ui/hero/
- assets/new-ui/network_icons/
- assets/new-ui/balance_card_icons/
- assets/new-ui/balance_card_backgrounds/
- assets/new-ui/settings_row_icons/
@@ -0,0 +1,10 @@
<svg width="309" height="48" viewBox="0 0 309 48" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect width="68.9935" height="47.7647" rx="8.4915" fill="#D7E2F7"/>
<path d="M35.1215 11.8378H38.2804V36.1235H34.7819V15.5741L29.0076 20.1255V16.4912L35.1215 11.8378Z" fill="#1D2541"/>
<line x1="73.2422" y1="22.8228" x2="115.7" y2="22.8228" stroke="#D7E2F7" stroke-width="2.12288" stroke-dasharray="3.18 6.37"/>
<rect x="121.003" y="1.06144" width="66.8706" height="45.6418" rx="7.43007" fill="#8C9FBB" stroke="#D7E2F7" stroke-width="2.12288"/>
<path d="M162.577 36.1235H146.884V33.3044L155.138 25.1185C156.134 24.1222 156.927 23.2504 157.516 22.5032C158.105 21.7333 158.512 21.02 158.739 20.3633C158.988 19.684 159.112 18.982 159.112 18.2574C159.112 17.0346 158.739 16.0609 157.991 15.3363C157.244 14.6117 156.225 14.2494 154.934 14.2494C153.712 14.2494 152.613 14.5664 151.64 15.2005C150.666 15.8345 149.772 16.8308 148.956 18.1895L146.647 15.9817C147.688 14.4192 148.911 13.2531 150.315 12.4832C151.719 11.6906 153.27 11.2944 154.968 11.2944C156.485 11.2944 157.799 11.5774 158.908 12.1435C160.041 12.7096 160.924 13.5135 161.558 14.5551C162.192 15.5741 162.509 16.7629 162.509 18.1215C162.509 19.1405 162.339 20.1142 161.999 21.0426C161.66 21.9484 161.071 22.9221 160.233 23.9637C159.418 25.0053 158.274 26.2507 156.802 27.7L151.3 33.2364H162.577V36.1235Z" fill="#1D2541"/>
<line x1="193.188" y1="22.8228" x2="235.645" y2="22.8228" stroke="#8C9FBB" stroke-width="2.12288" stroke-dasharray="3.18 6.37"/>
<rect x="240.952" y="1.06144" width="66.8706" height="45.6418" rx="7.43007" stroke="#8C9FBB" stroke-width="2.12288"/>
<path d="M265.677 32.2174L267.953 30.0097C268.836 31.323 269.765 32.2741 270.738 32.8628C271.712 33.4515 272.799 33.7459 273.999 33.7459C274.905 33.7459 275.731 33.5761 276.479 33.2364C277.248 32.8968 277.86 32.3986 278.313 31.7419C278.766 31.0626 278.992 30.2248 278.992 29.2284C278.992 27.9377 278.528 26.9074 277.599 26.1375C276.694 25.345 275.46 24.9487 273.897 24.9487H271.757V22.0276H273.897C275.233 22.0276 276.309 21.6653 277.124 20.9407C277.939 20.2161 278.347 19.299 278.347 18.1895C278.347 17.0346 277.95 16.0949 277.158 15.3703C276.388 14.623 275.38 14.2494 274.135 14.2494C273.003 14.2494 271.972 14.5438 271.044 15.1325C270.138 15.6986 269.278 16.6044 268.463 17.8498L266.187 15.5401C267.228 14.1362 268.429 13.0833 269.787 12.3813C271.169 11.6567 272.674 11.2944 274.305 11.2944C275.777 11.2944 277.09 11.5887 278.245 12.1775C279.4 12.7436 280.305 13.5475 280.962 14.5891C281.619 15.6081 281.947 16.7629 281.947 18.0536C281.947 19.2085 281.619 20.2274 280.962 21.1106C280.305 21.9937 279.4 22.6843 278.245 23.1825C277.09 23.6807 275.754 23.9297 274.237 23.9297L274.441 22.673C276.094 22.673 277.52 22.9447 278.72 23.4882C279.943 24.0316 280.894 24.8015 281.573 25.7979C282.253 26.7716 282.592 27.9377 282.592 29.2964C282.592 30.7229 282.23 31.991 281.505 33.1006C280.781 34.2101 279.785 35.0819 278.516 35.7159C277.271 36.35 275.822 36.667 274.169 36.667C272.38 36.667 270.761 36.2934 269.312 35.5461C267.885 34.7989 266.674 33.6893 265.677 32.2174Z" fill="#8C9FBB"/>
</svg>

After

Width:  |  Height:  |  Size: 3.0 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 75 KiB

@@ -0,0 +1,17 @@
<svg width="232" height="101" viewBox="0 0 232 101" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.0169 90.5868H85.5651C93.3237 90.5868 98.158 82.1708 94.2485 75.4692L58.9745 14.9991C55.0952 8.34926 45.4869 8.34926 41.6077 14.9991L6.33375 75.4692C2.42445 82.1708 7.25843 90.5868 15.0169 90.5868Z" fill="url(#paint0_linear_23582_541768)"/>
<path d="M37.3408 12.5029C43.129 2.58237 57.4632 2.58233 63.2514 12.5029V12.5045L98.5266 72.9739C104.36 82.9733 97.1454 95.5305 85.5697 95.5305H15.0225C3.44655 95.5305 -3.76722 82.973 2.06554 72.9739L37.3408 12.5029ZM58.9797 14.9955C55.1003 8.34625 45.4919 8.34629 41.6125 14.9955L6.33889 75.4664L5.99754 76.0992C2.83955 82.4729 7.20608 90.0758 14.3027 90.56L15.0225 90.5841H85.5697C93.0859 90.5841 97.8581 82.6855 94.5946 76.0992L94.2533 75.4664L58.9797 14.9955Z" fill="url(#paint1_linear_23582_541768)"/>
<path d="M50.2463 65.3789C52.9781 65.3789 55.1927 67.5935 55.1927 70.3253C55.1925 73.0569 52.978 75.2717 50.2463 75.2717H50.1964C47.4647 75.2717 45.2502 73.0569 45.25 70.3253C45.25 67.5935 47.4646 65.3789 50.1964 65.3789H50.2463ZM45.25 55.2462V40.1671C45.25 37.4353 47.4646 35.2207 50.1964 35.2207C52.9282 35.2207 55.1428 37.4353 55.1428 40.1671V55.2462C55.1427 57.9779 52.9281 60.1926 50.1964 60.1926C47.4646 60.1926 45.2501 57.9779 45.25 55.2462Z" fill="#312938"/>
<circle cx="181.066" cy="50.2961" r="50.2961" fill="#233461"/>
<path d="M162.369 76.8413C160.976 76.8413 159.785 76.3479 158.798 75.3611C157.811 74.3738 157.318 73.1835 157.318 71.7901V40.5003C156.498 40.0774 155.827 39.4764 155.305 38.6973C154.784 37.9182 154.523 37.0198 154.523 36.0023V28.8022C154.523 27.4089 155.017 26.2185 156.004 25.2312C156.991 24.2444 158.181 23.751 159.575 23.751H202.563C203.956 23.751 205.146 24.2444 206.134 25.2312C207.12 26.2185 207.614 27.4089 207.614 28.8022V36.0023C207.614 37.0198 207.353 37.9182 206.832 38.6973C206.311 39.4764 205.64 40.0774 204.82 40.5003V71.7901C204.82 73.1835 204.326 74.3738 203.339 75.3611C202.352 76.3479 201.162 76.8413 199.768 76.8413H162.369ZM161.509 41.0535V71.6559C161.509 71.9424 161.612 72.1796 161.818 72.3678C162.024 72.5559 162.28 72.65 162.584 72.65H199.768C200.019 72.65 200.225 72.5694 200.387 72.4083C200.548 72.2472 200.628 72.0411 200.628 71.7901V41.0535H161.509ZM159.575 36.8622H202.563C202.814 36.8622 203.02 36.7816 203.181 36.6205C203.342 36.4594 203.422 36.2533 203.422 36.0023V28.8022C203.422 28.5512 203.342 28.3452 203.181 28.184C203.02 28.0229 202.814 27.9423 202.563 27.9423H159.575C159.324 27.9423 159.118 28.0229 158.956 28.184C158.795 28.3452 158.715 28.5512 158.715 28.8022V36.0023C158.715 36.2533 158.795 36.4594 158.956 36.6205C159.118 36.7816 159.324 36.8622 159.575 36.8622ZM173.223 54.2996H188.914V50.2962H173.223V54.2996Z" fill="#91B0FF"/>
<defs>
<linearGradient id="paint0_linear_23582_541768" x1="50.2911" y1="10.0117" x2="50.8957" y2="104.323" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFC414"/>
<stop offset="1" stop-color="#FF9500"/>
</linearGradient>
<linearGradient id="paint1_linear_23582_541768" x1="50.2961" y1="10.0088" x2="50.2961" y2="90.5839" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFF8E4"/>
<stop offset="1" stop-color="#FFE9C4"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

@@ -0,0 +1,34 @@
<svg width="127" height="125" viewBox="0 0 127 125" fill="none" xmlns="http://www.w3.org/2000/svg">
<rect x="2.375" y="5.64893" width="122.5" height="82.351" rx="7.02815" fill="url(#paint0_linear_23582_540390)" stroke="url(#paint1_linear_23582_540390)" stroke-width="2.5"/>
<rect x="2.375" y="21.75" width="122.5" height="82.351" rx="7.02815" fill="url(#paint2_linear_23582_540390)" stroke="url(#paint3_linear_23582_540390)" stroke-width="2.5"/>
<rect x="2.375" y="37.8511" width="122.5" height="82.351" rx="7.02815" fill="#D9D9D9"/>
<rect x="2.375" y="37.8511" width="122.5" height="82.351" rx="7.02815" fill="url(#paint4_linear_23582_540390)"/>
<rect x="2.375" y="37.8511" width="122.5" height="82.351" rx="7.02815" stroke="url(#paint5_linear_23582_540390)" stroke-width="2.5"/>
<circle cx="104.875" cy="99.7261" r="9.375" fill="white" fill-opacity="0.2"/>
<defs>
<linearGradient id="paint0_linear_23582_540390" x1="63.625" y1="4.39893" x2="63.625" y2="89.2499" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFD000"/>
<stop offset="1" stop-color="#FFAA00"/>
</linearGradient>
<linearGradient id="paint1_linear_23582_540390" x1="63.625" y1="4.39893" x2="63.625" y2="89.2499" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFF5CB"/>
<stop offset="1" stop-color="#FFCD70"/>
</linearGradient>
<linearGradient id="paint2_linear_23582_540390" x1="63.625" y1="20.5" x2="63.625" y2="105.351" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF7C02"/>
<stop offset="1" stop-color="#FF5602"/>
</linearGradient>
<linearGradient id="paint3_linear_23582_540390" x1="63.625" y1="20.5" x2="63.625" y2="105.351" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFA048"/>
<stop offset="1" stop-color="#FF7F45"/>
</linearGradient>
<linearGradient id="paint4_linear_23582_540390" x1="63.625" y1="36.6011" x2="63.625" y2="121.452" gradientUnits="userSpaceOnUse">
<stop stop-color="#4EBEFF"/>
<stop offset="1" stop-color="#1D78FF"/>
</linearGradient>
<linearGradient id="paint5_linear_23582_540390" x1="63.625" y1="36.6011" x2="63.625" y2="121.452" gradientUnits="userSpaceOnUse">
<stop stop-color="#B4E2FF"/>
<stop offset="1" stop-color="#63A4FF"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.3 KiB

@@ -0,0 +1,43 @@
<svg width="213" height="213" viewBox="0 0 213 213" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_23582_541687)">
<path d="M200.302 60.4142C200.302 52.6224 200.279 49.141 199.185 46.1441C198.198 43.4378 196.591 40.9997 194.492 39.0262C192.168 36.8408 188.977 35.4475 181.815 32.378L118.297 5.1553C113.555 3.12296 111.433 2.22579 109.256 1.87017C107.286 1.54837 105.277 1.54837 103.307 1.87017C101.131 2.22579 99.0085 3.12297 94.2664 5.1553L30.7472 32.378C23.5853 35.4473 20.3951 36.8408 18.0711 39.0262C15.9725 40.9997 14.3649 43.4377 13.3777 46.1441C12.2847 49.141 12.261 52.6224 12.261 60.4142V92.2843C12.261 127.062 29.0565 159.698 57.3559 179.912L88.5524 202.196C95.3873 207.078 98.4573 209.237 101.752 210.072C104.725 210.825 107.839 210.825 110.812 210.072C114.106 209.237 117.176 207.078 124.011 202.196L155.207 179.912C183.507 159.698 200.302 127.062 200.302 92.2843V60.4142ZM201.942 92.2843L201.929 93.9381C201.406 128.624 184.442 161.045 156.161 181.246L124.964 203.53L122.593 205.22C117.397 208.909 114.423 210.849 111.215 211.661L110.606 211.805C107.757 212.433 104.806 212.433 101.958 211.805L101.348 211.661C98.1405 210.849 95.1665 208.909 89.9702 205.22L87.599 203.53L56.4025 181.246C27.6722 160.725 10.6211 127.591 10.6211 92.2843V60.4142C10.6211 52.7493 10.6208 48.916 11.8371 45.5815C12.845 42.8186 14.447 40.3135 16.5262 38.2404L16.9479 37.8315C19.5337 35.4 23.0563 33.8897 30.1012 30.8705L93.6205 3.64886C97.9964 1.77345 100.321 0.77691 102.589 0.333841L103.042 0.251633C105.188 -0.0988496 107.376 -0.0988537 109.521 0.251633C111.941 0.64704 114.275 1.64734 118.943 3.64779L182.462 30.8705C189.507 33.8897 193.03 35.4 195.615 37.8315C197.9 39.9804 199.651 42.6345 200.726 45.5815C201.942 48.916 201.942 52.7493 201.942 60.4142V92.2843Z" fill="#708BF4" fill-opacity="0.05"/>
<path d="M192.944 64.0372C192.944 56.8346 192.921 53.6479 191.921 50.9074C191.017 48.4277 189.544 46.1945 187.621 44.3862C185.496 42.3879 182.576 41.1113 175.956 38.274L117.324 13.145C112.941 11.2666 110.999 10.4467 109.008 10.1214C107.203 9.8265 105.362 9.82654 103.557 10.1214C101.567 10.4466 99.6243 11.2666 95.2413 13.145L36.6086 38.274C29.9886 41.1112 27.0698 42.388 24.9447 44.3862C23.0218 46.1944 21.5488 48.4277 20.6442 50.9074C19.6446 53.6479 19.6204 56.8346 19.6204 64.0372V93.456C19.6204 125.517 35.104 155.605 61.1932 174.24L89.9906 194.81C96.3082 199.323 99.1196 201.298 102.132 202.061C104.856 202.751 107.71 202.751 110.434 202.061C113.446 201.298 116.257 199.323 122.574 194.81L151.371 174.24C177.461 155.605 192.944 125.517 192.944 93.456V64.0372ZM194.584 93.456C194.584 126.047 178.845 156.631 152.325 175.575L123.527 196.144C117.322 200.576 114.22 202.793 110.836 203.65L110.274 203.783C107.644 204.362 104.92 204.362 102.291 203.783L101.729 203.65C98.7685 202.9 96.0225 201.11 91.2259 197.705L89.0372 196.145L60.2408 175.575C33.7205 156.631 17.9805 126.047 17.9805 93.456V64.0372C17.9805 57.4038 17.9808 53.8797 18.9061 50.9287L19.1036 50.3458C20.0339 47.7954 21.5114 45.4821 23.4308 43.5684L23.8205 43.1916C25.909 41.2276 28.66 39.9154 33.6716 37.7509L94.5954 11.6385C98.6349 9.90729 100.781 8.98656 102.874 8.57762L103.292 8.50288C105.272 8.17936 107.292 8.1794 109.272 8.50288C111.506 8.86788 113.661 9.79188 117.97 11.6385L176.603 36.7665C183.106 39.5534 186.357 40.9471 188.744 43.1916C190.854 45.1753 192.47 47.6254 193.462 50.3458C194.585 53.4239 194.584 56.962 194.584 64.0372V93.456Z" fill="#708BF4" fill-opacity="0.15"/>
<path d="M185.477 67.6681C185.477 61.0466 185.453 58.1785 184.555 55.717C183.739 53.48 182.41 51.4655 180.675 49.8343C178.766 48.0394 176.14 46.8855 170.054 44.2772L116.308 21.2439C112.279 19.5172 110.53 18.7805 108.742 18.4884C107.113 18.2224 105.452 18.2223 103.824 18.4884C102.036 18.7805 100.288 19.5173 96.2589 21.2439L42.5128 44.2772C36.4267 46.8855 33.8007 48.0394 31.8919 49.8343C30.1573 51.4655 28.8282 53.48 28.0121 55.717C27.1143 58.1785 27.0886 61.0466 27.0886 67.6681V94.6356C27.0887 123.946 41.2441 151.451 65.0945 168.487L91.4919 187.343C97.3001 191.492 99.8332 193.265 102.539 193.951C104.996 194.573 107.571 194.573 110.028 193.951C112.734 193.265 115.267 191.492 121.075 187.343L147.471 168.487C171.322 151.451 185.477 123.946 185.477 94.6356V67.6681ZM187.227 94.6356L187.216 96.0342C186.774 125.384 172.42 152.817 148.489 169.911L122.091 188.766L120.085 190.196C115.688 193.317 113.172 194.958 110.457 195.646C107.889 196.297 105.207 196.338 102.624 195.769L102.11 195.646C99.3952 194.958 96.8781 193.317 92.4805 190.196L64.0781 169.911C40.1477 152.817 25.7932 125.384 25.3505 96.0342L25.3398 94.6356V67.6681C25.3398 61.5882 25.3397 58.3577 26.1875 55.6529L26.369 55.118C27.2786 52.6244 28.7593 50.3779 30.693 48.5595C32.881 46.502 35.8619 45.2242 41.8231 42.6693L95.5702 19.6361C99.2733 18.0491 101.24 17.2052 103.159 16.8303L103.542 16.762C105.358 16.4654 107.209 16.4654 109.025 16.762C111.072 17.0966 113.047 17.9434 116.997 19.6361L170.743 42.6693C176.704 45.2241 179.685 46.5021 181.873 48.5595C183.807 50.3779 185.288 52.6243 186.198 55.118C187.227 57.9395 187.227 61.1827 187.227 67.6681V94.6356Z" fill="#708BF4" fill-opacity="0.5"/>
<path d="M67.908 164.248L91.9054 181.389C97.0763 185.082 99.6618 186.929 102.482 187.643C104.972 188.274 107.581 188.274 110.071 187.643C112.891 186.929 115.476 185.082 120.647 181.389L144.645 164.248C166.745 148.461 179.861 122.974 179.861 95.8152V71.2992C179.861 65.4031 179.861 62.4551 178.926 59.89C178.099 57.623 176.752 55.5811 174.994 53.928C173.005 52.0576 170.296 50.8963 164.876 48.5737L116.016 27.6335C112.425 26.0947 110.63 25.3252 108.768 25.021C107.118 24.7514 105.435 24.7514 103.785 25.021C101.923 25.3252 100.128 26.0947 96.5369 27.6335L47.6765 48.5737C42.2571 50.8963 39.5475 52.0576 37.5584 53.928C35.8004 55.5811 34.454 57.623 33.6271 59.89C32.6914 62.4551 32.6914 65.4031 32.6914 71.2992V95.8152C32.6914 122.974 45.8077 148.461 67.908 164.248Z" fill="url(#paint0_linear_23582_541687)"/>
<path d="M171.115 71.3009C171.115 64.7266 170.988 63.6537 170.709 62.889C170.351 61.9051 169.766 61.0185 169.003 60.301C168.41 59.7434 167.474 59.2046 161.431 56.6145L112.571 35.6738C108.584 33.965 107.92 33.7457 107.358 33.6538C106.642 33.5368 105.911 33.5368 105.195 33.6538C104.632 33.7457 103.969 33.9652 99.9826 35.6738L51.1221 56.6145C45.0797 59.2041 44.1434 59.7436 43.5504 60.301C42.7874 61.0185 42.2021 61.9051 41.8432 62.889C41.5644 63.6537 41.4375 64.7267 41.4375 71.3009V95.8171C41.4376 120.152 53.1899 142.987 72.9916 157.132L96.9889 174.274C102.76 178.396 103.791 178.954 104.629 179.167C105.71 179.441 106.843 179.441 107.924 179.167C108.761 178.954 109.792 178.396 115.564 174.274L139.561 157.132C159.363 142.987 171.115 120.152 171.115 95.8171V71.3009ZM179.861 95.8171L179.852 97.0887C179.449 123.77 166.4 148.71 144.645 164.25L120.648 181.391L118.824 182.69C114.827 185.528 112.538 187.02 110.071 187.645C107.736 188.236 105.297 188.273 102.95 187.756L102.482 187.645C100.014 187.02 97.7261 185.528 93.7284 182.69L67.9075 164.25C46.1526 148.71 33.1035 123.77 32.701 97.0887L32.6914 95.8171V71.3009C32.6914 65.7736 32.6914 62.8369 33.4622 60.3779L33.6267 59.8921C34.4019 57.7669 35.6338 55.839 37.2331 54.2443L37.5588 53.9294C39.2993 52.2928 41.5914 51.1989 45.7679 49.3951L96.5373 27.6355C99.9038 26.1927 101.692 25.4257 103.436 25.0849L103.784 25.023C105.435 24.7534 107.118 24.7534 108.768 25.023C110.63 25.3272 112.426 26.0967 116.016 27.6355L164.876 48.5752C170.295 50.8976 173.005 52.0592 174.994 53.9294C176.752 55.5825 178.099 57.6251 178.926 59.8921C179.861 62.4571 179.861 65.4053 179.861 71.3009V95.8171Z" fill="url(#paint1_linear_23582_541687)"/>
<path d="M173.302 71.3009C173.302 64.8958 173.207 63.3543 172.764 62.1395C172.288 60.8349 171.513 59.6595 170.501 58.7081C169.559 57.8223 168.18 57.1273 162.292 54.6041L113.432 33.6645C109.544 31.9982 108.597 31.6411 107.71 31.4961C106.761 31.341 105.792 31.341 104.842 31.4961C103.955 31.6411 103.009 31.9982 99.121 33.6645L50.2605 54.6041C44.3737 57.127 42.9945 57.8225 42.0525 58.7081C41.0407 59.6595 40.265 60.8348 39.7891 62.1395C39.4014 63.2024 39.2806 64.5154 39.2563 69.1176L39.251 71.3009V95.8171C39.2511 120.858 51.3447 144.357 71.7211 158.911L95.7184 176.052C101.34 180.068 102.76 180.948 104.093 181.286C105.526 181.649 107.028 181.649 108.461 181.286C109.794 180.948 111.213 180.068 116.834 176.052L140.832 158.911C161.208 144.357 173.302 120.858 173.302 95.8171V71.3009ZM179.861 95.8171L179.852 97.0887C179.449 123.77 166.4 148.71 144.645 164.25L120.648 181.391L118.824 182.69C114.827 185.528 112.538 187.02 110.071 187.645C107.736 188.236 105.297 188.273 102.95 187.756L102.482 187.645C100.014 187.02 97.7261 185.528 93.7284 182.69L67.9075 164.25C46.1526 148.71 33.1035 123.77 32.701 97.0887L32.6914 95.8171V71.3009C32.6914 65.7736 32.6914 62.8369 33.4622 60.3779L33.6267 59.8921C34.4019 57.7669 35.6338 55.839 37.2331 54.2443L37.5588 53.9294C39.2993 52.2928 41.5914 51.1989 45.7679 49.3951L96.5373 27.6355C99.9038 26.1927 101.692 25.4257 103.436 25.0849L103.784 25.023C105.435 24.7534 107.118 24.7534 108.768 25.023C110.63 25.3272 112.426 26.0967 116.016 27.6355L164.876 48.5752C170.295 50.8976 173.005 52.0592 174.994 53.9294C176.752 55.5825 178.099 57.6251 178.926 59.8921C179.861 62.4571 179.861 65.4053 179.861 71.3009V95.8171Z" fill="url(#paint2_linear_23582_541687)"/>
<path d="M178.221 71.3009C178.221 65.2777 178.198 62.6812 177.385 60.4537C176.646 58.4273 175.442 56.6017 173.871 55.1241C172.143 53.4999 169.766 52.4553 164.23 50.0827L115.369 29.142C111.705 27.5714 110.121 26.9059 108.503 26.6416C107.028 26.4006 105.524 26.4006 104.049 26.6416C102.431 26.9059 100.848 27.5714 97.1832 29.142L48.3227 50.0827C42.7865 52.4553 40.4092 53.4999 38.6819 55.1241C37.1105 56.6017 35.9065 58.4273 35.1673 60.4537C34.4564 62.4027 34.3491 64.6342 34.3334 69.1966L34.3313 71.3009V95.8171C34.3314 122.447 47.1917 147.437 68.8609 162.915L92.8582 180.056C98.1419 183.83 100.436 185.435 102.884 186.055C105.111 186.619 107.442 186.619 109.668 186.055C112.117 185.435 114.411 183.83 119.694 180.056L143.692 162.915C165.361 147.437 178.221 122.447 178.221 95.8171V71.3009ZM179.861 95.8171L179.852 97.0887C179.449 123.77 166.4 148.71 144.645 164.25L120.648 181.391L118.824 182.69C114.827 185.528 112.538 187.02 110.071 187.645C107.736 188.236 105.297 188.273 102.95 187.756L102.482 187.645C100.014 187.02 97.7261 185.528 93.7284 182.69L67.9075 164.25C46.1526 148.71 33.1035 123.77 32.701 97.0887L32.6914 95.8171V71.3009C32.6914 65.7736 32.6914 62.8369 33.4622 60.3779L33.6267 59.8921C34.4019 57.7669 35.6338 55.839 37.2331 54.2443L37.5588 53.9294C39.2993 52.2928 41.5914 51.1989 45.7679 49.3951L96.5373 27.6355C99.9038 26.1927 101.692 25.4257 103.436 25.0849L103.784 25.023C105.435 24.7534 107.118 24.7534 108.768 25.023C110.63 25.3272 112.426 26.0967 116.016 27.6355L164.876 48.5752C170.295 50.8976 173.005 52.0592 174.994 53.9294C176.752 55.5825 178.099 57.6251 178.926 59.8921C179.861 62.4571 179.861 65.4053 179.861 71.3009V95.8171Z" fill="url(#paint3_linear_23582_541687)"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M119.26 114.481C130.69 114.481 139.956 105.215 139.956 93.7851C139.956 82.3552 130.69 73.0894 119.26 73.0894C107.83 73.0894 98.5644 82.3552 98.5644 93.7851C98.5644 97.8348 99.7275 101.613 101.738 104.803L73.6641 132.877L87.4479 146.661L93.952 140.157L86.6722 132.877L93.9653 125.584L101.245 132.864L107.749 126.36L100.469 119.08L108.242 111.307C111.432 113.318 115.21 114.481 119.26 114.481ZM119.26 105.283C125.61 105.283 130.758 100.135 130.758 93.7851C130.758 87.4352 125.61 82.2875 119.26 82.2875C112.91 82.2875 107.762 87.4352 107.762 93.7851C107.762 100.135 112.91 105.283 119.26 105.283Z" fill="#082877"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M119.26 111.202C130.69 111.202 139.956 101.936 139.956 90.5058C139.956 79.0759 130.69 69.8101 119.26 69.8101C107.83 69.8101 98.5644 79.0759 98.5644 90.5058C98.5644 94.5555 99.7275 98.3335 101.738 101.524L73.6641 129.598L87.4479 143.382L93.952 136.878L86.6722 129.598L93.9653 122.305L101.245 129.585L107.749 123.081L100.469 115.801L108.242 108.028C111.432 110.038 115.21 111.202 119.26 111.202ZM119.26 102.003C125.61 102.003 130.758 96.8558 130.758 90.5058C130.758 84.1559 125.61 79.0082 119.26 79.0082C112.91 79.0082 107.762 84.1559 107.762 90.5058C107.762 96.8558 112.91 102.003 119.26 102.003Z" fill="url(#paint4_linear_23582_541687)"/>
<path d="M119.26 69.8101C130.69 69.8101 139.956 79.0763 139.956 90.5063C139.956 101.936 130.69 111.201 119.26 111.201C115.21 111.201 111.432 110.039 108.242 108.028L100.469 115.801L107.75 123.081L101.245 129.584L93.9652 122.305L86.6722 129.598L93.9524 136.878L87.4484 143.382L73.6641 129.598L101.738 101.524C99.7273 98.3339 98.5647 94.5558 98.5646 90.5063C98.5646 79.0764 107.83 69.8102 119.26 69.8101ZM119.26 70.9033C108.434 70.9035 99.6579 79.6802 99.6579 90.5063C99.658 94.3435 100.76 97.9203 102.663 100.941L103.129 101.68L75.21 129.597L87.4484 141.835L92.4054 136.877L85.1262 129.598L93.9652 120.759L101.244 128.038L106.203 123.08L98.9234 115.801L108.086 106.637L108.825 107.103C111.846 109.006 115.423 110.108 119.26 110.108C130.086 110.108 138.862 101.332 138.863 90.5063C138.863 79.6801 130.086 70.9033 119.26 70.9033ZM119.26 77.9145C126.213 77.9145 131.85 83.5525 131.85 90.5063C131.85 97.4598 126.213 103.097 119.26 103.097C112.306 103.097 106.669 97.4597 106.669 90.5063C106.669 83.5526 112.306 77.9147 119.26 77.9145ZM119.26 79.0078C112.91 79.0079 107.762 84.1564 107.762 90.5063C107.763 96.8559 112.91 102.004 119.26 102.004C125.61 102.004 130.757 96.856 130.757 90.5063C130.757 84.1563 125.61 79.0078 119.26 79.0078Z" fill="url(#paint5_linear_23582_541687)"/>
</g>
<defs>
<linearGradient id="paint0_linear_23582_541687" x1="106.276" y1="23.4595" x2="106.276" y2="191.654" gradientUnits="userSpaceOnUse">
<stop stop-color="#00113D"/>
<stop offset="1" stop-color="#1647C3"/>
</linearGradient>
<linearGradient id="paint1_linear_23582_541687" x1="106.276" y1="23.4611" x2="106.276" y2="191.655" gradientUnits="userSpaceOnUse">
<stop stop-color="#00288D"/>
<stop offset="1" stop-color="#A8B9FF"/>
</linearGradient>
<linearGradient id="paint2_linear_23582_541687" x1="106.276" y1="23.4611" x2="106.276" y2="191.655" gradientUnits="userSpaceOnUse">
<stop stop-color="#D8E3FF"/>
<stop offset="0.700262" stop-color="#718CF5"/>
</linearGradient>
<linearGradient id="paint3_linear_23582_541687" x1="106.276" y1="23.4611" x2="106.276" y2="191.655" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#4160DE"/>
</linearGradient>
<linearGradient id="paint4_linear_23582_541687" x1="106.81" y1="69.8101" x2="106.81" y2="143.382" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#779DFF"/>
</linearGradient>
<linearGradient id="paint5_linear_23582_541687" x1="106.81" y1="69.8101" x2="106.81" y2="143.382" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#A8C1FF"/>
</linearGradient>
<clipPath id="clip0_23582_541687">
<rect width="212.288" height="212.288" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 15 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="19" height="19" viewBox="0 0 19 19" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.80775 19C2.30908 19 1.88308 18.8234 1.52975 18.4703C1.17658 18.1169 1 17.6909 1 17.1923V5.99425C0.7065 5.84292 0.466417 5.62783 0.27975 5.349C0.0932501 5.07017 0 4.74867 0 4.3845V1.80775C0 1.30908 0.176583 0.883083 0.52975 0.52975C0.883083 0.176583 1.30908 0 1.80775 0H17.1923C17.6909 0 18.1169 0.176583 18.4703 0.52975C18.8234 0.883083 19 1.30908 19 1.80775V4.3845C19 4.74867 18.9067 5.07017 18.7203 5.349C18.5336 5.62783 18.2935 5.84292 18 5.99425V17.1923C18 17.6909 17.8234 18.1169 17.4703 18.4703C17.1169 18.8234 16.6909 19 16.1923 19H2.80775ZM2.5 6.19225V17.1443C2.5 17.2467 2.53683 17.3317 2.6105 17.399C2.68433 17.4663 2.77575 17.5 2.88475 17.5H16.1923C16.2821 17.5 16.3558 17.4712 16.4135 17.4135C16.4712 17.3558 16.5 17.2821 16.5 17.1923V6.19225H2.5ZM1.80775 4.69225H17.1923C17.2821 4.69225 17.3558 4.66342 17.4135 4.60575C17.4712 4.54808 17.5 4.47433 17.5 4.3845V1.80775C17.5 1.71792 17.4712 1.64417 17.4135 1.5865C17.3558 1.52883 17.2821 1.5 17.1923 1.5H1.80775C1.71792 1.5 1.64417 1.52883 1.5865 1.5865C1.52883 1.64417 1.5 1.71792 1.5 1.80775V4.3845C1.5 4.47433 1.52883 4.54808 1.5865 4.60575C1.64417 4.66342 1.71792 4.69225 1.80775 4.69225ZM6.69225 10.9327H12.3077V9.5H6.69225V10.9327Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M15.7731 12.9728L14.6501 11.8498C14.8001 11.0217 14.5638 10.2771 13.9413 9.61607C13.319 8.95524 12.5552 8.69982 11.6501 8.84982L10.5271 7.72682C10.7527 7.62549 10.9842 7.54949 11.2213 7.49882C11.4585 7.44815 11.7181 7.42282 12.0001 7.42282C13.1347 7.42282 14.0979 7.81865 14.8896 8.61032C15.6812 9.40199 16.0771 10.3652 16.0771 11.4998C16.0771 11.7818 16.0517 12.0447 16.0011 12.2883C15.9504 12.5318 15.8744 12.76 15.7731 12.9728ZM18.9538 16.0843L17.8501 15.0498C18.4834 14.5665 19.0459 14.0373 19.5376 13.4623C20.0292 12.8873 20.4501 12.2332 20.8001 11.4998C19.9667 9.81649 18.7709 8.47899 17.2126 7.48732C15.6542 6.49565 13.9167 5.99982 12.0001 5.99982C11.5167 5.99982 11.0417 6.03315 10.5751 6.09982C10.1084 6.16649 9.65007 6.26649 9.20007 6.39982L8.03482 5.23457C8.66682 4.98324 9.31233 4.79799 9.97132 4.67882C10.6303 4.55949 11.3066 4.49982 12.0001 4.49982C14.3436 4.49982 16.457 5.14599 18.3403 6.43832C20.2237 7.73065 21.5974 9.41782 22.4616 11.4998C22.0911 12.3933 21.6126 13.2273 21.0261 14.0018C20.4394 14.7762 19.7487 15.4703 18.9538 16.0843ZM19.7616 21.8691L15.7156 17.8536C15.2027 18.0434 14.6344 18.1986 14.0106 18.3191C13.3869 18.4396 12.7167 18.4998 12.0001 18.4998C9.65007 18.4998 7.53666 17.8537 5.65982 16.5613C3.78282 15.269 2.40907 13.5818 1.53857 11.4998C1.90774 10.6165 2.38466 9.79249 2.96932 9.02782C3.55399 8.26299 4.19757 7.59982 4.90007 7.03832L2.13082 4.23832L3.18482 3.18457L20.8153 20.8151L19.7616 21.8691ZM5.95407 8.09207C5.42574 8.51257 4.91191 9.01807 4.41257 9.60857C3.91324 10.1989 3.50907 10.8293 3.20007 11.4998C4.03341 13.1832 5.22924 14.5207 6.78757 15.5123C8.34591 16.504 10.0834 16.9998 12.0001 16.9998C12.4552 16.9998 12.9085 16.9613 13.3598 16.8843C13.811 16.8075 14.1937 16.7281 14.5078 16.6461L13.2423 15.3498C13.0718 15.419 12.8744 15.4741 12.6501 15.5151C12.4257 15.5562 12.2091 15.5768 12.0001 15.5768C10.8654 15.5768 9.90224 15.181 9.11058 14.3893C8.31891 13.5977 7.92307 12.6345 7.92307 11.4998C7.92307 11.2973 7.94366 11.0855 7.98483 10.8643C8.02583 10.6432 8.08091 10.4409 8.15007 10.2576L5.95407 8.09207Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

+59
View File
@@ -0,0 +1,59 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="network-arbitrum 1" clip-path="url(#clip0_0_93)">
<path id="Vector" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint0_linear_0_93)"/>
<path id="Vector_2" d="M13.3162 13.4389L12.4775 15.7401C12.4567 15.8025 12.4567 15.8718 12.4775 15.9411L13.9192 19.8988L15.5896 18.9354L13.5865 13.4389C13.538 13.3142 13.3647 13.3142 13.3162 13.4389Z" fill="#041935"/>
<path id="Vector_3" d="M15.0005 9.57129C14.952 9.44653 14.7787 9.44653 14.7302 9.57129L13.8915 11.8725C13.8707 11.9348 13.8707 12.0042 13.8915 12.0735L16.255 18.5542L17.9255 17.5907L15.0005 9.57822V9.57129Z" fill="#041935"/>
<path id="Vector_4" d="M12.0304 3.45801C12.2579 3.45857 12.4854 3.51406 12.6854 3.63129L19.0551 7.30482C19.4641 7.54048 19.7136 7.97022 19.7136 8.44153V15.7887C19.7136 16.26 19.4641 16.6898 19.0551 16.9254L12.6923 20.599C12.4843 20.7168 12.2626 20.7722 12.0339 20.7722C11.8051 20.7722 11.5764 20.7168 11.3754 20.599L8.49312 18.9348L9.31812 18.1773L11.916 19.6772C11.9506 19.6979 11.9923 19.7118 12.0339 19.7118C12.0754 19.7118 12.117 19.6979 12.1516 19.6772L18.5145 16.0035C18.5838 15.9619 18.6323 15.8788 18.6323 15.7956V8.44852C18.6323 8.36536 18.5908 8.2822 18.5145 8.24061L12.1516 4.56696C12.117 4.54618 12.0754 4.53234 12.0339 4.53233V4.52545C11.9923 4.52545 11.9506 4.53929 11.916 4.56008L5.55309 8.23361C5.48379 8.2752 5.43533 8.35837 5.43532 8.44153V15.7956C5.43532 15.8788 5.47687 15.9619 5.55309 16.0035L8.19732 17.5301L7.82414 18.5487L5.01249 16.9254C4.60356 16.6898 4.35401 16.26 4.354 15.7887V8.44153C4.35402 7.97022 4.60356 7.54048 5.01249 7.30482L11.3754 3.63129C11.5823 3.51406 11.8029 3.45856 12.0304 3.45801Z" fill="#041935"/>
<path id="Vector_5" d="M11.4933 7.92174H9.87832C9.76049 7.92174 9.64959 7.99798 9.608 8.10888L6.14931 17.5908L7.81974 18.5543L11.6319 8.10888C11.6666 8.01184 11.5973 7.9148 11.5002 7.9148L11.4933 7.92174Z" fill="#041935"/>
<path id="Vector_6" d="M14.3213 7.92175H12.7064C12.5885 7.92175 12.4776 7.998 12.436 8.1089L8.48523 18.9355L10.1557 19.8989L14.453 8.1089C14.4877 8.01186 14.4184 7.91482 14.3213 7.91482V7.92175Z" fill="#041935"/>
<path id="Vector_7" d="M13.3162 13.2073L12.4775 15.5085C12.4567 15.5708 12.4567 15.6402 12.4775 15.7095L13.9192 19.6672L15.5896 18.7038L13.5865 13.2073C13.538 13.0825 13.3647 13.0825 13.3162 13.2073Z" fill="url(#paint1_linear_0_93)"/>
<path id="Vector_8" d="M15.0005 9.33967C14.952 9.2149 14.7787 9.2149 14.7302 9.33967L13.8915 11.6408C13.8707 11.7032 13.8707 11.7725 13.8915 11.8418L16.2551 18.3226L17.9255 17.3591L15.0005 9.3466V9.33967Z" fill="url(#paint2_linear_0_93)"/>
<path id="Vector_9" d="M13.3162 13.2082C13.3647 13.0835 13.538 13.0835 13.5865 13.2082L15.5896 18.7047L13.9192 19.6681L12.4775 15.7104C12.4567 15.6411 12.4567 15.5717 12.4775 15.5094L13.3162 13.2082ZM13.4514 13.2399C13.447 13.2399 13.4433 13.2412 13.4407 13.2429C13.4388 13.2441 13.4357 13.2467 13.4331 13.2534L12.5965 15.549L12.5925 15.5626C12.5848 15.5945 12.5852 15.6314 12.5968 15.6716L13.9859 19.485L15.4358 18.6487L13.4697 13.2537C13.467 13.2468 13.4639 13.2442 13.462 13.2429C13.4594 13.2412 13.4558 13.24 13.4514 13.2399ZM14.7302 9.34064C14.7787 9.21588 14.952 9.21588 15.0005 9.34064V9.3475L17.9255 17.36L16.2551 18.3235L13.8915 11.8428C13.8733 11.7821 13.8711 11.7215 13.8847 11.6655L13.8915 11.6418L14.7302 9.34064ZM14.8654 9.37236C14.861 9.37236 14.8573 9.37364 14.8547 9.3753C14.8528 9.37656 14.8497 9.37911 14.8471 9.38578L14.0105 11.6814L14.0065 11.6951C13.9988 11.7269 13.9992 11.7637 14.0108 11.8039L16.3216 18.1404L17.7716 17.304L14.8828 9.39048L14.8778 9.37697L14.876 9.3753C14.8734 9.37365 14.8698 9.37237 14.8654 9.37236Z" fill="url(#paint3_linear_0_93)"/>
<path id="Vector_10" d="M12.0307 3.22754C12.2583 3.22809 12.4858 3.28359 12.6858 3.40084L19.0556 7.07437C19.4645 7.31003 19.7141 7.73977 19.7141 8.21109V15.5582C19.7141 16.0296 19.4645 16.4593 19.0556 16.695L12.6927 20.3685C12.4848 20.4863 12.263 20.5418 12.0342 20.5418C11.8055 20.5418 11.5768 20.4863 11.3758 20.3685L8.49358 18.7044L9.31865 17.9468L11.9165 19.4467C11.9511 19.4675 11.9927 19.4813 12.0342 19.4813C12.0758 19.4813 12.1175 19.4675 12.1521 19.4467L18.515 15.7731C18.5843 15.7315 18.6328 15.6483 18.6328 15.5651V8.21804C18.6328 8.13487 18.5912 8.05167 18.515 8.01008L12.1521 4.33655C12.1175 4.31576 12.0758 4.30189 12.0342 4.30189V4.29494C11.9927 4.29494 11.9511 4.30882 11.9165 4.3296L5.55358 8.00313C5.48427 8.04471 5.4357 8.12792 5.4357 8.21109V15.5651C5.4357 15.6483 5.47734 15.7315 5.55358 15.7731L8.1977 17.2996L7.82457 18.3182L5.01293 16.695C4.60399 16.4593 4.3545 16.0296 4.35449 15.5582V8.21109C4.3545 7.73977 4.60399 7.31003 5.01293 7.07437L11.3758 3.40084C11.5827 3.28362 11.8032 3.22811 12.0307 3.22754Z" fill="url(#paint4_linear_0_93)"/>
<path id="Vector_11" d="M19.5888 15.5582V8.21109C19.5888 7.79817 19.3772 7.42073 19.0273 7.20351L18.993 7.18295L12.6233 3.50942C12.4443 3.40452 12.2383 3.35341 12.0307 3.35286C11.8243 3.35343 11.6251 3.40365 11.4376 3.50991L5.07559 7.18295C4.71684 7.38969 4.49407 7.76072 4.4805 8.17124L4.47982 8.21109V15.5582C4.47983 15.9845 4.70517 16.373 5.07549 16.5864L7.75809 18.1351L8.04369 17.3555L5.49092 15.8816C5.37049 15.8146 5.31037 15.6863 5.31037 15.5651V8.21109C5.31038 8.08312 5.38269 7.95945 5.48906 7.89563L5.49004 7.89514L5.49092 7.89455L11.8538 4.22102C11.9037 4.19148 11.9666 4.16962 12.0342 4.16962H12.1596V4.20104C12.1792 4.20875 12.1977 4.21791 12.2147 4.22797L18.5777 7.9015C18.6982 7.96861 18.7581 8.09685 18.7581 8.21804V15.5651C18.7581 15.693 18.6859 15.8166 18.5795 15.8805L18.5786 15.8811L18.5777 15.8816L12.2148 19.5553C12.1649 19.5848 12.1019 19.6067 12.0342 19.6067C11.9666 19.6067 11.9037 19.5847 11.8538 19.5552L9.33559 18.1013L8.70408 18.6812L11.4385 20.2599C11.6184 20.3654 11.8256 20.4165 12.0342 20.4165V20.5418C11.8055 20.5418 11.5768 20.4863 11.3758 20.3685L8.49358 18.7044L9.31865 17.9468L11.9165 19.4467C11.9511 19.4675 11.9927 19.4813 12.0342 19.4813C12.0758 19.4813 12.1175 19.4675 12.1521 19.4467L18.515 15.7731C18.5843 15.7315 18.6328 15.6483 18.6328 15.5651V8.21804C18.6328 8.13487 18.5912 8.05167 18.515 8.01008L12.1521 4.33655C12.1175 4.31576 12.0758 4.30189 12.0342 4.30189V4.29494C11.9927 4.29494 11.9511 4.30882 11.9165 4.3296L5.55358 8.00313C5.48427 8.04471 5.4357 8.12792 5.4357 8.21109V15.5651C5.4357 15.6483 5.47734 15.7315 5.55358 15.7731L8.1977 17.2996L7.82457 18.3182L5.01293 16.695C4.60399 16.4593 4.3545 16.0296 4.35449 15.5582V8.21109C4.3545 7.73977 4.60399 7.31003 5.01293 7.07437L11.3758 3.40084C11.5827 3.28362 11.8032 3.22811 12.0307 3.22754C12.2583 3.22809 12.4858 3.28359 12.6858 3.40084L19.0556 7.07437C19.4645 7.31003 19.7141 7.73977 19.7141 8.21109V15.5582C19.7141 16.0296 19.4645 16.4593 19.0556 16.695L12.6927 20.3685C12.4848 20.4863 12.263 20.5418 12.0342 20.5418V20.4165C12.2419 20.4165 12.4423 20.3663 12.6309 20.2594L18.9929 16.5864C19.3517 16.3796 19.5745 16.0086 19.5881 15.5981L19.5888 15.5582Z" fill="url(#paint5_linear_0_93)"/>
<path id="Vector_12" d="M11.4934 7.69052H9.87842C9.76059 7.69052 9.64969 7.76677 9.6081 7.87767L6.14941 17.3596L7.81984 18.323L11.632 7.87767C11.6667 7.78063 11.5974 7.68359 11.5003 7.68359L11.4934 7.69052Z" fill="url(#paint6_linear_0_93)"/>
<path id="Vector_13" d="M14.3214 7.69054H12.7065C12.5886 7.69054 12.4777 7.76679 12.4361 7.87769L8.48534 18.7043L10.1558 19.6677L14.4531 7.87769C14.4878 7.78065 14.4185 7.68361 14.3214 7.68361V7.69054Z" fill="url(#paint7_linear_0_93)"/>
<path id="Vector_14" d="M14.3215 7.68359C14.4185 7.6836 14.4878 7.78063 14.4531 7.87765L10.1557 19.6677L8.48532 18.7043L12.4361 7.87765C12.4751 7.77371 12.575 7.70022 12.6844 7.69143L12.7065 7.69055H14.3215V7.68359ZM12.7065 7.81587C12.6406 7.81587 12.5767 7.85999 12.5535 7.92171L8.63913 18.6483L10.0892 19.4845L14.3354 7.83476C14.3382 7.82608 14.3365 7.81998 14.3338 7.81587H12.7065ZM11.5003 7.68359C11.5974 7.68359 11.6667 7.78061 11.632 7.87765L7.81983 18.323L6.14941 17.3596L9.60814 7.87765C9.64713 7.77369 9.74701 7.70021 9.85643 7.69143L9.87846 7.69055H11.4934L11.5003 7.68359ZM9.87846 7.81587C9.81258 7.81587 9.74857 7.85999 9.72543 7.92171L6.30313 17.3035L7.75326 18.1399L11.514 7.83525C11.5172 7.82629 11.5154 7.82006 11.5127 7.81587H9.87846Z" fill="url(#paint8_linear_0_93)"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_93" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#213147"/>
<stop offset="1" stop-color="#0E1D32"/>
</linearGradient>
<linearGradient id="paint1_linear_0_93" x1="15.1937" y1="9.24609" x2="15.1937" y2="19.6672" gradientUnits="userSpaceOnUse">
<stop stop-color="#12AAFF"/>
<stop offset="1" stop-color="#006AA6"/>
</linearGradient>
<linearGradient id="paint2_linear_0_93" x1="15.1937" y1="9.24609" x2="15.1937" y2="19.6672" gradientUnits="userSpaceOnUse">
<stop stop-color="#12AAFF"/>
<stop offset="1" stop-color="#006AA6"/>
</linearGradient>
<linearGradient id="paint3_linear_0_93" x1="15.1937" y1="9.24704" x2="15.1937" y2="19.6682" gradientUnits="userSpaceOnUse">
<stop stop-color="#27B2FF"/>
<stop offset="1" stop-color="#619EC9"/>
</linearGradient>
<linearGradient id="paint4_linear_0_93" x1="12.0342" y1="3.22754" x2="12.0342" y2="20.5418" gradientUnits="userSpaceOnUse">
<stop stop-color="#9DCCED"/>
<stop offset="1" stop-color="#5594C1"/>
</linearGradient>
<linearGradient id="paint5_linear_0_93" x1="12.0342" y1="3.22754" x2="12.0342" y2="20.5418" gradientUnits="userSpaceOnUse">
<stop stop-color="#D7EFFF"/>
<stop offset="1" stop-color="#2672A6"/>
</linearGradient>
<linearGradient id="paint6_linear_0_93" x1="10.3058" y1="7.68359" x2="10.3058" y2="19.6677" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D0ECFF"/>
</linearGradient>
<linearGradient id="paint7_linear_0_93" x1="10.3058" y1="7.68359" x2="10.3058" y2="19.6677" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#D0ECFF"/>
</linearGradient>
<linearGradient id="paint8_linear_0_93" x1="10.3058" y1="7.68359" x2="10.3058" y2="19.6677" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#5796C3"/>
</linearGradient>
<clipPath id="clip0_0_93">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

+25
View File
@@ -0,0 +1,25 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="network-base 1" clip-path="url(#clip0_0_56)">
<path id="Vector" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint0_linear_0_56)"/>
<path id="Vector_2" d="M11.9864 20.3391C16.3403 20.3391 19.8699 16.8156 19.8699 12.4694C19.8699 8.12301 16.3403 4.59961 11.9864 4.59961C7.85563 4.59961 4.46692 7.77106 4.13037 11.8078H14.5505V13.1308H4.13037C4.46692 17.1677 7.85563 20.3391 11.9864 20.3391Z" fill="#0037AD"/>
<path id="Vector_3" d="M11.9864 19.8792C16.3403 19.8792 19.8699 16.3557 19.8699 12.0094C19.8699 7.66305 16.3403 4.13965 11.9864 4.13965C7.85563 4.13965 4.46692 7.3111 4.13037 11.3479H14.5505V12.6709H4.13037C4.46692 16.7077 7.85563 19.8792 11.9864 19.8792Z" fill="url(#paint1_linear_0_56)"/>
<path id="Vector_4" d="M14.5505 12.6709V11.3479H4.13037C4.46692 7.31115 7.85562 4.13966 11.9863 4.13965C16.3403 4.13965 19.8699 7.66305 19.8699 12.0094C19.8699 16.3557 16.3403 19.8792 11.9863 19.8792V19.6872C16.2346 19.6872 19.6779 16.2493 19.6779 12.0094C19.6779 7.7694 16.2346 4.33165 11.9863 4.33165C8.02724 4.33166 4.76714 7.31764 4.34196 11.1559H14.7425V12.8629H4.34196C4.76717 16.7012 8.02726 19.6871 11.9863 19.6872V19.8792C7.85563 19.8791 4.46693 16.7077 4.13037 12.6709H14.5505Z" fill="url(#paint2_linear_0_56)"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_56" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#0052FF"/>
<stop offset="1" stop-color="#003CB9"/>
</linearGradient>
<linearGradient id="paint1_linear_0_56" x1="12.0001" y1="4.13965" x2="12.0001" y2="19.8792" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#A7C3FF"/>
</linearGradient>
<linearGradient id="paint2_linear_0_56" x1="12.0001" y1="4.13965" x2="12.0001" y2="19.8792" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<clipPath id="clip0_0_56">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 2.5 KiB

+40
View File
@@ -0,0 +1,40 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="network-bitcoin 1" clip-path="url(#clip0_0_118)">
<path id="Vector" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint0_linear_0_118)"/>
<path id="Vector_2" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint1_linear_0_118)"/>
<path id="Vector_3" d="M17.7887 10.7612C18.0484 9.02545 16.7267 8.09232 14.9196 7.46983L15.5058 5.11847L14.0745 4.76177L13.5038 7.05117C13.1275 6.95741 12.7411 6.86895 12.3571 6.7813L12.9319 4.47682L11.5014 4.12012L10.9148 6.47066C10.6033 6.39973 10.2976 6.32962 10.0008 6.25583L10.0025 6.24849L8.02858 5.75564L7.64783 7.28435C7.64783 7.28435 8.70977 7.52772 8.68735 7.5428C9.26704 7.68752 9.37181 8.07112 9.35428 8.37524L8.68654 11.0539C8.72649 11.0641 8.77826 11.0788 8.83533 11.1016C8.78764 11.0898 8.73668 11.0768 8.68409 11.0641L7.74811 14.8166C7.67718 14.9927 7.4974 15.2569 7.09219 15.1566C7.10646 15.1774 6.05185 14.8969 6.05185 14.8969L5.34131 16.5353L7.20389 16.9996C7.5504 17.0864 7.88998 17.1774 8.22426 17.263L7.63193 19.6412L9.06158 19.9979L9.6482 17.6449C10.0387 17.7509 10.4179 17.8488 10.7888 17.9409L10.2042 20.2829L11.6355 20.6396L12.2278 18.2658C14.6685 18.7277 16.5038 18.5414 17.2763 16.3339C17.8988 14.5565 17.2453 13.5313 15.9612 12.8627C16.8963 12.6471 17.6008 12.0319 17.7887 10.7612ZM14.5185 15.347C14.0762 17.1244 11.0836 16.1635 10.1133 15.9226L10.8993 12.7718C11.8695 13.014 14.9808 13.4934 14.5185 15.347ZM14.9612 10.7356C14.5576 12.3523 12.0668 11.5309 11.2588 11.3295L11.9714 8.47185C12.7794 8.67323 15.3815 9.04909 14.9612 10.7356Z" fill="url(#paint2_linear_0_118)"/>
<path id="Vector_4" d="M17.7887 10.1353C18.0484 8.39947 16.7267 7.46635 14.9196 6.84385L15.5058 4.49249L14.0745 4.13579L13.5038 6.42519C13.1275 6.33143 12.7411 6.24297 12.3571 6.15532L12.9319 3.85084L11.5014 3.49414L10.9148 5.84469C10.6033 5.77376 10.2976 5.70364 10.0008 5.62985L10.0025 5.62252L8.02858 5.12966L7.64783 6.65837C7.64783 6.65837 8.70977 6.90174 8.68735 6.91682C9.26704 7.06154 9.37181 7.44515 9.35428 7.74926L8.68654 10.428C8.72649 10.4382 8.77826 10.4528 8.83533 10.4757C8.78764 10.4638 8.73668 10.4508 8.68409 10.4382L7.74811 14.1906C7.67718 14.3667 7.4974 14.6309 7.09219 14.5306C7.10646 14.5514 6.05185 14.2709 6.05185 14.2709L5.34131 15.9093L7.20389 16.3736C7.5504 16.4605 7.88998 16.5514 8.22426 16.637L7.63193 19.0153L9.06158 19.372L9.6482 17.019C10.0387 17.125 10.4179 17.2228 10.7888 17.3149L10.2042 19.6569L11.6355 20.0136L12.2278 17.6398C14.6685 18.1017 16.5038 17.9154 17.2763 15.7079C17.8988 13.9306 17.2453 12.9053 15.9612 12.2367C16.8963 12.0211 17.6008 11.4059 17.7887 10.1353ZM14.5185 14.721C14.0762 16.4984 11.0836 15.5375 10.1133 15.2966L10.8993 12.1458C11.8695 12.388 14.9808 12.8674 14.5185 14.721ZM14.9612 10.1096C14.5576 11.7264 12.0668 10.9049 11.2588 10.7035L11.9714 7.84587C12.7794 8.04726 15.3815 8.42312 14.9612 10.1096Z" fill="white"/>
<path id="Vector_5" d="M17.7887 10.1353C18.0484 8.39947 16.7267 7.46635 14.9196 6.84385L15.5058 4.49249L14.0745 4.13579L13.5038 6.42519C13.1275 6.33143 12.7411 6.24297 12.3571 6.15532L12.9319 3.85084L11.5014 3.49414L10.9148 5.84469C10.6033 5.77376 10.2976 5.70364 10.0008 5.62985L10.0025 5.62252L8.02858 5.12966L7.64783 6.65837C7.64783 6.65837 8.70977 6.90174 8.68735 6.91682C9.26704 7.06154 9.37181 7.44515 9.35428 7.74926L8.68654 10.428C8.72649 10.4382 8.77826 10.4528 8.83533 10.4757C8.78764 10.4638 8.73668 10.4508 8.68409 10.4382L7.74811 14.1906C7.67718 14.3667 7.4974 14.6309 7.09219 14.5306C7.10646 14.5514 6.05185 14.2709 6.05185 14.2709L5.34131 15.9093L7.20389 16.3736C7.5504 16.4605 7.88998 16.5514 8.22426 16.637L7.63193 19.0153L9.06158 19.372L9.6482 17.019C10.0387 17.125 10.4179 17.2228 10.7888 17.3149L10.2042 19.6569L11.6355 20.0136L12.2278 17.6398C14.6685 18.1017 16.5038 17.9154 17.2763 15.7079C17.8988 13.9306 17.2453 12.9053 15.9612 12.2367C16.8963 12.0211 17.6008 11.4059 17.7887 10.1353ZM14.5185 14.721C14.0762 16.4984 11.0836 15.5375 10.1133 15.2966L10.8993 12.1458C11.8695 12.388 14.9808 12.8674 14.5185 14.721ZM14.9612 10.1096C14.5576 11.7264 12.0668 10.9049 11.2588 10.7035L11.9714 7.84587C12.7794 8.04726 15.3815 8.42312 14.9612 10.1096Z" fill="url(#paint3_linear_0_118)"/>
<path id="Vector_6" d="M17.7887 10.1353C18.0484 8.39947 16.7267 7.46635 14.9196 6.84385L15.5058 4.49249L14.0745 4.13579L13.5038 6.42519C13.1275 6.33143 12.7411 6.24297 12.3571 6.15532L12.9319 3.85084L11.5014 3.49414L10.9148 5.84469C10.6033 5.77376 10.2976 5.70364 10.0008 5.62985L10.0025 5.62252L8.02858 5.12966L7.64783 6.65837C7.64783 6.65837 8.70977 6.90174 8.68735 6.91682C9.26704 7.06154 9.37181 7.44515 9.35428 7.74926L8.68654 10.428C8.72649 10.4382 8.77826 10.4528 8.83533 10.4757C8.78764 10.4638 8.73668 10.4508 8.68409 10.4382L7.74811 14.1906C7.67718 14.3667 7.4974 14.6309 7.09219 14.5306C7.10646 14.5514 6.05185 14.2709 6.05185 14.2709L5.34131 15.9093L7.20389 16.3736C7.5504 16.4605 7.88998 16.5514 8.22426 16.637L7.63193 19.0153L9.06158 19.372L9.6482 17.019C10.0387 17.125 10.4179 17.2228 10.7888 17.3149L10.2042 19.6569L11.6355 20.0136L12.2278 17.6398C14.6685 18.1017 16.5038 17.9154 17.2763 15.7079C17.8988 13.9306 17.2453 12.9053 15.9612 12.2367C16.8963 12.0211 17.6008 11.4059 17.7887 10.1353ZM14.5185 14.721C14.0762 16.4984 11.0836 15.5375 10.1133 15.2966L10.8993 12.1458C11.8695 12.388 14.9808 12.8674 14.5185 14.721ZM14.9612 10.1096C14.5576 11.7264 12.0668 10.9049 11.2588 10.7035L11.9714 7.84587C12.7794 8.04726 15.3815 8.42312 14.9612 10.1096Z" fill="url(#paint4_linear_0_118)"/>
<path id="Vector_7" d="M12.9319 3.85084L12.3571 6.15532C12.6451 6.22106 12.9345 6.28725 13.2199 6.35579L13.5038 6.42519L14.0745 4.13579L15.5058 4.49249L14.9196 6.84385C16.7267 7.46635 18.0484 8.39947 17.7887 10.1353C17.6008 11.4059 16.8963 12.0211 15.9612 12.2367C17.2453 12.9053 17.8988 13.9306 17.2763 15.7079C16.5038 17.9154 14.6685 18.1017 12.2278 17.6398L11.6355 20.0136L10.2042 19.6569L10.7888 17.3149C10.4179 17.2228 10.0387 17.125 9.6482 17.019L9.06158 19.372L7.63193 19.0153L8.22426 16.637C7.88998 16.5514 7.5504 16.4605 7.20389 16.3736L5.34131 15.9093L6.05185 14.2709C6.05185 14.2709 7.10646 14.5514 7.09219 14.5306C7.4974 14.6309 7.67718 14.3667 7.74811 14.1906L8.68409 10.4382C8.73668 10.4508 8.78764 10.4638 8.83533 10.4757C8.77826 10.4528 8.72649 10.4382 8.68654 10.428L9.35428 7.74926C9.37181 7.44515 9.26704 7.06154 8.68735 6.91682C8.70976 6.90175 7.64859 6.65855 7.64783 6.65837L8.02858 5.12966L10.0025 5.62252L10.0008 5.62985C10.1492 5.66675 10.2998 5.70277 10.4523 5.73839L10.9148 5.84469L11.5014 3.49414L12.9319 3.85084ZM11.0678 6.09356L10.8684 6.04821C10.5571 5.9773 10.2495 5.9067 9.95048 5.83236L9.75286 5.78334L9.7545 5.77569L8.18053 5.38271L7.90149 6.50295C7.99489 6.52471 8.1099 6.55162 8.22446 6.57898C8.35606 6.6104 8.48828 6.6426 8.58666 6.66805C8.63533 6.68064 8.67825 6.69224 8.70926 6.70158C8.72353 6.70588 8.74115 6.7114 8.75665 6.71758C8.75834 6.71825 8.76236 6.71989 8.76786 6.72237C9.08267 6.80706 9.29458 6.96215 9.42103 7.16142C9.54865 7.36252 9.57299 7.58267 9.56269 7.76129L9.56157 7.78075L9.55678 7.79971L8.88904 10.4784L8.85235 10.4692L8.84919 10.4793L8.88659 10.4887L7.95062 14.2412L7.94715 14.2552L7.94175 14.2686C7.89861 14.3757 7.81658 14.5259 7.6678 14.6335C7.51602 14.7432 7.31582 14.7928 7.0713 14.7397C7.06348 14.7391 7.05781 14.7384 7.05571 14.7381C7.04071 14.7362 7.02376 14.7328 7.00934 14.7299C6.97834 14.7235 6.93555 14.7135 6.88673 14.7017C6.78822 14.678 6.65639 14.6445 6.52524 14.6107C6.39763 14.5778 6.26971 14.5442 6.17191 14.5185L5.63074 15.7663L7.25434 16.1711C7.60066 16.2579 7.94556 16.3502 8.27603 16.4348L8.4769 16.4863L7.88478 18.8632L8.90953 19.1189L9.49726 16.7617L9.70283 16.8176C10.0917 16.9231 10.4695 17.0205 10.8392 17.1123L11.042 17.1628L10.4573 19.5049L11.4835 19.7606L12.073 17.3981L12.2667 17.4348C13.4799 17.6644 14.5067 17.7246 15.3163 17.4754C16.1069 17.2321 16.7126 16.6867 17.0793 15.639C17.3789 14.7835 17.3612 14.1398 17.1425 13.6402C16.9225 13.1378 16.4832 12.7439 15.8648 12.4219L15.3628 12.1605L15.9143 12.0333C16.3502 11.9328 16.72 11.7424 17.0024 11.4394C17.2847 11.1365 17.4932 10.7068 17.5822 10.1047C17.7018 9.30507 17.4607 8.70265 16.981 8.21908C16.491 7.72506 15.745 7.34888 14.8516 7.04116L14.6708 6.97889L15.2528 4.64445L14.2265 4.38874L13.6559 6.67814L13.4534 6.62769C13.0794 6.53451 12.6949 6.44655 12.3106 6.35884L12.103 6.31145L12.6788 4.00279L11.6534 3.74709L11.0678 6.09356ZM10.9498 11.9433C11.4138 12.0591 12.468 12.2468 13.3323 12.6391C13.7662 12.836 14.1771 13.0945 14.4489 13.4422C14.7282 13.7996 14.8529 14.2426 14.721 14.7716C14.5933 15.2845 14.2751 15.6065 13.8635 15.786C13.4626 15.9608 12.9793 15.9989 12.503 15.9741C11.5522 15.9246 10.5326 15.6158 10.063 15.4992L9.86028 15.4489L10.7473 11.8928L10.9498 11.9433ZM10.1133 15.2966C11.0836 15.5375 14.0762 16.4984 14.5185 14.721C14.9808 12.8674 11.8695 12.388 10.8993 12.1458L10.1133 15.2966ZM12.0219 7.64337C12.4027 7.73828 13.2923 7.89038 14.016 8.23203C14.3806 8.40411 14.7277 8.6345 14.9547 8.95113C15.1881 9.27694 15.2834 9.67966 15.1637 10.16C15.0474 10.626 14.774 10.9271 14.4173 11.1005C14.0705 11.269 13.6569 11.3118 13.254 11.297C12.4516 11.2675 11.5953 11.0025 11.2084 10.906L11.0058 10.8556L11.8194 7.59292L12.0219 7.64337ZM11.2588 10.7035C12.0668 10.9049 14.5576 11.7264 14.9612 10.1096C15.3815 8.42312 12.7794 8.04726 11.9714 7.84587L11.2588 10.7035Z" fill="url(#paint5_linear_0_118)"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_118" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#F7BC1A"/>
<stop offset="1" stop-color="#FF6A00"/>
</linearGradient>
<linearGradient id="paint1_linear_0_118" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop offset="0.725084" stop-color="#C94701" stop-opacity="0"/>
<stop offset="1" stop-color="#C94701" stop-opacity="0.3"/>
</linearGradient>
<linearGradient id="paint2_linear_0_118" x1="11.5813" y1="4.12012" x2="11.5813" y2="20.6396" gradientUnits="userSpaceOnUse">
<stop stop-color="#F89A02"/>
<stop offset="1" stop-color="#F56600"/>
</linearGradient>
<linearGradient id="paint3_linear_0_118" x1="11.5813" y1="3.49414" x2="11.5813" y2="20.0136" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#FFF1CF"/>
</linearGradient>
<linearGradient id="paint4_linear_0_118" x1="11.5813" y1="3.49414" x2="11.5813" y2="20.0136" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#FEEABD"/>
</linearGradient>
<linearGradient id="paint5_linear_0_118" x1="11.5813" y1="3.49414" x2="11.5813" y2="20.0136" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<clipPath id="clip0_0_118">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 12 KiB

@@ -0,0 +1,31 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="network-bitcoincash 1" clip-path="url(#clip0_0_49)">
<path id="Vector" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint0_linear_0_49)"/>
<path id="Vector_2" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint1_linear_0_49)"/>
<path id="Vector_3" d="M16.0232 8.19774C15.3628 6.7 13.845 6.37977 11.987 6.68999L11.3899 4.375L9.98224 4.73859L10.5693 7.04691C10.1991 7.14031 9.81879 7.22037 9.44185 7.32711L8.85476 5.03214L7.44709 5.39573L8.04418 7.71072C7.74063 7.79745 5.20215 8.44792 5.20215 8.44792L5.58909 9.95566C5.58909 9.95566 6.62317 9.66545 6.61316 9.6888C7.1869 9.5387 7.4571 9.82557 7.58385 10.0958L9.22503 16.4403C9.24504 16.6238 9.21169 16.9373 8.81807 17.0441C8.84142 17.0574 7.794 17.3076 7.794 17.3076L7.94745 19.0655C7.94745 19.0655 10.4626 18.4217 10.7928 18.3383L11.3966 20.68L12.8043 20.3164L12.2005 17.9581C12.5874 17.868 12.9644 17.7746 13.3313 17.6779L13.9317 20.0229L15.3394 19.6593L14.7356 17.3209C16.9039 16.7939 18.435 15.4262 18.1214 13.3347C17.9213 12.0738 16.5436 11.0398 15.3995 10.923C16.1033 10.2992 16.4602 9.38859 16.0232 8.19774ZM15.3461 13.7184C15.6263 15.7898 12.7476 16.0434 11.7969 16.2935L10.9696 13.1946C11.9236 12.9445 14.8724 11.8937 15.3461 13.7184ZM13.6115 9.49867C13.9084 11.34 11.4466 11.5535 10.6527 11.757L9.89884 8.94494C10.6961 8.74813 13.0077 7.79412 13.6115 9.49867Z" fill="url(#paint2_linear_0_49)"/>
<path id="Vector_4" d="M16.0232 7.56688C15.3628 6.06914 13.845 5.74891 11.987 6.05913L11.3899 3.74414L9.98224 4.10773L10.5693 6.41605C10.1991 6.50945 9.81879 6.58951 9.44185 6.69625L8.85476 4.40128L7.44709 4.76487L8.04418 7.07986C7.74063 7.16659 5.20215 7.81706 5.20215 7.81706L5.58909 9.3248C5.58909 9.3248 6.62317 9.03459 6.61316 9.05794C7.1869 8.90784 7.4571 9.19471 7.58385 9.4649L9.22503 15.8094C9.24504 15.9929 9.21169 16.3065 8.81807 16.4132C8.84142 16.4266 7.794 16.6767 7.794 16.6767L7.94745 18.4347C7.94745 18.4347 10.4626 17.7909 10.7928 17.7075L11.3966 20.0491L12.8043 19.6856L12.2005 17.3272C12.5874 17.2371 12.9644 17.1437 13.3313 17.047L13.9317 19.392L15.3394 19.0284L14.7356 16.6901C16.9039 16.163 18.435 14.7954 18.1214 12.7039C17.9213 11.443 16.5436 10.4089 15.3995 10.2922C16.1033 9.66838 16.4602 8.75773 16.0232 7.56688ZM15.3461 13.0875C15.6263 15.159 12.7476 15.4125 11.7969 15.6627L10.9696 12.5638C11.9236 12.3136 14.8724 11.2629 15.3461 13.0875ZM13.6115 8.86781C13.9084 10.7091 11.4466 10.9226 10.6527 11.1261L9.89884 8.31408C10.6961 8.11727 13.0077 7.16326 13.6115 8.86781Z" fill="white"/>
<path id="Vector_5" d="M16.0232 7.56688C15.3628 6.06914 13.845 5.74891 11.987 6.05913L11.3899 3.74414L9.98224 4.10773L10.5693 6.41605C10.1991 6.50945 9.81879 6.58951 9.44185 6.69625L8.85476 4.40128L7.44709 4.76487L8.04418 7.07986C7.74063 7.16659 5.20215 7.81706 5.20215 7.81706L5.58909 9.3248C5.58909 9.3248 6.62317 9.03459 6.61316 9.05794C7.1869 8.90784 7.4571 9.19471 7.58385 9.4649L9.22503 15.8094C9.24504 15.9929 9.21169 16.3065 8.81807 16.4132C8.84142 16.4266 7.794 16.6767 7.794 16.6767L7.94745 18.4347C7.94745 18.4347 10.4626 17.7909 10.7928 17.7075L11.3966 20.0491L12.8043 19.6856L12.2005 17.3272C12.5874 17.2371 12.9644 17.1437 13.3313 17.047L13.9317 19.392L15.3394 19.0284L14.7356 16.6901C16.9039 16.163 18.435 14.7954 18.1214 12.7039C17.9213 11.443 16.5436 10.4089 15.3995 10.2922C16.1033 9.66838 16.4602 8.75773 16.0232 7.56688ZM15.3461 13.0875C15.6263 15.159 12.7476 15.4125 11.7969 15.6627L10.9696 12.5638C11.9236 12.3136 14.8724 11.2629 15.3461 13.0875ZM13.6115 8.86781C13.9084 10.7091 11.4466 10.9226 10.6527 11.1261L9.89884 8.31408C10.6961 8.11727 13.0077 7.16326 13.6115 8.86781Z" fill="url(#paint3_linear_0_49)"/>
<path id="Vector_6" d="M11.987 6.05911C13.845 5.74889 15.3628 6.06912 16.0232 7.56683C16.4602 8.75768 16.1033 9.66842 15.3995 10.2922C16.5436 10.409 17.9212 11.443 18.1214 12.7039C18.4349 14.7954 16.9039 16.163 14.7357 16.6901L15.3394 19.0284L13.9317 19.392L13.3313 17.047C12.9644 17.1437 12.5874 17.2371 12.2005 17.3272L12.8043 19.6856L11.3966 20.0492L10.7928 17.7075C10.4626 17.7909 7.94744 18.4346 7.94744 18.4346L7.79404 16.6767C7.80158 16.6749 8.84131 16.4265 8.81805 16.4132C9.21163 16.3065 9.24506 15.993 9.22506 15.8095L7.58386 9.46493C7.4571 9.19474 7.18689 8.90781 6.61315 9.05792C6.62253 9.03484 5.59753 9.32242 5.58914 9.32478L5.20215 7.81706C5.20215 7.81706 7.7406 7.16656 8.04416 7.07983L7.44709 4.76486L8.8548 4.40128L9.44181 6.69623C9.81875 6.58948 10.1991 6.50942 10.5693 6.41602L9.98221 4.10772L11.3899 3.74414L11.987 6.05911ZM10.2376 4.25886L10.8251 6.56839L10.6208 6.61994C10.2383 6.71642 9.87362 6.79255 9.49911 6.8986L9.2916 6.95734L8.70315 4.65756L7.70317 4.9159L8.29901 7.22574L8.10197 7.28211C7.94678 7.32645 7.23222 7.5117 6.56181 7.6846C6.22546 7.77135 5.89864 7.85544 5.65588 7.91778C5.58133 7.93693 5.51466 7.954 5.45812 7.96851L5.73936 9.0648C5.82959 9.03983 5.93984 9.00948 6.04996 8.97968C6.17883 8.94479 6.3087 8.91026 6.40625 8.88583C6.45451 8.87374 6.49746 8.86347 6.52905 8.85687C6.54363 8.85383 6.56168 8.85034 6.57823 8.84835C6.57823 8.84835 6.58416 8.84766 6.58973 8.84722C6.90511 8.77079 7.16389 8.80569 7.36875 8.92023C7.56227 9.02843 7.68376 9.19423 7.75964 9.34552L7.77422 9.3756L7.78254 9.39326L9.42857 15.7568L9.43247 15.7715L9.43411 15.7866C9.44642 15.8994 9.44465 16.0677 9.36624 16.2311C9.28659 16.397 9.13796 16.5358 8.90317 16.6072C8.89591 16.6106 8.89064 16.6128 8.88879 16.6136C8.87372 16.6196 8.85655 16.6251 8.84259 16.6294C8.81223 16.6387 8.77005 16.6504 8.72214 16.6631C8.62536 16.689 8.49515 16.722 8.36544 16.7541C8.24089 16.785 8.11571 16.8154 8.01921 16.8387L8.13534 18.1694C8.18253 18.1574 8.2356 18.1439 8.29347 18.1291C8.53442 18.0674 8.85912 17.9843 9.19415 17.8986C9.86394 17.7273 10.5757 17.5454 10.7413 17.5036L10.9442 17.4523L11.5476 19.7929L12.5485 19.5343L11.9435 17.1711L12.1528 17.1224C12.5378 17.0328 12.9128 16.9398 13.2776 16.8437L13.4825 16.7896L14.0832 19.1356L15.0832 18.8774L14.4787 16.5361L14.686 16.4857C15.7437 16.2286 16.6263 15.7708 17.2043 15.1414C17.7766 14.5182 18.0606 13.717 17.9134 12.7351C17.823 12.1693 17.4648 11.6381 16.9792 11.23C16.493 10.8213 15.901 10.5547 15.3781 10.5014L14.9013 10.4527L15.2599 10.1348C15.5869 9.84501 15.8261 9.49529 15.9361 9.08738C16.0454 8.68205 16.0315 8.2035 15.8281 7.64579C15.5226 6.95728 15.0266 6.54485 14.3884 6.3348C13.7394 6.1212 12.9336 6.11425 12.0216 6.26652L11.8315 6.29825L11.2388 4.00032L10.2376 4.25886ZM13.3229 11.8378C13.7953 11.8038 14.2771 11.8341 14.6798 12.0075C15.0939 12.1859 15.4139 12.512 15.5496 13.0346L15.5528 13.0468L15.5544 13.0593C15.6318 13.6312 15.4906 14.0922 15.2101 14.4568C14.9349 14.8147 14.5362 15.0664 14.1178 15.2505C13.698 15.4352 13.2427 15.5587 12.8388 15.6511C12.4197 15.7469 12.0875 15.8037 11.8504 15.8661L11.6477 15.9194L10.7119 12.4139L10.9163 12.3603C11.3734 12.2405 12.3815 11.9055 13.3229 11.8378ZM15.3461 13.0875C14.8724 11.2629 11.9237 12.3135 10.9697 12.5637L11.7968 15.6627C12.7475 15.4125 15.6263 15.159 15.3461 13.0875ZM11.8138 7.66807C12.2088 7.64183 12.6192 7.67592 12.978 7.84406C13.3331 8.01046 13.622 8.30115 13.7935 8.75337L13.8097 8.79763L13.8161 8.81549L13.8191 8.83439C13.9015 9.34574 13.7929 9.76098 13.5572 10.0911C13.3262 10.4146 12.9851 10.6399 12.6284 10.8025C12.2706 10.9657 11.8818 11.0727 11.5387 11.1513C11.3668 11.1907 11.204 11.2234 11.0618 11.2522C10.9175 11.2815 10.7979 11.3059 10.705 11.3298L10.5035 11.3814L9.64019 8.16133L9.84842 8.10989C10.212 8.02015 11.0367 7.71971 11.8138 7.66807ZM13.6116 8.86786C13.0078 7.16331 10.6961 8.11731 9.89883 8.31412L10.6527 11.1261C11.4466 10.9226 13.9084 10.7091 13.6116 8.86786Z" fill="white"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_49" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#00D096"/>
<stop offset="1" stop-color="#008F5D"/>
</linearGradient>
<linearGradient id="paint1_linear_0_49" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop offset="0.725084" stop-color="#00744C" stop-opacity="0"/>
<stop offset="1" stop-color="#00744C" stop-opacity="0.5"/>
</linearGradient>
<linearGradient id="paint2_linear_0_49" x1="11.6821" y1="4.375" x2="11.6821" y2="20.68" gradientUnits="userSpaceOnUse">
<stop stop-color="#01A06B"/>
<stop offset="1" stop-color="#029262"/>
</linearGradient>
<linearGradient id="paint3_linear_0_49" x1="11.6821" y1="3.74414" x2="11.6821" y2="20.0491" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#BCFFEC"/>
</linearGradient>
<clipPath id="clip0_0_49">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 9.4 KiB

+29
View File
@@ -0,0 +1,29 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="network-bsc 1" clip-path="url(#clip0_0_78)">
<path id="Vector" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint0_linear_0_78)"/>
<path id="Vector_2" d="M7.45682 6.36996L12.0249 3.71094L16.593 6.36996L14.9135 7.35227L12.0249 5.67556L9.13626 7.35227L7.45682 6.36996ZM16.593 9.72337L14.9135 8.74106L12.0249 10.4178L9.13626 8.74106L7.45682 9.72337V11.688L10.3454 13.3647V16.7181L12.0249 17.7004L13.7043 16.7181V13.3647L16.593 11.688V9.72337ZM16.593 15.0414V13.0768L14.9135 14.0591V16.0237L16.593 15.0414ZM17.7854 15.7358L14.8968 17.4125V19.3771L19.4648 16.7181V11.4001L17.7854 12.3824V15.7358ZM16.1059 8.04666L17.7854 9.02898V10.9936L19.4648 10.0113V8.04666L17.7854 7.06435L16.1059 8.04666ZM10.3454 18.1238V20.0885L12.0249 21.0708L13.7043 20.0885V18.1238L12.0249 19.1061L10.3454 18.1238ZM7.45682 15.0414L9.13626 16.0237V14.0591L7.45682 13.0768V15.0414ZM10.3454 8.04666L12.0249 9.02898L13.7043 8.04666L12.0249 7.06435L10.3454 8.04666ZM6.2644 9.02898L7.94384 8.04666L6.2644 7.06435L4.58496 8.04666V10.0113L6.2644 10.9936V9.02898ZM6.2644 12.3824L4.58496 11.4001V16.7181L9.15304 19.3771V17.4125L6.2644 15.7358V12.3824Z" fill="#F0B90B"/>
<path id="Vector_3" d="M7.45682 6.36996L12.0249 3.71094L16.593 6.36996L14.9135 7.35227L12.0249 5.67556L9.13626 7.35227L7.45682 6.36996ZM16.593 9.72337L14.9135 8.74106L12.0249 10.4178L9.13626 8.74106L7.45682 9.72337V11.688L10.3454 13.3647V16.7181L12.0249 17.7004L13.7043 16.7181V13.3647L16.593 11.688V9.72337ZM16.593 15.0414V13.0768L14.9135 14.0591V16.0237L16.593 15.0414ZM17.7854 15.7358L14.8968 17.4125V19.3771L19.4648 16.7181V11.4001L17.7854 12.3824V15.7358ZM16.1059 8.04666L17.7854 9.02898V10.9936L19.4648 10.0113V8.04666L17.7854 7.06435L16.1059 8.04666ZM10.3454 18.1238V20.0885L12.0249 21.0708L13.7043 20.0885V18.1238L12.0249 19.1061L10.3454 18.1238ZM7.45682 15.0414L9.13626 16.0237V14.0591L7.45682 13.0768V15.0414ZM10.3454 8.04666L12.0249 9.02898L13.7043 8.04666L12.0249 7.06435L10.3454 8.04666ZM6.2644 9.02898L7.94384 8.04666L6.2644 7.06435L4.58496 8.04666V10.0113L6.2644 10.9936V9.02898ZM6.2644 12.3824L4.58496 11.4001V16.7181L9.15304 19.3771V17.4125L6.2644 15.7358V12.3824Z" fill="#F1B80B"/>
<path id="Vector_4" d="M7.45682 6.36996L12.0249 3.71094L16.593 6.36996L14.9135 7.35227L12.0249 5.67556L9.13626 7.35227L7.45682 6.36996ZM16.593 9.72337L14.9135 8.74106L12.0249 10.4178L9.13626 8.74106L7.45682 9.72337V11.688L10.3454 13.3647V16.7181L12.0249 17.7004L13.7043 16.7181V13.3647L16.593 11.688V9.72337ZM16.593 15.0414V13.0768L14.9135 14.0591V16.0237L16.593 15.0414ZM17.7854 15.7358L14.8968 17.4125V19.3771L19.4648 16.7181V11.4001L17.7854 12.3824V15.7358ZM16.1059 8.04666L17.7854 9.02898V10.9936L19.4648 10.0113V8.04666L17.7854 7.06435L16.1059 8.04666ZM10.3454 18.1238V20.0885L12.0249 21.0708L13.7043 20.0885V18.1238L12.0249 19.1061L10.3454 18.1238ZM7.45682 15.0414L9.13626 16.0237V14.0591L7.45682 13.0768V15.0414ZM10.3454 8.04666L12.0249 9.02898L13.7043 8.04666L12.0249 7.06435L10.3454 8.04666ZM6.2644 9.02898L7.94384 8.04666L6.2644 7.06435L4.58496 8.04666V10.0113L6.2644 10.9936V9.02898ZM6.2644 12.3824L4.58496 11.4001V16.7181L9.15304 19.3771V17.4125L6.2644 15.7358V12.3824Z" fill="black"/>
<path id="Vector_5" d="M7.45682 5.9725L12.0249 3.31348L16.593 5.9725L14.9135 6.95481L12.0249 5.2781L9.13626 6.95481L7.45682 5.9725ZM16.593 9.32591L14.9135 8.3436L12.0249 10.0203L9.13626 8.3436L7.45682 9.32591V11.2905L10.3454 12.9672V16.3206L12.0249 17.303L13.7043 16.3206V12.9672L16.593 11.2905V9.32591ZM16.593 14.644V12.6793L14.9135 13.6616V15.6263L16.593 14.644ZM17.7854 15.3383L14.8968 17.015V18.9797L19.4648 16.3206V11.0026L17.7854 11.9849V15.3383ZM16.1059 7.6492L17.7854 8.63152V10.5961L19.4648 9.61383V7.6492L17.7854 6.66689L16.1059 7.6492ZM10.3454 17.7264V19.691L12.0249 20.6733L13.7043 19.691V17.7264L12.0249 18.7087L10.3454 17.7264ZM7.45682 14.644L9.13626 15.6263V13.6616L7.45682 12.6793V14.644ZM10.3454 7.6492L12.0249 8.63152L13.7043 7.6492L12.0249 6.66689L10.3454 7.6492ZM6.2644 8.63152L7.94384 7.6492L6.2644 6.66689L4.58496 7.6492V9.61383L6.2644 10.5961V8.63152ZM6.2644 11.9849L4.58496 11.0026V16.3206L9.15304 18.9797V17.015L6.2644 15.3383V11.9849Z" fill="#F0B90B"/>
<path id="Vector_6" d="M7.45682 5.9725L12.0249 3.31348L16.593 5.9725L14.9135 6.95481L12.0249 5.2781L9.13626 6.95481L7.45682 5.9725ZM16.593 9.32591L14.9135 8.3436L12.0249 10.0203L9.13626 8.3436L7.45682 9.32591V11.2905L10.3454 12.9672V16.3206L12.0249 17.303L13.7043 16.3206V12.9672L16.593 11.2905V9.32591ZM16.593 14.644V12.6793L14.9135 13.6616V15.6263L16.593 14.644ZM17.7854 15.3383L14.8968 17.015V18.9797L19.4648 16.3206V11.0026L17.7854 11.9849V15.3383ZM16.1059 7.6492L17.7854 8.63152V10.5961L19.4648 9.61383V7.6492L17.7854 6.66689L16.1059 7.6492ZM10.3454 17.7264V19.691L12.0249 20.6733L13.7043 19.691V17.7264L12.0249 18.7087L10.3454 17.7264ZM7.45682 14.644L9.13626 15.6263V13.6616L7.45682 12.6793V14.644ZM10.3454 7.6492L12.0249 8.63152L13.7043 7.6492L12.0249 6.66689L10.3454 7.6492ZM6.2644 8.63152L7.94384 7.6492L6.2644 6.66689L4.58496 7.6492V9.61383L6.2644 10.5961V8.63152ZM6.2644 11.9849L4.58496 11.0026V16.3206L9.15304 18.9797V17.015L6.2644 15.3383V11.9849Z" fill="#F1B80B"/>
<path id="Vector_7" d="M7.45682 5.9725L12.0249 3.31348L16.593 5.9725L14.9135 6.95481L12.0249 5.2781L9.13626 6.95481L7.45682 5.9725ZM16.593 9.32591L14.9135 8.3436L12.0249 10.0203L9.13626 8.3436L7.45682 9.32591V11.2905L10.3454 12.9672V16.3206L12.0249 17.303L13.7043 16.3206V12.9672L16.593 11.2905V9.32591ZM16.593 14.644V12.6793L14.9135 13.6616V15.6263L16.593 14.644ZM17.7854 15.3383L14.8968 17.015V18.9797L19.4648 16.3206V11.0026L17.7854 11.9849V15.3383ZM16.1059 7.6492L17.7854 8.63152V10.5961L19.4648 9.61383V7.6492L17.7854 6.66689L16.1059 7.6492ZM10.3454 17.7264V19.691L12.0249 20.6733L13.7043 19.691V17.7264L12.0249 18.7087L10.3454 17.7264ZM7.45682 14.644L9.13626 15.6263V13.6616L7.45682 12.6793V14.644ZM10.3454 7.6492L12.0249 8.63152L13.7043 7.6492L12.0249 6.66689L10.3454 7.6492ZM6.2644 8.63152L7.94384 7.6492L6.2644 6.66689L4.58496 7.6492V9.61383L6.2644 10.5961V8.63152ZM6.2644 11.9849L4.58496 11.0026V16.3206L9.15304 18.9797V17.015L6.2644 15.3383V11.9849Z" fill="url(#paint1_linear_0_78)"/>
<path id="Vector_8" d="M13.6055 19.6338L12.0244 20.5576L10.4443 19.6338V17.8984L11.9746 18.7939L12.0244 18.8232L12.0752 18.7939L13.6055 17.8984V19.6338ZM6.16504 12.041V15.3955L6.21484 15.4238L9.05371 17.0713V18.8057L4.68457 16.2637V11.1748L6.16504 12.041ZM19.3652 16.2637L14.9961 18.8057V17.0713L17.835 15.4238L17.8848 15.3955V12.041L19.3652 11.1748V16.2637ZM9.03711 13.7178V15.4531L7.55566 14.5869V12.8516L9.03711 13.7178ZM16.4941 14.5869L15.0127 15.4531V13.7178L16.4941 12.8506V14.5869ZM7.74707 7.64844L6.21387 8.5459L6.16504 8.57422V10.4229L4.68457 9.55664V7.70508L6.26367 6.78223L7.74707 7.64844ZM13.5078 7.64844L12.0244 8.51562L10.541 7.64844L12.0244 6.78223L13.5078 7.64844ZM16.3955 5.97266L14.9121 6.83984L12.0742 5.19238L12.0244 5.16309L11.9756 5.19238L9.13672 6.83984L7.65332 5.97266L12.0244 3.42773L16.3955 5.97266ZM10.4443 12.9102L10.3955 12.8818L7.55566 11.2334V9.38184L9.13672 8.45801L11.9756 10.1064L12.0244 10.1348L12.0742 10.1064L14.9121 8.45801L16.4941 9.38184V11.2334L13.6543 12.8818L13.6055 12.9102V16.2637L12.0244 17.1875L10.4443 16.2637V12.9102ZM17.8848 8.57422L17.8359 8.5459L16.3018 7.64844L17.7852 6.78223L19.3652 7.70508V9.55664L17.8848 10.4229V8.57422Z" stroke="url(#paint2_linear_0_78)" stroke-width="0.198398"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_78" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#231F10"/>
<stop offset="1" stop-color="#0E0B03"/>
</linearGradient>
<linearGradient id="paint1_linear_0_78" x1="12.0249" y1="3.31348" x2="12.0249" y2="20.6733" gradientUnits="userSpaceOnUse">
<stop stop-color="#F1B80B"/>
<stop offset="1" stop-color="#9F7800"/>
</linearGradient>
<linearGradient id="paint2_linear_0_78" x1="12.0249" y1="3.31348" x2="12.0249" y2="20.6733" gradientUnits="userSpaceOnUse">
<stop stop-color="#FFE69B"/>
<stop offset="1" stop-color="#D69F00"/>
</linearGradient>
<clipPath id="clip0_0_78">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 8.5 KiB

+49
View File
@@ -0,0 +1,49 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="network-decred 1" clip-path="url(#clip0_0_109)">
<path id="Vector" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint0_linear_0_109)"/>
<path id="Vector_2" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint1_linear_0_109)"/>
<path id="Vector_3" d="M12.9458 11.0445H9.2652C8.60741 11.0445 7.97661 11.3058 7.51148 11.7709C7.04636 12.2361 6.78502 12.8669 6.78501 13.5247C6.78501 14.1825 7.04635 14.8133 7.51148 15.2785C7.97661 15.7436 8.60743 16.0049 9.2652 16.005H10.4362L12.9446 18.1818H9.2652C8.18525 18.1816 7.13896 17.8061 6.30525 17.1196C5.47154 16.4332 4.90219 15.4783 4.6947 14.4185C4.48721 13.3587 4.65442 12.2596 5.16772 11.3094C5.68102 10.3593 6.50851 9.61693 7.50865 9.20946L4.60921 6.68945H7.93259L12.9458 11.0445Z" fill="url(#paint2_linear_0_109)"/>
<path id="Vector_4" d="M14.8294 6.68945C15.9093 6.68969 16.9557 7.06516 17.7894 7.75164C18.6231 8.43811 19.1924 9.39294 19.3999 10.4528C19.6074 11.5126 19.4402 12.6117 18.9269 13.5618C18.4136 14.512 17.5861 15.2544 16.5859 15.6618L19.4877 18.1807H16.1643L11.1489 13.8268H14.8294C15.4872 13.8268 16.1181 13.5655 16.5832 13.1003C17.0483 12.6352 17.3097 12.0044 17.3097 11.3466C17.3097 10.6888 17.0483 10.0579 16.5832 9.5928C16.1181 9.12767 15.4872 8.86633 14.8294 8.86633H13.6584L11.1489 6.68945H14.8294Z" fill="url(#paint3_linear_0_109)"/>
<path id="Vector_5" d="M12.9457 10.6451H9.2652C8.60741 10.6451 7.97651 10.9063 7.51138 11.3714C7.04625 11.8366 6.78501 12.4675 6.78501 13.1252C6.78501 13.783 7.04625 14.4139 7.51138 14.8791C7.97651 15.3442 8.60741 15.6054 9.2652 15.6054H10.4362L12.9445 17.7824H9.2652C8.18523 17.7822 7.13887 17.4067 6.30515 16.7202C5.47145 16.0338 4.90219 15.0789 4.6947 14.0191C4.48721 12.9592 4.65442 11.8602 5.16772 10.91C5.68102 9.95984 6.50851 9.21751 7.50865 8.81005L4.60921 6.29004H7.93259L12.9457 10.6451ZM14.8292 6.29004C15.9091 6.29028 16.9555 6.66575 17.7892 7.35222C18.6229 8.0387 19.1922 8.99352 19.3997 10.0534C19.6072 11.1132 19.44 12.2122 18.9267 13.1624C18.4134 14.1126 17.5859 14.8549 16.5857 15.2624L19.4875 17.7812H16.1641L11.1487 13.4274H14.8292C15.487 13.4274 16.1179 13.1661 16.583 12.7009C17.0481 12.2358 17.3095 11.605 17.3095 10.9472C17.3095 10.2894 17.0481 9.65852 16.583 9.19339C16.1179 8.72825 15.487 8.46691 14.8292 8.46691H13.6582L11.1487 6.29004H14.8292Z" fill="url(#paint4_linear_0_109)"/>
<path id="Vector_6" d="M12.9457 10.6451H9.2652C8.60741 10.6451 7.97651 10.9063 7.51138 11.3714C7.04625 11.8366 6.78501 12.4675 6.78501 13.1252C6.78501 13.783 7.04625 14.4139 7.51138 14.8791C7.97651 15.3442 8.60741 15.6054 9.2652 15.6054H10.4362L12.9445 17.7824H9.2652C8.18523 17.7822 7.13887 17.4067 6.30515 16.7202C5.47145 16.0338 4.90219 15.0789 4.6947 14.0191C4.48721 12.9592 4.65442 11.8602 5.16772 10.91C5.68102 9.95984 6.50851 9.21751 7.50865 8.81005L4.60921 6.29004H7.93259L12.9457 10.6451ZM14.8292 6.29004C15.9091 6.29028 16.9555 6.66575 17.7892 7.35222C18.6229 8.0387 19.1922 8.99352 19.3997 10.0534C19.6072 11.1132 19.44 12.2122 18.9267 13.1624C18.4134 14.1126 17.5859 14.8549 16.5857 15.2624L19.4875 17.7812H16.1641L11.1487 13.4274H14.8292C15.487 13.4274 16.1179 13.1661 16.583 12.7009C17.0481 12.2358 17.3095 11.605 17.3095 10.9472C17.3095 10.2894 17.0481 9.65852 16.583 9.19339C16.1179 8.72825 15.487 8.46691 14.8292 8.46691H13.6582L11.1487 6.29004H14.8292Z" fill="url(#paint5_linear_0_109)"/>
<path id="Vector_7" d="M12.9458 10.6451H9.2652V10.4452H12.411L7.85793 6.48991H5.14381L7.88516 8.8725L7.58409 8.99518C6.62688 9.38516 5.83486 10.0956 5.34358 11.005C4.85231 11.9144 4.69227 12.9664 4.89086 13.9807C5.08945 14.9951 5.63438 15.9089 6.43232 16.5659C7.23024 17.2229 8.23161 17.5823 9.2652 17.5825V17.7824C8.18525 17.7822 7.13896 17.4067 6.30525 16.7202C5.47154 16.0338 4.90219 15.0789 4.6947 14.0191C4.48721 12.9592 4.65442 11.8602 5.16772 10.91C5.68102 9.95985 6.50851 9.21751 7.50865 8.81005L4.60921 6.29004H7.93259L12.9458 10.6451ZM6.58514 13.1252C6.58515 12.4144 6.86757 11.7328 7.37017 11.2302C7.87277 10.7276 8.5544 10.4452 9.2652 10.4452V10.6451C8.60741 10.6451 7.97661 10.9064 7.51148 11.3715C7.04636 11.8367 6.78502 12.4675 6.78501 13.1252C6.78501 13.783 7.04635 14.4139 7.51148 14.8791C7.97661 15.3442 8.60743 15.6055 9.2652 15.6055H10.4362L12.9446 17.7824H9.2652V17.5825H12.4094L10.3615 15.8054H9.2652C8.55441 15.8054 7.87277 15.523 7.37017 15.0204C6.86756 14.5178 6.58514 13.8361 6.58514 13.1252ZM14.8294 6.29004C15.9093 6.29028 16.9557 6.66575 17.7894 7.35222C18.6231 8.0387 19.1924 8.99352 19.3999 10.0534C19.6074 11.1132 19.4402 12.2122 18.9269 13.1624C18.4136 14.1126 17.5861 14.8549 16.5859 15.2624L19.4877 17.7812H16.1643L11.1489 13.4274H14.8294C15.4872 13.4274 16.1181 13.1661 16.5832 12.7009C17.0483 12.2358 17.3097 11.605 17.3097 10.9472C17.3097 10.2894 17.0483 9.65852 16.5832 9.19339C16.1181 8.72826 15.4872 8.46691 14.8294 8.46691V8.26705C15.5402 8.26705 16.2219 8.54946 16.7245 9.05207C17.2114 9.53898 17.4917 10.194 17.5088 10.8806L17.5095 10.9472C17.5095 11.658 17.2271 12.3396 16.7245 12.8422C16.2219 13.3448 15.5402 13.6273 14.8294 13.6273H11.6841L16.2391 17.5814H18.9524L16.2092 15.2L16.5105 15.0773C17.4677 14.6873 18.2597 13.9769 18.751 13.0675C19.2423 12.1581 19.4023 11.1061 19.2037 10.0917C19.0051 9.07737 18.4603 8.16352 17.6624 7.50652C16.8893 6.87002 15.9253 6.51288 14.9261 6.49098L14.8294 6.48991H11.6843L13.7329 8.26705H14.8294V8.46691H13.6584L11.1489 6.29004H14.8294Z" fill="url(#paint6_linear_0_109)"/>
<path id="Vector_8" d="M12.9458 10.6451H9.2652V10.4452H12.411L7.85793 6.48991H5.14381L7.88516 8.8725L7.58409 8.99518C6.62688 9.38516 5.83486 10.0956 5.34358 11.005C4.85231 11.9144 4.69227 12.9664 4.89086 13.9807C5.08945 14.9951 5.63438 15.9089 6.43232 16.5659C7.23024 17.2229 8.23161 17.5823 9.2652 17.5825V17.7824C8.18525 17.7822 7.13896 17.4067 6.30525 16.7202C5.47154 16.0338 4.90219 15.0789 4.6947 14.0191C4.48721 12.9592 4.65442 11.8602 5.16772 10.91C5.68102 9.95985 6.50851 9.21751 7.50865 8.81005L4.60921 6.29004H7.93259L12.9458 10.6451ZM6.58514 13.1252C6.58515 12.4144 6.86757 11.7328 7.37017 11.2302C7.87277 10.7276 8.5544 10.4452 9.2652 10.4452V10.6451C8.60741 10.6451 7.97661 10.9064 7.51148 11.3715C7.04636 11.8367 6.78502 12.4675 6.78501 13.1252C6.78501 13.783 7.04635 14.4139 7.51148 14.8791C7.97661 15.3442 8.60743 15.6055 9.2652 15.6055H10.4362L12.9446 17.7824H9.2652V17.5825H12.4094L10.3615 15.8054H9.2652C8.55441 15.8054 7.87277 15.523 7.37017 15.0204C6.86756 14.5178 6.58514 13.8361 6.58514 13.1252ZM14.8294 6.29004C15.9093 6.29028 16.9557 6.66575 17.7894 7.35222C18.6231 8.0387 19.1924 8.99352 19.3999 10.0534C19.6074 11.1132 19.4402 12.2122 18.9269 13.1624C18.4136 14.1126 17.5861 14.8549 16.5859 15.2624L19.4877 17.7812H16.1643L11.1489 13.4274H14.8294C15.4872 13.4274 16.1181 13.1661 16.5832 12.7009C17.0483 12.2358 17.3097 11.605 17.3097 10.9472C17.3097 10.2894 17.0483 9.65852 16.5832 9.19339C16.1181 8.72826 15.4872 8.46691 14.8294 8.46691V8.26705C15.5402 8.26705 16.2219 8.54946 16.7245 9.05207C17.2114 9.53898 17.4917 10.194 17.5088 10.8806L17.5095 10.9472C17.5095 11.658 17.2271 12.3396 16.7245 12.8422C16.2219 13.3448 15.5402 13.6273 14.8294 13.6273H11.6841L16.2391 17.5814H18.9524L16.2092 15.2L16.5105 15.0773C17.4677 14.6873 18.2597 13.9769 18.751 13.0675C19.2423 12.1581 19.4023 11.1061 19.2037 10.0917C19.0051 9.07737 18.4603 8.16352 17.6624 7.50652C16.8893 6.87002 15.9253 6.51288 14.9261 6.49098L14.8294 6.48991H11.6843L13.7329 8.26705H14.8294V8.46691H13.6584L11.1489 6.29004H14.8294Z" fill="url(#paint7_linear_0_109)"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_109" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#0043D3"/>
<stop offset="1" stop-color="#00138C"/>
</linearGradient>
<linearGradient id="paint1_linear_0_109" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop offset="0.725084" stop-color="#000F3C" stop-opacity="0"/>
<stop offset="1" stop-color="#000F3C" stop-opacity="0.5"/>
</linearGradient>
<linearGradient id="paint2_linear_0_109" x1="12.0478" y1="6.68945" x2="12.0478" y2="18.1818" gradientUnits="userSpaceOnUse">
<stop stop-color="#001E78"/>
<stop offset="1" stop-color="#001553"/>
</linearGradient>
<linearGradient id="paint3_linear_0_109" x1="12.0478" y1="6.68945" x2="12.0478" y2="18.1818" gradientUnits="userSpaceOnUse">
<stop stop-color="#001E78"/>
<stop offset="1" stop-color="#001553"/>
</linearGradient>
<linearGradient id="paint4_linear_0_109" x1="8.77682" y1="6.29004" x2="8.77682" y2="17.7824" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#9ABBFF"/>
</linearGradient>
<linearGradient id="paint5_linear_0_109" x1="8.77682" y1="6.29004" x2="8.77682" y2="17.7824" gradientUnits="userSpaceOnUse">
<stop stop-color="#E0E9FF"/>
<stop offset="1" stop-color="#9ABBFF"/>
</linearGradient>
<linearGradient id="paint6_linear_0_109" x1="12.0478" y1="6.29004" x2="12.0478" y2="17.7824" gradientUnits="userSpaceOnUse">
<stop stop-color="white" stop-opacity="0.5"/>
<stop offset="1" stop-color="white" stop-opacity="0.2"/>
</linearGradient>
<linearGradient id="paint7_linear_0_109" x1="12.0478" y1="6.29004" x2="12.0478" y2="17.7824" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<clipPath id="clip0_0_109">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 10 KiB

+30
View File
@@ -0,0 +1,30 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="network-dogecoin 1" clip-path="url(#clip0_0_61)">
<path id="Vector" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint0_linear_0_61)"/>
<path id="Vector_2" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint1_linear_0_61)"/>
<path id="Vector_3" fill-rule="evenodd" clip-rule="evenodd" d="M11.4123 5.48099C12.3663 5.48098 18.6841 5.28301 18.6841 12.6091C18.6841 20.0565 12.0783 19.5029 12.0783 19.5029H7.38025V13.2571H5.72412V11.7272H7.38015V5.48099H11.4123ZM10.0265 8.07277V11.727H12.9425V13.257H10.0265V16.9109H11.9708C12.4705 16.9109 16.0722 16.9673 16.0666 12.6596C16.061 8.3519 12.5733 8.07278 11.88 8.07277H10.0265Z" fill="url(#paint2_linear_0_61)"/>
<path id="Vector_4" fill-rule="evenodd" clip-rule="evenodd" d="M11.4123 4.96927C12.3663 4.96927 18.6841 4.77129 18.6841 12.0974C18.6841 19.5448 12.0783 18.9912 12.0783 18.9912H7.38025V12.7454H5.72412V11.2155H7.38015V4.96927H11.4123ZM10.0265 7.56105V11.2153H12.9425V12.7453H10.0265V16.3992H11.9708C12.4705 16.3992 16.0722 16.4556 16.0666 12.1479C16.061 7.84018 12.5733 7.56106 11.88 7.56105H10.0265Z" fill="url(#paint3_linear_0_61)"/>
<path id="Vector_5" d="M11.4123 4.96927C12.3663 4.96927 18.6841 4.7713 18.6841 12.0974C18.6841 19.5448 12.0783 18.9912 12.0783 18.9912H7.38025V12.7454H5.72412V11.2155H7.38015V4.96927H11.4123ZM11.4123 5.17683H7.58771V11.423H5.93168V12.5379H7.58781V18.7836H12.0871L12.0957 18.7843C12.0955 18.7843 12.0957 18.7844 12.0957 18.7843C12.0962 18.7844 12.0974 18.7846 12.0986 18.7846C12.1012 18.7848 12.1053 18.7851 12.1109 18.7855C12.1221 18.7862 12.1394 18.7872 12.1622 18.7883C12.2078 18.7904 12.2757 18.7926 12.3628 18.7929C12.5372 18.7934 12.7878 18.7862 13.089 18.7549C13.6925 18.692 14.4934 18.533 15.2914 18.15C16.0877 17.7678 16.8807 17.1632 17.4757 16.2068C18.0709 15.2501 18.4766 13.928 18.4766 12.0974C18.4766 10.2962 18.0885 8.97345 17.5041 7.99978C16.92 7.02651 16.132 6.38933 15.3117 5.971C13.6629 5.13017 11.8927 5.17683 11.4123 5.17683ZM11.88 7.35349C12.2449 7.35349 13.3356 7.42552 14.3424 8.06384C15.3647 8.71204 16.2713 9.92649 16.2742 12.1476C16.2756 13.2538 16.0452 14.0951 15.6792 14.7327C15.313 15.3709 14.8175 15.7932 14.3075 16.0712C13.4215 16.554 12.4892 16.6019 12.1018 16.6064L11.9708 16.6068H9.81889V12.5378H12.735V11.4228H9.81889V7.35349H11.88ZM10.0265 11.2153H12.9425V12.7453H10.0265V16.3992H11.9708C12.4705 16.3992 16.0722 16.4556 16.0666 12.1479C16.061 7.84019 12.5733 7.56106 11.88 7.56105H10.0265V11.2153Z" fill="white"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_61" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#C2A633"/>
<stop offset="1" stop-color="#9A6A00"/>
</linearGradient>
<linearGradient id="paint1_linear_0_61" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop offset="0.725084" stop-color="#825101" stop-opacity="0"/>
<stop offset="1" stop-color="#825101" stop-opacity="0.5"/>
</linearGradient>
<linearGradient id="paint2_linear_0_61" x1="12.2041" y1="5.48047" x2="12.2041" y2="19.5122" gradientUnits="userSpaceOnUse">
<stop stop-color="#BB8300"/>
<stop offset="1" stop-color="#7B5700"/>
</linearGradient>
<linearGradient id="paint3_linear_0_61" x1="12.2041" y1="4.96875" x2="12.2041" y2="19.0005" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#FFECA3"/>
</linearGradient>
<clipPath id="clip0_0_61">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.4 KiB

+59
View File
@@ -0,0 +1,59 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="network-ethereum 1" clip-path="url(#clip0_0_13)">
<path id="Vector" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint0_linear_0_13)"/>
<path id="Vector_2" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint1_linear_0_13)"/>
<path id="Vector_3" d="M11.9961 21.585L6.47607 13.812L11.9961 17.0687L17.5161 13.8018L11.9961 21.585Z" fill="url(#paint2_linear_0_13)"/>
<path id="Vector_4" d="M17.5161 12.747L11.9961 16.0036L6.47607 12.747L11.9961 3.58105L17.5161 12.747Z" fill="url(#paint3_linear_0_13)"/>
<path id="Vector_5" d="M11.9961 16.4662V20.9825L17.5161 13.1992L11.9961 16.4662Z" fill="url(#paint4_linear_0_13)"/>
<path id="Vector_6" d="M6.47607 13.21L11.9961 20.983V16.4667L6.47607 13.21Z" fill="url(#paint5_linear_0_13)"/>
<path id="Vector_7" d="M17.5161 12.1444L11.9961 2.97852V15.4011L17.5161 12.1444Z" fill="url(#paint6_linear_0_13)"/>
<path id="Vector_8" d="M11.9961 2.97852L6.47607 12.1444L11.9961 15.4011V2.97852Z" fill="url(#paint7_linear_0_13)"/>
<path id="Vector_9" d="M11.9961 20.9826L6.47607 13.2094L11.9961 16.4661L17.5161 13.1992L11.9961 20.9826ZM12.0983 16.6388C12.0353 16.6761 11.9571 16.6762 11.894 16.639L7.1847 13.8606L11.996 20.6356L16.8069 13.8521L12.0983 16.6388ZM17.5161 12.1444L11.9961 15.401L6.47607 12.1444L11.9961 2.97852L17.5161 12.1444ZM6.75247 12.0743L11.996 15.168L17.2396 12.0743L11.9961 3.36752L6.75247 12.0743Z" fill="url(#paint8_linear_0_13)"/>
<path id="Vector_10" d="M11.9961 20.9826L6.47607 13.2094L11.9961 16.4661L17.5161 13.1992L11.9961 20.9826ZM12.0983 16.6388C12.0353 16.6761 11.9571 16.6762 11.894 16.639L7.1847 13.8606L11.996 20.6356L16.8069 13.8521L12.0983 16.6388ZM17.5161 12.1444L11.9961 15.401L6.47607 12.1444L11.9961 2.97852L17.5161 12.1444ZM6.75247 12.0743L11.996 15.168L17.2396 12.0743L11.9961 3.36752L6.75247 12.0743Z" fill="url(#paint9_linear_0_13)"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_13" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#5970FF"/>
<stop offset="1" stop-color="#3D1BFF"/>
</linearGradient>
<linearGradient id="paint1_linear_0_13" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop offset="0.725084" stop-color="#301CB7" stop-opacity="0"/>
<stop offset="1" stop-color="#301CB7" stop-opacity="0.5"/>
</linearGradient>
<linearGradient id="paint2_linear_0_13" x1="11.9961" y1="3.58105" x2="11.9961" y2="21.585" gradientUnits="userSpaceOnUse">
<stop offset="0.246132" stop-color="#3F39F9"/>
<stop offset="1" stop-color="#3122D3"/>
</linearGradient>
<linearGradient id="paint3_linear_0_13" x1="11.9961" y1="3.58105" x2="11.9961" y2="21.585" gradientUnits="userSpaceOnUse">
<stop offset="0.246132" stop-color="#3F39F9"/>
<stop offset="1" stop-color="#3122D3"/>
</linearGradient>
<linearGradient id="paint4_linear_0_13" x1="14.7561" y1="13.1992" x2="14.7561" y2="20.9825" gradientUnits="userSpaceOnUse">
<stop stop-color="#98A6FF"/>
<stop offset="1" stop-color="#526AFF"/>
</linearGradient>
<linearGradient id="paint5_linear_0_13" x1="9.23608" y1="13.21" x2="9.23608" y2="20.983" gradientUnits="userSpaceOnUse">
<stop stop-color="#B8C2FF"/>
<stop offset="1" stop-color="#8B9BFF"/>
</linearGradient>
<linearGradient id="paint6_linear_0_13" x1="14.7561" y1="2.97852" x2="14.7561" y2="15.4011" gradientUnits="userSpaceOnUse">
<stop stop-color="#B4BFFF"/>
<stop offset="1" stop-color="#6278FE"/>
</linearGradient>
<linearGradient id="paint7_linear_0_13" x1="9.23608" y1="2.97852" x2="9.23608" y2="15.4011" gradientUnits="userSpaceOnUse">
<stop stop-color="#F4F5FF"/>
<stop offset="1" stop-color="#AEB9FF"/>
</linearGradient>
<linearGradient id="paint8_linear_0_13" x1="11.9961" y1="2.97852" x2="11.9961" y2="20.9826" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="0.546865" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint9_linear_0_13" x1="11.9961" y1="2.97852" x2="11.9961" y2="20.9826" gradientUnits="userSpaceOnUse">
<stop offset="0.751951" stop-color="white" stop-opacity="0"/>
<stop offset="1" stop-color="white" stop-opacity="0.5"/>
</linearGradient>
<clipPath id="clip0_0_13">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

+30
View File
@@ -0,0 +1,30 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="network-litecoin 1" clip-path="url(#clip0_0_126)">
<path id="Vector" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint0_linear_0_126)"/>
<path id="Vector_2" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint1_linear_0_126)"/>
<path id="Vector_3" d="M11.4162 16.2609L12.2908 12.9679L14.3612 12.2114L14.8763 10.2762L14.8587 10.2281L12.8206 10.9727L14.289 5.44336H10.1244L8.20402 12.6593L6.60061 13.2451L6.0708 15.2402L7.67298 14.655L6.54115 18.9076H17.6248L18.3354 16.2609H11.4162Z" fill="url(#paint2_linear_0_126)"/>
<path id="Vector_4" d="M11.2009 15.6144L12.0754 12.3214L14.1459 11.565L14.6609 9.62967L14.6433 9.58166L12.6052 10.3262L14.0737 4.79688H9.90909L7.98868 12.0128L6.38528 12.5986L5.85547 14.5937L7.45765 14.0085L6.32582 18.2612H17.4095L18.12 15.6144H11.2009Z" fill="url(#paint3_linear_0_126)"/>
<path id="Vector_5" d="M14.0737 4.79688L12.6052 10.3262L14.6434 9.58161L14.661 9.62968L14.1459 11.565L12.0754 12.3214L11.2009 15.6144H18.12L17.4094 18.2612H6.32577L7.4576 14.0085L5.85547 14.5938L6.38531 12.5985L7.9887 12.0128L9.90914 4.79688H14.0737ZM8.16805 12.1766L6.56465 12.7623L6.16967 14.2495L7.77222 13.6642L6.6061 18.0458H17.2442L17.8391 15.8298H10.9207L11.8961 12.1576L13.9666 11.401L14.3624 9.91359L12.2909 10.6704L13.7936 5.0123H10.0747L8.16805 12.1766Z" fill="white"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_126" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#1C60CA"/>
<stop offset="1" stop-color="#002394"/>
</linearGradient>
<linearGradient id="paint1_linear_0_126" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop offset="0.725084" stop-color="#000E6C" stop-opacity="0"/>
<stop offset="1" stop-color="#000E6C" stop-opacity="0.3"/>
</linearGradient>
<linearGradient id="paint2_linear_0_126" x1="12.2031" y1="5.44336" x2="12.2031" y2="18.9076" gradientUnits="userSpaceOnUse">
<stop stop-color="#063ABA"/>
<stop offset="1" stop-color="#002A9C"/>
</linearGradient>
<linearGradient id="paint3_linear_0_126" x1="11.9878" y1="4.79687" x2="11.9878" y2="18.2612" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#C7DCFF"/>
</linearGradient>
<clipPath id="clip0_0_126">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

+40
View File
@@ -0,0 +1,40 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_24350_437589)">
<path d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint0_linear_24350_437589)"/>
<mask id="mask0_24350_437589" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="1" y="1" width="22" height="21">
<path d="M22.078 1.53613H1.91797V21.6961H22.078V1.53613Z" fill="white"/>
</mask>
<g mask="url(#mask0_24350_437589)">
<path d="M22.0779 15.825V17.9923H16.6007V12.3703L11.9979 16.9677L7.40055 12.3703V17.9923H1.91797V15.825H5.09915V6.8877L12.0033 13.7919L18.9075 6.8877V15.825H22.0779Z" fill="url(#paint1_linear_24350_437589)" fill-opacity="0.75"/>
<path d="M22.0779 14.9081V17.0753H16.6007V11.4533L11.9979 16.0507L7.40055 11.4533V17.0753H1.91797V14.9081H5.09915V5.9707L12.0033 12.8749L18.9075 5.9707V14.9081H22.0779Z" fill="url(#paint2_linear_24350_437589)"/>
<path d="M11.9979 15.7792L16.7927 10.9902V16.8833H21.8859V15.1001H18.7155V6.4342L12.0033 13.1464L5.29119 6.4343V15.1001H2.10997V16.8833H7.20857V10.9898L11.9979 15.7792ZM22.0779 14.9081V17.0753H16.6007V11.4533L11.9979 16.0507L7.40057 11.4533V17.0753H1.91797V14.9081H5.09919V5.9707L12.0033 12.8749L18.9075 5.9707V14.9081H22.0779Z" fill="url(#paint3_linear_24350_437589)"/>
<path d="M11.9979 15.7792L16.7927 10.9902V16.8833H21.8859V15.1001H18.7155V6.4342L12.0033 13.1464L5.29119 6.4343V15.1001H2.10997V16.8833H7.20857V10.9898L11.9979 15.7792ZM22.0779 14.9081V17.0753H16.6007V11.4533L11.9979 16.0507L7.40057 11.4533V17.0753H1.91797V14.9081H5.09919V5.9707L12.0033 12.8749L18.9075 5.9707V14.9081H22.0779Z" fill="url(#paint4_linear_24350_437589)"/>
</g>
</g>
<defs>
<linearGradient id="paint0_linear_24350_437589" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#FF6600"/>
<stop offset="0.662892" stop-color="#EA3E00"/>
<stop offset="1" stop-color="#B51500"/>
</linearGradient>
<linearGradient id="paint1_linear_24350_437589" x1="11.9979" y1="13.0366" x2="11.9979" y2="17.9923" gradientUnits="userSpaceOnUse">
<stop stop-color="#CE2901"/>
<stop offset="1" stop-color="#B72400"/>
</linearGradient>
<linearGradient id="paint2_linear_24350_437589" x1="11.9979" y1="5.9707" x2="11.9979" y2="17.0753" gradientUnits="userSpaceOnUse">
<stop offset="0.312806" stop-color="white"/>
<stop offset="0.750482" stop-color="#FFC7B2"/>
</linearGradient>
<linearGradient id="paint3_linear_24350_437589" x1="12.0109" y1="5.96914" x2="12.0109" y2="17.0753" gradientUnits="userSpaceOnUse">
<stop offset="0.628934" stop-color="white"/>
<stop offset="1" stop-color="white" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint4_linear_24350_437589" x1="12.0109" y1="5.96914" x2="12.0109" y2="17.0753" gradientUnits="userSpaceOnUse">
<stop offset="0.929637" stop-color="white" stop-opacity="0"/>
<stop offset="1" stop-color="white"/>
</linearGradient>
<clipPath id="clip0_24350_437589">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

+30
View File
@@ -0,0 +1,30 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="network-nano 1" clip-path="url(#clip0_0_87)">
<path id="Vector" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint0_linear_0_87)"/>
<path id="Vector_2" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint1_linear_0_87)"/>
<path id="Vector_3" fill-rule="evenodd" clip-rule="evenodd" d="M12.0462 11.2157L16.4404 4.47949H17.6312L12.9836 11.6505H16.8555V12.5602H12.9641L14.1207 14.3797H16.8559V15.2894H14.699L17.9951 20.4749H16.7503L13.4213 15.2894H10.6095L7.22967 20.4749H5.99512L9.33856 15.2894H7.17597L7.17637 14.3797H9.92518L11.0983 12.5602H7.17637V11.6505H11.059L6.47404 4.47949H7.74309L12.0462 11.2157ZM11.2024 14.3797H12.8373L12.0261 13.1161L11.2024 14.3797Z" fill="url(#paint2_linear_0_87)"/>
<path id="Vector_4" fill-rule="evenodd" clip-rule="evenodd" d="M12.0462 10.8065L16.4404 4.07031H17.6312L12.9836 11.2413H16.8555V12.151H12.9641L14.1207 13.9705H16.8559V14.8803H14.699L17.9951 20.0657H16.7503L13.4213 14.8803H10.6095L7.22967 20.0657H5.99512L9.33856 14.8803H7.17597L7.17637 13.9705H9.92518L11.0983 12.151H7.17637V11.2413H11.059L6.47404 4.07031H7.74309L12.0462 10.8065ZM11.2024 13.9705H12.8373L12.0261 12.7069L11.2024 13.9705Z" fill="url(#paint3_linear_0_87)"/>
<path id="Vector_5" d="M12.0462 10.8065L16.4404 4.07031H17.6312L12.9836 11.2413H16.8555V12.151H12.9641L14.1207 13.9705H16.8559V14.8803H14.699L17.9951 20.0657H16.7503L13.4213 14.8803H10.6095L7.22967 20.0657H5.99512L9.33856 14.8803H7.17597L7.17637 13.9705H9.92518L11.0983 12.151H7.17637V11.2413H11.059L6.47404 4.07031H7.74309L12.0462 10.8065ZM11.433 11.4461H7.38117V11.9462H11.474L10.0368 14.1753H7.38107L7.38087 14.6755H9.71427L6.37083 19.8609H7.11866L10.4985 14.6755H13.5332L16.8621 19.8609H17.6223L14.3261 14.6755H16.6511V14.1753H14.0082L12.5912 11.9462H16.6507V11.4461H12.6068L17.2544 4.27512H16.5513L12.0444 11.1841L7.63089 4.27512H6.84805L11.433 11.4461ZM13.2121 14.1753H10.8245L12.0274 12.3298L13.2121 14.1753ZM11.2024 13.9705H12.8373L12.0261 12.7069L11.2024 13.9705Z" fill="white"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_87" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#209CE9"/>
<stop offset="1" stop-color="#007AC5"/>
</linearGradient>
<linearGradient id="paint1_linear_0_87" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop offset="0.725084" stop-color="#003F88" stop-opacity="0"/>
<stop offset="1" stop-color="#003F88" stop-opacity="0.5"/>
</linearGradient>
<linearGradient id="paint2_linear_0_87" x1="11.9951" y1="4.47949" x2="11.9951" y2="20.4749" gradientUnits="userSpaceOnUse">
<stop stop-color="#0E86D2"/>
<stop offset="1" stop-color="#0069AE"/>
</linearGradient>
<linearGradient id="paint3_linear_0_87" x1="11.9951" y1="4.07031" x2="11.9951" y2="20.0657" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#A4DCFF"/>
</linearGradient>
<clipPath id="clip0_0_87">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.9 KiB

+30
View File
@@ -0,0 +1,30 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="network-polygon 1" clip-path="url(#clip0_0_67)">
<path id="Vector" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint0_linear_0_67)"/>
<path id="Vector_2" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint1_linear_0_67)"/>
<path id="Vector_3" d="M15.5495 5.65527L11.2207 8.14136V15.9005L8.83232 17.2851L6.42932 15.8994V13.1293L8.83232 11.7571L10.3774 12.6531V10.4118L8.81884 9.52701L4.49121 12.0411V17.0145L8.83344 19.5151L13.1611 17.0145V9.25639L15.564 7.87074L17.9659 9.25639V12.0142L15.564 13.4122L14.0055 12.5083V14.7383L15.5495 15.6288L19.9198 13.1427V8.14136L15.5495 5.65527Z" fill="url(#paint2_linear_0_67)"/>
<path id="Vector_4" d="M15.1379 5.03809L10.8091 7.52417V15.2834L8.4207 16.6679L6.0177 15.2823V12.5121L8.4207 11.1399L9.96582 12.0359V9.79466L8.40722 8.90982L4.07959 11.424V16.3973L8.42182 18.898L12.7495 16.3973V8.6392L15.1524 7.25355L17.5543 8.6392V11.3971L15.1524 12.795L13.5939 11.8911V14.1212L15.1379 15.0116L19.5082 12.5255V7.52417L15.1379 5.03809Z" fill="url(#paint3_linear_0_67)"/>
<path id="Vector_5" d="M19.5082 7.52413V12.5256L15.1378 15.0116L13.5939 14.1212V11.8911L15.1524 12.7951L17.5543 11.397V8.63919L15.1524 7.25353L12.7494 8.63919V16.3973L8.42179 18.898L4.07959 16.3973V11.424L8.40722 8.90979L9.96585 9.79463V12.0359L8.42068 11.1399L6.0177 12.5121V15.2822L8.42068 16.6679L10.8091 15.2833V7.52413L15.1378 5.03809L19.5082 7.52413ZM17.76 11.5154L15.1526 13.0329L13.7996 12.2481V14.0023L15.1385 14.7746L19.3024 12.4058V7.64377L15.1383 5.27494L11.0148 7.64316V15.4018L8.42098 16.9055L5.81199 15.4011V12.3927L8.42149 10.9025L9.76014 11.6788V9.91436L8.40843 9.14695L4.2853 11.5424V16.2782L8.42159 18.6604L12.5437 16.2785V8.52036L15.1524 7.01608L17.76 8.52036V11.5154Z" fill="white"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_67" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#7158FF"/>
<stop offset="1" stop-color="#4A2AFF"/>
</linearGradient>
<linearGradient id="paint1_linear_0_67" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop offset="0.725084" stop-color="#3115CD" stop-opacity="0"/>
<stop offset="1" stop-color="#3115CD" stop-opacity="0.5"/>
</linearGradient>
<linearGradient id="paint2_linear_0_67" x1="12.2055" y1="5.65527" x2="12.2055" y2="19.5151" gradientUnits="userSpaceOnUse">
<stop stop-color="#5132FF"/>
<stop offset="1" stop-color="#4C2CFF"/>
</linearGradient>
<linearGradient id="paint3_linear_0_67" x1="11.7939" y1="5.03809" x2="11.7939" y2="18.898" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#B9ADFF"/>
</linearGradient>
<clipPath id="clip0_0_67">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 3.7 KiB

+53
View File
@@ -0,0 +1,53 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="network-solana 1" clip-path="url(#clip0_0_31)">
<path id="Vector" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint0_linear_0_31)"/>
<path id="Vector_2" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint1_linear_0_31)"/>
<path id="Vector_3" d="M18.9123 15.9041L16.6143 18.3049C16.5644 18.3571 16.5039 18.3986 16.4368 18.4271C16.3696 18.4555 16.2972 18.4701 16.224 18.4701H5.33074C5.27876 18.4701 5.22791 18.4553 5.18445 18.4275C5.14098 18.3997 5.10679 18.3602 5.08607 18.3138C5.06536 18.2673 5.05901 18.216 5.06783 18.1661C5.07664 18.1162 5.10023 18.0699 5.13569 18.0329L7.43533 15.6321C7.48516 15.58 7.5454 15.5385 7.61234 15.5101C7.67929 15.4817 7.75151 15.467 7.82454 15.4669H18.7172C18.7691 15.4669 18.82 15.4817 18.8635 15.5094C18.9069 15.5372 18.9411 15.5768 18.9619 15.6232C18.9825 15.6696 18.9889 15.7209 18.9801 15.7708C18.9712 15.8208 18.9477 15.8671 18.9123 15.9041ZM16.6143 11.0695C16.5644 11.0174 16.5039 10.9758 16.4368 10.9474C16.3696 10.919 16.2972 10.9043 16.224 10.9043H5.33074C5.27876 10.9043 5.22791 10.9191 5.18445 10.9469C5.14098 10.9747 5.10679 11.0142 5.08607 11.0606C5.06536 11.1071 5.05901 11.1584 5.06783 11.2083C5.07664 11.2582 5.10023 11.3045 5.13569 11.3415L7.43533 13.7424C7.48516 13.7944 7.5454 13.8359 7.61234 13.8643C7.67929 13.8927 7.75151 13.9074 7.82454 13.9075H18.7172C18.7691 13.9075 18.82 13.8927 18.8635 13.865C18.9069 13.8372 18.9411 13.7977 18.9619 13.7512C18.9825 13.7048 18.9889 13.6535 18.9801 13.6036C18.9712 13.5537 18.9477 13.5074 18.9123 13.4703L16.6143 11.0695ZM5.33074 9.34499H16.224C16.2972 9.34502 16.3696 9.33038 16.4368 9.30197C16.5039 9.27355 16.5644 9.23197 16.6143 9.17981L18.9123 6.77899C18.9477 6.74197 18.9712 6.69566 18.9801 6.64576C18.9889 6.59586 18.9825 6.54454 18.9619 6.4981C18.9411 6.45166 18.9069 6.41213 18.8635 6.38436C18.82 6.35659 18.7691 6.3418 18.7172 6.3418H7.82454C7.75151 6.34192 7.67929 6.35664 7.61234 6.38505C7.5454 6.41346 7.48516 6.45496 7.43533 6.50697L5.13628 8.9078C5.10086 8.94477 5.07728 8.99104 5.06845 9.04088C5.05961 9.09073 5.0659 9.14201 5.08655 9.18843C5.10719 9.23485 5.14129 9.27437 5.18467 9.30219C5.22805 9.33 5.27881 9.34487 5.33074 9.34499Z" fill="url(#paint2_linear_0_31)"/>
<path id="Vector_4" d="M18.9123 15.0935L16.6143 17.4944C16.5644 17.5465 16.5039 17.5881 16.4368 17.6165C16.3696 17.6449 16.2972 17.6596 16.224 17.6595H5.33074C5.27876 17.6595 5.22791 17.6447 5.18445 17.617C5.14098 17.5892 5.10679 17.5497 5.08607 17.5032C5.06536 17.4568 5.05901 17.4055 5.06783 17.3556C5.07664 17.3057 5.10023 17.2594 5.13569 17.2223L7.43533 14.8215C7.48516 14.7695 7.5454 14.728 7.61234 14.6996C7.67929 14.6712 7.75151 14.6565 7.82454 14.6563H18.7172C18.7691 14.6563 18.82 14.6711 18.8635 14.6989C18.9069 14.7267 18.9411 14.7662 18.9619 14.8126C18.9825 14.8591 18.9889 14.9104 18.9801 14.9603C18.9712 15.0102 18.9477 15.0565 18.9123 15.0935ZM16.6143 10.259C16.5644 10.2068 16.5039 10.1652 16.4368 10.1368C16.3696 10.1084 16.2972 10.0938 16.224 10.0938H5.33074C5.27876 10.0938 5.22791 10.1086 5.18445 10.1364C5.14098 10.1641 5.10679 10.2037 5.08607 10.2501C5.06536 10.2965 5.05901 10.3479 5.06783 10.3978C5.07664 10.4477 5.10023 10.494 5.13569 10.531L7.43533 12.9318C7.48516 12.9838 7.5454 13.0253 7.61234 13.0537C7.67929 13.0821 7.75151 13.0969 7.82454 13.097H18.7172C18.7691 13.097 18.82 13.0822 18.8635 13.0544C18.9069 13.0267 18.9411 12.9871 18.9619 12.9407C18.9825 12.8942 18.9889 12.8429 18.9801 12.793C18.9712 12.7431 18.9477 12.6968 18.9123 12.6598L16.6143 10.259ZM5.33074 8.53445H16.224C16.2972 8.53447 16.3696 8.51984 16.4368 8.49142C16.5039 8.463 16.5644 8.42142 16.6143 8.36927L18.9123 5.96845C18.9477 5.93142 18.9712 5.88512 18.9801 5.83522C18.9889 5.78531 18.9825 5.73399 18.9619 5.68755C18.9411 5.64111 18.9069 5.60158 18.8635 5.57381C18.82 5.54604 18.7691 5.53125 18.7172 5.53125H7.82454C7.75151 5.53137 7.67929 5.54609 7.61234 5.5745C7.5454 5.60292 7.48516 5.64441 7.43533 5.69643L5.13628 8.09725C5.10086 8.13423 5.07728 8.18049 5.06845 8.23033C5.05961 8.28018 5.0659 8.33146 5.08655 8.37788C5.10719 8.4243 5.14129 8.46383 5.18467 8.49164C5.22805 8.51945 5.27881 8.53432 5.33074 8.53445Z" fill="url(#paint3_linear_0_31)"/>
<path id="Vector_5" d="M18.9123 15.4988L16.6143 17.8996C16.5644 17.9518 16.5039 17.9934 16.4368 18.0218C16.3696 18.0502 16.2972 18.0648 16.224 18.0648H5.33074C5.27876 18.0648 5.22791 18.05 5.18445 18.0222C5.14098 17.9945 5.10679 17.9549 5.08607 17.9085C5.06536 17.8621 5.05901 17.8107 5.06783 17.7608C5.07664 17.7109 5.10023 17.6646 5.13569 17.6276L7.43533 15.2268C7.48516 15.1748 7.5454 15.1333 7.61234 15.1049C7.67929 15.0765 7.75151 15.0617 7.82454 15.0616H18.7172C18.7691 15.0616 18.82 15.0764 18.8635 15.1042C18.9069 15.1319 18.9411 15.1715 18.9619 15.2179C18.9825 15.2644 18.9889 15.3157 18.9801 15.3656C18.9712 15.4155 18.9477 15.4618 18.9123 15.4988ZM16.6143 10.6642C16.5644 10.6121 16.5039 10.5705 16.4368 10.5421C16.3696 10.5137 16.2972 10.499 16.224 10.4991H5.33074C5.27876 10.4991 5.22791 10.5139 5.18445 10.5416C5.14098 10.5694 5.10679 10.6089 5.08607 10.6554C5.06536 10.7018 5.05901 10.7531 5.06783 10.803C5.07664 10.8529 5.10023 10.8992 5.13569 10.9363L7.43533 13.3371C7.48516 13.3891 7.5454 13.4306 7.61234 13.459C7.67929 13.4874 7.75151 13.5021 7.82454 13.5023H18.7172C18.7691 13.5023 18.82 13.4875 18.8635 13.4597C18.9069 13.4319 18.9411 13.3924 18.9619 13.346C18.9825 13.2995 18.9889 13.2482 18.9801 13.1983C18.9712 13.1484 18.9477 13.1021 18.9123 13.0651L16.6143 10.6642ZM5.33074 8.93972H16.224C16.2972 8.93975 16.3696 8.92511 16.4368 8.89669C16.5039 8.86827 16.5644 8.82669 16.6143 8.77454L18.9123 6.37372C18.9477 6.3367 18.9712 6.29039 18.9801 6.24049C18.9889 6.19059 18.9825 6.13926 18.9619 6.09282C18.9411 6.04638 18.9069 6.00685 18.8635 5.97909C18.82 5.95132 18.7691 5.93653 18.7172 5.93652H7.82454C7.75151 5.93664 7.67929 5.95137 7.61234 5.97978C7.5454 6.00819 7.48516 6.04969 7.43533 6.1017L5.13628 8.50252C5.10086 8.5395 5.07728 8.58577 5.06845 8.6356C5.05961 8.68545 5.0659 8.73674 5.08655 8.78316C5.10719 8.82957 5.14129 8.8691 5.18467 8.89691C5.22805 8.92473 5.27881 8.9396 5.33074 8.93972Z" fill="url(#paint4_linear_0_31)"/>
<path id="Vector_6" fill-rule="evenodd" clip-rule="evenodd" d="M16.2244 10.499C16.2977 10.499 16.3701 10.5137 16.4373 10.5421C16.5044 10.5705 16.5649 10.6122 16.6149 10.6643L18.9127 13.0651C18.9481 13.1021 18.9717 13.1485 18.9806 13.1984C18.9894 13.2483 18.983 13.2996 18.9624 13.346L18.954 13.3631C18.9329 13.4021 18.902 13.4355 18.864 13.4598L18.8473 13.4696C18.8077 13.491 18.7631 13.5023 18.7177 13.5023H7.82502C7.76112 13.5022 7.69783 13.4909 7.63816 13.4691L7.61286 13.4591C7.55429 13.4342 7.50079 13.3993 7.45497 13.3562L7.43579 13.3372L5.13613 10.9363C5.10513 10.9039 5.08317 10.8644 5.07226 10.8216L5.06831 10.8031C5.0606 10.7595 5.06451 10.7146 5.07948 10.673L5.0866 10.6554C5.10472 10.6148 5.13312 10.5794 5.16905 10.5526L5.18497 10.5417C5.22842 10.514 5.27923 10.499 5.33119 10.499H16.2244ZM5.33119 10.7016C5.31753 10.7016 5.30453 10.7055 5.29392 10.7123C5.28334 10.719 5.27581 10.7282 5.27147 10.7379C5.26718 10.7475 5.26597 10.7579 5.26772 10.7678C5.26949 10.7778 5.27433 10.7878 5.28245 10.7963L7.58201 13.1971C7.61261 13.229 7.64996 13.2548 7.69185 13.2726C7.7338 13.2904 7.77929 13.2997 7.82531 13.2998H18.7177C18.7313 13.2998 18.7442 13.2959 18.7549 13.2891L18.7623 13.2837C18.7691 13.2778 18.7742 13.2707 18.7776 13.2632C18.7818 13.2536 18.7829 13.2434 18.7812 13.2336C18.7794 13.2236 18.7745 13.2136 18.7664 13.2051L16.4685 10.8043C16.4379 10.7723 16.4004 10.7464 16.3584 10.7286C16.3163 10.7108 16.2707 10.7016 16.2245 10.7016H5.33119Z" fill="url(#paint5_linear_0_31)"/>
<path id="Vector_7" fill-rule="evenodd" clip-rule="evenodd" d="M18.737 15.0623C18.7822 15.0655 18.8259 15.0798 18.864 15.1041C18.9074 15.1319 18.9415 15.1715 18.9623 15.2179C18.983 15.2644 18.9894 15.3157 18.9805 15.3656L18.9766 15.3841C18.9657 15.4269 18.9437 15.4664 18.9127 15.4988L16.6148 17.8996L16.5956 17.9187C16.5496 17.9619 16.496 17.9969 16.4373 18.0218L16.4119 18.0318C16.352 18.0536 16.2885 18.0648 16.2244 18.0648H5.33117C5.28572 18.0648 5.24109 18.0535 5.20156 18.0321L5.18495 18.0223C5.14694 17.998 5.116 17.9646 5.09498 17.9256L5.08658 17.9085C5.06845 17.8679 5.06131 17.8235 5.06572 17.7796L5.06829 17.7609C5.076 17.7172 5.09507 17.6763 5.12346 17.642L5.13611 17.6276L7.43577 15.2268C7.47937 15.1813 7.53096 15.1438 7.58802 15.1161L7.61283 15.1049C7.67978 15.0765 7.75197 15.0616 7.825 15.0615H18.7177L18.737 15.0623ZM7.80809 15.2646C7.76795 15.2667 7.7286 15.2757 7.69193 15.2913C7.65004 15.3091 7.61263 15.3348 7.58199 15.3668L5.28233 17.7677C5.27426 17.7762 5.26946 17.7861 5.2677 17.7961C5.26595 17.806 5.26716 17.8164 5.27145 17.826C5.27579 17.8357 5.28332 17.8449 5.2939 17.8516L5.3023 17.8562C5.31108 17.8602 5.32096 17.8623 5.33117 17.8623H16.2245C16.2707 17.8623 16.3163 17.8531 16.3584 17.8353C16.4004 17.8175 16.4378 17.7916 16.4685 17.7596L18.7664 15.3588C18.7745 15.3504 18.7793 15.3404 18.7811 15.3303C18.7829 15.3206 18.7817 15.3104 18.7776 15.3008L18.7736 15.2934C18.7691 15.2862 18.7627 15.2798 18.7548 15.2748C18.7441 15.268 18.7312 15.2641 18.7177 15.2641H7.82539L7.80809 15.2646Z" fill="url(#paint6_linear_0_31)"/>
<path id="Vector_8" d="M18.7371 15.0623C18.7822 15.0655 18.8259 15.0799 18.864 15.1041C18.9074 15.1319 18.9416 15.1715 18.9624 15.2179C18.983 15.2644 18.9894 15.3157 18.9806 15.3656L18.9766 15.3841C18.9657 15.4269 18.9437 15.4664 18.9127 15.4988L16.6149 17.8996L16.5956 17.9187C16.5496 17.962 16.496 17.9969 16.4373 18.0218L16.4119 18.0318C16.352 18.0536 16.2885 18.0648 16.2244 18.0648H5.33119V17.8623H16.2245C16.2707 17.8624 16.3163 17.8531 16.3584 17.8353C16.4004 17.8176 16.4379 17.7916 16.4685 17.7596L18.7664 15.3588C18.7745 15.3504 18.7794 15.3404 18.7811 15.3303C18.7829 15.3206 18.7817 15.3104 18.7776 15.3008L18.7736 15.2934C18.7691 15.2862 18.7628 15.2798 18.7548 15.2748C18.7441 15.268 18.7312 15.2641 18.7177 15.2641H7.82541L7.80811 15.2646C7.76797 15.2667 7.72862 15.2757 7.69195 15.2913C7.65006 15.3091 7.61265 15.3348 7.58201 15.3668L5.28235 17.7677C5.27428 17.7762 5.26948 17.7861 5.26772 17.7961C5.26597 17.8061 5.26718 17.8164 5.27148 17.8261C5.27581 17.8358 5.28333 17.8449 5.29392 17.8517L5.30232 17.8562C5.31111 17.8602 5.32097 17.8623 5.33119 17.8623V18.0648C5.28573 18.0648 5.24113 18.0535 5.20158 18.0321L5.18497 18.0223C5.14695 17.998 5.11603 17.9647 5.09501 17.9256L5.0866 17.9085C5.06847 17.8679 5.06133 17.8235 5.06574 17.7796L5.06831 17.7609C5.07603 17.7172 5.09509 17.6763 5.12348 17.642L5.13613 17.6276L7.43579 15.2268C7.47939 15.1813 7.53098 15.1438 7.58804 15.1161L7.61286 15.1049C7.6798 15.0765 7.75199 15.0618 7.82502 15.0616H18.7177L18.7371 15.0623ZM5.33119 10.4991H16.2244C16.2977 10.499 16.3701 10.5137 16.4373 10.5421C16.5044 10.5705 16.5649 10.6121 16.6149 10.6643L18.9127 13.0651C18.9482 13.1021 18.9717 13.1485 18.9806 13.1983C18.9894 13.2482 18.983 13.2995 18.9624 13.346L18.954 13.3631C18.9329 13.4021 18.902 13.4354 18.864 13.4597L18.8473 13.4695C18.8077 13.491 18.7631 13.5022 18.7177 13.5023V13.2998C18.7313 13.2998 18.7442 13.2959 18.7548 13.2891L18.7623 13.2837C18.7691 13.2778 18.7742 13.2707 18.7776 13.2632C18.7818 13.2536 18.7829 13.2433 18.7811 13.2335C18.7794 13.2235 18.7745 13.2135 18.7664 13.2051L16.4685 10.8043C16.4379 10.7723 16.4004 10.7463 16.3584 10.7285C16.3163 10.7107 16.2707 10.7015 16.2245 10.7015H5.33119C5.31753 10.7016 5.30454 10.7054 5.29392 10.7122C5.28333 10.719 5.27581 10.7281 5.27148 10.7378C5.26717 10.7475 5.26597 10.7578 5.26772 10.7678C5.26948 10.7778 5.27433 10.7878 5.28245 10.7963L7.58201 13.1971C7.61261 13.229 7.64996 13.2548 7.69185 13.2726C7.73381 13.2904 7.77928 13.2997 7.82531 13.2998H18.7177V13.5023H7.82502C7.76112 13.5022 7.69784 13.4909 7.63817 13.469L7.61286 13.4591C7.55429 13.4342 7.5008 13.3993 7.45497 13.3561L7.43579 13.3372L5.13613 10.9363C5.10512 10.9038 5.08317 10.8644 5.07227 10.8216L5.06831 10.8031C5.0606 10.7594 5.06451 10.7146 5.07949 10.673L5.0866 10.6554C5.10473 10.6148 5.13311 10.5794 5.16906 10.5526L5.18497 10.5417C5.22843 10.5139 5.27923 10.4991 5.33119 10.4991ZM18.7177 5.93652C18.7696 5.93653 18.8205 5.95137 18.864 5.97913C18.9074 6.0069 18.9416 6.04641 18.9624 6.09283C18.983 6.13926 18.9894 6.19063 18.9806 6.24053L18.9766 6.25902C18.9657 6.30182 18.9437 6.3413 18.9127 6.3737L16.6149 8.7745L16.5956 8.79358C16.5496 8.83686 16.496 8.87183 16.4373 8.8967L16.4119 8.90668C16.352 8.92853 16.2885 8.93973 16.2244 8.9397H5.33119C5.28578 8.93959 5.24125 8.92824 5.20178 8.90678L5.18517 8.89689C5.14721 8.87255 5.11635 8.83926 5.0954 8.8002L5.087 8.7832C5.06636 8.73678 5.06007 8.68545 5.06891 8.6356C5.07774 8.58577 5.10132 8.5395 5.13673 8.50253L7.43579 6.10172C7.47939 6.05621 7.53098 6.01869 7.58804 5.991L7.61286 5.97983C7.6798 5.95142 7.75199 5.93665 7.82502 5.93652H18.7177ZM7.80811 6.13949C7.76799 6.14157 7.72864 6.15062 7.69195 6.16618C7.65004 6.18397 7.61265 6.20973 7.58201 6.24172L5.28305 8.64252C5.27499 8.65094 5.27008 8.66102 5.26832 8.67099C5.26657 8.68092 5.26779 8.69121 5.27207 8.70085C5.27638 8.71053 5.28384 8.71967 5.29441 8.72645C5.30502 8.73325 5.318 8.73719 5.33169 8.73723H16.2245C16.2708 8.73724 16.3164 8.72803 16.3584 8.71024C16.4004 8.69245 16.4379 8.66654 16.4685 8.63451L18.7664 6.23371C18.7745 6.22525 18.7794 6.21529 18.7811 6.20523C18.7829 6.19546 18.7817 6.18527 18.7776 6.17567L18.7736 6.16826C18.7691 6.16114 18.7628 6.15474 18.7548 6.14967C18.7469 6.14461 18.7376 6.1411 18.7278 6.13969L18.7177 6.139H7.82541L7.80811 6.13949Z" fill="url(#paint7_linear_0_31)"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_31" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#4701AA"/>
<stop offset="1" stop-color="#19004B"/>
</linearGradient>
<linearGradient id="paint1_linear_0_31" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop offset="0.725084" stop-color="#0C0025" stop-opacity="0"/>
<stop offset="1" stop-color="#0C0025" stop-opacity="0.5"/>
</linearGradient>
<linearGradient id="paint2_linear_0_31" x1="12.024" y1="6.3418" x2="12.024" y2="18.4701" gradientUnits="userSpaceOnUse">
<stop offset="0.179856" stop-color="#320080"/>
<stop offset="1" stop-color="#190041"/>
</linearGradient>
<linearGradient id="paint3_linear_0_31" x1="12.024" y1="5.53125" x2="12.024" y2="17.6595" gradientUnits="userSpaceOnUse">
<stop offset="0.0856031" stop-color="#4E12A7"/>
<stop offset="1" stop-color="#330083"/>
</linearGradient>
<linearGradient id="paint4_linear_0_31" x1="6.23897" y1="18.3539" x2="17.3291" y2="5.52082" gradientUnits="userSpaceOnUse">
<stop offset="0.08" stop-color="#9945FF"/>
<stop offset="0.3" stop-color="#8752F3"/>
<stop offset="0.5" stop-color="#5497D5"/>
<stop offset="0.6" stop-color="#43B4CA"/>
<stop offset="0.72" stop-color="#28E0B9"/>
<stop offset="0.97" stop-color="#19FB9B"/>
</linearGradient>
<linearGradient id="paint5_linear_0_31" x1="6.53239" y1="12.9117" x2="6.53239" y2="10.4821" gradientUnits="userSpaceOnUse">
<stop stop-color="#24E7B1" stop-opacity="0"/>
<stop offset="1" stop-color="#62BDF2"/>
</linearGradient>
<linearGradient id="paint6_linear_0_31" x1="11.7967" y1="17.9734" x2="11.8979" y2="15.4426" gradientUnits="userSpaceOnUse">
<stop stop-color="#B087FF"/>
<stop offset="1" stop-color="#7070E6" stop-opacity="0"/>
</linearGradient>
<linearGradient id="paint7_linear_0_31" x1="12.0244" y1="5.93652" x2="12.1004" y2="9.8747" gradientUnits="userSpaceOnUse">
<stop stop-color="#58FFBE"/>
<stop offset="1" stop-color="#24E7B1" stop-opacity="0"/>
</linearGradient>
<clipPath id="clip0_0_31">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 16 KiB

+31
View File
@@ -0,0 +1,31 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="network-tron 1" clip-path="url(#clip0_0_24)">
<path id="Vector" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint0_linear_0_24)"/>
<path id="Vector_2" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint1_linear_0_24)"/>
<path id="Vector_3" d="M19.8459 9.5211C19.0883 8.82162 18.0404 7.75347 17.1869 6.99592L17.1364 6.96057C17.0523 6.89309 16.9576 6.84017 16.8561 6.80401C14.7981 6.42018 5.22006 4.62983 5.0332 4.65256C4.98084 4.65989 4.93079 4.67888 4.88674 4.70811L4.83876 4.74599C4.77968 4.80599 4.73481 4.87847 4.70745 4.9581L4.69482 4.99093V5.17022V5.198C5.77307 8.20043 10.0305 18.036 10.8689 20.344C10.9194 20.5006 11.0153 20.7985 11.1946 20.8137H11.235C11.331 20.8137 11.7401 20.2733 11.7401 20.2733C11.7401 20.2733 19.053 11.4049 19.7929 10.4605C19.8886 10.3441 19.9732 10.219 20.0454 10.0867C20.0638 9.98325 20.0551 9.87676 20.0201 9.77763C19.9852 9.67851 19.9251 9.59013 19.8459 9.5211ZM13.6163 10.5539L16.7374 7.96559L18.5681 9.65241L13.6163 10.5539ZM12.4042 10.3847L7.03061 5.9808L15.7248 7.58429L12.4042 10.3847ZM12.889 11.5387L18.3889 10.6524L12.1012 18.2279L12.889 11.5387ZM6.30084 6.42018L11.9547 11.218L11.1365 18.233L6.30084 6.42018Z" fill="url(#paint2_linear_0_24)"/>
<path id="Vector_4" d="M19.8459 9.11094C19.0883 8.41147 18.0404 7.34332 17.1869 6.58577L17.1364 6.55041C17.0523 6.48293 16.9576 6.43001 16.8561 6.39385C14.7981 6.01003 5.22006 4.21968 5.0332 4.2424C4.98084 4.24974 4.93079 4.26872 4.88674 4.29796L4.83876 4.33583C4.77968 4.39583 4.73481 4.46832 4.70745 4.54795L4.69482 4.58078V4.76006V4.78784C5.77307 7.79027 10.0305 17.6258 10.8689 19.9338C10.9194 20.0904 11.0153 20.3884 11.1946 20.4035H11.235C11.331 20.4035 11.7401 19.8631 11.7401 19.8631C11.7401 19.8631 19.053 10.9947 19.7929 10.0503C19.8886 9.93397 19.9732 9.80884 20.0454 9.67658C20.0638 9.5731 20.0551 9.4666 20.0201 9.36748C19.9852 9.26835 19.9251 9.17997 19.8459 9.11094ZM13.6163 10.1437L16.7374 7.55543L18.5681 9.24225L13.6163 10.1437ZM12.4042 9.97455L7.03061 5.57064L15.7248 7.17413L12.4042 9.97455ZM12.889 11.1286L18.3889 10.2422L12.1012 17.8177L12.889 11.1286ZM6.30084 6.01002L11.9547 10.8079L11.1365 17.8228L6.30084 6.01002Z" fill="white"/>
<path id="Vector_5" d="M19.8459 9.11094C19.0883 8.41147 18.0404 7.34332 17.1869 6.58577L17.1364 6.55041C17.0523 6.48293 16.9576 6.43001 16.8561 6.39385C14.7981 6.01003 5.22006 4.21968 5.0332 4.2424C4.98084 4.24974 4.93079 4.26872 4.88674 4.29796L4.83876 4.33583C4.77968 4.39583 4.73481 4.46832 4.70745 4.54795L4.69482 4.58078V4.76006V4.78784C5.77307 7.79027 10.0305 17.6258 10.8689 19.9338C10.9194 20.0904 11.0153 20.3884 11.1946 20.4035H11.235C11.331 20.4035 11.7401 19.8631 11.7401 19.8631C11.7401 19.8631 19.053 10.9947 19.7929 10.0503C19.8886 9.93397 19.9732 9.80884 20.0454 9.67658C20.0638 9.5731 20.0551 9.4666 20.0201 9.36748C19.9852 9.26835 19.9251 9.17997 19.8459 9.11094ZM13.6163 10.1437L16.7374 7.55543L18.5681 9.24225L13.6163 10.1437ZM12.4042 9.97455L7.03061 5.57064L15.7248 7.17413L12.4042 9.97455ZM12.889 11.1286L18.3889 10.2422L12.1012 17.8177L12.889 11.1286ZM6.30084 6.01002L11.9547 10.8079L11.1365 17.8228L6.30084 6.01002Z" fill="url(#paint3_linear_0_24)"/>
<path id="Vector_6" d="M5.03322 4.2424C5.22098 4.21985 14.7982 6.01009 16.8561 6.39389C16.9576 6.43006 17.0524 6.48292 17.1364 6.55039L17.1869 6.58579C18.0404 7.34335 19.0883 8.41152 19.8459 9.11099C19.9251 9.18001 19.9852 9.26837 20.0202 9.36749C20.0551 9.46661 20.0638 9.57311 20.0454 9.67659L20.0177 9.72589C19.9518 9.84001 19.8767 9.94852 19.7929 10.0503C19.0535 10.9941 11.7498 19.8514 11.7401 19.8632C11.7401 19.8632 11.331 20.4036 11.235 20.4036H11.1946L11.1781 20.4013C11.0094 20.3699 10.9178 20.0856 10.8689 19.9339C10.0306 17.6259 5.7731 7.79038 4.69482 4.7879V4.5808L4.70742 4.548C4.73478 4.46837 4.77965 4.3958 4.83872 4.3358L4.88672 4.298C4.93078 4.26876 4.98086 4.24973 5.03322 4.2424ZM5.04682 4.4481C5.03174 4.4518 5.01737 4.45791 5.00412 4.4661L4.97752 4.4871C4.94348 4.52375 4.9174 4.56712 4.90112 4.6145L4.89992 4.618L4.89962 4.7519C5.44413 6.26076 6.76532 9.4399 8.06082 12.5424C9.32242 15.5637 10.5602 18.5138 11.0194 19.7498L11.0614 19.864L11.0638 19.871C11.09 19.9522 11.1211 20.0471 11.1629 20.1232C11.1773 20.1493 11.1906 20.1683 11.2016 20.1816C11.2046 20.1787 11.208 20.1759 11.2113 20.1727C11.2562 20.1288 11.3114 20.067 11.3672 20.0011C11.4222 19.936 11.4748 19.8705 11.5137 19.821C11.5331 19.7963 11.549 19.7758 11.56 19.7615C11.5655 19.7543 11.5698 19.7487 11.5726 19.745C11.574 19.7431 11.5751 19.7417 11.5758 19.7408C11.5762 19.7403 11.5765 19.74 11.5766 19.7398L11.5793 19.7362L11.582 19.7329L11.7401 19.8632C11.5857 19.7359 11.582 19.733 11.582 19.7329C11.5819 19.733 11.5821 19.7328 11.582 19.7329C11.5822 19.7326 11.583 19.7318 11.5834 19.7313C11.5843 19.7302 11.5856 19.7286 11.5873 19.7265C11.5908 19.7222 11.5961 19.7158 11.603 19.7074C11.6169 19.6906 11.6375 19.6656 11.6643 19.6331C11.718 19.5679 11.797 19.4721 11.8977 19.35C12.0991 19.1056 12.3877 18.7555 12.7362 18.3325C13.4333 17.4863 14.3705 16.3483 15.3308 15.1808C17.2529 12.844 19.2636 10.3937 19.6316 9.92399L19.6332 9.92209L19.6347 9.92019C19.7146 9.82313 19.7858 9.71919 19.8478 9.60989C19.8537 9.55108 19.8467 9.49156 19.827 9.43559C19.8038 9.36983 19.764 9.31118 19.7114 9.26539L19.7091 9.26349L19.707 9.26139C19.3258 8.90945 18.8717 8.46498 18.4098 8.01719C17.9493 7.57084 17.48 7.12037 17.0592 6.74639L17.0189 6.71819L17.0134 6.71429L17.0081 6.71009C16.9456 6.65993 16.8756 6.62007 16.8007 6.59179C15.7562 6.39698 12.8653 5.85695 10.2058 5.3671C8.86838 5.12076 7.5898 4.88714 6.63402 4.7166C6.15602 4.63131 5.75932 4.56194 5.47662 4.5146C5.33511 4.4909 5.22318 4.47287 5.14422 4.4612C5.10455 4.45534 5.07471 4.45126 5.05422 4.4489C5.05147 4.44858 5.04901 4.44833 5.04682 4.4481ZM11.8168 18.481L12.7037 10.951L18.8949 9.95329L11.8168 18.481ZM12.1708 10.7227L11.34 17.8466L10.947 17.9004L6.11132 6.08759L6.43332 5.8539L12.1708 10.7227ZM11.1365 17.8228L11.9547 10.8079L6.30082 6.01L11.1365 17.8228ZM12.889 11.1286L12.1012 17.8178L18.3889 10.2422L12.889 11.1286ZM19.0092 9.37009L12.8836 10.4853L16.7445 7.28349L19.0092 9.37009ZM16.1881 7.05129L12.4061 10.2409L6.90082 5.7291L7.06772 5.3693L16.1881 7.05129ZM13.6163 10.1438L18.5681 9.24229L16.7374 7.55549L13.6163 10.1438ZM12.4042 9.97459L15.7248 7.17409L7.03062 5.5707L12.4042 9.97459Z" fill="white"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_24" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#F9181C"/>
<stop offset="1" stop-color="#C40003"/>
</linearGradient>
<linearGradient id="paint1_linear_0_24" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop offset="0.725084" stop-color="#850305" stop-opacity="0"/>
<stop offset="1" stop-color="#850305" stop-opacity="0.5"/>
</linearGradient>
<linearGradient id="paint2_linear_0_24" x1="12.3748" y1="4.65234" x2="12.3748" y2="20.8137" gradientUnits="userSpaceOnUse">
<stop stop-color="#D30508"/>
<stop offset="1" stop-color="#B40003"/>
</linearGradient>
<linearGradient id="paint3_linear_0_24" x1="12.3748" y1="4.24219" x2="12.3748" y2="20.4035" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#FFA4A6"/>
</linearGradient>
<clipPath id="clip0_0_24">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 8.1 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 30 KiB

+46
View File
@@ -0,0 +1,46 @@
<svg preserveAspectRatio="none" overflow="visible" style="display: block;" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<g id="network-zcash 1" clip-path="url(#clip0_0_40)">
<path id="Vector" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint0_linear_0_40)"/>
<path id="Vector_2" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint1_linear_0_40)"/>
<path id="Vector_3" d="M0 9.984C0 6.48927 0 4.74191 0.680119 3.4071C1.27837 2.23297 2.23297 1.27837 3.4071 0.680119C4.74191 0 6.48927 0 9.984 0H14.016C17.5107 0 19.2581 0 20.5929 0.680119C21.767 1.27837 22.7216 2.23297 23.3199 3.4071C24 4.74191 24 6.48927 24 9.984V14.016C24 17.5107 24 19.2581 23.3199 20.5929C22.7216 21.767 21.767 22.7216 20.5929 23.3199C19.2581 24 17.5107 24 14.016 24H9.984C6.48927 24 4.74191 24 3.4071 23.3199C2.23297 22.7216 1.27837 21.767 0.680119 20.5929C0 19.2581 0 17.5107 0 14.016V9.984Z" fill="url(#paint2_linear_0_40)"/>
<path id="Vector_4" d="M16.8953 8.29807V6.2951H13.3042V4.08789H11.097V6.2951H7.50586V8.95175H13.0707L7.50586 16.5073V18.5103H11.097V20.7117H13.3042V18.5103H16.8953V15.8537H11.3246L16.8953 8.29807Z" fill="url(#paint3_linear_0_40)"/>
<path id="Vector_5" d="M16.8953 8.29807V6.2951H13.3042V4.08789H11.097V6.2951H7.50586V8.95175H13.0707L7.50586 16.5073V18.5103H11.097V20.7117H13.3042V18.5103H16.8953V15.8537H11.3246L16.8953 8.29807Z" fill="url(#paint4_linear_0_40)"/>
<path id="Vector_6" d="M16.6848 7.87717V5.8742H13.0937V3.66699H10.8865V5.8742H7.29541V8.53085H12.8602L7.29541 16.0865V18.0894H10.8865V20.2908H13.0937V18.0894H16.6848V15.4328H11.1142L16.6848 7.87717Z" fill="url(#paint5_linear_0_40)"/>
<path id="Vector_7" d="M16.6848 7.87717V5.8742H13.0937V3.66699H10.8865V5.8742H7.29541V8.53085H12.8602L7.29541 16.0865V18.0894H10.8865V20.2908H13.0937V18.0894H16.6848V15.4328H11.1142L16.6848 7.87717Z" fill="url(#paint6_linear_0_40)"/>
<path id="Vector_8" d="M12.8831 3.87757H11.0971V6.08478H7.50599V8.32026H13.2768L7.50599 16.1556V17.8788H11.0971V20.0801H12.8831V17.8788H16.4742V15.6433H10.6973L16.4742 7.80789V6.08478H12.8831V3.87757ZM16.6848 5.8742V7.87719L11.1142 15.4327H16.6848V18.0894H13.0937V20.2907H10.8865V18.0894H7.29541V16.0865L12.8602 8.53084H7.29541V5.8742H10.8865V3.66699H13.0937V5.8742H16.6848Z" fill="white"/>
</g>
<defs>
<linearGradient id="paint0_linear_0_40" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#4701AA"/>
<stop offset="1" stop-color="#19004B"/>
</linearGradient>
<linearGradient id="paint1_linear_0_40" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop offset="0.725084" stop-color="#0C0025" stop-opacity="0"/>
<stop offset="1" stop-color="#0C0025" stop-opacity="0.5"/>
</linearGradient>
<linearGradient id="paint2_linear_0_40" x1="12" y1="0" x2="12" y2="24" gradientUnits="userSpaceOnUse">
<stop stop-color="#F6B71D"/>
<stop offset="1" stop-color="#B68200"/>
</linearGradient>
<linearGradient id="paint3_linear_0_40" x1="12.2006" y1="4.08789" x2="12.2006" y2="20.7117" gradientUnits="userSpaceOnUse">
<stop stop-color="#DC9B00"/>
<stop offset="1" stop-color="#AE7B00"/>
</linearGradient>
<linearGradient id="paint4_linear_0_40" x1="12.2006" y1="4.08789" x2="12.2006" y2="20.7117" gradientUnits="userSpaceOnUse">
<stop stop-color="#DC9B00"/>
<stop offset="1" stop-color="#AA7700"/>
</linearGradient>
<linearGradient id="paint5_linear_0_40" x1="11.9901" y1="3.66699" x2="11.9901" y2="20.2908" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#FADD99"/>
</linearGradient>
<linearGradient id="paint6_linear_0_40" x1="11.9901" y1="3.66699" x2="11.9901" y2="20.2908" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="0.25" stop-color="#FFF5DC"/>
<stop offset="1" stop-color="#FADD99"/>
</linearGradient>
<clipPath id="clip0_0_40">
<rect width="24" height="24" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 4.7 KiB

+3
View File
@@ -0,0 +1,3 @@
<svg width="13" height="12" viewBox="0 0 13 12" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M2.25167 11.6667V10.4167H8.23229C9.10201 10.4167 9.85042 10.1295 10.4775 9.55521C11.1047 8.98104 11.4183 8.27194 11.4183 7.42792C11.4183 6.58389 11.1047 5.87604 10.4775 5.30437C9.85042 4.73285 9.10201 4.44708 8.23229 4.44708H2.38146L4.70021 6.76604L3.82208 7.64417L0 3.82208L3.82208 0L4.70021 0.878126L2.38146 3.19708H8.23229C9.45132 3.19708 10.4954 3.60389 11.3646 4.4175C12.2338 5.23111 12.6683 6.23458 12.6683 7.42792C12.6683 8.62125 12.2338 9.62604 11.3646 10.4423C10.4954 11.2585 9.45132 11.6667 8.23229 11.6667H2.25167Z" fill="white"/>
</svg>

After

Width:  |  Height:  |  Size: 658 B

+8 -1
View File
@@ -1,3 +1,10 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M4.16667 17.5C3.70833 17.5 3.31597 17.3368 2.98958 17.0104C2.66319 16.684 2.5 16.2917 2.5 15.8333V4.16667C2.5 3.70833 2.66319 3.31597 2.98958 2.98958C3.31597 2.66319 3.70833 2.5 4.16667 2.5H15.8333C16.2917 2.5 16.684 2.66319 17.0104 2.98958C17.3368 3.31597 17.5 3.70833 17.5 4.16667H10.8333C9.84722 4.16667 9.04514 4.47569 8.42708 5.09375C7.80903 5.71181 7.5 6.51389 7.5 7.5V12.5C7.5 13.4861 7.80903 14.2882 8.42708 14.9062C9.04514 15.5243 9.84722 15.8333 10.8333 15.8333H17.5C17.5 16.2917 17.3368 16.684 17.0104 17.0104C16.684 17.3368 16.2917 17.5 15.8333 17.5H4.16667ZM10.8333 14.1667C10.375 14.1667 9.98264 14.0035 9.65625 13.6771C9.32986 13.3507 9.16667 12.9583 9.16667 12.5V7.5C9.16667 7.04167 9.32986 6.64931 9.65625 6.32292C9.98264 5.99653 10.375 5.83333 10.8333 5.83333H16.6667C17.125 5.83333 17.5174 5.99653 17.8437 6.32292C18.1701 6.64931 18.3333 7.04167 18.3333 7.5V12.5C18.3333 12.9583 18.1701 13.3507 17.8437 13.6771C17.5174 14.0035 17.125 14.1667 16.6667 14.1667H10.8333ZM13.3333 11.25C13.6944 11.25 13.9931 11.1319 14.2292 10.8958C14.4653 10.6597 14.5833 10.3611 14.5833 10C14.5833 9.63889 14.4653 9.34028 14.2292 9.10417C13.9931 8.86806 13.6944 8.75 13.3333 8.75C12.9722 8.75 12.6736 8.86806 12.4375 9.10417C12.2014 9.34028 12.0833 9.63889 12.0833 10C12.0833 10.3611 12.2014 10.6597 12.4375 10.8958C12.6736 11.1319 12.9722 11.25 13.3333 11.25Z" fill="#8C9FBB"/>
<g clip-path="url(#clip0_23582_544208)">
<path d="M12.0989 0.57373C14.0136 0.57373 14.9709 0.573749 15.7023 0.946376C16.3456 1.27415 16.8686 1.79715 17.1963 2.44044C17.3608 2.76324 17.4526 3.13009 17.5039 3.60386C17.2012 3.59531 16.8718 3.5939 16.5184 3.59369H14.2926C13.6763 3.59369 13.2302 3.59062 12.8366 3.64244C10.2798 3.97907 8.2677 5.99107 7.93108 8.54794C7.87926 8.94154 7.88233 9.38768 7.88233 10.004C7.88233 10.6202 7.87926 11.0663 7.93108 11.4599C8.26771 14.0168 10.2798 16.0288 12.8366 16.3655C13.2302 16.4173 13.6763 16.4142 14.2926 16.4142H16.5184C16.8718 16.414 17.2012 16.4124 17.5039 16.4039C17.4526 16.8777 17.3608 17.2446 17.1963 17.5674C16.8686 18.2107 16.3456 18.7337 15.7023 19.0615C14.9709 19.4341 14.0136 19.4341 12.0989 19.4341H5.88806C3.97335 19.4341 3.016 19.4341 2.28467 19.0615C1.64139 18.7337 1.11839 18.2107 0.790614 17.5674C0.417991 16.8361 0.417969 15.8787 0.417969 13.964V6.04382C0.417969 4.12911 0.417987 3.17176 0.790614 2.44044C1.11839 1.79715 1.64139 1.27415 2.28467 0.946376C3.016 0.573749 3.97335 0.57373 5.88806 0.57373H12.0989ZM16.2513 5.01819C17.7478 5.01819 18.4961 5.01819 19.0626 5.32095C19.5098 5.56001 19.8761 5.9263 20.1152 6.37355C20.418 6.93998 20.418 7.68831 20.418 9.18487V10.823C20.418 12.3196 20.418 13.0679 20.1152 13.6343C19.8761 14.0816 19.5098 14.4478 19.0626 14.6869C18.4961 14.9897 17.7478 14.9897 16.2513 14.9897H14.2926C13.6311 14.9897 13.3003 14.9897 13.0226 14.9531C11.1049 14.7007 9.5959 13.1916 9.34343 11.274C9.30687 10.9963 9.30683 10.6655 9.30683 10.004C9.30683 9.3424 9.30687 9.01159 9.34343 8.73389C9.5959 6.81623 11.1049 5.3072 13.0226 5.05473C13.3003 5.01818 13.6311 5.01819 14.2926 5.01819H16.2513ZM13.5804 8.55093C12.7936 8.55093 12.1559 9.18871 12.1559 9.97543C12.1559 10.7622 12.7936 11.3999 13.5804 11.3999C14.3671 11.3999 15.0049 10.7622 15.0049 9.97543C15.0049 9.18871 14.3671 8.55094 13.5804 8.55093Z" fill="#91B0FF"/>
</g>
<defs>
<clipPath id="clip0_23582_544208">
<rect width="20" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 2.1 KiB

+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven من Cake Wallet",
"haven_app_wallet_text": "محفظة رائعة لـ Haven",
"help": "مساعدة",
"hidden_accounts": "الحسابات المخفية",
"hidden_addresses": "العناوين المخفية",
"hidden_balance": "الرصيد المخفي",
"hide": "إخفاء",
@@ -735,6 +736,8 @@
"no_buy_providers": "لم يتم العثور على موفري خدمة ${curr}.",
"no_cards_found": "لم يتم العثور على أي بطاقات",
"no_extra_detail": "لا تتوفر تفاصيل إضافية",
"no_hidden_accounts": "لا توجد حسابات مخفية",
"no_hidden_accounts_desc": "يمكنك إخفاء الحسابات من شاشة التخصيص.",
"no_id_needed": "لا حاجة لإثبات الهوية!",
"no_id_required": "لا حاجة لإثبات الهوية. اشحن وأنفق في أي مكان",
"no_providers_available": "لا يوجد مزوّدون متاحون",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven от Cake Wallet",
"haven_app_wallet_text": "Страхотен портфейл за Haven",
"help": "помощ",
"hidden_accounts": "Скрити сметки",
"hidden_addresses": "Скрити адреси",
"hidden_balance": "Скрит баланс",
"hide": "Скрий",
@@ -735,6 +736,8 @@
"no_buy_providers": "Няма намерени доставчици за ${curr}.",
"no_cards_found": "Няма намерени карти",
"no_extra_detail": "Няма налични допълнителни подробности",
"no_hidden_accounts": "Няма скрити акаунти",
"no_hidden_accounts_desc": "Можете да скриете акаунти от екрана за персонализиране.",
"no_id_needed": "Не е нужен документ за самоличност!",
"no_id_required": "Не се изисква документ за самоличност. Зареждайте и харчете навсякъде",
"no_providers_available": "Няма налични доставчици",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven od Cake Walletu",
"haven_app_wallet_text": "Skvělá peněženka pro Haven",
"help": "pomoc",
"hidden_accounts": "Skryté účty",
"hidden_addresses": "Skryté adresy",
"hidden_balance": "Skrytý zůstatek",
"hide": "Skrýt",
@@ -735,6 +736,8 @@
"no_buy_providers": "Pro ${curr} nebyli nalezeni žádní poskytovatelé.",
"no_cards_found": "Nebyly nalezeny žádné karty",
"no_extra_detail": "Nejsou k dispozici žádné další podrobnosti",
"no_hidden_accounts": "Žádné skryté účty",
"no_hidden_accounts_desc": "Účty můžete skrýt na obrazovce přizpůsobení.",
"no_id_needed": "Není potřeba žádné ID!",
"no_id_required": "Není vyžadován žádný doklad totožnosti. Dobijte si a utrácejte kdekoli",
"no_providers_available": "Nejsou k dispozici žádní poskytovatelé",
+3
View File
@@ -562,6 +562,7 @@
"haven_app": "Haven von Cake Wallet",
"haven_app_wallet_text": "Eine großartige Wallet für Haven",
"help": "Hilfe",
"hidden_accounts": "Versteckte Konten",
"hidden_addresses": "Versteckte Adressen",
"hidden_balance": "Versteckter Kontostand",
"hide": "Ausblenden",
@@ -737,6 +738,8 @@
"no_buy_providers": "Für ${curr} wurden keine Anbieter gefunden.",
"no_cards_found": "Keine Karten gefunden",
"no_extra_detail": "Keine zusätzlichen Details verfügbar",
"no_hidden_accounts": "Keine versteckten Konten",
"no_hidden_accounts_desc": "Sie können Konten auf dem Anpassungsbildschirm ausblenden.",
"no_id_needed": "Keine ID erforderlich!",
"no_id_required": "Keine ID erforderlich. Aufladen und überall ausgeben",
"no_providers_available": "Keine Anbieter verfügbar",
+42
View File
@@ -4,9 +4,27 @@
"about_litecoin_privacy": "About Litecoin Privacy",
"accent_color": "Accent color",
"account": "Account",
"account_creation_description": "Accounts let you organize your funds into different compartments without needing to create a separate wallet",
"account_customizer_desc": "Drag and drop cards to organize accounts.",
"account_name": "Account name",
"accounts": "Accounts",
"accounts_education_archive_description": "If you deposit funds to an account, they will still be there even if you archive it",
"accounts_education_archive_title": "Accounts cannot be deleted, only archived",
"accounts_education_order_description": "The order of creation is shown alongside the account name, in the Accounts menu",
"accounts_education_order_highlight": "Accounts",
"accounts_education_order_restore_description": "This is useful to know if you want to restore your accounts, both in Cake Wallet or elsewhere",
"accounts_education_order_title": "Accounts are created in order, and they are restored in the same order",
"accounts_education_organize_description": "You can create one for your regular spending, another for your savings... all accessible from the same homescreen",
"accounts_education_organize_title": "Accounts let you organize your funds by acting as separate pockets within one wallet",
"accounts_education_progress": "Page ${current} of ${total}",
"accounts_education_recovery_description": "This saves you from the hassle of creating and dealing with multiple separate wallets",
"accounts_education_recovery_highlight": "Recovery Phrase",
"accounts_education_recovery_title": "Accounts belong together in one wallet, they can all be restored from just one Recovery Phrase",
"accounts_education_understand_continue": "I understand. Continue",
"accounts_help": "Learn about accounts",
"accounts_home_promo_description": "Manage all your assets in a unified interface",
"accounts_home_promo_title": "Accounts for ${walletName} are here!",
"accounts_onchain": "Accounts (Onchain)",
"accounts_subaddresses": "Accounts and subaddresses",
"activate": "Activate",
"active": "Active",
@@ -80,6 +98,16 @@
"approve_request": "Approve Request",
"approve_tokens": "Approve tokens",
"apps": "Apps",
"archive_account": "Archive Account",
"archive_account_confirmation_title": "Are you sure you want to Archive this account?",
"archive_account_empty_disclaimer": "This action won’t delete the account or its past activity, but only hide it inside Cake Wallet",
"archive_account_funded_disclaimer": "Archiving an account does not delete any funds or activity. You can reverse this action",
"archive_account_funds_title": "This account has the following funds:",
"archive_account_move_funds": "Before proceeding, it is recommended you move them to an account you will use",
"archive_account_restore_hint": "You can reverse this action from Accounts settings",
"archive_account_reversible": "This change can be reverted",
"archive_account_title": "Archive Account",
"archived_accounts": "Archived Accounts",
"arbiscan_history": "ArbiScan History",
"are_you_sure_exit": "Are you sure you want to exit?",
"arrive_in_this_address": "${currency} ${tag}will arrive in this address",
@@ -236,6 +264,7 @@
"coin_control_desc": "Filter outputs for this transaction. The changes you make here will only reflect on the current transaction.",
"coin_control_desc_no_edit": "Freeze outputs if needed. The changes will be persistent across all transactions. You can also filter outputs for one transaction on the Send or Swap screens.",
"coin_control_load_failed": "Failed to load unspent coins",
"coin_control_settings": "Coin Control",
"cold_or_recover_wallet": "Add an air-gapped cold wallet or recover a paper wallet.",
"collection_address": "Collection Address",
"collection_description": "Collection Description",
@@ -419,6 +448,7 @@
"edit_current": "Edit Current",
"edit_node": "Edit Node",
"edit_token": "Edit token",
"empty_accounts": "Empty Accounts",
"electrum_address_disclaimer": "We generate new addresses each time you use one, but previous addresses continue to work",
"email_address": "Email Address",
"enable": "Enable",
@@ -542,6 +572,8 @@
"from": "From",
"frozen": "Frozen",
"frozen_balance": "Frozen Balance",
"funded_accounts": "Funded accounts",
"funded_accounts_description": "Unarchive an account to access its funds",
"full_balance": "Full Balance",
"gains": "Gains",
"gallery": "Gallery",
@@ -569,6 +601,7 @@
"haven_app": "Haven by Cake Wallet",
"haven_app_wallet_text": "Awesome wallet for Haven",
"help": "help",
"hidden_accounts": "Hidden Accounts",
"hidden_addresses": "Hidden Addresses",
"hidden_balance": "Hidden Balance",
"hide": "Hide",
@@ -744,9 +777,13 @@
"nft_some_not_loaded": "Some NFTs could not be loaded",
"nfts": "NFTs",
"no": "No",
"no_archived_accounts": "No Archived Accounts",
"no_archived_accounts_description": "When you Archive an Account, it will show up here",
"no_buy_providers": "No providers found for ${curr}.",
"no_cards_found": "No cards found",
"no_extra_detail": "No extra details available",
"no_hidden_accounts": "No hidden accounts",
"no_hidden_accounts_desc": "You can hide accounts from the customization screen.",
"no_id_needed": "No ID needed!",
"no_id_required": "No ID required. Top up and spend anywhere",
"no_providers_available": "No providers available",
@@ -1063,6 +1100,7 @@
"seedtype_alert_content": "Sharing a recovery phrase with other wallets is only possible with the BIP39 type.",
"seedtype_alert_title": "Recovery phrase type alert",
"select_a_wallet": "Select a wallet",
"select_account_to_unarchive": "Select an Account to Unarchive it",
"select_address_to_copy": "Select Address to Copy",
"select_all": "Select all",
"select_asset": "Select Asset",
@@ -1419,6 +1457,9 @@
"tx_wrong_balance_with_amount_exception": "You do not have enough ${currency} to send the total amount of ${amount}",
"tx_zero_fee_exception": "Cannot send transaction with 0 fee. Try increasing the rate or checking your connection for latest estimates.",
"type": "Type",
"unarchive_account_description": "This account will show up again on your wallet",
"unarchive_account_funds_description": "This account will show up again on your wallet, letting you access your funds",
"unarchive_account_title": "Unarchive this account?",
"unavailable_balance": "Unavailable balance",
"unavailable_balance_description": "Unavailable Balance: This total includes funds that are locked in pending transactions and those you have actively frozen in your Coin Control settings. Locked balances will become available once their respective transactions are completed, while frozen balances remain inaccessible for transactions until you decide to unfreeze them.",
"unconfirmed": "Unconfirmed Balance",
@@ -1426,6 +1467,7 @@
"unhide_address": "Unhide address",
"unified_view_key": "Unified View Key",
"unknown_error": "Unknown error",
"unnamed_account": "Unnamed Account",
"unlock": "Unlock",
"unmask": "Unmask",
"unmatched_currencies": "Your current wallet's currency does not match that of the scanned QR",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven de Cake Wallet",
"haven_app_wallet_text": "Excelente cartera para Haven",
"help": "ayuda",
"hidden_accounts": "Cuentas ocultas",
"hidden_addresses": "Direcciones ocultas",
"hidden_balance": "Saldo oculto",
"hide": "Ocultar",
@@ -735,6 +736,8 @@
"no_buy_providers": "No se encontraron proveedores para ${curr}.",
"no_cards_found": "No se encontraron tarjetas",
"no_extra_detail": "No hay detalles adicionales disponibles",
"no_hidden_accounts": "Sin cuentas ocultas",
"no_hidden_accounts_desc": "Puede ocultar cuentas desde la pantalla de personalización.",
"no_id_needed": "¡No se necesita identificación!",
"no_id_required": "No se requiere identificación. Recarga y gasta en cualquier lugar",
"no_providers_available": "No hay proveedores disponibles",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven توسط Cake Wallet",
"haven_app_wallet_text": "کیف پول فوق‌العاده برای Haven",
"help": "راهنما",
"hidden_accounts": "حساب های مخفی",
"hidden_addresses": "آدرس‌های پنهان",
"hidden_balance": "موجودی پنهان",
"hide": "پنهان کردن",
@@ -735,6 +736,8 @@
"no_buy_providers": "هیچ ارائه دهنده ای برای ${curr} یافت نشد.",
"no_cards_found": "هیچ کارتی پیدا نشد",
"no_extra_detail": "جزئیات بیشتری در دسترس نیست",
"no_hidden_accounts": "بدون حساب های مخفی",
"no_hidden_accounts_desc": "می توانید حساب ها را از صفحه سفارشی سازی مخفی کنید.",
"no_id_needed": "بدون نیاز به احراز هویت!",
"no_id_required": "بدون نیاز به مدرک شناسایی. شارژ کنید و همه‌جا خرج کنید",
"no_providers_available": "هیچ ارائه‌دهنده‌ای در دسترس نیست",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven par Cake Wallet",
"haven_app_wallet_text": "Excellent portefeuille pour Haven",
"help": "aide",
"hidden_accounts": "Comptes cachés",
"hidden_addresses": "Adresses masquées",
"hidden_balance": "Solde masqué",
"hide": "Masquer",
@@ -735,6 +736,8 @@
"no_buy_providers": "Aucun fournisseur trouvé pour ${curr}.",
"no_cards_found": "Aucune carte trouvée",
"no_extra_detail": "Aucun détail supplémentaire disponible",
"no_hidden_accounts": "Pas de comptes cachés",
"no_hidden_accounts_desc": "Vous pouvez masquer des comptes depuis l'écran de personnalisation.",
"no_id_needed": "Aucune pièce d’identité requise !",
"no_id_required": "Aucune pièce d’identité requise. Rechargez et dépensez partout",
"no_providers_available": "Aucun fournisseur disponible",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven na Cake Wallet",
"haven_app_wallet_text": "Kyakkyawan walat don Haven",
"help": "Taimako",
"hidden_accounts": "Hidden Accounts",
"hidden_addresses": "Adiresoshin da aka ɓoye",
"hidden_balance": "Ma’aunin da aka ɓoye",
"hide": "Boye",
@@ -735,6 +736,8 @@
"no_buy_providers": "Ba a sami masu samar da ${curr} ba.",
"no_cards_found": "Ba a sami katuna ba",
"no_extra_detail": "Babu ƙarin bayani",
"no_hidden_accounts": "Babu boye asusu",
"no_hidden_accounts_desc": "Kuna iya ɓoye asusu daga allon keɓancewa.",
"no_id_needed": "Ba a buƙatar ID!",
"no_id_required": "Ba a buƙatar ID. Yi top up kuma ka kashe a ko’ina",
"no_providers_available": "Babu masu ba da sabis",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven by Cake Wallet",
"haven_app_wallet_text": "Haven के लिए शानदार वॉलेट",
"help": "मदद",
"hidden_accounts": "छिपे हुए खाते",
"hidden_addresses": "छिपे हुए पते",
"hidden_balance": "छिपा हुआ बैलेंस",
"hide": "छिपाएँ",
@@ -735,6 +736,8 @@
"no_buy_providers": "${curr} के लिए कोई प्रदाता नहीं मिला।",
"no_cards_found": "कोई कार्ड नहीं मिले",
"no_extra_detail": "कोई अतिरिक्त विवरण उपलब्ध नहीं है",
"no_hidden_accounts": "कोई छिपा हुआ खाता नहीं",
"no_hidden_accounts_desc": "आप अनुकूलन स्क्रीन से खाते छिपा सकते हैं.",
"no_id_needed": "कोई ID नहीं चाहिए!",
"no_id_required": "कोई आईडी आवश्यक नहीं। टॉप अप करें और कहीं भी खर्च करें",
"no_providers_available": "कोई प्रदाता उपलब्ध नहीं है",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven by Cake Wallet",
"haven_app_wallet_text": "Odličan novčanik za Haven",
"help": "pomoć",
"hidden_accounts": "Skriveni računi",
"hidden_addresses": "Skrivene adrese",
"hidden_balance": "Skriveno stanje",
"hide": "Sakrij",
@@ -735,6 +736,8 @@
"no_buy_providers": "Nije pronađen nijedan pružatelj za ${curr}.",
"no_cards_found": "Nisu pronađene kartice",
"no_extra_detail": "Nema dostupnih dodatnih detalja",
"no_hidden_accounts": "Nema skrivenih računa",
"no_hidden_accounts_desc": "Možete sakriti račune sa zaslona za prilagodbu.",
"no_id_needed": "ID nije potreban!",
"no_id_required": "Nije potrebna osobna iskaznica. Nadopunite i trošite bilo gdje",
"no_providers_available": "Nema dostupnih pružatelja",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven՝ Cake Wallet-ից",
"haven_app_wallet_text": "Հիանալի դրամապանակ Haven-ի համար",
"help": "Օգնություն",
"hidden_accounts": "Թաքնված հաշիվներ",
"hidden_addresses": "Թաքնված հասցեներ",
"hidden_balance": "Թաքցված մնացորդ",
"hide": "Թաքցնել",
@@ -735,6 +736,8 @@
"no_buy_providers": "${curr}-ի մատակարարներ չեն գտնվել:",
"no_cards_found": "Քարտեր չեն գտնվել",
"no_extra_detail": "Լրացուցիչ մանրամասներ հասանելի չեն",
"no_hidden_accounts": "Թաքնված հաշիվներ չկան",
"no_hidden_accounts_desc": "Դուք կարող եք թաքցնել հաշիվները հարմարեցման էկրանից:",
"no_id_needed": "ID չի պահանջվում!",
"no_id_required": "Անձը հաստատող փաստաթուղթ չի պահանջվում։ Լրացրեք հաշիվը և ծախսեք ամենուր",
"no_providers_available": "Մատակարարներ չկան",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven oleh Cake Wallet",
"haven_app_wallet_text": "Dompet yang keren untuk Haven",
"help": "bantuan",
"hidden_accounts": "Akun Tersembunyi",
"hidden_addresses": "Alamat Tersembunyi",
"hidden_balance": "Saldo Tersembunyi",
"hide": "Sembunyikan",
@@ -735,6 +736,8 @@
"no_buy_providers": "Tidak ditemukan penyedia untuk ${curr}.",
"no_cards_found": "Tidak ada kartu ditemukan",
"no_extra_detail": "Tidak ada detail tambahan yang tersedia",
"no_hidden_accounts": "Tidak ada akun tersembunyi",
"no_hidden_accounts_desc": "Anda dapat menyembunyikan akun dari layar penyesuaian.",
"no_id_needed": "Tidak perlu ID!",
"no_id_required": "Tanpa perlu ID. Isi ulang dan belanja di mana saja",
"no_providers_available": "Tidak ada penyedia yang tersedia",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven di Cake Wallet",
"haven_app_wallet_text": "Ottimo wallet per Haven",
"help": "aiuto",
"hidden_accounts": "Conti nascosti",
"hidden_addresses": "Indirizzi nascosti",
"hidden_balance": "Saldo nascosto",
"hide": "Nascondi",
@@ -735,6 +736,8 @@
"no_buy_providers": "Nessun fornitore trovato per ${curr}.",
"no_cards_found": "Nessuna carta trovata",
"no_extra_detail": "Nessun dettaglio aggiuntivo disponibile",
"no_hidden_accounts": "Nessun account nascosto",
"no_hidden_accounts_desc": "Puoi nascondere gli account dalla schermata di personalizzazione.",
"no_id_needed": "Nessun ID necessario!",
"no_id_required": "Nessun documento d'identità richiesto. Ricarica e spendi ovunque",
"no_providers_available": "Nessun fornitore disponibile",
+3
View File
@@ -561,6 +561,7 @@
"haven_app": "Cake WalletのHaven",
"haven_app_wallet_text": "Haven向けの素晴らしいウォレット",
"help": "ヘルプ",
"hidden_accounts": "隠しアカウント",
"hidden_addresses": "非表示のアドレス",
"hidden_balance": "非表示残高",
"hide": "非表示",
@@ -736,6 +737,8 @@
"no_buy_providers": "${curr} のプロバイダーが見つかりません。",
"no_cards_found": "カードが見つかりません",
"no_extra_detail": "追加の詳細はありません",
"no_hidden_accounts": "隠しアカウントはありません",
"no_hidden_accounts_desc": "カスタマイズ画面からアカウントを非表示にすることができます。",
"no_id_needed": "ID不要!",
"no_id_required": "ID不要。どこでもチャージして使えます",
"no_providers_available": "利用可能なプロバイダーがありません",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Cake Wallet의 Haven",
"haven_app_wallet_text": "Haven용 멋진 지갑",
"help": "도움말",
"hidden_accounts": "숨겨진 계정",
"hidden_addresses": "숨겨진 주소",
"hidden_balance": "숨겨진 잔액",
"hide": "숨기기",
@@ -735,6 +736,8 @@
"no_buy_providers": "${curr}에 대한 제공업체를 찾을 수 없습니다.",
"no_cards_found": "카드를 찾을 수 없습니다",
"no_extra_detail": "추가 세부 정보가 없습니다",
"no_hidden_accounts": "숨겨진 계정 없음",
"no_hidden_accounts_desc": "사용자 정의 화면에서 계정을 숨길 수 있습니다.",
"no_id_needed": "신분증 필요 없음!",
"no_id_required": "신분증 필요 없음. 어디서나 충전하고 사용하세요",
"no_providers_available": "사용 가능한 제공업체가 없습니다",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Cake Wallet မှ Haven",
"haven_app_wallet_text": "Haven အတွက် အံ့ဩဖွယ်ကောင်းတဲ့ ဝေါလက်",
"help": "အကူအညီ",
"hidden_accounts": "ဝှက်ထားသောအကောင့်များ",
"hidden_addresses": "ဖျောက်ထားသော လိပ်စာများ",
"hidden_balance": "လျှို့ဝှက်ထားသော လက်ကျန်ငွေ",
"hide": "ဖျောက်ရန်",
@@ -735,6 +736,8 @@
"no_buy_providers": "${curr} အတွက် ဝန်ဆောင်မှုပေးသူများကို မတွေ့ပါ။",
"no_cards_found": "ကဒ် မတွေ့ပါ",
"no_extra_detail": "အပိုအသေးစိတ်အချက်အလက် မရှိပါ",
"no_hidden_accounts": "ဝှက်ထားသောအကောင့်များမရှိပါ။",
"no_hidden_accounts_desc": "စိတ်ကြိုက်ပြင်ဆင်ခြင်းစခရင်မှ အကောင့်များကို ဖျောက်ထားနိုင်သည်။",
"no_id_needed": "ID မလိုပါ!",
"no_id_required": "ID မလိုအပ်ပါ။ ငွေဖြည့်ပြီး ဘယ်နေရာမဆို သုံးနိုင်ပါသည်",
"no_providers_available": "ပံ့ပိုးသူများ မရှိပါ",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven by Cake Wallet",
"haven_app_wallet_text": "Geweldige wallet voor Haven",
"help": "Help",
"hidden_accounts": "Verborgen rekeningen",
"hidden_addresses": "Verborgen adressen",
"hidden_balance": "Verborgen saldo",
"hide": "Verbergen",
@@ -735,6 +736,8 @@
"no_buy_providers": "Geen providers gevonden voor ${curr}.",
"no_cards_found": "Geen kaarten gevonden",
"no_extra_detail": "Geen extra details beschikbaar",
"no_hidden_accounts": "Geen verborgen accounts",
"no_hidden_accounts_desc": "U kunt accounts verbergen in het aanpassingsscherm.",
"no_id_needed": "Geen ID nodig!",
"no_id_required": "Geen ID vereist. Bijladen en overal uitgeven",
"no_providers_available": "Geen providers beschikbaar",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven by Cake Wallet",
"haven_app_wallet_text": "Świetny portfel dla Haven",
"help": "pomoc",
"hidden_accounts": "Ukryte konta",
"hidden_addresses": "Ukryte adresy",
"hidden_balance": "Ukryte saldo",
"hide": "Ukryj",
@@ -735,6 +736,8 @@
"no_buy_providers": "Nie znaleziono dostawców dla ${curr}.",
"no_cards_found": "Nie znaleziono żadnych kart",
"no_extra_detail": "Brak dodatkowych szczegółów",
"no_hidden_accounts": "Żadnych ukrytych kont",
"no_hidden_accounts_desc": "Możesz ukryć konta na ekranie dostosowywania.",
"no_id_needed": "Nie wymaga dokumentu tożsamości!",
"no_id_required": "Nie jest wymagany dokument tożsamości. Doładuj i wydawaj wszędzie",
"no_providers_available": "Brak dostępnych dostawców",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven by Cake Wallet",
"haven_app_wallet_text": "Carteira incrível para Haven",
"help": "ajuda",
"hidden_accounts": "Contas ocultas",
"hidden_addresses": "Endereços ocultos",
"hidden_balance": "Saldo oculto",
"hide": "Ocultar",
@@ -736,6 +737,8 @@
"no_buy_providers": "Nenhum provedor encontrado para ${curr}.",
"no_cards_found": "Nenhum cartão encontrado",
"no_extra_detail": "Nenhum detalhe extra disponível",
"no_hidden_accounts": "Sem contas ocultas",
"no_hidden_accounts_desc": "Você pode ocultar contas na tela de personalização.",
"no_id_needed": "Não é necessário ID!",
"no_id_required": "Não é necessário documento de identificação. Recarregue e gaste em qualquer lugar",
"no_providers_available": "Nenhum provedor disponível",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven от Cake Wallet",
"haven_app_wallet_text": "Отличный кошелёк для Haven",
"help": "помощь",
"hidden_accounts": "Скрытые аккаунты",
"hidden_addresses": "Скрытые адреса",
"hidden_balance": "Скрытый баланс",
"hide": "Скрыть",
@@ -735,6 +736,8 @@
"no_buy_providers": "Для ${curr} провайдеров не найдено.",
"no_cards_found": "Карты не найдены",
"no_extra_detail": "Нет дополнительных сведений",
"no_hidden_accounts": "Никаких скрытых аккаунтов",
"no_hidden_accounts_desc": "Вы можете скрыть учетные записи с экрана настройки.",
"no_id_needed": "Документы не нужны!",
"no_id_required": "Документы не требуются. Пополняйте и тратьте где угодно",
"no_providers_available": "Нет доступных провайдеров",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven โดย Cake Wallet",
"haven_app_wallet_text": "กระเป๋าเงินที่ยอดเยี่ยมสำหรับ Haven",
"help": "ช่วยเหลือ",
"hidden_accounts": "บัญชีที่ซ่อนอยู่",
"hidden_addresses": "ที่อยู่ที่ซ่อนอยู่",
"hidden_balance": "ยอดคงเหลือที่ซ่อนอยู่",
"hide": "ซ่อน",
@@ -735,6 +736,8 @@
"no_buy_providers": "ไม่พบผู้ให้บริการสำหรับ ${curr}",
"no_cards_found": "ไม่พบการ์ด",
"no_extra_detail": "ไม่มีรายละเอียดเพิ่มเติม",
"no_hidden_accounts": "ไม่มีบัญชีที่ซ่อนอยู่",
"no_hidden_accounts_desc": "คุณสามารถซ่อนบัญชีได้จากหน้าจอการปรับแต่ง",
"no_id_needed": "ไม่ต้องใช้บัตรประชาชน!",
"no_id_required": "ไม่ต้องใช้บัตรประจำตัว เติมเงินและใช้จ่ายได้ทุกที่",
"no_providers_available": "ไม่มีผู้ให้บริการที่ใช้งานได้",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven by Cake Wallet",
"haven_app_wallet_text": "Napakagandang wallet para sa Haven",
"help": "Tulong",
"hidden_accounts": "Mga Nakatagong Account",
"hidden_addresses": "Nakatagong mga Address",
"hidden_balance": "Nakatagong Balanse",
"hide": "Itago",
@@ -735,6 +736,8 @@
"no_buy_providers": "Walang nakitang provider para sa ${curr}.",
"no_cards_found": "Walang nahanap na card",
"no_extra_detail": "Walang available na karagdagang detalye",
"no_hidden_accounts": "Walang nakatagong account",
"no_hidden_accounts_desc": "Maaari mong itago ang mga account mula sa screen ng pag-customize.",
"no_id_needed": "Hindi kailangan ng ID!",
"no_id_required": "Hindi kailangan ng ID. Mag-top up at gumastos kahit saan",
"no_providers_available": "Walang available na provider",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Cake Wallet'tan Haven",
"haven_app_wallet_text": "Haven için harika cüzdan",
"help": "yardım",
"hidden_accounts": "Gizli Hesaplar",
"hidden_addresses": "Gizli Adresler",
"hidden_balance": "Gizli Bakiye",
"hide": "Gizle",
@@ -735,6 +736,8 @@
"no_buy_providers": "${curr} için sağlayıcı bulunamadı.",
"no_cards_found": "Kart bulunamadı",
"no_extra_detail": "Ekstra ayrıntı mevcut değil",
"no_hidden_accounts": "Gizli hesap yok",
"no_hidden_accounts_desc": "Hesapları özelleştirme ekranından gizleyebilirsiniz.",
"no_id_needed": "Kimlik gerekmiyor!",
"no_id_required": "Kimlik gerekmez. Bakiye yükleyin ve her yerde harcayın",
"no_providers_available": "Kullanılabilir sağlayıcı yok",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Haven від Cake Wallet",
"haven_app_wallet_text": "Чудовий гаманець для Haven",
"help": "допомога",
"hidden_accounts": "Приховані облікові записи",
"hidden_addresses": "Приховані адреси",
"hidden_balance": "Прихований баланс",
"hide": "Сховати",
@@ -735,6 +736,8 @@
"no_buy_providers": "Не знайдено постачальників для ${curr}.",
"no_cards_found": "Картки не знайдено",
"no_extra_detail": "Немає додаткових відомостей",
"no_hidden_accounts": "Без прихованих облікових записів",
"no_hidden_accounts_desc": "Ви можете приховати облікові записи на екрані налаштування.",
"no_id_needed": "Без посвідчення особи!",
"no_id_required": "Документ не потрібен. Поповнюйте та витрачайте будь-де",
"no_providers_available": "Немає доступних провайдерів",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Cake Wallet کی جانب سے Haven",
"haven_app_wallet_text": "Haven کے لیے زبردست والیٹ",
"help": "مدد",
"hidden_accounts": "پوشیدہ اکاؤنٹس",
"hidden_addresses": "پوشیدہ پتے",
"hidden_balance": "پوشیدہ بیلنس",
"hide": "چھپائیں",
@@ -735,6 +736,8 @@
"no_buy_providers": "${curr} کے لیے کوئی فراہم کنندہ نہیں ملا۔",
"no_cards_found": "کوئی کارڈ نہیں ملا",
"no_extra_detail": "کوئی اضافی تفصیلات دستیاب نہیں ہیں",
"no_hidden_accounts": "کوئی پوشیدہ اکاؤنٹس نہیں۔",
"no_hidden_accounts_desc": "آپ حسب ضرورت اسکرین سے اکاؤنٹس چھپا سکتے ہیں۔",
"no_id_needed": "شناختی کارڈ کی ضرورت نہیں!",
"no_id_required": "کوئی شناختی دستاویز درکار نہیں۔ ٹاپ اپ کریں اور کہیں بھی خرچ کریں",
"no_providers_available": "کوئی فراہم کنندہ دستیاب نہیں ہے",
+3
View File
@@ -561,6 +561,7 @@
"haven_app": "Haven của Cake Wallet",
"haven_app_wallet_text": "Ví tuyệt vời cho Haven",
"help": "Trợ giúp",
"hidden_accounts": "Tài khoản ẩn",
"hidden_addresses": "Địa chỉ bị ẩn",
"hidden_balance": "Số dư ẩn",
"hide": "Ẩn",
@@ -736,6 +737,8 @@
"no_buy_providers": "Không tìm thấy nhà cung cấp nào cho ${curr}.",
"no_cards_found": "Không tìm thấy thẻ nào",
"no_extra_detail": "Không có thông tin chi tiết bổ sung",
"no_hidden_accounts": "Không có tài khoản ẩn",
"no_hidden_accounts_desc": "Bạn có thể ẩn tài khoản khỏi màn hình tùy chỉnh.",
"no_id_needed": "Không cần ID!",
"no_id_required": "Không cần ID. Nạp tiền và chi tiêu ở bất kỳ đâu",
"no_providers_available": "Không có nhà cung cấp nào khả dụng",
+3
View File
@@ -561,6 +561,7 @@
"haven_app": "Haven nipasẹ Cake Wallet",
"haven_app_wallet_text": "Àpamọ́wọ́ tó dára jùlọ fún Haven",
"help": "Ìrànlọ́wọ́",
"hidden_accounts": "Farasin Accounts",
"hidden_addresses": "Awọn Adirẹsi Tí a Fipamọ́",
"hidden_balance": "Ìwọ̀ntúnwọ̀nsì tí a fi pamọ́",
"hide": "Fi pamọ́",
@@ -736,6 +737,8 @@
"no_buy_providers": "Ko si olupese fun ${curr}.",
"no_cards_found": "A kò rí kaadi kankan",
"no_extra_detail": "Ko si alaye afikun ti o wa",
"no_hidden_accounts": "Ko si awọn iroyin pamọ",
"no_hidden_accounts_desc": "O le tọju awọn akọọlẹ lati iboju isọdi.",
"no_id_needed": "Kò sí ID tí o nílò!",
"no_id_required": "Kò sí ìdánimọ̀ tí a nílò. Ẹ lè fikún owó sí ìwọ̀n àti náà níbikíbi",
"no_providers_available": "Ko si olupese kankan ti o wa",
+3
View File
@@ -560,6 +560,7 @@
"haven_app": "Cake Wallet 的 Haven",
"haven_app_wallet_text": "适用于 Haven 的超棒钱包",
"help": "帮助",
"hidden_accounts": "隐藏账户",
"hidden_addresses": "隐藏地址",
"hidden_balance": "隐藏余额",
"hide": "隐藏",
@@ -735,6 +736,8 @@
"no_buy_providers": "未找到 ${curr} 的提供商。",
"no_cards_found": "未找到卡片",
"no_extra_detail": "没有可用的额外详细信息",
"no_hidden_accounts": "没有隐藏帐户",
"no_hidden_accounts_desc": "您可以从自定义屏幕隐藏帐户。",
"no_id_needed": "无需 ID!",
"no_id_required": "无需提供身份证明。随时充值,随处消费",
"no_providers_available": "暂无可用的服务提供商",
@@ -0,0 +1,177 @@
import "dart:async";
import "package:cake_wallet/core/execution_state.dart";
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/locales/locale.dart";
import "package:cake_wallet/src/screens/settings/widgets/account_creation_modal.dart";
import "package:cake_wallet/view_model/wallet_account_list/monero_account_list/monero_account_edit_or_create_view_model.dart";
import "package:flutter/material.dart";
import "package:flutter_test/flutter_test.dart";
import "package:mocktail/mocktail.dart";
class _MockAccountEditOrCreateViewModel extends Mock
implements MoneroAccountEditOrCreateViewModel {}
void main() {
late _MockAccountEditOrCreateViewModel viewModel;
bool? routeResult;
setUp(() {
viewModel = _MockAccountEditOrCreateViewModel();
routeResult = null;
});
Widget creationLauncher() => MaterialApp(
localizationsDelegates: localizationDelegates,
supportedLocales: S.delegate.supportedLocales,
home: Builder(
builder: (context) => Scaffold(
body: TextButton(
onPressed: () async {
routeResult = await Navigator.of(context).push<bool>(
MaterialPageRoute(
builder: (_) => Scaffold(
body: AccountCreationModal(
viewModel: viewModel,
),
),
),
);
},
child: const Text("Open account creation"),
),
),
),
);
Future<void> openModal(WidgetTester tester) async {
await tester.pumpWidget(creationLauncher());
await tester.tap(find.text("Open account creation"));
await tester.pumpAndSettle();
}
testWidgets("shows the Figma account-creation presentation", (tester) async {
await openModal(tester);
expect(find.text("Create Account"), findsOneWidget);
expect(
find.text(
"Accounts let you organize your funds into different compartments without needing to create a separate wallet",
),
findsOneWidget,
);
expect(find.byType(TextField), findsOneWidget);
expect(find.text("Continue"), findsOneWidget);
expect(find.bySemanticsLabel("Close"), findsOneWidget);
});
testWidgets("passes the entered name to the existing account save operation", (tester) async {
when(() => viewModel.save()).thenAnswer((_) async {});
when(() => viewModel.state).thenReturn(ExecutedSuccessfullyState());
await openModal(tester);
await tester.enterText(find.byType(TextField), "Savings");
await tester.pump();
await tester.tap(find.text("Continue"));
await tester.pumpAndSettle();
verify(() => viewModel.label = "Savings").called(1);
verify(() => viewModel.save()).called(1);
expect(routeResult, isTrue);
expect(find.byType(AccountCreationModal), findsNothing);
});
testWidgets("cannot be dismissed while account creation is in progress", (tester) async {
final saveCompleter = Completer<void>();
when(() => viewModel.save()).thenAnswer((_) => saveCompleter.future);
when(() => viewModel.state).thenReturn(ExecutedSuccessfullyState());
await openModal(tester);
await tester.enterText(find.byType(TextField), "Savings");
await tester.pump();
await tester.tap(find.text("Continue"));
await tester.pump();
await tester.tap(find.bySemanticsLabel("Close"));
await tester.pump();
expect(find.byType(AccountCreationModal), findsOneWidget);
await tester.binding.handlePopRoute();
await tester.pump();
expect(find.byType(AccountCreationModal), findsOneWidget);
saveCompleter.complete();
await tester.pumpAndSettle();
expect(routeResult, isTrue);
expect(find.byType(AccountCreationModal), findsNothing);
});
testWidgets("shows a save failure and restores safe dismissal", (tester) async {
when(() => viewModel.save()).thenAnswer((_) async {});
when(() => viewModel.state).thenReturn(FailureState("Could not create account"));
await openModal(tester);
await tester.enterText(find.byType(TextField), "Savings");
await tester.pump();
await tester.tap(find.text("Continue"));
await tester.pumpAndSettle();
expect(find.text("Could not create account"), findsOneWidget);
expect(find.byType(AccountCreationModal), findsOneWidget);
expect(routeResult, isNull);
await tester.tap(find.text("OK"));
await tester.pumpAndSettle();
await tester.tap(find.bySemanticsLabel("Close"));
await tester.pumpAndSettle();
verify(() => viewModel.save()).called(1);
expect(find.byType(AccountCreationModal), findsNothing);
expect(routeResult, isNull);
});
testWidgets("shows a thrown save error and restores safe dismissal", (tester) async {
when(() => viewModel.save()).thenThrow(Exception("Card design failed"));
await openModal(tester);
await tester.enterText(find.byType(TextField), "Savings");
await tester.pump();
await tester.tap(find.text("Continue"));
await tester.pumpAndSettle();
expect(find.text("Exception: Card design failed"), findsOneWidget);
expect(find.byType(AccountCreationModal), findsOneWidget);
expect(routeResult, isNull);
await tester.tap(find.text("OK"));
await tester.pumpAndSettle();
await tester.tap(find.bySemanticsLabel("Close"));
await tester.pumpAndSettle();
verify(() => viewModel.save()).called(1);
expect(find.byType(AccountCreationModal), findsNothing);
expect(routeResult, isNull);
});
testWidgets("requires a non-empty account name before continuing", (tester) async {
await openModal(tester);
TextButton continueButton() => tester.widget<TextButton>(
find.ancestor(
of: find.text("Continue"),
matching: find.byType(TextButton),
),
);
expect(continueButton().onPressed, isNull);
await tester.enterText(find.byType(TextField), " ");
await tester.pump();
expect(continueButton().onPressed, isNull);
verifyNever(() => viewModel.save());
await tester.enterText(find.byType(TextField), "Savings");
await tester.pump();
expect(continueButton().onPressed, isNotNull);
});
}
@@ -0,0 +1,206 @@
import "package:cake_wallet/di.dart";
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/locales/locale.dart";
import "package:cake_wallet/new-ui/pages/account_education_page.dart";
import "package:cake_wallet/store/settings_store.dart";
import "package:cake_wallet/themes/core/theme_store.dart";
import "package:flutter/material.dart";
import "package:flutter_test/flutter_test.dart";
import "package:mocktail/mocktail.dart";
class _MockSettingsStore extends Mock implements SettingsStore {}
void main() {
late bool registeredThemeStore;
late _MockSettingsStore settingsStore;
setUpAll(() {
registeredThemeStore = !getIt.isRegistered<ThemeStore>();
if (registeredThemeStore) {
getIt.registerSingleton(ThemeStore());
}
});
tearDownAll(() async {
if (registeredThemeStore) {
await getIt.unregister<ThemeStore>();
}
});
setUp(() {
settingsStore = _MockSettingsStore();
when(() => settingsStore.dismissEducation(any())).thenAnswer((_) async {});
});
Future<void> openEducation(WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
localizationsDelegates: localizationDelegates,
supportedLocales: S.delegate.supportedLocales,
home: Scaffold(
body: Builder(
builder: (context) => TextButton(
onPressed: () => AccountEducationPage(settingsStore: settingsStore).show(context),
child: const Text("Open education"),
),
),
),
),
);
await tester.tap(find.text("Open education"));
await tester.pumpAndSettle();
}
Future<void> continueToNextPage(WidgetTester tester) async {
await tester.tap(find.text("Continue"));
await tester.pump();
await tester.pumpAndSettle();
}
testWidgets("first page explains account organization and exposes progress", (tester) async {
final semantics = tester.ensureSemantics();
await openEducation(tester);
expect(
find.text(
"Accounts let you organize your funds by acting as separate pockets within one wallet",
),
findsOneWidget,
);
expect(
find.text(
"You can create one for your regular spending, another for your savings... all accessible from the same homescreen",
),
findsOneWidget,
);
expect(find.bySemanticsLabel(RegExp("Page 1 of 4")), findsOneWidget);
expect(find.text("Continue"), findsOneWidget);
verifyNever(() => settingsStore.dismissEducation(any()));
final title = find.text(
"Accounts let you organize your funds by acting as separate pockets within one wallet",
);
final image = find.byKey(const ValueKey("accounts-education-overview-image"));
final description = find.text(
"You can create one for your regular spending, another for your savings... all accessible from the same homescreen",
);
expect(tester.getBottomLeft(title).dy, lessThan(tester.getTopLeft(image).dy));
expect(tester.getBottomLeft(image).dy, lessThan(tester.getTopLeft(description).dy));
expect(
tester.getTopLeft(image).dy - tester.getBottomLeft(title).dy,
greaterThanOrEqualTo(24),
);
expect(
tester.getTopLeft(description).dy - tester.getBottomLeft(image).dy,
greaterThanOrEqualTo(24),
);
semantics.dispose();
});
testWidgets("Continue advances to the recovery education page", (tester) async {
final semantics = tester.ensureSemantics();
await openEducation(tester);
await continueToNextPage(tester);
expect(
find.text(
"Accounts belong together in one wallet, they can all be restored from just one Recovery Phrase",
),
findsOneWidget,
);
expect(find.bySemanticsLabel(RegExp("Page 2 of 4")), findsOneWidget);
verifyNever(() => settingsStore.dismissEducation(any()));
semantics.dispose();
});
testWidgets("account-order education follows the Figma content sequence", (tester) async {
await openEducation(tester);
await continueToNextPage(tester);
await continueToNextPage(tester);
final orderImage = find.byKey(const ValueKey("accounts-education-order-image"));
final title = find.text(
"Accounts are created in order, and they are restored in the same order",
);
final accountImage = find.byKey(
const ValueKey("accounts-education-ordered-account-image"),
);
final description = find.byWidgetPredicate(
(widget) =>
widget is RichText &&
widget.text.toPlainText() ==
"The order of creation is shown alongside the account name, in the Accounts menu",
);
final restoreDescription = find.text(
"This is useful to know if you want to restore your accounts, both in Cake Wallet or elsewhere",
);
expect(tester.getBottomLeft(orderImage).dy, lessThan(tester.getTopLeft(title).dy));
expect(tester.getBottomLeft(title).dy, lessThan(tester.getTopLeft(accountImage).dy));
expect(tester.getBottomLeft(accountImage).dy, lessThan(tester.getTopLeft(description).dy));
expect(
tester.getBottomLeft(description).dy,
lessThan(tester.getTopLeft(restoreDescription).dy),
);
expect(
tester.getTopLeft(title).dy - tester.getBottomLeft(orderImage).dy,
moreOrLessEquals(51, epsilon: 0.1),
);
expect(
tester.getTopLeft(accountImage).dy - tester.getBottomLeft(title).dy,
moreOrLessEquals(51, epsilon: 0.1),
);
expect(
tester.getTopLeft(description).dy - tester.getBottomLeft(accountImage).dy,
moreOrLessEquals(51, epsilon: 0.1),
);
});
testWidgets("final acknowledgement marks education as seen", (tester) async {
await openEducation(tester);
await continueToNextPage(tester);
await continueToNextPage(tester);
await continueToNextPage(tester);
expect(
find.text("Accounts cannot be deleted, only archived"),
findsOneWidget,
);
expect(
find.text(
"If you deposit funds to an account, they will still be there even if you archive it",
),
findsOneWidget,
);
expect(find.text("I understand. Continue"), findsOneWidget);
await tester.tap(find.text("I understand. Continue"));
await tester.pumpAndSettle();
verify(() => settingsStore.dismissEducation("accounts")).called(1);
});
testWidgets("closing education also marks it as seen", (tester) async {
final semantics = tester.ensureSemantics();
await openEducation(tester);
await tester.tap(find.bySemanticsLabel("Close"));
await tester.pumpAndSettle();
verify(() => settingsStore.dismissEducation("accounts")).called(1);
semantics.dispose();
});
testWidgets("dismissing the modal without completing education marks it as seen", (tester) async {
await openEducation(tester);
Navigator.of(tester.element(find.byType(AccountEducationPage))).pop();
await tester.pumpAndSettle();
expect(find.byType(AccountEducationPage), findsNothing);
verify(() => settingsStore.dismissEducation("accounts")).called(1);
});
}
@@ -0,0 +1,690 @@
import "dart:async";
import "package:cake_wallet/core/amount_parsing_proxy.dart";
import "package:cake_wallet/di.dart";
import "package:cake_wallet/entities/balance_display_mode.dart";
import "package:cake_wallet/entities/fiat_api_mode.dart";
import "package:cake_wallet/entities/fiat_currency.dart";
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/entities/bitcoin_amount_display_mode.dart";
import "package:cake_wallet/view_model/wallet_account_list/account_edit_or_create_view_model.dart";
import "package:cake_wallet/locales/locale.dart";
import "package:cake_wallet/new-ui/pages/wallet_accounts_page.dart";
import "package:cake_wallet/new-ui/pages/account_education_page.dart";
import "package:cake_wallet/new-ui/pages/card_customizer.dart";
import "package:cake_wallet/new-ui/pages/hidden_accounts.dart";
import "package:cake_wallet/new-ui/viewmodels/card_customizer/card_customizer_bloc.dart";
import "package:cake_wallet/new-ui/widgets/coins_page/cards/balance_card.dart";
import "package:cake_wallet/new-ui/widgets/money/money_settings_provider.dart";
import "package:cake_wallet/new-ui/widgets/modern_button.dart";
import "package:cake_wallet/store/app_store.dart";
import "package:cake_wallet/store/dashboard/fiat_conversion_store.dart";
import "package:cake_wallet/store/settings_store.dart";
import "package:cake_wallet/themes/core/theme_store.dart";
import "package:cake_wallet/view_model/dashboard/balance_view_model.dart";
import "package:cake_wallet/view_model/dashboard/dashboard_view_model.dart";
import "package:cake_wallet/view_model/wallet_account_list/account_list_item.dart";
import "package:cake_wallet/view_model/wallet_account_list/monero_account_list/monero_account_list_view_model.dart";
import "package:cw_core/amount/money.dart";
import "package:cw_core/balance.dart";
import "package:cw_core/balance_card_layout.dart";
import "package:cw_core/balance_card_style_settings.dart";
import "package:cw_core/card_design.dart";
import "package:cw_core/crypto_currency.dart";
import "package:cw_core/db/sqlite.dart" as sqlite;
import "package:cw_core/sync_status.dart";
import "package:cw_core/transaction_history.dart";
import "package:cw_core/transaction_info.dart";
import "package:cw_core/wallet_base.dart";
import "package:cw_core/wallet_info.dart";
import "package:cw_core/wallet_type.dart";
import "package:flutter/cupertino.dart";
import "package:flutter/material.dart";
import "package:flutter_test/flutter_test.dart";
import "package:mobx/mobx.dart" show Observable, runInAction;
import "package:mocktail/mocktail.dart";
import "package:sqflite_common_ffi/sqflite_ffi.dart";
class _MockAccountEditOrCreateViewModel extends Mock implements WalletAccountEditOrCreateViewModel {}
class _MockDashboardViewModel extends Mock implements DashboardViewModel {}
class _MockBalanceViewModel extends Mock implements BalanceViewModel {}
class _MockAppStore extends Mock implements AppStore {}
class _MockAccountListViewModel extends Mock implements MoneroAccountListViewModel {}
class _MockWallet extends Mock
implements WalletBase<Balance, TransactionHistoryBase<TransactionInfo>, TransactionInfo> {}
class _MockWalletInfo extends Mock implements WalletInfo {}
class _MockCardCustomizerBloc extends Mock implements CardCustomizerBloc {}
class _MockSettingsStore extends Mock implements SettingsStore {}
Future<void> _waitForArchivePage(WidgetTester tester) async {
for (var attempt = 0; attempt < 50; attempt++) {
await tester.runAsync(
() => Future<void>.delayed(const Duration(milliseconds: 10)),
);
await tester.pump();
if (find.byType(CupertinoActivityIndicator).evaluate().isEmpty) {
return;
}
}
throw TestFailure("Archived accounts did not finish loading");
}
Future<void> _waitForTextToDisappear(WidgetTester tester, String text) async {
for (var attempt = 0; attempt < 50; attempt++) {
await tester.runAsync(
() => Future<void>.delayed(const Duration(milliseconds: 10)),
);
await tester.pump(const Duration(milliseconds: 20));
if (find.text(text).evaluate().isEmpty) {
return;
}
}
throw TestFailure("$text did not disappear");
}
Future<void> _pumpUntil(WidgetTester tester, bool Function() done) async {
for (var attempt = 0; attempt < 100; attempt++) {
await tester.runAsync(
() => Future<void>.delayed(const Duration(milliseconds: 10)),
);
await tester.pump(const Duration(milliseconds: 10));
if (done()) {
return;
}
}
throw TestFailure("Timed out waiting for WalletAccountsPage");
}
void main() {
late bool registeredThemeStore;
late DatabaseFactory? originalDatabaseFactory;
late Database? originalDatabase;
late _MockDashboardViewModel dashboardViewModel;
late _MockBalanceViewModel balanceViewModel;
late _MockAccountListViewModel accountListViewModel;
late _MockWallet wallet;
late _MockWalletInfo walletInfo;
final fundedAccount =
AccountListItem(id: 0, label: "Savings", balance: Money.parse("1.25", CryptoCurrency.xmr));
final activeAccount =
AccountListItem(id: 1, label: "Primary", balance: Money.parse("0", CryptoCurrency.xmr));
final emptyAccount =
AccountListItem(id: 2, label: "Travel", balance: Money.parse("0", CryptoCurrency.xmr));
setUpAll(() {
registerFallbackValue(DesignSaved());
registerFallbackValue(
AccountListItem(id: -1, label: "fallback", balance: Money.zero(CryptoCurrency.xmr)),
);
registeredThemeStore = !getIt.isRegistered<ThemeStore>();
if (registeredThemeStore) {
getIt.registerSingleton(ThemeStore());
}
originalDatabaseFactory = databaseFactoryOrNull;
sqfliteFfiInit();
databaseFactory = databaseFactoryFfi;
});
tearDownAll(() async {
databaseFactoryOrNull = originalDatabaseFactory;
if (registeredThemeStore) {
await getIt.unregister<ThemeStore>();
}
});
setUp(() async {
originalDatabase = sqlite.db;
sqlite.db = await databaseFactory.openDatabase(inMemoryDatabasePath);
await sqlite.db!.execute("""
CREATE TABLE ${BalanceCardStyleSettings.tableName} (
walletInfoId INTEGER,
accountIndex INTEGER DEFAULT -1,
gradientIndex INTEGER DEFAULT -1,
useSpecialDesign BOOLEAN DEFAULT FALSE,
hidden BOOLEAN DEFAULT FALSE,
backgroundImagePath TEXT DEFAULT "",
iconStyleIndex INTEGER DEFAULT 0,
isGradientOnly BOOLEAN DEFAULT FALSE,
cardOrder INTEGER DEFAULT 0,
PRIMARY KEY (walletInfoId, accountIndex)
)
""");
dashboardViewModel = _MockDashboardViewModel();
balanceViewModel = _MockBalanceViewModel();
accountListViewModel = _MockAccountListViewModel();
wallet = _MockWallet();
walletInfo = _MockWalletInfo();
final settingsStore = _MockSettingsStore();
when(() => settingsStore.balanceDisplayMode).thenReturn(BalanceDisplayMode.displayableBalance);
when(() => settingsStore.displayAmountsInSatoshi).thenReturn(BitcoinAmountDisplayMode.bitcoin);
when(() => dashboardViewModel.settingsStore).thenReturn(settingsStore);
when(() => accountListViewModel.select(any())).thenAnswer((_) async {});
when(() => accountListViewModel.reload()).thenAnswer((_) async {});
when(() => dashboardViewModel.balanceViewModel).thenReturn(balanceViewModel);
when(() => balanceViewModel.accountFiatBalance(any())).thenReturn(null);
when(() => dashboardViewModel.isMultiAccountsEnabled).thenReturn(true);
when(() => dashboardViewModel.canToggleMultiAccounts).thenReturn(false);
when(() => dashboardViewModel.wallet).thenReturn(wallet);
when(() => dashboardViewModel.loadCardDesigns()).thenAnswer((_) async {});
when(() => wallet.walletInfo).thenReturn(walletInfo);
when(() => wallet.type).thenReturn(WalletType.monero);
when(() => wallet.currency).thenReturn(CryptoCurrency.xmr);
when(() => walletInfo.internalId).thenReturn(42);
when(() => accountListViewModel.currency).thenReturn(CryptoCurrency.xmr);
when(() => accountListViewModel.accounts).thenReturn([activeAccount]);
});
tearDown(() async {
await sqlite.db?.close();
sqlite.db = originalDatabase;
});
Future<void> hideAccount(int accountId, int order) => BalanceCardStyleSettings.fromCardDesign(
walletInfoId: 42,
accountIndex: accountId,
cardOrder: order,
design: CardDesign.gradientOnlyDesign,
hidden: true,
).insert();
Widget testApp(Widget home) => MaterialApp(
localizationsDelegates: localizationDelegates,
supportedLocales: S.delegate.supportedLocales,
builder: (_, child) => MoneySettingsProvider(
settingsStore: dashboardViewModel.settingsStore,
child: child!,
),
home: home,
);
testWidgets("empty archive explains where archived accounts will appear", (tester) async {
await tester.pumpWidget(
testApp(
HiddenAccountsPage(
accountListViewModel: accountListViewModel,
dashboardViewModel: dashboardViewModel,
),
),
);
await _waitForArchivePage(tester);
expect(find.text("Archived Accounts"), findsOneWidget);
expect(find.text("No Archived Accounts"), findsOneWidget);
expect(find.text("When you Archive an Account, it will show up here"), findsOneWidget);
});
testWidgets("archived accounts use the persisted hidden layout and Figma groups", (tester) async {
when(() => accountListViewModel.accounts)
.thenReturn([fundedAccount, activeAccount, emptyAccount]);
await tester.runAsync(() async {
await hideAccount(fundedAccount.id, 0);
await hideAccount(emptyAccount.id, 1);
});
await tester.pumpWidget(
testApp(
HiddenAccountsPage(
accountListViewModel: accountListViewModel,
dashboardViewModel: dashboardViewModel,
),
),
);
await _waitForArchivePage(tester);
expect(find.text("Funded accounts"), findsOneWidget);
expect(find.text("Unarchive an account to access its funds"), findsOneWidget);
expect(find.text("1. Savings"), findsOneWidget);
expect(find.text("1.25 XMR"), findsOneWidget);
expect(find.text("Empty Accounts"), findsOneWidget);
expect(find.text("3. Travel"), findsOneWidget);
expect(find.text("0 XMR"), findsNothing);
});
for (final currency in [CryptoCurrency.xmr, CryptoCurrency.btc]) {
testWidgets("archived ${currency.title} balances respect price, units, and privacy",
(tester) async {
final settingsStore = _MockSettingsStore();
final displayMode = Observable(BalanceDisplayMode.displayableBalance);
final amountDisplayMode = Observable(BitcoinAmountDisplayMode.bitcoin);
when(() => settingsStore.balanceDisplayMode).thenAnswer((_) => displayMode.value);
when(() => settingsStore.displayAmountsInSatoshi).thenAnswer((_) => amountDisplayMode.value);
final fundedAccount = AccountListItem(
id: 0,
label: "Savings",
balance: Money.parse("1.25", currency),
);
when(() => wallet.currency).thenReturn(currency);
when(() => wallet.type)
.thenReturn(currency == CryptoCurrency.btc ? WalletType.bitcoin : WalletType.monero);
when(() => accountListViewModel.currency).thenReturn(currency);
when(() => accountListViewModel.accounts)
.thenReturn([fundedAccount, activeAccount, emptyAccount]);
when(() => dashboardViewModel.settingsStore).thenReturn(settingsStore);
when(() => settingsStore.fiatCurrency).thenReturn(FiatCurrency.usd);
when(() => settingsStore.languageCode).thenReturn("de_DE");
when(() => settingsStore.fiatApiMode).thenReturn(FiatApiMode.enabled);
when(() => settingsStore.mwebAlwaysScan).thenReturn(false);
when(() => walletInfo.isShowIntroCakePayCard).thenReturn(false);
final appStore = _MockAppStore();
when(() => appStore.wallet).thenReturn(wallet);
when(() => appStore.amountParsingProxy)
.thenAnswer((_) => AmountParsingProxy(amountDisplayMode.value));
when(() => dashboardViewModel.balanceViewModel).thenReturn(
BalanceViewModel(
appStore: appStore,
settingsStore: settingsStore,
fiatConversionStore: FiatConversionStore()..prices[currency] = 20,
),
);
await tester.runAsync(() async {
await hideAccount(fundedAccount.id, 0);
await hideAccount(emptyAccount.id, 1);
});
await tester.pumpWidget(
testApp(
HiddenAccountsPage(
accountListViewModel: accountListViewModel,
dashboardViewModel: dashboardViewModel,
),
),
);
await _waitForArchivePage(tester);
expect(find.text("1.25 ${currency.title}"), findsOneWidget);
expect(find.text("25,00 USD"), findsOneWidget);
expect(find.text("3. Travel"), findsOneWidget);
expect(find.text("0,00 USD"), findsNothing);
if (currency == CryptoCurrency.btc) {
runInAction(() => amountDisplayMode.value = BitcoinAmountDisplayMode.satoshi);
await tester.pumpAndSettle();
expect(find.text("125,000,000 sats"), findsOneWidget);
expect(find.text("25,00 USD"), findsOneWidget);
}
runInAction(() => displayMode.value = BalanceDisplayMode.hiddenBalance);
await tester.pumpAndSettle();
expect(find.text("●●●●●●"), findsOneWidget);
expect(find.text("●●●●● USD"), findsOneWidget);
expect(find.text("25,00 USD"), findsNothing);
});
}
testWidgets("WalletAccountsPage shows education only until it has been seen", (tester) async {
var cardDesignLoads = 0;
var educationDismissed = false;
final settingsStore = _MockSettingsStore();
when(() => settingsStore.balanceDisplayMode).thenReturn(BalanceDisplayMode.displayableBalance);
when(() => settingsStore.displayAmountsInSatoshi).thenReturn(BitcoinAmountDisplayMode.bitcoin);
when(() => dashboardViewModel.settingsStore).thenReturn(settingsStore);
when(() => settingsStore.isEducationDismissed("accounts"))
.thenAnswer((_) => educationDismissed);
when(() => settingsStore.dismissEducation("accounts")).thenAnswer((_) async {
educationDismissed = true;
});
when(() => dashboardViewModel.loadCardDesigns()).thenAnswer((_) async {
cardDesignLoads++;
});
when(() => wallet.type).thenReturn(WalletType.monero);
when(() => wallet.currency).thenReturn(CryptoCurrency.xmr);
await tester.pumpWidget(
testApp(
WalletAccountsPage(
accountListViewModel: accountListViewModel,
accountEditOrCreateViewModel: _MockAccountEditOrCreateViewModel(),
dashboardViewModel: dashboardViewModel,
),
),
);
await _pumpUntil(tester, () => find.byType(AccountEducationPage).evaluate().isNotEmpty);
expect(find.byType(AccountEducationPage), findsOneWidget);
await tester.tap(
find.descendant(
of: find.byType(AccountEducationPage),
matching: find.bySemanticsLabel("Close"),
),
);
await tester.pumpAndSettle();
expect(settingsStore.isEducationDismissed("accounts"), isTrue);
final loadsBeforeFirstDispose = cardDesignLoads;
await tester.pumpWidget(testApp(const SizedBox.shrink()));
await _pumpUntil(tester, () => cardDesignLoads > loadsBeforeFirstDispose);
await tester.pumpWidget(
testApp(
WalletAccountsPage(
accountListViewModel: accountListViewModel,
accountEditOrCreateViewModel: _MockAccountEditOrCreateViewModel(),
dashboardViewModel: dashboardViewModel,
),
),
);
await _pumpUntil(tester, () => find.text("Add Account").evaluate().isNotEmpty);
await tester.pumpAndSettle();
expect(find.byType(AccountEducationPage), findsNothing);
final loadsBeforeSecondDispose = cardDesignLoads;
await tester.pumpWidget(testApp(const SizedBox.shrink()));
await _pumpUntil(tester, () => cardDesignLoads > loadsBeforeSecondDispose);
});
testWidgets("unnamed archived accounts get the Figma display fallback", (tester) async {
final unnamedAccount =
AccountListItem(id: 4, label: "", balance: Money.parse("0", CryptoCurrency.xmr));
when(() => accountListViewModel.accounts).thenReturn([activeAccount, unnamedAccount]);
await tester.runAsync(() => hideAccount(unnamedAccount.id, 0));
await tester.pumpWidget(
testApp(
HiddenAccountsPage(
accountListViewModel: accountListViewModel,
dashboardViewModel: dashboardViewModel,
),
),
);
await _waitForArchivePage(tester);
expect(find.text("5. Unnamed Account"), findsOneWidget);
});
testWidgets("unarchiving uses the latest account state for confirmation and selection",
(tester) async {
when(() => accountListViewModel.accounts).thenReturn([emptyAccount, activeAccount]);
await tester.runAsync(() => hideAccount(emptyAccount.id, 0));
await tester.pumpWidget(
testApp(
HiddenAccountsPage(
accountListViewModel: accountListViewModel,
dashboardViewModel: dashboardViewModel,
),
),
);
await _waitForArchivePage(tester);
final accountForConfirmation = AccountListItem(
id: emptyAccount.id,
label: emptyAccount.label,
balance: Money.parse("1.5", CryptoCurrency.xmr),
);
when(() => accountListViewModel.accounts).thenReturn([accountForConfirmation, activeAccount]);
await tester.tap(find.text("3. Travel"));
await tester.pumpAndSettle();
expect(find.text("Unarchive this account?"), findsOneWidget);
expect(
find.text("This account will show up again on your wallet, letting you access your funds"),
findsOneWidget,
);
expect(find.text("1.5 XMR"), findsOneWidget);
final latestAccount = AccountListItem(
id: emptyAccount.id,
label: "Updated",
balance: Money.parse("2.5", CryptoCurrency.xmr),
);
when(() => accountListViewModel.accounts).thenReturn([latestAccount, activeAccount]);
await tester.tap(find.text("Continue"));
await tester.pump();
await _waitForTextToDisappear(tester, "3. Travel");
final setting = await tester.runAsync(
() => BalanceCardStyleSettings.get(42, emptyAccount.id),
);
final settings = await tester.runAsync(() => BalanceCardStyleSettings.getAll(42));
final layout = BalanceCardLayout.resolve(
accountIndices: [emptyAccount.id, activeAccount.id],
settings: settings!,
);
expect(setting?.hidden, isFalse);
expect(layout.hidden, isEmpty);
expect(layout.visible, contains(emptyAccount.id));
verify(() => accountListViewModel.select(latestAccount)).called(1);
verify(() => dashboardViewModel.loadCardDesigns()).called(1);
expect(find.text("3. Travel"), findsNothing);
expect(find.text("No Archived Accounts"), findsOneWidget);
});
testWidgets("archive flow survives dismissal and protects the final visible account",
(tester) async {
final remainingAccount =
AccountListItem(id: 0, label: "Primary", balance: Money.parse("0", CryptoCurrency.xmr));
final archivedAccount = AccountListItem(
id: 1,
label: "Savings",
balance: Money.parse("0", CryptoCurrency.xmr),
isSelected: true,
);
final bloc = _MockCardCustomizerBloc();
final settingsStore = _MockSettingsStore();
when(() => settingsStore.balanceDisplayMode).thenReturn(BalanceDisplayMode.displayableBalance);
when(() => settingsStore.displayAmountsInSatoshi).thenReturn(BitcoinAmountDisplayMode.bitcoin);
final states = StreamController<CardCustomizerState>.broadcast();
final events = <Type>[];
final selections = <int>[];
final canHideValues = <bool>[];
final finishArchiveReload = Completer<void>();
var canHide = false;
var cardDesignLoads = 0;
var pauseCardDesignLoad = false;
when(() => settingsStore.isEducationDismissed("accounts")).thenReturn(true);
var customizerState = CardCustomizerInitial(
0,
0,
const <CardDesign>[CardDesign.gradientOnlyDesign],
const <Gradient>[CardDesign.gradientBlue],
"Savings",
archivedAccount.id,
false,
1,
);
final savedState = CardCustomizerSaved(
0,
0,
const <CardDesign>[CardDesign.gradientOnlyDesign],
const <Gradient>[CardDesign.gradientBlue],
"Savings",
archivedAccount.id,
false,
1,
);
final accounts = <AccountListItem>[remainingAccount, archivedAccount];
when(() => accountListViewModel.accounts).thenAnswer((_) => accounts);
when(() => accountListViewModel.select(any())).thenAnswer((invocation) async {
selections.add((invocation.positionalArguments.single as AccountListItem).id);
});
when(() => dashboardViewModel.status).thenReturn(SyncedSyncStatus());
when(() => dashboardViewModel.settingsStore).thenReturn(settingsStore);
when(() => dashboardViewModel.loadCardDesigns()).thenAnswer((_) async {
cardDesignLoads++;
if (pauseCardDesignLoad) {
await finishArchiveReload.future;
}
});
when(() => balanceViewModel.accountFiatBalance(any())).thenReturn("0,00 USD");
when(() => wallet.type).thenReturn(WalletType.monero);
when(() => wallet.currency).thenReturn(CryptoCurrency.xmr);
when(() => bloc.state).thenAnswer((_) => customizerState);
when(() => bloc.close()).thenAnswer((_) async {});
when(() => bloc.stream).thenAnswer((_) => states.stream);
when(() => bloc.canHide).thenAnswer((_) => canHide);
when(() => bloc.add(any())).thenAnswer((invocation) {
final event = invocation.positionalArguments.single as CardCustomizerEvent;
if (event is AccountNameChanged) {
customizerState = customizerState.copyWith(accountName: event.newAccountName);
return;
}
events.add(event.runtimeType);
if (event is DesignSaved) {
scheduleMicrotask(() => states.add(savedState));
} else if (event is AccountHidden) {
// Simulate AccountHidden's persisted output so WalletAccountsPage reloads visible cards.
scheduleMicrotask(() {
unawaited(
BalanceCardStyleSettings.fromCardDesign(
walletInfoId: 42,
accountIndex: archivedAccount.id,
cardOrder: 1,
design: CardDesign.gradientOnlyDesign,
hidden: true,
).insert().then((_) => states.add(savedState)),
);
});
}
});
var scopeOpen = true;
getIt.pushNewScope();
addTearDown(() async {
if (!finishArchiveReload.isCompleted) {
finishArchiveReload.complete();
}
if (!states.isClosed) {
await states.close();
}
if (scopeOpen) {
await getIt.popScope();
}
});
getIt.registerFactoryParam<CardCustomizerBloc, CardCustomizerBlocParams, void>(
(params, _) {
canHideValues.add(canHide = params.canHide);
return bloc;
},
);
await tester.pumpWidget(
testApp(
Scaffold(
body: WalletAccountsPage(
accountListViewModel: accountListViewModel,
accountEditOrCreateViewModel: _MockAccountEditOrCreateViewModel(),
dashboardViewModel: dashboardViewModel,
),
),
),
);
await _pumpUntil(tester, () => find.text("Add Account").evaluate().isNotEmpty);
ModernButton archiveButton() => tester.widget<ModernButton>(
find.byWidgetPredicate(
(widget) => widget is ModernButton && widget.semanticLabel == "Archived Accounts",
),
);
expect(archiveButton().backgroundColor, isNull);
expect(archiveButton().iconColor, isNull);
final frontCard = tester
.widgetList<BalanceCard>(find.byType(BalanceCard))
.singleWhere((card) => card.onCustomizeTapped != null);
expect(frontCard.fiatBalance, "0,00 USD");
frontCard.onCustomizeTapped!();
await tester.pumpAndSettle();
expect(find.byType(CardCustomizer), findsOneWidget);
expect(canHideValues, <bool>[true]);
expect(find.text("Archive Account"), findsOneWidget);
await tester.enterText(find.byType(TextField), "Long-term Savings");
await tester.ensureVisible(find.text("Archive Account"));
await tester.tap(find.text("Archive Account"));
await tester.pumpAndSettle();
expect(find.text("2. Long-term Savings"), findsOneWidget);
await tester.tap(find.text("Cancel"));
await tester.pumpAndSettle();
await tester.tap(find.text("Archive Account"));
await tester.pumpAndSettle();
final loadsBeforeArchive = cardDesignLoads;
pauseCardDesignLoad = true;
await tester.tap(find.text("Continue"));
await tester.pump();
await _pumpUntil(
tester,
() => events.length == 2 && selections.length == 2 && cardDesignLoads > loadsBeforeArchive,
);
expect(events, <Type>[DesignSaved, AccountHidden]);
expect(selections, <int>[archivedAccount.id, remainingAccount.id]);
await tester.pumpWidget(testApp(const SizedBox.shrink()));
pauseCardDesignLoad = false;
finishArchiveReload.complete();
await tester.pump();
final archivedSetting = await tester.runAsync(() async {
// Queue the final read behind both disposal writes from the unfixed flow.
await BalanceCardStyleSettings.getAll(42);
await BalanceCardStyleSettings.getAll(42);
return BalanceCardStyleSettings.get(42, archivedAccount.id);
});
expect(archivedSetting?.hidden, isTrue);
expect(selections, <int>[archivedAccount.id, remainingAccount.id]);
await tester.pumpWidget(
testApp(
Scaffold(
body: WalletAccountsPage(
accountListViewModel: accountListViewModel,
accountEditOrCreateViewModel: _MockAccountEditOrCreateViewModel(),
dashboardViewModel: dashboardViewModel,
),
),
),
);
await _pumpUntil(tester, () => find.text("Add Account").evaluate().isNotEmpty);
final colorScheme = Theme.of(tester.element(find.byType(WalletAccountsPage))).colorScheme;
expect(archiveButton().backgroundColor, colorScheme.primary);
expect(archiveButton().iconColor, colorScheme.onPrimary);
final remainingFrontCard = tester
.widgetList<BalanceCard>(find.byType(BalanceCard))
.singleWhere((card) => card.onCustomizeTapped != null);
remainingFrontCard.onCustomizeTapped!();
await tester.pumpAndSettle();
expect(canHideValues, <bool>[true, false]);
expect(find.text("Archive Account"), findsNothing);
Navigator.of(tester.element(find.byType(CardCustomizer))).pop(false);
await tester.pump();
await _pumpUntil(tester, () => events.length == 3 && selections.length == 3);
expect(events.last, DesignSaved);
expect(selections.last, remainingAccount.id);
final loadsBeforeDispose = cardDesignLoads;
await tester.pumpWidget(testApp(const SizedBox.shrink()));
await _pumpUntil(tester, () => cardDesignLoads > loadsBeforeDispose);
await states.close();
await getIt.popScope();
scopeOpen = false;
});
}
+252
View File
@@ -0,0 +1,252 @@
import "dart:async";
import "package:cake_wallet/di.dart";
import "package:cake_wallet/entities/balance_display_mode.dart";
import "package:cake_wallet/entities/bitcoin_amount_display_mode.dart";
import "package:cake_wallet/generated/i18n.dart";
import "package:cake_wallet/locales/locale.dart";
import "package:cake_wallet/new-ui/pages/card_customizer.dart";
import "package:cake_wallet/new-ui/viewmodels/card_customizer/card_customizer_bloc.dart";
import "package:cake_wallet/new-ui/widgets/coins_page/cards/balance_card.dart";
import "package:cake_wallet/new-ui/widgets/money/money_settings_provider.dart";
import "package:cake_wallet/themes/core/theme_store.dart";
import "package:cake_wallet/store/settings_store.dart";
import "package:cake_wallet/view_model/dashboard/dashboard_view_model.dart";
import "package:cake_wallet/view_model/wallet_account_list/account_list_item.dart";
import "package:cw_core/amount/money.dart";
import "package:cw_core/card_design.dart";
import "package:cw_core/crypto_currency.dart";
import "package:flutter/material.dart";
import "package:flutter_bloc/flutter_bloc.dart";
import "package:flutter_test/flutter_test.dart";
import "package:mocktail/mocktail.dart";
class _MockCardCustomizerBloc extends Mock implements CardCustomizerBloc {}
class _MockDashboardViewModel extends Mock implements DashboardViewModel {}
class _MockSettingsStore extends Mock implements SettingsStore {}
class _RouteTracker {
bool completed = false;
bool? result;
}
CardCustomizerState _accountState(String accountName) => CardCustomizerInitial(
0,
0,
const <CardDesign>[CardDesign.gradientOnlyDesign],
const <Gradient>[CardDesign.gradientBlue],
accountName,
0,
false,
0,
);
Future<_RouteTracker> _openCustomizer(
WidgetTester tester,
CardCustomizerBloc bloc, {
required DashboardViewModel dashboardViewModel,
required AccountListItem? account,
String fiatBalance = "",
}) async {
final tracker = _RouteTracker();
await tester.pumpWidget(
MaterialApp(
localizationsDelegates: localizationDelegates,
supportedLocales: S.delegate.supportedLocales,
builder: (_, child) => MoneySettingsProvider(
settingsStore: dashboardViewModel.settingsStore,
child: child!,
),
home: Builder(
builder: (context) => Scaffold(
body: TextButton(
onPressed: () {
Navigator.of(context)
.push<bool>(
MaterialPageRoute(
builder: (_) => BlocProvider<CardCustomizerBloc>.value(
value: bloc,
child: Material(
child: CardCustomizer(
cryptoTitle: "Monero",
cryptoName: "xmr",
account: account,
fiatBalance: fiatBalance,
),
),
),
),
)
.then((result) {
tracker
..completed = true
..result = result;
});
},
child: const Text("Open card customizer"),
),
),
),
),
);
await tester.tap(find.text("Open card customizer"));
await tester.pumpAndSettle();
return tracker;
}
void main() {
late _MockCardCustomizerBloc bloc;
late _MockDashboardViewModel dashboardViewModel;
late AccountListItem account;
late StreamController<CardCustomizerState> stateController;
setUpAll(() {
getIt.registerSingleton(ThemeStore());
});
tearDownAll(() async {
await getIt.unregister<ThemeStore>();
});
setUp(() {
bloc = _MockCardCustomizerBloc();
dashboardViewModel = _MockDashboardViewModel();
account =
AccountListItem(id: 0, label: "Savings", balance: Money.parse("1.25", CryptoCurrency.xmr));
final settingsStore = _MockSettingsStore();
when(() => settingsStore.balanceDisplayMode).thenReturn(BalanceDisplayMode.displayableBalance);
when(() => dashboardViewModel.settingsStore).thenReturn(settingsStore);
when(() => settingsStore.displayAmountsInSatoshi).thenReturn(BitcoinAmountDisplayMode.bitcoin);
stateController = StreamController<CardCustomizerState>.broadcast();
when(() => bloc.stream).thenAnswer((_) => stateController.stream);
when(() => bloc.canHide).thenReturn(true);
});
tearDown(() async {
await stateController.close();
});
testWidgets("account mode renders edit controls and cancels funded archival", (tester) async {
when(() => bloc.state).thenReturn(_accountState(""));
final tracker = await _openCustomizer(
tester,
bloc,
dashboardViewModel: dashboardViewModel,
account: account,
fiatBalance: "2.50 USD",
);
expect(find.text("Edit Account"), findsOneWidget);
expect(find.text("#1"), findsOneWidget);
expect(find.text("Unnamed Account"), findsOneWidget);
expect(find.text("1.25"), findsWidgets);
expect(find.text("2.50 USD"), findsOneWidget);
expect(find.text("Account name"), findsOneWidget);
expect(find.byType(TextField), findsOneWidget);
expect(find.text("Archive Account"), findsOneWidget);
expect(find.text("This change can be reverted"), findsOneWidget);
expect(
tester.getTopLeft(find.byType(BalanceCard).first).dy,
lessThan(tester.getTopLeft(find.text("Account name")).dy),
);
await tester.ensureVisible(find.text("Archive Account"));
await tester.pumpAndSettle();
await tester.tap(find.text("Archive Account"));
await tester.pumpAndSettle();
expect(find.text("Are you sure you want to Archive this account?"), findsOneWidget);
expect(find.text("This account has the following funds:"), findsOneWidget);
expect(find.text("1.25 XMR"), findsOneWidget);
expect(
find.text("Before proceeding, it is recommended you move them to an account you will use"),
findsOneWidget,
);
expect(
find.text(
"Archiving an account does not delete any funds or activity. You can reverse this action",
),
findsOneWidget,
);
await tester.tap(find.text("Cancel"));
await tester.pumpAndSettle();
expect(find.byType(CardCustomizer), findsOneWidget);
expect(tracker.completed, isFalse);
});
testWidgets("confirming hidden empty-account archival returns true to the parent",
(tester) async {
account =
AccountListItem(id: 0, label: "Savings", balance: Money.parse("0", CryptoCurrency.xmr));
final settingsStore = dashboardViewModel.settingsStore;
when(() => settingsStore.balanceDisplayMode).thenReturn(BalanceDisplayMode.hiddenBalance);
when(() => bloc.state).thenReturn(_accountState("Savings"));
final tracker = await _openCustomizer(
tester,
bloc,
dashboardViewModel: dashboardViewModel,
account: account,
);
await tester.ensureVisible(find.text("Archive Account"));
await tester.pumpAndSettle();
await tester.tap(find.text("Archive Account"));
await tester.pumpAndSettle();
expect(find.text("1. Savings"), findsOneWidget);
expect(find.text("This account has the following funds:"), findsNothing);
expect(
find.text(
"This action won’t delete the account or its past activity, but only hide it inside Cake Wallet",
),
findsOneWidget,
);
expect(find.text("You can reverse this action from Accounts settings"), findsOneWidget);
await tester.tap(find.text("Continue"));
await tester.pumpAndSettle();
expect(find.byType(CardCustomizer), findsNothing);
expect(tracker.completed, isTrue);
expect(tracker.result, isTrue);
});
testWidgets("account editing remains available when archival is disabled", (tester) async {
when(() => bloc.state).thenReturn(_accountState("Savings"));
when(() => bloc.canHide).thenReturn(false);
await _openCustomizer(
tester,
bloc,
dashboardViewModel: dashboardViewModel,
account: account,
);
expect(find.text("Edit Account"), findsOneWidget);
expect(find.text("Account name"), findsOneWidget);
expect(find.byType(TextField), findsOneWidget);
expect(find.text("Savings"), findsWidgets);
expect(find.text("Archive Account"), findsNothing);
});
testWidgets("wallet card editing does not require an account", (tester) async {
when(() => bloc.state).thenReturn(_accountState(""));
when(() => bloc.canHide).thenReturn(false);
await _openCustomizer(
tester,
bloc,
dashboardViewModel: dashboardViewModel,
account: null,
);
expect(find.text("Edit Card"), findsOneWidget);
expect(find.byType(BalanceCard), findsWidgets);
expect(find.byType(TextField), findsNothing);
expect(find.text("Archive Account"), findsNothing);
});
}

Some files were not shown because too many files have changed in this diff Show More