|
@ -1,4 +1,2 @@
|
|||
-
|
||||
uri: electrum2.hodlister.co:50002
|
||||
-
|
||||
uri: bitcoin.electrumx.multicoin.co:50002
|
||||
uri: electrumx.cakewallet.com:50002
|
Before ![]() (image error) Size: 5 KiB After ![]() (image error) Size: 5.2 KiB ![]() ![]() |
Before ![]() (image error) Size: 5.2 KiB After ![]() (image error) Size: 5.4 KiB ![]() ![]() |
Before ![]() (image error) Size: 4.9 KiB After ![]() (image error) Size: 5.1 KiB ![]() ![]() |
Before ![]() (image error) Size: 4.1 KiB After ![]() (image error) Size: 4.3 KiB ![]() ![]() |
Before ![]() (image error) Size: 8.3 KiB After ![]() (image error) Size: 8.8 KiB ![]() ![]() |
Before ![]() (image error) Size: 8.6 KiB After ![]() (image error) Size: 8.9 KiB ![]() ![]() |
Before ![]() (image error) Size: 8.6 KiB After ![]() (image error) Size: 9 KiB ![]() ![]() |
Before ![]() (image error) Size: 6.8 KiB After ![]() (image error) Size: 7.2 KiB ![]() ![]() |
Before ![]() (image error) Size: 2 KiB After ![]() (image error) Size: 2 KiB ![]() ![]() |
Before ![]() (image error) Size: 2.2 KiB After ![]() (image error) Size: 2.2 KiB ![]() ![]() |
Before ![]() (image error) Size: 2 KiB After ![]() (image error) Size: 2.1 KiB ![]() ![]() |
Before ![]() (image error) Size: 1.7 KiB After ![]() (image error) Size: 1.8 KiB ![]() ![]() |
|
@ -7,42 +7,42 @@ packages:
|
|||
name: archive
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.11"
|
||||
version: "2.0.13"
|
||||
args:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: args
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.2"
|
||||
version: "1.6.0"
|
||||
async:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: async
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.4.0"
|
||||
version: "2.4.1"
|
||||
boolean_selector:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: boolean_selector
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.0.5"
|
||||
version: "2.0.0"
|
||||
charcode:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: charcode
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.2"
|
||||
version: "1.1.3"
|
||||
collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: collection
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.14.11"
|
||||
version: "1.14.12"
|
||||
convert:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -56,7 +56,7 @@ packages:
|
|||
name: crypto
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.3"
|
||||
version: "2.1.4"
|
||||
ffi:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
|
@ -80,7 +80,7 @@ packages:
|
|||
name: image
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.1.4"
|
||||
version: "2.1.12"
|
||||
matcher:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -109,13 +109,6 @@ packages:
|
|||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.4.0"
|
||||
pedantic:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: pedantic
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.8.0+1"
|
||||
petitparser:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -136,7 +129,7 @@ packages:
|
|||
name: quiver
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.0.5"
|
||||
version: "2.1.3"
|
||||
sky_engine:
|
||||
dependency: transitive
|
||||
description: flutter
|
||||
|
@ -148,7 +141,7 @@ packages:
|
|||
name: source_span
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.5"
|
||||
version: "1.7.0"
|
||||
stack_trace:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -183,7 +176,7 @@ packages:
|
|||
name: test_api
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.2.11"
|
||||
version: "0.2.15"
|
||||
typed_data:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
@ -204,7 +197,7 @@ packages:
|
|||
name: xml
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.5.0"
|
||||
version: "3.6.1"
|
||||
sdks:
|
||||
dart: ">=2.6.0 <3.0.0"
|
||||
flutter: ">=0.1.4 <2.0.0"
|
||||
|
|
91
ios/Podfile
|
@ -15,59 +15,72 @@ def parse_KV_file(file, separator='=')
|
|||
if !File.exists? file_abs_path
|
||||
return [];
|
||||
end
|
||||
pods_ary = []
|
||||
generated_key_values = {}
|
||||
skip_line_start_symbols = ["#", "/"]
|
||||
File.foreach(file_abs_path) { |line|
|
||||
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
|
||||
plugin = line.split(pattern=separator)
|
||||
if plugin.length == 2
|
||||
podname = plugin[0].strip()
|
||||
path = plugin[1].strip()
|
||||
podpath = File.expand_path("#{path}", file_abs_path)
|
||||
pods_ary.push({:name => podname, :path => podpath});
|
||||
else
|
||||
puts "Invalid plugin specification: #{line}"
|
||||
end
|
||||
}
|
||||
return pods_ary
|
||||
File.foreach(file_abs_path) do |line|
|
||||
next if skip_line_start_symbols.any? { |symbol| line =~ /^\s*#{symbol}/ }
|
||||
plugin = line.split(pattern=separator)
|
||||
if plugin.length == 2
|
||||
podname = plugin[0].strip()
|
||||
path = plugin[1].strip()
|
||||
podpath = File.expand_path("#{path}", file_abs_path)
|
||||
generated_key_values[podname] = podpath
|
||||
else
|
||||
puts "Invalid plugin specification: #{line}"
|
||||
end
|
||||
end
|
||||
generated_key_values
|
||||
end
|
||||
|
||||
target 'Runner' do
|
||||
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
|
||||
# referring to absolute paths on developers' machines.
|
||||
use_frameworks!
|
||||
system('rm -rf .symlinks')
|
||||
system('mkdir -p .symlinks/plugins')
|
||||
use_modular_headers!
|
||||
|
||||
# Flutter Pods
|
||||
generated_xcode_build_settings = parse_KV_file('./Flutter/Generated.xcconfig')
|
||||
if generated_xcode_build_settings.empty?
|
||||
puts "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first."
|
||||
end
|
||||
generated_xcode_build_settings.map { |p|
|
||||
if p[:name] == 'FLUTTER_FRAMEWORK_DIR'
|
||||
symlink = File.join('.symlinks', 'flutter')
|
||||
File.symlink(File.dirname(p[:path]), symlink)
|
||||
pod 'Flutter', :path => File.join(symlink, File.basename(p[:path]))
|
||||
# Flutter Pod
|
||||
|
||||
copied_flutter_dir = File.join(__dir__, 'Flutter')
|
||||
copied_framework_path = File.join(copied_flutter_dir, 'Flutter.framework')
|
||||
copied_podspec_path = File.join(copied_flutter_dir, 'Flutter.podspec')
|
||||
unless File.exist?(copied_framework_path) && File.exist?(copied_podspec_path)
|
||||
# Copy Flutter.framework and Flutter.podspec to Flutter/ to have something to link against if the xcode backend script has not run yet.
|
||||
# That script will copy the correct debug/profile/release version of the framework based on the currently selected Xcode configuration.
|
||||
# CocoaPods will not embed the framework on pod install (before any build phases can generate) if the dylib does not exist.
|
||||
|
||||
generated_xcode_build_settings_path = File.join(copied_flutter_dir, 'Generated.xcconfig')
|
||||
unless File.exist?(generated_xcode_build_settings_path)
|
||||
raise "Generated.xcconfig must exist. If you're running pod install manually, make sure flutter pub get is executed first"
|
||||
end
|
||||
}
|
||||
generated_xcode_build_settings = parse_KV_file(generated_xcode_build_settings_path)
|
||||
cached_framework_dir = generated_xcode_build_settings['FLUTTER_FRAMEWORK_DIR'];
|
||||
|
||||
unless File.exist?(copied_framework_path)
|
||||
FileUtils.cp_r(File.join(cached_framework_dir, 'Flutter.framework'), copied_flutter_dir)
|
||||
end
|
||||
unless File.exist?(copied_podspec_path)
|
||||
FileUtils.cp(File.join(cached_framework_dir, 'Flutter.podspec'), copied_flutter_dir)
|
||||
end
|
||||
end
|
||||
|
||||
# Keep pod path relative so it can be checked into Podfile.lock.
|
||||
pod 'Flutter', :path => 'Flutter'
|
||||
|
||||
# Plugin Pods
|
||||
plugin_pods = parse_KV_file('../.flutter-plugins')
|
||||
plugin_pods.map { |p|
|
||||
symlink = File.join('.symlinks', 'plugins', p[:name])
|
||||
File.symlink(p[:path], symlink)
|
||||
pod p[:name], :path => File.join(symlink, 'ios')
|
||||
}
|
||||
end
|
||||
|
||||
# Prevent Cocoapods from embedding a second Flutter framework and causing an error with the new Xcode build system.
|
||||
install! 'cocoapods', :disable_input_output_paths => true
|
||||
# Prepare symlinks folder. We use symlinks to avoid having Podfile.lock
|
||||
# referring to absolute paths on developers' machines.
|
||||
system('rm -rf .symlinks')
|
||||
system('mkdir -p .symlinks/plugins')
|
||||
plugin_pods = parse_KV_file('../.flutter-plugins')
|
||||
plugin_pods.each do |name, path|
|
||||
symlink = File.join('.symlinks', 'plugins', name)
|
||||
File.symlink(path, symlink)
|
||||
pod name, :path => File.join(symlink, 'ios')
|
||||
end
|
||||
end
|
||||
|
||||
post_install do |installer|
|
||||
installer.pods_project.targets.each do |target|
|
||||
target.build_configurations.each do |config|
|
||||
config.build_settings['SWIFT_VERSION'] = '4.0' # required by simple_permission
|
||||
config.build_settings['ENABLE_BITCODE'] = 'NO'
|
||||
end
|
||||
end
|
||||
|
|
|
@ -65,7 +65,7 @@ DEPENDENCIES:
|
|||
- cw_monero (from `.symlinks/plugins/cw_monero/ios`)
|
||||
- devicelocale (from `.symlinks/plugins/devicelocale/ios`)
|
||||
- esys_flutter_share (from `.symlinks/plugins/esys_flutter_share/ios`)
|
||||
- Flutter (from `.symlinks/flutter/ios`)
|
||||
- Flutter (from `Flutter`)
|
||||
- flutter_plugin_android_lifecycle (from `.symlinks/plugins/flutter_plugin_android_lifecycle/ios`)
|
||||
- flutter_secure_storage (from `.symlinks/plugins/flutter_secure_storage/ios`)
|
||||
- local_auth (from `.symlinks/plugins/local_auth/ios`)
|
||||
|
@ -98,7 +98,7 @@ EXTERNAL SOURCES:
|
|||
esys_flutter_share:
|
||||
:path: ".symlinks/plugins/esys_flutter_share/ios"
|
||||
Flutter:
|
||||
:path: ".symlinks/flutter/ios"
|
||||
:path: Flutter
|
||||
flutter_plugin_android_lifecycle:
|
||||
:path: ".symlinks/plugins/flutter_plugin_android_lifecycle/ios"
|
||||
flutter_secure_storage:
|
||||
|
@ -157,6 +157,6 @@ SPEC CHECKSUMS:
|
|||
url_launcher_macos: fd7894421cd39320dce5f292fc99ea9270b2a313
|
||||
url_launcher_web: e5527357f037c87560776e36436bf2b0288b965c
|
||||
|
||||
PODFILE CHECKSUM: f1916a43bb28badbd408be80e8e4b8652a74e93e
|
||||
PODFILE CHECKSUM: c34e2287a9ccaa606aeceab922830efb9a6ff69a
|
||||
|
||||
COCOAPODS: 1.9.3
|
||||
|
|
|
@ -272,9 +272,40 @@
|
|||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
|
||||
"${PODS_ROOT}/../Flutter/Flutter.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/MTBBarcodeScanner/MTBBarcodeScanner.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/SwiftProtobuf/SwiftProtobuf.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/barcode_scan/barcode_scan.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/cw_monero/cw_monero.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/devicelocale/devicelocale.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/esys_flutter_share/esys_flutter_share.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/flutter_plugin_android_lifecycle/flutter_plugin_android_lifecycle.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/flutter_secure_storage/flutter_secure_storage.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/local_auth/local_auth.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/package_info/package_info.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/share/share.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework",
|
||||
"${BUILT_PRODUCTS_DIR}/url_launcher/url_launcher.framework",
|
||||
);
|
||||
name = "[CP] Embed Pods Frameworks";
|
||||
outputPaths = (
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/Flutter.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/MTBBarcodeScanner.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SwiftProtobuf.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/barcode_scan.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/cw_monero.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/devicelocale.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/esys_flutter_share.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_plugin_android_lifecycle.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/flutter_secure_storage.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/local_auth.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework",
|
||||
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.framework",
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>NSFaceIDUsageDescription</key>
|
||||
<string>Enable Face ID for fast and secure access to wallets and private keys</string>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
|
@ -23,7 +25,7 @@
|
|||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>NSCameraUsageDescription</key>
|
||||
<string>Cake Wallet requires access to your phone’s camera.</string>
|
||||
<string>Used for scan QR code</string>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>LaunchScreen</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
|
|
|
@ -6,6 +6,16 @@ import 'package:cake_wallet/bitcoin/script_hash.dart';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:rxdart/rxdart.dart';
|
||||
|
||||
class UriParseException implements Exception {
|
||||
UriParseException(this.uri);
|
||||
|
||||
final String uri;
|
||||
|
||||
@override
|
||||
String toString() =>
|
||||
'Cannot parse host and port from uri. Invalid uri format. Uri: $uri';
|
||||
}
|
||||
|
||||
String jsonrpcparams(List<Object> params) {
|
||||
final _params = params?.map((val) => '"${val.toString()}"')?.join(',');
|
||||
return '[$_params]';
|
||||
|
@ -40,9 +50,14 @@ class ElectrumClient {
|
|||
Timer _aliveTimer;
|
||||
|
||||
Future<void> connectToUri(String uri) async {
|
||||
final _uri = Uri.parse(uri);
|
||||
final host = _uri.scheme;
|
||||
final port = int.parse(_uri.path);
|
||||
final splittedUri = uri.split(':');
|
||||
|
||||
if (splittedUri.length != 2) {
|
||||
throw UriParseException(uri);
|
||||
}
|
||||
|
||||
final host = splittedUri.first;
|
||||
final port = int.parse(splittedUri.last);
|
||||
await connect(host: host, port: port);
|
||||
}
|
||||
|
||||
|
@ -51,7 +66,8 @@ class ElectrumClient {
|
|||
await socket?.close();
|
||||
} catch (_) {}
|
||||
|
||||
socket = await SecureSocket.connect(host, port, timeout: connectionTimeout);
|
||||
socket = await SecureSocket.connect(host, port,
|
||||
timeout: connectionTimeout, onBadCertificate: (_) => true);
|
||||
_setIsConnected(true);
|
||||
|
||||
socket.listen((Uint8List event) {
|
||||
|
@ -87,7 +103,7 @@ class ElectrumClient {
|
|||
|
||||
Future<void> ping() async {
|
||||
try {
|
||||
await callWithTimeout(method: 'server.ping');
|
||||
// await callWithTimeout(method: 'server.ping');
|
||||
_setIsConnected(true);
|
||||
} on RequestFailedTimeoutException catch (_) {
|
||||
_setIsConnected(false);
|
||||
|
|
|
@ -12,7 +12,7 @@ class ContactService {
|
|||
|
||||
Future add(Contact contact) async {
|
||||
await contactSource.add(contact);
|
||||
contactListStore.contacts.add(contact);
|
||||
// contactListStore.contacts.add(contact);
|
||||
}
|
||||
|
||||
Future update(Contact contact) async {
|
||||
|
|
42
lib/di.dart
|
@ -58,6 +58,7 @@ import 'package:mobx/mobx.dart';
|
|||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restoration_from_seed_vm.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restoration_from_keys_vm.dart';
|
||||
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
|
||||
|
@ -168,6 +169,16 @@ Future setup(
|
|||
type: type, language: language, seed: mnemonic);
|
||||
});
|
||||
|
||||
getIt
|
||||
.registerFactoryParam<WalletRestorationFromKeysVM, List, void>((args, _) {
|
||||
final type = args.first as WalletType;
|
||||
final language = args[1] as String;
|
||||
|
||||
return WalletRestorationFromKeysVM(
|
||||
getIt.get<WalletCreationService>(param1: type), walletInfoSource,
|
||||
type: type, language: language);
|
||||
});
|
||||
|
||||
getIt.registerFactory<WalletAddressListViewModel>(
|
||||
() => WalletAddressListViewModel(wallet: getIt.get<AppStore>().wallet));
|
||||
|
||||
|
@ -193,6 +204,10 @@ Future setup(
|
|||
|
||||
getIt.registerFactory<AuthPage>(
|
||||
() => AuthPage(
|
||||
allowBiometricalAuthentication: getIt
|
||||
.get<AppStore>()
|
||||
.settingsStore
|
||||
.allowBiometricalAuthentication,
|
||||
authViewModel: getIt.get<AuthViewModel>(),
|
||||
onAuthenticationFinished: (isAuthenticated, __) {
|
||||
if (isAuthenticated) {
|
||||
|
@ -204,10 +219,18 @@ Future setup(
|
|||
|
||||
getIt
|
||||
.registerFactoryParam<AuthPage, void Function(bool, AuthPageState), void>(
|
||||
(onAuthFinished, _) => AuthPage(
|
||||
authViewModel: getIt.get<AuthViewModel>(),
|
||||
onAuthenticationFinished: onAuthFinished,
|
||||
closable: false));
|
||||
(onAuthFinished, _) {
|
||||
final allowBiometricalAuthentication =
|
||||
getIt.get<AppStore>().settingsStore.allowBiometricalAuthentication;
|
||||
|
||||
print('allowBiometricalAuthentication $allowBiometricalAuthentication');
|
||||
|
||||
return AuthPage(
|
||||
allowBiometricalAuthentication: allowBiometricalAuthentication,
|
||||
authViewModel: getIt.get<AuthViewModel>(),
|
||||
onAuthenticationFinished: onAuthFinished,
|
||||
closable: false);
|
||||
});
|
||||
|
||||
getIt.registerFactory<DashboardPage>(() => DashboardPage(
|
||||
walletViewModel: getIt.get<DashboardViewModel>(),
|
||||
|
@ -294,14 +317,17 @@ Future setup(
|
|||
|
||||
getIt.registerFactoryParam<ContactViewModel, Contact, void>(
|
||||
(Contact contact, _) => ContactViewModel(
|
||||
getIt.get<ContactService>(), getIt.get<AppStore>().wallet,
|
||||
contactSource, getIt.get<AppStore>().wallet,
|
||||
contact: contact));
|
||||
|
||||
getIt.registerFactory(() => ContactListViewModel(
|
||||
getIt.get<AppStore>().contactListStore, getIt.get<ContactService>()));
|
||||
getIt.get<AppStore>().contactListStore,
|
||||
getIt.get<ContactService>(),
|
||||
contactSource));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => ContactListPage(getIt.get<ContactListViewModel>()));
|
||||
getIt.registerFactoryParam<ContactListPage, bool, void>(
|
||||
(bool isEditable, _) => ContactListPage(getIt.get<ContactListViewModel>(),
|
||||
isEditable: isEditable));
|
||||
|
||||
getIt.registerFactoryParam<ContactPage, Contact, void>((Contact contact, _) =>
|
||||
ContactPage(getIt.get<ContactViewModel>(param1: contact)));
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:cake_wallet/src/domain/monero/monero_transaction_creation_credentials.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cw_monero/wallet.dart';
|
||||
|
@ -18,7 +19,8 @@ import 'package:cake_wallet/src/domain/monero/subaddress.dart';
|
|||
import 'package:cake_wallet/src/domain/common/node.dart';
|
||||
import 'package:cake_wallet/core/pending_transaction.dart';
|
||||
import 'package:cake_wallet/src/domain/common/transaction_priority.dart';
|
||||
import 'package:cake_wallet/src/domain/common/calculate_fiat_amount.dart' as cfa;
|
||||
import 'package:cake_wallet/src/domain/common/calculate_fiat_amount.dart'
|
||||
as cfa;
|
||||
|
||||
part 'monero_wallet.g.dart';
|
||||
|
||||
|
@ -137,16 +139,16 @@ abstract class MoneroWalletBase extends WalletBase<MoneroBalance> with Store {
|
|||
|
||||
@override
|
||||
Future<PendingTransaction> createTransaction(Object credentials) async {
|
||||
// final _credentials = credentials as MoneroTransactionCreationCredentials;
|
||||
// final transactionDescription = await transaction_history.createTransaction(
|
||||
// address: _credentials.address,
|
||||
// paymentId: _credentials.paymentId,
|
||||
// amount: _credentials.amount,
|
||||
// priorityRaw: _credentials.priority.serialize(),
|
||||
// accountIndex: _account.value.id);
|
||||
//
|
||||
// return PendingTransaction.fromTransactionDescription(
|
||||
// transactionDescription);
|
||||
final _credentials = credentials as MoneroTransactionCreationCredentials;
|
||||
// final transactionDescription = await transaction_history.createTransaction(
|
||||
// address: _credentials.address,
|
||||
// paymentId: _credentials.paymentId,
|
||||
// amount: _credentials.amount,
|
||||
// priorityRaw: _credentials.priority.serialize(),
|
||||
// accountIndex: _account.value.id);
|
||||
|
||||
// return PendingTransaction.fromTransactionDescription(
|
||||
// transactionDescription);
|
||||
}
|
||||
|
||||
@override
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:cake_wallet/monero/monero_wallet.dart';
|
||||
import 'package:cake_wallet/core/wallet_credentials.dart';
|
||||
import 'package:cake_wallet/core/wallet_service.dart';
|
||||
|
@ -60,7 +62,7 @@ class MoneroWalletService extends WalletService<
|
|||
|
||||
return wallet;
|
||||
} catch (e) {
|
||||
// TODO: Implement Exception fop wallet list service.
|
||||
// TODO: Implement Exception for wallet list service.
|
||||
print('MoneroWalletsManager Error: $e');
|
||||
rethrow;
|
||||
}
|
||||
|
@ -72,7 +74,7 @@ class MoneroWalletService extends WalletService<
|
|||
final path = await pathForWallet(name: name, type: WalletType.monero);
|
||||
return monero_wallet_manager.isWalletExist(path: path);
|
||||
} catch (e) {
|
||||
// TODO: Implement Exception fop wallet list service.
|
||||
// TODO: Implement Exception for wallet list service.
|
||||
print('MoneroWalletsManager Error: $e');
|
||||
rethrow;
|
||||
}
|
||||
|
@ -83,26 +85,21 @@ class MoneroWalletService extends WalletService<
|
|||
try {
|
||||
final path = await pathForWallet(name: name, type: WalletType.monero);
|
||||
monero_wallet_manager.openWallet(path: path, password: password);
|
||||
|
||||
// final id = walletTypeToString(WalletType.monero).toLowerCase() + '_' + name;
|
||||
// final walletInfo = walletInfoSource.values
|
||||
// .firstWhere((info) => info.id == id, orElse: () => null);
|
||||
|
||||
final wallet = MoneroWallet(filename: monero_wallet.getFilename());
|
||||
await wallet.init();
|
||||
|
||||
return wallet;
|
||||
} catch (e) {
|
||||
// TODO: Implement Exception fop wallet list service.
|
||||
// TODO: Implement Exception for wallet list service.
|
||||
print('MoneroWalletsManager Error: $e');
|
||||
rethrow;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> remove(String wallet) async {
|
||||
// TODO: implement remove
|
||||
throw UnimplementedError();
|
||||
}
|
||||
@override
|
||||
Future<void> remove(String wallet) async =>
|
||||
File(await pathForWalletDir(name: wallet, type: WalletType.bitcoin))
|
||||
.delete(recursive: true);
|
||||
|
||||
@override
|
||||
Future<MoneroWallet> restoreFromKeys(
|
||||
|
@ -125,7 +122,7 @@ class MoneroWalletService extends WalletService<
|
|||
|
||||
return wallet;
|
||||
} catch (e) {
|
||||
// TODO: Implement Exception fop wallet list service.
|
||||
// TODO: Implement Exception for wallet list service.
|
||||
print('MoneroWalletsManager Error: $e');
|
||||
rethrow;
|
||||
}
|
||||
|
@ -149,7 +146,7 @@ class MoneroWalletService extends WalletService<
|
|||
|
||||
return wallet;
|
||||
} catch (e) {
|
||||
// TODO: Implement Exception fop wallet list service.
|
||||
// TODO: Implement Exception for wallet list service.
|
||||
print('MoneroWalletsManager Error: $e');
|
||||
rethrow;
|
||||
}
|
||||
|
|
|
@ -90,6 +90,8 @@ class PaletteDark {
|
|||
static const Color distantBlue = Color.fromRGBO(72, 85, 131, 1.0);
|
||||
static const Color moderateVioletBlue = Color.fromRGBO(62, 73, 113, 1.0);
|
||||
static const Color deepVioletBlue = Color.fromRGBO(52, 66, 104, 1.0);
|
||||
static const Color lightPurpleBlue = Color.fromRGBO(120, 133, 170, 1.0);
|
||||
static const Color indicatorVioletBlue = Color.fromRGBO(59, 72, 119, 1.0);
|
||||
|
||||
// FIXME: Rename.
|
||||
static const Color eee = Color.fromRGBO(236, 239, 245, 1.0);
|
||||
|
|
|
@ -24,7 +24,8 @@ import 'package:cake_wallet/store/dashboard/fiat_convertation_store.dart';
|
|||
// FIXME: move me
|
||||
Future<void> loadCurrentWallet() async {
|
||||
final appStore = getIt.get<AppStore>();
|
||||
final name = getIt.get<SharedPreferences>().getString('current_wallet_name');
|
||||
final name = 'test';
|
||||
getIt.get<SharedPreferences>().getString('current_wallet_name');
|
||||
final typeRaw =
|
||||
getIt.get<SharedPreferences>().getInt('current_wallet_type') ?? 0;
|
||||
final type = deserializeFromInt(typeRaw);
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:cake_wallet/src/screens/dashboard/dashboard_page.dart';
|
|||
import 'package:cake_wallet/src/screens/seed/wallet_seed_page.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_new_vm.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restoration_from_seed_vm.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restoration_from_keys_vm.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
|
@ -165,6 +166,7 @@ class Router {
|
|||
builder: (_) => NewWalletTypePage(
|
||||
onTypeSelected: (context, type) => Navigator.of(context)
|
||||
.pushNamed(Routes.restoreWalletOptions, arguments: type),
|
||||
isNewWallet: false,
|
||||
));
|
||||
|
||||
case Routes.restoreOptions:
|
||||
|
@ -196,7 +198,7 @@ class Router {
|
|||
? Routes.seedLanguage
|
||||
: Routes.restoreWalletFromKeys;
|
||||
final args = type == WalletType.monero
|
||||
? [type, Routes.restoreWalletFromSeed]
|
||||
? [type, Routes.restoreWalletFromKeys]
|
||||
: [type];
|
||||
|
||||
Navigator.of(context).pushNamed(route, arguments: args);
|
||||
|
@ -236,17 +238,12 @@ class Router {
|
|||
? args[1] as String
|
||||
: 'English'; // FIXME: Unnamed constant; English default and only one language for bitcoin.
|
||||
|
||||
final walletRestorationFromKeysVM =
|
||||
getIt.get<WalletRestorationFromKeysVM>(param1: [type, language]);
|
||||
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) =>
|
||||
ProxyProvider<AuthenticationStore, WalletRestorationStore>(
|
||||
update: (_, authStore, __) => WalletRestorationStore(
|
||||
authStore: authStore,
|
||||
sharedPreferences: sharedPreferences,
|
||||
walletListService: walletListService),
|
||||
child: RestoreWalletFromKeysPage(
|
||||
walletsService: walletListService,
|
||||
walletService: walletService,
|
||||
sharedPreferences: sharedPreferences)));
|
||||
builder: (_) => RestoreWalletFromKeysPage(
|
||||
walletRestorationFromKeysVM: walletRestorationFromKeysVM));
|
||||
|
||||
case Routes.dashboard:
|
||||
return CupertinoPageRoute<void>(
|
||||
|
@ -340,11 +337,11 @@ class Router {
|
|||
|
||||
case Routes.addressBook:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => getIt.get<ContactListPage>());
|
||||
builder: (_) => getIt.get<ContactListPage>(param1: true));
|
||||
|
||||
case Routes.pickerAddressBook:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => getIt.get<ContactListPage>());
|
||||
builder: (_) => getIt.get<ContactListPage>(param1: false));
|
||||
|
||||
case Routes.addressBookAddContact:
|
||||
return CupertinoPageRoute<void>(
|
||||
|
@ -360,24 +357,6 @@ class Router {
|
|||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<ExchangeTradePage>());
|
||||
|
||||
/*MultiProvider(
|
||||
providers: [
|
||||
ProxyProvider<SettingsStore, ExchangeTradeStore>(
|
||||
update: (_, settingsStore, __) => ExchangeTradeStore(
|
||||
trade: settings.arguments as Trade,
|
||||
walletStore: walletStore,
|
||||
trades: trades),
|
||||
),
|
||||
ProxyProvider<SettingsStore, SendStore>(
|
||||
update: (_, settingsStore, __) => SendStore(
|
||||
transactionDescriptions: transactionDescriptions,
|
||||
walletService: walletService,
|
||||
settingsStore: settingsStore,
|
||||
priceStore: priceStore)),
|
||||
],
|
||||
child: ExchangeTradePage(),
|
||||
));*/
|
||||
|
||||
case Routes.exchangeConfirm:
|
||||
return MaterialPageRoute<void>(
|
||||
builder: (_) => getIt.get<ExchangeConfirmPage>());
|
||||
|
|
|
@ -3,22 +3,28 @@ import 'package:flutter/services.dart';
|
|||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
class BiometricAuth {
|
||||
final _localAuth = LocalAuthentication();
|
||||
|
||||
Future<bool> isAuthenticated() async {
|
||||
final LocalAuthentication _localAuth = LocalAuthentication();
|
||||
|
||||
try {
|
||||
return await _localAuth.authenticateWithBiometrics(
|
||||
localizedReason: S.current.biometric_auth_reason,
|
||||
useErrorDialogs: true,
|
||||
stickyAuth: false
|
||||
);
|
||||
} on PlatformException
|
||||
catch(e) {
|
||||
stickyAuth: false);
|
||||
} on PlatformException catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
Future<bool> canCheckBiometrics() async {
|
||||
try {
|
||||
return await _localAuth.canCheckBiometrics;
|
||||
} on PlatformException catch (e) {
|
||||
print(e);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
|
||||
import 'package:cake_wallet/utils/mobx.dart';
|
||||
|
||||
part 'contact.g.dart';
|
||||
|
||||
@HiveType(typeId: 0)
|
||||
class Contact extends HiveObject {
|
||||
class Contact extends HiveObject with Keyable {
|
||||
Contact({@required this.name, @required this.address, CryptoCurrency type})
|
||||
: raw = type?.raw;
|
||||
|
||||
|
@ -22,6 +23,9 @@ class Contact extends HiveObject {
|
|||
|
||||
CryptoCurrency get type => CryptoCurrency.deserialize(raw: raw);
|
||||
|
||||
@override
|
||||
dynamic get keyIndex => key;
|
||||
|
||||
@override
|
||||
bool operator ==(Object o) => o is Contact && o.key == key;
|
||||
|
||||
|
|
38
lib/src/domain/common/contact_model.dart
Normal file
|
@ -0,0 +1,38 @@
|
|||
// import 'package:hive/hive.dart';
|
||||
// import 'package:mobx/mobx.dart';
|
||||
// import 'package:cake_wallet/src/domain/common/contact.dart';
|
||||
// import 'package:cake_wallet/src/domain/common/crypto_currency.dart';
|
||||
|
||||
// part 'contact_model.g.dart';
|
||||
|
||||
// class ContactModel = ContactModelBase with _$ContactModel;
|
||||
|
||||
// abstract class ContactModelBase with Store {
|
||||
// ContactModelBase(this._contacts, {Contact contact}) : _contact = contact {
|
||||
// name = _contact?.name;
|
||||
// address = _contact?.address;
|
||||
// currency = _contact?.type;
|
||||
|
||||
// _contacts.watch(key: contact.key).listen((event) {
|
||||
|
||||
// });
|
||||
// }
|
||||
|
||||
// @observable
|
||||
// String name;
|
||||
|
||||
// @observable
|
||||
// String address;
|
||||
|
||||
// @observable
|
||||
// CryptoCurrency currency;
|
||||
|
||||
// // @computed
|
||||
// // bool get isReady =>
|
||||
// // (name?.isNotEmpty ?? false) &&
|
||||
// // (currency?.toString()?.isNotEmpty ?? false) &&
|
||||
// // (address?.isNotEmpty ?? false);
|
||||
|
||||
// final Box<ContactBase> _contacts;
|
||||
// final Contact _contact;
|
||||
// }
|
|
@ -107,7 +107,7 @@ Future<void> changeMoneroCurrentNodeToDefault(
|
|||
}
|
||||
|
||||
Node getBitcoinDefaultElectrumServer({@required Box<Node> nodes}) {
|
||||
final uri = 'bitcoin.electrumx.multicoin.co:50002';
|
||||
final uri = 'electrumx.cakewallet.com:50002';
|
||||
|
||||
return nodes.values
|
||||
.firstWhere((Node node) => node.uri == uri, orElse: () => null) ??
|
||||
|
|
|
@ -30,7 +30,7 @@ class Language with ChangeNotifier {
|
|||
}
|
||||
|
||||
static Future<String> localeDetection() async {
|
||||
String locale = await Devicelocale.currentLocale;
|
||||
var locale = await Devicelocale.currentLocale;
|
||||
locale = Intl.shortLocale(locale);
|
||||
|
||||
return languages.keys.contains(locale) ? locale : 'en';
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:cake_wallet/utils/mobx.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
|
@ -8,7 +9,7 @@ import 'package:cake_wallet/src/domain/common/digest_request.dart';
|
|||
part 'node.g.dart';
|
||||
|
||||
@HiveType(typeId: 1)
|
||||
class Node extends HiveObject {
|
||||
class Node extends HiveObject with Keyable {
|
||||
Node(
|
||||
{@required this.uri,
|
||||
@required WalletType type,
|
||||
|
|
|
@ -5,19 +5,20 @@ import 'package:cake_wallet/generated/i18n.dart';
|
|||
import 'package:cake_wallet/view_model/auth_state.dart';
|
||||
import 'package:cake_wallet/view_model/auth_view_model.dart';
|
||||
import 'package:cake_wallet/src/screens/pin_code/pin_code.dart';
|
||||
import 'package:cake_wallet/src/stores/settings/settings_store.dart';
|
||||
import 'package:cake_wallet/src/domain/common/biometric_auth.dart';
|
||||
|
||||
typedef OnAuthenticationFinished = void Function(bool, AuthPageState);
|
||||
|
||||
class AuthPage extends StatefulWidget {
|
||||
AuthPage(
|
||||
{this.onAuthenticationFinished,
|
||||
{@required this.allowBiometricalAuthentication,
|
||||
this.onAuthenticationFinished,
|
||||
this.authViewModel,
|
||||
this.closable = true});
|
||||
|
||||
final AuthViewModel authViewModel;
|
||||
final OnAuthenticationFinished onAuthenticationFinished;
|
||||
final bool allowBiometricalAuthentication;
|
||||
final bool closable;
|
||||
|
||||
@override
|
||||
|
@ -95,6 +96,27 @@ class AuthPageState extends State<AuthPage> {
|
|||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (widget.allowBiometricalAuthentication) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
print('post');
|
||||
await Future<void>.delayed(Duration(milliseconds: 100));
|
||||
print('after timeout');
|
||||
final biometricAuth = BiometricAuth();
|
||||
final isAuth = await biometricAuth.isAuthenticated();
|
||||
|
||||
if (isAuth) {
|
||||
widget.authViewModel.biometricAuth();
|
||||
_key.currentState.showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(S.of(context).authenticated),
|
||||
backgroundColor: Colors.green,
|
||||
),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
@ -111,27 +133,7 @@ class AuthPageState extends State<AuthPage> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// final authStore = Provider.of<AuthStore>(context);
|
||||
// final settingsStore = Provider.of<SettingsStore>(context);
|
||||
|
||||
// if (settingsStore.allowBiometricalAuthentication) {
|
||||
// WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
// final biometricAuth = BiometricAuth();
|
||||
// biometricAuth.isAuthenticated().then(
|
||||
// (isAuth) {
|
||||
// if (isAuth) {
|
||||
// authStore.biometricAuth();
|
||||
// _key.currentState.showSnackBar(
|
||||
// SnackBar(
|
||||
// content: Text(S.of(context).authenticated),
|
||||
// backgroundColor: Colors.green,
|
||||
// ),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// );
|
||||
// });
|
||||
// }
|
||||
print('start');
|
||||
|
||||
return Scaffold(
|
||||
key: _key,
|
||||
|
|
|
@ -88,9 +88,7 @@ class DashboardPage extends BasePage {
|
|||
child: PageView.builder(
|
||||
controller: controller,
|
||||
itemCount: pages.length,
|
||||
itemBuilder: (context, index) {
|
||||
return pages[index];
|
||||
})),
|
||||
itemBuilder: (context, index) => pages[index])),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(bottom: 24),
|
||||
child: SmoothPageIndicator(
|
||||
|
@ -106,8 +104,9 @@ class DashboardPage extends BasePage {
|
|||
)),
|
||||
Container(
|
||||
width: double.infinity,
|
||||
padding: EdgeInsets.only(left: 45, right: 45, bottom: 24),
|
||||
padding: EdgeInsets.only(left: 44, right: 0, bottom: 24),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: ActionButton(
|
||||
|
@ -122,14 +121,6 @@ class DashboardPage extends BasePage {
|
|||
image: exchangeImage,
|
||||
title: S.of(context).exchange,
|
||||
route: Routes.exchange),
|
||||
),
|
||||
Flexible(
|
||||
child: ActionButton(
|
||||
image: receiveImage,
|
||||
title: S.of(context).receive,
|
||||
route: Routes.receive,
|
||||
alignment: Alignment.centerRight,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
|
|
|
@ -1,12 +1,11 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class ActionButton extends StatelessWidget{
|
||||
ActionButton({
|
||||
@required this.image,
|
||||
@required this.title,
|
||||
@required this.route,
|
||||
this.alignment = Alignment.center
|
||||
});
|
||||
class ActionButton extends StatelessWidget {
|
||||
ActionButton(
|
||||
{@required this.image,
|
||||
@required this.title,
|
||||
@required this.route,
|
||||
this.alignment = Alignment.center});
|
||||
|
||||
final Image image;
|
||||
final String title;
|
||||
|
@ -35,20 +34,16 @@ class ActionButton extends StatelessWidget{
|
|||
width: 60,
|
||||
alignment: Alignment.center,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).buttonColor,
|
||||
shape: BoxShape.circle),
|
||||
color: Theme.of(context).buttonColor, shape: BoxShape.circle),
|
||||
child: image,
|
||||
),
|
||||
),
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Colors.white
|
||||
),
|
||||
style: TextStyle(fontSize: 14, color: Colors.white),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import 'dart:ui';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
@ -132,6 +133,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
|||
_fileText,
|
||||
style: TextStyle(
|
||||
fontSize: 12.0,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
))
|
||||
|
@ -169,7 +171,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
|||
xmrtoUrl,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
color: Colors.blue,
|
||||
color: Palette.blueCraiola,
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.normal,
|
||||
decoration: TextDecoration.underline),
|
||||
|
@ -190,7 +192,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
|||
changenowUrl,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
color: Colors.blue,
|
||||
color: Palette.blueCraiola,
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.normal,
|
||||
decoration: TextDecoration.underline),
|
||||
|
@ -211,7 +213,7 @@ class DisclaimerBodyState extends State<DisclaimerPageBody> {
|
|||
morphUrl,
|
||||
textAlign: TextAlign.left,
|
||||
style: TextStyle(
|
||||
color: Colors.blue,
|
||||
color: Palette.blueCraiola,
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.normal,
|
||||
decoration: TextDecoration.underline),
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import 'dart:convert';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
@ -27,93 +29,85 @@ class FaqFormState extends State<FaqForm> {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final addIcon = Icon(Icons.add, color: Theme.of(context).primaryTextTheme.title.color);
|
||||
final removeIcon = Icon(Icons.remove, color: Colors.green);
|
||||
final removeIcon = Icon(Icons.remove, color: Palette.blueCraiola);
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 12),
|
||||
child: Container(
|
||||
color: Theme.of(context).accentTextTheme.headline.color,
|
||||
child: FutureBuilder(
|
||||
builder: (context, snapshot) {
|
||||
final faqItems = jsonDecode(snapshot.data.toString()) as List;
|
||||
padding: EdgeInsets.only(top: 12, left: 24),
|
||||
child: FutureBuilder(
|
||||
builder: (context, snapshot) {
|
||||
final faqItems = jsonDecode(snapshot.data.toString()) as List;
|
||||
|
||||
if (snapshot.hasData) {
|
||||
setIconsAndColors(context, faqItems.length, addIcon);
|
||||
}
|
||||
if (snapshot.hasData) {
|
||||
setIconsAndColors(context, faqItems.length, addIcon);
|
||||
}
|
||||
|
||||
return SingleChildScrollView(
|
||||
child: ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final itemTitle = faqItems[index]["question"].toString();
|
||||
final itemChild = faqItems[index]["answer"].toString();
|
||||
return SingleChildScrollView(
|
||||
child: Column(
|
||||
children: <Widget>[
|
||||
StandardListSeparator(),
|
||||
ListView.separated(
|
||||
shrinkWrap: true,
|
||||
physics: NeverScrollableScrollPhysics(),
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
final itemTitle = faqItems[index]["question"].toString();
|
||||
final itemChild = faqItems[index]["answer"].toString();
|
||||
|
||||
return ExpansionTile(
|
||||
title: Padding(
|
||||
padding: EdgeInsets.only(left: 8, top: 12, bottom: 12),
|
||||
child: Text(
|
||||
itemTitle,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: colors[index]
|
||||
return ListTileTheme(
|
||||
contentPadding: EdgeInsets.fromLTRB(0, 6, 24, 6),
|
||||
child: ExpansionTile(
|
||||
title: Text(
|
||||
itemTitle,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: colors[index]
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
trailing: Padding(
|
||||
padding: EdgeInsets.only(right: 24),
|
||||
child: Container(
|
||||
width: double.minPositive,
|
||||
child: Center(
|
||||
child: icons[index]
|
||||
),
|
||||
),
|
||||
),
|
||||
backgroundColor: Theme.of(context).accentTextTheme.headline.backgroundColor,
|
||||
onExpansionChanged: (value) {
|
||||
setState(() {
|
||||
if (value) {
|
||||
icons[index] = removeIcon;
|
||||
colors[index] = Colors.green;
|
||||
} else {
|
||||
icons[index] = addIcon;
|
||||
colors[index] = Theme.of(context).primaryTextTheme.title.color;
|
||||
}
|
||||
});
|
||||
},
|
||||
children: <Widget>[
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
trailing: icons[index],
|
||||
onExpansionChanged: (value) {
|
||||
setState(() {
|
||||
if (value) {
|
||||
icons[index] = removeIcon;
|
||||
colors[index] = Palette.blueCraiola;
|
||||
} else {
|
||||
icons[index] = addIcon;
|
||||
colors[index] = Theme.of(context).primaryTextTheme.title.color;
|
||||
}
|
||||
});
|
||||
},
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(
|
||||
left: 24.0,
|
||||
right: 24.0,
|
||||
bottom: 8
|
||||
),
|
||||
child: Text(
|
||||
itemChild,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
))
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(
|
||||
right: 24.0,
|
||||
),
|
||||
child: Text(
|
||||
itemChild,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
))
|
||||
],
|
||||
)
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
},
|
||||
separatorBuilder: (_, __) =>
|
||||
Container(color: Theme.of(context).dividerColor, height: 1.0),
|
||||
itemCount: faqItems == null ? 0 : faqItems.length,
|
||||
),
|
||||
);
|
||||
},
|
||||
future: rootBundle.loadString(getFaqPath(context)),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (_, __) =>
|
||||
StandardListSeparator(),
|
||||
itemCount: faqItems == null ? 0 : faqItems.length,
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
future: rootBundle.loadString(getFaqPath(context)),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -40,6 +42,7 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
|||
static const aspectRatioImage = 1.22;
|
||||
|
||||
final walletNameImage = Image.asset('assets/images/wallet_name.png');
|
||||
final walletNameLightImage = Image.asset('assets/images/wallet_name_light.png');
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final _languageSelectorKey = GlobalKey<SeedLanguageSelectorState>();
|
||||
ReactionDisposer _stateReaction;
|
||||
|
@ -72,6 +75,9 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final walletImage = getIt.get<SettingsStore>().isDarkTheme
|
||||
? walletNameImage : walletNameLightImage;
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: ScrollableWithBottomSection(
|
||||
|
@ -82,7 +88,7 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
|||
padding: EdgeInsets.only(left: 12, right: 12),
|
||||
child: AspectRatio(
|
||||
aspectRatio: aspectRatioImage,
|
||||
child: FittedBox(child: walletNameImage, fit: BoxFit.fill)),
|
||||
child: FittedBox(child: walletImage, fit: BoxFit.fill)),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
|
@ -98,19 +104,26 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
|||
Theme.of(context).primaryTextTheme.title.color),
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 16.0,
|
||||
fontSize: 18.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.caption
|
||||
.accentTextTheme
|
||||
.display3
|
||||
.color),
|
||||
hintText: S.of(context).wallet_name,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.display3
|
||||
.decorationColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.display3
|
||||
.decorationColor,
|
||||
width: 1.0))),
|
||||
validator: WalletNameValidator())),
|
||||
),
|
||||
|
@ -122,7 +135,7 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
|||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
),
|
||||
|
@ -140,7 +153,8 @@ class _WalletNameFormState extends State<WalletNameForm> {
|
|||
builder: (context) {
|
||||
return LoadingPrimaryButton(
|
||||
onPressed: _confirmForm,
|
||||
text: S.of(context).continue_text,
|
||||
//text: S.of(context).continue_text,
|
||||
text: S.of(context).seed_language_next,
|
||||
color: Colors.green,
|
||||
textColor: Colors.white,
|
||||
isLoading: _walletNewVM.state is WalletCreatedSuccessfully,
|
||||
|
|
|
@ -1,4 +1,6 @@
|
|||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
@ -6,15 +8,17 @@ import 'package:cake_wallet/src/screens/base_page.dart';
|
|||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
||||
class NewWalletTypePage extends BasePage {
|
||||
NewWalletTypePage({this.onTypeSelected});
|
||||
NewWalletTypePage({this.onTypeSelected, this.isNewWallet = true});
|
||||
|
||||
final void Function(BuildContext, WalletType) onTypeSelected;
|
||||
final bool isNewWallet;
|
||||
|
||||
@override
|
||||
String get title => S.current.new_wallet;
|
||||
String get title => isNewWallet
|
||||
? S.current.new_wallet
|
||||
: S.current.wallet_list_restore_wallet;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) =>
|
||||
|
@ -38,6 +42,7 @@ class WalletTypeFormState extends State<WalletTypeForm> {
|
|||
final bitcoinIcon =
|
||||
Image.asset('assets/images/bitcoin.png', height: 24, width: 24);
|
||||
final walletTypeImage = Image.asset('assets/images/wallet_type.png');
|
||||
final walletTypeLightImage = Image.asset('assets/images/wallet_type_light.png');
|
||||
|
||||
WalletType selected;
|
||||
List<WalletType> types;
|
||||
|
@ -50,6 +55,9 @@ class WalletTypeFormState extends State<WalletTypeForm> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final walletImage = getIt.get<SettingsStore>().isDarkTheme
|
||||
? walletTypeImage : walletTypeLightImage;
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: ScrollableWithBottomSection(
|
||||
|
@ -61,7 +69,7 @@ class WalletTypeFormState extends State<WalletTypeForm> {
|
|||
padding: EdgeInsets.only(left: 12, right: 12),
|
||||
child: AspectRatio(
|
||||
aspectRatio: aspectRatioImage,
|
||||
child: FittedBox(child: walletTypeImage, fit: BoxFit.fill)),
|
||||
child: FittedBox(child: walletImage, fit: BoxFit.fill)),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 48),
|
||||
|
@ -70,7 +78,7 @@ class WalletTypeFormState extends State<WalletTypeForm> {
|
|||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
),
|
||||
|
@ -79,8 +87,7 @@ class WalletTypeFormState extends State<WalletTypeForm> {
|
|||
child: SelectButton(
|
||||
image: _iconFor(type),
|
||||
text: walletTypeToString(type),
|
||||
color: _backgroundColorFor(selected == type),
|
||||
textColor: _textColorFor(selected == type),
|
||||
isSelected: selected == type,
|
||||
onTap: () => setState(() => selected = type)),
|
||||
))
|
||||
],
|
||||
|
@ -97,16 +104,6 @@ class WalletTypeFormState extends State<WalletTypeForm> {
|
|||
);
|
||||
}
|
||||
|
||||
// FIXME: Move color selection inside ui element; add isSelected to buttons.
|
||||
|
||||
Color _backgroundColorFor(bool isSelected) => isSelected
|
||||
? Theme.of(context).accentTextTheme.title.decorationColor
|
||||
: Theme.of(context).accentTextTheme.title.backgroundColor;
|
||||
|
||||
Color _textColorFor(bool isSelected) => isSelected
|
||||
? Theme.of(context).primaryTextTheme.title.backgroundColor
|
||||
: Theme.of(context).primaryTextTheme.title.color;
|
||||
|
||||
Image _iconFor(WalletType type) {
|
||||
switch (type) {
|
||||
case WalletType.monero:
|
||||
|
|
|
@ -4,21 +4,30 @@ class SelectButton extends StatelessWidget {
|
|||
SelectButton({
|
||||
@required this.image,
|
||||
@required this.text,
|
||||
@required this.color,
|
||||
@required this.textColor,
|
||||
@required this.onTap,
|
||||
this.isSelected = false,
|
||||
});
|
||||
|
||||
final Image image;
|
||||
final String text;
|
||||
final Color color;
|
||||
final Color textColor;
|
||||
final bool isSelected;
|
||||
final VoidCallback onTap;
|
||||
|
||||
final selectArrowImage = Image.asset('assets/images/select_arrow.png');
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final color = isSelected
|
||||
? Theme.of(context).accentTextTheme.subtitle.decorationColor
|
||||
: Theme.of(context).accentTextTheme.caption.color;
|
||||
final textColor = isSelected
|
||||
? Theme.of(context).accentTextTheme.headline.decorationColor
|
||||
: Theme.of(context).primaryTextTheme.title.color;
|
||||
final arrowColor = isSelected
|
||||
? Theme.of(context).accentTextTheme.headline.decorationColor
|
||||
: Theme.of(context).accentTextTheme.subhead.color;
|
||||
|
||||
final selectArrowImage = Image.asset('assets/images/select_arrow.png',
|
||||
color: arrowColor);
|
||||
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
|
@ -39,9 +48,7 @@ class SelectButton extends StatelessWidget {
|
|||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
image != null
|
||||
? image
|
||||
: Offstage(),
|
||||
image ?? Offstage(),
|
||||
Padding(
|
||||
padding: image != null
|
||||
? EdgeInsets.only(left: 15)
|
||||
|
@ -50,7 +57,7 @@ class SelectButton extends StatelessWidget {
|
|||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: textColor
|
||||
),
|
||||
),
|
||||
|
|
|
@ -108,7 +108,7 @@ class NodeListPage extends BasePage {
|
|||
});
|
||||
|
||||
final dismissibleRow = Dismissible(
|
||||
key: Key('${node.value.key}'),
|
||||
key: Key('${node.keyIndex}'),
|
||||
confirmDismiss: (direction) async {
|
||||
return await showDialog(
|
||||
context: context,
|
||||
|
|
|
@ -108,7 +108,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
|||
Text(title,
|
||||
style: TextStyle(
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).primaryTextTheme.title.color)),
|
||||
Spacer(flex: 3),
|
||||
Container(
|
||||
|
@ -126,7 +126,11 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
|||
shape: BoxShape.circle,
|
||||
color: isFilled
|
||||
? Theme.of(context).primaryTextTheme.title.color
|
||||
: Theme.of(context).primaryTextTheme.caption.color,
|
||||
: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.body1
|
||||
.color
|
||||
.withOpacity(0.25),
|
||||
));
|
||||
}),
|
||||
),
|
||||
|
@ -143,7 +147,11 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
|||
_changePinLengthText(),
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color),
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.body1
|
||||
.decorationColor),
|
||||
))
|
||||
],
|
||||
Spacer(flex: 1),
|
||||
|
@ -227,7 +235,7 @@ class PinCodeState<T extends PinCodeWidget> extends State<T> {
|
|||
child: Text('$index',
|
||||
style: TextStyle(
|
||||
fontSize: 30.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
|
|
|
@ -1,40 +1,36 @@
|
|||
import 'package:mobx/mobx.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:cake_wallet/core/validator.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/domain/services/wallet_list_service.dart';
|
||||
import 'package:cake_wallet/src/domain/services/wallet_service.dart';
|
||||
import 'package:cake_wallet/src/stores/wallet_restoration/wallet_restoration_store.dart';
|
||||
import 'package:cake_wallet/src/stores/wallet_restoration/wallet_restoration_state.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/src/stores/seed_language/seed_language_store.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restoration_from_keys_vm.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
|
||||
class RestoreWalletFromKeysPage extends BasePage {
|
||||
RestoreWalletFromKeysPage(
|
||||
{@required this.walletsService,
|
||||
@required this.sharedPreferences,
|
||||
@required this.walletService});
|
||||
{@required this.walletRestorationFromKeysVM});
|
||||
|
||||
final WalletListService walletsService;
|
||||
final WalletService walletService;
|
||||
final SharedPreferences sharedPreferences;
|
||||
final WalletRestorationFromKeysVM walletRestorationFromKeysVM;
|
||||
|
||||
@override
|
||||
String get title => S.current.restore_title_from_keys;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => RestoreFromKeysFrom();
|
||||
Widget body(BuildContext context) => RestoreFromKeysFrom(walletRestorationFromKeysVM);
|
||||
}
|
||||
|
||||
class RestoreFromKeysFrom extends StatefulWidget {
|
||||
RestoreFromKeysFrom(this.walletRestorationFromKeysVM);
|
||||
|
||||
final WalletRestorationFromKeysVM walletRestorationFromKeysVM;
|
||||
|
||||
@override
|
||||
_RestoreFromKeysFromState createState() => _RestoreFromKeysFromState();
|
||||
}
|
||||
|
@ -46,6 +42,23 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
|||
final _addressController = TextEditingController();
|
||||
final _viewKeyController = TextEditingController();
|
||||
final _spendKeyController = TextEditingController();
|
||||
final _wifController = TextEditingController();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_nameController.addListener(() =>
|
||||
widget.walletRestorationFromKeysVM.name = _nameController.text);
|
||||
_addressController.addListener(() =>
|
||||
widget.walletRestorationFromKeysVM.address = _addressController.text);
|
||||
_viewKeyController.addListener(() =>
|
||||
widget.walletRestorationFromKeysVM.viewKey = _viewKeyController.text);
|
||||
_spendKeyController.addListener(() =>
|
||||
widget.walletRestorationFromKeysVM.spendKey = _spendKeyController.text);
|
||||
_wifController.addListener(() =>
|
||||
widget.walletRestorationFromKeysVM.wif = _wifController.text);
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
|
@ -53,31 +66,14 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
|||
_addressController.dispose();
|
||||
_viewKeyController.dispose();
|
||||
_spendKeyController.dispose();
|
||||
_wifController.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
void onHandleControllers(WalletRestorationStore walletRestorationStore) {
|
||||
if (_nameController.text.isNotEmpty &&
|
||||
_addressController.text.isNotEmpty &&
|
||||
_viewKeyController.text.isNotEmpty &&
|
||||
_spendKeyController.text.isNotEmpty) {
|
||||
walletRestorationStore.setDisabledState(false);
|
||||
} else {
|
||||
walletRestorationStore.setDisabledState(true);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final walletRestorationStore = Provider.of<WalletRestorationStore>(context);
|
||||
final seedLanguageStore = Provider.of<SeedLanguageStore>(context);
|
||||
|
||||
_nameController.addListener(() {onHandleControllers(walletRestorationStore);});
|
||||
_addressController.addListener(() {onHandleControllers(walletRestorationStore);});
|
||||
_viewKeyController.addListener(() {onHandleControllers(walletRestorationStore);});
|
||||
_spendKeyController.addListener(() {onHandleControllers(walletRestorationStore);});
|
||||
|
||||
reaction((_) => walletRestorationStore.state, (WalletRestorationState state) {
|
||||
/*reaction((_) => walletRestorationStore.state, (WalletRestorationState state) {
|
||||
if (state is WalletRestoredSuccessfully) {
|
||||
Navigator.of(context).popUntil((route) => route.isFirst);
|
||||
}
|
||||
|
@ -96,7 +92,7 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
|||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
});*/
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
|
@ -110,66 +106,39 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
|||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
child: BaseTextFormField(
|
||||
controller: _nameController,
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontSize: 16
|
||||
),
|
||||
hintText: S.of(context).restore_wallet_name,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))),
|
||||
validator: (value) {
|
||||
walletRestorationStore.validateWalletName(value);
|
||||
return walletRestorationStore.errorMessage;
|
||||
},
|
||||
),
|
||||
hintText: S.of(context).restore_wallet_name,
|
||||
validator: WalletNameValidator(),
|
||||
)
|
||||
))
|
||||
],
|
||||
),
|
||||
if (!widget.walletRestorationFromKeysVM.hasRestorationHeight)
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: BaseTextFormField(
|
||||
controller: _wifController,
|
||||
hintText: 'WIF',
|
||||
)
|
||||
))
|
||||
],
|
||||
),
|
||||
if (widget.walletRestorationFromKeysVM.hasRestorationHeight) ... [
|
||||
Row(
|
||||
children: <Widget>[
|
||||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
child: BaseTextFormField(
|
||||
controller: _addressController,
|
||||
keyboardType: TextInputType.multiline,
|
||||
maxLines: null,
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontSize: 16
|
||||
),
|
||||
hintText: S.of(context).restore_address,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))),
|
||||
validator: (value) {
|
||||
walletRestorationStore.validateAddress(value);
|
||||
return walletRestorationStore.errorMessage;
|
||||
},
|
||||
),
|
||||
hintText: S.of(context).restore_address,
|
||||
)
|
||||
))
|
||||
],
|
||||
),
|
||||
|
@ -178,31 +147,10 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
|||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
child: BaseTextFormField(
|
||||
controller: _viewKeyController,
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontSize: 16
|
||||
),
|
||||
hintText: S.of(context).restore_view_key_private,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))),
|
||||
validator: (value) {
|
||||
walletRestorationStore.validateKeys(value);
|
||||
return walletRestorationStore.errorMessage;
|
||||
},
|
||||
),
|
||||
hintText: S.of(context).restore_view_key_private,
|
||||
)
|
||||
))
|
||||
],
|
||||
),
|
||||
|
@ -211,35 +159,19 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
|||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
child: BaseTextFormField(
|
||||
controller: _spendKeyController,
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontSize: 16
|
||||
),
|
||||
hintText: S.of(context).restore_spend_key_private,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))),
|
||||
validator: (value) {
|
||||
walletRestorationStore.validateKeys(value);
|
||||
return walletRestorationStore.errorMessage;
|
||||
},
|
||||
),
|
||||
hintText: S.of(context).restore_spend_key_private,
|
||||
)
|
||||
))
|
||||
],
|
||||
),
|
||||
BlockchainHeightWidget(key: _blockchainHeightKey),
|
||||
BlockchainHeightWidget(
|
||||
key: _blockchainHeightKey,
|
||||
onHeightChange: (height) {
|
||||
widget.walletRestorationFromKeysVM.height = height;
|
||||
print(height);
|
||||
})],
|
||||
]),
|
||||
),
|
||||
bottomSectionPadding: EdgeInsets.only(bottom: 24),
|
||||
|
@ -247,19 +179,19 @@ class _RestoreFromKeysFromState extends State<RestoreFromKeysFrom> {
|
|||
return LoadingPrimaryButton(
|
||||
onPressed: () {
|
||||
if (_formKey.currentState.validate()) {
|
||||
walletRestorationStore.restoreFromKeys(
|
||||
/*walletRestorationStore.restoreFromKeys(
|
||||
name: _nameController.text,
|
||||
language: seedLanguageStore.selectedSeedLanguage,
|
||||
address: _addressController.text,
|
||||
viewKey: _viewKeyController.text,
|
||||
spendKey: _spendKeyController.text,
|
||||
restoreHeight: _blockchainHeightKey.currentState.height);
|
||||
restoreHeight: _blockchainHeightKey.currentState.height);*/
|
||||
}
|
||||
},
|
||||
text: S.of(context).restore_recover,
|
||||
color: Colors.green,
|
||||
color: Palette.blueCraiola,
|
||||
textColor: Colors.white,
|
||||
isDisabled: walletRestorationStore.disabledState,
|
||||
//isDisabled: walletRestorationStore.disabledState,
|
||||
);
|
||||
}),
|
||||
),
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
@ -9,6 +10,7 @@ import 'package:cake_wallet/src/widgets/blockchain_height_widget.dart';
|
|||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_with_one_action.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_restoration_from_seed_vm.dart';
|
||||
|
||||
class RestoreWalletFromSeedDetailsPage extends BasePage {
|
||||
|
@ -91,27 +93,9 @@ class _RestoreFromSeedDetailsFormState
|
|||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 20.0),
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
child: BaseTextFormField(
|
||||
controller: _nameController,
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.caption
|
||||
.color,
|
||||
fontSize: 16),
|
||||
hintText: S.of(context).restore_wallet_name,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))),
|
||||
hintText: S.of(context).restore_wallet_name,
|
||||
validator: WalletNameValidator(),
|
||||
),
|
||||
))
|
||||
|
@ -137,7 +121,7 @@ class _RestoreFromSeedDetailsFormState
|
|||
isLoading:
|
||||
widget.walletRestorationFromSeedVM.state is WalletCreating,
|
||||
text: S.of(context).restore_recover,
|
||||
color: Colors.green,
|
||||
color: Palette.blueCraiola,
|
||||
textColor: Colors.white,
|
||||
isDisabled: _nameController.text.isNotEmpty,
|
||||
);
|
||||
|
|
|
@ -20,20 +20,40 @@ class RestoreWalletFromSeedPage extends BasePage {
|
|||
String get title => S.current.restore_title_from_seed;
|
||||
|
||||
@override
|
||||
Color get backgroundLightColor => Palette.lavender;
|
||||
Color get titleColor => Colors.white;
|
||||
|
||||
@override
|
||||
Color get backgroundDarkColor => PaletteDark.lightNightBlue;
|
||||
Color get backgroundLightColor => Colors.transparent;
|
||||
|
||||
@override
|
||||
Color get backgroundDarkColor => Colors.transparent;
|
||||
|
||||
@override
|
||||
bool get resizeToAvoidBottomPadding => false;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) =>
|
||||
RestoreFromSeedForm(key: formKey, type: type, language: language);
|
||||
RestoreFromSeedForm(key: formKey, type: type, language: language,
|
||||
leading: leading(context), middle: middle(context));
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomPadding: resizeToAvoidBottomPadding,
|
||||
body: Container(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: body(context)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class RestoreFromSeedForm extends StatefulWidget {
|
||||
RestoreFromSeedForm({Key key, this.type, this.language}) : super(key: key);
|
||||
RestoreFromSeedForm({Key key, this.type, this.language, this.leading, this.middle}) : super(key: key);
|
||||
final WalletType type;
|
||||
final String language;
|
||||
final Widget leading;
|
||||
final Widget middle;
|
||||
|
||||
@override
|
||||
_RestoreFromSeedFormState createState() => _RestoreFromSeedFormState();
|
||||
|
@ -49,18 +69,17 @@ class _RestoreFromSeedFormState extends State<RestoreFromSeedForm> {
|
|||
return GestureDetector(
|
||||
onTap: () =>
|
||||
SystemChannels.textInput.invokeMethod<void>('TextInput.hide'),
|
||||
child: Container(
|
||||
color: Theme.of(context).backgroundColor,
|
||||
child: SeedWidget(
|
||||
key: _seedKey,
|
||||
maxLength: mnemonicLength(widget.type),
|
||||
onMnemonicChange: (seed) => null,
|
||||
onFinish: () => Navigator.of(context).pushNamed(
|
||||
Routes.restoreWalletFromSeedDetails,
|
||||
arguments: [widget.type, widget.language, mnemonic()]),
|
||||
validator:
|
||||
SeedValidator(type: widget.type, language: widget.language),
|
||||
),
|
||||
child: SeedWidget(
|
||||
key: _seedKey,
|
||||
maxLength: mnemonicLength(widget.type),
|
||||
onMnemonicChange: (seed) => null,
|
||||
onFinish: () => Navigator.of(context).pushNamed(
|
||||
Routes.restoreWalletFromSeedDetails,
|
||||
arguments: [widget.type, widget.language, mnemonic()]),
|
||||
leading: widget.leading,
|
||||
middle: widget.middle,
|
||||
validator:
|
||||
SeedValidator(type: widget.type, language: widget.language),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -1,11 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/screens/restore/widgets/restore_button.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/stores/seed_language/seed_language_store.dart';
|
||||
|
||||
class RestoreWalletOptionsPage extends BasePage {
|
||||
RestoreWalletOptionsPage(
|
||||
|
@ -18,7 +15,7 @@ class RestoreWalletOptionsPage extends BasePage {
|
|||
final Function(BuildContext context) onRestoreFromKeys;
|
||||
|
||||
@override
|
||||
String get title => S.current.restore_seed_keys_restore;
|
||||
String get title => S.current.restore_restore_wallet;
|
||||
|
||||
final imageSeed = Image.asset('assets/images/restore_seed.png');
|
||||
final imageKeys = Image.asset('assets/images/restore_keys.png');
|
||||
|
@ -56,7 +53,7 @@ class RestoreWalletOptionsPage extends BasePage {
|
|||
return S.of(context).restore_description_from_seed;
|
||||
case WalletType.bitcoin:
|
||||
// TODO: Add transaction for bitcoin description.
|
||||
return 'Restore your wallet from 12 word combination code';
|
||||
return S.of(context).restore_bitcoin_description_from_seed;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
|
@ -68,7 +65,7 @@ class RestoreWalletOptionsPage extends BasePage {
|
|||
return S.of(context).restore_description_from_keys;
|
||||
case WalletType.bitcoin:
|
||||
// TODO: Add transaction for bitcoin description.
|
||||
return 'Restore your wallet from generated WIF string from your private keys';
|
||||
return S.of(context).restore_bitcoin_description_from_keys;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
|
@ -80,7 +77,7 @@ class RestoreWalletOptionsPage extends BasePage {
|
|||
return S.of(context).restore_title_from_keys;
|
||||
case WalletType.bitcoin:
|
||||
// TODO: Add transaction for bitcoin description.
|
||||
return 'Restore from WIF';
|
||||
return S.of(context).restore_bitcoin_title_from_keys;
|
||||
default:
|
||||
return '';
|
||||
}
|
||||
|
|
|
@ -19,12 +19,12 @@ class RestoreButton extends StatelessWidget {
|
|||
onTap: onPressed,
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: 150,
|
||||
height: 170,
|
||||
padding: EdgeInsets.all(24),
|
||||
alignment: Alignment.topLeft,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(12)),
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
color: Theme.of(context).accentTextTheme.caption.color,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
|
@ -44,7 +44,7 @@ class RestoreButton extends StatelessWidget {
|
|||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).primaryTextTheme.title.color
|
||||
),
|
||||
),
|
||||
|
@ -54,7 +54,8 @@ class RestoreButton extends StatelessWidget {
|
|||
description,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).primaryTextTheme.overline.color
|
||||
),
|
||||
),
|
||||
)
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/src/widgets/seed_language_selector.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
|
@ -7,8 +8,6 @@ import 'package:cake_wallet/generated/i18n.dart';
|
|||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/widgets/scollable_with_bottom_section.dart';
|
||||
import 'package:cake_wallet/src/stores/seed_language/seed_language_store.dart';
|
||||
import 'package:cake_wallet/src/screens/new_wallet/widgets/select_button.dart';
|
||||
import 'package:cake_wallet/src/screens/seed_language/widgets/seed_language_picker.dart';
|
||||
|
||||
class SeedLanguage extends BasePage {
|
||||
|
@ -16,6 +15,9 @@ class SeedLanguage extends BasePage {
|
|||
|
||||
final Function(BuildContext, String) onConfirm;
|
||||
|
||||
@override
|
||||
String get title => S.current.wallet_list_restore_wallet;
|
||||
|
||||
@override
|
||||
Widget body(BuildContext context) => SeedLanguageForm(onConfirm: onConfirm);
|
||||
}
|
||||
|
@ -33,10 +35,14 @@ class SeedLanguageFormState extends State<SeedLanguageForm> {
|
|||
static const aspectRatioImage = 1.22;
|
||||
|
||||
final walletNameImage = Image.asset('assets/images/wallet_name.png');
|
||||
final walletNameLightImage = Image.asset('assets/images/wallet_name_light.png');
|
||||
final _languageSelectorKey = GlobalKey<SeedLanguageSelectorState>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final walletImage = getIt.get<SettingsStore>().isDarkTheme
|
||||
? walletNameImage : walletNameLightImage;
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: ScrollableWithBottomSection(
|
||||
|
@ -47,7 +53,7 @@ class SeedLanguageFormState extends State<SeedLanguageForm> {
|
|||
padding: EdgeInsets.only(left: 12, right: 12),
|
||||
child: AspectRatio(
|
||||
aspectRatio: aspectRatioImage,
|
||||
child: FittedBox(child: walletNameImage, fit: BoxFit.fill)),
|
||||
child: FittedBox(child: walletImage, fit: BoxFit.fill)),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 40),
|
||||
|
@ -56,7 +62,7 @@ class SeedLanguageFormState extends State<SeedLanguageForm> {
|
|||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
),
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import 'dart:ui';
|
||||
import 'package:cake_wallet/src/widgets/alert_background.dart';
|
||||
import 'package:cake_wallet/src/widgets/alert_close_button.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/src/stores/seed_language/seed_language_store.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
|
||||
List<Image> flagImages = [
|
||||
|
@ -57,170 +57,111 @@ class SeedLanguagePicker extends StatefulWidget {
|
|||
class SeedLanguagePickerState extends State<SeedLanguagePicker> {
|
||||
SeedLanguagePickerState({this.selected});
|
||||
|
||||
final closeButton = Image.asset('assets/images/close.png');
|
||||
String selected;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
onTap: () => Navigator.of(context).pop(),
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: BackdropFilter(
|
||||
filter: ImageFilter.blur(sigmaX: 3.0, sigmaY: 3.0),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: PaletteDark.darkNightBlue.withOpacity(0.75)),
|
||||
child: Center(
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: Text(
|
||||
S.of(context).seed_choose,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
decoration: TextDecoration.none,
|
||||
color: Colors.white),
|
||||
return AlertBackground(
|
||||
child: Stack(
|
||||
alignment: Alignment.center,
|
||||
children: <Widget>[
|
||||
Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: <Widget>[
|
||||
Container(
|
||||
padding: EdgeInsets.only(left: 24, right: 24),
|
||||
child: Text(
|
||||
S.of(context).seed_choose,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontFamily: 'Poppins',
|
||||
decoration: TextDecoration.none,
|
||||
color: Colors.white
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: GestureDetector(
|
||||
onTap: () => null,
|
||||
child: Container(
|
||||
height: 300,
|
||||
width: 300,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.all(Radius.circular(14)),
|
||||
color: Theme.of(context).dividerColor),
|
||||
child: GridView.count(
|
||||
shrinkWrap: true,
|
||||
crossAxisCount: 3,
|
||||
childAspectRatio: 1,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
crossAxisSpacing: 1,
|
||||
mainAxisSpacing: 1,
|
||||
children: List.generate(9, (index) {
|
||||
if (index == 8) {
|
||||
return gridTile(
|
||||
isCurrent: false,
|
||||
place: Places.bottomRight,
|
||||
image: null,
|
||||
text: '',
|
||||
onTap: null);
|
||||
} else {
|
||||
final code = languageCodes[index];
|
||||
final flag = flagImages[index];
|
||||
final isCurrent =
|
||||
index == seedLanguages.indexOf(selected);
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 24),
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.all(Radius.circular(14)),
|
||||
child: Container(
|
||||
height: 300,
|
||||
width: 300,
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: GridView.count(
|
||||
shrinkWrap: true,
|
||||
crossAxisCount: 3,
|
||||
childAspectRatio: 1,
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
crossAxisSpacing: 1,
|
||||
mainAxisSpacing: 1,
|
||||
children: List.generate(9, (index) {
|
||||
|
||||
if (index == 0) {
|
||||
return gridTile(
|
||||
isCurrent: isCurrent,
|
||||
place: Places.topLeft,
|
||||
image: flag,
|
||||
text: code,
|
||||
onTap: () {
|
||||
selected = seedLanguages[index];
|
||||
Navigator.of(context).pop(selected);
|
||||
});
|
||||
if (index == 8) {
|
||||
|
||||
return gridTile(
|
||||
isCurrent: false,
|
||||
image: null,
|
||||
text: '',
|
||||
onTap: null);
|
||||
|
||||
}
|
||||
|
||||
final code = languageCodes[index];
|
||||
final flag = flagImages[index];
|
||||
final isCurrent =
|
||||
index == seedLanguages.indexOf(selected);
|
||||
|
||||
return gridTile(
|
||||
isCurrent: isCurrent,
|
||||
image: flag,
|
||||
text: code,
|
||||
onTap: () {
|
||||
selected = seedLanguages[index];
|
||||
Navigator.of(context).pop(selected);
|
||||
}
|
||||
|
||||
if (index == 2) {
|
||||
return gridTile(
|
||||
isCurrent: isCurrent,
|
||||
place: Places.topRight,
|
||||
image: flag,
|
||||
text: code,
|
||||
onTap: () {
|
||||
selected = seedLanguages[index];
|
||||
Navigator.of(context).pop(selected);
|
||||
});
|
||||
}
|
||||
|
||||
if (index == 6) {
|
||||
return gridTile(
|
||||
isCurrent: isCurrent,
|
||||
place: Places.bottomLeft,
|
||||
image: flag,
|
||||
text: code,
|
||||
onTap: () {
|
||||
selected = seedLanguages[index];
|
||||
Navigator.of(context).pop(selected);
|
||||
});
|
||||
}
|
||||
|
||||
return gridTile(
|
||||
isCurrent: isCurrent,
|
||||
place: Places.inside,
|
||||
image: flag,
|
||||
text: code,
|
||||
onTap: () {
|
||||
selected = seedLanguages[index];
|
||||
Navigator.of(context).pop(selected);
|
||||
});
|
||||
}
|
||||
}),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
AlertCloseButton(image: closeButton)
|
||||
],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Widget gridTile(
|
||||
{@required bool isCurrent,
|
||||
@required Places place,
|
||||
@required Image image,
|
||||
@required String text,
|
||||
@required VoidCallback onTap}) {
|
||||
BorderRadius borderRadius;
|
||||
final color = isCurrent
|
||||
? Theme.of(context).accentTextTheme.subtitle.decorationColor
|
||||
: Theme.of(context).primaryTextTheme.display1.color;
|
||||
final textColor = isCurrent
|
||||
? Colors.blue
|
||||
: Theme.of(context).primaryTextTheme.title.color;
|
||||
Widget gridTile({
|
||||
@required bool isCurrent,
|
||||
@required Image image,
|
||||
@required String text,
|
||||
@required VoidCallback onTap}) {
|
||||
|
||||
switch (place) {
|
||||
case Places.topLeft:
|
||||
borderRadius = BorderRadius.only(topLeft: Radius.circular(14));
|
||||
break;
|
||||
case Places.topRight:
|
||||
borderRadius = BorderRadius.only(topRight: Radius.circular(14));
|
||||
break;
|
||||
case Places.bottomLeft:
|
||||
borderRadius = BorderRadius.only(bottomLeft: Radius.circular(14));
|
||||
break;
|
||||
case Places.bottomRight:
|
||||
borderRadius = BorderRadius.only(bottomRight: Radius.circular(14));
|
||||
break;
|
||||
case Places.inside:
|
||||
borderRadius = BorderRadius.all(Radius.circular(0));
|
||||
break;
|
||||
}
|
||||
final color = isCurrent
|
||||
? Theme.of(context).textTheme.body2.color
|
||||
: Theme.of(context).accentTextTheme.title.color;
|
||||
final textColor = isCurrent
|
||||
? Palette.blueCraiola
|
||||
: Theme.of(context).primaryTextTheme.title.color;
|
||||
|
||||
return GestureDetector(
|
||||
onTap: onTap,
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(10),
|
||||
decoration: BoxDecoration(borderRadius: borderRadius, color: color),
|
||||
color: color,
|
||||
child: Center(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
image != null ? image : Offstage(),
|
||||
image ?? Offstage(),
|
||||
Padding(
|
||||
padding: image != null
|
||||
? EdgeInsets.only(left: 10)
|
||||
|
@ -229,14 +170,17 @@ class SeedLanguagePickerState extends State<SeedLanguagePicker> {
|
|||
text,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontFamily: 'Poppins',
|
||||
decoration: TextDecoration.none,
|
||||
color: textColor),
|
||||
color: textColor
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
));
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'package:cake_wallet/src/screens/settings/widgets/language_row.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
|
@ -16,29 +18,13 @@ class ChangeLanguage extends BasePage {
|
|||
final settingsStore = Provider.of<SettingsStore>(context);
|
||||
final currentLanguage = Provider.of<Language>(context);
|
||||
|
||||
final currentColor = Colors.green;
|
||||
final notCurrentColor = Theme.of(context).primaryTextTheme.title.color;
|
||||
|
||||
final shortDivider = Container(
|
||||
height: 1,
|
||||
padding: EdgeInsets.only(left: 24),
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
),
|
||||
);
|
||||
|
||||
final longDivider = Container(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor,
|
||||
);
|
||||
|
||||
return Container(
|
||||
padding: EdgeInsets.only(top: 10.0),
|
||||
child: ListView.builder(
|
||||
itemCount: languages.values.length,
|
||||
itemBuilder: (BuildContext context, int index) {
|
||||
child: SectionStandardList(
|
||||
sectionCount: 1,
|
||||
context: context,
|
||||
itemCounter: (int sectionIndex) => languages.values.length,
|
||||
itemBuilder: (_, sectionIndex, index) {
|
||||
final item = languages.values.elementAt(index);
|
||||
final code = languages.keys.elementAt(index);
|
||||
|
||||
|
@ -46,52 +32,30 @@ class ChangeLanguage extends BasePage {
|
|||
? false
|
||||
: code == settingsStore.languageCode;
|
||||
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
index == 0 ? longDivider : Offstage(),
|
||||
Container(
|
||||
padding: EdgeInsets.only(top: 4, bottom: 4),
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
child: ListTile(
|
||||
contentPadding: EdgeInsets.only(left: 24, right: 24),
|
||||
title: Text(
|
||||
item,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: isCurrent ? currentColor : notCurrentColor
|
||||
),
|
||||
),
|
||||
trailing: isCurrent
|
||||
? Icon(Icons.done, color: currentColor)
|
||||
: Offstage(),
|
||||
onTap: () async {
|
||||
if (!isCurrent) {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).change_language,
|
||||
alertContent: S.of(context).change_language_to(item),
|
||||
leftButtonText: S.of(context).change,
|
||||
rightButtonText: S.of(context).cancel,
|
||||
actionLeftButton: () {
|
||||
settingsStore.saveLanguageCode(
|
||||
languageCode: code);
|
||||
currentLanguage.setCurrentLanguage(code);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
actionRightButton: () => Navigator.of(context).pop()
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
item == languages.values.last
|
||||
? longDivider
|
||||
: shortDivider
|
||||
],
|
||||
return LanguageRow(
|
||||
title: item,
|
||||
isSelected: isCurrent,
|
||||
handler: (context) async {
|
||||
if (!isCurrent) {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: S.of(context).change_language,
|
||||
alertContent: S.of(context).change_language_to(item),
|
||||
leftButtonText: S.of(context).change,
|
||||
rightButtonText: S.of(context).cancel,
|
||||
actionLeftButton: () {
|
||||
settingsStore.saveLanguageCode(
|
||||
languageCode: code);
|
||||
currentLanguage.setCurrentLanguage(code);
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
actionRightButton: () => Navigator.of(context).pop()
|
||||
);
|
||||
});
|
||||
}
|
||||
},
|
||||
);
|
||||
},
|
||||
)
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import 'package:cake_wallet/src/screens/settings/widgets/settings_version_cell.dart';
|
||||
import 'package:cake_wallet/view_model/settings/version_list_item.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
|
@ -41,6 +43,7 @@ class SettingsPage extends BasePage {
|
|||
return SettingsPickerCell<dynamic>(
|
||||
title: item.title,
|
||||
selectedItem: item.selectedItem(),
|
||||
isAlwaysShowScrollThumb: item.isAlwaysShowScrollThumb,
|
||||
items: item.items,
|
||||
onItemSelected: (dynamic value) => item.onItemSelected(value),
|
||||
);
|
||||
|
@ -57,7 +60,8 @@ class SettingsPage extends BasePage {
|
|||
}
|
||||
|
||||
if (item is RegularListItem) {
|
||||
return SettingsCellWithArrow(title: item.title);
|
||||
return SettingsCellWithArrow(
|
||||
title: item.title, handler: item.handler);
|
||||
}
|
||||
|
||||
if (item is LinkListItem) {
|
||||
|
@ -68,6 +72,14 @@ class SettingsPage extends BasePage {
|
|||
linkTitle: item.linkTitle);
|
||||
}
|
||||
|
||||
if (item is VersionListItem) {
|
||||
return Observer(builder: (_) {
|
||||
return SettingsVersionCell(
|
||||
title:
|
||||
S.of(context).version(settingsViewModel.currentVersion));
|
||||
});
|
||||
}
|
||||
|
||||
return Container();
|
||||
});
|
||||
}
|
||||
|
|
30
lib/src/screens/settings/widgets/language_row.dart
Normal file
|
@ -0,0 +1,30 @@
|
|||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
|
||||
class LanguageRow extends StandardListRow {
|
||||
LanguageRow({@required String title, @required this.isSelected, @required Function(BuildContext context) handler}) :
|
||||
super(title: title, isSelected: isSelected, onTap: handler);
|
||||
|
||||
@override
|
||||
final bool isSelected;
|
||||
|
||||
@override
|
||||
Widget buildCenter(BuildContext context, {@required bool hasLeftOffset}) {
|
||||
return Expanded(
|
||||
child: Row(mainAxisAlignment: MainAxisAlignment.start, children: [
|
||||
if (hasLeftOffset) SizedBox(width: 10),
|
||||
Text(title,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: titleColor(context)))
|
||||
]));
|
||||
}
|
||||
|
||||
@override
|
||||
Widget buildTrailing(BuildContext context) =>
|
||||
isSelected
|
||||
? Icon(Icons.done, color: Palette.blueCraiola)
|
||||
: Offstage();
|
||||
}
|
|
@ -2,11 +2,11 @@ import 'package:flutter/material.dart';
|
|||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
|
||||
class SettingsCellWithArrow extends StandardListRow {
|
||||
SettingsCellWithArrow({@required String title})
|
||||
: super(title: title, isSelected: false);
|
||||
SettingsCellWithArrow({@required String title, @required Function(BuildContext context) handler})
|
||||
: super(title: title, isSelected: false, onTap: handler);
|
||||
|
||||
@override
|
||||
Widget buildTrailing(BuildContext context) =>
|
||||
Image.asset('assets/images/select_arrow.png',
|
||||
color: Theme.of(context).primaryTextTheme.caption.color);
|
||||
color: Theme.of(context).primaryTextTheme.overline.color);
|
||||
}
|
|
@ -1,5 +1,7 @@
|
|||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/src/widgets/standard_list.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class SettingsLinkProviderCell extends StandardListRow {
|
||||
SettingsLinkProviderCell(
|
||||
|
@ -7,7 +9,7 @@ class SettingsLinkProviderCell extends StandardListRow {
|
|||
@required this.icon,
|
||||
@required this.link,
|
||||
@required this.linkTitle})
|
||||
: super(title: title, isSelected: false);
|
||||
: super(title: title, isSelected: false, onTap: (BuildContext context) => _launchUrl(link) );
|
||||
|
||||
final String icon;
|
||||
final String link;
|
||||
|
@ -20,5 +22,11 @@ class SettingsLinkProviderCell extends StandardListRow {
|
|||
@override
|
||||
Widget buildTrailing(BuildContext context) => Text(linkTitle,
|
||||
style: TextStyle(
|
||||
fontSize: 14.0, fontWeight: FontWeight.w500, color: Colors.blue));
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Palette.blueCraiola));
|
||||
|
||||
static void _launchUrl(String url) async {
|
||||
if (await canLaunch(url)) await launch(url);
|
||||
}
|
||||
}
|
|
@ -8,7 +8,8 @@ class SettingsPickerCell<ItemType> extends StandardListRow {
|
|||
{@required String title,
|
||||
this.selectedItem,
|
||||
this.items,
|
||||
this.onItemSelected})
|
||||
this.onItemSelected,
|
||||
this.isAlwaysShowScrollThumb})
|
||||
: super(
|
||||
title: title,
|
||||
isSelected: false,
|
||||
|
@ -22,12 +23,15 @@ class SettingsPickerCell<ItemType> extends StandardListRow {
|
|||
selectedAtIndex: selectedAtIndex,
|
||||
title: S.current.please_select,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
onItemSelected: (ItemType item) => onItemSelected?.call(item)));
|
||||
isAlwaysShowScrollThumb: isAlwaysShowScrollThumb,
|
||||
onItemSelected: (ItemType item) =>
|
||||
onItemSelected?.call(item)));
|
||||
});
|
||||
|
||||
final ItemType selectedItem;
|
||||
final List<ItemType> items;
|
||||
final void Function(ItemType item) onItemSelected;
|
||||
final bool isAlwaysShowScrollThumb;
|
||||
|
||||
@override
|
||||
Widget buildTrailing(BuildContext context) {
|
||||
|
@ -37,7 +41,7 @@ class SettingsPickerCell<ItemType> extends StandardListRow {
|
|||
style: TextStyle(
|
||||
fontSize: 14.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color),
|
||||
color: Theme.of(context).primaryTextTheme.overline.color),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,9 +8,9 @@ class SettingsSwitcherCell extends StandardListRow {
|
|||
: super(title: title, isSelected: false);
|
||||
|
||||
final bool value;
|
||||
final void Function(bool value) onValueChange;
|
||||
final void Function(BuildContext context, bool value) onValueChange;
|
||||
|
||||
@override
|
||||
Widget buildTrailing(BuildContext context) =>
|
||||
StandartSwitch(value: value, onTaped: () => onValueChange(!value));
|
||||
Widget buildTrailing(BuildContext context) => StandartSwitch(
|
||||
value: value, onTaped: () => onValueChange(context, !value));
|
||||
}
|
||||
|
|
28
lib/src/screens/settings/widgets/settings_version_cell.dart
Normal file
|
@ -0,0 +1,28 @@
|
|||
import 'package:flutter/material.dart';
|
||||
|
||||
class SettingsVersionCell extends StatelessWidget {
|
||||
SettingsVersionCell({@required this.title});
|
||||
|
||||
final String title;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Padding(
|
||||
padding: EdgeInsets.only(bottom: 24),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.max,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
title,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).primaryTextTheme.overline.color
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -53,7 +53,7 @@ class _SetupPinCodeFormState<WidgetType extends SetupPinCodeForm>
|
|||
state.clear();
|
||||
} else {
|
||||
if (listEquals<int>(state.pin, _originalPin)) {
|
||||
final String pin = state.pin.fold("", (ac, val) => ac + '$val');
|
||||
final String pin = state.pin.fold('', (ac, val) => ac + '$val');
|
||||
_userStore.set(password: pin);
|
||||
_settingsStore.setDefaultPinLength(pinLength: state.pinLength);
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_list/wallet_list_view_model.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
@ -36,10 +37,14 @@ class WalletMenu {
|
|||
];
|
||||
|
||||
final List<Image> listImages = [
|
||||
Image.asset('assets/images/load.png', height: 24, width: 24, color: Colors.white),
|
||||
Image.asset('assets/images/eye_action.png', height: 24, width: 24, color: Colors.white),
|
||||
Image.asset('assets/images/trash.png', height: 24, width: 24, color: Colors.white),
|
||||
Image.asset('assets/images/scanner.png', height: 24, width: 24, color: Colors.white)
|
||||
Image.asset('assets/images/load.png',
|
||||
height: 24, width: 24, color: Colors.white),
|
||||
Image.asset('assets/images/eye_action.png',
|
||||
height: 24, width: 24, color: Colors.white),
|
||||
Image.asset('assets/images/trash.png',
|
||||
height: 24, width: 24, color: Colors.white),
|
||||
Image.asset('assets/images/scanner.png',
|
||||
height: 24, width: 24, color: Colors.white)
|
||||
];
|
||||
|
||||
List<String> generateItemsForWalletMenu(bool isCurrentWallet) {
|
||||
|
@ -87,10 +92,11 @@ class WalletMenu {
|
|||
return images;
|
||||
}
|
||||
|
||||
void action(int index, WalletListItem wallet, bool isCurrentWallet) {
|
||||
Future<void> action(
|
||||
int index, WalletListItem wallet, bool isCurrentWallet) async {
|
||||
switch (index) {
|
||||
case 0:
|
||||
Navigator.of(context).pushNamed(Routes.auth, arguments:
|
||||
await Navigator.of(context).pushNamed(Routes.auth, arguments:
|
||||
(bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
|
@ -110,7 +116,7 @@ class WalletMenu {
|
|||
});
|
||||
break;
|
||||
case 1:
|
||||
Navigator.of(context).pushNamed(Routes.auth, arguments:
|
||||
await Navigator.of(context).pushNamed(Routes.auth, arguments:
|
||||
(bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
|
@ -120,7 +126,23 @@ class WalletMenu {
|
|||
});
|
||||
break;
|
||||
case 2:
|
||||
Navigator.of(context).pushNamed(Routes.auth, arguments:
|
||||
final isComfirmed = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (BuildContext context) {
|
||||
return AlertWithTwoActions(
|
||||
alertTitle: 'Remove wallet',
|
||||
alertContent: S.of(context).confirm_delete_wallet,
|
||||
leftButtonText: S.of(context).cancel,
|
||||
rightButtonText: S.of(context).remove,
|
||||
actionLeftButton: () => Navigator.of(context).pop(false),
|
||||
actionRightButton: () => Navigator.of(context).pop(true));
|
||||
});
|
||||
|
||||
if (isComfirmed == null || !isComfirmed) {
|
||||
return;
|
||||
}
|
||||
|
||||
await Navigator.of(context).pushNamed(Routes.auth, arguments:
|
||||
(bool isAuthenticatedSuccessfully, AuthPageState auth) async {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
|
@ -139,7 +161,7 @@ class WalletMenu {
|
|||
});
|
||||
break;
|
||||
case 3:
|
||||
Navigator.of(context).pushNamed(Routes.rescan);
|
||||
await Navigator.of(context).pushNamed(Routes.rescan);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/palette.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/screens/base_page.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:cake_wallet/themes.dart';
|
||||
import 'package:cake_wallet/theme_changer.dart';
|
||||
|
||||
class WelcomePage extends BasePage {
|
||||
static const aspectRatioImage = 1.25;
|
||||
|
@ -23,14 +21,13 @@ class WelcomePage extends BasePage {
|
|||
|
||||
@override
|
||||
Widget body(BuildContext context) {
|
||||
final _themeChanger = Provider.of<ThemeChanger>(context);
|
||||
final welcomeImage = _themeChanger.getTheme() == Themes.darkTheme
|
||||
? welcomeImageDark : welcomeImageLight;
|
||||
final welcomeImage = getIt.get<SettingsStore>().isDarkTheme
|
||||
? welcomeImageDark : welcomeImageLight;
|
||||
|
||||
final newWalletImage = Image.asset('assets/images/new_wallet.png',
|
||||
height: 12,
|
||||
width: 12,
|
||||
color: Palette.oceanBlue);
|
||||
color: Theme.of(context).accentTextTheme.headline.decorationColor);
|
||||
final restoreWalletImage = Image.asset('assets/images/restore_wallet.png',
|
||||
height: 12,
|
||||
width: 12,
|
||||
|
@ -60,13 +57,14 @@ class WelcomePage extends BasePage {
|
|||
S.of(context).welcome,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).accentTextTheme.display3.color,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Text(
|
||||
S.of(context).cake_wallet,
|
||||
style: TextStyle(
|
||||
|
@ -78,13 +76,13 @@ class WelcomePage extends BasePage {
|
|||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 14),
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Text(
|
||||
S.of(context).first_wallet_text,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.w600,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).accentTextTheme.display3.color,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
|
@ -97,7 +95,8 @@ class WelcomePage extends BasePage {
|
|||
S.of(context).please_make_selection,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: Theme.of(context).accentTextTheme.display3.color,
|
||||
),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
|
@ -107,18 +106,17 @@ class WelcomePage extends BasePage {
|
|||
onPressed: () => Navigator.pushNamed(context, Routes.newWalletFromWelcome),
|
||||
image: newWalletImage,
|
||||
text: S.of(context).create_new,
|
||||
color: Colors.white,
|
||||
textColor: Palette.oceanBlue,
|
||||
borderColor: Palette.oceanBlue,
|
||||
color: Theme.of(context).accentTextTheme.subtitle.decorationColor,
|
||||
textColor: Theme.of(context).accentTextTheme.headline.decorationColor,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 10),
|
||||
child: PrimaryImageButton(
|
||||
onPressed: () => Navigator.pushNamed(context, Routes.restoreOptions),
|
||||
onPressed: () => Navigator.pushNamed(context, Routes.restoreWalletOptionsFromWelcome),
|
||||
image: restoreWalletImage,
|
||||
text: S.of(context).restore_wallet,
|
||||
color: Theme.of(context).primaryTextTheme.overline.color,
|
||||
color: Theme.of(context).accentTextTheme.caption.color,
|
||||
textColor: Theme.of(context).primaryTextTheme.title.color),
|
||||
)
|
||||
],
|
||||
|
|
|
@ -31,6 +31,7 @@ class BaseAlertDialog extends StatelessWidget {
|
|||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
fontSize: 16,
|
||||
fontWeight: FontWeight.normal,
|
||||
fontFamily: 'Poppins',
|
||||
color: Theme.of(context).primaryTextTheme.title.color,
|
||||
decoration: TextDecoration.none,
|
||||
|
|
|
@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:intl/intl.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/src/domain/monero/get_height_by_date.dart';
|
||||
import 'package:cake_wallet/src/widgets/base_text_form_field.dart';
|
||||
|
||||
class BlockchainHeightWidget extends StatefulWidget {
|
||||
BlockchainHeightWidget({GlobalKey key, this.onHeightChange})
|
||||
|
@ -46,26 +47,12 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
|
|||
Flexible(
|
||||
child: Container(
|
||||
padding: EdgeInsets.only(top: 20.0, bottom: 10.0),
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
child: BaseTextFormField(
|
||||
controller: restoreHeightController,
|
||||
keyboardType: TextInputType.numberWithOptions(
|
||||
signed: false, decimal: false),
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context).primaryTextTheme.caption.color,
|
||||
fontSize: 16),
|
||||
hintText: S.of(context).widgets_restore_from_blockheight,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor, width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))),
|
||||
),
|
||||
hintText: S.of(context).widgets_restore_from_blockheight,
|
||||
)
|
||||
))
|
||||
],
|
||||
),
|
||||
|
@ -75,7 +62,7 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
|
|||
S.of(context).widgets_or,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
),
|
||||
|
@ -86,31 +73,10 @@ class BlockchainHeightState extends State<BlockchainHeightWidget> {
|
|||
child: InkWell(
|
||||
onTap: () => _selectDate(context),
|
||||
child: IgnorePointer(
|
||||
child: TextFormField(
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
color: Theme.of(context).primaryTextTheme.title.color),
|
||||
decoration: InputDecoration(
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.caption
|
||||
.color,
|
||||
fontSize: 16),
|
||||
hintText: S.of(context).widgets_restore_from_date,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
width: 1.0))),
|
||||
child: BaseTextFormField(
|
||||
controller: dateController,
|
||||
validator: (value) {
|
||||
return null;
|
||||
},
|
||||
),
|
||||
hintText: S.of(context).widgets_restore_from_date,
|
||||
)
|
||||
),
|
||||
),
|
||||
))
|
||||
|
|
|
@ -123,9 +123,7 @@ class PickerState<Item> extends State<Picker> {
|
|||
mainAxisAlignment: widget.mainAxisAlignment,
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: <Widget>[
|
||||
image != null
|
||||
? image
|
||||
: Offstage(),
|
||||
image ?? Offstage(),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: image != null ? 12 : 0
|
||||
|
|
|
@ -34,14 +34,14 @@ class SeedLanguageSelectorState extends State<SeedLanguageSelector> {
|
|||
return SelectButton(
|
||||
image: null,
|
||||
text: seedLocales[seedLanguages.indexOf(selected)],
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor,
|
||||
textColor: Theme.of(context).primaryTextTheme.title.color,
|
||||
onTap: () async {
|
||||
final selected = await showDialog<String>(
|
||||
context: context,
|
||||
builder: (BuildContext context) =>
|
||||
SeedLanguagePicker(key: _pickerKey, selected: this.selected));
|
||||
setState(() => this.selected = selected);
|
||||
if (selected != null) {
|
||||
setState(() => this.selected = selected);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,6 +6,7 @@ import 'package:cake_wallet/core/seed_validator.dart';
|
|||
import 'package:cake_wallet/src/widgets/primary_button.dart';
|
||||
import 'package:cake_wallet/src/domain/common/mnemonic_item.dart';
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
class SeedWidget extends StatefulWidget {
|
||||
SeedWidget(
|
||||
|
@ -13,6 +14,8 @@ class SeedWidget extends StatefulWidget {
|
|||
this.maxLength,
|
||||
this.onMnemonicChange,
|
||||
this.onFinish,
|
||||
this.leading,
|
||||
this.middle,
|
||||
this.validator})
|
||||
: super(key: key);
|
||||
|
||||
|
@ -20,6 +23,8 @@ class SeedWidget extends StatefulWidget {
|
|||
final Function(List<MnemonicItem>) onMnemonicChange;
|
||||
final Function() onFinish;
|
||||
final SeedValidator validator;
|
||||
final Widget leading;
|
||||
final Widget middle;
|
||||
|
||||
@override
|
||||
SeedWidgetState createState() => SeedWidgetState(maxLength: maxLength);
|
||||
|
@ -199,74 +204,90 @@ class SeedWidgetState extends State<SeedWidget> {
|
|||
child: Column(children: [
|
||||
Flexible(
|
||||
fit: FlexFit.tight,
|
||||
flex: 1,
|
||||
flex: 2,
|
||||
child: Container(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
padding: EdgeInsets.all(24),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(24),
|
||||
bottomRight: Radius.circular(24)),
|
||||
color: Theme.of(context).accentTextTheme.title.backgroundColor),
|
||||
child: SingleChildScrollView(
|
||||
width: double.infinity,
|
||||
height: double.infinity,
|
||||
padding: EdgeInsets.all(0),
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.only(
|
||||
bottomLeft: Radius.circular(24),
|
||||
bottomRight: Radius.circular(24)),
|
||||
gradient: LinearGradient(colors: [
|
||||
Theme.of(context).primaryTextTheme.subhead.color,
|
||||
Theme.of(context).primaryTextTheme.subhead.decorationColor,
|
||||
], begin: Alignment.topLeft, end: Alignment.bottomRight)),
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).restore_active_seed,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color:
|
||||
Theme.of(context).primaryTextTheme.caption.color),
|
||||
CupertinoNavigationBar(
|
||||
leading: widget.leading,
|
||||
middle: widget.middle,
|
||||
backgroundColor: Colors.transparent,
|
||||
border: null,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Wrap(
|
||||
children: items.map((item) {
|
||||
final isValid = widget.validator.isValid(item);
|
||||
final isSelected = selectedItem == item;
|
||||
Expanded(
|
||||
child: Container(
|
||||
padding: EdgeInsets.all(24),
|
||||
alignment: Alignment.topLeft,
|
||||
child: SingleChildScrollView(
|
||||
child: Column(
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: <Widget>[
|
||||
Text(
|
||||
S.of(context).restore_active_seed,
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context)
|
||||
.textTheme
|
||||
.overline
|
||||
.backgroundColor),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(top: 5),
|
||||
child: Wrap(
|
||||
children: items.map((item) {
|
||||
final isValid =
|
||||
widget.validator.isValid(item);
|
||||
final isSelected = selectedItem == item;
|
||||
|
||||
return InkWell(
|
||||
onTap: () => onMnemonicTap(item),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: isValid
|
||||
? Colors.transparent
|
||||
: Palette.red),
|
||||
margin: EdgeInsets.only(right: 7, bottom: 8),
|
||||
child: Text(
|
||||
item.toString(),
|
||||
style: TextStyle(
|
||||
color: isValid
|
||||
? Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
.color
|
||||
: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.caption
|
||||
.color,
|
||||
fontSize: 16,
|
||||
fontWeight: isSelected
|
||||
? FontWeight.w900
|
||||
: FontWeight.w400,
|
||||
decoration: isSelected
|
||||
? TextDecoration.underline
|
||||
: TextDecoration.none),
|
||||
)),
|
||||
);
|
||||
}).toList(),
|
||||
))
|
||||
return InkWell(
|
||||
onTap: () => onMnemonicTap(item),
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
color: isValid
|
||||
? Colors.transparent
|
||||
: Palette.red),
|
||||
margin: EdgeInsets.only(
|
||||
right: 7, bottom: 8),
|
||||
child: Text(
|
||||
item.toString(),
|
||||
style: TextStyle(
|
||||
color: isValid
|
||||
? Colors.white
|
||||
: Colors.grey,
|
||||
fontSize: 16,
|
||||
fontWeight: isSelected
|
||||
? FontWeight.w900
|
||||
: FontWeight.w600,
|
||||
decoration: isSelected
|
||||
? TextDecoration.underline
|
||||
: TextDecoration.none),
|
||||
)),
|
||||
);
|
||||
}).toList(),
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
))
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)),
|
||||
),
|
||||
Flexible(
|
||||
fit: FlexFit.tight,
|
||||
flex: 2,
|
||||
flex: 3,
|
||||
child: Padding(
|
||||
padding:
|
||||
EdgeInsets.only(left: 24, top: 48, right: 24, bottom: 24),
|
||||
|
@ -277,8 +298,8 @@ class SeedWidgetState extends State<SeedWidget> {
|
|||
Text(
|
||||
S.of(context).restore_new_seed,
|
||||
style: TextStyle(
|
||||
fontSize: 18,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 20,
|
||||
fontWeight: FontWeight.w500,
|
||||
color:
|
||||
Theme.of(context).primaryTextTheme.title.color),
|
||||
),
|
||||
|
@ -291,6 +312,7 @@ class SeedWidgetState extends State<SeedWidget> {
|
|||
: null,
|
||||
style: TextStyle(
|
||||
fontSize: 16.0,
|
||||
fontWeight: FontWeight.normal,
|
||||
color:
|
||||
Theme.of(context).primaryTextTheme.title.color),
|
||||
controller: _seedController,
|
||||
|
@ -306,10 +328,11 @@ class SeedWidgetState extends State<SeedWidget> {
|
|||
Text('${items.length}/$maxLength',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.caption
|
||||
.color,
|
||||
fontSize: 14)),
|
||||
.accentTextTheme
|
||||
.display2
|
||||
.decorationColor,
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 16)),
|
||||
SizedBox(width: 10),
|
||||
InkWell(
|
||||
onTap: () async =>
|
||||
|
@ -322,17 +345,14 @@ class SeedWidgetState extends State<SeedWidget> {
|
|||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.title
|
||||
.backgroundColor,
|
||||
.caption
|
||||
.color,
|
||||
borderRadius:
|
||||
BorderRadius.circular(10.0)),
|
||||
child: Text(
|
||||
S.of(context).paste,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.title
|
||||
.color),
|
||||
color: Palette.blueCraiola),
|
||||
)),
|
||||
)
|
||||
],
|
||||
|
@ -341,20 +361,27 @@ class SeedWidgetState extends State<SeedWidget> {
|
|||
),
|
||||
hintStyle: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.primaryTextTheme
|
||||
.caption
|
||||
.color,
|
||||
.accentTextTheme
|
||||
.display2
|
||||
.decorationColor,
|
||||
fontWeight: FontWeight.normal,
|
||||
fontSize: 16),
|
||||
hintText:
|
||||
S.of(context).restore_from_seed_placeholder,
|
||||
errorText: _errorMessage,
|
||||
focusedBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.subtitle
|
||||
.backgroundColor,
|
||||
width: 1.0)),
|
||||
enabledBorder: UnderlineInputBorder(
|
||||
borderSide: BorderSide(
|
||||
color: Theme.of(context).dividerColor,
|
||||
color: Theme.of(context)
|
||||
.accentTextTheme
|
||||
.subtitle
|
||||
.backgroundColor,
|
||||
width: 1.0))),
|
||||
enableInteractiveSelection: false,
|
||||
),
|
||||
|
@ -386,7 +413,7 @@ class SeedWidgetState extends State<SeedWidget> {
|
|||
onPressed: () => widget.onFinish != null
|
||||
? widget.onFinish()
|
||||
: null,
|
||||
color: Colors.green,
|
||||
color: Palette.blueCraiola,
|
||||
textColor: Colors.white)
|
||||
: PrimaryButton(
|
||||
text: selectedItem != null
|
||||
|
@ -397,7 +424,7 @@ class SeedWidgetState extends State<SeedWidget> {
|
|||
: null,
|
||||
onDisabledPressed: () => showErrorIfExist(),
|
||||
isDisabled: !isCurrentMnemonicValid,
|
||||
color: Colors.green,
|
||||
color: Palette.blueCraiola,
|
||||
textColor: Colors.white),
|
||||
),
|
||||
)
|
||||
|
|
|
@ -41,18 +41,17 @@ class StandardListRow extends StatelessWidget {
|
|||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.normal,
|
||||
color: _titleColor(context)))
|
||||
color: titleColor(context)))
|
||||
]));
|
||||
}
|
||||
|
||||
Widget buildTrailing(BuildContext context) => null;
|
||||
|
||||
Color _titleColor(BuildContext context) => isSelected
|
||||
Color titleColor(BuildContext context) => isSelected
|
||||
? Palette.blueCraiola
|
||||
: Theme.of(context).primaryTextTheme.title.color;
|
||||
|
||||
Color _backgroundColor(BuildContext context) {
|
||||
// return Theme.of(context).accentTextTheme.subtitle.decorationColor;
|
||||
return Theme.of(context).backgroundColor;
|
||||
}
|
||||
}
|
||||
|
@ -114,16 +113,20 @@ class SectionStandardList extends StatelessWidget {
|
|||
{@required this.itemCounter,
|
||||
@required this.itemBuilder,
|
||||
@required this.sectionCount,
|
||||
this.hasTopSeparator = false,
|
||||
BuildContext context})
|
||||
: totalRows = transform(context, sectionCount, itemCounter, itemBuilder);
|
||||
: totalRows = transform(hasTopSeparator, context, sectionCount,
|
||||
itemCounter, itemBuilder);
|
||||
|
||||
final int sectionCount;
|
||||
final bool hasTopSeparator;
|
||||
final int Function(int sectionIndex) itemCounter;
|
||||
final Widget Function(BuildContext context, int sectionIndex, int itemIndex)
|
||||
itemBuilder;
|
||||
final List<Widget> totalRows;
|
||||
|
||||
static List<Widget> transform(
|
||||
bool hasTopSeparator,
|
||||
BuildContext context,
|
||||
int sectionCount,
|
||||
int Function(int sectionIndex) itemCounter,
|
||||
|
@ -132,9 +135,9 @@ class SectionStandardList extends StatelessWidget {
|
|||
final items = <Widget>[];
|
||||
|
||||
for (var sectionIndex = 0; sectionIndex < sectionCount; sectionIndex++) {
|
||||
/*if (sectionIndex == 0) {
|
||||
items.add(StandardListSeparator());
|
||||
}*/
|
||||
if ((sectionIndex == 0)&&(hasTopSeparator)) {
|
||||
items.add(StandardListSeparator(padding: EdgeInsets.only(left: 24)));
|
||||
}
|
||||
|
||||
final itemCount = itemCounter(sectionIndex);
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@ class StandartSwitchState extends State<StandartSwitch> {
|
|||
decoration: BoxDecoration(
|
||||
color: widget.value
|
||||
? Colors.green
|
||||
: PaletteDark.distantBlue,
|
||||
: Theme.of(context).accentTextTheme.display4.color,
|
||||
borderRadius: BorderRadius.all(Radius.circular(14.0))),
|
||||
child: Container(
|
||||
width: 24.0,
|
||||
|
|
|
@ -44,9 +44,14 @@ abstract class SettingsStoreBase with Store {
|
|||
languageCode = initialLanguageCode;
|
||||
currentLocale = initialCurrentLocale;
|
||||
itemHeaders = {};
|
||||
this.nodes = ObservableMap<WalletType, Node>.of(nodes);
|
||||
_sharedPreferences = sharedPreferences;
|
||||
_nodeSource = nodeSource;
|
||||
_nodes = nodes;
|
||||
|
||||
reaction(
|
||||
(_) => allowBiometricalAuthentication,
|
||||
(bool biometricalAuthentication) => sharedPreferences.setBool(
|
||||
allowBiometricalAuthenticationKey, biometricalAuthentication));
|
||||
}
|
||||
|
||||
static const currentNodeIdKey = 'current_node_id';
|
||||
|
@ -62,9 +67,6 @@ abstract class SettingsStoreBase with Store {
|
|||
static const currentPinLength = 'current_pin_length';
|
||||
static const currentLanguageCode = 'language_code';
|
||||
|
||||
// @observable
|
||||
// Node node;
|
||||
|
||||
@observable
|
||||
FiatCurrency fiatCurrency;
|
||||
|
||||
|
@ -101,9 +103,9 @@ abstract class SettingsStoreBase with Store {
|
|||
SharedPreferences _sharedPreferences;
|
||||
Box<Node> _nodeSource;
|
||||
|
||||
Map<WalletType, Node> _nodes;
|
||||
ObservableMap<WalletType, Node> nodes;
|
||||
|
||||
Node getCurrentNode(WalletType walletType) => _nodes[walletType];
|
||||
Node getCurrentNode(WalletType walletType) => nodes[walletType];
|
||||
|
||||
Future<void> setCurrentNode(Node node, WalletType walletType) async {
|
||||
switch (walletType) {
|
||||
|
@ -118,7 +120,7 @@ abstract class SettingsStoreBase with Store {
|
|||
break;
|
||||
}
|
||||
|
||||
_nodes[walletType] = node;
|
||||
nodes[walletType] = node;
|
||||
}
|
||||
|
||||
static Future<SettingsStore> load(
|
||||
|
|
|
@ -154,7 +154,19 @@ class Themes {
|
|||
),
|
||||
display2: TextStyle(
|
||||
color: Palette.shadowWhite, // action button color (address text field)
|
||||
decorationColor: Palette.darkGray // hint text (seed widget)
|
||||
),
|
||||
display3: TextStyle(
|
||||
color: Palette.darkGray, // hint text (new wallet page)
|
||||
decorationColor: Palette.periwinkleCraiola // underline (new wallet page)
|
||||
),
|
||||
display4: TextStyle(
|
||||
color: Palette.darkGray, // switch background (settings page)
|
||||
),
|
||||
body1: TextStyle(
|
||||
color: Palette.darkGray, // indicators (PIN code)
|
||||
decorationColor: Palette.darkGray // switch (PIN code)
|
||||
)
|
||||
),
|
||||
|
||||
|
||||
|
@ -320,7 +332,19 @@ class Themes {
|
|||
),
|
||||
display2: TextStyle(
|
||||
color: PaletteDark.nightBlue, // action button color (address text field)
|
||||
decorationColor: PaletteDark.darkCyanBlue // hint text (seed widget)
|
||||
),
|
||||
display3: TextStyle(
|
||||
color: PaletteDark.cyanBlue, // hint text (new wallet page)
|
||||
decorationColor: PaletteDark.darkGrey // underline (new wallet page)
|
||||
),
|
||||
display4: TextStyle(
|
||||
color: PaletteDark.deepVioletBlue, // switch background (settings page)
|
||||
),
|
||||
body1: TextStyle(
|
||||
color: PaletteDark.indicatorVioletBlue, // indicators (PIN code)
|
||||
decorationColor: PaletteDark.lightPurpleBlue // switch (PIN code)
|
||||
)
|
||||
),
|
||||
|
||||
|
||||
|
|
11
lib/utils/item_cell.dart
Normal file
|
@ -0,0 +1,11 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cake_wallet/utils/mobx.dart';
|
||||
|
||||
class ItemCell<Item> with Keyable {
|
||||
ItemCell(this.value, {@required this.isSelected, @required dynamic key}) {
|
||||
keyIndex = key;
|
||||
}
|
||||
|
||||
final Item value;
|
||||
final bool isSelected;
|
||||
}
|
|
@ -1,46 +1,90 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
void connectDifferent<T, Y>(
|
||||
mixin Keyable {
|
||||
dynamic keyIndex;
|
||||
}
|
||||
|
||||
void connectDifferent<T extends Keyable, Y extends Keyable>(
|
||||
ObservableList<T> source, ObservableList<Y> dest, Y Function(T) transform,
|
||||
{bool Function(T) filter}) {
|
||||
source.observe((ListChange<T> change) {
|
||||
// switch (change.type) {
|
||||
// case OperationType.add:
|
||||
// final _values = change.added;
|
||||
// Iterable<T> values;
|
||||
change.elementChanges.forEach((change) {
|
||||
switch (change.type) {
|
||||
case OperationType.add:
|
||||
if (filter?.call(change.newValue as T) ?? true) {
|
||||
dest.add(transform(change.newValue as T));
|
||||
}
|
||||
break;
|
||||
case OperationType.remove:
|
||||
// Hive could has equal index and key
|
||||
dest.removeWhere(
|
||||
(elem) => elem.keyIndex == (change.oldValue.key ?? change.index));
|
||||
break;
|
||||
case OperationType.update:
|
||||
for (var i = 0; i < dest.length; i++) {
|
||||
final item = dest[i];
|
||||
|
||||
// if (filter != null) {
|
||||
// values = _values.where(filter);
|
||||
// }
|
||||
|
||||
// dest.addAll(values.map((e) => transform(e)));
|
||||
// break;
|
||||
// case OperationType.remove:
|
||||
// change.removed.forEach((element) {
|
||||
// dest.remove(element);
|
||||
// });
|
||||
|
||||
// // dest.removeAt(change.index);
|
||||
// break;
|
||||
// case OperationType.update:
|
||||
// // change.index
|
||||
// break;
|
||||
// }
|
||||
if (item.keyIndex == change.newValue.key) {
|
||||
dest[i] = transform(change.newValue as T);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
void connect<T>(ObservableList<T> source, ObservableList<T> dest) {
|
||||
void connect<T extends Keyable>(
|
||||
ObservableList<T> source, ObservableList<T> dest) {
|
||||
source.observe((ListChange<T> change) {
|
||||
// switch (change.type) {
|
||||
// case OperationType.add:
|
||||
// dest.addAll(change.added);
|
||||
// break;
|
||||
// case OperationType.remove:
|
||||
// dest.removeAt(change.index);
|
||||
// break;
|
||||
// case OperationType.update:
|
||||
// // change.index
|
||||
// break;
|
||||
// }
|
||||
source.observe((ListChange<T> change) {
|
||||
change.elementChanges.forEach((change) {
|
||||
switch (change.type) {
|
||||
case OperationType.add:
|
||||
// if (filter?.call(change.newValue as T) ?? true) {
|
||||
dest.add(change.newValue as T);
|
||||
// }
|
||||
break;
|
||||
case OperationType.remove:
|
||||
// Hive could has equal index and key
|
||||
dest.removeWhere((elem) =>
|
||||
elem.keyIndex == (change.oldValue.key ?? change.index));
|
||||
break;
|
||||
case OperationType.update:
|
||||
for (var i = 0; i < dest.length; i++) {
|
||||
final item = dest[i];
|
||||
|
||||
if (item.keyIndex == change.newValue.key) {
|
||||
dest[i] = change.newValue as T;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
StreamSubscription<BoxEvent> bindBox<T extends Keyable>(
|
||||
Box<T> source, ObservableList<T> dest) {
|
||||
return source.watch().listen((event) {
|
||||
if (event.deleted) {
|
||||
dest.removeWhere((el) => el.keyIndex == event.key);
|
||||
}
|
||||
|
||||
final dynamic value = event.value;
|
||||
|
||||
if (value is T) {
|
||||
final elIndex = dest.indexWhere((el) => el.keyIndex == value.keyIndex);
|
||||
|
||||
if (elIndex > -1) {
|
||||
dest[elIndex] = value;
|
||||
} else {
|
||||
dest.add(value);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,20 +1,34 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/core/contact_service.dart';
|
||||
import 'package:cake_wallet/store/contact_list_store.dart';
|
||||
import 'package:cake_wallet/src/domain/common/contact.dart';
|
||||
import 'package:cake_wallet/utils/mobx.dart';
|
||||
|
||||
part 'contact_list_view_model.g.dart';
|
||||
|
||||
class ContactListViewModel = ContactListViewModelBase with _$ContactListViewModel;
|
||||
class ContactListViewModel = ContactListViewModelBase
|
||||
with _$ContactListViewModel;
|
||||
|
||||
abstract class ContactListViewModelBase with Store {
|
||||
ContactListViewModelBase(this.addressBookStore, this.contactService);
|
||||
ContactListViewModelBase(
|
||||
this.addressBookStore, this.contactService, this.contactSource) {
|
||||
_subscription = bindBox(contactSource, addressBookStore.contacts);
|
||||
}
|
||||
|
||||
final ContactListStore addressBookStore;
|
||||
final ContactService contactService;
|
||||
final Box<Contact> contactSource;
|
||||
|
||||
@computed
|
||||
ObservableList<Contact> get contacts => addressBookStore.contacts;
|
||||
|
||||
StreamSubscription<BoxEvent> _subscription;
|
||||
|
||||
void dispose() {
|
||||
_subscription.cancel();
|
||||
}
|
||||
|
||||
Future<void> delete(Contact contact) async => contactService.delete(contact);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/core/wallet_base.dart';
|
||||
import 'package:cake_wallet/core/contact_service.dart';
|
||||
|
@ -10,7 +11,7 @@ part 'contact_view_model.g.dart';
|
|||
class ContactViewModel = ContactViewModelBase with _$ContactViewModel;
|
||||
|
||||
abstract class ContactViewModelBase with Store {
|
||||
ContactViewModelBase(this._contactService, this._wallet, {Contact contact})
|
||||
ContactViewModelBase(this._contacts, this._wallet, {Contact contact})
|
||||
: state = InitialContactViewModelState(),
|
||||
currencies = CryptoCurrency.all,
|
||||
_contact = contact {
|
||||
|
@ -33,12 +34,14 @@ abstract class ContactViewModelBase with Store {
|
|||
|
||||
@computed
|
||||
bool get isReady =>
|
||||
(name?.isNotEmpty ?? false) && (currency?.toString()?.isNotEmpty ?? false)
|
||||
&& (address?.isNotEmpty ?? false);
|
||||
(name?.isNotEmpty ?? false) &&
|
||||
(currency?.toString()?.isNotEmpty ?? false) &&
|
||||
(address?.isNotEmpty ?? false);
|
||||
|
||||
final List<CryptoCurrency> currencies;
|
||||
final ContactService _contactService;
|
||||
// final ContactService _contactService;
|
||||
final WalletBase _wallet;
|
||||
final Box<Contact> _contacts;
|
||||
final Contact _contact;
|
||||
|
||||
@action
|
||||
|
@ -57,10 +60,13 @@ abstract class ContactViewModelBase with Store {
|
|||
_contact.name = name;
|
||||
_contact.address = address;
|
||||
_contact.updateCryptoCurrency(currency: currency);
|
||||
await _contactService.update(_contact);
|
||||
await _contacts.put(_contact.key, _contact);
|
||||
// await _contactService.update(_contact);
|
||||
} else {
|
||||
await _contactService
|
||||
await _contacts
|
||||
.add(Contact(name: name, address: address, type: currency));
|
||||
// await _contactService
|
||||
// .add(Contact(name: name, address: address, type: currency));
|
||||
}
|
||||
|
||||
state = ContactSavingSuccessfully();
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'package:cake_wallet/utils/item_cell.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
@ -14,13 +15,6 @@ part 'node_list_view_model.g.dart';
|
|||
|
||||
class NodeListViewModel = NodeListViewModelBase with _$NodeListViewModel;
|
||||
|
||||
class ItemCell<Item> {
|
||||
ItemCell(this.value, {@required this.isSelected});
|
||||
|
||||
final Item value;
|
||||
final bool isSelected;
|
||||
}
|
||||
|
||||
abstract class NodeListViewModelBase with Store {
|
||||
NodeListViewModelBase(
|
||||
this._nodeListStore, this._nodeSource, this._wallet, this._settingsStore)
|
||||
|
@ -29,16 +23,16 @@ abstract class NodeListViewModelBase with Store {
|
|||
final values = _nodeListStore.nodes;
|
||||
nodes.clear();
|
||||
nodes.addAll(values.where((Node node) => node.type == _wallet.type).map(
|
||||
(Node val) =>
|
||||
ItemCell<Node>(val, isSelected: val.key == currentNode.key)));
|
||||
(Node val) => ItemCell<Node>(val,
|
||||
isSelected: val.key == currentNode.key, key: val.key)));
|
||||
connectDifferent(
|
||||
_nodeListStore.nodes,
|
||||
nodes,
|
||||
(Node val) =>
|
||||
ItemCell<Node>(val, isSelected: val.key == currentNode.key),
|
||||
filter: (Node val) {
|
||||
return val.type == _wallet.type;
|
||||
});
|
||||
(Node val) => ItemCell<Node>(val,
|
||||
isSelected: val.key == currentNode.key, key: val.key),
|
||||
filter: (Node val) => val.type == _wallet.type);
|
||||
reaction((_) => _settingsStore.nodes[_wallet.type],
|
||||
(Node _) => _updateCurrentNode());
|
||||
}
|
||||
|
||||
ObservableList<ItemCell<Node>> nodes;
|
||||
|
@ -66,17 +60,18 @@ abstract class NodeListViewModelBase with Store {
|
|||
break;
|
||||
}
|
||||
|
||||
await _wallet.connectToNode(node: node);
|
||||
await setAsCurrent(node);
|
||||
}
|
||||
|
||||
Future<void> delete(Node node) async => _nodeSource.delete(node.key);
|
||||
|
||||
Future<void> setAsCurrent(Node node) async {
|
||||
await _wallet.connectToNode(node: node);
|
||||
await _settingsStore.setCurrentNode(node, _wallet.type);
|
||||
_updateCurrentNode();
|
||||
await _wallet.connectToNode(node: node);
|
||||
}
|
||||
|
||||
@action
|
||||
void _updateCurrentNode() {
|
||||
final currentNode = _settingsStore.getCurrentNode(_wallet.type);
|
||||
|
||||
|
@ -85,7 +80,8 @@ abstract class NodeListViewModelBase with Store {
|
|||
final isSelected = item.value.key == currentNode.key;
|
||||
|
||||
if (item.isSelected != isSelected) {
|
||||
nodes[i] = ItemCell<Node>(item.value, isSelected: isSelected);
|
||||
nodes[i] = ItemCell<Node>(item.value,
|
||||
isSelected: isSelected, key: item.keyIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,13 +6,15 @@ class PickerListItem<ItemType> extends SettingsListItem {
|
|||
{@required String title,
|
||||
@required this.selectedItem,
|
||||
@required this.items,
|
||||
void Function(ItemType item) onItemSelected})
|
||||
void Function(ItemType item) onItemSelected,
|
||||
this.isAlwaysShowScrollThumb = false})
|
||||
: _onItemSelected = onItemSelected,
|
||||
super(title);
|
||||
|
||||
final ItemType Function() selectedItem;
|
||||
final List<ItemType> items;
|
||||
final void Function(ItemType item) _onItemSelected;
|
||||
final bool isAlwaysShowScrollThumb;
|
||||
|
||||
void onItemSelected(dynamic item) {
|
||||
if (item is ItemType) {
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
import 'package:cake_wallet/core/wallet_base.dart';
|
||||
import 'package:cake_wallet/src/domain/common/biometric_auth.dart';
|
||||
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
|
||||
import 'package:cake_wallet/di.dart';
|
||||
import 'package:cake_wallet/store/theme_changer_store.dart';
|
||||
import 'package:cake_wallet/themes.dart';
|
||||
import 'package:cake_wallet/view_model/settings/version_list_item.dart';
|
||||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
|
@ -19,6 +21,7 @@ import 'package:cake_wallet/view_model/settings/picker_list_item.dart';
|
|||
import 'package:cake_wallet/view_model/settings/regular_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/settings/settings_list_item.dart';
|
||||
import 'package:cake_wallet/view_model/settings/switcher_list_item.dart';
|
||||
import 'package:package_info/package_info.dart';
|
||||
|
||||
part 'settings_view_model.g.dart';
|
||||
|
||||
|
@ -27,7 +30,11 @@ class SettingsViewModel = SettingsViewModelBase with _$SettingsViewModel;
|
|||
abstract class SettingsViewModelBase with Store {
|
||||
SettingsViewModelBase(this._settingsStore, WalletBase wallet)
|
||||
: itemHeaders = {},
|
||||
_walletType = wallet.type {
|
||||
_walletType = wallet.type,
|
||||
_biometricAuth = BiometricAuth() {
|
||||
currentVersion = '';
|
||||
PackageInfo.fromPlatform().then(
|
||||
(PackageInfo packageInfo) => currentVersion = packageInfo.version);
|
||||
sections = [
|
||||
[
|
||||
PickerListItem(
|
||||
|
@ -37,17 +44,22 @@ abstract class SettingsViewModelBase with Store {
|
|||
PickerListItem(
|
||||
title: S.current.settings_currency,
|
||||
items: FiatCurrency.all,
|
||||
selectedItem: () => fiatCurrency),
|
||||
isAlwaysShowScrollThumb: true,
|
||||
selectedItem: () => fiatCurrency,
|
||||
onItemSelected: (FiatCurrency currency) =>
|
||||
setFiatCurrency(currency)),
|
||||
PickerListItem(
|
||||
title: S.current.settings_fee_priority,
|
||||
items: _transactionPriorities(wallet.type),
|
||||
selectedItem: () => transactionPriority,
|
||||
isAlwaysShowScrollThumb: true,
|
||||
onItemSelected: (TransactionPriority priority) =>
|
||||
_settingsStore.transactionPriority = priority),
|
||||
SwitcherListItem(
|
||||
title: S.current.settings_save_recipient_address,
|
||||
value: () => shouldSaveRecipientAddress,
|
||||
onValueChange: (bool value) => setShouldSaveRecipientAddress(value))
|
||||
onValueChange: (_, bool value) =>
|
||||
setShouldSaveRecipientAddress(value))
|
||||
],
|
||||
[
|
||||
RegularListItem(
|
||||
|
@ -72,12 +84,32 @@ abstract class SettingsViewModelBase with Store {
|
|||
SwitcherListItem(
|
||||
title: S.current.settings_allow_biometrical_authentication,
|
||||
value: () => allowBiometricalAuthentication,
|
||||
onValueChange: (bool value) =>
|
||||
setAllowBiometricalAuthentication(value)),
|
||||
onValueChange: (BuildContext context, bool value) {
|
||||
if (value) {
|
||||
Navigator.of(context).pushNamed(Routes.auth, arguments:
|
||||
(bool isAuthenticatedSuccessfully,
|
||||
AuthPageState auth) async {
|
||||
if (isAuthenticatedSuccessfully) {
|
||||
if (await _biometricAuth.canCheckBiometrics() &&
|
||||
await _biometricAuth.isAuthenticated()) {
|
||||
setAllowBiometricalAuthentication(
|
||||
isAuthenticatedSuccessfully);
|
||||
}
|
||||
} else {
|
||||
setAllowBiometricalAuthentication(
|
||||
isAuthenticatedSuccessfully);
|
||||
}
|
||||
|
||||
Navigator.of(context).pop();
|
||||
});
|
||||
} else {
|
||||
setAllowBiometricalAuthentication(value);
|
||||
}
|
||||
}),
|
||||
SwitcherListItem(
|
||||
title: S.current.settings_dark_mode,
|
||||
value: () => _settingsStore.isDarkTheme,
|
||||
onValueChange: (bool value) {
|
||||
onValueChange: (_, bool value) {
|
||||
_settingsStore.isDarkTheme = value;
|
||||
getIt
|
||||
.get<ThemeChangerStore>()
|
||||
|
@ -119,11 +151,20 @@ abstract class SettingsViewModelBase with Store {
|
|||
title: S.current.settings_terms_and_conditions,
|
||||
handler: (BuildContext context) =>
|
||||
Navigator.of(context).pushNamed(Routes.disclaimer),
|
||||
),
|
||||
RegularListItem(
|
||||
title: S.current.faq,
|
||||
handler: (BuildContext context) =>
|
||||
Navigator.pushNamed(context, Routes.faq),
|
||||
)
|
||||
]
|
||||
],
|
||||
[VersionListItem(title: currentVersion)]
|
||||
];
|
||||
}
|
||||
|
||||
@observable
|
||||
String currentVersion;
|
||||
|
||||
@computed
|
||||
Node get node => _settingsStore.getCurrentNode(_walletType);
|
||||
|
||||
|
@ -151,10 +192,18 @@ abstract class SettingsViewModelBase with Store {
|
|||
_settingsStore.allowBiometricalAuthentication;
|
||||
|
||||
final Map<String, String> itemHeaders;
|
||||
List<List<SettingsListItem>> sections;
|
||||
final SettingsStore _settingsStore;
|
||||
final WalletType _walletType;
|
||||
List<List<SettingsListItem>> sections;
|
||||
final BiometricAuth _biometricAuth;
|
||||
|
||||
@action
|
||||
void setBalanceDisplayMode(BalanceDisplayMode value) =>
|
||||
_settingsStore.balanceDisplayMode = value;
|
||||
|
||||
@action
|
||||
void setFiatCurrency(FiatCurrency value) =>
|
||||
_settingsStore.fiatCurrency = value;
|
||||
@action
|
||||
void setShouldSaveRecipientAddress(bool value) =>
|
||||
_settingsStore.shouldSaveRecipientAddress = value;
|
||||
|
@ -190,11 +239,6 @@ abstract class SettingsViewModelBase with Store {
|
|||
@action
|
||||
void _showTrades() => actionlistDisplayMode.add(ActionListDisplayMode.trades);
|
||||
|
||||
//
|
||||
// @observable
|
||||
// int defaultPinLength;
|
||||
// bool isDarkTheme;
|
||||
|
||||
static List<TransactionPriority> _transactionPriorities(WalletType type) {
|
||||
switch (type) {
|
||||
case WalletType.monero:
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import 'package:flutter/cupertino.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cake_wallet/view_model/settings/settings_list_item.dart';
|
||||
|
||||
class SwitcherListItem extends SettingsListItem {
|
||||
SwitcherListItem(
|
||||
{@required String title,
|
||||
@required this.value,
|
||||
@required this.onValueChange})
|
||||
@required this.value,
|
||||
@required this.onValueChange})
|
||||
: super(title);
|
||||
|
||||
final bool Function() value;
|
||||
final void Function(bool value) onValueChange;
|
||||
}
|
||||
final void Function(BuildContext context, bool value) onValueChange;
|
||||
}
|
||||
|
|
6
lib/view_model/settings/version_list_item.dart
Normal file
|
@ -0,0 +1,6 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:cake_wallet/view_model/settings/settings_list_item.dart';
|
||||
|
||||
class VersionListItem extends SettingsListItem {
|
||||
VersionListItem({@required String title}) : super(title);
|
||||
}
|
|
@ -67,7 +67,8 @@ abstract class WalletAddressListViewModelBase with Store {
|
|||
WalletType get type => _wallet.type;
|
||||
|
||||
@computed
|
||||
WalletAddressListItem get address => WalletAddressListItem(address: _wallet.address);
|
||||
WalletAddressListItem get address =>
|
||||
WalletAddressListItem(address: _wallet.address);
|
||||
|
||||
@computed
|
||||
PaymentURI get uri {
|
||||
|
@ -100,15 +101,16 @@ abstract class WalletAddressListViewModelBase with Store {
|
|||
}
|
||||
|
||||
if (wallet is BitcoinWallet) {
|
||||
final bitcoinAddresses = wallet.addresses.map(
|
||||
(addr) => WalletAddressListItem(name: addr.label, address: addr.address));
|
||||
final bitcoinAddresses = wallet.addresses.map((addr) =>
|
||||
WalletAddressListItem(name: addr.label, address: addr.address));
|
||||
addressList.addAll(bitcoinAddresses);
|
||||
}
|
||||
|
||||
return addressList;
|
||||
}
|
||||
|
||||
set address(WalletAddressListItem address) => _wallet.address = address.address;
|
||||
set address(WalletAddressListItem address) =>
|
||||
_wallet.address = address.address;
|
||||
|
||||
bool hasAccounts;
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ abstract class WalletCreationVMBase with Store {
|
|||
|
||||
final bool isRecovery;
|
||||
|
||||
Box<WalletInfo> _walletInfoSource;
|
||||
final Box<WalletInfo> _walletInfoSource;
|
||||
|
||||
Future<void> create({dynamic options}) async {
|
||||
try {
|
||||
|
|
64
lib/view_model/wallet_restoration_from_keys_vm.dart
Normal file
|
@ -0,0 +1,64 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:cake_wallet/monero/monero_wallet_service.dart';
|
||||
import 'package:cake_wallet/bitcoin/bitcoin_wallet_creation_credentials.dart';
|
||||
import 'package:cake_wallet/core/generate_wallet_password.dart';
|
||||
import 'package:cake_wallet/core/wallet_creation_service.dart';
|
||||
import 'package:cake_wallet/core/wallet_credentials.dart';
|
||||
import 'package:cake_wallet/src/domain/common/wallet_type.dart';
|
||||
import 'package:cake_wallet/view_model/wallet_creation_vm.dart';
|
||||
import 'package:cake_wallet/src/domain/common/wallet_info.dart';
|
||||
|
||||
part 'wallet_restoration_from_keys_vm.g.dart';
|
||||
|
||||
class WalletRestorationFromKeysVM = WalletRestorationFromKeysVMBase
|
||||
with _$WalletRestorationFromKeysVM;
|
||||
|
||||
abstract class WalletRestorationFromKeysVMBase extends WalletCreationVM
|
||||
with Store {
|
||||
WalletRestorationFromKeysVMBase(this._walletCreationService, Box<WalletInfo> walletInfoSource,
|
||||
{@required WalletType type, @required this.language})
|
||||
: super(walletInfoSource, type: type, isRecovery: true);
|
||||
|
||||
@observable
|
||||
int height;
|
||||
|
||||
@observable
|
||||
String viewKey;
|
||||
|
||||
@observable
|
||||
String spendKey;
|
||||
|
||||
@observable
|
||||
String wif;
|
||||
|
||||
@observable
|
||||
String address;
|
||||
|
||||
bool get hasRestorationHeight => type == WalletType.monero;
|
||||
|
||||
final String language;
|
||||
final WalletCreationService _walletCreationService;
|
||||
|
||||
@override
|
||||
WalletCredentials getCredentials(dynamic options) {
|
||||
final password = generateWalletPassword(type);
|
||||
|
||||
switch (type) {
|
||||
case WalletType.monero:
|
||||
return MoneroRestoreWalletFromKeysCredentials(
|
||||
name: name, password: password, language: language, address: address,
|
||||
viewKey: viewKey, spendKey: spendKey, height: height);
|
||||
case WalletType.bitcoin:
|
||||
return BitcoinRestoreWalletFromWIFCredentials(
|
||||
name: name, password: password, wif: wif);
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> process(WalletCredentials credentials) async =>
|
||||
_walletCreationService.restoreFromKeys(credentials);
|
||||
}
|
|
@ -165,6 +165,9 @@
|
|||
"restore_wallet_restore_description" : "Beschreibung zur Wiederherstellung der Brieftasche",
|
||||
"restore_new_seed" : "Neuer Seed",
|
||||
"restore_active_seed" : "Aktives Seed",
|
||||
"restore_bitcoin_description_from_seed" : "Stellen Sie Ihre Brieftasche aus dem 12-Wort-Kombinationscode wieder her",
|
||||
"restore_bitcoin_description_from_keys" : "Stellen Sie Ihre Brieftasche aus der generierten WIF-Zeichenfolge aus Ihren privaten Schlüsseln wieder her",
|
||||
"restore_bitcoin_title_from_keys" : "Aus WIF wiederherstellen",
|
||||
|
||||
|
||||
"seed_title" : "Seed",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"welcome" : "Welcome to",
|
||||
"cake_wallet" : "Cake Wallet",
|
||||
"first_wallet_text" : "Awesome wallet for Monero",
|
||||
"first_wallet_text" : "Awesome wallet for Monero and Bitcoin",
|
||||
"please_make_selection" : "Please make selection below to create or recover your wallet.",
|
||||
"create_new" : "Create New Wallet",
|
||||
"restore_wallet" : "Restore Wallet",
|
||||
|
@ -165,6 +165,9 @@
|
|||
"restore_wallet_restore_description" : "Wallet restore description",
|
||||
"restore_new_seed" : "New seed",
|
||||
"restore_active_seed" : "Active seed",
|
||||
"restore_bitcoin_description_from_seed" : "Restore your wallet from 12 word combination code",
|
||||
"restore_bitcoin_description_from_keys" : "Restore your wallet from generated WIF string from your private keys",
|
||||
"restore_bitcoin_title_from_keys" : "Restore from WIF",
|
||||
|
||||
|
||||
"seed_title" : "Seed",
|
||||
|
|
|
@ -165,6 +165,9 @@
|
|||
"restore_wallet_restore_description" : "Restaurar billetera",
|
||||
"restore_new_seed" : "Nueva semilla",
|
||||
"restore_active_seed" : "Semilla activa",
|
||||
"restore_bitcoin_description_from_seed" : "Restaure su billetera a partir del código de combinación de 12 palabras",
|
||||
"restore_bitcoin_description_from_keys" : "Restaure su billetera a partir de una cadena WIF generada a partir de sus claves privadas",
|
||||
"restore_bitcoin_title_from_keys" : "Restaurar desde WIF",
|
||||
|
||||
|
||||
"seed_title" : "Semilla",
|
||||
|
|
|
@ -165,6 +165,9 @@
|
|||
"restore_wallet_restore_description" : "बटुआ विवरण पुनर्स्थापित करें",
|
||||
"restore_new_seed" : "नया बीज",
|
||||
"restore_active_seed" : "सक्रिय बीज",
|
||||
"restore_bitcoin_description_from_seed" : "12 शब्द संयोजन कोड से अपने वॉलेट को पुनर्स्थापित करें",
|
||||
"restore_bitcoin_description_from_keys" : "अपने निजी कुंजी से उत्पन्न WIF स्ट्रिंग से अपने वॉलेट को पुनर्स्थापित करें",
|
||||
"restore_bitcoin_title_from_keys" : "WIF से पुनर्स्थापित करें",
|
||||
|
||||
|
||||
"seed_title" : "बीज",
|
||||
|
|
|
@ -165,6 +165,9 @@
|
|||
"restore_wallet_restore_description" : "ウォレットの復元",
|
||||
"restore_new_seed" : "新しい種",
|
||||
"restore_active_seed" : "アクティブシード",
|
||||
"restore_bitcoin_description_from_seed" : "12ワードの組み合わせコードからウォレットを復元する",
|
||||
"restore_bitcoin_description_from_keys" : "秘密鍵から生成されたWIF文字列からウォレットを復元します",
|
||||
"restore_bitcoin_title_from_keys" : "WIFから復元",
|
||||
|
||||
|
||||
"seed_title" : "シード",
|
||||
|
|
|
@ -165,6 +165,9 @@
|
|||
"restore_wallet_restore_description" : "월렛 복원 설명",
|
||||
"restore_new_seed" : "새로운 씨앗",
|
||||
"restore_active_seed" : "활성 종자",
|
||||
"restore_bitcoin_description_from_seed" : "12 단어 조합 코드에서 지갑 복원",
|
||||
"restore_bitcoin_description_from_keys" : "개인 키에서 생성 된 WIF 문자열에서 지갑 복원",
|
||||
"restore_bitcoin_title_from_keys" : "WIF에서 복원",
|
||||
|
||||
|
||||
"seed_title" : "씨",
|
||||
|
|
|
@ -165,6 +165,9 @@
|
|||
"restore_wallet_restore_description" : "Portemonnee-herstelbeschrijving",
|
||||
"restore_new_seed" : "Nieuw zaad",
|
||||
"restore_active_seed" : "Actief zaad",
|
||||
"restore_bitcoin_description_from_seed" : "Herstel uw portemonnee met een combinatiecode van 12 woorden",
|
||||
"restore_bitcoin_description_from_keys" : "Herstel uw portemonnee van de gegenereerde WIF-string van uw privésleutels",
|
||||
"restore_bitcoin_title_from_keys" : "Herstel van WIF",
|
||||
|
||||
|
||||
"seed_title" : "Zaad",
|
||||
|
|
|
@ -165,6 +165,9 @@
|
|||
"restore_wallet_restore_description" : "Opis przywracania portfela",
|
||||
"restore_new_seed" : "Nowe nasienie",
|
||||
"restore_active_seed" : "Aktywne nasiona",
|
||||
"restore_bitcoin_description_from_seed" : "Przywróć swój portfel z kodu złożonego z 12 słów",
|
||||
"restore_bitcoin_description_from_keys" : "Przywróć swój portfel z wygenerowanego ciągu WIF z kluczy prywatnych",
|
||||
"restore_bitcoin_title_from_keys" : "Przywróć z WIF",
|
||||
|
||||
|
||||
"seed_title" : "Ziarno",
|
||||
|
|
|
@ -165,6 +165,9 @@
|
|||
"restore_wallet_restore_description" : "Restauração da carteira",
|
||||
"restore_new_seed" : "Nova semente",
|
||||
"restore_active_seed" : "Semente ativa",
|
||||
"restore_bitcoin_description_from_seed" : "Restaure sua carteira a partir de um código de combinação de 12 palavras",
|
||||
"restore_bitcoin_description_from_keys" : "Restaure sua carteira a partir da string WIF gerada de suas chaves privadas",
|
||||
"restore_bitcoin_title_from_keys" : "Restaurar de WIF",
|
||||
|
||||
|
||||
"seed_title" : "Semente",
|
||||
|
|
|
@ -165,6 +165,9 @@
|
|||
"restore_wallet_restore_description" : "Описание восстановления кошелька",
|
||||
"restore_new_seed" : "Новая мнемоническая фраза",
|
||||
"restore_active_seed" : "Активная мнемоническая фраза",
|
||||
"restore_bitcoin_description_from_seed" : "Вы можете восстановить кошелёк используя 12-ти значную мнемоническую фразу",
|
||||
"restore_bitcoin_description_from_keys" : "Вы можете восстановить кошелёк с помощью WIF",
|
||||
"restore_bitcoin_title_from_keys" : "Восстановить с помощью WIF",
|
||||
|
||||
|
||||
"seed_title" : "Мнемоническая фраза",
|
||||
|
|
|
@ -165,6 +165,9 @@
|
|||
"restore_wallet_restore_description" : "Опис відновлюваного гаманця",
|
||||
"restore_new_seed" : "Нова мнемонічна фраза",
|
||||
"restore_active_seed" : "Активна мнемонічна фраза",
|
||||
"restore_bitcoin_description_from_seed" : "Ви можете відновити гаманець використовуючи 12-ти слівну мнемонічну фразу",
|
||||
"restore_bitcoin_description_from_keys" : "Ви можете відновити гаманець за допомогою WIF",
|
||||
"restore_bitcoin_title_from_keys" : "Відновити за допомогою WIF",
|
||||
|
||||
|
||||
"seed_title" : "Мнемонічна фраза",
|
||||
|
|
|
@ -165,6 +165,9 @@
|
|||
"restore_wallet_restore_description" : "钱包还原说明",
|
||||
"restore_new_seed" : "新種子",
|
||||
"restore_active_seed" : "活性種子",
|
||||
"restore_bitcoin_description_from_seed" : "從12個單詞的組合碼恢復您的錢包",
|
||||
"restore_bitcoin_description_from_keys" : "從私鑰中生成的WIF字符串還原您的錢包",
|
||||
"restore_bitcoin_title_from_keys" : "從WIF還原",
|
||||
|
||||
|
||||
"seed_title" : "种子",
|
||||
|
|