mirror of
https://github.com/cake-tech/cake_wallet.git
synced 2024-12-23 12:09:43 +00:00
Merge branch 'main' of https://github.com/cake-tech/cake_wallet into CW-438-add-nano
This commit is contained in:
commit
82c7648897
58 changed files with 672 additions and 252 deletions
|
@ -1,6 +1,8 @@
|
|||
Improved edit/delete for nodes and wallets
|
||||
Wallets can now be renamed
|
||||
Accessibility improvements
|
||||
Improve Monero wallet rescan
|
||||
Additional exchange assets: SHIB, AAVE, ARB, BAT, COMP, CRO, ENS, FTM, FRAX, GUSD, GTC, GRT, LDO, NEXO, CAKE, PEPE, STORJ, TUSD, WBTC, WETH, ZRX, DYDX, STETH
|
||||
Cake Pay is temporarily removed, see https://cakelabs.com/news/cake-pay-mobile-to-shut-down/
|
||||
Monero background syncing! See https://guides.cakewallet.com/docs/monero/#background-syncing
|
||||
Cake 2FA access control settings! See https://guides.cakewallet.com/docs/advanced-features/authentication/#cake-2fa-presets-and-access-control-settings
|
||||
Support Monero node proxy
|
||||
UI improvements when sending to Address Book entry
|
||||
Allow renaming Monero account names
|
||||
Send templates now support multiple recipients (try using to make Monero change)
|
||||
Onramper improvements
|
||||
Scan node QR codes (for Umbrel)
|
|
@ -1,7 +1,9 @@
|
|||
Improved edit/delete for nodes and wallets
|
||||
Wallets can now be renamed
|
||||
Accessibility improvements
|
||||
Bitcoin transaction bug fixes
|
||||
Improve Monero wallet rescan
|
||||
Additional exchange assets: SHIB, AAVE, ARB, BAT, COMP, CRO, ENS, FTM, FRAX, GUSD, GTC, GRT, LDO, NEXO, CAKE, PEPE, STORJ, TUSD, WBTC, WETH, ZRX, DYDX, STETH
|
||||
Cake Pay is temporarily removed, see https://cakelabs.com/news/cake-pay-mobile-to-shut-down/
|
||||
Ethereum! Store ETH and ERC-20 tokens
|
||||
Monero background syncing! See https://guides.cakewallet.com/docs/monero/#background-syncing
|
||||
Cake 2FA access control settings! See https://guides.cakewallet.com/docs/advanced-features/authentication/#cake-2fa-presets-and-access-control-settings
|
||||
Support Monero node proxy
|
||||
UI improvements when sending to Address Book entry
|
||||
Allow renaming Monero/Haven account names
|
||||
Send templates now support multiple recipients (try using to make Monero change)
|
||||
Onramper improvements
|
||||
Scan node QR codes (for Umbrel)
|
|
@ -1,7 +1,9 @@
|
|||
import 'package:flutter/services.dart';
|
||||
|
||||
const utils = const MethodChannel('com.cake_wallet/native_utils');
|
||||
|
||||
void setIsAppSecureNative(bool isAppSecure) {
|
||||
utils.invokeMethod<Uint8List>('setIsAppSecure', {'isAppSecure': isAppSecure});
|
||||
try {
|
||||
final utils = const MethodChannel('com.cake_wallet/native_utils');
|
||||
|
||||
utils.invokeMethod<Uint8List>('setIsAppSecure', {'isAppSecure': isAppSecure});
|
||||
} catch (_) {}
|
||||
}
|
|
@ -134,6 +134,8 @@ PODS:
|
|||
- SDWebImage (5.16.0):
|
||||
- SDWebImage/Core (= 5.16.0)
|
||||
- SDWebImage/Core (5.16.0)
|
||||
- sensitive_clipboard (0.0.1):
|
||||
- Flutter
|
||||
- share_plus (0.0.1):
|
||||
- Flutter
|
||||
- shared_preferences_foundation (0.0.1):
|
||||
|
@ -150,6 +152,8 @@ PODS:
|
|||
- Flutter
|
||||
- wakelock (0.0.1):
|
||||
- Flutter
|
||||
- workmanager (0.0.1):
|
||||
- Flutter
|
||||
|
||||
DEPENDENCIES:
|
||||
- barcode_scan2 (from `.symlinks/plugins/barcode_scan2/ios`)
|
||||
|
@ -173,12 +177,14 @@ DEPENDENCIES:
|
|||
- path_provider_foundation (from `.symlinks/plugins/path_provider_foundation/ios`)
|
||||
- permission_handler_apple (from `.symlinks/plugins/permission_handler_apple/ios`)
|
||||
- platform_device_id (from `.symlinks/plugins/platform_device_id/ios`)
|
||||
- sensitive_clipboard (from `.symlinks/plugins/sensitive_clipboard/ios`)
|
||||
- share_plus (from `.symlinks/plugins/share_plus/ios`)
|
||||
- shared_preferences_foundation (from `.symlinks/plugins/shared_preferences_foundation/ios`)
|
||||
- uni_links (from `.symlinks/plugins/uni_links/ios`)
|
||||
- UnstoppableDomainsResolution (~> 4.0.0)
|
||||
- url_launcher_ios (from `.symlinks/plugins/url_launcher_ios/ios`)
|
||||
- wakelock (from `.symlinks/plugins/wakelock/ios`)
|
||||
- workmanager (from `.symlinks/plugins/workmanager/ios`)
|
||||
|
||||
SPEC REPOS:
|
||||
https://github.com/CocoaPods/Specs.git:
|
||||
|
@ -235,6 +241,8 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/permission_handler_apple/ios"
|
||||
platform_device_id:
|
||||
:path: ".symlinks/plugins/platform_device_id/ios"
|
||||
sensitive_clipboard:
|
||||
:path: ".symlinks/plugins/sensitive_clipboard/ios"
|
||||
share_plus:
|
||||
:path: ".symlinks/plugins/share_plus/ios"
|
||||
shared_preferences_foundation:
|
||||
|
@ -245,6 +253,8 @@ EXTERNAL SOURCES:
|
|||
:path: ".symlinks/plugins/url_launcher_ios/ios"
|
||||
wakelock:
|
||||
:path: ".symlinks/plugins/wakelock/ios"
|
||||
workmanager:
|
||||
:path: ".symlinks/plugins/workmanager/ios"
|
||||
|
||||
SPEC CHECKSUMS:
|
||||
barcode_scan2: 0af2bb63c81b4565aab6cd78278e4c0fa136dbb0
|
||||
|
@ -270,11 +280,12 @@ SPEC CHECKSUMS:
|
|||
MTBBarcodeScanner: f453b33c4b7dfe545d8c6484ed744d55671788cb
|
||||
OrderedSet: aaeb196f7fef5a9edf55d89760da9176ad40b93c
|
||||
package_info: 873975fc26034f0b863a300ad47e7f1ac6c7ec62
|
||||
path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8
|
||||
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
||||
permission_handler_apple: e76247795d700c14ea09e3a2d8855d41ee80a2e6
|
||||
platform_device_id: 81b3e2993881f87d0c82ef151dc274df4869aef5
|
||||
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
||||
SDWebImage: 2aea163b50bfcb569a2726b6a754c54a4506fcf6
|
||||
sensitive_clipboard: d4866e5d176581536c27bb1618642ee83adca986
|
||||
share_plus: 056a1e8ac890df3e33cb503afffaf1e9b4fbae68
|
||||
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
|
||||
SwiftProtobuf: 40bd808372cb8706108f22d28f8ab4a6b9bc6989
|
||||
|
@ -283,6 +294,7 @@ SPEC CHECKSUMS:
|
|||
UnstoppableDomainsResolution: c3c67f4d0a5e2437cb00d4bd50c2e00d6e743841
|
||||
url_launcher_ios: 08a3dfac5fb39e8759aeb0abbd5d9480f30fc8b4
|
||||
wakelock: d0fc7c864128eac40eba1617cb5264d9c940b46f
|
||||
workmanager: 0afdcf5628bbde6924c21af7836fed07b42e30e6
|
||||
|
||||
PODFILE CHECKSUM: 09df1114e7c360f55770d35a79356bf5446e0100
|
||||
|
||||
|
|
|
@ -606,4 +606,9 @@
|
|||
/* End XCConfigurationList section */
|
||||
};
|
||||
rootObject = 97C146E61CF9000F007C117D /* Project object */;
|
||||
SystemCapabilities = {
|
||||
com.apple.BackgroundModes = {
|
||||
enabled = 1;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import UIKit
|
||||
import Flutter
|
||||
import UnstoppableDomainsResolution
|
||||
import workmanager
|
||||
|
||||
@UIApplicationMain
|
||||
@objc class AppDelegate: FlutterAppDelegate {
|
||||
|
@ -16,6 +17,15 @@ import UnstoppableDomainsResolution
|
|||
UNUserNotificationCenter.current().delegate = self as? UNUserNotificationCenterDelegate
|
||||
}
|
||||
|
||||
WorkmanagerPlugin.setPluginRegistrantCallback { registry in
|
||||
// Registry in this case is the FlutterEngine that is created in Workmanager's
|
||||
// performFetchWithCompletionHandler or BGAppRefreshTask.
|
||||
// This will make other plugins available during a background operation.
|
||||
GeneratedPluginRegistrant.register(with: registry)
|
||||
}
|
||||
|
||||
WorkmanagerPlugin.registerTask(withIdentifier: "com.fotolockr.cakewallet.monero_sync_task")
|
||||
|
||||
makeSecure()
|
||||
|
||||
let controller : FlutterViewController = window?.rootViewController as! FlutterViewController
|
||||
|
|
|
@ -2,6 +2,10 @@
|
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>BGTaskSchedulerPermittedIdentifiers</key>
|
||||
<array>
|
||||
<string>com.fotolockr.cakewallet.monero_sync_task</string>
|
||||
</array>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
|
@ -113,6 +117,7 @@
|
|||
<key>UIBackgroundModes</key>
|
||||
<array>
|
||||
<string>fetch</string>
|
||||
<string>processing</string>
|
||||
<string>remote-notification</string>
|
||||
</array>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
|
|
|
@ -243,6 +243,8 @@ class BackupService {
|
|||
final sortBalanceTokensBy = data[PreferencesKey.sortBalanceBy] as int?;
|
||||
final pinNativeTokenAtTop = data[PreferencesKey.pinNativeTokenAtTop] as bool?;
|
||||
final useEtherscan = data[PreferencesKey.useEtherscan] as bool?;
|
||||
final syncAll = data[PreferencesKey.syncAllKey] as bool?;
|
||||
final syncMode = data[PreferencesKey.syncModeKey] as int?;
|
||||
|
||||
await _sharedPreferences.setString(PreferencesKey.currentWalletName, currentWalletName);
|
||||
|
||||
|
@ -361,11 +363,11 @@ class BackupService {
|
|||
if (useEtherscan != null)
|
||||
await _sharedPreferences.setBool(PreferencesKey.useEtherscan, useEtherscan);
|
||||
|
||||
if (sortBalanceTokensBy != null)
|
||||
await _sharedPreferences.setInt(PreferencesKey.sortBalanceBy, sortBalanceTokensBy);
|
||||
if (syncAll != null)
|
||||
await _sharedPreferences.setBool(PreferencesKey.syncAllKey, syncAll);
|
||||
|
||||
if (pinNativeTokenAtTop != null)
|
||||
await _sharedPreferences.setBool(PreferencesKey.pinNativeTokenAtTop, pinNativeTokenAtTop);
|
||||
if (syncMode != null)
|
||||
await _sharedPreferences.setInt(PreferencesKey.syncModeKey, syncMode);
|
||||
|
||||
await preferencesFile.delete();
|
||||
}
|
||||
|
@ -516,6 +518,10 @@ class BackupService {
|
|||
_sharedPreferences.getBool(PreferencesKey.pinNativeTokenAtTop),
|
||||
PreferencesKey.useEtherscan:
|
||||
_sharedPreferences.getBool(PreferencesKey.useEtherscan),
|
||||
PreferencesKey.syncModeKey:
|
||||
_sharedPreferences.getInt(PreferencesKey.syncModeKey),
|
||||
PreferencesKey.syncAllKey:
|
||||
_sharedPreferences.getBool(PreferencesKey.syncAllKey),
|
||||
};
|
||||
|
||||
return json.encode(preferences);
|
||||
|
|
11
lib/di.dart
11
lib/di.dart
|
@ -4,6 +4,7 @@ import 'package:cake_wallet/anonpay/anonpay_invoice_info.dart';
|
|||
import 'package:cake_wallet/buy/onramper/onramper_buy_provider.dart';
|
||||
import 'package:cake_wallet/buy/payfura/payfura_buy_provider.dart';
|
||||
import 'package:cake_wallet/core/yat_service.dart';
|
||||
import 'package:cake_wallet/entities/background_tasks.dart';
|
||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
||||
import 'package:cake_wallet/entities/receive_page_option.dart';
|
||||
|
@ -24,6 +25,7 @@ import 'package:cake_wallet/src/screens/dashboard/widgets/transactions_page.dart
|
|||
import 'package:cake_wallet/src/screens/receive/anonpay_invoice_page.dart';
|
||||
import 'package:cake_wallet/src/screens/receive/anonpay_receive_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/manage_nodes_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/other_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/privacy_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/security_backup_page.dart';
|
||||
|
@ -245,6 +247,10 @@ Future setup({
|
|||
getIt.registerSingletonAsync<SharedPreferences>(() => SharedPreferences.getInstance());
|
||||
}
|
||||
|
||||
if (!_isSetupFinished) {
|
||||
getIt.registerFactory(() => BackgroundTasks());
|
||||
}
|
||||
|
||||
final isBitcoinBuyEnabled = (secrets.wyreSecretKey.isNotEmpty) &&
|
||||
(secrets.wyreApiKey.isNotEmpty) &&
|
||||
(secrets.wyreAccountId.isNotEmpty);
|
||||
|
@ -682,8 +688,7 @@ Future setup({
|
|||
return NodeListViewModel(_nodeSource, appStore);
|
||||
});
|
||||
|
||||
getIt.registerFactory(
|
||||
() => ConnectionSyncPage(getIt.get<NodeListViewModel>(), getIt.get<DashboardViewModel>()));
|
||||
getIt.registerFactory(() => ConnectionSyncPage(getIt.get<DashboardViewModel>()));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => SecurityBackupPage(getIt.get<SecuritySettingsViewModel>(), getIt.get<AuthService>()));
|
||||
|
@ -1058,5 +1063,7 @@ Future setup({
|
|||
),
|
||||
);
|
||||
|
||||
getIt.registerFactory<ManageNodesPage>(() => ManageNodesPage(getIt.get<NodeListViewModel>()));
|
||||
|
||||
_isSetupFinished = true;
|
||||
}
|
||||
|
|
164
lib/entities/background_tasks.dart
Normal file
164
lib/entities/background_tasks.dart
Normal file
|
@ -0,0 +1,164 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/core/wallet_loading_service.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:workmanager/workmanager.dart';
|
||||
import 'package:cake_wallet/main.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
|
||||
const moneroSyncTaskKey = "com.fotolockr.cakewallet.monero_sync_task";
|
||||
|
||||
@pragma('vm:entry-point')
|
||||
void callbackDispatcher() {
|
||||
Workmanager().executeTask((task, inputData) async {
|
||||
try {
|
||||
switch (task) {
|
||||
case moneroSyncTaskKey:
|
||||
|
||||
/// The work manager runs on a separate isolate from the main flutter isolate.
|
||||
/// thus we initialize app configs first; hive, getIt, etc...
|
||||
await initializeAppConfigs();
|
||||
|
||||
final walletLoadingService = getIt.get<WalletLoadingService>();
|
||||
|
||||
final node = getIt.get<SettingsStore>().getCurrentNode(WalletType.monero);
|
||||
|
||||
final typeRaw = getIt.get<SharedPreferences>().getInt(PreferencesKey.currentWalletType);
|
||||
|
||||
WalletBase? wallet;
|
||||
|
||||
if (inputData!['sync_all'] as bool) {
|
||||
/// get all Monero wallets of the user and sync them
|
||||
final List<WalletListItem> moneroWallets = getIt
|
||||
.get<WalletListViewModel>()
|
||||
.wallets
|
||||
.where((element) => element.type == WalletType.monero)
|
||||
.toList();
|
||||
|
||||
for (int i = 0; i < moneroWallets.length; i++) {
|
||||
wallet = await walletLoadingService.load(WalletType.monero, moneroWallets[i].name);
|
||||
|
||||
await wallet.connectToNode(node: node);
|
||||
await wallet.startSync();
|
||||
}
|
||||
} else {
|
||||
/// if the user chose to sync only active wallet
|
||||
/// if the current wallet is monero; sync it only
|
||||
if (typeRaw == WalletType.monero.index) {
|
||||
final name =
|
||||
getIt.get<SharedPreferences>().getString(PreferencesKey.currentWalletName);
|
||||
|
||||
wallet = await walletLoadingService.load(WalletType.monero, name!);
|
||||
|
||||
await wallet.connectToNode(node: node);
|
||||
await wallet.startSync();
|
||||
}
|
||||
}
|
||||
|
||||
if (wallet?.syncStatus.progress() == null) {
|
||||
return Future.error("No Monero wallet found");
|
||||
}
|
||||
|
||||
for (int i = 0;; i++) {
|
||||
await Future<void>.delayed(const Duration(seconds: 1));
|
||||
if (wallet?.syncStatus.progress() == 1.0) {
|
||||
break;
|
||||
}
|
||||
if (i > 600) {
|
||||
return Future.error("Synchronization Timed out");
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return Future.value(true);
|
||||
} catch (error, stackTrace) {
|
||||
print(error);
|
||||
print(stackTrace);
|
||||
return Future.error(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
class BackgroundTasks {
|
||||
void registerSyncTask({bool changeExisting = false}) async {
|
||||
try {
|
||||
bool hasMonero = getIt
|
||||
.get<WalletListViewModel>()
|
||||
.wallets
|
||||
.any((element) => element.type == WalletType.monero);
|
||||
|
||||
/// if its not android nor ios, or the user has no monero wallets; exit
|
||||
if (!DeviceInfo.instance.isMobile || !hasMonero) {
|
||||
return;
|
||||
}
|
||||
|
||||
final settingsStore = getIt.get<SettingsStore>();
|
||||
|
||||
final SyncMode syncMode = settingsStore.currentSyncMode;
|
||||
final bool syncAll = settingsStore.currentSyncAll;
|
||||
|
||||
if (syncMode.type == SyncType.disabled) {
|
||||
cancelSyncTask();
|
||||
return;
|
||||
}
|
||||
|
||||
await Workmanager().initialize(
|
||||
callbackDispatcher,
|
||||
isInDebugMode: kDebugMode,
|
||||
);
|
||||
|
||||
final inputData = <String, dynamic>{"sync_all": syncAll};
|
||||
final constraints = Constraints(
|
||||
networkType:
|
||||
syncMode.type == SyncType.unobtrusive ? NetworkType.unmetered : NetworkType.connected,
|
||||
requiresBatteryNotLow: syncMode.type == SyncType.unobtrusive,
|
||||
requiresCharging: syncMode.type == SyncType.unobtrusive,
|
||||
requiresDeviceIdle: syncMode.type == SyncType.unobtrusive,
|
||||
);
|
||||
|
||||
if (Platform.isIOS) {
|
||||
await Workmanager().registerOneOffTask(
|
||||
moneroSyncTaskKey,
|
||||
moneroSyncTaskKey,
|
||||
initialDelay: syncMode.frequency,
|
||||
existingWorkPolicy: ExistingWorkPolicy.replace,
|
||||
inputData: inputData,
|
||||
constraints: constraints,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
await Workmanager().registerPeriodicTask(
|
||||
moneroSyncTaskKey,
|
||||
moneroSyncTaskKey,
|
||||
initialDelay: syncMode.frequency,
|
||||
frequency: syncMode.frequency,
|
||||
existingWorkPolicy: changeExisting ? ExistingWorkPolicy.replace : ExistingWorkPolicy.keep,
|
||||
inputData: inputData,
|
||||
constraints: constraints,
|
||||
);
|
||||
} catch (error, stackTrace) {
|
||||
print(error);
|
||||
print(stackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
void cancelSyncTask() {
|
||||
try {
|
||||
Workmanager().cancelByUniqueName(moneroSyncTaskKey);
|
||||
} catch (error, stackTrace) {
|
||||
print(error);
|
||||
print(stackTrace);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/core/key_service.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:cake_wallet/entities/background_tasks.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
import 'package:cake_wallet/core/wallet_loading_service.dart';
|
||||
|
@ -24,4 +23,6 @@ Future<void> loadCurrentWallet() async {
|
|||
final walletLoadingService = getIt.get<WalletLoadingService>();
|
||||
final wallet = await walletLoadingService.load(type, name);
|
||||
appStore.changeCurrentWallet(wallet);
|
||||
|
||||
getIt.get<BackgroundTasks>().registerSyncTask();
|
||||
}
|
||||
|
|
|
@ -37,6 +37,8 @@ class PreferencesKey {
|
|||
static const shouldShowReceiveWarning = 'should_show_receive_warning';
|
||||
static const shouldShowYatPopup = 'should_show_yat_popup';
|
||||
static const moneroWalletPasswordUpdateV1Base = 'monero_wallet_update_v1';
|
||||
static const syncModeKey = 'sync_mode';
|
||||
static const syncAllKey = 'sync_all';
|
||||
static const pinTimeOutDuration = 'pin_timeout_duration';
|
||||
static const lastAuthTimeMilliseconds = 'last_auth_time_milliseconds';
|
||||
static const lastPopupDate = 'last_popup_date';
|
||||
|
|
170
lib/main.dart
170
lib/main.dart
|
@ -57,97 +57,103 @@ Future<void> main() async {
|
|||
return true;
|
||||
};
|
||||
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
await Hive.close();
|
||||
Hive.init(appDir.path);
|
||||
|
||||
if (!Hive.isAdapterRegistered(Contact.typeId)) {
|
||||
Hive.registerAdapter(ContactAdapter());
|
||||
}
|
||||
await initializeAppConfigs();
|
||||
|
||||
if (!Hive.isAdapterRegistered(Node.typeId)) {
|
||||
Hive.registerAdapter(NodeAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(TransactionDescription.typeId)) {
|
||||
Hive.registerAdapter(TransactionDescriptionAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(Trade.typeId)) {
|
||||
Hive.registerAdapter(TradeAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(WalletInfo.typeId)) {
|
||||
Hive.registerAdapter(WalletInfoAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(walletTypeTypeId)) {
|
||||
Hive.registerAdapter(WalletTypeAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(Template.typeId)) {
|
||||
Hive.registerAdapter(TemplateAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(ExchangeTemplate.typeId)) {
|
||||
Hive.registerAdapter(ExchangeTemplateAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(Order.typeId)) {
|
||||
Hive.registerAdapter(OrderAdapter());
|
||||
}
|
||||
|
||||
if (!isMoneroOnly && !Hive.isAdapterRegistered(UnspentCoinsInfo.typeId)) {
|
||||
Hive.registerAdapter(UnspentCoinsInfoAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(AnonpayInvoiceInfo.typeId)) {
|
||||
Hive.registerAdapter(AnonpayInvoiceInfoAdapter());
|
||||
}
|
||||
|
||||
final secureStorage = FlutterSecureStorage();
|
||||
final transactionDescriptionsBoxKey =
|
||||
await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
|
||||
final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey);
|
||||
final ordersBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Order.boxKey);
|
||||
final contacts = await Hive.openBox<Contact>(Contact.boxName);
|
||||
final nodes = await Hive.openBox<Node>(Node.boxName);
|
||||
final transactionDescriptions = await Hive.openBox<TransactionDescription>(
|
||||
TransactionDescription.boxName,
|
||||
encryptionKey: transactionDescriptionsBoxKey);
|
||||
final trades = await Hive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
|
||||
final orders = await Hive.openBox<Order>(Order.boxName, encryptionKey: ordersBoxKey);
|
||||
final walletInfoSource = await Hive.openBox<WalletInfo>(WalletInfo.boxName);
|
||||
final templates = await Hive.openBox<Template>(Template.boxName);
|
||||
final exchangeTemplates = await Hive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
|
||||
final anonpayInvoiceInfo = await Hive.openBox<AnonpayInvoiceInfo>(AnonpayInvoiceInfo.boxName);
|
||||
Box<UnspentCoinsInfo>? unspentCoinsInfoSource;
|
||||
|
||||
if (!isMoneroOnly) {
|
||||
unspentCoinsInfoSource = await Hive.openBox<UnspentCoinsInfo>(UnspentCoinsInfo.boxName);
|
||||
}
|
||||
|
||||
await initialSetup(
|
||||
sharedPreferences: await SharedPreferences.getInstance(),
|
||||
nodes: nodes,
|
||||
walletInfoSource: walletInfoSource,
|
||||
contactSource: contacts,
|
||||
tradesSource: trades,
|
||||
ordersSource: orders,
|
||||
unspentCoinsInfoSource: unspentCoinsInfoSource,
|
||||
// fiatConvertationService: fiatConvertationService,
|
||||
templates: templates,
|
||||
exchangeTemplates: exchangeTemplates,
|
||||
transactionDescriptions: transactionDescriptions,
|
||||
secureStorage: secureStorage,
|
||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||
initialMigrationVersion: 22);
|
||||
runApp(App());
|
||||
}, (error, stackTrace) async {
|
||||
ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stackTrace));
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> initializeAppConfigs() async {
|
||||
final appDir = await getApplicationDocumentsDirectory();
|
||||
Hive.init(appDir.path);
|
||||
|
||||
if (!Hive.isAdapterRegistered(Contact.typeId)) {
|
||||
Hive.registerAdapter(ContactAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(Node.typeId)) {
|
||||
Hive.registerAdapter(NodeAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(TransactionDescription.typeId)) {
|
||||
Hive.registerAdapter(TransactionDescriptionAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(Trade.typeId)) {
|
||||
Hive.registerAdapter(TradeAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(WalletInfo.typeId)) {
|
||||
Hive.registerAdapter(WalletInfoAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(walletTypeTypeId)) {
|
||||
Hive.registerAdapter(WalletTypeAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(Template.typeId)) {
|
||||
Hive.registerAdapter(TemplateAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(ExchangeTemplate.typeId)) {
|
||||
Hive.registerAdapter(ExchangeTemplateAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(Order.typeId)) {
|
||||
Hive.registerAdapter(OrderAdapter());
|
||||
}
|
||||
|
||||
if (!isMoneroOnly && !Hive.isAdapterRegistered(UnspentCoinsInfo.typeId)) {
|
||||
Hive.registerAdapter(UnspentCoinsInfoAdapter());
|
||||
}
|
||||
|
||||
if (!Hive.isAdapterRegistered(AnonpayInvoiceInfo.typeId)) {
|
||||
Hive.registerAdapter(AnonpayInvoiceInfoAdapter());
|
||||
}
|
||||
|
||||
final secureStorage = FlutterSecureStorage();
|
||||
final transactionDescriptionsBoxKey =
|
||||
await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
|
||||
final tradesBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Trade.boxKey);
|
||||
final ordersBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Order.boxKey);
|
||||
final contacts = await Hive.openBox<Contact>(Contact.boxName);
|
||||
final nodes = await Hive.openBox<Node>(Node.boxName);
|
||||
final transactionDescriptions = await Hive.openBox<TransactionDescription>(
|
||||
TransactionDescription.boxName,
|
||||
encryptionKey: transactionDescriptionsBoxKey);
|
||||
final trades = await Hive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
|
||||
final orders = await Hive.openBox<Order>(Order.boxName, encryptionKey: ordersBoxKey);
|
||||
final walletInfoSource = await Hive.openBox<WalletInfo>(WalletInfo.boxName);
|
||||
final templates = await Hive.openBox<Template>(Template.boxName);
|
||||
final exchangeTemplates = await Hive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
|
||||
final anonpayInvoiceInfo = await Hive.openBox<AnonpayInvoiceInfo>(AnonpayInvoiceInfo.boxName);
|
||||
Box<UnspentCoinsInfo>? unspentCoinsInfoSource;
|
||||
|
||||
if (!isMoneroOnly) {
|
||||
unspentCoinsInfoSource = await Hive.openBox<UnspentCoinsInfo>(UnspentCoinsInfo.boxName);
|
||||
}
|
||||
|
||||
await initialSetup(
|
||||
sharedPreferences: await SharedPreferences.getInstance(),
|
||||
nodes: nodes,
|
||||
walletInfoSource: walletInfoSource,
|
||||
contactSource: contacts,
|
||||
tradesSource: trades,
|
||||
ordersSource: orders,
|
||||
unspentCoinsInfoSource: unspentCoinsInfoSource,
|
||||
// fiatConvertationService: fiatConvertationService,
|
||||
templates: templates,
|
||||
exchangeTemplates: exchangeTemplates,
|
||||
transactionDescriptions: transactionDescriptions,
|
||||
secureStorage: secureStorage,
|
||||
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
||||
initialMigrationVersion: 21);
|
||||
}
|
||||
|
||||
Future<void> initialSetup(
|
||||
{required SharedPreferences sharedPreferences,
|
||||
required Box<Node> nodes,
|
||||
|
|
|
@ -20,6 +20,7 @@ import 'package:cake_wallet/src/screens/dashboard/desktop_widgets/desktop_dashbo
|
|||
import 'package:cake_wallet/src/screens/dashboard/widgets/transactions_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/desktop_settings/desktop_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/display_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/manage_nodes_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/other_settings_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/privacy_page.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/security_backup_page.dart';
|
||||
|
@ -569,6 +570,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
|||
),
|
||||
);
|
||||
|
||||
case Routes.manageNodes:
|
||||
return MaterialPageRoute<void>(builder: (_) => getIt.get<ManageNodesPage>());
|
||||
|
||||
default:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => Scaffold(
|
||||
|
|
|
@ -91,4 +91,5 @@ class Routes {
|
|||
static const modify2FAPage = '/modify_2fa_page';
|
||||
static const homeSettings = '/home_settings';
|
||||
static const editToken = '/edit_token';
|
||||
static const manageNodes = '/manage_nodes';
|
||||
}
|
||||
|
|
|
@ -298,24 +298,7 @@ class _DashboardPageView extends BasePage {
|
|||
}
|
||||
});
|
||||
|
||||
final sharedPrefs = await SharedPreferences.getInstance();
|
||||
final currentAppVersion =
|
||||
VersionComparator.getExtendedVersionNumber(dashboardViewModel.settingsStore.appVersion);
|
||||
final lastSeenAppVersion = sharedPrefs.getInt(PreferencesKey.lastSeenAppVersion);
|
||||
final isNewInstall = sharedPrefs.getBool(PreferencesKey.isNewInstall);
|
||||
|
||||
if (currentAppVersion != lastSeenAppVersion && !isNewInstall!) {
|
||||
await Future<void>.delayed(Duration(seconds: 1));
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return ReleaseNotesScreen(
|
||||
title: 'Version ${dashboardViewModel.settingsStore.appVersion}');
|
||||
});
|
||||
sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
|
||||
} else if (isNewInstall!) {
|
||||
sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
|
||||
}
|
||||
_showReleaseNotesPopup(context);
|
||||
|
||||
var needToPresentYat = false;
|
||||
var isInactive = false;
|
||||
|
@ -341,4 +324,27 @@ class _DashboardPageView extends BasePage {
|
|||
needToPresentYat = true;
|
||||
});
|
||||
}
|
||||
|
||||
void _showReleaseNotesPopup(BuildContext context) async {
|
||||
final sharedPrefs = await SharedPreferences.getInstance();
|
||||
final currentAppVersion =
|
||||
VersionComparator.getExtendedVersionNumber(dashboardViewModel.settingsStore.appVersion);
|
||||
final lastSeenAppVersion = sharedPrefs.getInt(PreferencesKey.lastSeenAppVersion);
|
||||
final isNewInstall = sharedPrefs.getBool(PreferencesKey.isNewInstall);
|
||||
|
||||
if (currentAppVersion != lastSeenAppVersion && !isNewInstall!) {
|
||||
Future<void>.delayed(Duration(seconds: 1), () {
|
||||
showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return ReleaseNotesScreen(
|
||||
title: 'Version ${dashboardViewModel.settingsStore.appVersion}');
|
||||
});
|
||||
});
|
||||
|
||||
sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
|
||||
} else if (isNewInstall!) {
|
||||
sharedPrefs.setInt(PreferencesKey.lastSeenAppVersion, currentAppVersion);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,25 +1,25 @@
|
|||
import 'package:cake_wallet/src/screens/settings/widgets/settings_cell_with_arrow.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_picker_cell.dart';
|
||||
import 'package:cake_wallet/src/screens/settings/widgets/settings_switcher_cell.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/dashboard_view_model.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/widgets/node_list_row.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class ConnectionSyncPage extends BasePage {
|
||||
ConnectionSyncPage(this.nodeListViewModel, this.dashboardViewModel);
|
||||
ConnectionSyncPage(this.dashboardViewModel);
|
||||
|
||||
@override
|
||||
String get title => S.current.connection_sync;
|
||||
|
||||
final NodeListViewModel nodeListViewModel;
|
||||
final DashboardViewModel dashboardViewModel;
|
||||
|
||||
@override
|
||||
|
@ -33,72 +33,39 @@ class ConnectionSyncPage extends BasePage {
|
|||
title: S.current.reconnect,
|
||||
handler: (context) => _presentReconnectAlert(context),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
if (dashboardViewModel.hasRescan)
|
||||
const StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
if (dashboardViewModel.hasRescan) ...[
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.rescan,
|
||||
handler: (context) => Navigator.of(context).pushNamed(Routes.rescan),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
Semantics(
|
||||
button: true,
|
||||
child: NodeHeaderListRow(
|
||||
title: S.of(context).add_new_node,
|
||||
onTap: (_) async =>
|
||||
await Navigator.of(context).pushNamed(Routes.newNode),
|
||||
),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
SizedBox(height: 100),
|
||||
Observer(
|
||||
builder: (BuildContext context) {
|
||||
return Flexible(
|
||||
child: SectionStandardList(
|
||||
sectionCount: 1,
|
||||
context: context,
|
||||
dividerPadding: EdgeInsets.symmetric(horizontal: 24),
|
||||
itemCounter: (int sectionIndex) {
|
||||
return nodeListViewModel.nodes.length;
|
||||
},
|
||||
itemBuilder: (_, sectionIndex, index) {
|
||||
final node = nodeListViewModel.nodes[index];
|
||||
final isSelected = node.keyIndex == nodeListViewModel.currentNode.keyIndex;
|
||||
final nodeListRow = NodeListRow(
|
||||
title: node.uriRaw,
|
||||
node: node,
|
||||
isSelected: isSelected,
|
||||
onTap: (_) async {
|
||||
if (isSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle:
|
||||
S.of(context).change_current_node_title,
|
||||
alertContent: nodeListViewModel
|
||||
.getAlertContent(node.uriRaw),
|
||||
leftButtonText: S.of(context).cancel,
|
||||
rightButtonText: S.of(context).change,
|
||||
actionLeftButton: () =>
|
||||
Navigator.of(context).pop(),
|
||||
actionRightButton: () async {
|
||||
await nodeListViewModel.setAsCurrent(node);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
return nodeListRow;
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
const StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
if (DeviceInfo.instance.isMobile) ...[
|
||||
Observer(builder: (context) {
|
||||
return SettingsPickerCell<SyncMode>(
|
||||
title: S.current.background_sync_mode,
|
||||
items: SyncMode.all,
|
||||
displayItem: (SyncMode syncMode) => syncMode.name,
|
||||
selectedItem: dashboardViewModel.syncMode,
|
||||
onItemSelected: dashboardViewModel.setSyncMode,
|
||||
);
|
||||
}),
|
||||
const StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
Observer(builder: (context) {
|
||||
return SettingsSwitcherCell(
|
||||
title: S.current.sync_all_wallets,
|
||||
value: dashboardViewModel.syncAll,
|
||||
onValueChange: (_, bool value) => dashboardViewModel.setSyncAll(value),
|
||||
);
|
||||
}),
|
||||
const StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
],
|
||||
],
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.manage_nodes,
|
||||
handler: (context) => Navigator.of(context).pushNamed(Routes.manageNodes),
|
||||
),
|
||||
const StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
|
85
lib/src/screens/settings/manage_nodes_page.dart
Normal file
85
lib/src/screens/settings/manage_nodes_page.dart
Normal file
|
@ -0,0 +1,85 @@
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/screens/nodes/widgets/node_list_row.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:cake_wallet/utils/show_pop_up.dart';
|
||||
import 'package:cake_wallet/view_model/node_list/node_list_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
||||
class ManageNodesPage extends BasePage {
|
||||
ManageNodesPage(this.nodeListViewModel);
|
||||
|
||||
final NodeListViewModel nodeListViewModel;
|
||||
|
||||
@override
|
||||
String get title => S.current.manage_nodes;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
Semantics(
|
||||
button: true,
|
||||
child: NodeHeaderListRow(
|
||||
title: S.of(context).add_new_node,
|
||||
onTap: (_) async => await Navigator.of(context).pushNamed(Routes.newNode),
|
||||
),
|
||||
),
|
||||
const StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
SizedBox(height: 20),
|
||||
Observer(
|
||||
builder: (BuildContext context) {
|
||||
return Flexible(
|
||||
child: SectionStandardList(
|
||||
sectionCount: 1,
|
||||
context: context,
|
||||
dividerPadding: EdgeInsets.symmetric(horizontal: 24),
|
||||
itemCounter: (int sectionIndex) {
|
||||
return nodeListViewModel.nodes.length;
|
||||
},
|
||||
itemBuilder: (_, sectionIndex, index) {
|
||||
final node = nodeListViewModel.nodes[index];
|
||||
final isSelected = node.keyIndex == nodeListViewModel.currentNode.keyIndex;
|
||||
final nodeListRow = NodeListRow(
|
||||
title: node.uriRaw,
|
||||
node: node,
|
||||
isSelected: isSelected,
|
||||
onTap: (_) async {
|
||||
if (isSelected) {
|
||||
return;
|
||||
}
|
||||
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).change_current_node_title,
|
||||
alertContent: nodeListViewModel.getAlertContent(node.uriRaw),
|
||||
leftButtonText: S.of(context).cancel,
|
||||
rightButtonText: S.of(context).change,
|
||||
actionLeftButton: () => Navigator.of(context).pop(),
|
||||
actionRightButton: () async {
|
||||
await nodeListViewModel.setAsCurrent(node);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
|
||||
return nodeListRow;
|
||||
},
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -20,33 +20,38 @@ class OtherSettingsPage extends BasePage {
|
|||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
return Observer(builder: (_) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(children: [
|
||||
SettingsPickerCell(
|
||||
title: S.current.settings_fee_priority,
|
||||
items: priorityForWalletType(_otherSettingsViewModel.walletType),
|
||||
displayItem: _otherSettingsViewModel.getDisplayPriority,
|
||||
selectedItem: _otherSettingsViewModel.transactionPriority,
|
||||
onItemSelected: _otherSettingsViewModel.onDisplayPrioritySelected,
|
||||
return Observer(
|
||||
builder: (_) {
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: Column(
|
||||
children: [
|
||||
SettingsPickerCell(
|
||||
title: S.current.settings_fee_priority,
|
||||
items: priorityForWalletType(_otherSettingsViewModel.walletType),
|
||||
displayItem: _otherSettingsViewModel.getDisplayPriority,
|
||||
selectedItem: _otherSettingsViewModel.transactionPriority,
|
||||
onItemSelected: _otherSettingsViewModel.onDisplayPrioritySelected,
|
||||
),
|
||||
if (_otherSettingsViewModel.changeRepresentativeEnabled)
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.change_rep,
|
||||
handler: (BuildContext context) =>
|
||||
Navigator.of(context).pushNamed(Routes.changeRep),
|
||||
),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.settings_terms_and_conditions,
|
||||
handler: (BuildContext context) =>
|
||||
Navigator.of(context).pushNamed(Routes.readDisclaimer),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
Spacer(),
|
||||
SettingsVersionCell(
|
||||
title: S.of(context).version(_otherSettingsViewModel.currentVersion)),
|
||||
],
|
||||
),
|
||||
if (_otherSettingsViewModel.changeRepresentativeEnabled)
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.change_rep,
|
||||
handler: (BuildContext context) =>
|
||||
Navigator.of(context).pushNamed(Routes.changeRep),
|
||||
),
|
||||
SettingsCellWithArrow(
|
||||
title: S.current.settings_terms_and_conditions,
|
||||
handler: (BuildContext context) =>
|
||||
Navigator.of(context).pushNamed(Routes.readDisclaimer),
|
||||
),
|
||||
StandardListSeparator(padding: EdgeInsets.symmetric(horizontal: 24)),
|
||||
Spacer(),
|
||||
SettingsVersionCell(title: S.of(context).version(_otherSettingsViewModel.currentVersion))
|
||||
]),
|
||||
);
|
||||
});
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ class SectionHeaderListRow extends StatelessWidget {
|
|||
|
||||
class StandardListSeparator extends StatelessWidget {
|
||||
|
||||
StandardListSeparator({this.padding, this.height = 1});
|
||||
const StandardListSeparator({this.padding, this.height = 1});
|
||||
|
||||
final EdgeInsets? padding;
|
||||
final double height;
|
||||
|
|
|
@ -2,10 +2,12 @@ import 'dart:io';
|
|||
|
||||
import 'package:cake_wallet/bitcoin/bitcoin.dart';
|
||||
import 'package:cake_wallet/entities/cake_2fa_preset_options.dart';
|
||||
import 'package:cake_wallet/entities/background_tasks.dart';
|
||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/pin_code_required_duration.dart';
|
||||
import 'package:cake_wallet/entities/preferences_key.dart';
|
||||
import 'package:cake_wallet/entities/sort_balance_types.dart';
|
||||
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/ethereum/ethereum.dart';
|
||||
import 'package:cw_core/transaction_priority.dart';
|
||||
|
@ -34,7 +36,8 @@ class SettingsStore = SettingsStoreBase with _$SettingsStore;
|
|||
|
||||
abstract class SettingsStoreBase with Store {
|
||||
SettingsStoreBase(
|
||||
{required SharedPreferences sharedPreferences,
|
||||
{required BackgroundTasks backgroundTasks,
|
||||
required SharedPreferences sharedPreferences,
|
||||
required bool initialShouldShowMarketPlaceInDashboard,
|
||||
required FiatCurrency initialFiatCurrency,
|
||||
required BalanceDisplayMode initialBalanceDisplayMode,
|
||||
|
@ -51,6 +54,8 @@ abstract class SettingsStoreBase with Store {
|
|||
required ThemeBase initialTheme,
|
||||
required int initialPinLength,
|
||||
required String initialLanguageCode,
|
||||
required SyncMode initialSyncMode,
|
||||
required bool initialSyncAll,
|
||||
// required String initialCurrentLocale,
|
||||
required this.appVersion,
|
||||
required this.deviceName,
|
||||
|
@ -78,6 +83,7 @@ abstract class SettingsStoreBase with Store {
|
|||
TransactionPriority? initialEthereumTransactionPriority})
|
||||
: nodes = ObservableMap<WalletType, Node>.of(nodes),
|
||||
_sharedPreferences = sharedPreferences,
|
||||
_backgroundTasks = backgroundTasks,
|
||||
fiatCurrency = initialFiatCurrency,
|
||||
balanceDisplayMode = initialBalanceDisplayMode,
|
||||
shouldSaveRecipientAddress = initialSaveRecipientAddress,
|
||||
|
@ -107,6 +113,8 @@ abstract class SettingsStoreBase with Store {
|
|||
initialShouldRequireTOTP2FAForCreatingNewWallets,
|
||||
shouldRequireTOTP2FAForAllSecurityAndBackupSettings =
|
||||
initialShouldRequireTOTP2FAForAllSecurityAndBackupSettings,
|
||||
currentSyncMode = initialSyncMode,
|
||||
currentSyncAll = initialSyncAll,
|
||||
priority = ObservableMap<WalletType, TransactionPriority>() {
|
||||
//this.nodes = ObservableMap<WalletType, Node>.of(nodes);
|
||||
|
||||
|
@ -287,6 +295,18 @@ abstract class SettingsStoreBase with Store {
|
|||
(BalanceDisplayMode mode) => sharedPreferences.setInt(
|
||||
PreferencesKey.currentBalanceDisplayModeKey, mode.serialize()));
|
||||
|
||||
reaction((_) => currentSyncMode, (SyncMode syncMode) {
|
||||
sharedPreferences.setInt(PreferencesKey.syncModeKey, syncMode.type.index);
|
||||
|
||||
_backgroundTasks.registerSyncTask(changeExisting: true);
|
||||
});
|
||||
|
||||
reaction((_) => currentSyncAll, (bool syncAll) {
|
||||
sharedPreferences.setBool(PreferencesKey.syncAllKey, syncAll);
|
||||
|
||||
_backgroundTasks.registerSyncTask(changeExisting: true);
|
||||
});
|
||||
|
||||
reaction(
|
||||
(_) => exchangeStatus,
|
||||
(ExchangeApiMode mode) =>
|
||||
|
@ -422,11 +442,18 @@ abstract class SettingsStoreBase with Store {
|
|||
@observable
|
||||
bool useEtherscan;
|
||||
|
||||
@observable
|
||||
SyncMode currentSyncMode;
|
||||
|
||||
@observable
|
||||
bool currentSyncAll;
|
||||
|
||||
String appVersion;
|
||||
|
||||
String deviceName;
|
||||
|
||||
SharedPreferences _sharedPreferences;
|
||||
final SharedPreferences _sharedPreferences;
|
||||
final BackgroundTasks _backgroundTasks;
|
||||
|
||||
ObservableMap<WalletType, Node> nodes;
|
||||
|
||||
|
@ -455,6 +482,7 @@ abstract class SettingsStoreBase with Store {
|
|||
BalanceDisplayMode initialBalanceDisplayMode = BalanceDisplayMode.availableBalance,
|
||||
ThemeBase? initialTheme}) async {
|
||||
final sharedPreferences = await getIt.getAsync<SharedPreferences>();
|
||||
final backgroundTasks = getIt.get<BackgroundTasks>();
|
||||
final currentFiatCurrency = FiatCurrency.deserialize(
|
||||
raw: sharedPreferences.getString(PreferencesKey.currentFiatCurrencyKey)!);
|
||||
|
||||
|
@ -603,6 +631,11 @@ abstract class SettingsStoreBase with Store {
|
|||
nodes[WalletType.nano] = nanoNode;
|
||||
}
|
||||
|
||||
final savedSyncMode = SyncMode.all.firstWhere((element) {
|
||||
return element.type.index == (sharedPreferences.getInt(PreferencesKey.syncModeKey) ?? 1);
|
||||
});
|
||||
final savedSyncAll = sharedPreferences.getBool(PreferencesKey.syncAllKey) ?? true;
|
||||
|
||||
return SettingsStore(
|
||||
sharedPreferences: sharedPreferences,
|
||||
initialShouldShowMarketPlaceInDashboard: shouldShowMarketPlaceInDashboard,
|
||||
|
@ -647,6 +680,9 @@ abstract class SettingsStoreBase with Store {
|
|||
initialShouldRequireTOTP2FAForAllSecurityAndBackupSettings:
|
||||
shouldRequireTOTP2FAForAllSecurityAndBackupSettings,
|
||||
initialEthereumTransactionPriority: ethereumTransactionPriority,
|
||||
backgroundTasks: backgroundTasks,
|
||||
initialSyncMode: savedSyncMode,
|
||||
initialSyncAll: savedSyncAll,
|
||||
shouldShowYatPopup: shouldShowYatPopup);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
import 'package:cake_wallet/store/anonpay/anonpay_transactions_store.dart';
|
||||
import 'package:cake_wallet/view_model/dashboard/anonpay_transaction_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/settings/sync_mode.dart';
|
||||
import 'package:cake_wallet/wallet_type_utils.dart';
|
||||
import 'package:cw_core/transaction_history.dart';
|
||||
import 'package:cw_core/balance.dart';
|
||||
|
@ -403,4 +404,16 @@ abstract class DashboardViewModelBase with Store {
|
|||
hasBuyAction = !isHaven;
|
||||
hasSellAction = !isHaven;
|
||||
}
|
||||
|
||||
@computed
|
||||
SyncMode get syncMode => settingsStore.currentSyncMode;
|
||||
|
||||
@action
|
||||
void setSyncMode(SyncMode syncMode) => settingsStore.currentSyncMode = syncMode;
|
||||
|
||||
@computed
|
||||
bool get syncAll => settingsStore.currentSyncAll;
|
||||
|
||||
@action
|
||||
void setSyncAll(bool value) => settingsStore.currentSyncAll = value;
|
||||
}
|
||||
|
|
|
@ -1,20 +1,19 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cake_wallet/view_model/settings/settings_list_item.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class ChoicesListItem<ItemType> extends SettingsListItem {
|
||||
ChoicesListItem(
|
||||
{required String title,
|
||||
required this.selectedItem,
|
||||
required this.items,
|
||||
this.displayItem,
|
||||
String Function(ItemType item)? displayItem,
|
||||
void Function(ItemType item)? onItemSelected})
|
||||
: _onItemSelected = onItemSelected,
|
||||
_displayItem = displayItem,
|
||||
super(title);
|
||||
|
||||
final ItemType selectedItem;
|
||||
final List<ItemType> items;
|
||||
final String Function(ItemType item)? displayItem;
|
||||
final String Function(ItemType item)? _displayItem;
|
||||
final void Function(ItemType item)? _onItemSelected;
|
||||
|
||||
void onItemSelected(dynamic item) {
|
||||
|
@ -22,4 +21,11 @@ class ChoicesListItem<ItemType> extends SettingsListItem {
|
|||
_onItemSelected?.call(item);
|
||||
}
|
||||
}
|
||||
|
||||
String displayItem(dynamic item) {
|
||||
if (item is ItemType && _displayItem != null) {
|
||||
return _displayItem!.call(item);
|
||||
}
|
||||
return item.toString();
|
||||
}
|
||||
}
|
||||
|
|
15
lib/view_model/settings/sync_mode.dart
Normal file
15
lib/view_model/settings/sync_mode.dart
Normal file
|
@ -0,0 +1,15 @@
|
|||
enum SyncType { disabled, unobtrusive, aggressive }
|
||||
|
||||
class SyncMode {
|
||||
SyncMode(this.name, this.type, this.frequency);
|
||||
|
||||
final String name;
|
||||
final SyncType type;
|
||||
final Duration frequency;
|
||||
|
||||
static final all = [
|
||||
SyncMode("Disabled", SyncType.disabled, Duration.zero),
|
||||
SyncMode("Unobtrusive", SyncType.unobtrusive, Duration(days: 1)),
|
||||
SyncMode("Aggressive", SyncType.aggressive, Duration(hours: 6)),
|
||||
];
|
||||
}
|
|
@ -1,4 +1,6 @@
|
|||
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/entities/background_tasks.dart';
|
||||
import 'package:cake_wallet/view_model/restore/restore_wallet.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
@ -71,6 +73,7 @@ abstract class WalletCreationVMBase with Store {
|
|||
walletInfo.address = wallet.walletAddresses.address;
|
||||
await _walletInfoSource.add(walletInfo);
|
||||
_appStore.changeCurrentWallet(wallet);
|
||||
getIt.get<BackgroundTasks>().registerSyncTask();
|
||||
_appStore.authenticationStore.allowed();
|
||||
state = ExecutedSuccessfullyState();
|
||||
} catch (e) {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'package:cake_wallet/core/auth_service.dart';
|
||||
import 'package:cake_wallet/core/wallet_loading_service.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
|
@ -58,8 +57,8 @@ abstract class WalletListViewModelBase with Store {
|
|||
name: info.name,
|
||||
type: info.type,
|
||||
key: info.key,
|
||||
isCurrent: info.name == _appStore.wallet!.name &&
|
||||
info.type == _appStore.wallet!.type,
|
||||
isCurrent: info.name == _appStore.wallet?.name &&
|
||||
info.type == _appStore.wallet?.type,
|
||||
isEnabled: availableWalletTypes.contains(info.type),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -110,13 +110,13 @@ SPEC CHECKSUMS:
|
|||
FlutterMacOS: 8f6f14fa908a6fb3fba0cd85dbd81ec4b251fb24
|
||||
in_app_review: a850789fad746e89bce03d4aeee8078b45a53fd0
|
||||
package_info: 6eba2fd8d3371dda2d85c8db6fe97488f24b74b2
|
||||
path_provider_foundation: eaf5b3e458fc0e5fbb9940fb09980e853fe058b8
|
||||
path_provider_foundation: 29f094ae23ebbca9d3d0cec13889cd9060c0e943
|
||||
platform_device_id: 3e414428f45df149bbbfb623e2c0ca27c545b763
|
||||
platform_device_id_macos: f763bb55f088be804d61b96eb4710b8ab6598e94
|
||||
ReachabilitySwift: 985039c6f7b23a1da463388634119492ff86c825
|
||||
share_plus_macos: 853ee48e7dce06b633998ca0735d482dd671ade4
|
||||
shared_preferences_foundation: 5b919d13b803cadd15ed2dc053125c68730e5126
|
||||
url_launcher_macos: 5335912b679c073563f29d89d33d10d459f95451
|
||||
url_launcher_macos: d2691c7dd33ed713bf3544850a623080ec693d95
|
||||
wakelock_macos: bc3f2a9bd8d2e6c89fee1e1822e7ddac3bd004a9
|
||||
|
||||
PODFILE CHECKSUM: 5107934592df7813b33d744aebc8ddc6b5a5445f
|
||||
|
|
|
@ -66,6 +66,7 @@ dependencies:
|
|||
# check unorm_dart for usage and for replace
|
||||
permission_handler: ^10.0.0
|
||||
device_display_brightness: ^0.0.6
|
||||
workmanager: ^0.5.1
|
||||
platform_device_id: ^1.0.1
|
||||
wakelock: ^0.6.2
|
||||
flutter_mailer: ^2.0.2
|
||||
|
|
|
@ -669,5 +669,6 @@
|
|||
"etherscan_history": "Etherscan تاريخ",
|
||||
"template_name": "اسم القالب",
|
||||
"change_rep": "ﺏﻭﺪﻨﻣ ﺮﻴﻴﻐﺗ",
|
||||
"change_rep_message": "؟ﻦﻴﻠﺜﻤﻤﻟﺍ ﺮﻴﻴﻐﺗ ﺪﻳﺮﺗ ﻚﻧﺃ ﺪﻛﺄﺘﻣ ﺖﻧﺃ ﻞﻫ"
|
||||
"change_rep_message": "؟ﻦﻴﻠﺜﻤﻤﻟﺍ ﺮﻴﻴﻐﺗ ﺪﻳﺮﺗ ﻚﻧﺃ ﺪﻛﺄﺘﻣ ﺖﻧﺃ ﻞﻫ",
|
||||
"manage_nodes": "ﺪﻘﻌﻟﺍ ﺓﺭﺍﺩﺇ"
|
||||
}
|
||||
|
|
|
@ -665,5 +665,6 @@
|
|||
"etherscan_history": "История на Etherscan",
|
||||
"template_name": "Име на шаблон",
|
||||
"change_rep": "Смяна на представител",
|
||||
"change_rep_message": "Сигурни ли сте, че искате да смените представителите?"
|
||||
"change_rep_message": "Сигурни ли сте, че искате да смените представителите?",
|
||||
"manage_nodes": "Управление на възли"
|
||||
}
|
||||
|
|
|
@ -662,6 +662,7 @@
|
|||
"balance_page": "Stránka zůstatku",
|
||||
"share": "Podíl",
|
||||
"slidable": "Posuvné",
|
||||
"manage_nodes": "Spravovat uzly",
|
||||
"etherscan_history": "Historie Etherscanu",
|
||||
"template_name": "Název šablony",
|
||||
"change_rep": "Změna zástupce",
|
||||
|
|
|
@ -538,6 +538,8 @@
|
|||
"open_gift_card": "Geschenkkarte öffnen",
|
||||
"contact_support": "Support kontaktieren",
|
||||
"gift_cards_unavailable": "Geschenkkarten können derzeit nur über Monero, Bitcoin und Litecoin erworben werden",
|
||||
"background_sync_mode": "Hintergrundsynchronisierungsmodus",
|
||||
"sync_all_wallets": "Alle Wallets synchronisieren",
|
||||
"introducing_cake_pay": "Einführung von Cake Pay!",
|
||||
"cake_pay_learn_more": "Kaufen und lösen Sie Geschenkkarten sofort in der App ein!\nWischen Sie von links nach rechts, um mehr zu erfahren.",
|
||||
"automatic": "Automatisch",
|
||||
|
@ -668,6 +670,7 @@
|
|||
"balance_page": "Balance-Seite",
|
||||
"share": "Aktie",
|
||||
"slidable": "Verschiebbar",
|
||||
"manage_nodes": "Knoten verwalten",
|
||||
"etherscan_history": "Etherscan-Geschichte",
|
||||
"template_name": "Vorlagenname",
|
||||
"change_rep": "Change-Beauftragter",
|
||||
|
|
|
@ -538,6 +538,8 @@
|
|||
"open_gift_card": "Open Gift Card",
|
||||
"contact_support": "Contact Support",
|
||||
"gift_cards_unavailable": "Gift cards are available for purchase only with Monero, Bitcoin, and Litecoin at this time",
|
||||
"background_sync_mode": "Background sync mode",
|
||||
"sync_all_wallets": "Sync all wallets",
|
||||
"introducing_cake_pay": "Introducing Cake Pay!",
|
||||
"cake_pay_learn_more": "Instantly purchase and redeem gift cards in the app!\nSwipe left to right to learn more.",
|
||||
"automatic": "Automatic",
|
||||
|
@ -668,6 +670,7 @@
|
|||
"balance_page": "Balance Page",
|
||||
"share": "Share",
|
||||
"slidable": "Slidable",
|
||||
"manage_nodes": "Manage nodes",
|
||||
"etherscan_history": "Etherscan history",
|
||||
"template_name": "Template Name",
|
||||
"change_rep": "Change Representative",
|
||||
|
|
|
@ -538,6 +538,8 @@
|
|||
"open_gift_card": "Abrir tarjeta de regalo",
|
||||
"contact_support": "Contactar con Soporte",
|
||||
"gift_cards_unavailable": "Las tarjetas de regalo están disponibles para comprar solo a través de Monero, Bitcoin y Litecoin en este momento",
|
||||
"background_sync_mode": "Modo de sincronización en segundo plano",
|
||||
"sync_all_wallets": "Sincronizar todas las billeteras",
|
||||
"introducing_cake_pay": "¡Presentamos Cake Pay!",
|
||||
"cake_pay_learn_more": "¡Compre y canjee tarjetas de regalo al instante en la aplicación!\nDeslice el dedo de izquierda a derecha para obtener más información.",
|
||||
"automatic": "Automático",
|
||||
|
@ -668,6 +670,7 @@
|
|||
"balance_page": "Página de saldo",
|
||||
"share": "Compartir",
|
||||
"slidable": "deslizable",
|
||||
"manage_nodes": "Administrar nodos",
|
||||
"etherscan_history": "historia de etherscan",
|
||||
"template_name": "Nombre de la plantilla",
|
||||
"change_rep": "Representante de cambio",
|
||||
|
|
|
@ -536,8 +536,10 @@
|
|||
"gift_card_is_generated": "La carte-cadeau est générée",
|
||||
"open_gift_card": "Ouvrir la carte-cadeau",
|
||||
"contact_support": "Contacter l'assistance",
|
||||
"gift_cards": "Cartes-Cadeaux",
|
||||
"gift_cards_unavailable": "Les cartes-cadeaux ne sont disponibles à l'achat que via Monero, Bitcoin et Litecoin pour le moment",
|
||||
"background_sync_mode": "Mode de synchronisation en arrière-plan",
|
||||
"sync_all_wallets": "Synchroniser tous les portefeuilles",
|
||||
"gift_cards": "Cartes-Cadeaux",
|
||||
"introducing_cake_pay": "Présentation de Cake Pay !",
|
||||
"cake_pay_learn_more": "Achetez et utilisez instantanément des cartes-cadeaux dans l'application !\nBalayer de gauche à droite pour en savoir plus.",
|
||||
"automatic": "Automatique",
|
||||
|
@ -668,6 +670,7 @@
|
|||
"balance_page": "Page Solde",
|
||||
"share": "Partager",
|
||||
"slidable": "Glissable",
|
||||
"manage_nodes": "Gérer les nœuds",
|
||||
"etherscan_history": "Historique d'Etherscan",
|
||||
"template_name": "Nom du modèle",
|
||||
"change_rep": "Changer de représentant",
|
||||
|
|
|
@ -651,5 +651,6 @@
|
|||
"etherscan_history": "Etherscan tarihin kowane zamani",
|
||||
"template_name": "Sunan Samfura",
|
||||
"change_rep": "Canza Wakili",
|
||||
"change_rep_message": "Shin kun tabbata kuna son canza wakilai?"
|
||||
"change_rep_message": "Shin kun tabbata kuna son canza wakilai?",
|
||||
"manage_nodes": "Sarrafa nodes"
|
||||
}
|
||||
|
|
|
@ -538,6 +538,8 @@
|
|||
"open_gift_card": "गिफ्ट कार्ड खोलें",
|
||||
"contact_support": "सहायता से संपर्क करें",
|
||||
"gift_cards_unavailable": "उपहार कार्ड इस समय केवल मोनेरो, बिटकॉइन और लिटकोइन के माध्यम से खरीदने के लिए उपलब्ध हैं",
|
||||
"background_sync_mode": "बैकग्राउंड सिंक मोड",
|
||||
"sync_all_wallets": "सभी वॉलेट सिंक करें",
|
||||
"introducing_cake_pay": "परिचय Cake Pay!",
|
||||
"cake_pay_learn_more": "ऐप में उपहार कार्ड तुरंत खरीदें और रिडीम करें!\nअधिक जानने के लिए बाएं से दाएं स्वाइप करें।",
|
||||
"automatic": "स्वचालित",
|
||||
|
@ -668,6 +670,7 @@
|
|||
"balance_page": "बैलेंस पेज",
|
||||
"share": "शेयर करना",
|
||||
"slidable": "फिसलने लायक",
|
||||
"manage_nodes": "नोड्स प्रबंधित करें",
|
||||
"etherscan_history": "इथरस्कैन इतिहास",
|
||||
"template_name": "टेम्पलेट नाम",
|
||||
"change_rep": "प्रतिनिधि बदलें",
|
||||
|
|
|
@ -538,6 +538,8 @@
|
|||
"open_gift_card": "Otvori darovnu karticu",
|
||||
"contact_support": "Kontaktirajte podršku",
|
||||
"gift_cards_unavailable": "Poklon kartice trenutno su dostupne za kupnju samo putem Monera, Bitcoina i Litecoina",
|
||||
"background_sync_mode": "Sinkronizacija u pozadini",
|
||||
"sync_all_wallets": "Sinkronizirajte sve novčanike",
|
||||
"introducing_cake_pay": "Predstavljamo Cake Pay!",
|
||||
"cake_pay_learn_more": "Azonnal vásárolhat és válthat be ajándékutalványokat az alkalmazásban!\nTovábbi információért csúsztassa balról jobbra az ujját.",
|
||||
"automatic": "Automatski",
|
||||
|
@ -668,6 +670,7 @@
|
|||
"balance_page": "Stranica sa stanjem",
|
||||
"share": "Udio",
|
||||
"slidable": "Klizna",
|
||||
"manage_nodes": "Upravljanje čvorovima",
|
||||
"etherscan_history": "Etherscan povijest",
|
||||
"template_name": "Naziv predloška",
|
||||
"change_rep": "Promjena predstavnika",
|
||||
|
|
|
@ -658,6 +658,7 @@
|
|||
"balance_page": "Halaman Saldo",
|
||||
"share": "Membagikan",
|
||||
"slidable": "Dapat digeser",
|
||||
"manage_nodes": "Kelola node",
|
||||
"etherscan_history": "Sejarah Etherscan",
|
||||
"template_name": "Nama Templat",
|
||||
"change_rep": "Ubah Perwakilan",
|
||||
|
|
|
@ -538,6 +538,8 @@
|
|||
"open_gift_card": "Apri carta regalo",
|
||||
"contact_support": "Contatta l'assistenza",
|
||||
"gift_cards_unavailable": "Le carte regalo sono disponibili per l'acquisto solo tramite Monero, Bitcoin e Litecoin in questo momento",
|
||||
"background_sync_mode": "Modalità di sincronizzazione in background",
|
||||
"sync_all_wallets": "Sincronizza tutti i portafogli",
|
||||
"introducing_cake_pay": "Presentazione di Cake Pay!",
|
||||
"cake_pay_learn_more": "Acquista e riscatta istantaneamente carte regalo nell'app!\nScorri da sinistra a destra per saperne di più.",
|
||||
"automatic": "Automatico",
|
||||
|
@ -668,6 +670,7 @@
|
|||
"balance_page": "Pagina di equilibrio",
|
||||
"share": "Condividere",
|
||||
"slidable": "Scorrevole",
|
||||
"manage_nodes": "Gestisci i nodi",
|
||||
"etherscan_history": "Storia Etherscan",
|
||||
"template_name": "Nome modello",
|
||||
"change_rep": "Cambia rappresentante",
|
||||
|
|
|
@ -538,6 +538,8 @@
|
|||
"open_gift_card": "オープンギフトカード",
|
||||
"contact_support": "サポートに連絡する",
|
||||
"gift_cards_unavailable": "現時点では、ギフトカードはMonero、Bitcoin、Litecoinからのみ購入できます。",
|
||||
"background_sync_mode": "バックグラウンド同期モード",
|
||||
"sync_all_wallets": "すべてのウォレットを同期",
|
||||
"introducing_cake_pay": "序章Cake Pay!",
|
||||
"cake_pay_learn_more": "アプリですぐにギフトカードを購入して引き換えましょう!\n左から右にスワイプして詳細をご覧ください。",
|
||||
"automatic": "自動",
|
||||
|
@ -668,6 +670,7 @@
|
|||
"balance_page": "残高ページ",
|
||||
"share": "共有",
|
||||
"slidable": "スライド可能",
|
||||
"manage_nodes": "ノードの管理",
|
||||
"etherscan_history": "イーサスキャンの歴史",
|
||||
"template_name": "テンプレート名",
|
||||
"change_rep": "代表者の変更",
|
||||
|
|
|
@ -539,6 +539,8 @@
|
|||
"open_gift_card": "기프트 카드 열기",
|
||||
"contact_support": "지원팀에 문의",
|
||||
"gift_cards_unavailable": "기프트 카드는 현재 Monero, Bitcoin 및 Litecoin을 통해서만 구매할 수 있습니다.",
|
||||
"background_sync_mode": "백그라운드 동기화 모드",
|
||||
"sync_all_wallets": "모든 지갑 동기화",
|
||||
"introducing_cake_pay": "소개 Cake Pay!",
|
||||
"cake_pay_learn_more": "앱에서 즉시 기프트 카드를 구매하고 사용하세요!\n자세히 알아보려면 왼쪽에서 오른쪽으로 스와이프하세요.",
|
||||
"automatic": "자동적 인",
|
||||
|
@ -669,6 +671,7 @@
|
|||
"balance_page": "잔액 페이지",
|
||||
"share": "공유하다",
|
||||
"slidable": "슬라이딩 가능",
|
||||
"manage_nodes": "노드 관리",
|
||||
"etherscan_history": "이더스캔 역사",
|
||||
"template_name": "템플릿 이름",
|
||||
"change_rep": "대표자 변경",
|
||||
|
|
|
@ -668,6 +668,7 @@
|
|||
"balance_page": "လက်ကျန်စာမျက်နှာ",
|
||||
"share": "မျှဝေပါ။",
|
||||
"slidable": "လျှောချနိုင်သည်။",
|
||||
"manage_nodes": "ဆုံမှတ်များကို စီမံပါ။",
|
||||
"etherscan_history": "Etherscan သမိုင်း",
|
||||
"template_name": "နမူနာပုံစံ",
|
||||
"change_rep": "ကိုယ်စားလှယ်ပြောင်းပါ။",
|
||||
|
|
|
@ -538,6 +538,8 @@
|
|||
"open_gift_card": "Geschenkkaart openen",
|
||||
"contact_support": "Contact opnemen met ondersteuning",
|
||||
"gift_cards_unavailable": "Cadeaubonnen kunnen momenteel alleen worden gekocht via Monero, Bitcoin en Litecoin",
|
||||
"background_sync_mode": "Achtergrondsynchronisatiemodus",
|
||||
"sync_all_wallets": "Alle portemonnees synchroniseren",
|
||||
"introducing_cake_pay": "Introductie van Cake Pay!",
|
||||
"cake_pay_learn_more": "Koop en wissel cadeaubonnen direct in de app in!\nSwipe van links naar rechts voor meer informatie.",
|
||||
"automatic": "automatisch",
|
||||
|
@ -668,6 +670,7 @@
|
|||
"balance_page": "Saldo pagina",
|
||||
"share": "Deel",
|
||||
"slidable": "Verschuifbaar",
|
||||
"manage_nodes": "Beheer knooppunten",
|
||||
"etherscan_history": "Etherscan-geschiedenis",
|
||||
"template_name": "Sjabloonnaam",
|
||||
"change_rep": "Vertegenwoordiger wijzigen",
|
||||
|
|
|
@ -538,6 +538,8 @@
|
|||
"open_gift_card": "Otwórz kartę podarunkową",
|
||||
"contact_support": "Skontaktuj się z pomocą techniczną",
|
||||
"gift_cards_unavailable": "Karty podarunkowe można obecnie kupić tylko za pośrednictwem Monero, Bitcoin i Litecoin",
|
||||
"background_sync_mode": "Tryb synchronizacji w tle",
|
||||
"sync_all_wallets": "Synchronizuj wszystkie portfele",
|
||||
"introducing_cake_pay": "Przedstawiamy Cake Pay!",
|
||||
"cake_pay_learn_more": "Kupuj i wykorzystuj karty podarunkowe od razu w aplikacji!\nPrzesuń od lewej do prawej, aby dowiedzieć się więcej.",
|
||||
"automatic": "Automatyczny",
|
||||
|
@ -668,6 +670,7 @@
|
|||
"balance_page": "Strona salda",
|
||||
"share": "Udział",
|
||||
"slidable": "Przesuwne",
|
||||
"manage_nodes": "Zarządzaj węzłami",
|
||||
"etherscan_history": "Historia Etherscanu",
|
||||
"template_name": "Nazwa szablonu",
|
||||
"change_rep": "Zmień przedstawiciela",
|
||||
|
|
|
@ -537,6 +537,8 @@
|
|||
"open_gift_card": "Abrir vale-presente",
|
||||
"contact_support": "Contatar Suporte",
|
||||
"gift_cards_unavailable": "Os cartões-presente estão disponíveis para compra apenas através do Monero, Bitcoin e Litecoin no momento",
|
||||
"background_sync_mode": "Modo de sincronização em segundo plano",
|
||||
"sync_all_wallets": "Sincronize todas as carteiras",
|
||||
"introducing_cake_pay": "Apresentando o Cake Pay!",
|
||||
"cake_pay_learn_more": "Compre e resgate vales-presente instantaneamente no app!\nDeslize da esquerda para a direita para saber mais.",
|
||||
"automatic": "Automático",
|
||||
|
@ -667,6 +669,7 @@
|
|||
"balance_page": "Página de saldo",
|
||||
"share": "Compartilhar",
|
||||
"slidable": "Deslizável",
|
||||
"manage_nodes": "Gerenciar nós",
|
||||
"etherscan_history": "história Etherscan",
|
||||
"template_name": "Nome do modelo",
|
||||
"change_rep": "Alterar representante",
|
||||
|
|
|
@ -538,6 +538,8 @@
|
|||
"open_gift_card": "Открыть подарочную карту",
|
||||
"contact_support": "Связаться со службой поддержки",
|
||||
"gift_cards_unavailable": "В настоящее время подарочные карты можно приобрести только через Monero, Bitcoin и Litecoin.",
|
||||
"background_sync_mode": "Режим фоновой синхронизации",
|
||||
"sync_all_wallets": "Синхронизировать все кошельки",
|
||||
"introducing_cake_pay": "Представляем Cake Pay!",
|
||||
"cake_pay_learn_more": "Мгновенно покупайте и используйте подарочные карты в приложении!\nПроведите по экрану слева направо, чтобы узнать больше.",
|
||||
"automatic": "автоматический",
|
||||
|
@ -668,6 +670,7 @@
|
|||
"balance_page": "Страница баланса",
|
||||
"share": "Делиться",
|
||||
"slidable": "Скользящий",
|
||||
"manage_nodes": "Управление узлами",
|
||||
"etherscan_history": "История Эфириума",
|
||||
"template_name": "Имя Шаблона",
|
||||
"change_rep": "Изменить представителя",
|
||||
|
|
|
@ -668,6 +668,7 @@
|
|||
"balance_page": "หน้ายอดคงเหลือ",
|
||||
"share": "แบ่งปัน",
|
||||
"slidable": "เลื่อนได้",
|
||||
"manage_nodes": "จัดการโหนด",
|
||||
"etherscan_history": "ประวัติอีเธอร์สแกน",
|
||||
"template_name": "ชื่อแม่แบบ",
|
||||
"change_rep": "เปลี่ยนผู้แทน",
|
||||
|
|
|
@ -669,6 +669,7 @@
|
|||
"balance_page": "Bakiye Sayfası",
|
||||
"share": "Paylaşmak",
|
||||
"slidable": "kaydırılabilir",
|
||||
"manage_nodes": "Düğümleri yönet",
|
||||
"etherscan_history": "Etherscan geçmişi",
|
||||
"template_name": "şablon adı",
|
||||
"change_rep": "Temsilciyi Değiştir",
|
||||
|
|
|
@ -538,6 +538,8 @@
|
|||
"open_gift_card": "Відкрити подарункову картку",
|
||||
"contact_support": "Звернутися до служби підтримки",
|
||||
"gift_cards_unavailable": "Наразі подарункові картки можна придбати лише через Monero, Bitcoin і Litecoin",
|
||||
"background_sync_mode": "Фоновий режим синхронізації",
|
||||
"sync_all_wallets": "Синхронізувати всі гаманці",
|
||||
"introducing_cake_pay": "Представляємо Cake Pay!",
|
||||
"cake_pay_learn_more": "Миттєво купуйте та активуйте подарункові картки в додатку!\nПроведіть пальцем зліва направо, щоб дізнатися більше.",
|
||||
"automatic": "Автоматичний",
|
||||
|
@ -668,6 +670,7 @@
|
|||
"balance_page": "Сторінка балансу",
|
||||
"share": "Поділіться",
|
||||
"slidable": "Розсувний",
|
||||
"manage_nodes": "Керуйте вузлами",
|
||||
"etherscan_history": "Історія Etherscan",
|
||||
"template_name": "Назва шаблону",
|
||||
"change_rep": "Зміна представника",
|
||||
|
|
|
@ -662,6 +662,7 @@
|
|||
"balance_page": "بیلنس صفحہ",
|
||||
"share": "بانٹیں",
|
||||
"slidable": "سلائیڈ ایبل",
|
||||
"manage_nodes": "۔ﮟﯾﺮﮐ ﻢﻈﻧ ﺎﮐ ﺱﮈﻮﻧ",
|
||||
"etherscan_history": "ﺦﯾﺭﺎﺗ ﯽﮐ ﻦﯿﮑﺳﺍ ﺮﮭﺘﯾﺍ",
|
||||
"template_name": "ٹیمپلیٹ کا نام",
|
||||
"change_rep": "۔ﮟﯾﺮﮐ ﻞﯾﺪﺒﺗ ﮦﺪﻨﺋﺎﻤﻧ",
|
||||
|
|
|
@ -664,6 +664,7 @@
|
|||
"balance_page": "Oju-iwe iwọntunwọnsi",
|
||||
"share": "Pinpin",
|
||||
"slidable": "Slidable",
|
||||
"manage_nodes": "Ṣakoso awọn apa",
|
||||
"etherscan_history": "Etherscan itan",
|
||||
"template_name": "Orukọ Awoṣe",
|
||||
"change_rep": "Yi Aṣoju",
|
||||
|
|
|
@ -537,6 +537,8 @@
|
|||
"open_gift_card": "打开礼品卡",
|
||||
"contact_support": "联系支持",
|
||||
"gift_cards_unavailable": "目前只能通过门罗币、比特币和莱特币购买礼品卡",
|
||||
"background_sync_mode": "后台同步模式",
|
||||
"sync_all_wallets": "同步所有钱包",
|
||||
"introducing_cake_pay": "介绍 Cake Pay!",
|
||||
"cake_pay_learn_more": "立即在应用中购买和兑换礼品卡!\n从左向右滑动以了解详情。",
|
||||
"automatic": "自动的",
|
||||
|
@ -667,6 +669,7 @@
|
|||
"balance_page": "余额页",
|
||||
"share": "分享",
|
||||
"slidable": "可滑动",
|
||||
"manage_nodes": "管理节点",
|
||||
"etherscan_history": "以太扫描历史",
|
||||
"template_name": "模板名称",
|
||||
"change_rep": "变革代表",
|
||||
|
|
|
@ -14,14 +14,14 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
|
|||
APP_ANDROID_TYPE=$1
|
||||
|
||||
MONERO_COM_NAME="Monero.com"
|
||||
MONERO_COM_VERSION="1.4.0"
|
||||
MONERO_COM_BUILD_NUMBER=52
|
||||
MONERO_COM_VERSION="1.5.0"
|
||||
MONERO_COM_BUILD_NUMBER=54
|
||||
MONERO_COM_BUNDLE_ID="com.monero.app"
|
||||
MONERO_COM_PACKAGE="com.monero.app"
|
||||
|
||||
CAKEWALLET_NAME="Cake Wallet"
|
||||
CAKEWALLET_VERSION="4.7.0"
|
||||
CAKEWALLET_BUILD_NUMBER=162
|
||||
CAKEWALLET_VERSION="4.8.0"
|
||||
CAKEWALLET_BUILD_NUMBER=167
|
||||
CAKEWALLET_BUNDLE_ID="com.cakewallet.cake_wallet"
|
||||
CAKEWALLET_PACKAGE="com.cakewallet.cake_wallet"
|
||||
|
||||
|
|
|
@ -13,13 +13,13 @@ TYPES=($MONERO_COM $CAKEWALLET $HAVEN)
|
|||
APP_IOS_TYPE=$1
|
||||
|
||||
MONERO_COM_NAME="Monero.com"
|
||||
MONERO_COM_VERSION="1.4.0"
|
||||
MONERO_COM_BUILD_NUMBER=50
|
||||
MONERO_COM_VERSION="1.5.0"
|
||||
MONERO_COM_BUILD_NUMBER=52
|
||||
MONERO_COM_BUNDLE_ID="com.cakewallet.monero"
|
||||
|
||||
CAKEWALLET_NAME="Cake Wallet"
|
||||
CAKEWALLET_VERSION="4.7.0"
|
||||
CAKEWALLET_BUILD_NUMBER=165
|
||||
CAKEWALLET_VERSION="4.8.0"
|
||||
CAKEWALLET_BUILD_NUMBER=175
|
||||
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
|
||||
|
||||
HAVEN_NAME="Haven"
|
||||
|
|
|
@ -23,7 +23,7 @@ CONFIG_ARGS=""
|
|||
|
||||
case $APP_MACOS_TYPE in
|
||||
$CAKEWALLET)
|
||||
CONFIG_ARGS="--monero --bitcoin";; #--haven
|
||||
CONFIG_ARGS="--monero --bitcoin --ethereum";; #--haven
|
||||
esac
|
||||
|
||||
cp -rf pubspec_description.yaml pubspec.yaml
|
||||
|
|
|
@ -15,8 +15,8 @@ if [ -n "$1" ]; then
|
|||
fi
|
||||
|
||||
CAKEWALLET_NAME="Cake Wallet"
|
||||
CAKEWALLET_VERSION="1.0.7"
|
||||
CAKEWALLET_BUILD_NUMBER=26
|
||||
CAKEWALLET_VERSION="1.1.0"
|
||||
CAKEWALLET_BUILD_NUMBER=28
|
||||
CAKEWALLET_BUNDLE_ID="com.fotolockr.cakewallet"
|
||||
|
||||
if ! [[ " ${TYPES[*]} " =~ " ${APP_MACOS_TYPE} " ]]; then
|
||||
|
|
|
@ -497,8 +497,6 @@ Future<void> generateEthereum(bool hasImplementation) async {
|
|||
|
||||
final outputFile = File(ethereumOutputPath);
|
||||
const ethereumCommonHeaders = """
|
||||
""";
|
||||
const ethereumCWHeaders = """
|
||||
import 'package:cake_wallet/view_model/send/output.dart';
|
||||
import 'package:cw_core/crypto_amount_format.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
|
@ -510,6 +508,9 @@ import 'package:cw_core/wallet_base.dart';
|
|||
import 'package:cw_core/wallet_credentials.dart';
|
||||
import 'package:cw_core/wallet_info.dart';
|
||||
import 'package:cw_core/wallet_service.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
""";
|
||||
const ethereumCWHeaders = """
|
||||
import 'package:cw_ethereum/ethereum_formatter.dart';
|
||||
import 'package:cw_ethereum/ethereum_mnemonics.dart';
|
||||
import 'package:cw_ethereum/ethereum_transaction_credentials.dart';
|
||||
|
@ -518,7 +519,6 @@ import 'package:cw_ethereum/ethereum_wallet.dart';
|
|||
import 'package:cw_ethereum/ethereum_wallet_creation_credentials.dart';
|
||||
import 'package:cw_ethereum/ethereum_wallet_service.dart';
|
||||
import 'package:cw_ethereum/ethereum_transaction_priority.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
""";
|
||||
const ethereumCwPart = "part 'cw_ethereum.dart';";
|
||||
const ethereumContent = """
|
||||
|
|
Loading…
Reference in a new issue