mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2025-03-21 14:48:55 +00:00
commit
a5af60535e
107 changed files with 7290 additions and 3430 deletions
assets/svg
crypto_plugins
lib
hive
main.dartmodels
notifications
pages
add_wallet_views
new_wallet_recovery_phrase_warning_view
restore_wallet_view
address_book_views/subviews
exchange_view
pinpad_views
send_view
settings_views/global_settings_view
advanced_views
manage_nodes_views
security_views/change_pin_view
stack_backup_views
wallet_view/sub_widgets
pages_desktop_specific
create_password
desktop_login_view.darthome
address_book_view
desktop_home_view.dartdesktop_menu.dartmy_stack_view/wallet_view/sub_widgets
notifications
settings_menu
providers
desktop
global
services
auto_swb_service.dart
coins
node_service.dartwallets.dartwallets_service.dartutilities
assets.dartdb_version_migration.dartdesktop_password_service.dartflutter_secure_storage_interface.dartstack_file_system.dart
widgets
test
cached_electrumx_test.mocks.dartelectrumx_test.mocks.dartflutter_secure_storage_interface_test.dart
pages/send_view
screen_tests
services
coins
node_service_test.dartwallets_service_test.dartwallets_service_test.mocks.dartwidget_tests
12
assets/svg/plus-circle.svg
Normal file
12
assets/svg/plus-circle.svg
Normal file
|
@ -0,0 +1,12 @@
|
|||
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g clip-path="url(#clip0_5370_82626)">
|
||||
<path d="M9.99935 18.3337C14.6017 18.3337 18.3327 14.6027 18.3327 10.0003C18.3327 5.39795 14.6017 1.66699 9.99935 1.66699C5.39698 1.66699 1.66602 5.39795 1.66602 10.0003C1.66602 14.6027 5.39698 18.3337 9.99935 18.3337Z" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M10 6.66699V13.3337" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path d="M6.66602 10H13.3327" stroke="white" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
<defs>
|
||||
<clipPath id="clip0_5370_82626">
|
||||
<rect width="20" height="20" fill="white"/>
|
||||
</clipPath>
|
||||
</defs>
|
||||
</svg>
|
After (image error) Size: 780 B |
|
@ -1 +1 @@
|
|||
Subproject commit 2da77438527732dfaa5398aa391eab5253dabe19
|
||||
Subproject commit de29931dacc9aefaf42a9ca139a8754a42adc40d
|
|
@ -33,6 +33,7 @@ class DB {
|
|||
static const String boxNamePriceCache = "priceAPIPrice24hCache";
|
||||
static const String boxNameDBInfo = "dbInfo";
|
||||
static const String boxNameTheme = "theme";
|
||||
static const String boxNameDesktopData = "desktopData";
|
||||
|
||||
String boxNameTxCache({required Coin coin}) => "${coin.name}_txCache";
|
||||
String boxNameSetCache({required Coin coin}) =>
|
||||
|
@ -42,22 +43,23 @@ class DB {
|
|||
|
||||
static bool _initialized = false;
|
||||
|
||||
late final Box<dynamic> _boxAddressBook;
|
||||
late final Box<String> _boxDebugInfo;
|
||||
late final Box<NodeModel> _boxNodeModels;
|
||||
late final Box<NodeModel> _boxPrimaryNodes;
|
||||
late final Box<dynamic> _boxAllWalletsData;
|
||||
late final Box<NotificationModel> _boxNotifications;
|
||||
late final Box<NotificationModel> _boxWatchedTransactions;
|
||||
late final Box<NotificationModel> _boxWatchedTrades;
|
||||
late final Box<ExchangeTransaction> _boxTrades;
|
||||
late final Box<Trade> _boxTradesV2;
|
||||
late final Box<String> _boxTradeNotes;
|
||||
late final Box<String> _boxFavoriteWallets;
|
||||
late final Box<xmr.WalletInfo> _walletInfoSource;
|
||||
late final Box<dynamic> _boxPrefs;
|
||||
late final Box<TradeWalletLookup> _boxTradeLookup;
|
||||
late final Box<dynamic> _boxDBInfo;
|
||||
Box<dynamic>? _boxAddressBook;
|
||||
Box<String>? _boxDebugInfo;
|
||||
Box<NodeModel>? _boxNodeModels;
|
||||
Box<NodeModel>? _boxPrimaryNodes;
|
||||
Box<dynamic>? _boxAllWalletsData;
|
||||
Box<NotificationModel>? _boxNotifications;
|
||||
Box<NotificationModel>? _boxWatchedTransactions;
|
||||
Box<NotificationModel>? _boxWatchedTrades;
|
||||
Box<ExchangeTransaction>? _boxTrades;
|
||||
Box<Trade>? _boxTradesV2;
|
||||
Box<String>? _boxTradeNotes;
|
||||
Box<String>? _boxFavoriteWallets;
|
||||
Box<xmr.WalletInfo>? _walletInfoSource;
|
||||
Box<dynamic>? _boxPrefs;
|
||||
Box<TradeWalletLookup>? _boxTradeLookup;
|
||||
Box<dynamic>? _boxDBInfo;
|
||||
Box<String>? _boxDesktopData;
|
||||
|
||||
final Map<String, Box<dynamic>> _walletBoxes = {};
|
||||
|
||||
|
@ -66,7 +68,7 @@ class DB {
|
|||
final Map<Coin, Box<dynamic>> _usedSerialsCacheBoxes = {};
|
||||
|
||||
// exposed for monero
|
||||
Box<xmr.WalletInfo> get moneroWalletInfoBox => _walletInfoSource;
|
||||
Box<xmr.WalletInfo> get moneroWalletInfoBox => _walletInfoSource!;
|
||||
|
||||
// mutex for stack backup
|
||||
final mutex = Mutex();
|
||||
|
@ -122,6 +124,12 @@ class DB {
|
|||
_boxAllWalletsData = await Hive.openBox<dynamic>(boxNameAllWalletsData);
|
||||
}
|
||||
|
||||
if (Hive.isBoxOpen(boxNameDesktopData)) {
|
||||
_boxDesktopData = Hive.box<String>(boxNameDesktopData);
|
||||
} else {
|
||||
_boxDesktopData = await Hive.openBox<String>(boxNameDesktopData);
|
||||
}
|
||||
|
||||
_boxNotifications =
|
||||
await Hive.openBox<NotificationModel>(boxNameNotifications);
|
||||
_boxWatchedTransactions =
|
||||
|
@ -145,11 +153,11 @@ class DB {
|
|||
_initialized = true;
|
||||
|
||||
try {
|
||||
if (_boxPrefs.get("familiarity") == null) {
|
||||
await _boxPrefs.put("familiarity", 0);
|
||||
if (_boxPrefs!.get("familiarity") == null) {
|
||||
await _boxPrefs!.put("familiarity", 0);
|
||||
}
|
||||
int count = _boxPrefs.get("familiarity") as int;
|
||||
await _boxPrefs.put("familiarity", count + 1);
|
||||
int count = _boxPrefs!.get("familiarity") as int;
|
||||
await _boxPrefs!.put("familiarity", count + 1);
|
||||
Constants.exchangeForExperiencedUsers(count + 1);
|
||||
} catch (e, s) {
|
||||
print("$e $s");
|
||||
|
@ -158,7 +166,7 @@ class DB {
|
|||
}
|
||||
|
||||
Future<void> _loadWalletBoxes() async {
|
||||
final names = _boxAllWalletsData.get("names") as Map? ?? {};
|
||||
final names = _boxAllWalletsData!.get("names") as Map? ?? {};
|
||||
names.removeWhere((name, dyn) {
|
||||
final jsonObject = Map<String, dynamic>.from(dyn as Map);
|
||||
try {
|
||||
|
|
198
lib/main.dart
198
lib/main.dart
|
@ -10,6 +10,7 @@ import 'package:flutter/services.dart';
|
|||
import 'package:flutter_libmonero/monero/monero.dart';
|
||||
import 'package:flutter_libmonero/wownero/wownero.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:google_fonts/google_fonts.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
@ -47,12 +48,12 @@ import 'package:stackwallet/services/node_service.dart';
|
|||
import 'package:stackwallet/services/notifications_api.dart';
|
||||
import 'package:stackwallet/services/notifications_service.dart';
|
||||
import 'package:stackwallet/services/trade_service.dart';
|
||||
import 'package:stackwallet/services/wallets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/db_version_migration.dart';
|
||||
import 'package:stackwallet/utilities/enums/backup_frequency_type.dart';
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
import 'package:stackwallet/utilities/stack_file_system.dart';
|
||||
import 'package:stackwallet/utilities/theme/color_theme.dart';
|
||||
import 'package:stackwallet/utilities/theme/dark_colors.dart';
|
||||
import 'package:stackwallet/utilities/theme/light_colors.dart';
|
||||
|
@ -79,19 +80,11 @@ void main() async {
|
|||
setWindowMaxSize(Size.infinite);
|
||||
}
|
||||
|
||||
Directory appDirectory = (await getApplicationDocumentsDirectory());
|
||||
if (Platform.isIOS) {
|
||||
appDirectory = (await getLibraryDirectory());
|
||||
}
|
||||
if (Platform.isLinux || Logging.isArmLinux) {
|
||||
appDirectory = Directory("${appDirectory.path}/.stackwallet");
|
||||
await appDirectory.create();
|
||||
}
|
||||
// FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
|
||||
if (!(Logging.isArmLinux || Logging.isTestEnv)) {
|
||||
final isar = await Isar.open(
|
||||
[LogSchema],
|
||||
directory: appDirectory.path,
|
||||
directory: (await StackFileSystem.applicationIsarDirectory()).path,
|
||||
inspector: false,
|
||||
);
|
||||
await Logging.instance.init(isar);
|
||||
|
@ -140,18 +133,29 @@ void main() async {
|
|||
Hive.registerAdapter(WalletTypeAdapter());
|
||||
|
||||
Hive.registerAdapter(UnspentCoinsInfoAdapter());
|
||||
await Hive.initFlutter(appDirectory.path);
|
||||
await Hive.initFlutter(
|
||||
(await StackFileSystem.applicationHiveDirectory()).path);
|
||||
|
||||
await Hive.openBox<dynamic>(DB.boxNameDBInfo);
|
||||
int dbVersion = DB.instance.get<dynamic>(
|
||||
boxName: DB.boxNameDBInfo, key: "hive_data_version") as int? ??
|
||||
0;
|
||||
if (dbVersion < Constants.currentHiveDbVersion) {
|
||||
try {
|
||||
await DbVersionMigrator().migrate(dbVersion);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("Cannot migrate database\n$e $s",
|
||||
level: LogLevel.Error, printFullLength: true);
|
||||
|
||||
// todo: db migrate stuff for desktop needs to be handled eventually
|
||||
if (!Util.isDesktop) {
|
||||
int dbVersion = DB.instance.get<dynamic>(
|
||||
boxName: DB.boxNameDBInfo, key: "hive_data_version") as int? ??
|
||||
0;
|
||||
if (dbVersion < Constants.currentHiveDbVersion) {
|
||||
try {
|
||||
await DbVersionMigrator().migrate(
|
||||
dbVersion,
|
||||
secureStore: const SecureStorageWrapper(
|
||||
store: FlutterSecureStorage(),
|
||||
isDesktop: false,
|
||||
),
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("Cannot migrate database\n$e $s",
|
||||
level: LogLevel.Error, printFullLength: true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -199,8 +203,8 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
static const platform = MethodChannel("STACK_WALLET_RESTORE");
|
||||
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
|
||||
|
||||
late final Wallets _wallets;
|
||||
late final Prefs _prefs;
|
||||
// late final Wallets _wallets;
|
||||
// late final Prefs _prefs;
|
||||
late final NotificationsService _notificationsService;
|
||||
late final NodeService _nodeService;
|
||||
late final TradesService _tradesService;
|
||||
|
@ -208,8 +212,24 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
late final Completer<void> loadingCompleter;
|
||||
|
||||
bool didLoad = false;
|
||||
bool didLoadShared = false;
|
||||
bool _desktopHasPassword = false;
|
||||
|
||||
Future<void> loadShared() async {
|
||||
if (didLoadShared) {
|
||||
return;
|
||||
}
|
||||
didLoadShared = true;
|
||||
|
||||
await DB.instance.init();
|
||||
await ref.read(prefsChangeNotifierProvider).init();
|
||||
|
||||
if (Util.isDesktop) {
|
||||
_desktopHasPassword =
|
||||
await ref.read(storageCryptoHandlerProvider).hasPassword();
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> load() async {
|
||||
try {
|
||||
if (didLoad) {
|
||||
|
@ -217,19 +237,15 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
}
|
||||
didLoad = true;
|
||||
|
||||
await DB.instance.init();
|
||||
await _prefs.init();
|
||||
|
||||
if (Util.isDesktop) {
|
||||
_desktopHasPassword =
|
||||
await ref.read(storageCryptoHandlerProvider).hasPassword();
|
||||
if (!Util.isDesktop) {
|
||||
await loadShared();
|
||||
}
|
||||
|
||||
_notificationsService = ref.read(notificationsProvider);
|
||||
_nodeService = ref.read(nodeServiceChangeNotifierProvider);
|
||||
_tradesService = ref.read(tradesServiceProvider);
|
||||
|
||||
NotificationApi.prefs = _prefs;
|
||||
NotificationApi.prefs = ref.read(prefsChangeNotifierProvider);
|
||||
NotificationApi.notificationsService = _notificationsService;
|
||||
|
||||
unawaited(ref.read(baseCurrenciesProvider).update());
|
||||
|
@ -238,23 +254,25 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
await _notificationsService.init(
|
||||
nodeService: _nodeService,
|
||||
tradesService: _tradesService,
|
||||
prefs: _prefs,
|
||||
prefs: ref.read(prefsChangeNotifierProvider),
|
||||
);
|
||||
ref.read(priceAnd24hChangeNotifierProvider).start(true);
|
||||
await _wallets.load(_prefs);
|
||||
await ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.load(ref.read(prefsChangeNotifierProvider));
|
||||
loadingCompleter.complete();
|
||||
// TODO: this should probably run unawaited. Keep commented out for now as proper community nodes ui hasn't been implemented yet
|
||||
// unawaited(_nodeService.updateCommunityNodes());
|
||||
|
||||
// run without awaiting
|
||||
if (Constants.enableExchange &&
|
||||
_prefs.externalCalls &&
|
||||
await _prefs.isExternalCallsSet()) {
|
||||
ref.read(prefsChangeNotifierProvider).externalCalls &&
|
||||
await ref.read(prefsChangeNotifierProvider).isExternalCallsSet()) {
|
||||
unawaited(ExchangeDataLoadingService().loadAll(ref));
|
||||
}
|
||||
|
||||
if (_prefs.isAutoBackupEnabled) {
|
||||
switch (_prefs.backupFrequencyType) {
|
||||
if (ref.read(prefsChangeNotifierProvider).isAutoBackupEnabled) {
|
||||
switch (ref.read(prefsChangeNotifierProvider).backupFrequencyType) {
|
||||
case BackupFrequencyType.everyTenMinutes:
|
||||
ref.read(autoSWBServiceProvider).startPeriodicBackupTimer(
|
||||
duration: const Duration(minutes: 10));
|
||||
|
@ -294,9 +312,6 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
.read(localeServiceChangeNotifierProvider.notifier)
|
||||
.loadLocale(notify: false);
|
||||
|
||||
_prefs = ref.read(prefsChangeNotifierProvider);
|
||||
_wallets = ref.read(walletsChangeNotifierProvider);
|
||||
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) async {
|
||||
ref.read(colorThemeProvider.state).state =
|
||||
StackColors.fromStackColorTheme(
|
||||
|
@ -401,7 +416,7 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
}
|
||||
|
||||
Future<void> goToRestoreSWB(String encrypted) async {
|
||||
if (!_prefs.hasPin) {
|
||||
if (!ref.read(prefsChangeNotifierProvider).hasPin) {
|
||||
await Navigator.of(navigatorKey.currentContext!)
|
||||
.pushNamed(CreatePinView.routeName, arguments: true)
|
||||
.then((value) {
|
||||
|
@ -547,51 +562,70 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
_buildOutlineInputBorder(colorScheme.textFieldDefaultBG),
|
||||
),
|
||||
),
|
||||
home: FutureBuilder(
|
||||
future: load(),
|
||||
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
// FlutterNativeSplash.remove();
|
||||
if (Util.isDesktop &&
|
||||
(_wallets.hasWallets || _desktopHasPassword)) {
|
||||
String? startupWalletId;
|
||||
if (ref.read(prefsChangeNotifierProvider).gotoWalletOnStartup) {
|
||||
startupWalletId =
|
||||
ref.read(prefsChangeNotifierProvider).startupWalletId;
|
||||
}
|
||||
home: Util.isDesktop
|
||||
? FutureBuilder(
|
||||
future: loadShared(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
if (_desktopHasPassword) {
|
||||
String? startupWalletId;
|
||||
if (ref
|
||||
.read(prefsChangeNotifierProvider)
|
||||
.gotoWalletOnStartup) {
|
||||
startupWalletId =
|
||||
ref.read(prefsChangeNotifierProvider).startupWalletId;
|
||||
}
|
||||
|
||||
return DesktopLoginView(startupWalletId: startupWalletId);
|
||||
} else if (!Util.isDesktop &&
|
||||
(_wallets.hasWallets || _prefs.hasPin)) {
|
||||
// return HomeView();
|
||||
return DesktopLoginView(
|
||||
startupWalletId: startupWalletId,
|
||||
load: load,
|
||||
);
|
||||
} else {
|
||||
return const IntroView();
|
||||
}
|
||||
} else {
|
||||
return const LoadingView();
|
||||
}
|
||||
},
|
||||
)
|
||||
: FutureBuilder(
|
||||
future: load(),
|
||||
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
|
||||
if (snapshot.connectionState == ConnectionState.done) {
|
||||
// FlutterNativeSplash.remove();
|
||||
if (ref.read(walletsChangeNotifierProvider).hasWallets ||
|
||||
ref.read(prefsChangeNotifierProvider).hasPin) {
|
||||
// return HomeView();
|
||||
|
||||
String? startupWalletId;
|
||||
if (ref.read(prefsChangeNotifierProvider).gotoWalletOnStartup) {
|
||||
startupWalletId =
|
||||
ref.read(prefsChangeNotifierProvider).startupWalletId;
|
||||
}
|
||||
String? startupWalletId;
|
||||
if (ref
|
||||
.read(prefsChangeNotifierProvider)
|
||||
.gotoWalletOnStartup) {
|
||||
startupWalletId =
|
||||
ref.read(prefsChangeNotifierProvider).startupWalletId;
|
||||
}
|
||||
|
||||
return LockscreenView(
|
||||
isInitialAppLogin: true,
|
||||
routeOnSuccess: HomeView.routeName,
|
||||
routeOnSuccessArguments: startupWalletId,
|
||||
biometricsAuthenticationTitle: "Unlock Stack",
|
||||
biometricsLocalizedReason:
|
||||
"Unlock your stack wallet using biometrics",
|
||||
biometricsCancelButtonString: "Cancel",
|
||||
);
|
||||
} else {
|
||||
return const IntroView();
|
||||
}
|
||||
} else {
|
||||
// CURRENTLY DISABLED as cannot be animated
|
||||
// technically not needed as FlutterNativeSplash will overlay
|
||||
// anything returned here until the future completes but
|
||||
// FutureBuilder requires you to return something
|
||||
return const LoadingView();
|
||||
}
|
||||
},
|
||||
),
|
||||
return LockscreenView(
|
||||
isInitialAppLogin: true,
|
||||
routeOnSuccess: HomeView.routeName,
|
||||
routeOnSuccessArguments: startupWalletId,
|
||||
biometricsAuthenticationTitle: "Unlock Stack",
|
||||
biometricsLocalizedReason:
|
||||
"Unlock your stack wallet using biometrics",
|
||||
biometricsCancelButtonString: "Cancel",
|
||||
);
|
||||
} else {
|
||||
return const IntroView();
|
||||
}
|
||||
} else {
|
||||
// CURRENTLY DISABLED as cannot be animated
|
||||
// technically not needed as FlutterNativeSplash will overlay
|
||||
// anything returned here until the future completes but
|
||||
// FutureBuilder requires you to return something
|
||||
return const LoadingView();
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
18
lib/models/isar/models/encrypted_string_value.dart
Normal file
18
lib/models/isar/models/encrypted_string_value.dart
Normal file
|
@ -0,0 +1,18 @@
|
|||
import 'package:isar/isar.dart';
|
||||
|
||||
part 'encrypted_string_value.g.dart';
|
||||
|
||||
@Collection()
|
||||
class EncryptedStringValue {
|
||||
Id id = Isar.autoIncrement;
|
||||
|
||||
@Index(unique: true, replace: true)
|
||||
late String key;
|
||||
|
||||
late String value;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return "EncryptedStringValue {\n key=$key\n value=$value\n}";
|
||||
}
|
||||
}
|
748
lib/models/isar/models/encrypted_string_value.g.dart
Normal file
748
lib/models/isar/models/encrypted_string_value.g.dart
Normal file
|
@ -0,0 +1,748 @@
|
|||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'encrypted_string_value.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// IsarCollectionGenerator
|
||||
// **************************************************************************
|
||||
|
||||
// coverage:ignore-file
|
||||
// ignore_for_file: duplicate_ignore, non_constant_identifier_names, constant_identifier_names, invalid_use_of_protected_member, unnecessary_cast, prefer_const_constructors, lines_longer_than_80_chars, require_trailing_commas, inference_failure_on_function_invocation, unnecessary_parenthesis, unnecessary_raw_strings, join_return_with_assignment, avoid_js_rounded_ints, prefer_final_locals
|
||||
|
||||
extension GetEncryptedStringValueCollection on Isar {
|
||||
IsarCollection<EncryptedStringValue> get encryptedStringValues =>
|
||||
this.collection();
|
||||
}
|
||||
|
||||
const EncryptedStringValueSchema = CollectionSchema(
|
||||
name: r'EncryptedStringValue',
|
||||
id: 4826543019451092626,
|
||||
properties: {
|
||||
r'key': PropertySchema(
|
||||
id: 0,
|
||||
name: r'key',
|
||||
type: IsarType.string,
|
||||
),
|
||||
r'value': PropertySchema(
|
||||
id: 1,
|
||||
name: r'value',
|
||||
type: IsarType.string,
|
||||
)
|
||||
},
|
||||
estimateSize: _encryptedStringValueEstimateSize,
|
||||
serializeNative: _encryptedStringValueSerializeNative,
|
||||
deserializeNative: _encryptedStringValueDeserializeNative,
|
||||
deserializePropNative: _encryptedStringValueDeserializePropNative,
|
||||
serializeWeb: _encryptedStringValueSerializeWeb,
|
||||
deserializeWeb: _encryptedStringValueDeserializeWeb,
|
||||
deserializePropWeb: _encryptedStringValueDeserializePropWeb,
|
||||
idName: r'id',
|
||||
indexes: {
|
||||
r'key': IndexSchema(
|
||||
id: -4906094122524121629,
|
||||
name: r'key',
|
||||
unique: true,
|
||||
replace: true,
|
||||
properties: [
|
||||
IndexPropertySchema(
|
||||
name: r'key',
|
||||
type: IndexType.hash,
|
||||
caseSensitive: true,
|
||||
)
|
||||
],
|
||||
)
|
||||
},
|
||||
links: {},
|
||||
embeddedSchemas: {},
|
||||
getId: _encryptedStringValueGetId,
|
||||
getLinks: _encryptedStringValueGetLinks,
|
||||
attach: _encryptedStringValueAttach,
|
||||
version: 5,
|
||||
);
|
||||
|
||||
int _encryptedStringValueEstimateSize(
|
||||
EncryptedStringValue object,
|
||||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
var bytesCount = offsets.last;
|
||||
bytesCount += 3 + object.key.length * 3;
|
||||
bytesCount += 3 + object.value.length * 3;
|
||||
return bytesCount;
|
||||
}
|
||||
|
||||
int _encryptedStringValueSerializeNative(
|
||||
EncryptedStringValue object,
|
||||
IsarBinaryWriter writer,
|
||||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
writer.writeString(offsets[0], object.key);
|
||||
writer.writeString(offsets[1], object.value);
|
||||
return writer.usedBytes;
|
||||
}
|
||||
|
||||
EncryptedStringValue _encryptedStringValueDeserializeNative(
|
||||
int id,
|
||||
IsarBinaryReader reader,
|
||||
List<int> offsets,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
final object = EncryptedStringValue();
|
||||
object.id = id;
|
||||
object.key = reader.readString(offsets[0]);
|
||||
object.value = reader.readString(offsets[1]);
|
||||
return object;
|
||||
}
|
||||
|
||||
P _encryptedStringValueDeserializePropNative<P>(
|
||||
Id id,
|
||||
IsarBinaryReader reader,
|
||||
int propertyId,
|
||||
int offset,
|
||||
Map<Type, List<int>> allOffsets,
|
||||
) {
|
||||
switch (propertyId) {
|
||||
case 0:
|
||||
return (reader.readString(offset)) as P;
|
||||
case 1:
|
||||
return (reader.readString(offset)) as P;
|
||||
default:
|
||||
throw IsarError('Unknown property with id $propertyId');
|
||||
}
|
||||
}
|
||||
|
||||
Object _encryptedStringValueSerializeWeb(
|
||||
IsarCollection<EncryptedStringValue> collection,
|
||||
EncryptedStringValue object) {
|
||||
/*final jsObj = IsarNative.newJsObject();*/ throw UnimplementedError();
|
||||
}
|
||||
|
||||
EncryptedStringValue _encryptedStringValueDeserializeWeb(
|
||||
IsarCollection<EncryptedStringValue> collection, Object jsObj) {
|
||||
/*final object = EncryptedStringValue();object.id = IsarNative.jsObjectGet(jsObj, r'id') ?? (double.negativeInfinity as int);object.key = IsarNative.jsObjectGet(jsObj, r'key') ?? '';object.value = IsarNative.jsObjectGet(jsObj, r'value') ?? '';*/
|
||||
//return object;
|
||||
throw UnimplementedError();
|
||||
}
|
||||
|
||||
P _encryptedStringValueDeserializePropWeb<P>(
|
||||
Object jsObj, String propertyName) {
|
||||
switch (propertyName) {
|
||||
default:
|
||||
throw IsarError('Illegal propertyName');
|
||||
}
|
||||
}
|
||||
|
||||
int? _encryptedStringValueGetId(EncryptedStringValue object) {
|
||||
if (object.id == Isar.autoIncrement) {
|
||||
return null;
|
||||
} else {
|
||||
return object.id;
|
||||
}
|
||||
}
|
||||
|
||||
List<IsarLinkBase<dynamic>> _encryptedStringValueGetLinks(
|
||||
EncryptedStringValue object) {
|
||||
return [];
|
||||
}
|
||||
|
||||
void _encryptedStringValueAttach(
|
||||
IsarCollection<dynamic> col, Id id, EncryptedStringValue object) {
|
||||
object.id = id;
|
||||
}
|
||||
|
||||
extension EncryptedStringValueByIndex on IsarCollection<EncryptedStringValue> {
|
||||
Future<EncryptedStringValue?> getByKey(String key) {
|
||||
return getByIndex(r'key', [key]);
|
||||
}
|
||||
|
||||
EncryptedStringValue? getByKeySync(String key) {
|
||||
return getByIndexSync(r'key', [key]);
|
||||
}
|
||||
|
||||
Future<bool> deleteByKey(String key) {
|
||||
return deleteByIndex(r'key', [key]);
|
||||
}
|
||||
|
||||
bool deleteByKeySync(String key) {
|
||||
return deleteByIndexSync(r'key', [key]);
|
||||
}
|
||||
|
||||
Future<List<EncryptedStringValue?>> getAllByKey(List<String> keyValues) {
|
||||
final values = keyValues.map((e) => [e]).toList();
|
||||
return getAllByIndex(r'key', values);
|
||||
}
|
||||
|
||||
List<EncryptedStringValue?> getAllByKeySync(List<String> keyValues) {
|
||||
final values = keyValues.map((e) => [e]).toList();
|
||||
return getAllByIndexSync(r'key', values);
|
||||
}
|
||||
|
||||
Future<int> deleteAllByKey(List<String> keyValues) {
|
||||
final values = keyValues.map((e) => [e]).toList();
|
||||
return deleteAllByIndex(r'key', values);
|
||||
}
|
||||
|
||||
int deleteAllByKeySync(List<String> keyValues) {
|
||||
final values = keyValues.map((e) => [e]).toList();
|
||||
return deleteAllByIndexSync(r'key', values);
|
||||
}
|
||||
|
||||
Future<int> putByKey(EncryptedStringValue object) {
|
||||
return putByIndex(r'key', object);
|
||||
}
|
||||
|
||||
int putByKeySync(EncryptedStringValue object, {bool saveLinks = true}) {
|
||||
return putByIndexSync(r'key', object, saveLinks: saveLinks);
|
||||
}
|
||||
|
||||
Future<List<int>> putAllByKey(List<EncryptedStringValue> objects) {
|
||||
return putAllByIndex(r'key', objects);
|
||||
}
|
||||
|
||||
List<int> putAllByKeySync(List<EncryptedStringValue> objects,
|
||||
{bool saveLinks = true}) {
|
||||
return putAllByIndexSync(r'key', objects, saveLinks: saveLinks);
|
||||
}
|
||||
}
|
||||
|
||||
extension EncryptedStringValueQueryWhereSort
|
||||
on QueryBuilder<EncryptedStringValue, EncryptedStringValue, QWhere> {
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterWhere>
|
||||
anyId() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addWhereClause(const IdWhereClause.any());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension EncryptedStringValueQueryWhere
|
||||
on QueryBuilder<EncryptedStringValue, EncryptedStringValue, QWhereClause> {
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterWhereClause>
|
||||
idEqualTo(int id) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addWhereClause(IdWhereClause.between(
|
||||
lower: id,
|
||||
upper: id,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterWhereClause>
|
||||
idNotEqualTo(int id) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
if (query.whereSort == Sort.asc) {
|
||||
return query
|
||||
.addWhereClause(
|
||||
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||
)
|
||||
.addWhereClause(
|
||||
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||
);
|
||||
} else {
|
||||
return query
|
||||
.addWhereClause(
|
||||
IdWhereClause.greaterThan(lower: id, includeLower: false),
|
||||
)
|
||||
.addWhereClause(
|
||||
IdWhereClause.lessThan(upper: id, includeUpper: false),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterWhereClause>
|
||||
idGreaterThan(int id, {bool include = false}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addWhereClause(
|
||||
IdWhereClause.greaterThan(lower: id, includeLower: include),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterWhereClause>
|
||||
idLessThan(int id, {bool include = false}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addWhereClause(
|
||||
IdWhereClause.lessThan(upper: id, includeUpper: include),
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterWhereClause>
|
||||
idBetween(
|
||||
int lowerId,
|
||||
int upperId, {
|
||||
bool includeLower = true,
|
||||
bool includeUpper = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addWhereClause(IdWhereClause.between(
|
||||
lower: lowerId,
|
||||
includeLower: includeLower,
|
||||
upper: upperId,
|
||||
includeUpper: includeUpper,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterWhereClause>
|
||||
keyEqualTo(String key) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addWhereClause(IndexWhereClause.equalTo(
|
||||
indexName: r'key',
|
||||
value: [key],
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterWhereClause>
|
||||
keyNotEqualTo(String key) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
if (query.whereSort == Sort.asc) {
|
||||
return query
|
||||
.addWhereClause(IndexWhereClause.between(
|
||||
indexName: r'key',
|
||||
lower: [],
|
||||
upper: [key],
|
||||
includeUpper: false,
|
||||
))
|
||||
.addWhereClause(IndexWhereClause.between(
|
||||
indexName: r'key',
|
||||
lower: [key],
|
||||
includeLower: false,
|
||||
upper: [],
|
||||
));
|
||||
} else {
|
||||
return query
|
||||
.addWhereClause(IndexWhereClause.between(
|
||||
indexName: r'key',
|
||||
lower: [key],
|
||||
includeLower: false,
|
||||
upper: [],
|
||||
))
|
||||
.addWhereClause(IndexWhereClause.between(
|
||||
indexName: r'key',
|
||||
lower: [],
|
||||
upper: [key],
|
||||
includeUpper: false,
|
||||
));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension EncryptedStringValueQueryFilter on QueryBuilder<EncryptedStringValue,
|
||||
EncryptedStringValue, QFilterCondition> {
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition> idEqualTo(int value) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'id',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition> idGreaterThan(
|
||||
int value, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.greaterThan(
|
||||
include: include,
|
||||
property: r'id',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition> idLessThan(
|
||||
int value, {
|
||||
bool include = false,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.lessThan(
|
||||
include: include,
|
||||
property: r'id',
|
||||
value: value,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition> idBetween(
|
||||
int lower,
|
||||
int upper, {
|
||||
bool includeLower = true,
|
||||
bool includeUpper = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.between(
|
||||
property: r'id',
|
||||
lower: lower,
|
||||
includeLower: includeLower,
|
||||
upper: upper,
|
||||
includeUpper: includeUpper,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition> keyEqualTo(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'key',
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition> keyGreaterThan(
|
||||
String value, {
|
||||
bool include = false,
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.greaterThan(
|
||||
include: include,
|
||||
property: r'key',
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition> keyLessThan(
|
||||
String value, {
|
||||
bool include = false,
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.lessThan(
|
||||
include: include,
|
||||
property: r'key',
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition> keyBetween(
|
||||
String lower,
|
||||
String upper, {
|
||||
bool includeLower = true,
|
||||
bool includeUpper = true,
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.between(
|
||||
property: r'key',
|
||||
lower: lower,
|
||||
includeLower: includeLower,
|
||||
upper: upper,
|
||||
includeUpper: includeUpper,
|
||||
caseSensitive: caseSensitive,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition> keyStartsWith(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.startsWith(
|
||||
property: r'key',
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition> keyEndsWith(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.endsWith(
|
||||
property: r'key',
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition>
|
||||
keyContains(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.contains(
|
||||
property: r'key',
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition>
|
||||
keyMatches(String pattern, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.matches(
|
||||
property: r'key',
|
||||
wildcard: pattern,
|
||||
caseSensitive: caseSensitive,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition> valueEqualTo(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.equalTo(
|
||||
property: r'value',
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition> valueGreaterThan(
|
||||
String value, {
|
||||
bool include = false,
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.greaterThan(
|
||||
include: include,
|
||||
property: r'value',
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition> valueLessThan(
|
||||
String value, {
|
||||
bool include = false,
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.lessThan(
|
||||
include: include,
|
||||
property: r'value',
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition> valueBetween(
|
||||
String lower,
|
||||
String upper, {
|
||||
bool includeLower = true,
|
||||
bool includeUpper = true,
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.between(
|
||||
property: r'value',
|
||||
lower: lower,
|
||||
includeLower: includeLower,
|
||||
upper: upper,
|
||||
includeUpper: includeUpper,
|
||||
caseSensitive: caseSensitive,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition> valueStartsWith(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.startsWith(
|
||||
property: r'value',
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition> valueEndsWith(
|
||||
String value, {
|
||||
bool caseSensitive = true,
|
||||
}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.endsWith(
|
||||
property: r'value',
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition>
|
||||
valueContains(String value, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.contains(
|
||||
property: r'value',
|
||||
value: value,
|
||||
caseSensitive: caseSensitive,
|
||||
));
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue,
|
||||
QAfterFilterCondition>
|
||||
valueMatches(String pattern, {bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addFilterCondition(FilterCondition.matches(
|
||||
property: r'value',
|
||||
wildcard: pattern,
|
||||
caseSensitive: caseSensitive,
|
||||
));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension EncryptedStringValueQueryObject on QueryBuilder<EncryptedStringValue,
|
||||
EncryptedStringValue, QFilterCondition> {}
|
||||
|
||||
extension EncryptedStringValueQueryLinks on QueryBuilder<EncryptedStringValue,
|
||||
EncryptedStringValue, QFilterCondition> {}
|
||||
|
||||
extension EncryptedStringValueQuerySortBy
|
||||
on QueryBuilder<EncryptedStringValue, EncryptedStringValue, QSortBy> {
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterSortBy>
|
||||
sortByKey() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'key', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterSortBy>
|
||||
sortByKeyDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'key', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterSortBy>
|
||||
sortByValue() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'value', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterSortBy>
|
||||
sortByValueDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'value', Sort.desc);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension EncryptedStringValueQuerySortThenBy
|
||||
on QueryBuilder<EncryptedStringValue, EncryptedStringValue, QSortThenBy> {
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterSortBy>
|
||||
thenById() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'id', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterSortBy>
|
||||
thenByIdDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'id', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterSortBy>
|
||||
thenByKey() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'key', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterSortBy>
|
||||
thenByKeyDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'key', Sort.desc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterSortBy>
|
||||
thenByValue() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'value', Sort.asc);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QAfterSortBy>
|
||||
thenByValueDesc() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addSortBy(r'value', Sort.desc);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension EncryptedStringValueQueryWhereDistinct
|
||||
on QueryBuilder<EncryptedStringValue, EncryptedStringValue, QDistinct> {
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QDistinct>
|
||||
distinctByKey({bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'key', caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, EncryptedStringValue, QDistinct>
|
||||
distinctByValue({bool caseSensitive = true}) {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addDistinctBy(r'value', caseSensitive: caseSensitive);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
extension EncryptedStringValueQueryProperty on QueryBuilder<
|
||||
EncryptedStringValue, EncryptedStringValue, QQueryProperty> {
|
||||
QueryBuilder<EncryptedStringValue, int, QQueryOperations> idProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'id');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, String, QQueryOperations> keyProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'key');
|
||||
});
|
||||
}
|
||||
|
||||
QueryBuilder<EncryptedStringValue, String, QQueryOperations> valueProperty() {
|
||||
return QueryBuilder.apply(this, (query) {
|
||||
return query.addPropertyName(r'value');
|
||||
});
|
||||
}
|
||||
}
|
|
@ -65,8 +65,7 @@ class NodeModel {
|
|||
}
|
||||
|
||||
/// convenience getter to retrieve login password
|
||||
Future<String?> getPassword(
|
||||
FlutterSecureStorageInterface secureStorage) async {
|
||||
Future<String?> getPassword(SecureStorageInterface secureStorage) async {
|
||||
return await secureStorage.read(key: "${id}_nodePW");
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@ import 'package:stackwallet/models/notification_model.dart';
|
|||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
|
||||
|
@ -20,22 +22,33 @@ class NotificationCard extends StatelessWidget {
|
|||
return Format.extractDateFrom(date.millisecondsSinceEpoch ~/ 1000);
|
||||
}
|
||||
|
||||
static const double mobileIconSize = 24;
|
||||
static const double desktopIconSize = 30;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final isDesktop = Util.isDesktop;
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
RoundedWhiteContainer(
|
||||
padding: isDesktop
|
||||
? const EdgeInsets.symmetric(
|
||||
horizontal: 20,
|
||||
vertical: 10,
|
||||
)
|
||||
: const EdgeInsets.all(12),
|
||||
child: Row(
|
||||
children: [
|
||||
notification.changeNowId == null
|
||||
? SvgPicture.asset(
|
||||
notification.iconAssetName,
|
||||
width: 24,
|
||||
height: 24,
|
||||
width: isDesktop ? desktopIconSize : mobileIconSize,
|
||||
height: isDesktop ? desktopIconSize : mobileIconSize,
|
||||
)
|
||||
: Container(
|
||||
width: 24,
|
||||
height: 24,
|
||||
width: isDesktop ? desktopIconSize : mobileIconSize,
|
||||
height: isDesktop ? desktopIconSize : mobileIconSize,
|
||||
decoration: BoxDecoration(
|
||||
color: Colors.transparent,
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
|
@ -45,8 +58,8 @@ class NotificationCard extends StatelessWidget {
|
|||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
width: 24,
|
||||
height: 24,
|
||||
width: isDesktop ? desktopIconSize : mobileIconSize,
|
||||
height: isDesktop ? desktopIconSize : mobileIconSize,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -56,9 +69,35 @@ class NotificationCard extends StatelessWidget {
|
|||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
Text(
|
||||
notification.title,
|
||||
style: STextStyles.titleBold12(context),
|
||||
ConditionalParent(
|
||||
condition: isDesktop && !notification.read,
|
||||
builder: (child) => Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
child,
|
||||
Text(
|
||||
"New",
|
||||
style:
|
||||
STextStyles.desktopTextExtraExtraSmall(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorGreen,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
child: Text(
|
||||
notification.title,
|
||||
style: isDesktop
|
||||
? STextStyles.desktopTextExtraExtraSmall(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark,
|
||||
)
|
||||
: STextStyles.titleBold12(context),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
|
@ -68,11 +107,25 @@ class NotificationCard extends StatelessWidget {
|
|||
children: [
|
||||
Text(
|
||||
notification.description,
|
||||
style: STextStyles.label(context),
|
||||
style: isDesktop
|
||||
? STextStyles.desktopTextExtraExtraSmall(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
)
|
||||
: STextStyles.label(context),
|
||||
),
|
||||
Text(
|
||||
extractPrettyDateString(notification.date),
|
||||
style: STextStyles.label(context),
|
||||
style: isDesktop
|
||||
? STextStyles.desktopTextExtraExtraSmall(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle1,
|
||||
)
|
||||
: STextStyles.label(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -4,6 +4,7 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/pages/add_wallet_views/new_wallet_recovery_phrase_view/new_wallet_recovery_phrase_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
|
||||
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/services/coins/coin_service.dart';
|
||||
import 'package:stackwallet/services/coins/manager.dart';
|
||||
|
@ -241,6 +242,7 @@ class _NewWalletRecoveryPhraseWarningViewState
|
|||
coin,
|
||||
walletId,
|
||||
walletName,
|
||||
ref.read(secureStoreProvider),
|
||||
node,
|
||||
txTracker,
|
||||
ref.read(prefsChangeNotifierProvider),
|
||||
|
|
|
@ -19,6 +19,7 @@ import 'package:stackwallet/pages/add_wallet_views/restore_wallet_view/sub_widge
|
|||
import 'package:stackwallet/pages/home_view/home_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/exit_to_my_stack_button.dart';
|
||||
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/services/coins/coin_service.dart';
|
||||
import 'package:stackwallet/services/coins/manager.dart';
|
||||
|
@ -273,6 +274,7 @@ class _RestoreWalletViewState extends ConsumerState<RestoreWalletView> {
|
|||
widget.coin,
|
||||
walletId,
|
||||
widget.walletName,
|
||||
ref.read(secureStoreProvider),
|
||||
node,
|
||||
txTracker,
|
||||
ref.read(prefsChangeNotifierProvider),
|
||||
|
|
|
@ -15,15 +15,17 @@ import 'package:stackwallet/utilities/clipboard_interface.dart';
|
|||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||
import 'package:stackwallet/widgets/emoji_select_sheet.dart';
|
||||
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
|
||||
import 'package:stackwallet/widgets/stack_text_field.dart';
|
||||
import 'package:stackwallet/widgets/textfield_icon_button.dart';
|
||||
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
||||
class AddAddressBookEntryView extends ConsumerStatefulWidget {
|
||||
const AddAddressBookEntryView({
|
||||
Key? key,
|
||||
|
@ -108,395 +110,537 @@ class _AddAddressBookEntryViewState
|
|||
Widget build(BuildContext context) {
|
||||
debugPrint("BUILD: $runtimeType");
|
||||
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
|
||||
appBar: AppBar(
|
||||
leading: AppBarBackButton(
|
||||
onPressed: () async {
|
||||
if (FocusScope.of(context).hasFocus) {
|
||||
FocusScope.of(context).unfocus();
|
||||
await Future<void>.delayed(const Duration(milliseconds: 75));
|
||||
}
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
title: Text(
|
||||
"New contact",
|
||||
style: STextStyles.navBarTitle(context),
|
||||
),
|
||||
actions: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 10,
|
||||
bottom: 10,
|
||||
right: 10,
|
||||
),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: AppBarIconButton(
|
||||
key: const Key("addAddressBookEntryFavoriteButtonKey"),
|
||||
size: 36,
|
||||
shadows: const [],
|
||||
color: Theme.of(context).extension<StackColors>()!.background,
|
||||
icon: SvgPicture.asset(
|
||||
Assets.svg.star,
|
||||
color: _isFavorite
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.favoriteStarActive
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.favoriteStarInactive,
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isFavorite = !_isFavorite;
|
||||
});
|
||||
final isDesktop = Util.isDesktop;
|
||||
return ConditionalParent(
|
||||
condition: !isDesktop,
|
||||
builder: (child) {
|
||||
return Scaffold(
|
||||
backgroundColor:
|
||||
Theme.of(context).extension<StackColors>()!.background,
|
||||
appBar: AppBar(
|
||||
leading: AppBarBackButton(
|
||||
onPressed: () async {
|
||||
if (FocusScope.of(context).hasFocus) {
|
||||
FocusScope.of(context).unfocus();
|
||||
await Future<void>.delayed(
|
||||
const Duration(milliseconds: 75));
|
||||
}
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: LayoutBuilder(
|
||||
builder: (context, constraint) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: SingleChildScrollView(
|
||||
controller: scrollController,
|
||||
padding: const EdgeInsets.only(
|
||||
// top: 8,
|
||||
left: 4,
|
||||
right: 4,
|
||||
bottom: 16,
|
||||
title: Text(
|
||||
"New contact",
|
||||
style: STextStyles.navBarTitle(context),
|
||||
),
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
// subtract top and bottom padding set in parent
|
||||
minHeight: constraint.maxHeight - 16, // - 8,
|
||||
),
|
||||
child: IntrinsicHeight(
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
actions: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 10,
|
||||
bottom: 10,
|
||||
right: 10,
|
||||
),
|
||||
child: AspectRatio(
|
||||
aspectRatio: 1,
|
||||
child: AppBarIconButton(
|
||||
key: const Key("addAddressBookEntryFavoriteButtonKey"),
|
||||
size: 36,
|
||||
shadows: const [],
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.background,
|
||||
icon: SvgPicture.asset(
|
||||
Assets.svg.star,
|
||||
color: _isFavorite
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.favoriteStarActive
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.favoriteStarInactive,
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (_selectedEmoji != null) {
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_isFavorite = !_isFavorite;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
body: child);
|
||||
},
|
||||
child: ConditionalParent(
|
||||
condition: isDesktop,
|
||||
builder: (child) {
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(32),
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
"New contact",
|
||||
style: STextStyles.desktopH3(context),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
AppBarIconButton(
|
||||
key:
|
||||
const Key("addAddressBookEntryFavoriteButtonKey"),
|
||||
size: 36,
|
||||
shadows: const [],
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.background,
|
||||
icon: SvgPicture.asset(
|
||||
Assets.svg.star,
|
||||
color: _isFavorite
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.favoriteStarActive
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.favoriteStarInactive,
|
||||
width: 20,
|
||||
height: 20,
|
||||
),
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
_selectedEmoji = null;
|
||||
_isFavorite = !_isFavorite;
|
||||
});
|
||||
return;
|
||||
}
|
||||
showModalBottomSheet<dynamic>(
|
||||
backgroundColor: Colors.transparent,
|
||||
context: context,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(20),
|
||||
),
|
||||
),
|
||||
builder: (_) => const EmojiSelectSheet(),
|
||||
).then((value) {
|
||||
if (value is Emoji) {
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const DesktopDialogCloseButton(),
|
||||
],
|
||||
),
|
||||
Expanded(child: child),
|
||||
],
|
||||
);
|
||||
},
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraint) {
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||
child: SingleChildScrollView(
|
||||
controller: scrollController,
|
||||
padding: const EdgeInsets.only(
|
||||
// top: 8,
|
||||
left: 4,
|
||||
right: 4,
|
||||
bottom: 16,
|
||||
),
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
// subtract top and bottom padding set in parent
|
||||
minHeight: constraint.maxHeight - 16, // - 8,
|
||||
),
|
||||
child: IntrinsicHeight(
|
||||
child: Column(
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 4,
|
||||
),
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (_selectedEmoji != null) {
|
||||
setState(() {
|
||||
_selectedEmoji = value;
|
||||
_selectedEmoji = null;
|
||||
});
|
||||
return;
|
||||
}
|
||||
});
|
||||
},
|
||||
child: SizedBox(
|
||||
height: 48,
|
||||
width: 48,
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
height: 48,
|
||||
width: 48,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldActiveBG,
|
||||
),
|
||||
child: Center(
|
||||
child: _selectedEmoji == null
|
||||
? SvgPicture.asset(
|
||||
Assets.svg.user,
|
||||
height: 24,
|
||||
width: 24,
|
||||
)
|
||||
: Text(
|
||||
_selectedEmoji!.char,
|
||||
style:
|
||||
STextStyles.pageTitleH1(context),
|
||||
|
||||
///TODO if desktop make dialog
|
||||
!isDesktop
|
||||
? showModalBottomSheet<dynamic>(
|
||||
backgroundColor: Colors.transparent,
|
||||
context: context,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(20),
|
||||
),
|
||||
),
|
||||
builder: (_) => const EmojiSelectSheet(),
|
||||
).then((value) {
|
||||
if (value is Emoji) {
|
||||
setState(() {
|
||||
_selectedEmoji = value;
|
||||
});
|
||||
}
|
||||
})
|
||||
: showDialog<dynamic>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
return DesktopDialog(
|
||||
maxHeight: 700,
|
||||
maxWidth: 700,
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.all(32),
|
||||
child: Text(
|
||||
"Select emoji",
|
||||
style:
|
||||
STextStyles.desktopH3(
|
||||
context),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Expanded(
|
||||
child: LayoutBuilder(
|
||||
builder:
|
||||
(context, constraints) {
|
||||
return SingleChildScrollView(
|
||||
scrollDirection:
|
||||
Axis.vertical,
|
||||
child: ConstrainedBox(
|
||||
constraints:
|
||||
BoxConstraints(
|
||||
minHeight: constraints
|
||||
.maxHeight,
|
||||
minWidth: constraints
|
||||
.maxWidth,
|
||||
),
|
||||
child: IntrinsicHeight(
|
||||
child: Column(
|
||||
children: const [
|
||||
Padding(
|
||||
padding: EdgeInsets
|
||||
.symmetric(
|
||||
horizontal:
|
||||
32),
|
||||
// child:
|
||||
// EmojiSelectSheet(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: Container(
|
||||
height: 14,
|
||||
width: 14,
|
||||
);
|
||||
}).then((value) {
|
||||
if (value is Emoji) {
|
||||
setState(() {
|
||||
_selectedEmoji = value;
|
||||
});
|
||||
}
|
||||
});
|
||||
},
|
||||
child: SizedBox(
|
||||
height: 48,
|
||||
width: 48,
|
||||
child: Stack(
|
||||
children: [
|
||||
Container(
|
||||
height: 48,
|
||||
width: 48,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark),
|
||||
borderRadius: BorderRadius.circular(24),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldActiveBG,
|
||||
),
|
||||
child: Center(
|
||||
child: _selectedEmoji == null
|
||||
? SvgPicture.asset(
|
||||
Assets.svg.plus,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textWhite,
|
||||
width: 12,
|
||||
height: 12,
|
||||
Assets.svg.user,
|
||||
height: 24,
|
||||
width: 24,
|
||||
)
|
||||
: SvgPicture.asset(
|
||||
Assets.svg.thickX,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textWhite,
|
||||
width: 8,
|
||||
height: 8,
|
||||
: Text(
|
||||
_selectedEmoji!.char,
|
||||
style: STextStyles.pageTitleH1(
|
||||
context),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
autocorrect: Util.isDesktop ? false : true,
|
||||
enableSuggestions: Util.isDesktop ? false : true,
|
||||
controller: nameController,
|
||||
focusNode: nameFocusNode,
|
||||
style: STextStyles.field(context),
|
||||
decoration: standardInputDecoration(
|
||||
"Enter contact name",
|
||||
nameFocusNode,
|
||||
context,
|
||||
).copyWith(
|
||||
suffixIcon: ref
|
||||
.read(contactNameIsNotEmptyStateProvider
|
||||
.state)
|
||||
.state
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(right: 0),
|
||||
child: UnconstrainedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
TextFieldIconButton(
|
||||
child: const XIcon(),
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
nameController.text = "";
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
Align(
|
||||
alignment: Alignment.bottomRight,
|
||||
child: Container(
|
||||
height: 14,
|
||||
width: 14,
|
||||
decoration: BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(14),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark),
|
||||
child: Center(
|
||||
child: _selectedEmoji == null
|
||||
? SvgPicture.asset(
|
||||
Assets.svg.plus,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textWhite,
|
||||
width: 12,
|
||||
height: 12,
|
||||
)
|
||||
: SvgPicture.asset(
|
||||
Assets.svg.thickX,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textWhite,
|
||||
width: 8,
|
||||
height: 8,
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
onChanged: (newValue) {
|
||||
ref
|
||||
.read(contactNameIsNotEmptyStateProvider.state)
|
||||
.state = newValue.isNotEmpty;
|
||||
},
|
||||
),
|
||||
),
|
||||
if (forms.length <= 1)
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
if (forms.length <= 1) forms[0],
|
||||
if (forms.length > 1)
|
||||
for (int i = 0; i < forms.length; i++)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Address ${i + 1}",
|
||||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
BlueTextButton(
|
||||
onTap: () {
|
||||
_removeForm(forms[i].id);
|
||||
},
|
||||
text: "Remove",
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
forms[i],
|
||||
],
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
BlueTextButton(
|
||||
onTap: () {
|
||||
_addForm();
|
||||
scrollController.animateTo(
|
||||
scrollController.position.maxScrollExtent + 500,
|
||||
duration: const Duration(milliseconds: 500),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
},
|
||||
text: "+ Add another address",
|
||||
),
|
||||
// GestureDetector(
|
||||
//
|
||||
// child: Text(
|
||||
// "+ Add another address",
|
||||
// style: STextStyles.largeMedium14(context),
|
||||
// ),
|
||||
// ),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
const Spacer(),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getSecondaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Cancel",
|
||||
style: STextStyles.button(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark),
|
||||
),
|
||||
onPressed: () async {
|
||||
if (FocusScope.of(context).hasFocus) {
|
||||
FocusScope.of(context).unfocus();
|
||||
await Future<void>.delayed(
|
||||
const Duration(milliseconds: 75));
|
||||
}
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
child: TextField(
|
||||
autocorrect: Util.isDesktop ? false : true,
|
||||
enableSuggestions: Util.isDesktop ? false : true,
|
||||
controller: nameController,
|
||||
focusNode: nameFocusNode,
|
||||
style: STextStyles.field(context),
|
||||
decoration: standardInputDecoration(
|
||||
"Enter contact name",
|
||||
nameFocusNode,
|
||||
context,
|
||||
).copyWith(
|
||||
suffixIcon: ref
|
||||
.read(contactNameIsNotEmptyStateProvider
|
||||
.state)
|
||||
.state
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(right: 0),
|
||||
child: UnconstrainedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
TextFieldIconButton(
|
||||
child: const XIcon(),
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
nameController.text = "";
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
onChanged: (newValue) {
|
||||
ref
|
||||
.read(
|
||||
contactNameIsNotEmptyStateProvider.state)
|
||||
.state = newValue.isNotEmpty;
|
||||
},
|
||||
),
|
||||
),
|
||||
if (forms.length <= 1)
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
height: 8,
|
||||
),
|
||||
Expanded(
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
bool nameExists = ref
|
||||
.watch(contactNameIsNotEmptyStateProvider
|
||||
.state)
|
||||
.state;
|
||||
|
||||
bool validForms = ref.watch(
|
||||
validContactStateProvider(forms
|
||||
.map((e) => e.id)
|
||||
.toList(growable: false)));
|
||||
|
||||
bool shouldEnableSave =
|
||||
validForms && nameExists;
|
||||
|
||||
return TextButton(
|
||||
style: shouldEnableSave
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonColor(context)
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryDisabledButtonColor(
|
||||
context),
|
||||
onPressed: shouldEnableSave
|
||||
? () async {
|
||||
if (FocusScope.of(context).hasFocus) {
|
||||
FocusScope.of(context).unfocus();
|
||||
await Future<void>.delayed(
|
||||
const Duration(milliseconds: 75),
|
||||
);
|
||||
}
|
||||
List<ContactAddressEntry> entries =
|
||||
[];
|
||||
for (int i = 0;
|
||||
i < forms.length;
|
||||
i++) {
|
||||
entries.add(ref
|
||||
.read(addressEntryDataProvider(
|
||||
forms[i].id))
|
||||
.buildAddressEntry());
|
||||
}
|
||||
Contact contact = Contact(
|
||||
emojiChar: _selectedEmoji?.char,
|
||||
name: nameController.text,
|
||||
addresses: entries,
|
||||
isFavorite: _isFavorite,
|
||||
);
|
||||
|
||||
if (await ref
|
||||
.read(addressBookServiceProvider)
|
||||
.addContact(contact)) {
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
// TODO show success notification
|
||||
} else {
|
||||
// TODO show error notification
|
||||
}
|
||||
}
|
||||
: null,
|
||||
child: Text(
|
||||
"Save",
|
||||
style: STextStyles.button(context).copyWith(
|
||||
color: shouldEnableSave
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonTextPrimary
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonTextPrimaryDisabled,
|
||||
if (forms.length <= 1) forms[0],
|
||||
if (forms.length > 1)
|
||||
for (int i = 0; i < forms.length; i++)
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Address ${i + 1}",
|
||||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
BlueTextButton(
|
||||
onTap: () {
|
||||
_removeForm(forms[i].id);
|
||||
},
|
||||
text: "Remove",
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
forms[i],
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
BlueTextButton(
|
||||
onTap: () {
|
||||
_addForm();
|
||||
scrollController.animateTo(
|
||||
scrollController.position.maxScrollExtent + 500,
|
||||
duration: const Duration(milliseconds: 500),
|
||||
curve: Curves.easeInOut,
|
||||
);
|
||||
},
|
||||
text: "+ Add another address",
|
||||
),
|
||||
// GestureDetector(
|
||||
//
|
||||
// child: Text(
|
||||
// "+ Add another address",
|
||||
// style: STextStyles.largeMedium14(context),
|
||||
// ),
|
||||
// ),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
const Spacer(),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getSecondaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Cancel",
|
||||
style: STextStyles.button(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark),
|
||||
),
|
||||
onPressed: () async {
|
||||
if (FocusScope.of(context).hasFocus) {
|
||||
FocusScope.of(context).unfocus();
|
||||
await Future<void>.delayed(
|
||||
const Duration(milliseconds: 75));
|
||||
}
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
Expanded(
|
||||
child: Builder(
|
||||
builder: (context) {
|
||||
bool nameExists = ref
|
||||
.watch(contactNameIsNotEmptyStateProvider
|
||||
.state)
|
||||
.state;
|
||||
|
||||
bool validForms = ref.watch(
|
||||
validContactStateProvider(forms
|
||||
.map((e) => e.id)
|
||||
.toList(growable: false)));
|
||||
|
||||
bool shouldEnableSave =
|
||||
validForms && nameExists;
|
||||
|
||||
return TextButton(
|
||||
style: shouldEnableSave
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonColor(
|
||||
context)
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryDisabledButtonColor(
|
||||
context),
|
||||
onPressed: shouldEnableSave
|
||||
? () async {
|
||||
if (FocusScope.of(context)
|
||||
.hasFocus) {
|
||||
FocusScope.of(context).unfocus();
|
||||
await Future<void>.delayed(
|
||||
const Duration(
|
||||
milliseconds: 75),
|
||||
);
|
||||
}
|
||||
List<ContactAddressEntry> entries =
|
||||
[];
|
||||
for (int i = 0;
|
||||
i < forms.length;
|
||||
i++) {
|
||||
entries.add(ref
|
||||
.read(
|
||||
addressEntryDataProvider(
|
||||
forms[i].id))
|
||||
.buildAddressEntry());
|
||||
}
|
||||
Contact contact = Contact(
|
||||
emojiChar: _selectedEmoji?.char,
|
||||
name: nameController.text,
|
||||
addresses: entries,
|
||||
isFavorite: _isFavorite,
|
||||
);
|
||||
|
||||
if (await ref
|
||||
.read(
|
||||
addressBookServiceProvider)
|
||||
.addContact(contact)) {
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
// TODO show success notification
|
||||
} else {
|
||||
// TODO show error notification
|
||||
}
|
||||
}
|
||||
: null,
|
||||
child: Text(
|
||||
"Save",
|
||||
style:
|
||||
STextStyles.button(context).copyWith(
|
||||
color: shouldEnableSave
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonTextPrimary
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonTextPrimaryDisabled,
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
|
@ -5,7 +5,12 @@ import 'package:stackwallet/providers/ui/address_book_providers/address_book_fil
|
|||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
|
||||
class AddressBookFilterView extends ConsumerStatefulWidget {
|
||||
|
@ -41,167 +46,224 @@ class _AddressBookFilterViewState extends ConsumerState<AddressBookFilterView> {
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
|
||||
appBar: AppBar(
|
||||
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
|
||||
leading: AppBarBackButton(
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
title: Text(
|
||||
"Filter addresses",
|
||||
style: STextStyles.navBarTitle(context),
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: LayoutBuilder(builder: (builderContext, constraints) {
|
||||
return SingleChildScrollView(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: constraints.maxHeight,
|
||||
final isDesktop = Util.isDesktop;
|
||||
return ConditionalParent(
|
||||
condition: !isDesktop,
|
||||
builder: (child) {
|
||||
return Scaffold(
|
||||
backgroundColor:
|
||||
Theme.of(context).extension<StackColors>()!.background,
|
||||
appBar: AppBar(
|
||||
backgroundColor:
|
||||
Theme.of(context).extension<StackColors>()!.background,
|
||||
leading: AppBarBackButton(
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
title: Text(
|
||||
"Filter addresses",
|
||||
style: STextStyles.navBarTitle(context),
|
||||
),
|
||||
),
|
||||
body: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: LayoutBuilder(builder: (builderContext, constraints) {
|
||||
return SingleChildScrollView(
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: constraints.maxHeight,
|
||||
),
|
||||
child: IntrinsicHeight(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
RoundedWhiteContainer(
|
||||
child: Text(
|
||||
"Only selected cryptocurrency addresses will be displayed.",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Text(
|
||||
"Select cryptocurrency",
|
||||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
child,
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: ConditionalParent(
|
||||
condition: isDesktop,
|
||||
builder: (child) {
|
||||
return Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(32),
|
||||
child: Text(
|
||||
"Select cryptocurrency",
|
||||
style: STextStyles.desktopH3(context),
|
||||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
const DesktopDialogCloseButton(),
|
||||
],
|
||||
),
|
||||
child: IntrinsicHeight(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(4),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||
children: [
|
||||
RoundedWhiteContainer(
|
||||
child: Text(
|
||||
"Only selected cryptocurrency addresses will be displayed.",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
Expanded(
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) {
|
||||
return SingleChildScrollView(
|
||||
scrollDirection: Axis.vertical,
|
||||
child: ConstrainedBox(
|
||||
constraints: BoxConstraints(
|
||||
minHeight: constraints.maxHeight,
|
||||
),
|
||||
child: IntrinsicHeight(
|
||||
child: Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 32),
|
||||
child: child,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
Text(
|
||||
"Select cryptocurrency",
|
||||
style: STextStyles.smallMed12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 12,
|
||||
),
|
||||
RoundedWhiteContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
child: Wrap(
|
||||
children: [
|
||||
..._coins.map(
|
||||
(coin) => Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (ref
|
||||
.read(addressBookFilterProvider)
|
||||
.coins
|
||||
.contains(coin)) {
|
||||
ref
|
||||
.read(addressBookFilterProvider)
|
||||
.remove(coin, true);
|
||||
} else {
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding:
|
||||
const EdgeInsets.symmetric(horizontal: 32, vertical: 32),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
SecondaryButton(
|
||||
width: 248,
|
||||
desktopMed: true,
|
||||
enabled: true,
|
||||
label: "Cancel",
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
// const SizedBox(width: 16),
|
||||
PrimaryButton(
|
||||
width: 248,
|
||||
desktopMed: true,
|
||||
enabled: true,
|
||||
label: "Apply",
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
child: RoundedWhiteContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
child: Wrap(
|
||||
children: [
|
||||
..._coins.map(
|
||||
(coin) => Row(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: () {
|
||||
if (ref
|
||||
.read(addressBookFilterProvider)
|
||||
.coins
|
||||
.contains(coin)) {
|
||||
ref
|
||||
.read(addressBookFilterProvider)
|
||||
.remove(coin, true);
|
||||
} else {
|
||||
ref.read(addressBookFilterProvider).add(coin, true);
|
||||
}
|
||||
setState(() {});
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: Checkbox(
|
||||
value: ref
|
||||
.watch(addressBookFilterProvider
|
||||
.select((value) => value.coins))
|
||||
.contains(coin),
|
||||
onChanged: (value) {
|
||||
if (value is bool) {
|
||||
if (value) {
|
||||
ref
|
||||
.read(addressBookFilterProvider)
|
||||
.add(coin, true);
|
||||
} else {
|
||||
ref
|
||||
.read(addressBookFilterProvider)
|
||||
.remove(coin, true);
|
||||
}
|
||||
setState(() {});
|
||||
},
|
||||
child: Container(
|
||||
color: Colors.transparent,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(12),
|
||||
child: Row(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 20,
|
||||
width: 20,
|
||||
child: Checkbox(
|
||||
value: ref
|
||||
.watch(
|
||||
addressBookFilterProvider
|
||||
.select((value) =>
|
||||
value.coins))
|
||||
.contains(coin),
|
||||
onChanged: (value) {
|
||||
if (value is bool) {
|
||||
if (value) {
|
||||
ref
|
||||
.read(
|
||||
addressBookFilterProvider)
|
||||
.add(coin, true);
|
||||
} else {
|
||||
ref
|
||||
.read(
|
||||
addressBookFilterProvider)
|
||||
.remove(coin, true);
|
||||
}
|
||||
setState(() {});
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
coin.prettyName,
|
||||
style:
|
||||
STextStyles.largeMedium14(
|
||||
context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
Text(
|
||||
coin.ticker,
|
||||
style:
|
||||
STextStyles.itemSubtitle(
|
||||
context),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
coin.prettyName,
|
||||
style: STextStyles.largeMedium14(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
Text(
|
||||
coin.ticker,
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
// Row(
|
||||
// children: [
|
||||
// TextButton(
|
||||
// onPressed: () {},
|
||||
// child: Text("Cancel"),
|
||||
// ),
|
||||
// SizedBox(
|
||||
// width: 16,
|
||||
// ),
|
||||
// TextButton(
|
||||
// onPressed: () {},
|
||||
// child: Text("Cancel"),
|
||||
// ),
|
||||
// ],
|
||||
// )
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -2,10 +2,10 @@ import 'dart:io';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/pages/home_view/home_view.dart';
|
||||
import 'package:stackwallet/providers/global/prefs_provider.dart';
|
||||
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/biometrics.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
|
@ -20,15 +20,11 @@ class CreatePinView extends ConsumerStatefulWidget {
|
|||
const CreatePinView({
|
||||
Key? key,
|
||||
this.popOnSuccess = false,
|
||||
this.secureStore = const SecureStorageWrapper(
|
||||
FlutterSecureStorage(),
|
||||
),
|
||||
this.biometrics = const Biometrics(),
|
||||
}) : super(key: key);
|
||||
|
||||
static const String routeName = "/createPin";
|
||||
|
||||
final FlutterSecureStorageInterface secureStore;
|
||||
final Biometrics biometrics;
|
||||
final bool popOnSuccess;
|
||||
|
||||
|
@ -58,12 +54,12 @@ class _CreatePinViewState extends ConsumerState<CreatePinView> {
|
|||
final TextEditingController _pinPutController2 = TextEditingController();
|
||||
final FocusNode _pinPutFocusNode2 = FocusNode();
|
||||
|
||||
late FlutterSecureStorageInterface _secureStore;
|
||||
late SecureStorageInterface _secureStore;
|
||||
late Biometrics biometrics;
|
||||
|
||||
@override
|
||||
initState() {
|
||||
_secureStore = widget.secureStore;
|
||||
_secureStore = ref.read(secureStoreProvider);
|
||||
biometrics = widget.biometrics;
|
||||
super.initState();
|
||||
}
|
||||
|
|
|
@ -2,12 +2,12 @@ import 'dart:async';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/pages/home_view/home_view.dart';
|
||||
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
||||
// import 'package:stackwallet/providers/global/has_authenticated_start_state_provider.dart';
|
||||
import 'package:stackwallet/providers/global/prefs_provider.dart';
|
||||
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||
// import 'package:stackwallet/providers/global/should_show_lockscreen_on_resume_state_provider.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
|
@ -33,9 +33,6 @@ class LockscreenView extends ConsumerStatefulWidget {
|
|||
this.popOnSuccess = false,
|
||||
this.isInitialAppLogin = false,
|
||||
this.routeOnSuccessArguments,
|
||||
this.secureStore = const SecureStorageWrapper(
|
||||
FlutterSecureStorage(),
|
||||
),
|
||||
this.biometrics = const Biometrics(),
|
||||
this.onSuccess,
|
||||
}) : super(key: key);
|
||||
|
@ -50,7 +47,6 @@ class LockscreenView extends ConsumerStatefulWidget {
|
|||
final String biometricsAuthenticationTitle;
|
||||
final String biometricsLocalizedReason;
|
||||
final String biometricsCancelButtonString;
|
||||
final FlutterSecureStorageInterface secureStore;
|
||||
final Biometrics biometrics;
|
||||
final VoidCallback? onSuccess;
|
||||
|
||||
|
@ -134,7 +130,7 @@ class _LockscreenViewState extends ConsumerState<LockscreenView> {
|
|||
void initState() {
|
||||
_shakeController = ShakeController();
|
||||
|
||||
_secureStore = widget.secureStore;
|
||||
_secureStore = ref.read(secureStoreProvider);
|
||||
biometrics = widget.biometrics;
|
||||
_attempts = 0;
|
||||
_timeout = Duration.zero;
|
||||
|
@ -162,7 +158,7 @@ class _LockscreenViewState extends ConsumerState<LockscreenView> {
|
|||
final _pinTextController = TextEditingController();
|
||||
final FocusNode _pinFocusNode = FocusNode();
|
||||
|
||||
late FlutterSecureStorageInterface _secureStore;
|
||||
late SecureStorageInterface _secureStore;
|
||||
late Biometrics biometrics;
|
||||
|
||||
Scaffold get _body => Scaffold(
|
||||
|
|
|
@ -8,6 +8,7 @@ import 'package:stackwallet/notifications/show_flush_bar.dart';
|
|||
import 'package:stackwallet/pages/pinpad_views/lock_screen_view.dart';
|
||||
import 'package:stackwallet/pages/send_view/sub_widgets/sending_transaction_dialog.dart';
|
||||
import 'package:stackwallet/pages/wallet_view/wallet_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/desktop_auth_send.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/providers/wallet/public_private_balance_state_provider.dart';
|
||||
import 'package:stackwallet/route_generator.dart';
|
||||
|
@ -23,6 +24,8 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
|||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
|
@ -54,22 +57,17 @@ class _ConfirmTransactionViewState
|
|||
late final String routeOnSuccessName;
|
||||
late final bool isDesktop;
|
||||
|
||||
int _fee = 12;
|
||||
final List<int> _dropDownItems = [
|
||||
12,
|
||||
22,
|
||||
234,
|
||||
];
|
||||
|
||||
Future<void> _attemptSend(BuildContext context) async {
|
||||
unawaited(showDialog<dynamic>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
barrierDismissible: false,
|
||||
builder: (context) {
|
||||
return const SendingTransactionDialog();
|
||||
},
|
||||
));
|
||||
unawaited(
|
||||
showDialog<dynamic>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
barrierDismissible: false,
|
||||
builder: (context) {
|
||||
return const SendingTransactionDialog();
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
final note = transactionInfo["note"] as String? ?? "";
|
||||
final manager =
|
||||
|
@ -122,25 +120,66 @@ class _ConfirmTransactionViewState
|
|||
useSafeArea: false,
|
||||
barrierDismissible: true,
|
||||
builder: (context) {
|
||||
return StackDialog(
|
||||
title: "Broadcast transaction failed",
|
||||
message: e.toString(),
|
||||
rightButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getSecondaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Ok",
|
||||
style: STextStyles.button(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark),
|
||||
if (isDesktop) {
|
||||
return DesktopDialog(
|
||||
maxWidth: 450,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(32),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Broadcast transaction failed",
|
||||
style: STextStyles.desktopH3(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
Text(
|
||||
e.toString(),
|
||||
style: STextStyles.smallMed14(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 56,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
const Spacer(),
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
desktopMed: true,
|
||||
label: "Ok",
|
||||
onPressed: Navigator.of(context).pop,
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
);
|
||||
);
|
||||
} else {
|
||||
return StackDialog(
|
||||
title: "Broadcast transaction failed",
|
||||
message: e.toString(),
|
||||
rightButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getSecondaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Ok",
|
||||
style: STextStyles.button(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -568,32 +607,101 @@ class _ConfirmTransactionViewState
|
|||
),
|
||||
if (isDesktop)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 10,
|
||||
left: 32,
|
||||
right: 32,
|
||||
),
|
||||
child: DropdownButtonFormField(
|
||||
value: _fee,
|
||||
items: _dropDownItems
|
||||
.map(
|
||||
(e) => DropdownMenuItem(
|
||||
value: e,
|
||||
child: Text(
|
||||
e.toString(),
|
||||
),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
onChanged: (value) {
|
||||
if (value is int) {
|
||||
setState(() {
|
||||
_fee = value;
|
||||
});
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.only(
|
||||
top: 10,
|
||||
left: 32,
|
||||
right: 32,
|
||||
),
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 18,
|
||||
),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultBG,
|
||||
child: Builder(builder: (context) {
|
||||
final coin = ref
|
||||
.watch(walletsChangeNotifierProvider
|
||||
.select((value) => value.getManager(walletId)))
|
||||
.coin;
|
||||
|
||||
final fee = Format.satoshisToAmount(
|
||||
transactionInfo["fee"] as int,
|
||||
coin: coin,
|
||||
);
|
||||
|
||||
return Text(
|
||||
"${Format.localizedStringAsFixed(
|
||||
value: fee,
|
||||
locale: ref.watch(localeServiceChangeNotifierProvider
|
||||
.select((value) => value.locale)),
|
||||
decimalPlaces: coin == Coin.monero
|
||||
? Constants.decimalPlacesMonero
|
||||
: coin == Coin.wownero
|
||||
? Constants.decimalPlacesWownero
|
||||
: Constants.decimalPlaces,
|
||||
)} ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
}),
|
||||
)
|
||||
// DropdownButtonHideUnderline(
|
||||
// child: DropdownButton2(
|
||||
// offset: const Offset(0, -10),
|
||||
// isExpanded: true,
|
||||
//
|
||||
// dropdownElevation: 0,
|
||||
// value: _fee,
|
||||
// items: [
|
||||
// ..._dropDownItems.map(
|
||||
// (e) {
|
||||
// String message = _fee.toString();
|
||||
//
|
||||
// return DropdownMenuItem(
|
||||
// value: e,
|
||||
// child: Text(message),
|
||||
// );
|
||||
// },
|
||||
// ),
|
||||
// ],
|
||||
// onChanged: (value) {
|
||||
// if (value is int) {
|
||||
// setState(() {
|
||||
// _fee = value;
|
||||
// });
|
||||
// }
|
||||
// },
|
||||
// icon: SvgPicture.asset(
|
||||
// Assets.svg.chevronDown,
|
||||
// width: 12,
|
||||
// height: 6,
|
||||
// color:
|
||||
// Theme.of(context).extension<StackColors>()!.textDark3,
|
||||
// ),
|
||||
// buttonPadding: const EdgeInsets.symmetric(
|
||||
// horizontal: 16,
|
||||
// vertical: 8,
|
||||
// ),
|
||||
// buttonDecoration: BoxDecoration(
|
||||
// color: Theme.of(context)
|
||||
// .extension<StackColors>()!
|
||||
// .textFieldDefaultBG,
|
||||
// borderRadius: BorderRadius.circular(
|
||||
// Constants.size.circularBorderRadius,
|
||||
// ),
|
||||
// ),
|
||||
// dropdownDecoration: BoxDecoration(
|
||||
// color: Theme.of(context)
|
||||
// .extension<StackColors>()!
|
||||
// .textFieldDefaultBG,
|
||||
// borderRadius: BorderRadius.circular(
|
||||
// Constants.size.circularBorderRadius,
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
// ),
|
||||
),
|
||||
if (!isDesktop) const Spacer(),
|
||||
SizedBox(
|
||||
height: isDesktop ? 23 : 12,
|
||||
|
@ -674,25 +782,56 @@ class _ConfirmTransactionViewState
|
|||
label: "Send",
|
||||
desktopMed: true,
|
||||
onPressed: () async {
|
||||
final unlocked = await Navigator.push(
|
||||
context,
|
||||
RouteGenerator.getRoute(
|
||||
shouldUseMaterialRoute:
|
||||
RouteGenerator.useMaterialPageRoute,
|
||||
builder: (_) => const LockscreenView(
|
||||
showBackButton: true,
|
||||
popOnSuccess: true,
|
||||
routeOnSuccessArguments: true,
|
||||
routeOnSuccess: "",
|
||||
biometricsCancelButtonString: "CANCEL",
|
||||
biometricsLocalizedReason:
|
||||
"Authenticate to send transaction",
|
||||
biometricsAuthenticationTitle: "Confirm Transaction",
|
||||
final dynamic unlocked;
|
||||
|
||||
if (isDesktop) {
|
||||
unlocked = await showDialog<bool?>(
|
||||
context: context,
|
||||
builder: (context) => DesktopDialog(
|
||||
maxWidth: 580,
|
||||
maxHeight: double.infinity,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: const [
|
||||
DesktopDialogCloseButton(),
|
||||
],
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 32,
|
||||
right: 32,
|
||||
bottom: 32,
|
||||
),
|
||||
child: DesktopAuthSend(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
settings:
|
||||
const RouteSettings(name: "/confirmsendlockscreen"),
|
||||
),
|
||||
);
|
||||
);
|
||||
} else {
|
||||
unlocked = await Navigator.push(
|
||||
context,
|
||||
RouteGenerator.getRoute(
|
||||
shouldUseMaterialRoute:
|
||||
RouteGenerator.useMaterialPageRoute,
|
||||
builder: (_) => const LockscreenView(
|
||||
showBackButton: true,
|
||||
popOnSuccess: true,
|
||||
routeOnSuccessArguments: true,
|
||||
routeOnSuccess: "",
|
||||
biometricsCancelButtonString: "CANCEL",
|
||||
biometricsLocalizedReason:
|
||||
"Authenticate to send transaction",
|
||||
biometricsAuthenticationTitle: "Confirm Transaction",
|
||||
),
|
||||
settings:
|
||||
const RouteSettings(name: "/confirmsendlockscreen"),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if (unlocked is bool && unlocked && mounted) {
|
||||
unawaited(_attemptSend(context));
|
||||
|
|
|
@ -1,7 +1,10 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||
|
||||
class SendingTransactionDialog extends StatefulWidget {
|
||||
|
@ -43,24 +46,56 @@ class _RestoringDialogState extends State<SendingTransactionDialog>
|
|||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
return false;
|
||||
},
|
||||
child: StackDialog(
|
||||
title: "Sending transaction",
|
||||
// // TODO get message from design team
|
||||
// message: "<PLACEHOLDER>",
|
||||
icon: RotationTransition(
|
||||
turns: _spinAnimation,
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.arrowRotate,
|
||||
color: Theme.of(context).extension<StackColors>()!.accentColorDark,
|
||||
width: 24,
|
||||
height: 24,
|
||||
if (Util.isDesktop) {
|
||||
return DesktopDialog(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(40),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
"Sending transaction",
|
||||
style: STextStyles.desktopH3(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 40,
|
||||
),
|
||||
RotationTransition(
|
||||
turns: _spinAnimation,
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.arrowRotate,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
} else {
|
||||
return WillPopScope(
|
||||
onWillPop: () async {
|
||||
return false;
|
||||
},
|
||||
child: StackDialog(
|
||||
title: "Sending transaction",
|
||||
// // TODO get message from design team
|
||||
// message: "<PLACEHOLDER>",
|
||||
icon: RotationTransition(
|
||||
turns: _spinAnimation,
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.arrowRotate,
|
||||
color:
|
||||
Theme.of(context).extension<StackColors>()!.accentColorDark,
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,19 +7,25 @@ import 'package:event_bus/event_bus.dart';
|
|||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_libepiccash/git_versions.dart' as EPIC_VERSIONS;
|
||||
import 'package:flutter_libmonero/git_versions.dart' as MONERO_VERSIONS;
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:lelantus/git_versions.dart' as FIRO_VERSIONS;
|
||||
import 'package:package_info_plus/package_info_plus.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:stackwallet/models/isar/models/log.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/swb_file_system.dart';
|
||||
import 'package:stackwallet/providers/global/debug_service_provider.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/clipboard_interface.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/stack_file_system.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
|
||||
import 'package:stackwallet/widgets/custom_loading_overlay.dart';
|
||||
|
@ -28,15 +34,6 @@ import 'package:stackwallet/widgets/rounded_container.dart';
|
|||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||
import 'package:stackwallet/widgets/stack_text_field.dart';
|
||||
import 'package:stackwallet/widgets/textfield_icon_button.dart';
|
||||
import 'package:flutter_libepiccash/git_versions.dart' as EPIC_VERSIONS;
|
||||
import 'package:flutter_libmonero/git_versions.dart' as MONERO_VERSIONS;
|
||||
import 'package:lelantus/git_versions.dart' as FIRO_VERSIONS;
|
||||
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/stack_file_system.dart';
|
||||
|
||||
import 'package:stackwallet/utilities/clipboard_interface.dart';
|
||||
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
||||
class DebugView extends ConsumerStatefulWidget {
|
||||
const DebugView({Key? key}) : super(key: key);
|
||||
|
@ -352,10 +349,10 @@ class _DebugViewState extends ConsumerState<DebugView> {
|
|||
BlueTextButton(
|
||||
text: "Save logs to file",
|
||||
onTap: () async {
|
||||
final systemfile = StackFileSystem();
|
||||
final systemfile = SWBFileSystem();
|
||||
await systemfile.prepareStorage();
|
||||
Directory rootPath =
|
||||
(await getApplicationDocumentsDirectory());
|
||||
Directory rootPath = await StackFileSystem
|
||||
.applicationRootDirectory();
|
||||
|
||||
if (Platform.isAndroid) {
|
||||
rootPath = Directory("/storage/emulated/0/");
|
||||
|
|
|
@ -3,11 +3,11 @@ import 'dart:async';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||
import 'package:stackwallet/models/node_model.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
|
@ -40,9 +40,6 @@ class AddEditNodeView extends ConsumerStatefulWidget {
|
|||
required this.coin,
|
||||
required this.nodeId,
|
||||
required this.routeOnSuccessOrDelete,
|
||||
this.secureStore = const SecureStorageWrapper(
|
||||
FlutterSecureStorage(),
|
||||
),
|
||||
}) : super(key: key);
|
||||
|
||||
static const String routeName = "/addEditNode";
|
||||
|
@ -51,7 +48,6 @@ class AddEditNodeView extends ConsumerStatefulWidget {
|
|||
final Coin coin;
|
||||
final String routeOnSuccessOrDelete;
|
||||
final String? nodeId;
|
||||
final FlutterSecureStorageInterface secureStore;
|
||||
|
||||
@override
|
||||
ConsumerState<AddEditNodeView> createState() => _AddEditNodeViewState();
|
||||
|
@ -533,7 +529,7 @@ class _AddEditNodeViewState extends ConsumerState<AddEditNodeView> {
|
|||
children: [
|
||||
NodeForm(
|
||||
node: node,
|
||||
secureStore: widget.secureStore,
|
||||
secureStore: ref.read(secureStoreProvider),
|
||||
readOnly: false,
|
||||
coin: widget.coin,
|
||||
onChanged: (canSave, canTest) {
|
||||
|
@ -638,7 +634,7 @@ class NodeForm extends ConsumerStatefulWidget {
|
|||
}) : super(key: key);
|
||||
|
||||
final NodeModel? node;
|
||||
final FlutterSecureStorageInterface secureStore;
|
||||
final SecureStorageInterface secureStore;
|
||||
final bool readOnly;
|
||||
final Coin coin;
|
||||
final void Function(bool canSave, bool canTestConnection)? onChanged;
|
||||
|
|
|
@ -2,11 +2,11 @@ import 'dart:async';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/manage_nodes_views/add_edit_node_view.dart';
|
||||
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
|
@ -32,14 +32,10 @@ class NodeDetailsView extends ConsumerStatefulWidget {
|
|||
required this.coin,
|
||||
required this.nodeId,
|
||||
required this.popRouteName,
|
||||
this.secureStore = const SecureStorageWrapper(
|
||||
FlutterSecureStorage(),
|
||||
),
|
||||
}) : super(key: key);
|
||||
|
||||
static const String routeName = "/nodeDetails";
|
||||
|
||||
final FlutterSecureStorageInterface secureStore;
|
||||
final Coin coin;
|
||||
final String nodeId;
|
||||
final String popRouteName;
|
||||
|
@ -49,7 +45,7 @@ class NodeDetailsView extends ConsumerStatefulWidget {
|
|||
}
|
||||
|
||||
class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
|
||||
late final FlutterSecureStorageInterface secureStore;
|
||||
late final SecureStorageInterface secureStore;
|
||||
late final Coin coin;
|
||||
late final String nodeId;
|
||||
late final String popRouteName;
|
||||
|
@ -58,7 +54,7 @@ class _NodeDetailsViewState extends ConsumerState<NodeDetailsView> {
|
|||
|
||||
@override
|
||||
initState() {
|
||||
secureStore = widget.secureStore;
|
||||
secureStore = ref.read(secureStoreProvider);
|
||||
coin = widget.coin;
|
||||
nodeId = widget.nodeId;
|
||||
popRouteName = widget.popRouteName;
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/security_views/security_view.dart';
|
||||
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
|
||||
|
@ -11,23 +12,18 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
|||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/custom_pin_put/custom_pin_put.dart';
|
||||
|
||||
class ChangePinView extends StatefulWidget {
|
||||
class ChangePinView extends ConsumerStatefulWidget {
|
||||
const ChangePinView({
|
||||
Key? key,
|
||||
this.secureStore = const SecureStorageWrapper(
|
||||
FlutterSecureStorage(),
|
||||
),
|
||||
}) : super(key: key);
|
||||
|
||||
static const String routeName = "/changePin";
|
||||
|
||||
final FlutterSecureStorageInterface secureStore;
|
||||
|
||||
@override
|
||||
State<ChangePinView> createState() => _ChangePinViewState();
|
||||
ConsumerState<ChangePinView> createState() => _ChangePinViewState();
|
||||
}
|
||||
|
||||
class _ChangePinViewState extends State<ChangePinView> {
|
||||
class _ChangePinViewState extends ConsumerState<ChangePinView> {
|
||||
BoxDecoration get _pinPutDecoration {
|
||||
return BoxDecoration(
|
||||
color: Theme.of(context).extension<StackColors>()!.textSubtitle2,
|
||||
|
@ -49,11 +45,11 @@ class _ChangePinViewState extends State<ChangePinView> {
|
|||
final TextEditingController _pinPutController2 = TextEditingController();
|
||||
final FocusNode _pinPutFocusNode2 = FocusNode();
|
||||
|
||||
late final FlutterSecureStorageInterface _secureStore;
|
||||
late final SecureStorageInterface _secureStore;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_secureStore = widget.secureStore;
|
||||
_secureStore = ref.read(secureStoreProvider);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
|
|
|
@ -4,15 +4,15 @@ import 'dart:io';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stack_wallet_backup/stack_wallet_backup.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/auto_backup_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/stack_file_system.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/swb_file_system.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/sub_views/backup_frequency_type_select_sheet.dart';
|
||||
import 'package:stackwallet/providers/global/prefs_provider.dart';
|
||||
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
|
||||
|
@ -21,33 +21,27 @@ import 'package:stackwallet/utilities/format.dart';
|
|||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/progress_bar.dart';
|
||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||
import 'package:stackwallet/widgets/stack_text_field.dart';
|
||||
import 'package:zxcvbn/zxcvbn.dart';
|
||||
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
||||
class CreateAutoBackupView extends ConsumerStatefulWidget {
|
||||
const CreateAutoBackupView({
|
||||
Key? key,
|
||||
this.secureStore = const SecureStorageWrapper(
|
||||
FlutterSecureStorage(),
|
||||
),
|
||||
}) : super(key: key);
|
||||
|
||||
static const String routeName = "/createAutoBackup";
|
||||
|
||||
final FlutterSecureStorageInterface secureStore;
|
||||
|
||||
@override
|
||||
ConsumerState<CreateAutoBackupView> createState() =>
|
||||
_EnableAutoBackupViewState();
|
||||
}
|
||||
|
||||
class _EnableAutoBackupViewState extends ConsumerState<CreateAutoBackupView> {
|
||||
late final FlutterSecureStorageInterface secureStore;
|
||||
late final SecureStorageInterface secureStore;
|
||||
|
||||
late final TextEditingController fileLocationController;
|
||||
late final TextEditingController passwordController;
|
||||
|
@ -55,7 +49,7 @@ class _EnableAutoBackupViewState extends ConsumerState<CreateAutoBackupView> {
|
|||
|
||||
late final FocusNode passwordFocusNode;
|
||||
late final FocusNode passwordRepeatFocusNode;
|
||||
late final StackFileSystem stackFileSystem;
|
||||
late final SWBFileSystem stackFileSystem;
|
||||
final zxcvbn = Zxcvbn();
|
||||
|
||||
String passwordFeedback =
|
||||
|
@ -75,8 +69,8 @@ class _EnableAutoBackupViewState extends ConsumerState<CreateAutoBackupView> {
|
|||
|
||||
@override
|
||||
void initState() {
|
||||
secureStore = widget.secureStore;
|
||||
stackFileSystem = StackFileSystem();
|
||||
secureStore = ref.read(secureStoreProvider);
|
||||
stackFileSystem = SWBFileSystem();
|
||||
fileLocationController = TextEditingController();
|
||||
passwordController = TextEditingController();
|
||||
passwordRepeatController = TextEditingController();
|
||||
|
@ -585,7 +579,9 @@ class _EnableAutoBackupViewState extends ConsumerState<CreateAutoBackupView> {
|
|||
final String fileToSave =
|
||||
createAutoBackupFilename(pathToSave, now);
|
||||
|
||||
final backup = await SWB.createStackWalletJSON();
|
||||
final backup = await SWB.createStackWalletJSON(
|
||||
secureStorage: secureStore,
|
||||
);
|
||||
|
||||
bool result = await SWB.encryptStackWalletWithADK(
|
||||
fileToSave,
|
||||
|
|
|
@ -7,7 +7,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/stack_file_system.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/swb_file_system.dart';
|
||||
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
|
||||
|
@ -40,7 +41,7 @@ class _RestoreFromFileViewState extends State<CreateBackupView> {
|
|||
|
||||
late final FocusNode passwordFocusNode;
|
||||
late final FocusNode passwordRepeatFocusNode;
|
||||
late final StackFileSystem stackFileSystem;
|
||||
late final SWBFileSystem stackFileSystem;
|
||||
final zxcvbn = Zxcvbn();
|
||||
|
||||
String passwordFeedback =
|
||||
|
@ -60,7 +61,7 @@ class _RestoreFromFileViewState extends State<CreateBackupView> {
|
|||
|
||||
@override
|
||||
void initState() {
|
||||
stackFileSystem = StackFileSystem();
|
||||
stackFileSystem = SWBFileSystem();
|
||||
fileLocationController = TextEditingController();
|
||||
passwordController = TextEditingController();
|
||||
passwordRepeatController = TextEditingController();
|
||||
|
@ -443,222 +444,229 @@ class _RestoreFromFileViewState extends State<CreateBackupView> {
|
|||
),
|
||||
if (!isDesktop) const Spacer(),
|
||||
!isDesktop
|
||||
? TextButton(
|
||||
style: shouldEnableCreate
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonColor(context)
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryDisabledButtonColor(context),
|
||||
onPressed: !shouldEnableCreate
|
||||
? null
|
||||
: () async {
|
||||
final String pathToSave =
|
||||
fileLocationController.text;
|
||||
final String passphrase = passwordController.text;
|
||||
final String repeatPassphrase =
|
||||
passwordRepeatController.text;
|
||||
? Consumer(builder: (context, ref, __) {
|
||||
return TextButton(
|
||||
style: shouldEnableCreate
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonColor(context)
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryDisabledButtonColor(context),
|
||||
onPressed: !shouldEnableCreate
|
||||
? null
|
||||
: () async {
|
||||
final String pathToSave =
|
||||
fileLocationController.text;
|
||||
final String passphrase = passwordController.text;
|
||||
final String repeatPassphrase =
|
||||
passwordRepeatController.text;
|
||||
|
||||
if (pathToSave.isEmpty) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Directory not chosen",
|
||||
context: context,
|
||||
));
|
||||
return;
|
||||
}
|
||||
if (!(await Directory(pathToSave).exists())) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Directory does not exist",
|
||||
context: context,
|
||||
));
|
||||
return;
|
||||
}
|
||||
if (passphrase.isEmpty) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "A passphrase is required",
|
||||
context: context,
|
||||
));
|
||||
return;
|
||||
}
|
||||
if (passphrase != repeatPassphrase) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Passphrase does not match",
|
||||
context: context,
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
unawaited(showDialog<dynamic>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => const StackDialog(
|
||||
title: "Encrypting backup",
|
||||
message: "This shouldn't take long",
|
||||
),
|
||||
));
|
||||
// make sure the dialog is able to be displayed for at least 1 second
|
||||
await Future<void>.delayed(
|
||||
const Duration(seconds: 1));
|
||||
|
||||
final DateTime now = DateTime.now();
|
||||
final String fileToSave =
|
||||
"$pathToSave/stackbackup_${now.year}_${now.month}_${now.day}_${now.hour}_${now.minute}_${now.second}.swb";
|
||||
|
||||
final backup = await SWB.createStackWalletJSON();
|
||||
|
||||
bool result =
|
||||
await SWB.encryptStackWalletWithPassphrase(
|
||||
fileToSave,
|
||||
passphrase,
|
||||
jsonEncode(backup),
|
||||
);
|
||||
|
||||
if (mounted) {
|
||||
// pop encryption progress dialog
|
||||
Navigator.of(context).pop();
|
||||
|
||||
if (result) {
|
||||
await showDialog<dynamic>(
|
||||
if (pathToSave.isEmpty) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Directory not chosen",
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => Platform.isAndroid
|
||||
? StackOkDialog(
|
||||
title: "Backup saved to:",
|
||||
message: fileToSave,
|
||||
)
|
||||
: const StackOkDialog(
|
||||
title: "Backup creation succeeded"),
|
||||
);
|
||||
passwordController.text = "";
|
||||
passwordRepeatController.text = "";
|
||||
setState(() {});
|
||||
} else {
|
||||
await showDialog<dynamic>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => const StackOkDialog(
|
||||
title: "Backup creation failed"),
|
||||
);
|
||||
));
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
"Create backup",
|
||||
style: STextStyles.button(context),
|
||||
),
|
||||
)
|
||||
if (!(await Directory(pathToSave).exists())) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Directory does not exist",
|
||||
context: context,
|
||||
));
|
||||
return;
|
||||
}
|
||||
if (passphrase.isEmpty) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "A passphrase is required",
|
||||
context: context,
|
||||
));
|
||||
return;
|
||||
}
|
||||
if (passphrase != repeatPassphrase) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Passphrase does not match",
|
||||
context: context,
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
unawaited(showDialog<dynamic>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => const StackDialog(
|
||||
title: "Encrypting backup",
|
||||
message: "This shouldn't take long",
|
||||
),
|
||||
));
|
||||
// make sure the dialog is able to be displayed for at least 1 second
|
||||
await Future<void>.delayed(
|
||||
const Duration(seconds: 1));
|
||||
|
||||
final DateTime now = DateTime.now();
|
||||
final String fileToSave =
|
||||
"$pathToSave/stackbackup_${now.year}_${now.month}_${now.day}_${now.hour}_${now.minute}_${now.second}.swb";
|
||||
|
||||
final backup = await SWB.createStackWalletJSON(
|
||||
secureStorage: ref.read(secureStoreProvider));
|
||||
|
||||
bool result =
|
||||
await SWB.encryptStackWalletWithPassphrase(
|
||||
fileToSave,
|
||||
passphrase,
|
||||
jsonEncode(backup),
|
||||
);
|
||||
|
||||
if (mounted) {
|
||||
// pop encryption progress dialog
|
||||
Navigator.of(context).pop();
|
||||
|
||||
if (result) {
|
||||
await showDialog<dynamic>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => Platform.isAndroid
|
||||
? StackOkDialog(
|
||||
title: "Backup saved to:",
|
||||
message: fileToSave,
|
||||
)
|
||||
: const StackOkDialog(
|
||||
title: "Backup creation succeeded"),
|
||||
);
|
||||
passwordController.text = "";
|
||||
passwordRepeatController.text = "";
|
||||
setState(() {});
|
||||
} else {
|
||||
await showDialog<dynamic>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => const StackOkDialog(
|
||||
title: "Backup creation failed"),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
child: Text(
|
||||
"Create backup",
|
||||
style: STextStyles.button(context),
|
||||
),
|
||||
);
|
||||
})
|
||||
: Row(
|
||||
children: [
|
||||
PrimaryButton(
|
||||
width: 183,
|
||||
desktopMed: true,
|
||||
label: "Create backup",
|
||||
enabled: shouldEnableCreate,
|
||||
onPressed: !shouldEnableCreate
|
||||
? null
|
||||
: () async {
|
||||
final String pathToSave =
|
||||
fileLocationController.text;
|
||||
final String passphrase =
|
||||
passwordController.text;
|
||||
final String repeatPassphrase =
|
||||
passwordRepeatController.text;
|
||||
Consumer(builder: (context, ref, __) {
|
||||
return PrimaryButton(
|
||||
width: 183,
|
||||
desktopMed: true,
|
||||
label: "Create backup",
|
||||
enabled: shouldEnableCreate,
|
||||
onPressed: !shouldEnableCreate
|
||||
? null
|
||||
: () async {
|
||||
final String pathToSave =
|
||||
fileLocationController.text;
|
||||
final String passphrase =
|
||||
passwordController.text;
|
||||
final String repeatPassphrase =
|
||||
passwordRepeatController.text;
|
||||
|
||||
if (pathToSave.isEmpty) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Directory not chosen",
|
||||
context: context,
|
||||
));
|
||||
return;
|
||||
}
|
||||
if (!(await Directory(pathToSave).exists())) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Directory does not exist",
|
||||
context: context,
|
||||
));
|
||||
return;
|
||||
}
|
||||
if (passphrase.isEmpty) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "A passphrase is required",
|
||||
context: context,
|
||||
));
|
||||
return;
|
||||
}
|
||||
if (passphrase != repeatPassphrase) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Passphrase does not match",
|
||||
context: context,
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
unawaited(showDialog<dynamic>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => const StackDialog(
|
||||
title: "Encrypting backup",
|
||||
message: "This shouldn't take long",
|
||||
),
|
||||
));
|
||||
// make sure the dialog is able to be displayed for at least 1 second
|
||||
await Future<void>.delayed(
|
||||
const Duration(seconds: 1));
|
||||
|
||||
final DateTime now = DateTime.now();
|
||||
final String fileToSave =
|
||||
"$pathToSave/stackbackup_${now.year}_${now.month}_${now.day}_${now.hour}_${now.minute}_${now.second}.swb";
|
||||
|
||||
final backup =
|
||||
await SWB.createStackWalletJSON();
|
||||
|
||||
bool result =
|
||||
await SWB.encryptStackWalletWithPassphrase(
|
||||
fileToSave,
|
||||
passphrase,
|
||||
jsonEncode(backup),
|
||||
);
|
||||
|
||||
if (mounted) {
|
||||
// pop encryption progress dialog
|
||||
Navigator.of(context).pop();
|
||||
|
||||
if (result) {
|
||||
await showDialog<dynamic>(
|
||||
if (pathToSave.isEmpty) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Directory not chosen",
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => Platform.isAndroid
|
||||
? StackOkDialog(
|
||||
title: "Backup saved to:",
|
||||
message: fileToSave,
|
||||
)
|
||||
: const StackOkDialog(
|
||||
title:
|
||||
"Backup creation succeeded"),
|
||||
);
|
||||
passwordController.text = "";
|
||||
passwordRepeatController.text = "";
|
||||
setState(() {});
|
||||
} else {
|
||||
await showDialog<dynamic>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => const StackOkDialog(
|
||||
title: "Backup creation failed"),
|
||||
);
|
||||
));
|
||||
return;
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
if (!(await Directory(pathToSave).exists())) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Directory does not exist",
|
||||
context: context,
|
||||
));
|
||||
return;
|
||||
}
|
||||
if (passphrase.isEmpty) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "A passphrase is required",
|
||||
context: context,
|
||||
));
|
||||
return;
|
||||
}
|
||||
if (passphrase != repeatPassphrase) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Passphrase does not match",
|
||||
context: context,
|
||||
));
|
||||
return;
|
||||
}
|
||||
|
||||
unawaited(showDialog<dynamic>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => const StackDialog(
|
||||
title: "Encrypting backup",
|
||||
message: "This shouldn't take long",
|
||||
),
|
||||
));
|
||||
// make sure the dialog is able to be displayed for at least 1 second
|
||||
await Future<void>.delayed(
|
||||
const Duration(seconds: 1));
|
||||
|
||||
final DateTime now = DateTime.now();
|
||||
final String fileToSave =
|
||||
"$pathToSave/stackbackup_${now.year}_${now.month}_${now.day}_${now.hour}_${now.minute}_${now.second}.swb";
|
||||
|
||||
final backup =
|
||||
await SWB.createStackWalletJSON(
|
||||
secureStorage:
|
||||
ref.read(secureStoreProvider));
|
||||
|
||||
bool result = await SWB
|
||||
.encryptStackWalletWithPassphrase(
|
||||
fileToSave,
|
||||
passphrase,
|
||||
jsonEncode(backup),
|
||||
);
|
||||
|
||||
if (mounted) {
|
||||
// pop encryption progress dialog
|
||||
Navigator.of(context).pop();
|
||||
|
||||
if (result) {
|
||||
await showDialog<dynamic>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => Platform.isAndroid
|
||||
? StackOkDialog(
|
||||
title: "Backup saved to:",
|
||||
message: fileToSave,
|
||||
)
|
||||
: const StackOkDialog(
|
||||
title:
|
||||
"Backup creation succeeded"),
|
||||
);
|
||||
passwordController.text = "";
|
||||
passwordRepeatController.text = "";
|
||||
setState(() {});
|
||||
} else {
|
||||
await showDialog<dynamic>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => const StackOkDialog(
|
||||
title: "Backup creation failed"),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
}),
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||
|
||||
class CancelStackRestoreDialog extends StatelessWidget {
|
||||
|
@ -14,38 +19,95 @@ class CancelStackRestoreDialog extends StatelessWidget {
|
|||
onWillPop: () async {
|
||||
return false;
|
||||
},
|
||||
child: StackDialog(
|
||||
title: "Cancel restore process",
|
||||
message:
|
||||
"Cancelling will revert any changes that may have been applied",
|
||||
leftButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getSecondaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Back",
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(false);
|
||||
},
|
||||
),
|
||||
rightButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Yes, cancel",
|
||||
style: STextStyles.itemSubtitle12(context).copyWith(
|
||||
color:
|
||||
Theme.of(context).extension<StackColors>()!.buttonTextPrimary,
|
||||
child: !Util.isDesktop
|
||||
? StackDialog(
|
||||
title: "Cancel restore process",
|
||||
message:
|
||||
"Cancelling will revert any changes that may have been applied",
|
||||
leftButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getSecondaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Back",
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(false);
|
||||
},
|
||||
),
|
||||
rightButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Yes, cancel",
|
||||
style: STextStyles.itemSubtitle12(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonTextPrimary,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
),
|
||||
)
|
||||
: DesktopDialog(
|
||||
maxHeight: 250,
|
||||
maxWidth: 600,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
top: 20, left: 32, right: 32, bottom: 20),
|
||||
child: Column(
|
||||
children: [
|
||||
Text(
|
||||
"Cancel Restore Process",
|
||||
style: STextStyles.desktopH3(context),
|
||||
),
|
||||
const SizedBox(height: 24),
|
||||
SizedBox(
|
||||
width: 500,
|
||||
child: RoundedContainer(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.snackBarBackError,
|
||||
child: Text(
|
||||
"If you cancel, the restore will not complete, and "
|
||||
"the wallets will not appear in your Stack.",
|
||||
style: STextStyles.desktopTextMedium(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
const Spacer(),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
SecondaryButton(
|
||||
width: 248,
|
||||
desktopMed: true,
|
||||
enabled: true,
|
||||
label: "Keep restoring",
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(false);
|
||||
},
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
PrimaryButton(
|
||||
width: 248,
|
||||
desktopMed: true,
|
||||
enabled: true,
|
||||
label: "Cancel anyway",
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop(true);
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -3,10 +3,7 @@ import 'dart:convert';
|
|||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:stack_wallet_backup/stack_wallet_backup.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||
import 'package:stackwallet/hive/db.dart';
|
||||
import 'package:stackwallet/models/contact.dart';
|
||||
import 'package:stackwallet/models/contact_address_entry.dart';
|
||||
|
@ -91,10 +88,13 @@ abstract class SWB {
|
|||
|
||||
static bool _shouldCancelRestore = false;
|
||||
|
||||
static bool _checkShouldCancel(PreRestoreState? revertToState) {
|
||||
static bool _checkShouldCancel(
|
||||
PreRestoreState? revertToState,
|
||||
SecureStorageInterface secureStorageInterface,
|
||||
) {
|
||||
if (_shouldCancelRestore) {
|
||||
if (revertToState != null) {
|
||||
_revert(revertToState);
|
||||
_revert(revertToState, secureStorageInterface);
|
||||
} else {
|
||||
_cancelCompleter!.complete();
|
||||
_shouldCancelRestore = false;
|
||||
|
@ -193,15 +193,15 @@ abstract class SWB {
|
|||
|
||||
/// [secureStorage] parameter exposed for testing purposes
|
||||
static Future<Map<String, dynamic>> createStackWalletJSON({
|
||||
FlutterSecureStorageInterface? secureStorage,
|
||||
required SecureStorageInterface secureStorage,
|
||||
}) async {
|
||||
Logging.instance
|
||||
.log("Starting createStackWalletJSON...", level: LogLevel.Info);
|
||||
final _wallets = Wallets.sharedInstance;
|
||||
Map<String, dynamic> backupJson = {};
|
||||
NodeService nodeService = NodeService();
|
||||
final _secureStore =
|
||||
secureStorage ?? const SecureStorageWrapper(FlutterSecureStorage());
|
||||
NodeService nodeService =
|
||||
NodeService(secureStorageInterface: secureStorage);
|
||||
final _secureStore = secureStorage;
|
||||
|
||||
Logging.instance.log("createStackWalletJSON awaiting DB.instance.mutex...",
|
||||
level: LogLevel.Info);
|
||||
|
@ -448,6 +448,7 @@ abstract class SWB {
|
|||
Map<String, dynamic> validJSON,
|
||||
StackRestoringUIState? uiState,
|
||||
Map<String, String> oldToNewWalletIdMap,
|
||||
SecureStorageInterface secureStorageInterface,
|
||||
) async {
|
||||
Map<String, dynamic> prefs = validJSON["prefs"] as Map<String, dynamic>;
|
||||
List<dynamic>? addressBookEntries =
|
||||
|
@ -486,7 +487,11 @@ abstract class SWB {
|
|||
"SWB restoring nodes",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
await _restoreNodes(nodes, primaryNodes);
|
||||
await _restoreNodes(
|
||||
nodes,
|
||||
primaryNodes,
|
||||
secureStorageInterface,
|
||||
);
|
||||
|
||||
uiState?.nodes = StackRestoringStatus.success;
|
||||
uiState?.trades = StackRestoringStatus.restoring;
|
||||
|
@ -543,6 +548,7 @@ abstract class SWB {
|
|||
static Future<bool?> restoreStackWalletJSON(
|
||||
String jsonBackup,
|
||||
StackRestoringUIState? uiState,
|
||||
SecureStorageInterface secureStorageInterface,
|
||||
) async {
|
||||
if (!Platform.isLinux) await Wakelock.enable();
|
||||
|
||||
|
@ -550,7 +556,8 @@ abstract class SWB {
|
|||
"SWB creating temp backup",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
final preRestoreJSON = await createStackWalletJSON();
|
||||
final preRestoreJSON =
|
||||
await createStackWalletJSON(secureStorage: secureStorageInterface);
|
||||
Logging.instance.log(
|
||||
"SWB temp backup created",
|
||||
level: LogLevel.Warning,
|
||||
|
@ -587,19 +594,34 @@ abstract class SWB {
|
|||
|
||||
// basic cancel check here
|
||||
// no reverting required yet as nothing has been written to store
|
||||
if (_checkShouldCancel(null)) {
|
||||
if (_checkShouldCancel(
|
||||
null,
|
||||
secureStorageInterface,
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
await _restoreEverythingButWallets(validJSON, uiState, oldToNewWalletIdMap);
|
||||
await _restoreEverythingButWallets(
|
||||
validJSON,
|
||||
uiState,
|
||||
oldToNewWalletIdMap,
|
||||
secureStorageInterface,
|
||||
);
|
||||
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
if (_checkShouldCancel(
|
||||
preRestoreState,
|
||||
secureStorageInterface,
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
final nodeService = NodeService();
|
||||
final walletsService = WalletsService();
|
||||
final nodeService = NodeService(
|
||||
secureStorageInterface: secureStorageInterface,
|
||||
);
|
||||
final walletsService = WalletsService(
|
||||
secureStorageInterface: secureStorageInterface,
|
||||
);
|
||||
final _prefs = Prefs.instance;
|
||||
await _prefs.init();
|
||||
|
||||
|
@ -609,7 +631,10 @@ abstract class SWB {
|
|||
|
||||
for (var walletbackup in wallets) {
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
if (_checkShouldCancel(
|
||||
preRestoreState,
|
||||
secureStorageInterface,
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -647,7 +672,10 @@ abstract class SWB {
|
|||
final failovers = nodeService.failoverNodesFor(coin: coin);
|
||||
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
if (_checkShouldCancel(
|
||||
preRestoreState,
|
||||
secureStorageInterface,
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -655,6 +683,7 @@ abstract class SWB {
|
|||
coin,
|
||||
walletId,
|
||||
walletName,
|
||||
secureStorageInterface,
|
||||
node,
|
||||
txTracker,
|
||||
_prefs,
|
||||
|
@ -665,7 +694,10 @@ abstract class SWB {
|
|||
|
||||
managers.add(Tuple2(walletbackup, manager));
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
if (_checkShouldCancel(
|
||||
preRestoreState,
|
||||
secureStorageInterface,
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -679,7 +711,10 @@ abstract class SWB {
|
|||
}
|
||||
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
if (_checkShouldCancel(
|
||||
preRestoreState,
|
||||
secureStorageInterface,
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -690,7 +725,10 @@ abstract class SWB {
|
|||
// start restoring wallets
|
||||
for (final tuple in managers) {
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
if (_checkShouldCancel(
|
||||
preRestoreState,
|
||||
secureStorageInterface,
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
final bools = await asyncRestore(tuple, uiState, walletsService);
|
||||
|
@ -698,13 +736,19 @@ abstract class SWB {
|
|||
}
|
||||
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
if (_checkShouldCancel(
|
||||
preRestoreState,
|
||||
secureStorageInterface,
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (Future<bool> status in restoreStatuses) {
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
if (_checkShouldCancel(
|
||||
preRestoreState,
|
||||
secureStorageInterface,
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
await status;
|
||||
|
@ -712,7 +756,10 @@ abstract class SWB {
|
|||
|
||||
if (!Platform.isLinux) await Wakelock.disable();
|
||||
// check if cancel was requested and restore previous state
|
||||
if (_checkShouldCancel(preRestoreState)) {
|
||||
if (_checkShouldCancel(
|
||||
preRestoreState,
|
||||
secureStorageInterface,
|
||||
)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -720,7 +767,10 @@ abstract class SWB {
|
|||
return true;
|
||||
}
|
||||
|
||||
static Future<void> _revert(PreRestoreState revertToState) async {
|
||||
static Future<void> _revert(
|
||||
PreRestoreState revertToState,
|
||||
SecureStorageInterface secureStorageInterface,
|
||||
) async {
|
||||
Map<String, dynamic> prefs =
|
||||
revertToState.validJSON["prefs"] as Map<String, dynamic>;
|
||||
List<dynamic>? addressBookEntries =
|
||||
|
@ -788,7 +838,9 @@ abstract class SWB {
|
|||
}
|
||||
|
||||
// nodes
|
||||
NodeService nodeService = NodeService();
|
||||
NodeService nodeService = NodeService(
|
||||
secureStorageInterface: secureStorageInterface,
|
||||
);
|
||||
final currentNodes = nodeService.nodes;
|
||||
if (nodes == null) {
|
||||
// no pre nodes found so we delete all but defaults
|
||||
|
@ -914,7 +966,8 @@ abstract class SWB {
|
|||
}
|
||||
|
||||
// finally remove any added wallets
|
||||
final walletsService = WalletsService();
|
||||
final walletsService =
|
||||
WalletsService(secureStorageInterface: secureStorageInterface);
|
||||
final namesData = await walletsService.walletNames;
|
||||
for (final entry in namesData.entries) {
|
||||
if (!revertToState.walletIds.contains(entry.value.walletId)) {
|
||||
|
@ -989,8 +1042,11 @@ abstract class SWB {
|
|||
static Future<void> _restoreNodes(
|
||||
List<dynamic>? nodes,
|
||||
List<dynamic>? primaryNodes,
|
||||
SecureStorageInterface secureStorageInterface,
|
||||
) async {
|
||||
NodeService nodeService = NodeService();
|
||||
NodeService nodeService = NodeService(
|
||||
secureStorageInterface: secureStorageInterface,
|
||||
);
|
||||
if (nodes != null) {
|
||||
for (var node in nodes) {
|
||||
await nodeService.add(
|
||||
|
|
|
@ -4,15 +4,16 @@ import 'package:file_picker/file_picker.dart';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:permission_handler/permission_handler.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
||||
class StackFileSystem {
|
||||
class SWBFileSystem {
|
||||
Directory? rootPath;
|
||||
Directory? startPath;
|
||||
|
||||
String? filePath;
|
||||
String? dirPath;
|
||||
|
||||
final bool isDesktop = !(Platform.isAndroid || Platform.isIOS);
|
||||
final bool isDesktop = Util.isDesktop;
|
||||
|
||||
Future<Directory> prepareStorage() async {
|
||||
if (Platform.isAndroid) {
|
||||
|
@ -25,11 +26,20 @@ class StackFileSystem {
|
|||
}
|
||||
debugPrint(rootPath!.absolute.toString());
|
||||
|
||||
Directory sampleFolder =
|
||||
Directory('${rootPath!.path}Documents/Stack_backups');
|
||||
late Directory sampleFolder;
|
||||
|
||||
if (Platform.isIOS) {
|
||||
sampleFolder = Directory(rootPath!.path);
|
||||
} else if (Platform.isAndroid) {
|
||||
sampleFolder = Directory('${rootPath!.path}Documents/Stack_backups');
|
||||
} else if (Platform.isLinux) {
|
||||
sampleFolder = Directory('${rootPath!.path}/Stack_backups');
|
||||
} else if (Platform.isWindows) {
|
||||
sampleFolder = Directory('${rootPath!.path}/Stack_backups');
|
||||
} else if (Platform.isMacOS) {
|
||||
sampleFolder = Directory('${rootPath!.path}/Stack_backups');
|
||||
}
|
||||
|
||||
try {
|
||||
if (!sampleFolder.existsSync()) {
|
||||
sampleFolder.createSync(recursive: true);
|
|
@ -7,9 +7,8 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/stack_file_system.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/swb_file_system.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/sub_views/stack_restore_progress_view.dart';
|
||||
// import 'package:stackwallet/pages_desktop_specific/home/settings_menu/backup_and_restore/restore_backup_dialog.dart';
|
||||
import 'package:stackwallet/route_generator.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
|
@ -44,24 +43,13 @@ class _RestoreFromFileViewState extends ConsumerState<RestoreFromFileView> {
|
|||
|
||||
late final FocusNode passwordFocusNode;
|
||||
|
||||
late final StackFileSystem stackFileSystem;
|
||||
late final SWBFileSystem stackFileSystem;
|
||||
|
||||
bool hidePassword = true;
|
||||
|
||||
Future<void> restoreBackupPopup(BuildContext context) async {
|
||||
// await showDialog<dynamic>(
|
||||
// context: context,
|
||||
// useSafeArea: false,
|
||||
// barrierDismissible: true,
|
||||
// builder: (context) {
|
||||
// return const RestoreBackupDialog();
|
||||
// },
|
||||
// );
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
stackFileSystem = StackFileSystem();
|
||||
stackFileSystem = SWBFileSystem();
|
||||
fileLocationController = TextEditingController();
|
||||
passwordController = TextEditingController();
|
||||
|
||||
|
@ -237,7 +225,7 @@ class _RestoreFromFileViewState extends ConsumerState<RestoreFromFileView> {
|
|||
enableSuggestions: false,
|
||||
autocorrect: false,
|
||||
decoration: standardInputDecoration(
|
||||
"Enter password",
|
||||
"Enter passphrase",
|
||||
passwordFocusNode,
|
||||
context,
|
||||
).copyWith(
|
||||
|
@ -534,7 +522,7 @@ class _RestoreFromFileViewState extends ConsumerState<RestoreFromFileView> {
|
|||
const EdgeInsets
|
||||
.all(32),
|
||||
child: Text(
|
||||
"Restoring Stack Wallet",
|
||||
"Restore Stack Wallet",
|
||||
style: STextStyles
|
||||
.desktopH3(
|
||||
context),
|
||||
|
@ -546,12 +534,10 @@ class _RestoreFromFileViewState extends ConsumerState<RestoreFromFileView> {
|
|||
const DesktopDialogCloseButton(),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 30,
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets
|
||||
.symmetric(
|
||||
padding:
|
||||
const EdgeInsets
|
||||
.symmetric(
|
||||
horizontal:
|
||||
32),
|
||||
child:
|
||||
|
@ -560,6 +546,9 @@ class _RestoreFromFileViewState extends ConsumerState<RestoreFromFileView> {
|
|||
jsonString,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 32,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
|
|
@ -9,6 +9,7 @@ import 'package:stackwallet/pages/settings_views/global_settings_view/stack_back
|
|||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/stack_backup_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_item_card.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/sub_widgets/restoring_wallet_card.dart';
|
||||
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/providers/stack_restore/stack_restoring_ui_state_provider.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
|
@ -19,10 +20,13 @@ import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
|||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/conditional_parent.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||
import 'package:stackwallet/widgets/icon_widgets/addressbook_icon.dart';
|
||||
import 'package:stackwallet/widgets/loading_indicator.dart';
|
||||
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||
|
||||
import '../../../../../widgets/desktop/primary_button.dart';
|
||||
|
||||
class StackRestoreProgressView extends ConsumerStatefulWidget {
|
||||
const StackRestoreProgressView({
|
||||
Key? key,
|
||||
|
@ -100,6 +104,30 @@ class _StackRestoreProgressViewState
|
|||
context: context,
|
||||
builder: (_) => const CancelStackRestoreDialog(),
|
||||
);
|
||||
// : await Row(
|
||||
// children: [
|
||||
// SecondaryButton(
|
||||
// width: 248,
|
||||
// desktopMed: true,
|
||||
// enabled: true,
|
||||
// label: "Keep restoring",
|
||||
// onPressed: () {
|
||||
// false;
|
||||
// },
|
||||
// ),
|
||||
// const SizedBox(width: 16),
|
||||
// PrimaryButton(
|
||||
// width: 248,
|
||||
// desktopMed: true,
|
||||
// enabled: true,
|
||||
// label: "Cancel anyway",
|
||||
// onPressed: () {
|
||||
// true;
|
||||
// },
|
||||
// )
|
||||
// ],
|
||||
// );
|
||||
|
||||
if (result is bool && result) {
|
||||
return true;
|
||||
}
|
||||
|
@ -115,6 +143,7 @@ class _StackRestoreProgressViewState
|
|||
finished = await SWB.restoreStackWalletJSON(
|
||||
widget.jsonString,
|
||||
uiState,
|
||||
ref.read(secureStoreProvider),
|
||||
);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e\n$s", level: LogLevel.Warning);
|
||||
|
@ -128,6 +157,7 @@ class _StackRestoreProgressViewState
|
|||
}
|
||||
|
||||
bool _success = false;
|
||||
bool pendingCancel = false;
|
||||
|
||||
Future<bool> _onWillPop() async {
|
||||
if (_success) {
|
||||
|
@ -239,7 +269,7 @@ class _StackRestoreProgressViewState
|
|||
left: 4,
|
||||
top: 4,
|
||||
right: 4,
|
||||
bottom: 0,
|
||||
bottom: 4,
|
||||
),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
|
@ -255,40 +285,84 @@ class _StackRestoreProgressViewState
|
|||
builder: (_, ref, __) {
|
||||
final state = ref.watch(stackRestoringUIStateProvider
|
||||
.select((value) => value.preferences));
|
||||
return RestoringItemCard(
|
||||
left: SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.gear,
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
return !isDesktop
|
||||
? RestoringItemCard(
|
||||
left: SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.gear,
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
right: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: _getIconForState(state),
|
||||
),
|
||||
title: "Preferences",
|
||||
subTitle: state == StackRestoringStatus.failed
|
||||
? Text(
|
||||
"Something went wrong",
|
||||
style: STextStyles.errorSmall(context),
|
||||
)
|
||||
: null,
|
||||
);
|
||||
right: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: _getIconForState(state),
|
||||
),
|
||||
title: "Preferences",
|
||||
subTitle: state == StackRestoringStatus.failed
|
||||
? Text(
|
||||
"Something went wrong",
|
||||
style: STextStyles.errorSmall(context),
|
||||
)
|
||||
: null,
|
||||
)
|
||||
: RoundedContainer(
|
||||
padding: EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.popupBG,
|
||||
borderColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.background,
|
||||
child: RestoringItemCard(
|
||||
left: SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.gear,
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
right: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: _getIconForState(state),
|
||||
),
|
||||
title: "Preferences",
|
||||
subTitle: state == StackRestoringStatus.failed
|
||||
? Text(
|
||||
"Something went wrong",
|
||||
style: STextStyles.errorSmall(context),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -298,39 +372,82 @@ class _StackRestoreProgressViewState
|
|||
builder: (_, ref, __) {
|
||||
final state = ref.watch(stackRestoringUIStateProvider
|
||||
.select((value) => value.addressBook));
|
||||
return RestoringItemCard(
|
||||
left: SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
child: Center(
|
||||
child: AddressBookIcon(
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
return !isDesktop
|
||||
? RestoringItemCard(
|
||||
left: SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
child: Center(
|
||||
child: AddressBookIcon(
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
right: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: _getIconForState(state),
|
||||
),
|
||||
title: "Address book",
|
||||
subTitle: state == StackRestoringStatus.failed
|
||||
? Text(
|
||||
"Something went wrong",
|
||||
style: STextStyles.errorSmall(context),
|
||||
)
|
||||
: null,
|
||||
);
|
||||
right: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: _getIconForState(state),
|
||||
),
|
||||
title: "Address book",
|
||||
subTitle: state == StackRestoringStatus.failed
|
||||
? Text(
|
||||
"Something went wrong",
|
||||
style: STextStyles.errorSmall(context),
|
||||
)
|
||||
: null,
|
||||
)
|
||||
: RoundedContainer(
|
||||
padding: EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.popupBG,
|
||||
borderColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.background,
|
||||
child: RestoringItemCard(
|
||||
left: SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
child: Center(
|
||||
child: AddressBookIcon(
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
right: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: _getIconForState(state),
|
||||
),
|
||||
title: "Address book",
|
||||
subTitle: state == StackRestoringStatus.failed
|
||||
? Text(
|
||||
"Something went wrong",
|
||||
style: STextStyles.errorSmall(context),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -340,40 +457,83 @@ class _StackRestoreProgressViewState
|
|||
builder: (_, ref, __) {
|
||||
final state = ref.watch(stackRestoringUIStateProvider
|
||||
.select((value) => value.nodes));
|
||||
return RestoringItemCard(
|
||||
left: SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.node,
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
return !isDesktop
|
||||
? RestoringItemCard(
|
||||
left: SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.node,
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
right: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: _getIconForState(state),
|
||||
),
|
||||
title: "Nodes",
|
||||
subTitle: state == StackRestoringStatus.failed
|
||||
? Text(
|
||||
"Something went wrong",
|
||||
style: STextStyles.errorSmall(context),
|
||||
)
|
||||
: null,
|
||||
);
|
||||
right: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: _getIconForState(state),
|
||||
),
|
||||
title: "Nodes",
|
||||
subTitle: state == StackRestoringStatus.failed
|
||||
? Text(
|
||||
"Something went wrong",
|
||||
style: STextStyles.errorSmall(context),
|
||||
)
|
||||
: null,
|
||||
)
|
||||
: RoundedContainer(
|
||||
padding: EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.popupBG,
|
||||
borderColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.background,
|
||||
child: RestoringItemCard(
|
||||
left: SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.node,
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
right: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: _getIconForState(state),
|
||||
),
|
||||
title: "Nodes",
|
||||
subTitle: state == StackRestoringStatus.failed
|
||||
? Text(
|
||||
"Something went wrong",
|
||||
style: STextStyles.errorSmall(context),
|
||||
)
|
||||
: null,
|
||||
));
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -383,40 +543,86 @@ class _StackRestoreProgressViewState
|
|||
builder: (_, ref, __) {
|
||||
final state = ref.watch(stackRestoringUIStateProvider
|
||||
.select((value) => value.trades));
|
||||
return RestoringItemCard(
|
||||
left: SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.arrowRotate2,
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
return !isDesktop
|
||||
? Container(
|
||||
child: RestoringItemCard(
|
||||
left: SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.arrowRotate2,
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
right: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: _getIconForState(state),
|
||||
),
|
||||
title: "Exchange history",
|
||||
subTitle: state == StackRestoringStatus.failed
|
||||
? Text(
|
||||
"Something went wrong",
|
||||
style: STextStyles.errorSmall(context),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
right: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: _getIconForState(state),
|
||||
),
|
||||
title: "Exchange history",
|
||||
subTitle: state == StackRestoringStatus.failed
|
||||
? Text(
|
||||
"Something went wrong",
|
||||
style: STextStyles.errorSmall(context),
|
||||
)
|
||||
: null,
|
||||
);
|
||||
)
|
||||
: RoundedContainer(
|
||||
padding: EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.popupBG,
|
||||
borderColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.background,
|
||||
child: RestoringItemCard(
|
||||
left: SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.arrowRotate2,
|
||||
width: 16,
|
||||
height: 16,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
right: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: _getIconForState(state),
|
||||
),
|
||||
title: "Exchange history",
|
||||
subTitle: state == StackRestoringStatus.failed
|
||||
? Text(
|
||||
"Something went wrong",
|
||||
style: STextStyles.errorSmall(context),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -446,28 +652,55 @@ class _StackRestoreProgressViewState
|
|||
),
|
||||
SizedBox(
|
||||
width: MediaQuery.of(context).size.width - 32,
|
||||
child: TextButton(
|
||||
onPressed: () async {
|
||||
if (_success) {
|
||||
Navigator.of(context).pop();
|
||||
} else {
|
||||
if (await _requestCancel()) {
|
||||
await _cancel();
|
||||
}
|
||||
}
|
||||
},
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
_success ? "OK" : "Cancel restore process",
|
||||
style: STextStyles.button(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonTextPrimary,
|
||||
),
|
||||
),
|
||||
),
|
||||
child: !isDesktop
|
||||
? TextButton(
|
||||
onPressed: () async {
|
||||
if (_success) {
|
||||
Navigator.of(context).pop();
|
||||
} else {
|
||||
if (await _requestCancel()) {
|
||||
await _cancel();
|
||||
}
|
||||
}
|
||||
},
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
_success ? "OK" : "Cancel restore process",
|
||||
style: STextStyles.button(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonTextPrimary,
|
||||
),
|
||||
),
|
||||
)
|
||||
: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.end,
|
||||
children: [
|
||||
_success
|
||||
? PrimaryButton(
|
||||
width: 248,
|
||||
desktopMed: true,
|
||||
enabled: true,
|
||||
label: "Done",
|
||||
onPressed: () async {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
)
|
||||
: SecondaryButton(
|
||||
width: 248,
|
||||
desktopMed: true,
|
||||
enabled: true,
|
||||
label: "Cancel restore process",
|
||||
onPressed: () async {
|
||||
if (await _requestCancel()) {
|
||||
await _cancel();
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -11,6 +11,7 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
|||
import 'package:stackwallet/utilities/enums/stack_restoring_status.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/loading_indicator.dart';
|
||||
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||
|
||||
|
@ -68,140 +69,287 @@ class _RestoringWalletCardState extends ConsumerState<RestoringWalletCard> {
|
|||
final coin = ref.watch(provider.select((value) => value.coin));
|
||||
final restoringStatus =
|
||||
ref.watch(provider.select((value) => value.restoringState));
|
||||
return RestoringItemCard(
|
||||
left: SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
color: Theme.of(context).extension<StackColors>()!.colorForCoin(coin),
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.iconFor(
|
||||
coin: coin,
|
||||
),
|
||||
height: 20,
|
||||
width: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
onRightTapped: restoringStatus == StackRestoringStatus.failed
|
||||
? () async {
|
||||
final manager = ref.read(provider).manager!;
|
||||
|
||||
ref.read(stackRestoringUIStateProvider).update(
|
||||
walletId: manager.walletId,
|
||||
restoringStatus: StackRestoringStatus.restoring);
|
||||
|
||||
try {
|
||||
final mnemonicList = await manager.mnemonic;
|
||||
int maxUnusedAddressGap = 20;
|
||||
if (coin == Coin.firo) {
|
||||
maxUnusedAddressGap = 50;
|
||||
}
|
||||
const maxNumberOfIndexesToCheck = 1000;
|
||||
|
||||
if (mnemonicList.isEmpty) {
|
||||
await manager.recoverFromMnemonic(
|
||||
mnemonic: ref.read(provider).mnemonic!,
|
||||
maxUnusedAddressGap: maxUnusedAddressGap,
|
||||
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
|
||||
height: ref.read(provider).height ?? 0,
|
||||
);
|
||||
} else {
|
||||
await manager.fullRescan(
|
||||
maxUnusedAddressGap,
|
||||
maxNumberOfIndexesToCheck,
|
||||
);
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
final address = await manager.currentReceivingAddress;
|
||||
|
||||
ref.read(stackRestoringUIStateProvider).update(
|
||||
walletId: manager.walletId,
|
||||
restoringStatus: StackRestoringStatus.success,
|
||||
address: address,
|
||||
);
|
||||
}
|
||||
} catch (_) {
|
||||
if (mounted) {
|
||||
ref.read(stackRestoringUIStateProvider).update(
|
||||
walletId: manager.walletId,
|
||||
restoringStatus: StackRestoringStatus.failed,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
: null,
|
||||
right: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: _getIconForState(
|
||||
ref.watch(provider.select((value) => value.restoringState)),
|
||||
),
|
||||
),
|
||||
title:
|
||||
"${ref.watch(provider.select((value) => value.walletName))} (${coin.ticker})",
|
||||
subTitle: restoringStatus == StackRestoringStatus.failed
|
||||
? Text(
|
||||
"Unable to restore. Tap icon to retry.",
|
||||
style: STextStyles.errorSmall(context),
|
||||
)
|
||||
: ref.watch(provider.select((value) => value.address)) != null
|
||||
? Text(
|
||||
ref.watch(provider.select((value) => value.address))!,
|
||||
style: STextStyles.infoSmall(context),
|
||||
)
|
||||
: null,
|
||||
button: restoringStatus == StackRestoringStatus.failed
|
||||
? Container(
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
return !Util.isDesktop
|
||||
? RestoringItemCard(
|
||||
left: SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
borderRadius: BorderRadius.circular(
|
||||
1000,
|
||||
),
|
||||
),
|
||||
child: RawMaterialButton(
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
splashColor:
|
||||
Theme.of(context).extension<StackColors>()!.highlight,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
1000,
|
||||
.colorForCoin(coin),
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.iconFor(
|
||||
coin: coin,
|
||||
),
|
||||
height: 20,
|
||||
width: 20,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
final mnemonic = ref.read(provider).mnemonic;
|
||||
),
|
||||
),
|
||||
onRightTapped: restoringStatus == StackRestoringStatus.failed
|
||||
? () async {
|
||||
final manager = ref.read(provider).manager!;
|
||||
|
||||
if (mnemonic != null) {
|
||||
Navigator.of(context).push(
|
||||
RouteGenerator.getRoute(
|
||||
builder: (_) => RecoverPhraseView(
|
||||
walletName: ref.read(provider).walletName,
|
||||
mnemonic: mnemonic.split(" "),
|
||||
ref.read(stackRestoringUIStateProvider).update(
|
||||
walletId: manager.walletId,
|
||||
restoringStatus: StackRestoringStatus.restoring);
|
||||
|
||||
try {
|
||||
final mnemonicList = await manager.mnemonic;
|
||||
int maxUnusedAddressGap = 20;
|
||||
if (coin == Coin.firo) {
|
||||
maxUnusedAddressGap = 50;
|
||||
}
|
||||
const maxNumberOfIndexesToCheck = 1000;
|
||||
|
||||
if (mnemonicList.isEmpty) {
|
||||
await manager.recoverFromMnemonic(
|
||||
mnemonic: ref.read(provider).mnemonic!,
|
||||
maxUnusedAddressGap: maxUnusedAddressGap,
|
||||
maxNumberOfIndexesToCheck: maxNumberOfIndexesToCheck,
|
||||
height: ref.read(provider).height ?? 0,
|
||||
);
|
||||
} else {
|
||||
await manager.fullRescan(
|
||||
maxUnusedAddressGap,
|
||||
maxNumberOfIndexesToCheck,
|
||||
);
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
final address = await manager.currentReceivingAddress;
|
||||
|
||||
ref.read(stackRestoringUIStateProvider).update(
|
||||
walletId: manager.walletId,
|
||||
restoringStatus: StackRestoringStatus.success,
|
||||
address: address,
|
||||
);
|
||||
}
|
||||
} catch (_) {
|
||||
if (mounted) {
|
||||
ref.read(stackRestoringUIStateProvider).update(
|
||||
walletId: manager.walletId,
|
||||
restoringStatus: StackRestoringStatus.failed,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
: null,
|
||||
right: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: _getIconForState(
|
||||
ref.watch(provider.select((value) => value.restoringState)),
|
||||
),
|
||||
),
|
||||
title:
|
||||
"${ref.watch(provider.select((value) => value.walletName))} (${coin.ticker})",
|
||||
subTitle: restoringStatus == StackRestoringStatus.failed
|
||||
? Text(
|
||||
"Unable to restore. Tap icon to retry.",
|
||||
style: STextStyles.errorSmall(context),
|
||||
)
|
||||
: ref.watch(provider.select((value) => value.address)) != null
|
||||
? Text(
|
||||
ref.watch(provider.select((value) => value.address))!,
|
||||
style: STextStyles.infoSmall(context),
|
||||
)
|
||||
: null,
|
||||
button: restoringStatus == StackRestoringStatus.failed
|
||||
? Container(
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
borderRadius: BorderRadius.circular(
|
||||
1000,
|
||||
),
|
||||
),
|
||||
child: RawMaterialButton(
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
splashColor:
|
||||
Theme.of(context).extension<StackColors>()!.highlight,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
1000,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Text(
|
||||
"Show recovery phrase",
|
||||
style: STextStyles.infoSmall(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark),
|
||||
onPressed: () async {
|
||||
final mnemonic = ref.read(provider).mnemonic;
|
||||
|
||||
if (mnemonic != null) {
|
||||
Navigator.of(context).push(
|
||||
RouteGenerator.getRoute(
|
||||
builder: (_) => RecoverPhraseView(
|
||||
walletName: ref.read(provider).walletName,
|
||||
mnemonic: mnemonic.split(" "),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Text(
|
||||
"Show recovery phrase",
|
||||
style: STextStyles.infoSmall(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
)
|
||||
: RoundedContainer(
|
||||
padding: EdgeInsets.all(0),
|
||||
color: Theme.of(context).extension<StackColors>()!.popupBG,
|
||||
borderColor: Theme.of(context).extension<StackColors>()!.background,
|
||||
child: RestoringItemCard(
|
||||
left: SizedBox(
|
||||
width: 32,
|
||||
height: 32,
|
||||
child: RoundedContainer(
|
||||
padding: const EdgeInsets.all(0),
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.colorForCoin(coin),
|
||||
child: Center(
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.iconFor(
|
||||
coin: coin,
|
||||
),
|
||||
height: 20,
|
||||
width: 20,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
);
|
||||
onRightTapped: restoringStatus == StackRestoringStatus.failed
|
||||
? () async {
|
||||
final manager = ref.read(provider).manager!;
|
||||
|
||||
ref.read(stackRestoringUIStateProvider).update(
|
||||
walletId: manager.walletId,
|
||||
restoringStatus: StackRestoringStatus.restoring);
|
||||
|
||||
try {
|
||||
final mnemonicList = await manager.mnemonic;
|
||||
int maxUnusedAddressGap = 20;
|
||||
if (coin == Coin.firo) {
|
||||
maxUnusedAddressGap = 50;
|
||||
}
|
||||
const maxNumberOfIndexesToCheck = 1000;
|
||||
|
||||
if (mnemonicList.isEmpty) {
|
||||
await manager.recoverFromMnemonic(
|
||||
mnemonic: ref.read(provider).mnemonic!,
|
||||
maxUnusedAddressGap: maxUnusedAddressGap,
|
||||
maxNumberOfIndexesToCheck:
|
||||
maxNumberOfIndexesToCheck,
|
||||
height: ref.read(provider).height ?? 0,
|
||||
);
|
||||
} else {
|
||||
await manager.fullRescan(
|
||||
maxUnusedAddressGap,
|
||||
maxNumberOfIndexesToCheck,
|
||||
);
|
||||
}
|
||||
|
||||
if (mounted) {
|
||||
final address = await manager.currentReceivingAddress;
|
||||
|
||||
ref.read(stackRestoringUIStateProvider).update(
|
||||
walletId: manager.walletId,
|
||||
restoringStatus: StackRestoringStatus.success,
|
||||
address: address,
|
||||
);
|
||||
}
|
||||
} catch (_) {
|
||||
if (mounted) {
|
||||
ref.read(stackRestoringUIStateProvider).update(
|
||||
walletId: manager.walletId,
|
||||
restoringStatus: StackRestoringStatus.failed,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
: null,
|
||||
right: SizedBox(
|
||||
width: 20,
|
||||
height: 20,
|
||||
child: _getIconForState(
|
||||
ref.watch(provider.select((value) => value.restoringState)),
|
||||
),
|
||||
),
|
||||
title:
|
||||
"${ref.watch(provider.select((value) => value.walletName))} (${coin.ticker})",
|
||||
subTitle: restoringStatus == StackRestoringStatus.failed
|
||||
? Text(
|
||||
"Unable to restore. Tap icon to retry.",
|
||||
style: STextStyles.errorSmall(context),
|
||||
)
|
||||
: ref.watch(provider.select((value) => value.address)) != null
|
||||
? Text(
|
||||
ref.watch(provider.select((value) => value.address))!,
|
||||
style: STextStyles.infoSmall(context),
|
||||
)
|
||||
: null,
|
||||
button: restoringStatus == StackRestoringStatus.failed
|
||||
? Container(
|
||||
height: 20,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
borderRadius: BorderRadius.circular(
|
||||
1000,
|
||||
),
|
||||
),
|
||||
child: RawMaterialButton(
|
||||
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
splashColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.highlight,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
1000,
|
||||
),
|
||||
),
|
||||
onPressed: () async {
|
||||
final mnemonic = ref.read(provider).mnemonic;
|
||||
|
||||
if (mnemonic != null) {
|
||||
Navigator.of(context).push(
|
||||
RouteGenerator.getRoute(
|
||||
builder: (_) => RecoverPhraseView(
|
||||
walletName: ref.read(provider).walletName,
|
||||
mnemonic: mnemonic.split(" "),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||
child: Text(
|
||||
"Show recovery phrase",
|
||||
style: STextStyles.infoSmall(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark),
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,10 +7,14 @@ import 'package:stackwallet/pages/exchange_view/trade_details_view.dart';
|
|||
import 'package:stackwallet/pages/wallet_view/sub_widgets/no_transactions_found.dart';
|
||||
import 'package:stackwallet/providers/global/trades_service_provider.dart';
|
||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||
import 'package:stackwallet/route_generator.dart';
|
||||
import 'package:stackwallet/services/coins/manager.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||
import 'package:stackwallet/widgets/loading_indicator.dart';
|
||||
import 'package:stackwallet/widgets/trade_card.dart';
|
||||
import 'package:stackwallet/widgets/transaction_card.dart';
|
||||
|
@ -94,18 +98,79 @@ class _TransactionsListState extends ConsumerState<TransactionsList> {
|
|||
// this may mess with combined firo transactions
|
||||
key: Key(tx.toString() + trade.uuid), //
|
||||
trade: trade,
|
||||
onTap: () {
|
||||
unawaited(
|
||||
Navigator.of(context).pushNamed(
|
||||
TradeDetailsView.routeName,
|
||||
arguments: Tuple4(
|
||||
trade.tradeId,
|
||||
tx,
|
||||
widget.walletId,
|
||||
ref.read(managerProvider).walletName,
|
||||
onTap: () async {
|
||||
if (Util.isDesktop) {
|
||||
await showDialog<void>(
|
||||
context: context,
|
||||
builder: (context) => Navigator(
|
||||
initialRoute: TradeDetailsView.routeName,
|
||||
onGenerateRoute: RouteGenerator.generateRoute,
|
||||
onGenerateInitialRoutes: (_, __) {
|
||||
return [
|
||||
FadePageRoute(
|
||||
DesktopDialog(
|
||||
// maxHeight:
|
||||
// MediaQuery.of(context).size.height - 64,
|
||||
maxHeight: double.infinity,
|
||||
maxWidth: 580,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 32,
|
||||
bottom: 16,
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Trade details",
|
||||
style: STextStyles.desktopH3(context),
|
||||
),
|
||||
DesktopDialogCloseButton(
|
||||
onPressedOverride: Navigator.of(
|
||||
context,
|
||||
rootNavigator: true,
|
||||
).pop,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Flexible(
|
||||
child: TradeDetailsView(
|
||||
tradeId: trade.tradeId,
|
||||
transactionIfSentFromStack: tx,
|
||||
walletName:
|
||||
ref.read(managerProvider).walletName,
|
||||
walletId: widget.walletId,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const RouteSettings(
|
||||
name: TradeDetailsView.routeName,
|
||||
),
|
||||
),
|
||||
];
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
);
|
||||
} else {
|
||||
unawaited(
|
||||
Navigator.of(context).pushNamed(
|
||||
TradeDetailsView.routeName,
|
||||
arguments: Tuple4(
|
||||
trade.tradeId,
|
||||
tx,
|
||||
widget.walletId,
|
||||
ref.read(managerProvider).walletName,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
)
|
||||
],
|
||||
|
|
|
@ -2,11 +2,11 @@ import 'dart:async';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
|
||||
import 'package:stackwallet/providers/desktop/storage_crypto_handler_provider.dart';
|
||||
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
|
||||
|
@ -23,15 +23,10 @@ import 'package:zxcvbn/zxcvbn.dart';
|
|||
class CreatePasswordView extends ConsumerStatefulWidget {
|
||||
const CreatePasswordView({
|
||||
Key? key,
|
||||
this.secureStore = const SecureStorageWrapper(
|
||||
FlutterSecureStorage(),
|
||||
),
|
||||
}) : super(key: key);
|
||||
|
||||
static const String routeName = "/createPasswordDesktop";
|
||||
|
||||
final FlutterSecureStorageInterface secureStore;
|
||||
|
||||
@override
|
||||
ConsumerState<CreatePasswordView> createState() => _CreatePasswordViewState();
|
||||
}
|
||||
|
@ -79,7 +74,13 @@ class _CreatePasswordViewState extends ConsumerState<CreatePasswordView> {
|
|||
}
|
||||
|
||||
try {
|
||||
if (await ref.read(storageCryptoHandlerProvider).hasPassword()) {
|
||||
throw Exception(
|
||||
"Tried creating a new password and attempted to overwrite an existing entry!");
|
||||
}
|
||||
|
||||
await ref.read(storageCryptoHandlerProvider).initFromNew(passphrase);
|
||||
await (ref.read(secureStoreProvider).store as DesktopSecureStore).init();
|
||||
} catch (e) {
|
||||
unawaited(showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
|
|
|
@ -1,9 +1,17 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/forgot_password_desktop_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
|
||||
import 'package:stackwallet/providers/desktop/storage_crypto_handler_provider.dart';
|
||||
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
|
||||
|
@ -11,21 +19,23 @@ import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
|||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
import 'package:stackwallet/widgets/stack_text_field.dart';
|
||||
|
||||
class DesktopLoginView extends StatefulWidget {
|
||||
class DesktopLoginView extends ConsumerStatefulWidget {
|
||||
const DesktopLoginView({
|
||||
Key? key,
|
||||
this.startupWalletId,
|
||||
this.load,
|
||||
}) : super(key: key);
|
||||
|
||||
static const String routeName = "/desktopLogin";
|
||||
|
||||
final String? startupWalletId;
|
||||
final Future<void> Function()? load;
|
||||
|
||||
@override
|
||||
State<DesktopLoginView> createState() => _DesktopLoginViewState();
|
||||
ConsumerState<DesktopLoginView> createState() => _DesktopLoginViewState();
|
||||
}
|
||||
|
||||
class _DesktopLoginViewState extends State<DesktopLoginView> {
|
||||
class _DesktopLoginViewState extends ConsumerState<DesktopLoginView> {
|
||||
late final TextEditingController passwordController;
|
||||
|
||||
late final FocusNode passwordFocusNode;
|
||||
|
@ -33,6 +43,34 @@ class _DesktopLoginViewState extends State<DesktopLoginView> {
|
|||
bool hidePassword = true;
|
||||
bool _continueEnabled = false;
|
||||
|
||||
Future<void> login() async {
|
||||
try {
|
||||
await ref
|
||||
.read(storageCryptoHandlerProvider)
|
||||
.initFromExisting(passwordController.text);
|
||||
|
||||
await (ref.read(secureStoreProvider).store as DesktopSecureStore).init();
|
||||
|
||||
await widget.load?.call();
|
||||
|
||||
// if no errors passphrase is correct
|
||||
if (mounted) {
|
||||
unawaited(
|
||||
Navigator.of(context).pushNamedAndRemoveUntil(
|
||||
DesktopHomeView.routeName,
|
||||
(route) => false,
|
||||
),
|
||||
);
|
||||
}
|
||||
} catch (e) {
|
||||
await showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: e.toString(),
|
||||
context: context,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
passwordController = TextEditingController();
|
||||
|
@ -153,14 +191,7 @@ class _DesktopLoginViewState extends State<DesktopLoginView> {
|
|||
PrimaryButton(
|
||||
label: "Continue",
|
||||
enabled: _continueEnabled,
|
||||
onPressed: () {
|
||||
// todo auth
|
||||
|
||||
Navigator.of(context).pushNamedAndRemoveUntil(
|
||||
DesktopHomeView.routeName,
|
||||
(route) => false,
|
||||
);
|
||||
},
|
||||
onPressed: login,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 60,
|
||||
|
|
|
@ -1,12 +1,19 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/models/contact.dart';
|
||||
import 'package:stackwallet/pages/address_book_views/subviews/add_address_book_entry_view.dart';
|
||||
import 'package:stackwallet/pages/address_book_views/subviews/address_book_filter_view.dart';
|
||||
import 'package:stackwallet/providers/global/wallets_provider.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/icon_widgets/x_icon.dart';
|
||||
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
import 'package:stackwallet/widgets/stack_text_field.dart';
|
||||
import 'package:stackwallet/widgets/textfield_icon_button.dart';
|
||||
|
||||
|
@ -24,8 +31,43 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
|
|||
|
||||
late final FocusNode _searchFocusNode;
|
||||
|
||||
List<Contact>? _cache;
|
||||
List<Contact>? _cacheFav;
|
||||
|
||||
late bool hasContacts = false;
|
||||
|
||||
String filter = "";
|
||||
|
||||
Future<void> selectCryptocurrency() async {
|
||||
await showDialog<dynamic>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
barrierDismissible: true,
|
||||
builder: (context) {
|
||||
return const DesktopDialog(
|
||||
maxHeight: 609,
|
||||
maxWidth: 576,
|
||||
child: AddressBookFilterView(),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> newContact() async {
|
||||
await showDialog<dynamic>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
barrierDismissible: true,
|
||||
builder: (context) {
|
||||
return const DesktopDialog(
|
||||
maxHeight: 609,
|
||||
maxWidth: 576,
|
||||
child: AddAddressBookEntryView(),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
_searchController = TextEditingController();
|
||||
|
@ -46,9 +88,11 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
|
|||
Widget build(BuildContext context) {
|
||||
debugPrint("BUILD: $runtimeType");
|
||||
final hasWallets = ref.watch(walletsChangeNotifierProvider).hasWallets;
|
||||
final size = MediaQuery.of(context).size;
|
||||
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
DesktopAppBar(
|
||||
isCompactHeight: true,
|
||||
|
@ -67,72 +111,148 @@ class _DesktopAddressBook extends ConsumerState<DesktopAddressBook> {
|
|||
const SizedBox(height: 53),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24),
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 60,
|
||||
width: 489,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
controller: _searchController,
|
||||
focusNode: _searchFocusNode,
|
||||
onChanged: (newString) {
|
||||
setState(() => filter = newString);
|
||||
},
|
||||
style: STextStyles.field(context),
|
||||
decoration: standardInputDecoration(
|
||||
"Search...",
|
||||
_searchFocusNode,
|
||||
context,
|
||||
).copyWith(
|
||||
labelStyle: STextStyles.fieldLabel(context)
|
||||
.copyWith(fontSize: 16),
|
||||
prefixIcon: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 16,
|
||||
child: RoundedContainer(
|
||||
color: Theme.of(context).extension<StackColors>()!.background,
|
||||
child: Row(
|
||||
children: [
|
||||
SizedBox(
|
||||
height: 60,
|
||||
width: size.width - 800,
|
||||
child: ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
autocorrect: false,
|
||||
enableSuggestions: false,
|
||||
controller: _searchController,
|
||||
focusNode: _searchFocusNode,
|
||||
onChanged: (newString) {
|
||||
setState(() => filter = newString);
|
||||
},
|
||||
style: STextStyles.field(context),
|
||||
decoration: standardInputDecoration(
|
||||
"Search...",
|
||||
_searchFocusNode,
|
||||
context,
|
||||
).copyWith(
|
||||
labelStyle: STextStyles.fieldLabel(context)
|
||||
.copyWith(fontSize: 16),
|
||||
prefixIcon: Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 10,
|
||||
vertical: 16,
|
||||
),
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.search,
|
||||
width: 16,
|
||||
height: 16,
|
||||
),
|
||||
),
|
||||
child: SvgPicture.asset(
|
||||
Assets.svg.search,
|
||||
width: 16,
|
||||
height: 16,
|
||||
),
|
||||
),
|
||||
suffixIcon: _searchController.text.isNotEmpty
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(right: 0),
|
||||
child: UnconstrainedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
TextFieldIconButton(
|
||||
child: const XIcon(),
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
_searchController.text = "";
|
||||
filter = "";
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
suffixIcon: _searchController.text.isNotEmpty
|
||||
? Padding(
|
||||
padding: const EdgeInsets.only(right: 0),
|
||||
child: UnconstrainedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
TextFieldIconButton(
|
||||
child: const XIcon(),
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
_searchController.text = "";
|
||||
filter = "";
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
)
|
||||
: null,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
const SizedBox(width: 20),
|
||||
TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getDesktopMenuButtonColorSelected(context),
|
||||
onPressed: () {
|
||||
selectCryptocurrency();
|
||||
},
|
||||
child: SizedBox(
|
||||
width: 200,
|
||||
height: 56,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: SvgPicture.asset(Assets.svg.filter),
|
||||
),
|
||||
Text(
|
||||
"Filter",
|
||||
style: STextStyles.desktopTextExtraExtraSmall(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 20),
|
||||
TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonColor(context),
|
||||
onPressed: () {
|
||||
newContact();
|
||||
},
|
||||
child: SizedBox(
|
||||
width: 200,
|
||||
height: 56,
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 10),
|
||||
child: SvgPicture.asset(Assets.svg.circlePlus),
|
||||
),
|
||||
Text(
|
||||
"Add new",
|
||||
style: STextStyles.desktopTextExtraExtraSmall(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.popupBG,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 24, vertical: 26),
|
||||
child: SizedBox(
|
||||
width: 489,
|
||||
child: RoundedWhiteContainer(
|
||||
child: Center(
|
||||
child: Text(
|
||||
"Your contacts will appear here",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
// Expanded(
|
||||
// child: hasWallets ? const MyWallets() : const EmptyWallets(),
|
||||
// ),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
|
@ -4,8 +4,12 @@ import 'package:stackwallet/pages_desktop_specific/home/address_book_view/deskto
|
|||
import 'package:stackwallet/pages_desktop_specific/home/desktop_menu.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/desktop_settings_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/my_stack_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/notifications/desktop_notifications_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/support_and_about_view/desktop_about_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/support_and_about_view/desktop_support_view.dart';
|
||||
import 'package:stackwallet/providers/desktop/current_desktop_menu_item.dart';
|
||||
import 'package:stackwallet/providers/global/notifications_provider.dart';
|
||||
import 'package:stackwallet/providers/ui/unread_notifications_provider.dart';
|
||||
import 'package:stackwallet/route_generator.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
|
||||
|
@ -19,45 +23,73 @@ class DesktopHomeView extends ConsumerStatefulWidget {
|
|||
}
|
||||
|
||||
class _DesktopHomeViewState extends ConsumerState<DesktopHomeView> {
|
||||
int currentViewIndex = 0;
|
||||
final List<Widget> contentViews = [
|
||||
const Navigator(
|
||||
final Map<DesktopMenuItemId, Widget> contentViews = {
|
||||
DesktopMenuItemId.myStack: const Navigator(
|
||||
key: Key("desktopStackHomeKey"),
|
||||
onGenerateRoute: RouteGenerator.generateRoute,
|
||||
initialRoute: MyStackView.routeName,
|
||||
),
|
||||
Container(
|
||||
color: Colors.green,
|
||||
// Container(
|
||||
// // todo: exchange
|
||||
// color: Colors.green,
|
||||
// ),
|
||||
DesktopMenuItemId.notifications: const Navigator(
|
||||
key: Key("desktopNotificationsHomeKey"),
|
||||
onGenerateRoute: RouteGenerator.generateRoute,
|
||||
initialRoute: DesktopNotificationsView.routeName,
|
||||
),
|
||||
Container(
|
||||
color: Colors.red,
|
||||
),
|
||||
const Navigator(
|
||||
DesktopMenuItemId.addressBook: const Navigator(
|
||||
key: Key("desktopAddressBookHomeKey"),
|
||||
onGenerateRoute: RouteGenerator.generateRoute,
|
||||
initialRoute: DesktopAddressBook.routeName,
|
||||
),
|
||||
const Navigator(
|
||||
DesktopMenuItemId.settings: const Navigator(
|
||||
key: Key("desktopSettingHomeKey"),
|
||||
onGenerateRoute: RouteGenerator.generateRoute,
|
||||
initialRoute: DesktopSettingsView.routeName,
|
||||
),
|
||||
const Navigator(
|
||||
DesktopMenuItemId.support: const Navigator(
|
||||
key: Key("desktopSupportHomeKey"),
|
||||
onGenerateRoute: RouteGenerator.generateRoute,
|
||||
initialRoute: DesktopSupportView.routeName,
|
||||
),
|
||||
const Navigator(
|
||||
DesktopMenuItemId.about: const Navigator(
|
||||
key: Key("desktopAboutHomeKey"),
|
||||
onGenerateRoute: RouteGenerator.generateRoute,
|
||||
initialRoute: DesktopAboutView.routeName,
|
||||
),
|
||||
];
|
||||
};
|
||||
|
||||
void onMenuSelectionChanged(int newIndex) {
|
||||
setState(() {
|
||||
currentViewIndex = newIndex;
|
||||
});
|
||||
void onMenuSelectionWillChange(DesktopMenuItemId newKey) {
|
||||
// check for unread notifications and refresh provider before
|
||||
// showing notifications view
|
||||
if (newKey == DesktopMenuItemId.notifications) {
|
||||
ref.refresh(unreadNotificationsStateProvider);
|
||||
}
|
||||
// mark notifications as read if leaving notifications view
|
||||
if (ref.read(currentDesktopMenuItemProvider.state).state ==
|
||||
DesktopMenuItemId.notifications &&
|
||||
newKey != DesktopMenuItemId.notifications) {
|
||||
final Set<int> unreadNotificationIds =
|
||||
ref.read(unreadNotificationsStateProvider.state).state;
|
||||
|
||||
if (unreadNotificationIds.isNotEmpty) {
|
||||
List<Future<void>> futures = [];
|
||||
for (int i = 0; i < unreadNotificationIds.length - 1; i++) {
|
||||
futures.add(ref
|
||||
.read(notificationsProvider)
|
||||
.markAsRead(unreadNotificationIds.elementAt(i), false));
|
||||
}
|
||||
|
||||
// wait for multiple to update if any
|
||||
Future.wait(futures).then((_) {
|
||||
// only notify listeners once
|
||||
ref
|
||||
.read(notificationsProvider)
|
||||
.markAsRead(unreadNotificationIds.last, true);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -67,14 +99,16 @@ class _DesktopHomeViewState extends ConsumerState<DesktopHomeView> {
|
|||
child: Row(
|
||||
children: [
|
||||
DesktopMenu(
|
||||
onSelectionChanged: onMenuSelectionChanged,
|
||||
// onSelectionChanged: onMenuSelectionChanged,
|
||||
onSelectionWillChange: onMenuSelectionWillChange,
|
||||
),
|
||||
Container(
|
||||
width: 1,
|
||||
color: Theme.of(context).extension<StackColors>()!.background,
|
||||
),
|
||||
Expanded(
|
||||
child: contentViews[currentViewIndex],
|
||||
child: contentViews[
|
||||
ref.watch(currentDesktopMenuItemProvider.state).state]!,
|
||||
),
|
||||
],
|
||||
),
|
||||
|
|
|
@ -4,17 +4,30 @@ import 'package:flutter/material.dart';
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/desktop_menu_item.dart';
|
||||
import 'package:stackwallet/providers/desktop/current_desktop_menu_item.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
|
||||
enum DesktopMenuItemId {
|
||||
myStack,
|
||||
exchange,
|
||||
notifications,
|
||||
addressBook,
|
||||
settings,
|
||||
support,
|
||||
about,
|
||||
}
|
||||
|
||||
class DesktopMenu extends ConsumerStatefulWidget {
|
||||
const DesktopMenu({
|
||||
Key? key,
|
||||
required this.onSelectionChanged,
|
||||
this.onSelectionChanged,
|
||||
this.onSelectionWillChange,
|
||||
}) : super(key: key);
|
||||
|
||||
final void Function(int)? onSelectionChanged;
|
||||
final void Function(DesktopMenuItemId)? onSelectionChanged;
|
||||
final void Function(DesktopMenuItemId)? onSelectionWillChange;
|
||||
|
||||
@override
|
||||
ConsumerState<DesktopMenu> createState() => _DesktopMenuState();
|
||||
|
@ -25,13 +38,13 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
|||
static const minimizedWidth = 72.0;
|
||||
|
||||
double _width = expandedWidth;
|
||||
int selectedMenuItem = 0;
|
||||
|
||||
void updateSelectedMenuItem(int index) {
|
||||
setState(() {
|
||||
selectedMenuItem = index;
|
||||
});
|
||||
widget.onSelectionChanged?.call(index);
|
||||
void updateSelectedMenuItem(DesktopMenuItemId idKey) {
|
||||
widget.onSelectionWillChange?.call(idKey);
|
||||
|
||||
ref.read(currentDesktopMenuItemProvider.state).state = idKey;
|
||||
|
||||
widget.onSelectionChanged?.call(idKey);
|
||||
}
|
||||
|
||||
void toggleMinimize() {
|
||||
|
@ -85,7 +98,10 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
|||
Assets.svg.walletDesktop,
|
||||
width: 20,
|
||||
height: 20,
|
||||
color: 0 == selectedMenuItem
|
||||
color: DesktopMenuItemId.myStack ==
|
||||
ref
|
||||
.watch(currentDesktopMenuItemProvider.state)
|
||||
.state
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark
|
||||
|
@ -95,43 +111,47 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
|||
.withOpacity(0.8),
|
||||
),
|
||||
label: "My Stack",
|
||||
value: 0,
|
||||
group: selectedMenuItem,
|
||||
onChanged: updateSelectedMenuItem,
|
||||
iconOnly: _width == minimizedWidth,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
DesktopMenuItem(
|
||||
icon: SvgPicture.asset(
|
||||
Assets.svg.exchangeDesktop,
|
||||
width: 20,
|
||||
height: 20,
|
||||
color: 1 == selectedMenuItem
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark
|
||||
.withOpacity(0.8),
|
||||
),
|
||||
label: "Exchange",
|
||||
value: 1,
|
||||
group: selectedMenuItem,
|
||||
value: DesktopMenuItemId.myStack,
|
||||
group:
|
||||
ref.watch(currentDesktopMenuItemProvider.state).state,
|
||||
onChanged: updateSelectedMenuItem,
|
||||
iconOnly: _width == minimizedWidth,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 2,
|
||||
),
|
||||
// DesktopMenuItem(
|
||||
// icon: SvgPicture.asset(
|
||||
// Assets.svg.exchangeDesktop,
|
||||
// width: 20,
|
||||
// height: 20,
|
||||
// color: DesktopMenuItemId.exchange == ref.watch(currentDesktopMenuItemProvider.state).state
|
||||
// ? Theme.of(context)
|
||||
// .extension<StackColors>()!
|
||||
// .textDark
|
||||
// : Theme.of(context)
|
||||
// .extension<StackColors>()!
|
||||
// .textDark
|
||||
// .withOpacity(0.8),
|
||||
// ),
|
||||
// label: "Exchange",
|
||||
// value: DesktopMenuItemId.exchange,
|
||||
// group: ref.watch(currentDesktopMenuItemProvider.state).state,
|
||||
// onChanged: updateSelectedMenuItem,
|
||||
// iconOnly: _width == minimizedWidth,
|
||||
// ),
|
||||
// const SizedBox(
|
||||
// height: 2,
|
||||
// ),
|
||||
DesktopMenuItem(
|
||||
icon: SvgPicture.asset(
|
||||
Assets.svg.bell,
|
||||
width: 20,
|
||||
height: 20,
|
||||
color: 2 == selectedMenuItem
|
||||
color: DesktopMenuItemId.notifications ==
|
||||
ref
|
||||
.watch(currentDesktopMenuItemProvider.state)
|
||||
.state
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark
|
||||
|
@ -141,8 +161,9 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
|||
.withOpacity(0.8),
|
||||
),
|
||||
label: "Notifications",
|
||||
value: 2,
|
||||
group: selectedMenuItem,
|
||||
value: DesktopMenuItemId.notifications,
|
||||
group:
|
||||
ref.watch(currentDesktopMenuItemProvider.state).state,
|
||||
onChanged: updateSelectedMenuItem,
|
||||
iconOnly: _width == minimizedWidth,
|
||||
),
|
||||
|
@ -154,7 +175,10 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
|||
Assets.svg.addressBookDesktop,
|
||||
width: 20,
|
||||
height: 20,
|
||||
color: 3 == selectedMenuItem
|
||||
color: DesktopMenuItemId.addressBook ==
|
||||
ref
|
||||
.watch(currentDesktopMenuItemProvider.state)
|
||||
.state
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark
|
||||
|
@ -164,8 +188,9 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
|||
.withOpacity(0.8),
|
||||
),
|
||||
label: "Address Book",
|
||||
value: 3,
|
||||
group: selectedMenuItem,
|
||||
value: DesktopMenuItemId.addressBook,
|
||||
group:
|
||||
ref.watch(currentDesktopMenuItemProvider.state).state,
|
||||
onChanged: updateSelectedMenuItem,
|
||||
iconOnly: _width == minimizedWidth,
|
||||
),
|
||||
|
@ -177,7 +202,10 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
|||
Assets.svg.gear,
|
||||
width: 20,
|
||||
height: 20,
|
||||
color: 4 == selectedMenuItem
|
||||
color: DesktopMenuItemId.settings ==
|
||||
ref
|
||||
.watch(currentDesktopMenuItemProvider.state)
|
||||
.state
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark
|
||||
|
@ -187,8 +215,9 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
|||
.withOpacity(0.8),
|
||||
),
|
||||
label: "Settings",
|
||||
value: 4,
|
||||
group: selectedMenuItem,
|
||||
value: DesktopMenuItemId.settings,
|
||||
group:
|
||||
ref.watch(currentDesktopMenuItemProvider.state).state,
|
||||
onChanged: updateSelectedMenuItem,
|
||||
iconOnly: _width == minimizedWidth,
|
||||
),
|
||||
|
@ -200,7 +229,10 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
|||
Assets.svg.messageQuestion,
|
||||
width: 20,
|
||||
height: 20,
|
||||
color: 5 == selectedMenuItem
|
||||
color: DesktopMenuItemId.support ==
|
||||
ref
|
||||
.watch(currentDesktopMenuItemProvider.state)
|
||||
.state
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark
|
||||
|
@ -210,8 +242,9 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
|||
.withOpacity(0.8),
|
||||
),
|
||||
label: "Support",
|
||||
value: 5,
|
||||
group: selectedMenuItem,
|
||||
value: DesktopMenuItemId.support,
|
||||
group:
|
||||
ref.watch(currentDesktopMenuItemProvider.state).state,
|
||||
onChanged: updateSelectedMenuItem,
|
||||
iconOnly: _width == minimizedWidth,
|
||||
),
|
||||
|
@ -223,7 +256,10 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
|||
Assets.svg.aboutDesktop,
|
||||
width: 20,
|
||||
height: 20,
|
||||
color: 6 == selectedMenuItem
|
||||
color: DesktopMenuItemId.about ==
|
||||
ref
|
||||
.watch(currentDesktopMenuItemProvider.state)
|
||||
.state
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark
|
||||
|
@ -233,8 +269,9 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
|||
.withOpacity(0.8),
|
||||
),
|
||||
label: "About",
|
||||
value: 6,
|
||||
group: selectedMenuItem,
|
||||
value: DesktopMenuItemId.about,
|
||||
group:
|
||||
ref.watch(currentDesktopMenuItemProvider.state).state,
|
||||
onChanged: updateSelectedMenuItem,
|
||||
iconOnly: _width == minimizedWidth,
|
||||
),
|
||||
|
@ -251,7 +288,8 @@ class _DesktopMenuState extends ConsumerState<DesktopMenu> {
|
|||
),
|
||||
label: "Exit",
|
||||
value: 7,
|
||||
group: selectedMenuItem,
|
||||
group:
|
||||
ref.watch(currentDesktopMenuItemProvider.state).state,
|
||||
onChanged: (_) {
|
||||
// todo: save stuff/ notify before exit?
|
||||
exit(0);
|
||||
|
|
|
@ -0,0 +1,173 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:stackwallet/providers/desktop/storage_crypto_handler_provider.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||
import 'package:stackwallet/widgets/stack_text_field.dart';
|
||||
|
||||
class DesktopAuthSend extends ConsumerStatefulWidget {
|
||||
const DesktopAuthSend({Key? key}) : super(key: key);
|
||||
|
||||
@override
|
||||
ConsumerState<DesktopAuthSend> createState() => _DesktopAuthSendState();
|
||||
}
|
||||
|
||||
class _DesktopAuthSendState extends ConsumerState<DesktopAuthSend> {
|
||||
late final TextEditingController passwordController;
|
||||
late final FocusNode passwordFocusNode;
|
||||
|
||||
bool hidePassword = true;
|
||||
|
||||
bool _confirmEnabled = false;
|
||||
|
||||
Future<bool> verifyPassphrase() async {
|
||||
return await ref
|
||||
.read(storageCryptoHandlerProvider)
|
||||
.verifyPassphrase(passwordController.text);
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
passwordController = TextEditingController();
|
||||
passwordFocusNode = FocusNode();
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
passwordController.dispose();
|
||||
passwordFocusNode.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.svg.keys,
|
||||
width: 100,
|
||||
),
|
||||
const SizedBox(
|
||||
height: 56,
|
||||
),
|
||||
Text(
|
||||
"Confirm transaction",
|
||||
style: STextStyles.desktopH3(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Text(
|
||||
"Enter your wallet password to send BTC",
|
||||
style: STextStyles.desktopTextMedium(context).copyWith(
|
||||
color: Theme.of(context).extension<StackColors>()!.textDark3,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 24,
|
||||
),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
key: const Key("desktopLoginPasswordFieldKey"),
|
||||
focusNode: passwordFocusNode,
|
||||
controller: passwordController,
|
||||
style: STextStyles.desktopTextMedium(context).copyWith(
|
||||
height: 2,
|
||||
),
|
||||
obscureText: hidePassword,
|
||||
enableSuggestions: false,
|
||||
autocorrect: false,
|
||||
decoration: standardInputDecoration(
|
||||
"Enter password",
|
||||
passwordFocusNode,
|
||||
context,
|
||||
).copyWith(
|
||||
suffixIcon: UnconstrainedBox(
|
||||
child: SizedBox(
|
||||
height: 70,
|
||||
child: Row(
|
||||
children: [
|
||||
const SizedBox(
|
||||
width: 24,
|
||||
),
|
||||
GestureDetector(
|
||||
key: const Key(
|
||||
"restoreFromFilePasswordFieldShowPasswordButtonKey"),
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
hidePassword = !hidePassword;
|
||||
});
|
||||
},
|
||||
child: SvgPicture.asset(
|
||||
hidePassword ? Assets.svg.eye : Assets.svg.eyeSlash,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark3,
|
||||
width: 24,
|
||||
height: 24,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
onChanged: (newValue) {
|
||||
setState(() {
|
||||
_confirmEnabled = passwordController.text.isNotEmpty;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 48,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: SecondaryButton(
|
||||
label: "Cancel",
|
||||
desktopMed: true,
|
||||
onPressed: Navigator.of(context).pop,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
enabled: _confirmEnabled,
|
||||
label: "Confirm",
|
||||
desktopMed: true,
|
||||
onPressed: () async {
|
||||
// TODO show spinner while verifying passphrase
|
||||
|
||||
final passwordIsValid = await verifyPassphrase();
|
||||
|
||||
if (mounted) {
|
||||
Navigator.of(context).pop(passwordIsValid);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:decimal/decimal.dart';
|
||||
import 'package:dropdown_button2/dropdown_button2.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
|
@ -9,8 +10,8 @@ import 'package:stackwallet/models/contact_address_entry.dart';
|
|||
import 'package:stackwallet/models/send_view_auto_fill_data.dart';
|
||||
import 'package:stackwallet/pages/send_view/confirm_transaction_view.dart';
|
||||
import 'package:stackwallet/pages/send_view/sub_widgets/building_transaction_dialog.dart';
|
||||
import 'package:stackwallet/pages/send_view/sub_widgets/firo_balance_selection_sheet.dart';
|
||||
import 'package:stackwallet/pages/send_view/sub_widgets/transaction_fee_selection_sheet.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/desktop_home_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/address_book_address_chooser/address_book_address_chooser.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/providers/ui/fee_rate_type_state_provider.dart';
|
||||
|
@ -332,6 +333,7 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
child: ConfirmTransactionView(
|
||||
transactionInfo: txData,
|
||||
walletId: walletId,
|
||||
routeOnSuccessName: DesktopHomeView.routeName,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -550,13 +552,13 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
Future<String?> _firoBalanceFuture(
|
||||
ChangeNotifierProvider<Manager> provider,
|
||||
String locale,
|
||||
bool private,
|
||||
) async {
|
||||
final wallet = ref.read(provider).wallet as FiroWallet?;
|
||||
|
||||
if (wallet != null) {
|
||||
Decimal? balance;
|
||||
if (ref.read(publicPrivateBalanceStateProvider.state).state ==
|
||||
"Private") {
|
||||
if (private) {
|
||||
balance = await wallet.availablePrivateBalance();
|
||||
} else {
|
||||
balance = await wallet.availablePublicBalance();
|
||||
|
@ -572,24 +574,21 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
Widget firoBalanceFutureBuilder(
|
||||
BuildContext context,
|
||||
AsyncSnapshot<String?> snapshot,
|
||||
bool private,
|
||||
) {
|
||||
if (snapshot.connectionState == ConnectionState.done && snapshot.hasData) {
|
||||
if (ref.read(publicPrivateBalanceStateProvider.state).state ==
|
||||
"Private") {
|
||||
if (private) {
|
||||
_privateBalanceString = snapshot.data!;
|
||||
} else {
|
||||
_publicBalanceString = snapshot.data!;
|
||||
}
|
||||
}
|
||||
if (ref.read(publicPrivateBalanceStateProvider.state).state == "Private" &&
|
||||
_privateBalanceString != null) {
|
||||
if (private && _privateBalanceString != null) {
|
||||
return Text(
|
||||
"$_privateBalanceString ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
);
|
||||
} else if (ref.read(publicPrivateBalanceStateProvider.state).state ==
|
||||
"Public" &&
|
||||
_publicBalanceString != null) {
|
||||
} else if (!private && _publicBalanceString != null) {
|
||||
return Text(
|
||||
"$_publicBalanceString ${coin.ticker}",
|
||||
style: STextStyles.itemSubtitle(context),
|
||||
|
@ -889,71 +888,95 @@ class _DesktopSendState extends ConsumerState<DesktopSend> {
|
|||
height: 10,
|
||||
),
|
||||
if (coin == Coin.firo)
|
||||
Stack(
|
||||
children: [
|
||||
TextField(
|
||||
autocorrect: Util.isDesktop ? false : true,
|
||||
enableSuggestions: Util.isDesktop ? false : true,
|
||||
readOnly: true,
|
||||
textInputAction: TextInputAction.none,
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 12,
|
||||
),
|
||||
child: RawMaterialButton(
|
||||
splashColor:
|
||||
Theme.of(context).extension<StackColors>()!.highlight,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
showModalBottomSheet<dynamic>(
|
||||
backgroundColor: Colors.transparent,
|
||||
context: context,
|
||||
shape: const RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.vertical(
|
||||
top: Radius.circular(20),
|
||||
),
|
||||
),
|
||||
builder: (_) => FiroBalanceSelectionSheet(
|
||||
walletId: walletId,
|
||||
),
|
||||
);
|
||||
},
|
||||
DropdownButtonHideUnderline(
|
||||
child: DropdownButton2(
|
||||
offset: const Offset(0, -10),
|
||||
isExpanded: true,
|
||||
dropdownElevation: 0,
|
||||
value: ref.watch(publicPrivateBalanceStateProvider.state).state,
|
||||
items: [
|
||||
DropdownMenuItem(
|
||||
value: "Private",
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Row(
|
||||
children: [
|
||||
Text(
|
||||
"${ref.watch(publicPrivateBalanceStateProvider.state).state} balance",
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
FutureBuilder(
|
||||
future: _firoBalanceFuture(provider, locale),
|
||||
builder: firoBalanceFutureBuilder,
|
||||
),
|
||||
],
|
||||
Text(
|
||||
"Private balance",
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
SvgPicture.asset(
|
||||
Assets.svg.chevronDown,
|
||||
width: 8,
|
||||
height: 4,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textSubtitle2,
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
FutureBuilder(
|
||||
future: _firoBalanceFuture(provider, locale, true),
|
||||
builder: (context, AsyncSnapshot<String?> snapshot) =>
|
||||
firoBalanceFutureBuilder(
|
||||
context,
|
||||
snapshot,
|
||||
true,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
DropdownMenuItem(
|
||||
value: "Public",
|
||||
child: Row(
|
||||
children: [
|
||||
Text(
|
||||
"Public balance",
|
||||
style: STextStyles.itemSubtitle12(context),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 10,
|
||||
),
|
||||
FutureBuilder(
|
||||
future: _firoBalanceFuture(provider, locale, false),
|
||||
builder: (context, AsyncSnapshot<String?> snapshot) =>
|
||||
firoBalanceFutureBuilder(
|
||||
context,
|
||||
snapshot,
|
||||
false,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
onChanged: (value) {
|
||||
if (value is String) {
|
||||
setState(() {
|
||||
ref.watch(publicPrivateBalanceStateProvider.state).state =
|
||||
value;
|
||||
});
|
||||
}
|
||||
},
|
||||
icon: SvgPicture.asset(
|
||||
Assets.svg.chevronDown,
|
||||
width: 12,
|
||||
height: 6,
|
||||
color: Theme.of(context).extension<StackColors>()!.textDark3,
|
||||
),
|
||||
buttonPadding: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 8,
|
||||
),
|
||||
buttonDecoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultBG,
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
dropdownDecoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultBG,
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (coin == Coin.firo)
|
||||
const SizedBox(
|
||||
|
|
|
@ -1,10 +1,15 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart';
|
||||
import 'package:stackwallet/providers/desktop/storage_crypto_handler_provider.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
|
@ -196,36 +201,32 @@ class _UnlockWalletKeysDesktopState
|
|||
enabled: continueEnabled,
|
||||
onPressed: continueEnabled
|
||||
? () async {
|
||||
// todo: check password
|
||||
// Navigator.of(context).pop();
|
||||
final words = await ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(widget.walletId)
|
||||
.mnemonic;
|
||||
final verified = await ref
|
||||
.read(storageCryptoHandlerProvider)
|
||||
.verifyPassphrase(passwordController.text);
|
||||
|
||||
await Navigator.of(context).pushReplacementNamed(
|
||||
WalletKeysDesktopPopup.routeName,
|
||||
arguments: words,
|
||||
);
|
||||
//
|
||||
// await showDialog<void>(
|
||||
// context: context,
|
||||
// barrierDismissible: false,
|
||||
// builder: (context) => Navigator(
|
||||
// initialRoute: WalletKeysDesktopPopup.routeName,
|
||||
// onGenerateRoute: RouteGenerator.generateRoute,
|
||||
// onGenerateInitialRoutes: (_, __) {
|
||||
// return [
|
||||
// RouteGenerator.generateRoute(
|
||||
// RouteSettings(
|
||||
// name: WalletKeysDesktopPopup.routeName,
|
||||
// arguments: words,
|
||||
// ),
|
||||
// )
|
||||
// ];
|
||||
// },
|
||||
// ),
|
||||
// );
|
||||
if (verified) {
|
||||
final words = await ref
|
||||
.read(walletsChangeNotifierProvider)
|
||||
.getManager(widget.walletId)
|
||||
.mnemonic;
|
||||
|
||||
if (mounted) {
|
||||
await Navigator.of(context)
|
||||
.pushReplacementNamed(
|
||||
WalletKeysDesktopPopup.routeName,
|
||||
arguments: words,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Invalid passphrase!",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
: null,
|
||||
),
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/notifications/notification_card.dart';
|
||||
import 'package:stackwallet/providers/providers.dart';
|
||||
import 'package:stackwallet/providers/ui/unread_notifications_provider.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_app_bar.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_scaffold.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
|
||||
class DesktopNotificationsView extends ConsumerStatefulWidget {
|
||||
const DesktopNotificationsView({Key? key}) : super(key: key);
|
||||
|
||||
static const String routeName = "/desktopNotifications";
|
||||
|
||||
@override
|
||||
ConsumerState<DesktopNotificationsView> createState() =>
|
||||
_DesktopNotificationsViewState();
|
||||
}
|
||||
|
||||
class _DesktopNotificationsViewState
|
||||
extends ConsumerState<DesktopNotificationsView> {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final notifications =
|
||||
ref.watch(notificationsProvider.select((value) => value.notifications));
|
||||
|
||||
return DesktopScaffold(
|
||||
background: Theme.of(context).extension<StackColors>()!.background,
|
||||
appBar: DesktopAppBar(
|
||||
isCompactHeight: true,
|
||||
leading: Padding(
|
||||
padding: const EdgeInsets.only(left: 24),
|
||||
child: Text(
|
||||
"Notifications",
|
||||
style: STextStyles.desktopH3(context),
|
||||
),
|
||||
),
|
||||
),
|
||||
body: notifications.isEmpty
|
||||
? RoundedWhiteContainer(
|
||||
child: Center(
|
||||
child: Text(
|
||||
"Notifications will appear here",
|
||||
style: STextStyles.desktopTextExtraExtraSmall(context),
|
||||
),
|
||||
),
|
||||
)
|
||||
: ListView.builder(
|
||||
primary: false,
|
||||
itemCount: notifications.length,
|
||||
itemBuilder: (context, index) {
|
||||
final notification = notifications[index];
|
||||
if (notification.read == false) {
|
||||
ref
|
||||
.read(unreadNotificationsStateProvider.state)
|
||||
.state
|
||||
.add(notification.id);
|
||||
}
|
||||
|
||||
return Padding(
|
||||
padding: const EdgeInsets.symmetric(
|
||||
horizontal: 24,
|
||||
vertical: 5,
|
||||
),
|
||||
child: NotificationCard(
|
||||
notification: notification,
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -4,9 +4,11 @@ import 'package:flutter_riverpod/flutter_riverpod.dart';
|
|||
import 'package:flutter_svg/flutter_svg.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/create_backup_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/edit_auto_backup_view.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/restore_from_file_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/backup_and_restore/create_auto_backup.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/backup_and_restore/enable_backup_dialog.dart';
|
||||
import 'package:stackwallet/providers/global/auto_swb_service_provider.dart';
|
||||
import 'package:stackwallet/providers/global/locale_provider.dart';
|
||||
import 'package:stackwallet/providers/global/prefs_provider.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
|
@ -14,16 +16,18 @@ import 'package:stackwallet/utilities/enums/backup_frequency_type.dart';
|
|||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/blue_text_button.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/draggable_switch_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||
import 'package:stackwallet/widgets/rounded_container.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
import 'package:stackwallet/widgets/stack_dialog.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
import '../../../../providers/global/auto_swb_service_provider.dart';
|
||||
import '../../../../widgets/custom_buttons/blue_text_button.dart';
|
||||
|
||||
class BackupRestoreSettings extends ConsumerStatefulWidget {
|
||||
const BackupRestoreSettings({Key? key}) : super(key: key);
|
||||
|
||||
|
@ -97,53 +101,171 @@ class _BackupRestoreSettings extends ConsumerState<BackupRestoreSettings> {
|
|||
useSafeArea: false,
|
||||
barrierDismissible: true,
|
||||
builder: (context) {
|
||||
return CreateAutoBackup();
|
||||
return const CreateAutoBackup();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> editAutoBackup() async {
|
||||
await showDialog<dynamic>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
barrierDismissible: true,
|
||||
builder: (context) => DesktopDialog(
|
||||
maxWidth: 580,
|
||||
maxHeight: double.infinity,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(left: 32),
|
||||
child: Text(
|
||||
"Edit auto backup",
|
||||
style: STextStyles.desktopH3(context),
|
||||
),
|
||||
),
|
||||
const DesktopDialogCloseButton(),
|
||||
],
|
||||
),
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 32,
|
||||
right: 32,
|
||||
bottom: 32,
|
||||
),
|
||||
child: EditAutoBackupView(),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> attemptDisable() async {
|
||||
final result = await showDialog<bool?>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
barrierDismissible: true,
|
||||
builder: (context) {
|
||||
return StackDialog(
|
||||
title: "Disable Auto Backup",
|
||||
message:
|
||||
"You are turning off Auto Backup. You can turn it back on at any time. Your previous Auto Backup file will not be deleted. Remember to backup your wallets manually so you don't lose important information.",
|
||||
leftButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getSecondaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Back",
|
||||
style: STextStyles.button(context).copyWith(
|
||||
color:
|
||||
Theme.of(context).extension<StackColors>()!.accentColorDark,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
rightButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Disable",
|
||||
style: STextStyles.button(context),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
setState(() {
|
||||
ref.watch(prefsChangeNotifierProvider).isAutoBackupEnabled =
|
||||
false;
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
return !Util.isDesktop
|
||||
? StackDialog(
|
||||
title: "Disable Auto Backup",
|
||||
message:
|
||||
"You are turning off Auto Backup. You can turn it back on at any time. Your previous Auto Backup file will not be deleted. Remember to backup your wallets manually so you don't lose important information.",
|
||||
leftButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getSecondaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Back",
|
||||
style: STextStyles.button(context).copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorDark,
|
||||
),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
rightButton: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonColor(context),
|
||||
child: Text(
|
||||
"Disable",
|
||||
style: STextStyles.button(context),
|
||||
),
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
setState(() {
|
||||
ref
|
||||
.watch(prefsChangeNotifierProvider)
|
||||
.isAutoBackupEnabled = false;
|
||||
});
|
||||
},
|
||||
),
|
||||
)
|
||||
: DesktopDialog(
|
||||
maxHeight: double.infinity,
|
||||
maxWidth: 580,
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 32,
|
||||
),
|
||||
child: Text(
|
||||
"Disable Auto Backup",
|
||||
style: STextStyles.desktopH3(context),
|
||||
),
|
||||
),
|
||||
const DesktopDialogCloseButton(),
|
||||
],
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 32,
|
||||
right: 32,
|
||||
bottom: 32,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SizedBox(
|
||||
width: 600,
|
||||
child: Text(
|
||||
"You are turning off Auto Backup. You can turn it back on at any time. Your previous Auto Backup file will not be deleted. Remember to backup your wallets manually so you don't lose important information.",
|
||||
style: STextStyles.desktopTextSmall(context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark3,
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 48,
|
||||
),
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Expanded(
|
||||
child: SecondaryButton(
|
||||
desktopMed: true,
|
||||
label: "Cancel",
|
||||
onPressed: Navigator.of(context).pop,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
desktopMed: true,
|
||||
label: "Disable",
|
||||
onPressed: () {
|
||||
ref
|
||||
.read(prefsChangeNotifierProvider)
|
||||
.isAutoBackupEnabled = false;
|
||||
Navigator.of(context).pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
if (mounted) {
|
||||
|
@ -310,40 +432,32 @@ class _BackupRestoreSettings extends ConsumerState<BackupRestoreSettings> {
|
|||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Container(
|
||||
RoundedContainer(
|
||||
width: 403,
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.background,
|
||||
child: Padding(
|
||||
padding:
|
||||
const EdgeInsets.all(8.0),
|
||||
child: Column(
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Backed up ${prettySinceLastBackupString(ref.watch(prefsChangeNotifierProvider.select((value) => value.lastAutoBackup)))}",
|
||||
style: STextStyles
|
||||
.itemSubtitle(
|
||||
context),
|
||||
),
|
||||
BlueTextButton(
|
||||
text: "Back up now",
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
autoSWBServiceProvider)
|
||||
.doBackup();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
child: Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Backed up ${prettySinceLastBackupString(ref.watch(prefsChangeNotifierProvider.select((value) => value.lastAutoBackup)))}",
|
||||
style:
|
||||
STextStyles.itemSubtitle(
|
||||
context),
|
||||
),
|
||||
BlueTextButton(
|
||||
text: "Back up now",
|
||||
onTap: () {
|
||||
ref
|
||||
.read(
|
||||
autoSWBServiceProvider)
|
||||
.doBackup();
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -365,7 +479,7 @@ class _BackupRestoreSettings extends ConsumerState<BackupRestoreSettings> {
|
|||
width: 190,
|
||||
label: "Edit auto backup",
|
||||
onPressed: () {
|
||||
createAutoBackup();
|
||||
editAutoBackup();
|
||||
},
|
||||
),
|
||||
],
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
|
@ -5,26 +6,25 @@ import 'package:dropdown_button2/dropdown_button2.dart';
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stack_wallet_backup/stack_wallet_backup.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/stack_file_system.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/swb_file_system.dart';
|
||||
import 'package:stackwallet/providers/global/prefs_provider.dart';
|
||||
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/backup_frequency_type.dart';
|
||||
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
|
||||
import 'package:stackwallet/utilities/enums/log_level_enum.dart';
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
import 'package:stackwallet/utilities/format.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
import 'package:stackwallet/widgets/custom_buttons/app_bar_icon_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog.dart';
|
||||
import 'package:stackwallet/widgets/desktop/desktop_dialog_close_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
import 'package:stackwallet/widgets/desktop/secondary_button.dart';
|
||||
import 'package:stackwallet/widgets/progress_bar.dart';
|
||||
|
@ -35,13 +35,8 @@ import 'package:zxcvbn/zxcvbn.dart';
|
|||
class CreateAutoBackup extends ConsumerStatefulWidget {
|
||||
const CreateAutoBackup({
|
||||
Key? key,
|
||||
this.secureStore = const SecureStorageWrapper(
|
||||
FlutterSecureStorage(),
|
||||
),
|
||||
}) : super(key: key);
|
||||
|
||||
final FlutterSecureStorageInterface secureStore;
|
||||
|
||||
@override
|
||||
ConsumerState<CreateAutoBackup> createState() => _CreateAutoBackup();
|
||||
}
|
||||
|
@ -51,9 +46,9 @@ class _CreateAutoBackup extends ConsumerState<CreateAutoBackup> {
|
|||
late final TextEditingController passphraseController;
|
||||
late final TextEditingController passphraseRepeatController;
|
||||
|
||||
late final FlutterSecureStorageInterface secureStore;
|
||||
late final SecureStorageInterface secureStore;
|
||||
|
||||
late final StackFileSystem stackFileSystem;
|
||||
late final SWBFileSystem stackFileSystem;
|
||||
late final FocusNode passphraseFocusNode;
|
||||
late final FocusNode passphraseRepeatFocusNode;
|
||||
final zxcvbn = Zxcvbn();
|
||||
|
@ -85,8 +80,8 @@ class _CreateAutoBackup extends ConsumerState<CreateAutoBackup> {
|
|||
|
||||
@override
|
||||
void initState() {
|
||||
secureStore = widget.secureStore;
|
||||
stackFileSystem = StackFileSystem();
|
||||
secureStore = ref.read(secureStoreProvider);
|
||||
stackFileSystem = SWBFileSystem();
|
||||
|
||||
fileLocationController = TextEditingController();
|
||||
passphraseController = TextEditingController();
|
||||
|
@ -125,10 +120,9 @@ class _CreateAutoBackup extends ConsumerState<CreateAutoBackup> {
|
|||
Widget build(BuildContext context) {
|
||||
debugPrint("BUILD: $runtimeType ");
|
||||
|
||||
bool isEnabledAutoBackup = ref.watch(prefsChangeNotifierProvider
|
||||
.select((value) => value.isAutoBackupEnabled));
|
||||
// bool isEnabledAutoBackup = ref.watch(prefsChangeNotifierProvider
|
||||
// .select((value) => value.isAutoBackupEnabled));
|
||||
|
||||
String? selectedItem = "Every 10 minutes";
|
||||
final isDesktop = Util.isDesktop;
|
||||
return DesktopDialog(
|
||||
maxHeight: 680,
|
||||
|
@ -146,25 +140,7 @@ class _CreateAutoBackup extends ConsumerState<CreateAutoBackup> {
|
|||
textAlign: TextAlign.center,
|
||||
),
|
||||
),
|
||||
Padding(
|
||||
padding: const EdgeInsets.all(20.0),
|
||||
child: AppBarIconButton(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textFieldDefaultBG,
|
||||
size: 40,
|
||||
icon: SvgPicture.asset(
|
||||
Assets.svg.x,
|
||||
color: Theme.of(context).extension<StackColors>()!.textDark,
|
||||
width: 22,
|
||||
height: 22,
|
||||
),
|
||||
onPressed: () {
|
||||
int count = 0;
|
||||
Navigator.of(context).popUntil((_) => count++ >= 2);
|
||||
},
|
||||
),
|
||||
),
|
||||
const DesktopDialogCloseButton(),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -407,7 +383,7 @@ class _CreateAutoBackup extends ConsumerState<CreateAutoBackup> {
|
|||
),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
height: 16,
|
||||
),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
|
@ -493,7 +469,7 @@ class _CreateAutoBackup extends ConsumerState<CreateAutoBackup> {
|
|||
child: isDesktop
|
||||
? DropdownButtonHideUnderline(
|
||||
child: DropdownButton2(
|
||||
offset: Offset(0, -10),
|
||||
offset: const Offset(0, -10),
|
||||
isExpanded: true,
|
||||
dropdownElevation: 0,
|
||||
value: _currentDropDownValue,
|
||||
|
@ -576,12 +552,8 @@ class _CreateAutoBackup extends ConsumerState<CreateAutoBackup> {
|
|||
Expanded(
|
||||
child: SecondaryButton(
|
||||
label: "Cancel",
|
||||
onPressed: () {
|
||||
int count = 0;
|
||||
!isEnabledAutoBackup
|
||||
? Navigator.of(context).popUntil((_) => count++ >= 2)
|
||||
: Navigator.of(context).pop();
|
||||
},
|
||||
desktopMed: true,
|
||||
onPressed: Navigator.of(context).pop,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
|
@ -589,6 +561,7 @@ class _CreateAutoBackup extends ConsumerState<CreateAutoBackup> {
|
|||
),
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
desktopMed: true,
|
||||
label: "Enable Auto Backup",
|
||||
enabled: shouldEnableCreate,
|
||||
onPressed: !shouldEnableCreate
|
||||
|
@ -601,44 +574,89 @@ class _CreateAutoBackup extends ConsumerState<CreateAutoBackup> {
|
|||
passphraseRepeatController.text;
|
||||
|
||||
if (pathToSave.isEmpty) {
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Directory not chosen",
|
||||
context: context,
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Directory not chosen",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (!(await Directory(pathToSave).exists())) {
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Directory does not exist",
|
||||
context: context,
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Directory does not exist",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (passphrase.isEmpty) {
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "A passphrase is required",
|
||||
context: context,
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "A passphrase is required",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
if (passphrase != repeatPassphrase) {
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Passphrase does not match",
|
||||
context: context,
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Passphrase does not match",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
showDialog<dynamic>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => const StackDialog(
|
||||
title: "Encrypting initial backup",
|
||||
message: "This shouldn't take long",
|
||||
unawaited(
|
||||
showDialog<dynamic>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) {
|
||||
if (Util.isDesktop) {
|
||||
return DesktopDialog(
|
||||
maxHeight: double.infinity,
|
||||
maxWidth: 450,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(
|
||||
32,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Encrypting initial backup",
|
||||
style: STextStyles.desktopH3(
|
||||
context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 40,
|
||||
),
|
||||
Text(
|
||||
"This shouldn't take long",
|
||||
style: STextStyles
|
||||
.desktopTextExtraExtraSmall(
|
||||
context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const StackDialog(
|
||||
title: "Encrypting initial backup",
|
||||
message: "This shouldn't take long",
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
|
@ -659,10 +677,12 @@ class _CreateAutoBackup extends ConsumerState<CreateAutoBackup> {
|
|||
.log("$err\n$s", level: LogLevel.Error);
|
||||
// pop encryption progress dialog
|
||||
Navigator.of(context).pop();
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: err,
|
||||
context: context,
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: err,
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
return;
|
||||
} catch (e, s) {
|
||||
|
@ -670,10 +690,12 @@ class _CreateAutoBackup extends ConsumerState<CreateAutoBackup> {
|
|||
.log("$e\n$s", level: LogLevel.Error);
|
||||
// pop encryption progress dialog
|
||||
Navigator.of(context).pop();
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "$e",
|
||||
context: context,
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "$e",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
@ -688,7 +710,9 @@ class _CreateAutoBackup extends ConsumerState<CreateAutoBackup> {
|
|||
final String fileToSave =
|
||||
createAutoBackupFilename(pathToSave, now);
|
||||
|
||||
final backup = await SWB.createStackWalletJSON();
|
||||
final backup = await SWB.createStackWalletJSON(
|
||||
secureStorage: secureStore,
|
||||
);
|
||||
|
||||
bool result = await SWB.encryptStackWalletWithADK(
|
||||
fileToSave,
|
||||
|
@ -702,9 +726,7 @@ class _CreateAutoBackup extends ConsumerState<CreateAutoBackup> {
|
|||
|
||||
if (mounted) {
|
||||
// pop encryption progress dialog
|
||||
int count = 0;
|
||||
Navigator.of(context)
|
||||
.popUntil((_) => count++ >= 2);
|
||||
Navigator.of(context).pop();
|
||||
|
||||
if (result) {
|
||||
ref
|
||||
|
@ -721,22 +743,76 @@ class _CreateAutoBackup extends ConsumerState<CreateAutoBackup> {
|
|||
await showDialog<dynamic>(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (_) => Platform.isAndroid
|
||||
? StackOkDialog(
|
||||
title:
|
||||
"Stack Auto Backup enabled and saved to:",
|
||||
message: fileToSave,
|
||||
)
|
||||
: const StackOkDialog(
|
||||
title: "Stack Auto Backup enabled!"),
|
||||
builder: (context) {
|
||||
if (Platform.isAndroid) {
|
||||
return StackOkDialog(
|
||||
title:
|
||||
"Stack Auto Backup enabled and saved to:",
|
||||
message: fileToSave,
|
||||
);
|
||||
} else if (Util.isDesktop) {
|
||||
return DesktopDialog(
|
||||
maxHeight: double.infinity,
|
||||
maxWidth: 500,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 32,
|
||||
right: 32,
|
||||
bottom: 32,
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment:
|
||||
CrossAxisAlignment.start,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment:
|
||||
MainAxisAlignment
|
||||
.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
"Stack Auto Backup enabled!",
|
||||
style:
|
||||
STextStyles.desktopH3(
|
||||
context),
|
||||
),
|
||||
const DesktopDialogCloseButton(),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 40,
|
||||
),
|
||||
Row(
|
||||
children: [
|
||||
const Spacer(),
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
label: "Ok",
|
||||
desktopMed: true,
|
||||
onPressed: () {
|
||||
Navigator.of(context)
|
||||
.pop();
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const StackOkDialog(
|
||||
title: "Stack Auto Backup enabled!",
|
||||
);
|
||||
}
|
||||
},
|
||||
);
|
||||
if (mounted) {
|
||||
passphraseController.text = "";
|
||||
passphraseRepeatController.text = "";
|
||||
|
||||
int count = 0;
|
||||
Navigator.of(context)
|
||||
.popUntil((_) => count++ >= 2);
|
||||
Navigator.of(context).pop();
|
||||
}
|
||||
} else {
|
||||
await showDialog<dynamic>(
|
||||
|
|
|
@ -18,7 +18,7 @@ class EnableBackupDialog extends StatelessWidget {
|
|||
useSafeArea: false,
|
||||
barrierDismissible: true,
|
||||
builder: (context) {
|
||||
return CreateAutoBackup();
|
||||
return const CreateAutoBackup();
|
||||
},
|
||||
);
|
||||
}
|
||||
|
@ -59,6 +59,7 @@ class EnableBackupDialog extends StatelessWidget {
|
|||
children: [
|
||||
Expanded(
|
||||
child: SecondaryButton(
|
||||
desktopMed: true,
|
||||
label: "Cancel",
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
|
@ -70,8 +71,10 @@ class EnableBackupDialog extends StatelessWidget {
|
|||
),
|
||||
Expanded(
|
||||
child: PrimaryButton(
|
||||
desktopMed: true,
|
||||
label: "Continue",
|
||||
onPressed: () {
|
||||
Navigator.of(context).pop();
|
||||
createAutoBackup();
|
||||
},
|
||||
),
|
||||
|
|
|
@ -1,12 +1,20 @@
|
|||
import 'dart:async';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/src/widgets/framework.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_svg/svg.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/backup_and_restore/enable_backup_dialog.dart';
|
||||
import 'package:stackwallet/notifications/show_flush_bar.dart';
|
||||
import 'package:stackwallet/providers/desktop/storage_crypto_handler_provider.dart';
|
||||
import 'package:stackwallet/utilities/assets.dart';
|
||||
import 'package:stackwallet/utilities/constants.dart';
|
||||
import 'package:stackwallet/utilities/enums/flush_bar_type.dart';
|
||||
import 'package:stackwallet/utilities/text_styles.dart';
|
||||
import 'package:stackwallet/utilities/theme/stack_colors.dart';
|
||||
import 'package:stackwallet/widgets/desktop/primary_button.dart';
|
||||
import 'package:stackwallet/widgets/progress_bar.dart';
|
||||
import 'package:stackwallet/widgets/rounded_white_container.dart';
|
||||
import 'package:stackwallet/widgets/stack_text_field.dart';
|
||||
import 'package:zxcvbn/zxcvbn.dart';
|
||||
|
||||
class SecuritySettings extends ConsumerStatefulWidget {
|
||||
const SecuritySettings({Key? key}) : super(key: key);
|
||||
|
@ -18,21 +26,112 @@ class SecuritySettings extends ConsumerStatefulWidget {
|
|||
}
|
||||
|
||||
class _SecuritySettings extends ConsumerState<SecuritySettings> {
|
||||
Future<void> enableAutoBackup() async {
|
||||
// wait for keyboard to disappear
|
||||
FocusScope.of(context).unfocus();
|
||||
await Future<void>.delayed(
|
||||
const Duration(milliseconds: 100),
|
||||
);
|
||||
late bool changePassword = false;
|
||||
|
||||
await showDialog<dynamic>(
|
||||
context: context,
|
||||
useSafeArea: false,
|
||||
barrierDismissible: true,
|
||||
builder: (context) {
|
||||
return EnableBackupDialog();
|
||||
},
|
||||
);
|
||||
late final TextEditingController passwordCurrentController;
|
||||
late final TextEditingController passwordController;
|
||||
late final TextEditingController passwordRepeatController;
|
||||
|
||||
late final FocusNode passwordCurrentFocusNode;
|
||||
late final FocusNode passwordFocusNode;
|
||||
late final FocusNode passwordRepeatFocusNode;
|
||||
final zxcvbn = Zxcvbn();
|
||||
|
||||
bool hidePassword = true;
|
||||
bool shouldShowPasswordHint = true;
|
||||
|
||||
double passwordStrength = 0.0;
|
||||
|
||||
bool get shouldEnableSave {
|
||||
return passwordCurrentController.text.isNotEmpty &&
|
||||
passwordController.text.isNotEmpty &&
|
||||
passwordRepeatController.text.isNotEmpty;
|
||||
}
|
||||
|
||||
String passwordFeedback =
|
||||
"Add another word or two. Uncommon words are better. Use a few words, avoid common phrases. No need for symbols, digits, or uppercase letters.";
|
||||
|
||||
Future<bool> attemptChangePW() async {
|
||||
final String pw = passwordCurrentController.text;
|
||||
final String pwNew = passwordController.text;
|
||||
final String pwNewRepeat = passwordRepeatController.text;
|
||||
|
||||
final verified =
|
||||
await ref.read(storageCryptoHandlerProvider).verifyPassphrase(pw);
|
||||
|
||||
if (verified) {
|
||||
if (pwNew != pwNewRepeat) {
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "New passphrase does not match!",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
return false;
|
||||
} else {
|
||||
final success =
|
||||
await ref.read(storageCryptoHandlerProvider).changePassphrase(
|
||||
pw,
|
||||
pwNew,
|
||||
);
|
||||
|
||||
if (success) {
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.success,
|
||||
message: "Passphrase successfully changed",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
return true;
|
||||
} else {
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Passphrase change failed",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
unawaited(
|
||||
showFloatingFlushBar(
|
||||
type: FlushBarType.warning,
|
||||
message: "Current passphrase is not valid!",
|
||||
context: context,
|
||||
),
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
passwordCurrentController = TextEditingController();
|
||||
passwordController = TextEditingController();
|
||||
passwordRepeatController = TextEditingController();
|
||||
|
||||
passwordCurrentFocusNode = FocusNode();
|
||||
passwordFocusNode = FocusNode();
|
||||
passwordRepeatFocusNode = FocusNode();
|
||||
|
||||
super.initState();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
passwordCurrentController.dispose();
|
||||
passwordController.dispose();
|
||||
passwordRepeatController.dispose();
|
||||
|
||||
passwordCurrentFocusNode.dispose();
|
||||
passwordFocusNode.dispose();
|
||||
passwordRepeatFocusNode.dispose();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -40,104 +139,394 @@ class _SecuritySettings extends ConsumerState<SecuritySettings> {
|
|||
debugPrint("BUILD: $runtimeType");
|
||||
return Column(
|
||||
children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
right: 30,
|
||||
),
|
||||
child: RoundedWhiteContainer(
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.svg.circleLock,
|
||||
width: 48,
|
||||
height: 48,
|
||||
),
|
||||
Center(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(10),
|
||||
child: RichText(
|
||||
textAlign: TextAlign.start,
|
||||
text: TextSpan(
|
||||
children: [
|
||||
TextSpan(
|
||||
text: "Change Password",
|
||||
style: STextStyles.desktopTextSmall(context),
|
||||
),
|
||||
TextSpan(
|
||||
text:
|
||||
"\n\nProtect your Stack Wallet with a strong password. Stack Wallet does not store "
|
||||
"your password, and is therefore NOT able to restore it. Keep your password safe and secure.",
|
||||
style:
|
||||
STextStyles.desktopTextExtraExtraSmall(context),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
Column(
|
||||
Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: RoundedWhiteContainer(
|
||||
radiusMultiplier: 2,
|
||||
padding: const EdgeInsets.all(24),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: const [
|
||||
Padding(
|
||||
padding: EdgeInsets.all(
|
||||
10,
|
||||
),
|
||||
child: NewPasswordButton(),
|
||||
children: [
|
||||
SvgPicture.asset(
|
||||
Assets.svg.circleLock,
|
||||
width: 48,
|
||||
height: 48,
|
||||
),
|
||||
Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Text(
|
||||
"Change Password",
|
||||
style: STextStyles.desktopTextSmall(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 8,
|
||||
),
|
||||
Text(
|
||||
"Protect your Stack Wallet with a strong password. Stack Wallet does not store "
|
||||
"your password, and is therefore NOT able to restore it. Keep your password safe and secure.",
|
||||
style:
|
||||
STextStyles.desktopTextExtraExtraSmall(context),
|
||||
),
|
||||
const SizedBox(
|
||||
height: 20,
|
||||
),
|
||||
changePassword
|
||||
? SizedBox(
|
||||
width: 512,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
"Current password",
|
||||
style: STextStyles
|
||||
.desktopTextExtraExtraSmall(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark3),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
key: const Key(
|
||||
"desktopSecurityRestoreFromFilePasswordFieldKey"),
|
||||
focusNode: passwordCurrentFocusNode,
|
||||
controller: passwordCurrentController,
|
||||
style: STextStyles.field(context),
|
||||
obscureText: hidePassword,
|
||||
enableSuggestions: false,
|
||||
autocorrect: false,
|
||||
decoration: standardInputDecoration(
|
||||
"Enter current password",
|
||||
passwordCurrentFocusNode,
|
||||
context,
|
||||
).copyWith(
|
||||
labelStyle:
|
||||
STextStyles.fieldLabel(context),
|
||||
suffixIcon: UnconstrainedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
GestureDetector(
|
||||
key: const Key(
|
||||
"desktopSecurityRestoreFromFilePasswordFieldShowPasswordButtonKey"),
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
hidePassword =
|
||||
!hidePassword;
|
||||
});
|
||||
},
|
||||
child: SvgPicture.asset(
|
||||
hidePassword
|
||||
? Assets.svg.eye
|
||||
: Assets.svg.eyeSlash,
|
||||
color: Theme.of(context)
|
||||
.extension<
|
||||
StackColors>()!
|
||||
.textDark3,
|
||||
width: 16,
|
||||
height: 16,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
onChanged: (newValue) {
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
"New password",
|
||||
style: STextStyles
|
||||
.desktopTextExtraExtraSmall(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark3),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
key: const Key(
|
||||
"desktopSecurityCreateNewPasswordFieldKey1"),
|
||||
focusNode: passwordFocusNode,
|
||||
controller: passwordController,
|
||||
style: STextStyles.field(context),
|
||||
obscureText: hidePassword,
|
||||
enableSuggestions: false,
|
||||
autocorrect: false,
|
||||
decoration: standardInputDecoration(
|
||||
"Enter new password",
|
||||
passwordFocusNode,
|
||||
context,
|
||||
).copyWith(
|
||||
labelStyle:
|
||||
STextStyles.fieldLabel(context),
|
||||
suffixIcon: UnconstrainedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
GestureDetector(
|
||||
key: const Key(
|
||||
"desktopSecurityCreateNewPasswordButtonKey1"),
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
hidePassword =
|
||||
!hidePassword;
|
||||
});
|
||||
},
|
||||
child: SvgPicture.asset(
|
||||
hidePassword
|
||||
? Assets.svg.eye
|
||||
: Assets.svg.eyeSlash,
|
||||
color: Theme.of(context)
|
||||
.extension<
|
||||
StackColors>()!
|
||||
.textDark3,
|
||||
width: 16,
|
||||
height: 16,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
onChanged: (newValue) {
|
||||
if (newValue.isEmpty) {
|
||||
setState(() {
|
||||
passwordFeedback = "";
|
||||
});
|
||||
return;
|
||||
}
|
||||
final result =
|
||||
zxcvbn.evaluate(newValue);
|
||||
String suggestionsAndTips = "";
|
||||
for (var sug in result
|
||||
.feedback.suggestions!
|
||||
.toSet()) {
|
||||
suggestionsAndTips += "$sug\n";
|
||||
}
|
||||
suggestionsAndTips +=
|
||||
result.feedback.warning!;
|
||||
String feedback =
|
||||
// "Password Strength: ${((result.score! / 4.0) * 100).toInt()}%\n"
|
||||
suggestionsAndTips;
|
||||
|
||||
passwordStrength = result.score! / 4;
|
||||
|
||||
// hack fix to format back string returned from zxcvbn
|
||||
if (feedback
|
||||
.contains("phrasesNo need")) {
|
||||
feedback = feedback.replaceFirst(
|
||||
"phrasesNo need",
|
||||
"phrases\nNo need");
|
||||
}
|
||||
|
||||
if (feedback.endsWith("\n")) {
|
||||
feedback = feedback.substring(
|
||||
0, feedback.length - 2);
|
||||
}
|
||||
|
||||
setState(() {
|
||||
passwordFeedback = feedback;
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
if (passwordFocusNode.hasFocus ||
|
||||
passwordRepeatFocusNode.hasFocus ||
|
||||
passwordController.text.isNotEmpty)
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 12,
|
||||
right: 12,
|
||||
top: passwordFeedback.isNotEmpty
|
||||
? 4
|
||||
: 0,
|
||||
),
|
||||
child: passwordFeedback.isNotEmpty
|
||||
? Text(
|
||||
passwordFeedback,
|
||||
style: STextStyles.infoSmall(
|
||||
context),
|
||||
)
|
||||
: null,
|
||||
),
|
||||
if (passwordFocusNode.hasFocus ||
|
||||
passwordRepeatFocusNode.hasFocus ||
|
||||
passwordController.text.isNotEmpty)
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: 12,
|
||||
right: 12,
|
||||
top: 10,
|
||||
),
|
||||
child: ProgressBar(
|
||||
key: const Key(
|
||||
"desktopSecurityCreateStackBackUpProgressBar"),
|
||||
width: 450,
|
||||
height: 5,
|
||||
fillColor: passwordStrength < 0.51
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorRed
|
||||
: passwordStrength < 1
|
||||
? Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorYellow
|
||||
: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.accentColorGreen,
|
||||
backgroundColor: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.buttonBackSecondary,
|
||||
percent: passwordStrength < 0.25
|
||||
? 0.03
|
||||
: passwordStrength,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 16),
|
||||
Text(
|
||||
"Confirm new password",
|
||||
style: STextStyles
|
||||
.desktopTextExtraExtraSmall(
|
||||
context)
|
||||
.copyWith(
|
||||
color: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.textDark3),
|
||||
textAlign: TextAlign.left,
|
||||
),
|
||||
const SizedBox(height: 10),
|
||||
ClipRRect(
|
||||
borderRadius: BorderRadius.circular(
|
||||
Constants.size.circularBorderRadius,
|
||||
),
|
||||
child: TextField(
|
||||
key: const Key(
|
||||
"desktopSecurityCreateNewPasswordFieldKey2"),
|
||||
focusNode: passwordRepeatFocusNode,
|
||||
controller: passwordRepeatController,
|
||||
style: STextStyles.field(context),
|
||||
obscureText: hidePassword,
|
||||
enableSuggestions: false,
|
||||
autocorrect: false,
|
||||
decoration: standardInputDecoration(
|
||||
"Confirm new password",
|
||||
passwordRepeatFocusNode,
|
||||
context,
|
||||
).copyWith(
|
||||
labelStyle:
|
||||
STextStyles.fieldLabel(context),
|
||||
suffixIcon: UnconstrainedBox(
|
||||
child: Row(
|
||||
children: [
|
||||
const SizedBox(
|
||||
width: 16,
|
||||
),
|
||||
GestureDetector(
|
||||
key: const Key(
|
||||
"desktopSecurityCreateNewPasswordButtonKey2"),
|
||||
onTap: () async {
|
||||
setState(() {
|
||||
hidePassword =
|
||||
!hidePassword;
|
||||
});
|
||||
},
|
||||
child: SvgPicture.asset(
|
||||
hidePassword
|
||||
? Assets.svg.eye
|
||||
: Assets.svg.eyeSlash,
|
||||
color: Theme.of(context)
|
||||
.extension<
|
||||
StackColors>()!
|
||||
.textDark3,
|
||||
width: 16,
|
||||
height: 16,
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 12,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
onChanged: (newValue) {
|
||||
setState(() {});
|
||||
},
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
PrimaryButton(
|
||||
width: 160,
|
||||
desktopMed: true,
|
||||
enabled: shouldEnableSave,
|
||||
label: "Save changes",
|
||||
onPressed: () async {
|
||||
final didChangePW =
|
||||
await attemptChangePW();
|
||||
if (didChangePW) {
|
||||
setState(() {
|
||||
changePassword = false;
|
||||
});
|
||||
}
|
||||
},
|
||||
)
|
||||
],
|
||||
),
|
||||
)
|
||||
: PrimaryButton(
|
||||
width: 210,
|
||||
desktopMed: true,
|
||||
enabled: true,
|
||||
label: "Set up new password",
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
changePassword = true;
|
||||
});
|
||||
},
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
const SizedBox(
|
||||
width: 40,
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class NewPasswordButton extends ConsumerWidget {
|
||||
const NewPasswordButton({
|
||||
Key? key,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context, WidgetRef ref) {
|
||||
return SizedBox(
|
||||
width: 200,
|
||||
height: 48,
|
||||
child: TextButton(
|
||||
style: Theme.of(context)
|
||||
.extension<StackColors>()!
|
||||
.getPrimaryEnabledButtonColor(context),
|
||||
onPressed: () {
|
||||
// Expandable(
|
||||
// header: Row(
|
||||
// mainAxisAlignment: MainAxisAlignment.start,
|
||||
// children: [
|
||||
// NewPasswordButton(),
|
||||
// ],
|
||||
// ),
|
||||
// body: Column(
|
||||
// mainAxisAlignment: MainAxisAlignment.start,
|
||||
// children: [
|
||||
// Text(
|
||||
// "Current Password",
|
||||
// style: STextStyles.desktopTextExtraSmall(context).copyWith(
|
||||
// color:
|
||||
// Theme.of(context).extension<StackColors>()!.textDark3,
|
||||
// ),
|
||||
// textAlign: TextAlign.left,
|
||||
// ),
|
||||
// ],
|
||||
// ),
|
||||
// );
|
||||
},
|
||||
child: Text(
|
||||
"Set up new password",
|
||||
style: STextStyles.button(context),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
5
lib/providers/desktop/current_desktop_menu_item.dart
Normal file
5
lib/providers/desktop/current_desktop_menu_item.dart
Normal file
|
@ -0,0 +1,5 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/desktop_menu.dart';
|
||||
|
||||
final currentDesktopMenuItemProvider =
|
||||
StateProvider<DesktopMenuItemId>((ref) => DesktopMenuItemId.myStack);
|
|
@ -1,5 +1,9 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
||||
import 'package:stackwallet/services/auto_swb_service.dart';
|
||||
|
||||
final autoSWBServiceProvider =
|
||||
ChangeNotifierProvider<AutoSWBService>((_) => AutoSWBService());
|
||||
final autoSWBServiceProvider = ChangeNotifierProvider<AutoSWBService>(
|
||||
(ref) => AutoSWBService(
|
||||
secureStorageInterface: ref.read(secureStoreProvider),
|
||||
),
|
||||
);
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
||||
import 'package:stackwallet/services/node_service.dart';
|
||||
|
||||
int _count = 0;
|
||||
final nodeServiceChangeNotifierProvider =
|
||||
ChangeNotifierProvider<NodeService>((_) {
|
||||
ChangeNotifierProvider<NodeService>((ref) {
|
||||
if (kDebugMode) {
|
||||
_count++;
|
||||
debugPrint(
|
||||
"nodeServiceChangeNotifierProvider instantiation count: $_count");
|
||||
}
|
||||
|
||||
return NodeService();
|
||||
return NodeService(secureStorageInterface: ref.read(secureStoreProvider));
|
||||
});
|
||||
|
|
18
lib/providers/global/secure_store_provider.dart
Normal file
18
lib/providers/global/secure_store_provider.dart
Normal file
|
@ -0,0 +1,18 @@
|
|||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:stackwallet/providers/desktop/storage_crypto_handler_provider.dart';
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
||||
final secureStoreProvider = Provider<SecureStorageInterface>((ref) {
|
||||
if (Util.isDesktop) {
|
||||
final handler = ref.read(storageCryptoHandlerProvider).handler;
|
||||
return SecureStorageWrapper(
|
||||
store: DesktopSecureStore(handler), isDesktop: true);
|
||||
} else {
|
||||
return const SecureStorageWrapper(
|
||||
store: FlutterSecureStorage(),
|
||||
isDesktop: false,
|
||||
);
|
||||
}
|
||||
});
|
|
@ -1,16 +1,19 @@
|
|||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:stackwallet/providers/global/secure_store_provider.dart';
|
||||
import 'package:stackwallet/services/wallets_service.dart';
|
||||
|
||||
int _count = 0;
|
||||
|
||||
final walletsServiceChangeNotifierProvider =
|
||||
ChangeNotifierProvider<WalletsService>((_) {
|
||||
ChangeNotifierProvider<WalletsService>((ref) {
|
||||
if (kDebugMode) {
|
||||
_count++;
|
||||
debugPrint(
|
||||
"walletsServiceChangeNotifierProvider instantiation count: $_count");
|
||||
}
|
||||
|
||||
return WalletsService();
|
||||
return WalletsService(
|
||||
secureStorageInterface: ref.read(secureStoreProvider),
|
||||
);
|
||||
});
|
||||
|
|
|
@ -93,6 +93,7 @@ import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/my_stack_v
|
|||
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/desktop_wallet_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/qr_code_desktop_popup_content.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/my_stack_view/wallet_view/sub_widgets/wallet_keys_desktop_popup.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/notifications/desktop_notifications_view.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/advanced_settings/advanced_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/appearance_settings.dart';
|
||||
import 'package:stackwallet/pages_desktop_specific/home/settings_menu/backup_and_restore/backup_and_restore_settings.dart';
|
||||
|
@ -1012,6 +1013,12 @@ class RouteGenerator {
|
|||
builder: (_) => const DesktopHomeView(),
|
||||
settings: RouteSettings(name: settings.name));
|
||||
|
||||
case DesktopNotificationsView.routeName:
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
builder: (_) => const DesktopNotificationsView(),
|
||||
settings: RouteSettings(name: settings.name));
|
||||
|
||||
case DesktopSettingsView.routeName:
|
||||
return getRoute(
|
||||
shouldUseMaterialRoute: useMaterialPageRoute,
|
||||
|
|
|
@ -3,7 +3,6 @@ import 'dart:convert';
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:stackwallet/pages/settings_views/global_settings_view/stack_backup_views/helpers/restore_create_backup.dart';
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
@ -25,11 +24,9 @@ class AutoSWBService extends ChangeNotifier {
|
|||
bool _isActiveTimer = false;
|
||||
bool get isActivePeriodicTimer => _isActiveTimer;
|
||||
|
||||
final FlutterSecureStorageInterface secureStorageInterface;
|
||||
final SecureStorageInterface secureStorageInterface;
|
||||
|
||||
AutoSWBService(
|
||||
{this.secureStorageInterface =
|
||||
const SecureStorageWrapper(FlutterSecureStorage())});
|
||||
AutoSWBService({required this.secureStorageInterface});
|
||||
|
||||
/// Attempt a backup.
|
||||
Future<void> doBackup() async {
|
||||
|
|
|
@ -12,7 +12,6 @@ import 'package:crypto/crypto.dart';
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:devicelocale/devicelocale.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||
|
@ -1357,7 +1356,7 @@ class BitcoinWallet extends CoinServiceAPI {
|
|||
|
||||
CachedElectrumX get cachedElectrumXClient => _cachedElectrumXClient;
|
||||
|
||||
late FlutterSecureStorageInterface _secureStore;
|
||||
late SecureStorageInterface _secureStore;
|
||||
|
||||
late PriceAPI _priceAPI;
|
||||
|
||||
|
@ -1369,7 +1368,7 @@ class BitcoinWallet extends CoinServiceAPI {
|
|||
required CachedElectrumX cachedClient,
|
||||
required TransactionNotificationTracker tracker,
|
||||
PriceAPI? priceAPI,
|
||||
FlutterSecureStorageInterface? secureStore,
|
||||
required SecureStorageInterface secureStore,
|
||||
}) {
|
||||
txTracker = tracker;
|
||||
_walletId = walletId;
|
||||
|
@ -1379,13 +1378,12 @@ class BitcoinWallet extends CoinServiceAPI {
|
|||
_cachedElectrumXClient = cachedClient;
|
||||
|
||||
_priceAPI = priceAPI ?? PriceAPI(Client());
|
||||
_secureStore =
|
||||
secureStore ?? const SecureStorageWrapper(FlutterSecureStorage());
|
||||
_secureStore = secureStore;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateNode(bool shouldRefresh) async {
|
||||
final failovers = NodeService()
|
||||
final failovers = NodeService(secureStorageInterface: _secureStore)
|
||||
.failoverNodesFor(coin: coin)
|
||||
.map((e) => ElectrumXNode(
|
||||
address: e.host,
|
||||
|
@ -1423,7 +1421,8 @@ class BitcoinWallet extends CoinServiceAPI {
|
|||
}
|
||||
|
||||
Future<ElectrumXNode> getCurrentNode() async {
|
||||
final node = NodeService().getPrimaryNodeFor(coin: coin) ??
|
||||
final node = NodeService(secureStorageInterface: _secureStore)
|
||||
.getPrimaryNodeFor(coin: coin) ??
|
||||
DefaultNodes.getNodeFor(coin);
|
||||
|
||||
return ElectrumXNode(
|
||||
|
|
|
@ -13,7 +13,6 @@ import 'package:crypto/crypto.dart';
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:devicelocale/devicelocale.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||
|
@ -1262,7 +1261,7 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
|
||||
CachedElectrumX get cachedElectrumXClient => _cachedElectrumXClient;
|
||||
|
||||
late FlutterSecureStorageInterface _secureStore;
|
||||
late SecureStorageInterface _secureStore;
|
||||
|
||||
late PriceAPI _priceAPI;
|
||||
|
||||
|
@ -1274,7 +1273,7 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
required CachedElectrumX cachedClient,
|
||||
required TransactionNotificationTracker tracker,
|
||||
PriceAPI? priceAPI,
|
||||
FlutterSecureStorageInterface? secureStore,
|
||||
required SecureStorageInterface secureStore,
|
||||
}) {
|
||||
txTracker = tracker;
|
||||
_walletId = walletId;
|
||||
|
@ -1284,13 +1283,12 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
_cachedElectrumXClient = cachedClient;
|
||||
|
||||
_priceAPI = priceAPI ?? PriceAPI(Client());
|
||||
_secureStore =
|
||||
secureStore ?? const SecureStorageWrapper(FlutterSecureStorage());
|
||||
_secureStore = secureStore;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateNode(bool shouldRefresh) async {
|
||||
final failovers = NodeService()
|
||||
final failovers = NodeService(secureStorageInterface: _secureStore)
|
||||
.failoverNodesFor(coin: coin)
|
||||
.map((e) => ElectrumXNode(
|
||||
address: e.host,
|
||||
|
@ -1328,7 +1326,8 @@ class BitcoinCashWallet extends CoinServiceAPI {
|
|||
}
|
||||
|
||||
Future<ElectrumXNode> getCurrentNode() async {
|
||||
final node = NodeService().getPrimaryNodeFor(coin: coin) ??
|
||||
final node = NodeService(secureStorageInterface: _secureStore)
|
||||
.getPrimaryNodeFor(coin: coin) ??
|
||||
DefaultNodes.getNodeFor(coin);
|
||||
|
||||
return ElectrumXNode(
|
||||
|
|
|
@ -13,6 +13,7 @@ import 'package:stackwallet/services/coins/namecoin/namecoin_wallet.dart';
|
|||
import 'package:stackwallet/services/coins/wownero/wownero_wallet.dart';
|
||||
import 'package:stackwallet/services/transaction_notification_tracker.dart';
|
||||
import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
|
||||
import 'litecoin/litecoin_wallet.dart';
|
||||
|
@ -24,6 +25,7 @@ abstract class CoinServiceAPI {
|
|||
Coin coin,
|
||||
String walletId,
|
||||
String walletName,
|
||||
SecureStorageInterface secureStorageInterface,
|
||||
NodeModel node,
|
||||
TransactionNotificationTracker tracker,
|
||||
Prefs prefs,
|
||||
|
@ -68,6 +70,7 @@ abstract class CoinServiceAPI {
|
|||
walletId: walletId,
|
||||
walletName: walletName,
|
||||
coin: coin,
|
||||
secureStore: secureStorageInterface,
|
||||
client: client,
|
||||
cachedClient: cachedClient,
|
||||
tracker: tracker,
|
||||
|
@ -77,6 +80,7 @@ abstract class CoinServiceAPI {
|
|||
walletId: walletId,
|
||||
walletName: walletName,
|
||||
coin: coin,
|
||||
secureStore: secureStorageInterface,
|
||||
client: client,
|
||||
cachedClient: cachedClient,
|
||||
tracker: tracker,
|
||||
|
@ -87,6 +91,7 @@ abstract class CoinServiceAPI {
|
|||
walletId: walletId,
|
||||
walletName: walletName,
|
||||
coin: coin,
|
||||
secureStore: secureStorageInterface,
|
||||
client: client,
|
||||
cachedClient: cachedClient,
|
||||
tracker: tracker,
|
||||
|
@ -97,6 +102,7 @@ abstract class CoinServiceAPI {
|
|||
walletId: walletId,
|
||||
walletName: walletName,
|
||||
coin: coin,
|
||||
secureStore: secureStorageInterface,
|
||||
client: client,
|
||||
cachedClient: cachedClient,
|
||||
tracker: tracker,
|
||||
|
@ -107,6 +113,7 @@ abstract class CoinServiceAPI {
|
|||
walletId: walletId,
|
||||
walletName: walletName,
|
||||
coin: coin,
|
||||
secureStore: secureStorageInterface,
|
||||
client: client,
|
||||
cachedClient: cachedClient,
|
||||
tracker: tracker,
|
||||
|
@ -117,6 +124,7 @@ abstract class CoinServiceAPI {
|
|||
walletId: walletId,
|
||||
walletName: walletName,
|
||||
coin: coin,
|
||||
secureStore: secureStorageInterface,
|
||||
client: client,
|
||||
cachedClient: cachedClient,
|
||||
tracker: tracker,
|
||||
|
@ -127,6 +135,7 @@ abstract class CoinServiceAPI {
|
|||
walletId: walletId,
|
||||
walletName: walletName,
|
||||
coin: coin,
|
||||
secureStore: secureStorageInterface,
|
||||
client: client,
|
||||
cachedClient: cachedClient,
|
||||
tracker: tracker,
|
||||
|
@ -137,6 +146,7 @@ abstract class CoinServiceAPI {
|
|||
walletId: walletId,
|
||||
walletName: walletName,
|
||||
coin: coin,
|
||||
secureStore: secureStorageInterface,
|
||||
client: client,
|
||||
cachedClient: cachedClient,
|
||||
tracker: tracker,
|
||||
|
@ -147,6 +157,7 @@ abstract class CoinServiceAPI {
|
|||
walletId: walletId,
|
||||
walletName: walletName,
|
||||
coin: coin,
|
||||
secureStore: secureStorageInterface,
|
||||
client: client,
|
||||
cachedClient: cachedClient,
|
||||
tracker: tracker,
|
||||
|
@ -157,6 +168,7 @@ abstract class CoinServiceAPI {
|
|||
walletId: walletId,
|
||||
walletName: walletName,
|
||||
coin: coin,
|
||||
secureStore: secureStorageInterface,
|
||||
// tracker: tracker,
|
||||
);
|
||||
|
||||
|
@ -165,6 +177,7 @@ abstract class CoinServiceAPI {
|
|||
walletId: walletId,
|
||||
walletName: walletName,
|
||||
coin: coin,
|
||||
secureStore: secureStorageInterface,
|
||||
// tracker: tracker,
|
||||
);
|
||||
|
||||
|
@ -173,6 +186,7 @@ abstract class CoinServiceAPI {
|
|||
walletId: walletId,
|
||||
walletName: walletName,
|
||||
coin: coin,
|
||||
secureStore: secureStorageInterface,
|
||||
// tracker: tracker,
|
||||
);
|
||||
|
||||
|
@ -181,6 +195,7 @@ abstract class CoinServiceAPI {
|
|||
walletId: walletId,
|
||||
walletName: walletName,
|
||||
coin: coin,
|
||||
secureStore: secureStorageInterface,
|
||||
tracker: tracker,
|
||||
cachedClient: cachedClient,
|
||||
client: client,
|
||||
|
@ -191,6 +206,7 @@ abstract class CoinServiceAPI {
|
|||
walletId: walletId,
|
||||
walletName: walletName,
|
||||
coin: coin,
|
||||
secureStore: secureStorageInterface,
|
||||
client: client,
|
||||
cachedClient: cachedClient,
|
||||
tracker: tracker,
|
||||
|
|
|
@ -12,7 +12,6 @@ import 'package:crypto/crypto.dart';
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:devicelocale/devicelocale.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||
|
@ -1125,7 +1124,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
|
||||
CachedElectrumX get cachedElectrumXClient => _cachedElectrumXClient;
|
||||
|
||||
late FlutterSecureStorageInterface _secureStore;
|
||||
late SecureStorageInterface _secureStore;
|
||||
|
||||
late PriceAPI _priceAPI;
|
||||
|
||||
|
@ -1137,7 +1136,7 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
required CachedElectrumX cachedClient,
|
||||
required TransactionNotificationTracker tracker,
|
||||
PriceAPI? priceAPI,
|
||||
FlutterSecureStorageInterface? secureStore,
|
||||
required SecureStorageInterface secureStore,
|
||||
}) {
|
||||
txTracker = tracker;
|
||||
_walletId = walletId;
|
||||
|
@ -1147,13 +1146,12 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
_cachedElectrumXClient = cachedClient;
|
||||
|
||||
_priceAPI = priceAPI ?? PriceAPI(Client());
|
||||
_secureStore =
|
||||
secureStore ?? const SecureStorageWrapper(FlutterSecureStorage());
|
||||
_secureStore = secureStore;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateNode(bool shouldRefresh) async {
|
||||
final failovers = NodeService()
|
||||
final failovers = NodeService(secureStorageInterface: _secureStore)
|
||||
.failoverNodesFor(coin: coin)
|
||||
.map((e) => ElectrumXNode(
|
||||
address: e.host,
|
||||
|
@ -1191,7 +1189,8 @@ class DogecoinWallet extends CoinServiceAPI {
|
|||
}
|
||||
|
||||
Future<ElectrumXNode> getCurrentNode() async {
|
||||
final node = NodeService().getPrimaryNodeFor(coin: coin) ??
|
||||
final node = NodeService(secureStorageInterface: _secureStore)
|
||||
.getPrimaryNodeFor(coin: coin) ??
|
||||
DefaultNodes.getNodeFor(coin);
|
||||
|
||||
return ElectrumXNode(
|
||||
|
|
|
@ -6,11 +6,9 @@ import 'dart:isolate';
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_libepiccash/epic_cash.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:mutex/mutex.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:stack_wallet_backup/generate_password.dart';
|
||||
import 'package:stackwallet/hive/db.dart';
|
||||
import 'package:stackwallet/models/node_model.dart';
|
||||
|
@ -32,6 +30,7 @@ import 'package:stackwallet/utilities/enums/coin_enum.dart';
|
|||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
import 'package:stackwallet/utilities/stack_file_system.dart';
|
||||
import 'package:stackwallet/utilities/test_epic_box_connection.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
|
@ -251,26 +250,29 @@ Future<String> _deleteWalletWrapper(String wallet) async {
|
|||
|
||||
Future<String> deleteEpicWallet({
|
||||
required String walletId,
|
||||
required FlutterSecureStorageInterface secureStore,
|
||||
required SecureStorageInterface secureStore,
|
||||
}) async {
|
||||
String? config = await secureStore.read(key: '${walletId}_config');
|
||||
if (Platform.isIOS) {
|
||||
Directory appDir = (await getApplicationDocumentsDirectory());
|
||||
if (Platform.isIOS) {
|
||||
appDir = (await getLibraryDirectory());
|
||||
}
|
||||
if (Platform.isLinux) {
|
||||
appDir = Directory("${appDir.path}/.stackwallet");
|
||||
}
|
||||
final path = "${appDir.path}/epiccash";
|
||||
final String name = walletId;
|
||||
|
||||
final walletDir = '$path/$name';
|
||||
var editConfig = jsonDecode(config as String);
|
||||
|
||||
editConfig["wallet_dir"] = walletDir;
|
||||
config = jsonEncode(editConfig);
|
||||
}
|
||||
// is this even needed for anything?
|
||||
// String? config = await secureStore.read(key: '${walletId}_config');
|
||||
// // TODO: why double check for iOS?
|
||||
// if (Platform.isIOS) {
|
||||
// Directory appDir = await StackFileSystem.applicationRootDirectory();
|
||||
// // todo why double check for ios?
|
||||
// // if (Platform.isIOS) {
|
||||
// // appDir = (await getLibraryDirectory());
|
||||
// // }
|
||||
// // if (Platform.isLinux) {
|
||||
// // appDir = Directory("${appDir.path}/.stackwallet");
|
||||
// // }
|
||||
// final path = "${appDir.path}/epiccash";
|
||||
// final String name = walletId;
|
||||
//
|
||||
// final walletDir = '$path/$name';
|
||||
// var editConfig = jsonDecode(config as String);
|
||||
//
|
||||
// editConfig["wallet_dir"] = walletDir;
|
||||
// config = jsonEncode(editConfig);
|
||||
// }
|
||||
|
||||
final wallet = await secureStore.read(key: '${walletId}_wallet');
|
||||
|
||||
|
@ -518,14 +520,13 @@ class EpicCashWallet extends CoinServiceAPI {
|
|||
required String walletName,
|
||||
required Coin coin,
|
||||
PriceAPI? priceAPI,
|
||||
FlutterSecureStorageInterface? secureStore}) {
|
||||
required SecureStorageInterface secureStore}) {
|
||||
_walletId = walletId;
|
||||
_walletName = walletName;
|
||||
_coin = coin;
|
||||
|
||||
_priceAPI = priceAPI ?? PriceAPI(Client());
|
||||
_secureStore =
|
||||
secureStore ?? const SecureStorageWrapper(FlutterSecureStorage());
|
||||
_secureStore = secureStore;
|
||||
|
||||
Logging.instance.log("$walletName isolate length: ${isolates.length}",
|
||||
level: LogLevel.Info);
|
||||
|
@ -537,7 +538,8 @@ class EpicCashWallet extends CoinServiceAPI {
|
|||
|
||||
@override
|
||||
Future<void> updateNode(bool shouldRefresh) async {
|
||||
_epicNode = NodeService().getPrimaryNodeFor(coin: coin) ??
|
||||
_epicNode = NodeService(secureStorageInterface: _secureStore)
|
||||
.getPrimaryNodeFor(coin: coin) ??
|
||||
DefaultNodes.getNodeFor(coin);
|
||||
// TODO notify ui/ fire event for node changed?
|
||||
|
||||
|
@ -659,7 +661,7 @@ class EpicCashWallet extends CoinServiceAPI {
|
|||
@override
|
||||
Coin get coin => _coin;
|
||||
|
||||
late FlutterSecureStorageInterface _secureStore;
|
||||
late SecureStorageInterface _secureStore;
|
||||
|
||||
late PriceAPI _priceAPI;
|
||||
|
||||
|
@ -1238,13 +1240,8 @@ class EpicCashWallet extends CoinServiceAPI {
|
|||
}
|
||||
|
||||
Future<String> currentWalletDirPath() async {
|
||||
Directory appDir = (await getApplicationDocumentsDirectory());
|
||||
if (Platform.isIOS) {
|
||||
appDir = (await getLibraryDirectory());
|
||||
}
|
||||
if (Platform.isLinux) {
|
||||
appDir = Directory("${appDir.path}/.stackwallet");
|
||||
}
|
||||
Directory appDir = await StackFileSystem.applicationRootDirectory();
|
||||
|
||||
final path = "${appDir.path}/epiccash";
|
||||
final String name = _walletId.trim();
|
||||
return '$path/$name';
|
||||
|
|
|
@ -11,7 +11,6 @@ import 'package:bitcoindart/bitcoindart.dart';
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:devicelocale/devicelocale.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:lelantus/lelantus.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
|
||||
|
@ -1306,7 +1305,7 @@ class FiroWallet extends CoinServiceAPI {
|
|||
late CachedElectrumX _cachedElectrumXClient;
|
||||
CachedElectrumX get cachedElectrumXClient => _cachedElectrumXClient;
|
||||
|
||||
late FlutterSecureStorageInterface _secureStore;
|
||||
late SecureStorageInterface _secureStore;
|
||||
|
||||
late PriceAPI _priceAPI;
|
||||
|
||||
|
@ -1321,7 +1320,7 @@ class FiroWallet extends CoinServiceAPI {
|
|||
required CachedElectrumX cachedClient,
|
||||
required TransactionNotificationTracker tracker,
|
||||
PriceAPI? priceAPI,
|
||||
FlutterSecureStorageInterface? secureStore,
|
||||
required SecureStorageInterface secureStore,
|
||||
}) {
|
||||
txTracker = tracker;
|
||||
_walletId = walletId;
|
||||
|
@ -1331,8 +1330,7 @@ class FiroWallet extends CoinServiceAPI {
|
|||
_cachedElectrumXClient = cachedClient;
|
||||
|
||||
_priceAPI = priceAPI ?? PriceAPI(Client());
|
||||
_secureStore =
|
||||
secureStore ?? const SecureStorageWrapper(FlutterSecureStorage());
|
||||
_secureStore = secureStore;
|
||||
|
||||
Logging.instance.log("$walletName isolates length: ${isolates.length}",
|
||||
level: LogLevel.Info);
|
||||
|
@ -1870,7 +1868,7 @@ class FiroWallet extends CoinServiceAPI {
|
|||
|
||||
@override
|
||||
Future<void> updateNode(bool shouldRefresh) async {
|
||||
final failovers = NodeService()
|
||||
final failovers = NodeService(secureStorageInterface: _secureStore)
|
||||
.failoverNodesFor(coin: coin)
|
||||
.map(
|
||||
(e) => ElectrumXNode(
|
||||
|
@ -3071,7 +3069,8 @@ class FiroWallet extends CoinServiceAPI {
|
|||
}
|
||||
|
||||
Future<ElectrumXNode> _getCurrentNode() async {
|
||||
final node = NodeService().getPrimaryNodeFor(coin: coin) ??
|
||||
final node = NodeService(secureStorageInterface: _secureStore)
|
||||
.getPrimaryNodeFor(coin: coin) ??
|
||||
DefaultNodes.getNodeFor(coin);
|
||||
|
||||
return ElectrumXNode(
|
||||
|
|
|
@ -12,7 +12,6 @@ import 'package:crypto/crypto.dart';
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:devicelocale/devicelocale.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||
|
@ -1359,7 +1358,7 @@ class LitecoinWallet extends CoinServiceAPI {
|
|||
|
||||
CachedElectrumX get cachedElectrumXClient => _cachedElectrumXClient;
|
||||
|
||||
late FlutterSecureStorageInterface _secureStore;
|
||||
late SecureStorageInterface _secureStore;
|
||||
|
||||
late PriceAPI _priceAPI;
|
||||
|
||||
|
@ -1371,7 +1370,7 @@ class LitecoinWallet extends CoinServiceAPI {
|
|||
required CachedElectrumX cachedClient,
|
||||
required TransactionNotificationTracker tracker,
|
||||
PriceAPI? priceAPI,
|
||||
FlutterSecureStorageInterface? secureStore,
|
||||
required SecureStorageInterface secureStore,
|
||||
}) {
|
||||
txTracker = tracker;
|
||||
_walletId = walletId;
|
||||
|
@ -1381,13 +1380,12 @@ class LitecoinWallet extends CoinServiceAPI {
|
|||
_cachedElectrumXClient = cachedClient;
|
||||
|
||||
_priceAPI = priceAPI ?? PriceAPI(Client());
|
||||
_secureStore =
|
||||
secureStore ?? const SecureStorageWrapper(FlutterSecureStorage());
|
||||
_secureStore = secureStore;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateNode(bool shouldRefresh) async {
|
||||
final failovers = NodeService()
|
||||
final failovers = NodeService(secureStorageInterface: _secureStore)
|
||||
.failoverNodesFor(coin: coin)
|
||||
.map((e) => ElectrumXNode(
|
||||
address: e.host,
|
||||
|
@ -1425,7 +1423,8 @@ class LitecoinWallet extends CoinServiceAPI {
|
|||
}
|
||||
|
||||
Future<ElectrumXNode> getCurrentNode() async {
|
||||
final node = NodeService().getPrimaryNodeFor(coin: coin) ??
|
||||
final node = NodeService(secureStorageInterface: _secureStore)
|
||||
.getPrimaryNodeFor(coin: coin) ??
|
||||
DefaultNodes.getNodeFor(coin);
|
||||
|
||||
return ElectrumXNode(
|
||||
|
|
|
@ -23,11 +23,8 @@ import 'package:flutter_libmonero/core/key_service.dart';
|
|||
import 'package:flutter_libmonero/core/wallet_creation_service.dart';
|
||||
import 'package:flutter_libmonero/monero/monero.dart';
|
||||
import 'package:flutter_libmonero/view_model/send/output.dart' as monero_output;
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:mutex/mutex.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:stackwallet/hive/db.dart';
|
||||
import 'package:stackwallet/models/node_model.dart';
|
||||
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
||||
|
@ -49,6 +46,7 @@ import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
|||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
import 'package:stackwallet/utilities/stack_file_system.dart';
|
||||
|
||||
const int MINIMUM_CONFIRMATIONS = 10;
|
||||
|
||||
|
@ -67,12 +65,13 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
Timer? moneroAutosaveTimer;
|
||||
late Coin _coin;
|
||||
|
||||
late FlutterSecureStorageInterface _secureStore;
|
||||
late SecureStorageInterface _secureStore;
|
||||
|
||||
late PriceAPI _priceAPI;
|
||||
|
||||
Future<NodeModel> getCurrentNode() async {
|
||||
return NodeService().getPrimaryNodeFor(coin: coin) ??
|
||||
return NodeService(secureStorageInterface: _secureStore)
|
||||
.getPrimaryNodeFor(coin: coin) ??
|
||||
DefaultNodes.getNodeFor(coin);
|
||||
}
|
||||
|
||||
|
@ -81,14 +80,13 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
required String walletName,
|
||||
required Coin coin,
|
||||
PriceAPI? priceAPI,
|
||||
FlutterSecureStorageInterface? secureStore}) {
|
||||
required SecureStorageInterface secureStore}) {
|
||||
_walletId = walletId;
|
||||
_walletName = walletName;
|
||||
_coin = coin;
|
||||
|
||||
_priceAPI = priceAPI ?? PriceAPI(Client());
|
||||
_secureStore =
|
||||
secureStore ?? const SecureStorageWrapper(FlutterSecureStorage());
|
||||
_secureStore = secureStore;
|
||||
}
|
||||
|
||||
bool _shouldAutoSync = false;
|
||||
|
@ -154,7 +152,7 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
try {
|
||||
_height = (walletBase!.syncStatus as SyncingSyncStatus).height;
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e $s", level: LogLevel.Warning);
|
||||
// Logging.instance.log("$e $s", level: LogLevel.Warning);
|
||||
}
|
||||
|
||||
int blocksRemaining = -1;
|
||||
|
@ -163,7 +161,7 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
blocksRemaining =
|
||||
(walletBase!.syncStatus as SyncingSyncStatus).blocksLeft;
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e $s", level: LogLevel.Warning);
|
||||
// Logging.instance.log("$e $s", level: LogLevel.Warning);
|
||||
}
|
||||
int currentHeight = _height + blocksRemaining;
|
||||
if (_height == -1 || blocksRemaining == -1) {
|
||||
|
@ -196,7 +194,7 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
try {
|
||||
syncingHeight = (walletBase!.syncStatus as SyncingSyncStatus).height;
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e $s", level: LogLevel.Warning);
|
||||
// Logging.instance.log("$e $s", level: LogLevel.Warning);
|
||||
}
|
||||
final cachedHeight =
|
||||
DB.instance.get<dynamic>(boxName: walletId, key: "storedSyncingHeight")
|
||||
|
@ -419,7 +417,7 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
try {
|
||||
progress = (walletBase!.syncStatus!).progress();
|
||||
} catch (e, s) {
|
||||
Logging.instance.log("$e $s", level: LogLevel.Warning);
|
||||
// Logging.instance.log("$e $s", level: LogLevel.Warning);
|
||||
}
|
||||
await _fetchTransactionData();
|
||||
|
||||
|
@ -670,11 +668,9 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
"Attempted to overwrite mnemonic on generate new wallet!");
|
||||
}
|
||||
|
||||
storage = const FlutterSecureStorage();
|
||||
walletService =
|
||||
monero.createMoneroWalletService(DB.instance.moneroWalletInfoBox);
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
keysStorage = KeyService(storage!);
|
||||
keysStorage = KeyService(_secureStore);
|
||||
WalletInfo walletInfo;
|
||||
WalletCredentials credentials;
|
||||
try {
|
||||
|
@ -708,8 +704,7 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
credentials.walletInfo = walletInfo;
|
||||
|
||||
_walletCreationService = WalletCreationService(
|
||||
secureStorage: storage,
|
||||
sharedPreferences: prefs,
|
||||
secureStorage: _secureStore,
|
||||
walletService: walletService,
|
||||
keyService: keysStorage,
|
||||
);
|
||||
|
@ -787,11 +782,10 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
// Logging.instance.log("Caught in initializeWallet(): $e\n$s");
|
||||
// return false;
|
||||
// }
|
||||
storage = const FlutterSecureStorage();
|
||||
|
||||
walletService =
|
||||
monero.createMoneroWalletService(DB.instance.moneroWalletInfoBox);
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
keysStorage = KeyService(storage!);
|
||||
keysStorage = KeyService(_secureStore);
|
||||
|
||||
await _generateNewWallet();
|
||||
// var password;
|
||||
|
@ -833,11 +827,9 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
"Attempted to initialize an existing wallet using an unknown wallet ID!");
|
||||
}
|
||||
|
||||
storage = const FlutterSecureStorage();
|
||||
walletService =
|
||||
monero.createMoneroWalletService(DB.instance.moneroWalletInfoBox);
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
keysStorage = KeyService(storage!);
|
||||
keysStorage = KeyService(_secureStore);
|
||||
|
||||
await _prefs.init();
|
||||
final data =
|
||||
|
@ -889,9 +881,8 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
bool longMutex = false;
|
||||
|
||||
// TODO: are these needed?
|
||||
FlutterSecureStorage? storage;
|
||||
|
||||
WalletService? walletService;
|
||||
SharedPreferences? prefs;
|
||||
KeyService? keysStorage;
|
||||
MoneroWalletBase? walletBase;
|
||||
WalletCreationService? _walletCreationService;
|
||||
|
@ -906,14 +897,8 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
required String name,
|
||||
required WalletType type,
|
||||
}) async {
|
||||
Directory root = (await getApplicationDocumentsDirectory());
|
||||
if (Platform.isIOS) {
|
||||
root = (await getLibraryDirectory());
|
||||
}
|
||||
//
|
||||
if (Platform.isLinux) {
|
||||
root = Directory("${root.path}/.stackwallet");
|
||||
}
|
||||
Directory root = await StackFileSystem.applicationRootDirectory();
|
||||
|
||||
final prefix = walletTypeToString(type).toLowerCase();
|
||||
final walletsDir = Directory('${root.path}/wallets');
|
||||
final walletDire = Directory('${walletsDir.path}/$prefix/$name');
|
||||
|
@ -970,11 +955,9 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
await DB.instance
|
||||
.put<dynamic>(boxName: walletId, key: "restoreHeight", value: height);
|
||||
|
||||
storage = const FlutterSecureStorage();
|
||||
walletService =
|
||||
monero.createMoneroWalletService(DB.instance.moneroWalletInfoBox);
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
keysStorage = KeyService(storage!);
|
||||
keysStorage = KeyService(_secureStore);
|
||||
WalletInfo walletInfo;
|
||||
WalletCredentials credentials;
|
||||
String name = _walletId;
|
||||
|
@ -1001,8 +984,7 @@ class MoneroWallet extends CoinServiceAPI {
|
|||
credentials.walletInfo = walletInfo;
|
||||
|
||||
_walletCreationService = WalletCreationService(
|
||||
secureStorage: storage,
|
||||
sharedPreferences: prefs,
|
||||
secureStorage: _secureStore,
|
||||
walletService: walletService,
|
||||
keyService: keysStorage,
|
||||
);
|
||||
|
|
|
@ -12,7 +12,6 @@ import 'package:crypto/crypto.dart';
|
|||
import 'package:decimal/decimal.dart';
|
||||
import 'package:devicelocale/devicelocale.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/cached_electrumx.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||
|
@ -1350,7 +1349,7 @@ class NamecoinWallet extends CoinServiceAPI {
|
|||
|
||||
CachedElectrumX get cachedElectrumXClient => _cachedElectrumXClient;
|
||||
|
||||
late FlutterSecureStorageInterface _secureStore;
|
||||
late SecureStorageInterface _secureStore;
|
||||
|
||||
late PriceAPI _priceAPI;
|
||||
|
||||
|
@ -1362,7 +1361,7 @@ class NamecoinWallet extends CoinServiceAPI {
|
|||
required CachedElectrumX cachedClient,
|
||||
required TransactionNotificationTracker tracker,
|
||||
PriceAPI? priceAPI,
|
||||
FlutterSecureStorageInterface? secureStore,
|
||||
required SecureStorageInterface secureStore,
|
||||
}) {
|
||||
txTracker = tracker;
|
||||
_walletId = walletId;
|
||||
|
@ -1372,13 +1371,12 @@ class NamecoinWallet extends CoinServiceAPI {
|
|||
_cachedElectrumXClient = cachedClient;
|
||||
|
||||
_priceAPI = priceAPI ?? PriceAPI(Client());
|
||||
_secureStore =
|
||||
secureStore ?? const SecureStorageWrapper(FlutterSecureStorage());
|
||||
_secureStore = secureStore;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> updateNode(bool shouldRefresh) async {
|
||||
final failovers = NodeService()
|
||||
final failovers = NodeService(secureStorageInterface: _secureStore)
|
||||
.failoverNodesFor(coin: coin)
|
||||
.map((e) => ElectrumXNode(
|
||||
address: e.host,
|
||||
|
@ -1416,7 +1414,8 @@ class NamecoinWallet extends CoinServiceAPI {
|
|||
}
|
||||
|
||||
Future<ElectrumXNode> getCurrentNode() async {
|
||||
final node = NodeService().getPrimaryNodeFor(coin: coin) ??
|
||||
final node = NodeService(secureStorageInterface: _secureStore)
|
||||
.getPrimaryNodeFor(coin: coin) ??
|
||||
DefaultNodes.getNodeFor(coin);
|
||||
|
||||
return ElectrumXNode(
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:cw_core/get_height_by_date.dart';
|
||||
import 'package:cw_core/monero_transaction_priority.dart';
|
||||
import 'package:cw_core/node.dart';
|
||||
import 'package:cw_core/pending_transaction.dart';
|
||||
|
@ -25,11 +24,8 @@ import 'package:flutter_libmonero/core/wallet_creation_service.dart';
|
|||
import 'package:flutter_libmonero/view_model/send/output.dart'
|
||||
as wownero_output;
|
||||
import 'package:flutter_libmonero/wownero/wownero.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:mutex/mutex.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:stackwallet/hive/db.dart';
|
||||
import 'package:stackwallet/models/node_model.dart';
|
||||
import 'package:stackwallet/models/paymint/fee_object_model.dart';
|
||||
|
@ -51,6 +47,7 @@ import 'package:stackwallet/utilities/enums/fee_rate_type_enum.dart';
|
|||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/prefs.dart';
|
||||
import 'package:stackwallet/utilities/stack_file_system.dart';
|
||||
|
||||
const int MINIMUM_CONFIRMATIONS = 10;
|
||||
|
||||
|
@ -69,12 +66,13 @@ class WowneroWallet extends CoinServiceAPI {
|
|||
Timer? wowneroAutosaveTimer;
|
||||
late Coin _coin;
|
||||
|
||||
late FlutterSecureStorageInterface _secureStore;
|
||||
late SecureStorageInterface _secureStore;
|
||||
|
||||
late PriceAPI _priceAPI;
|
||||
|
||||
Future<NodeModel> getCurrentNode() async {
|
||||
return NodeService().getPrimaryNodeFor(coin: coin) ??
|
||||
return NodeService(secureStorageInterface: _secureStore)
|
||||
.getPrimaryNodeFor(coin: coin) ??
|
||||
DefaultNodes.getNodeFor(coin);
|
||||
}
|
||||
|
||||
|
@ -83,14 +81,13 @@ class WowneroWallet extends CoinServiceAPI {
|
|||
required String walletName,
|
||||
required Coin coin,
|
||||
PriceAPI? priceAPI,
|
||||
FlutterSecureStorageInterface? secureStore}) {
|
||||
required SecureStorageInterface secureStore}) {
|
||||
_walletId = walletId;
|
||||
_walletName = walletName;
|
||||
_coin = coin;
|
||||
|
||||
_priceAPI = priceAPI ?? PriceAPI(Client());
|
||||
_secureStore =
|
||||
secureStore ?? const SecureStorageWrapper(FlutterSecureStorage());
|
||||
_secureStore = secureStore;
|
||||
}
|
||||
|
||||
bool _shouldAutoSync = false;
|
||||
|
@ -672,12 +669,10 @@ class WowneroWallet extends CoinServiceAPI {
|
|||
"Attempted to overwrite mnemonic on generate new wallet!");
|
||||
}
|
||||
|
||||
storage = const FlutterSecureStorage();
|
||||
// TODO: Wallet Service may need to be switched to Wownero
|
||||
walletService =
|
||||
wownero.createWowneroWalletService(DB.instance.moneroWalletInfoBox);
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
keysStorage = KeyService(storage!);
|
||||
keysStorage = KeyService(_secureStore);
|
||||
WalletInfo walletInfo;
|
||||
WalletCredentials credentials;
|
||||
try {
|
||||
|
@ -702,8 +697,7 @@ class WowneroWallet extends CoinServiceAPI {
|
|||
credentials.walletInfo = walletInfo;
|
||||
|
||||
_walletCreationService = WalletCreationService(
|
||||
secureStorage: storage,
|
||||
sharedPreferences: prefs,
|
||||
secureStorage: _secureStore,
|
||||
walletService: walletService,
|
||||
keyService: keysStorage,
|
||||
);
|
||||
|
@ -793,11 +787,9 @@ class WowneroWallet extends CoinServiceAPI {
|
|||
// Logging.instance.log("Caught in initializeWallet(): $e\n$s");
|
||||
// return false;
|
||||
// }
|
||||
storage = const FlutterSecureStorage();
|
||||
walletService =
|
||||
wownero.createWowneroWalletService(DB.instance.moneroWalletInfoBox);
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
keysStorage = KeyService(storage!);
|
||||
keysStorage = KeyService(_secureStore);
|
||||
|
||||
await _generateNewWallet(seedWordsLength: seedWordsLength);
|
||||
// var password;
|
||||
|
@ -839,11 +831,9 @@ class WowneroWallet extends CoinServiceAPI {
|
|||
"Attempted to initialize an existing wallet using an unknown wallet ID!");
|
||||
}
|
||||
|
||||
storage = const FlutterSecureStorage();
|
||||
walletService =
|
||||
wownero.createWowneroWalletService(DB.instance.moneroWalletInfoBox);
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
keysStorage = KeyService(storage!);
|
||||
keysStorage = KeyService(_secureStore);
|
||||
|
||||
await _prefs.init();
|
||||
final data =
|
||||
|
@ -895,9 +885,8 @@ class WowneroWallet extends CoinServiceAPI {
|
|||
bool longMutex = false;
|
||||
|
||||
// TODO: are these needed?
|
||||
FlutterSecureStorage? storage;
|
||||
|
||||
WalletService? walletService;
|
||||
SharedPreferences? prefs;
|
||||
KeyService? keysStorage;
|
||||
WowneroWalletBase? walletBase;
|
||||
WalletCreationService? _walletCreationService;
|
||||
|
@ -912,13 +901,8 @@ class WowneroWallet extends CoinServiceAPI {
|
|||
required String name,
|
||||
required WalletType type,
|
||||
}) async {
|
||||
Directory root = (await getApplicationDocumentsDirectory());
|
||||
if (Platform.isIOS) {
|
||||
root = (await getLibraryDirectory());
|
||||
}
|
||||
if (Platform.isLinux) {
|
||||
root = Directory("${root.path}/.stackwallet");
|
||||
}
|
||||
Directory root = await StackFileSystem.applicationRootDirectory();
|
||||
|
||||
final prefix = walletTypeToString(type).toLowerCase();
|
||||
final walletsDir = Directory('${root.path}/wallets');
|
||||
final walletDire = Directory('${walletsDir.path}/$prefix/$name');
|
||||
|
@ -993,11 +977,9 @@ class WowneroWallet extends CoinServiceAPI {
|
|||
await DB.instance
|
||||
.put<dynamic>(boxName: walletId, key: "restoreHeight", value: height);
|
||||
|
||||
storage = const FlutterSecureStorage();
|
||||
walletService =
|
||||
wownero.createWowneroWalletService(DB.instance.moneroWalletInfoBox);
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
keysStorage = KeyService(storage!);
|
||||
keysStorage = KeyService(_secureStore);
|
||||
WalletInfo walletInfo;
|
||||
WalletCredentials credentials;
|
||||
String name = _walletId;
|
||||
|
@ -1024,8 +1006,7 @@ class WowneroWallet extends CoinServiceAPI {
|
|||
credentials.walletInfo = walletInfo;
|
||||
|
||||
_walletCreationService = WalletCreationService(
|
||||
secureStorage: storage,
|
||||
sharedPreferences: prefs,
|
||||
secureStorage: _secureStore,
|
||||
walletService: walletService,
|
||||
keyService: keysStorage,
|
||||
);
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:http/http.dart';
|
||||
import 'package:stackwallet/hive/db.dart';
|
||||
import 'package:stackwallet/models/node_model.dart';
|
||||
|
@ -13,13 +12,11 @@ import 'package:stackwallet/utilities/logger.dart';
|
|||
const kStackCommunityNodesEndpoint = "https://extras.stackwallet.com";
|
||||
|
||||
class NodeService extends ChangeNotifier {
|
||||
final FlutterSecureStorageInterface secureStorageInterface;
|
||||
final SecureStorageInterface secureStorageInterface;
|
||||
|
||||
/// Exposed [secureStorageInterface] in order to inject mock for tests
|
||||
NodeService({
|
||||
this.secureStorageInterface = const SecureStorageWrapper(
|
||||
FlutterSecureStorage(),
|
||||
),
|
||||
required this.secureStorageInterface,
|
||||
});
|
||||
|
||||
Future<void> updateDefaults() async {
|
||||
|
|
|
@ -205,13 +205,14 @@ class Wallets extends ChangeNotifier {
|
|||
final txTracker =
|
||||
TransactionNotificationTracker(walletId: walletId);
|
||||
|
||||
final failovers = NodeService().failoverNodesFor(coin: coin);
|
||||
final failovers = nodeService.failoverNodesFor(coin: coin);
|
||||
|
||||
// load wallet
|
||||
final wallet = CoinServiceAPI.from(
|
||||
coin,
|
||||
walletId,
|
||||
entry.value.name,
|
||||
nodeService.secureStorageInterface,
|
||||
node,
|
||||
txTracker,
|
||||
prefs,
|
||||
|
|
|
@ -3,7 +3,6 @@ import 'dart:convert';
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_libmonero/monero/monero.dart';
|
||||
import 'package:flutter_libmonero/wownero/wownero.dart';
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:stackwallet/hive/db.dart';
|
||||
import 'package:stackwallet/services/coins/epiccash/epiccash_wallet.dart';
|
||||
import 'package:stackwallet/services/notifications_service.dart';
|
||||
|
@ -48,17 +47,14 @@ class WalletInfo {
|
|||
}
|
||||
|
||||
class WalletsService extends ChangeNotifier {
|
||||
late final FlutterSecureStorageInterface _secureStore;
|
||||
late final SecureStorageInterface _secureStore;
|
||||
|
||||
Future<Map<String, WalletInfo>>? _walletNames;
|
||||
Future<Map<String, WalletInfo>> get walletNames =>
|
||||
_walletNames ??= _fetchWalletNames();
|
||||
|
||||
WalletsService({
|
||||
FlutterSecureStorageInterface secureStorageInterface =
|
||||
const SecureStorageWrapper(
|
||||
FlutterSecureStorage(),
|
||||
),
|
||||
required SecureStorageInterface secureStorageInterface,
|
||||
}) {
|
||||
_secureStore = secureStorageInterface;
|
||||
}
|
||||
|
|
|
@ -59,6 +59,7 @@ class _SVG {
|
|||
String txExchangeFailed(BuildContext context) =>
|
||||
"assets/svg/${Theme.of(context).extension<StackColors>()!.themeType.name}/tx-exchange-icon-failed.svg";
|
||||
|
||||
String get circlePlus => "assets/svg/plus-circle.svg";
|
||||
String get framedGear => "assets/svg/framed-gear.svg";
|
||||
String get framedAddressBook => "assets/svg/framed-address-book.svg";
|
||||
String get themeLight => "assets/svg/light/light-mode.svg";
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:stackwallet/electrumx_rpc/electrumx.dart';
|
||||
import 'package:stackwallet/hive/db.dart';
|
||||
|
@ -17,9 +16,7 @@ import 'package:stackwallet/utilities/prefs.dart';
|
|||
class DbVersionMigrator {
|
||||
Future<void> migrate(
|
||||
int fromVersion, {
|
||||
FlutterSecureStorageInterface secureStore = const SecureStorageWrapper(
|
||||
FlutterSecureStorage(),
|
||||
),
|
||||
required SecureStorageInterface secureStore,
|
||||
}) async {
|
||||
Logging.instance.log(
|
||||
"Running migrate fromVersion $fromVersion",
|
||||
|
@ -29,8 +26,9 @@ class DbVersionMigrator {
|
|||
case 0:
|
||||
await Hive.openBox<dynamic>(DB.boxNameAllWalletsData);
|
||||
await Hive.openBox<dynamic>(DB.boxNamePrefs);
|
||||
final walletsService = WalletsService();
|
||||
final nodeService = NodeService();
|
||||
final walletsService =
|
||||
WalletsService(secureStorageInterface: secureStore);
|
||||
final nodeService = NodeService(secureStorageInterface: secureStore);
|
||||
final prefs = Prefs.instance;
|
||||
final walletInfoList = await walletsService.walletNames;
|
||||
await prefs.init();
|
||||
|
@ -118,7 +116,7 @@ class DbVersionMigrator {
|
|||
boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 1);
|
||||
|
||||
// try to continue migrating
|
||||
return await migrate(1);
|
||||
return await migrate(1, secureStore: secureStore);
|
||||
|
||||
case 1:
|
||||
await Hive.openBox<ExchangeTransaction>(DB.boxNameTrades);
|
||||
|
@ -142,7 +140,7 @@ class DbVersionMigrator {
|
|||
boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 2);
|
||||
|
||||
// try to continue migrating
|
||||
return await migrate(2);
|
||||
return await migrate(2, secureStore: secureStore);
|
||||
case 2:
|
||||
await Hive.openBox<dynamic>(DB.boxNamePrefs);
|
||||
final prefs = Prefs.instance;
|
||||
|
@ -154,7 +152,7 @@ class DbVersionMigrator {
|
|||
// update version
|
||||
await DB.instance.put<dynamic>(
|
||||
boxName: DB.boxNameDBInfo, key: "hive_data_version", value: 3);
|
||||
return await migrate(3);
|
||||
return await migrate(3, secureStore: secureStore);
|
||||
|
||||
default:
|
||||
// finally return
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:stack_wallet_backup/secure_storage.dart';
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
import 'package:stackwallet/hive/db.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
|
||||
const String _kKeyBlobKey = "swbKeyBlobKeyStringID";
|
||||
|
@ -24,7 +24,6 @@ String _getMessageFromException(Object exception) {
|
|||
|
||||
class DPS {
|
||||
StorageCryptoHandler? _handler;
|
||||
final SecureStorageWrapper secureStorageWrapper;
|
||||
|
||||
StorageCryptoHandler get handler {
|
||||
if (_handler == null) {
|
||||
|
@ -34,11 +33,7 @@ class DPS {
|
|||
return _handler!;
|
||||
}
|
||||
|
||||
DPS({
|
||||
this.secureStorageWrapper = const SecureStorageWrapper(
|
||||
FlutterSecureStorage(),
|
||||
),
|
||||
});
|
||||
DPS();
|
||||
|
||||
Future<void> initFromNew(String passphrase) async {
|
||||
if (_handler != null) {
|
||||
|
@ -47,10 +42,14 @@ class DPS {
|
|||
|
||||
try {
|
||||
_handler = await StorageCryptoHandler.fromNewPassphrase(passphrase);
|
||||
await secureStorageWrapper.write(
|
||||
|
||||
final box = await Hive.openBox<String>(DB.boxNameDesktopData);
|
||||
await DB.instance.put<String>(
|
||||
boxName: DB.boxNameDesktopData,
|
||||
key: _kKeyBlobKey,
|
||||
value: await _handler!.getKeyBlob(),
|
||||
);
|
||||
await box.close();
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"${_getMessageFromException(e)}\n$s",
|
||||
|
@ -65,7 +64,13 @@ class DPS {
|
|||
throw Exception(
|
||||
"DPS: attempted to re initialize with existing passphrase");
|
||||
}
|
||||
final keyBlob = await secureStorageWrapper.read(key: _kKeyBlobKey);
|
||||
|
||||
final box = await Hive.openBox<String>(DB.boxNameDesktopData);
|
||||
final keyBlob = DB.instance.get<String>(
|
||||
boxName: DB.boxNameDesktopData,
|
||||
key: _kKeyBlobKey,
|
||||
);
|
||||
await box.close();
|
||||
|
||||
if (keyBlob == null) {
|
||||
throw Exception(
|
||||
|
@ -79,11 +84,84 @@ class DPS {
|
|||
"${_getMessageFromException(e)}\n$s",
|
||||
level: LogLevel.Error,
|
||||
);
|
||||
rethrow;
|
||||
throw Exception(_getMessageFromException(e));
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> verifyPassphrase(String passphrase) async {
|
||||
final box = await Hive.openBox<String>(DB.boxNameDesktopData);
|
||||
final keyBlob = DB.instance.get<String>(
|
||||
boxName: DB.boxNameDesktopData,
|
||||
key: _kKeyBlobKey,
|
||||
);
|
||||
await box.close();
|
||||
|
||||
if (keyBlob == null) {
|
||||
// no passphrase key blob found so any passphrase is technically bad
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
await StorageCryptoHandler.fromExisting(passphrase, keyBlob);
|
||||
// existing passphrase matches key blob
|
||||
return true;
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"${_getMessageFromException(e)}\n$s",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
// password is wrong or some other error
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> changePassphrase(
|
||||
String passphraseOld,
|
||||
String passphraseNew,
|
||||
) async {
|
||||
final box = await Hive.openBox<String>(DB.boxNameDesktopData);
|
||||
final keyBlob = DB.instance.get<String>(
|
||||
boxName: DB.boxNameDesktopData,
|
||||
key: _kKeyBlobKey,
|
||||
);
|
||||
await box.close();
|
||||
|
||||
if (keyBlob == null) {
|
||||
// no passphrase key blob found so any passphrase is technically bad
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!(await verifyPassphrase(passphraseOld))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
try {
|
||||
await _handler!.resetPassphrase(passphraseNew);
|
||||
|
||||
final box = await Hive.openBox<String>(DB.boxNameDesktopData);
|
||||
await DB.instance.put<String>(
|
||||
boxName: DB.boxNameDesktopData,
|
||||
key: _kKeyBlobKey,
|
||||
value: await _handler!.getKeyBlob(),
|
||||
);
|
||||
await box.close();
|
||||
|
||||
// successfully updated passphrase
|
||||
return true;
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
"${_getMessageFromException(e)}\n$s",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
Future<bool> hasPassword() async {
|
||||
return (await secureStorageWrapper.read(key: _kKeyBlobKey)) != null;
|
||||
final keyBlob = DB.instance.get<String>(
|
||||
boxName: DB.boxNameDesktopData,
|
||||
key: _kKeyBlobKey,
|
||||
);
|
||||
return keyBlob != null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,12 @@
|
|||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:stack_wallet_backup/secure_storage.dart';
|
||||
import 'package:stackwallet/models/isar/models/encrypted_string_value.dart';
|
||||
import 'package:stackwallet/utilities/stack_file_system.dart';
|
||||
|
||||
abstract class SecureStorageInterface {
|
||||
dynamic get store;
|
||||
|
||||
abstract class FlutterSecureStorageInterface {
|
||||
Future<void> write({
|
||||
required String key,
|
||||
required String? value,
|
||||
|
@ -33,10 +39,82 @@ abstract class FlutterSecureStorageInterface {
|
|||
});
|
||||
}
|
||||
|
||||
class SecureStorageWrapper implements FlutterSecureStorageInterface {
|
||||
final FlutterSecureStorage secureStore;
|
||||
class DesktopSecureStore {
|
||||
final StorageCryptoHandler handler;
|
||||
late final Isar isar;
|
||||
|
||||
const SecureStorageWrapper(this.secureStore);
|
||||
DesktopSecureStore(this.handler);
|
||||
|
||||
Future<void> init() async {
|
||||
isar = await Isar.open(
|
||||
[EncryptedStringValueSchema],
|
||||
directory: (await StackFileSystem.applicationIsarDirectory()).path,
|
||||
inspector: false,
|
||||
name: "desktopStore",
|
||||
);
|
||||
}
|
||||
|
||||
Future<String?> read({
|
||||
required String key,
|
||||
}) async {
|
||||
final value =
|
||||
await isar.encryptedStringValues.filter().keyEqualTo(key).findFirst();
|
||||
|
||||
// value does not exist;
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return await handler.decryptValue(key, value.value);
|
||||
}
|
||||
|
||||
Future<void> write({
|
||||
required String key,
|
||||
required String? value,
|
||||
}) async {
|
||||
if (value == null) {
|
||||
// here we assume that a value is to be deleted
|
||||
await isar.writeTxn(() async {
|
||||
await isar.encryptedStringValues.deleteByKey(key);
|
||||
});
|
||||
} else {
|
||||
// otherwise created encrypted object value
|
||||
final object = EncryptedStringValue();
|
||||
object.key = key;
|
||||
object.value = await handler.encryptValue(key, value);
|
||||
|
||||
// store object value
|
||||
await isar.writeTxn(() async {
|
||||
await isar.encryptedStringValues.put(object);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> delete({
|
||||
required String key,
|
||||
}) async {
|
||||
await isar.writeTxn(() async {
|
||||
await isar.encryptedStringValues.deleteByKey(key);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/// all *Options params ignored on desktop
|
||||
class SecureStorageWrapper implements SecureStorageInterface {
|
||||
final dynamic _store;
|
||||
final bool _isDesktop;
|
||||
|
||||
@override
|
||||
dynamic get store => _store;
|
||||
|
||||
const SecureStorageWrapper({
|
||||
required dynamic store,
|
||||
required bool isDesktop,
|
||||
}) : assert(isDesktop
|
||||
? store is DesktopSecureStore
|
||||
: store is FlutterSecureStorage),
|
||||
_store = store,
|
||||
_isDesktop = isDesktop;
|
||||
|
||||
@override
|
||||
Future<String?> read({
|
||||
|
@ -47,16 +125,20 @@ class SecureStorageWrapper implements FlutterSecureStorageInterface {
|
|||
WebOptions? webOptions,
|
||||
MacOsOptions? mOptions,
|
||||
WindowsOptions? wOptions,
|
||||
}) {
|
||||
return secureStore.read(
|
||||
key: key,
|
||||
iOptions: iOptions,
|
||||
aOptions: aOptions,
|
||||
lOptions: lOptions,
|
||||
webOptions: webOptions,
|
||||
mOptions: mOptions,
|
||||
wOptions: wOptions,
|
||||
);
|
||||
}) async {
|
||||
if (_isDesktop) {
|
||||
return await (_store as DesktopSecureStore).read(key: key);
|
||||
} else {
|
||||
return await (_store as FlutterSecureStorage).read(
|
||||
key: key,
|
||||
iOptions: iOptions,
|
||||
aOptions: aOptions,
|
||||
lOptions: lOptions,
|
||||
webOptions: webOptions,
|
||||
mOptions: mOptions,
|
||||
wOptions: wOptions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -69,17 +151,21 @@ class SecureStorageWrapper implements FlutterSecureStorageInterface {
|
|||
WebOptions? webOptions,
|
||||
MacOsOptions? mOptions,
|
||||
WindowsOptions? wOptions,
|
||||
}) {
|
||||
return secureStore.write(
|
||||
key: key,
|
||||
value: value,
|
||||
iOptions: iOptions,
|
||||
aOptions: aOptions,
|
||||
lOptions: lOptions,
|
||||
webOptions: webOptions,
|
||||
mOptions: mOptions,
|
||||
wOptions: wOptions,
|
||||
);
|
||||
}) async {
|
||||
if (_isDesktop) {
|
||||
return await (_store as DesktopSecureStore).write(key: key, value: value);
|
||||
} else {
|
||||
return await (_store as FlutterSecureStorage).write(
|
||||
key: key,
|
||||
value: value,
|
||||
iOptions: iOptions,
|
||||
aOptions: aOptions,
|
||||
lOptions: lOptions,
|
||||
webOptions: webOptions,
|
||||
mOptions: mOptions,
|
||||
wOptions: wOptions,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
|
@ -92,20 +178,24 @@ class SecureStorageWrapper implements FlutterSecureStorageInterface {
|
|||
MacOsOptions? mOptions,
|
||||
WindowsOptions? wOptions,
|
||||
}) async {
|
||||
await secureStore.delete(
|
||||
key: key,
|
||||
iOptions: iOptions,
|
||||
aOptions: aOptions,
|
||||
lOptions: lOptions,
|
||||
webOptions: webOptions,
|
||||
mOptions: mOptions,
|
||||
wOptions: wOptions,
|
||||
);
|
||||
if (_isDesktop) {
|
||||
return (_store as DesktopSecureStore).delete(key: key);
|
||||
} else {
|
||||
return await (_store as FlutterSecureStorage).delete(
|
||||
key: key,
|
||||
iOptions: iOptions,
|
||||
aOptions: aOptions,
|
||||
lOptions: lOptions,
|
||||
webOptions: webOptions,
|
||||
mOptions: mOptions,
|
||||
wOptions: wOptions,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Mock class for testing purposes
|
||||
class FakeSecureStorage implements FlutterSecureStorageInterface {
|
||||
class FakeSecureStorage implements SecureStorageInterface {
|
||||
final Map<String, String?> _store = {};
|
||||
int _interactions = 0;
|
||||
int get interactions => _interactions;
|
||||
|
@ -161,4 +251,7 @@ class FakeSecureStorage implements FlutterSecureStorageInterface {
|
|||
_deletes++;
|
||||
_store.remove(key);
|
||||
}
|
||||
|
||||
@override
|
||||
dynamic get store => throw UnimplementedError();
|
||||
}
|
||||
|
|
66
lib/utilities/stack_file_system.dart
Normal file
66
lib/utilities/stack_file_system.dart
Normal file
|
@ -0,0 +1,66 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:stackwallet/utilities/logger.dart';
|
||||
import 'package:stackwallet/utilities/util.dart';
|
||||
|
||||
abstract class StackFileSystem {
|
||||
static Future<Directory> applicationRootDirectory() async {
|
||||
Directory appDirectory;
|
||||
|
||||
// todo: can merge and do same as regular linux home dir?
|
||||
if (Logging.isArmLinux) {
|
||||
appDirectory = await getApplicationDocumentsDirectory();
|
||||
appDirectory = Directory("${appDirectory.path}/.stackwallet");
|
||||
} else if (Platform.isLinux) {
|
||||
appDirectory = Directory("${Platform.environment['HOME']}/.stackwallet");
|
||||
} else if (Platform.isWindows) {
|
||||
// TODO: windows root .stackwallet dir location
|
||||
throw Exception("Unsupported platform");
|
||||
} else if (Platform.isMacOS) {
|
||||
// currently run in ipad mode??
|
||||
throw Exception("Unsupported platform");
|
||||
} else if (Platform.isIOS) {
|
||||
// todo: check if we need different behaviour here
|
||||
if (Util.isDesktop) {
|
||||
appDirectory = await getLibraryDirectory();
|
||||
} else {
|
||||
appDirectory = await getLibraryDirectory();
|
||||
}
|
||||
} else if (Platform.isAndroid) {
|
||||
appDirectory = await getApplicationDocumentsDirectory();
|
||||
} else {
|
||||
throw Exception("Unsupported platform");
|
||||
}
|
||||
if (!appDirectory.existsSync()) {
|
||||
await appDirectory.create(recursive: true);
|
||||
}
|
||||
return appDirectory;
|
||||
}
|
||||
|
||||
static Future<Directory> applicationIsarDirectory() async {
|
||||
final root = await applicationRootDirectory();
|
||||
if (Util.isDesktop) {
|
||||
final dir = Directory("${root.path}/isar");
|
||||
if (!dir.existsSync()) {
|
||||
await dir.create();
|
||||
}
|
||||
return dir;
|
||||
} else {
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
static Future<Directory> applicationHiveDirectory() async {
|
||||
final root = await applicationRootDirectory();
|
||||
if (Util.isDesktop) {
|
||||
final dir = Directory("${root.path}/hive");
|
||||
if (!dir.existsSync()) {
|
||||
await dir.create();
|
||||
}
|
||||
return dir;
|
||||
} else {
|
||||
return root;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -21,3 +21,27 @@ class ConditionalParent extends StatelessWidget {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
class BranchedParent extends StatelessWidget {
|
||||
const BranchedParent({
|
||||
Key? key,
|
||||
required this.condition,
|
||||
required this.conditionBranchBuilder,
|
||||
required this.otherBranchBuilder,
|
||||
required this.children,
|
||||
}) : super(key: key);
|
||||
|
||||
final bool condition;
|
||||
final Widget Function(List<Widget>) conditionBranchBuilder;
|
||||
final Widget Function(List<Widget>) otherBranchBuilder;
|
||||
final List<Widget> children;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (condition) {
|
||||
return conditionBranchBuilder(children);
|
||||
} else {
|
||||
return otherBranchBuilder(children);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1244,7 +1244,7 @@ packages:
|
|||
source: hosted
|
||||
version: "3.0.1"
|
||||
shared_preferences:
|
||||
dependency: "direct main"
|
||||
dependency: transitive
|
||||
description:
|
||||
name: shared_preferences
|
||||
url: "https://pub.dartlang.org"
|
||||
|
|
|
@ -126,7 +126,7 @@ dependencies:
|
|||
pointycastle: ^3.6.0
|
||||
package_info_plus: ^1.4.2
|
||||
lottie: ^1.3.0
|
||||
shared_preferences: ^2.0.15
|
||||
# shared_preferences: ^2.0.15
|
||||
file_picker: ^5.0.1
|
||||
connectivity_plus: 2.3.6+1
|
||||
# document_file_save_plus: ^1.0.5
|
||||
|
@ -314,6 +314,7 @@ flutter:
|
|||
- assets/svg/exit-desktop.svg
|
||||
- assets/svg/keys.svg
|
||||
- assets/svg/arrow-down.svg
|
||||
- assets/svg/plus-circle.svg
|
||||
# coin icons
|
||||
- assets/svg/coin_icons/Bitcoin.svg
|
||||
- assets/svg/coin_icons/Litecoin.svg
|
||||
|
|
|
@ -678,6 +678,14 @@ class MockPrefs extends _i1.Mock implements _i5.Prefs {
|
|||
returnValueForMissingStub: _i4.Future<void>.value(),
|
||||
) as _i4.Future<void>);
|
||||
@override
|
||||
_i4.Future<bool> isExternalCallsSet() => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#isExternalCallsSet,
|
||||
[],
|
||||
),
|
||||
returnValue: _i4.Future<bool>.value(false),
|
||||
) as _i4.Future<bool>);
|
||||
@override
|
||||
void addListener(_i9.VoidCallback? listener) => super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#addListener,
|
||||
|
|
|
@ -399,6 +399,14 @@ class MockPrefs extends _i1.Mock implements _i4.Prefs {
|
|||
returnValueForMissingStub: _i3.Future<void>.value(),
|
||||
) as _i3.Future<void>);
|
||||
@override
|
||||
_i3.Future<bool> isExternalCallsSet() => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#isExternalCallsSet,
|
||||
[],
|
||||
),
|
||||
returnValue: _i3.Future<bool>.value(false),
|
||||
) as _i3.Future<bool>);
|
||||
@override
|
||||
void addListener(_i8.VoidCallback? listener) => super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#addListener,
|
||||
|
|
|
@ -13,7 +13,7 @@ void main() {
|
|||
when(secureStore.write(key: "testKey", value: "some value"))
|
||||
.thenAnswer((_) async => null);
|
||||
|
||||
final wrapper = SecureStorageWrapper(secureStore);
|
||||
final wrapper = SecureStorageWrapper(store: secureStore, isDesktop: false);
|
||||
|
||||
await expectLater(
|
||||
() async => await wrapper.write(key: "testKey", value: "some value"),
|
||||
|
@ -27,7 +27,7 @@ void main() {
|
|||
final secureStore = MockFlutterSecureStorage();
|
||||
when(secureStore.read(key: "testKey"))
|
||||
.thenAnswer((_) async => "some value");
|
||||
final wrapper = SecureStorageWrapper(secureStore);
|
||||
final wrapper = SecureStorageWrapper(store: secureStore, isDesktop: false);
|
||||
|
||||
final result = await wrapper.read(key: "testKey");
|
||||
|
||||
|
@ -40,7 +40,7 @@ void main() {
|
|||
test("SecureStorageWrapper delete", () async {
|
||||
final secureStore = MockFlutterSecureStorage();
|
||||
when(secureStore.delete(key: "testKey")).thenAnswer((_) async {});
|
||||
final wrapper = SecureStorageWrapper(secureStore);
|
||||
final wrapper = SecureStorageWrapper(store: secureStore, isDesktop: false);
|
||||
|
||||
await expectLater(
|
||||
() async => await wrapper.delete(key: "testKey"), returnsNormally);
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// Mocks generated by Mockito 5.3.2 from annotations
|
||||
// in stackwallet/test/pages/send_view_test.dart.
|
||||
// in stackwallet/test/pages/send_view/send_view_test.dart.
|
||||
// Do not manually edit this file.
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
|
@ -86,7 +86,7 @@ class _FakeManager_3 extends _i1.SmartFake implements _i6.Manager {
|
|||
}
|
||||
|
||||
class _FakeFlutterSecureStorageInterface_4 extends _i1.SmartFake
|
||||
implements _i7.FlutterSecureStorageInterface {
|
||||
implements _i7.SecureStorageInterface {
|
||||
_FakeFlutterSecureStorageInterface_4(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
|
@ -621,14 +621,13 @@ class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
|||
}
|
||||
|
||||
@override
|
||||
_i7.FlutterSecureStorageInterface get secureStorageInterface =>
|
||||
(super.noSuchMethod(
|
||||
_i7.SecureStorageInterface get secureStorageInterface => (super.noSuchMethod(
|
||||
Invocation.getter(#secureStorageInterface),
|
||||
returnValue: _FakeFlutterSecureStorageInterface_4(
|
||||
this,
|
||||
Invocation.getter(#secureStorageInterface),
|
||||
),
|
||||
) as _i7.FlutterSecureStorageInterface);
|
||||
) as _i7.SecureStorageInterface);
|
||||
@override
|
||||
List<_i19.NodeModel> get primaryNodes => (super.noSuchMethod(
|
||||
Invocation.getter(#primaryNodes),
|
||||
|
@ -890,6 +889,14 @@ class MockBitcoinWallet extends _i1.Mock implements _i20.BitcoinWallet {
|
|||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
set cachedTxData(_i9.TransactionData? _cachedTxData) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#cachedTxData,
|
||||
_cachedTxData,
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
bool get isActive => (super.noSuchMethod(
|
||||
Invocation.getter(#isActive),
|
||||
returnValue: false,
|
||||
|
@ -1272,6 +1279,16 @@ class MockBitcoinWallet extends _i1.Mock implements _i20.BitcoinWallet {
|
|||
returnValueForMissingStub: _i16.Future<void>.value(),
|
||||
) as _i16.Future<void>);
|
||||
@override
|
||||
_i16.Future<void> updateSentCachedTxData(Map<String, dynamic>? txData) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#updateSentCachedTxData,
|
||||
[txData],
|
||||
),
|
||||
returnValue: _i16.Future<void>.value(),
|
||||
returnValueForMissingStub: _i16.Future<void>.value(),
|
||||
) as _i16.Future<void>);
|
||||
@override
|
||||
bool validateAddress(String? address) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#validateAddress,
|
||||
|
@ -1875,6 +1892,14 @@ class MockPrefs extends _i1.Mock implements _i17.Prefs {
|
|||
returnValueForMissingStub: _i16.Future<void>.value(),
|
||||
) as _i16.Future<void>);
|
||||
@override
|
||||
_i16.Future<bool> isExternalCallsSet() => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#isExternalCallsSet,
|
||||
[],
|
||||
),
|
||||
returnValue: _i16.Future<bool>.value(false),
|
||||
) as _i16.Future<bool>);
|
||||
@override
|
||||
void addListener(_i18.VoidCallback? listener) => super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#addListener,
|
||||
|
@ -2623,4 +2648,14 @@ class MockCoinServiceAPI extends _i1.Mock implements _i13.CoinServiceAPI {
|
|||
),
|
||||
returnValue: _i16.Future<bool>.value(false),
|
||||
) as _i16.Future<bool>);
|
||||
@override
|
||||
_i16.Future<void> updateSentCachedTxData(Map<String, dynamic>? txData) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#updateSentCachedTxData,
|
||||
[txData],
|
||||
),
|
||||
returnValue: _i16.Future<void>.value(),
|
||||
returnValueForMissingStub: _i16.Future<void>.value(),
|
||||
) as _i16.Future<void>);
|
||||
}
|
||||
|
|
|
@ -350,6 +350,14 @@ class MockPrefs extends _i1.Mock implements _i3.Prefs {
|
|||
returnValueForMissingStub: _i7.Future<void>.value(),
|
||||
) as _i7.Future<void>);
|
||||
@override
|
||||
_i7.Future<bool> isExternalCallsSet() => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#isExternalCallsSet,
|
||||
[],
|
||||
),
|
||||
returnValue: _i7.Future<bool>.value(false),
|
||||
) as _i7.Future<bool>);
|
||||
@override
|
||||
void addListener(_i8.VoidCallback? listener) => super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#addListener,
|
||||
|
|
|
@ -30,7 +30,7 @@ import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'
|
|||
// ignore_for_file: subtype_of_sealed_class
|
||||
|
||||
class _FakeFlutterSecureStorageInterface_0 extends _i1.SmartFake
|
||||
implements _i2.FlutterSecureStorageInterface {
|
||||
implements _i2.SecureStorageInterface {
|
||||
_FakeFlutterSecureStorageInterface_0(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
|
@ -309,14 +309,13 @@ class MockWalletsService extends _i1.Mock implements _i6.WalletsService {
|
|||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockNodeService extends _i1.Mock implements _i10.NodeService {
|
||||
@override
|
||||
_i2.FlutterSecureStorageInterface get secureStorageInterface =>
|
||||
(super.noSuchMethod(
|
||||
_i2.SecureStorageInterface get secureStorageInterface => (super.noSuchMethod(
|
||||
Invocation.getter(#secureStorageInterface),
|
||||
returnValue: _FakeFlutterSecureStorageInterface_0(
|
||||
this,
|
||||
Invocation.getter(#secureStorageInterface),
|
||||
),
|
||||
) as _i2.FlutterSecureStorageInterface);
|
||||
) as _i2.SecureStorageInterface);
|
||||
@override
|
||||
List<_i11.NodeModel> get primaryNodes => (super.noSuchMethod(
|
||||
Invocation.getter(#primaryNodes),
|
||||
|
|
|
@ -30,7 +30,7 @@ import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'
|
|||
// ignore_for_file: subtype_of_sealed_class
|
||||
|
||||
class _FakeFlutterSecureStorageInterface_0 extends _i1.SmartFake
|
||||
implements _i2.FlutterSecureStorageInterface {
|
||||
implements _i2.SecureStorageInterface {
|
||||
_FakeFlutterSecureStorageInterface_0(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
|
@ -309,14 +309,13 @@ class MockWalletsService extends _i1.Mock implements _i6.WalletsService {
|
|||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockNodeService extends _i1.Mock implements _i10.NodeService {
|
||||
@override
|
||||
_i2.FlutterSecureStorageInterface get secureStorageInterface =>
|
||||
(super.noSuchMethod(
|
||||
_i2.SecureStorageInterface get secureStorageInterface => (super.noSuchMethod(
|
||||
Invocation.getter(#secureStorageInterface),
|
||||
returnValue: _FakeFlutterSecureStorageInterface_0(
|
||||
this,
|
||||
Invocation.getter(#secureStorageInterface),
|
||||
),
|
||||
) as _i2.FlutterSecureStorageInterface);
|
||||
) as _i2.SecureStorageInterface);
|
||||
@override
|
||||
List<_i11.NodeModel> get primaryNodes => (super.noSuchMethod(
|
||||
Invocation.getter(#primaryNodes),
|
||||
|
|
|
@ -84,7 +84,7 @@ class _FakeTransactionData_4 extends _i1.SmartFake
|
|||
}
|
||||
|
||||
class _FakeFlutterSecureStorageInterface_5 extends _i1.SmartFake
|
||||
implements _i6.FlutterSecureStorageInterface {
|
||||
implements _i6.SecureStorageInterface {
|
||||
_FakeFlutterSecureStorageInterface_5(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
|
@ -744,14 +744,14 @@ class MockManager extends _i1.Mock implements _i12.Manager {
|
|||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockNodeService extends _i1.Mock implements _i13.NodeService {
|
||||
@override
|
||||
_i6.FlutterSecureStorageInterface get secureStorageInterface =>
|
||||
_i6.SecureStorageInterface get secureStorageInterface =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.getter(#secureStorageInterface),
|
||||
returnValue: _FakeFlutterSecureStorageInterface_5(
|
||||
this,
|
||||
Invocation.getter(#secureStorageInterface),
|
||||
),
|
||||
) as _i6.FlutterSecureStorageInterface);
|
||||
) as _i6.SecureStorageInterface);
|
||||
@override
|
||||
List<_i14.NodeModel> get primaryNodes => (super.noSuchMethod(
|
||||
Invocation.getter(#primaryNodes),
|
||||
|
|
|
@ -29,7 +29,7 @@ import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'
|
|||
// ignore_for_file: subtype_of_sealed_class
|
||||
|
||||
class _FakeFlutterSecureStorageInterface_0 extends _i1.SmartFake
|
||||
implements _i2.FlutterSecureStorageInterface {
|
||||
implements _i2.SecureStorageInterface {
|
||||
_FakeFlutterSecureStorageInterface_0(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
|
@ -86,14 +86,13 @@ class _FakeTransactionData_4 extends _i1.SmartFake
|
|||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockNodeService extends _i1.Mock implements _i6.NodeService {
|
||||
@override
|
||||
_i2.FlutterSecureStorageInterface get secureStorageInterface =>
|
||||
(super.noSuchMethod(
|
||||
_i2.SecureStorageInterface get secureStorageInterface => (super.noSuchMethod(
|
||||
Invocation.getter(#secureStorageInterface),
|
||||
returnValue: _FakeFlutterSecureStorageInterface_0(
|
||||
this,
|
||||
Invocation.getter(#secureStorageInterface),
|
||||
),
|
||||
) as _i2.FlutterSecureStorageInterface);
|
||||
) as _i2.SecureStorageInterface);
|
||||
@override
|
||||
List<_i7.NodeModel> get primaryNodes => (super.noSuchMethod(
|
||||
Invocation.getter(#primaryNodes),
|
||||
|
|
|
@ -29,7 +29,7 @@ import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'
|
|||
// ignore_for_file: subtype_of_sealed_class
|
||||
|
||||
class _FakeFlutterSecureStorageInterface_0 extends _i1.SmartFake
|
||||
implements _i2.FlutterSecureStorageInterface {
|
||||
implements _i2.SecureStorageInterface {
|
||||
_FakeFlutterSecureStorageInterface_0(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
|
@ -86,14 +86,13 @@ class _FakeTransactionData_4 extends _i1.SmartFake
|
|||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockNodeService extends _i1.Mock implements _i6.NodeService {
|
||||
@override
|
||||
_i2.FlutterSecureStorageInterface get secureStorageInterface =>
|
||||
(super.noSuchMethod(
|
||||
_i2.SecureStorageInterface get secureStorageInterface => (super.noSuchMethod(
|
||||
Invocation.getter(#secureStorageInterface),
|
||||
returnValue: _FakeFlutterSecureStorageInterface_0(
|
||||
this,
|
||||
Invocation.getter(#secureStorageInterface),
|
||||
),
|
||||
) as _i2.FlutterSecureStorageInterface);
|
||||
) as _i2.SecureStorageInterface);
|
||||
@override
|
||||
List<_i7.NodeModel> get primaryNodes => (super.noSuchMethod(
|
||||
Invocation.getter(#primaryNodes),
|
||||
|
|
|
@ -25,7 +25,7 @@ import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'
|
|||
// ignore_for_file: subtype_of_sealed_class
|
||||
|
||||
class _FakeFlutterSecureStorageInterface_0 extends _i1.SmartFake
|
||||
implements _i2.FlutterSecureStorageInterface {
|
||||
implements _i2.SecureStorageInterface {
|
||||
_FakeFlutterSecureStorageInterface_0(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
|
@ -40,14 +40,13 @@ class _FakeFlutterSecureStorageInterface_0 extends _i1.SmartFake
|
|||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
||||
@override
|
||||
_i2.FlutterSecureStorageInterface get secureStorageInterface =>
|
||||
(super.noSuchMethod(
|
||||
_i2.SecureStorageInterface get secureStorageInterface => (super.noSuchMethod(
|
||||
Invocation.getter(#secureStorageInterface),
|
||||
returnValue: _FakeFlutterSecureStorageInterface_0(
|
||||
this,
|
||||
Invocation.getter(#secureStorageInterface),
|
||||
),
|
||||
) as _i2.FlutterSecureStorageInterface);
|
||||
) as _i2.SecureStorageInterface);
|
||||
@override
|
||||
List<_i4.NodeModel> get primaryNodes => (super.noSuchMethod(
|
||||
Invocation.getter(#primaryNodes),
|
||||
|
|
|
@ -139,6 +139,22 @@ class MockCachedElectrumX extends _i1.Mock implements _i6.CachedElectrumX {
|
|||
_i8.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||
) as _i8.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
String base64ToHex(String? source) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#base64ToHex,
|
||||
[source],
|
||||
),
|
||||
returnValue: '',
|
||||
) as String);
|
||||
@override
|
||||
String base64ToReverseHex(String? source) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#base64ToReverseHex,
|
||||
[source],
|
||||
),
|
||||
returnValue: '',
|
||||
) as String);
|
||||
@override
|
||||
_i8.Future<Map<String, dynamic>> getTransaction({
|
||||
required String? txHash,
|
||||
required _i9.Coin? coin,
|
||||
|
|
|
@ -103,7 +103,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
BitcoinWallet? testnetWallet;
|
||||
|
@ -194,7 +194,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
BitcoinWallet? mainnetWallet;
|
||||
|
@ -363,7 +363,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
BitcoinWallet? btc;
|
||||
|
@ -428,7 +428,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
BitcoinWallet? btc;
|
||||
|
@ -640,7 +640,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
BitcoinWallet? btc;
|
||||
|
|
|
@ -465,6 +465,22 @@ class MockCachedElectrumX extends _i1.Mock implements _i7.CachedElectrumX {
|
|||
_i6.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||
) as _i6.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
String base64ToHex(String? source) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#base64ToHex,
|
||||
[source],
|
||||
),
|
||||
returnValue: '',
|
||||
) as String);
|
||||
@override
|
||||
String base64ToReverseHex(String? source) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#base64ToReverseHex,
|
||||
[source],
|
||||
),
|
||||
returnValue: '',
|
||||
) as String);
|
||||
@override
|
||||
_i6.Future<Map<String, dynamic>> getTransaction({
|
||||
required String? txHash,
|
||||
required _i8.Coin? coin,
|
||||
|
|
|
@ -64,7 +64,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
BitcoinCashWallet? mainnetWallet;
|
||||
|
@ -203,7 +203,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
BitcoinCashWallet? mainnetWallet;
|
||||
|
@ -314,7 +314,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
BitcoinCashWallet? bch;
|
||||
|
@ -383,7 +383,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
BitcoinCashWallet? bch;
|
||||
|
@ -606,7 +606,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
BitcoinCashWallet? bch;
|
||||
|
|
|
@ -465,6 +465,22 @@ class MockCachedElectrumX extends _i1.Mock implements _i7.CachedElectrumX {
|
|||
_i6.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||
) as _i6.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
String base64ToHex(String? source) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#base64ToHex,
|
||||
[source],
|
||||
),
|
||||
returnValue: '',
|
||||
) as String);
|
||||
@override
|
||||
String base64ToReverseHex(String? source) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#base64ToReverseHex,
|
||||
[source],
|
||||
),
|
||||
returnValue: '',
|
||||
) as String);
|
||||
@override
|
||||
_i6.Future<Map<String, dynamic>> getTransaction({
|
||||
required String? txHash,
|
||||
required _i8.Coin? coin,
|
||||
|
|
|
@ -97,7 +97,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
DogecoinWallet? mainnetWallet;
|
||||
|
@ -196,7 +196,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
DogecoinWallet? doge;
|
||||
|
@ -266,7 +266,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
DogecoinWallet? doge;
|
||||
|
@ -489,7 +489,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
DogecoinWallet? doge;
|
||||
|
|
|
@ -465,6 +465,22 @@ class MockCachedElectrumX extends _i1.Mock implements _i7.CachedElectrumX {
|
|||
_i6.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||
) as _i6.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
String base64ToHex(String? source) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#base64ToHex,
|
||||
[source],
|
||||
),
|
||||
returnValue: '',
|
||||
) as String);
|
||||
@override
|
||||
String base64ToReverseHex(String? source) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#base64ToReverseHex,
|
||||
[source],
|
||||
),
|
||||
returnValue: '',
|
||||
) as String);
|
||||
@override
|
||||
_i6.Future<Map<String, dynamic>> getTransaction({
|
||||
required String? txHash,
|
||||
required _i8.Coin? coin,
|
||||
|
|
|
@ -465,6 +465,22 @@ class MockCachedElectrumX extends _i1.Mock implements _i7.CachedElectrumX {
|
|||
_i6.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||
) as _i6.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
String base64ToHex(String? source) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#base64ToHex,
|
||||
[source],
|
||||
),
|
||||
returnValue: '',
|
||||
) as String);
|
||||
@override
|
||||
String base64ToReverseHex(String? source) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#base64ToReverseHex,
|
||||
[source],
|
||||
),
|
||||
returnValue: '',
|
||||
) as String);
|
||||
@override
|
||||
_i6.Future<Map<String, dynamic>> getTransaction({
|
||||
required String? txHash,
|
||||
required _i8.Coin? coin,
|
||||
|
|
|
@ -117,6 +117,14 @@ class MockFiroWallet extends _i1.Mock implements _i7.FiroWallet {
|
|||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
set cachedTxData(_i4.TransactionData? _cachedTxData) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#cachedTxData,
|
||||
_cachedTxData,
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
_i2.TransactionNotificationTracker get txTracker => (super.noSuchMethod(
|
||||
Invocation.getter(#txTracker),
|
||||
returnValue: _FakeTransactionNotificationTracker_0(
|
||||
|
@ -375,6 +383,16 @@ class MockFiroWallet extends _i1.Mock implements _i7.FiroWallet {
|
|||
returnValue: false,
|
||||
) as bool);
|
||||
@override
|
||||
_i8.Future<void> updateSentCachedTxData(Map<String, dynamic>? txData) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#updateSentCachedTxData,
|
||||
[txData],
|
||||
),
|
||||
returnValue: _i8.Future<void>.value(),
|
||||
returnValueForMissingStub: _i8.Future<void>.value(),
|
||||
) as _i8.Future<void>);
|
||||
@override
|
||||
_i8.Future<bool> testNetworkConnection() => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#testNetworkConnection,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'dart:core';
|
||||
import 'dart:core' as core;
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
|
@ -19,18 +18,13 @@ import 'package:hive/hive.dart';
|
|||
import 'package:hive_test/hive_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:stackwallet/services/wallets.dart';
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
|
||||
// TODO trim down to the minimum imports above
|
||||
|
||||
import 'monero_wallet_test_data.dart';
|
||||
|
||||
//FlutterSecureStorage? storage;
|
||||
FakeSecureStorage? storage;
|
||||
WalletService? walletService;
|
||||
SharedPreferences? prefs;
|
||||
KeyService? keysStorage;
|
||||
MoneroWalletBase? walletBase;
|
||||
late WalletCreationService _walletCreationService;
|
||||
|
@ -46,7 +40,6 @@ WalletType type = WalletType.monero;
|
|||
@GenerateMocks([])
|
||||
void main() async {
|
||||
storage = FakeSecureStorage();
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
keysStorage = KeyService(storage!);
|
||||
WalletInfo walletInfo = WalletInfo.external(
|
||||
id: '',
|
||||
|
@ -90,12 +83,12 @@ void main() async {
|
|||
final dirPath = await pathForWalletDir(name: name, type: type);
|
||||
path = await pathForWallet(name: name, type: type);
|
||||
credentials =
|
||||
// // creating a new wallet
|
||||
// monero.createMoneroNewWalletCredentials(
|
||||
// name: name, language: "English");
|
||||
// restoring a previous wallet
|
||||
monero.createMoneroRestoreWalletFromSeedCredentials(
|
||||
name: name, height: 2580000, mnemonic: testMnemonic);
|
||||
// // creating a new wallet
|
||||
// monero.createMoneroNewWalletCredentials(
|
||||
// name: name, language: "English");
|
||||
// restoring a previous wallet
|
||||
monero.createMoneroRestoreWalletFromSeedCredentials(
|
||||
name: name, height: 2580000, mnemonic: testMnemonic);
|
||||
|
||||
walletInfo = WalletInfo.external(
|
||||
id: WalletBase.idFor(name, type),
|
||||
|
@ -111,7 +104,6 @@ void main() async {
|
|||
|
||||
_walletCreationService = WalletCreationService(
|
||||
secureStorage: storage,
|
||||
sharedPreferences: prefs,
|
||||
walletService: walletService,
|
||||
keyService: keysStorage,
|
||||
);
|
||||
|
@ -124,8 +116,8 @@ void main() async {
|
|||
|
||||
test("Test mainnet address generation from seed", () async {
|
||||
final wallet = await
|
||||
// _walletCreationService.create(credentials);
|
||||
_walletCreationService.restoreFromSeed(credentials);
|
||||
// _walletCreationService.create(credentials);
|
||||
_walletCreationService.restoreFromSeed(credentials);
|
||||
walletInfo.address = wallet.walletAddresses.address;
|
||||
//print(walletInfo.address);
|
||||
|
||||
|
@ -134,8 +126,7 @@ void main() async {
|
|||
walletBase = wallet as MoneroWalletBase;
|
||||
//print("${walletBase?.seed}");
|
||||
|
||||
expect(
|
||||
await walletBase!.validateAddress(walletInfo.address ?? ''), true);
|
||||
expect(await walletBase!.validateAddress(walletInfo.address ?? ''), true);
|
||||
|
||||
// print(walletBase);
|
||||
// loggerPrint(walletBase.toString());
|
||||
|
@ -157,20 +148,31 @@ void main() async {
|
|||
expect(
|
||||
await walletBase!.getTransactionAddress(1, 2), mainnetTestData[1][2]);
|
||||
|
||||
expect(await walletBase!.validateAddress(''), false);
|
||||
expect(
|
||||
await walletBase!.validateAddress(''), false);
|
||||
await walletBase!.validateAddress(
|
||||
'4AeRgkWZsMJhAWKMeCZ3h4ZSPnAcW5VBtRFyLd6gBEf6GgJU2FHXDA6i1DnQTd6h8R3VU5AkbGcWSNhtSwNNPgaD48gp4nn'),
|
||||
true);
|
||||
expect(
|
||||
await walletBase!.validateAddress('4AeRgkWZsMJhAWKMeCZ3h4ZSPnAcW5VBtRFyLd6gBEf6GgJU2FHXDA6i1DnQTd6h8R3VU5AkbGcWSNhtSwNNPgaD48gp4nn'), true);
|
||||
await walletBase!.validateAddress(
|
||||
'4asdfkWZsMJhAWKMeCZ3h4ZSPnAcW5VBtRFyLd6gBEf6GgJU2FHXDA6i1DnQTd6h8R3VU5AkbGcWSNhtSwNNPgaD48gpjkl'),
|
||||
false);
|
||||
expect(
|
||||
await walletBase!.validateAddress('4asdfkWZsMJhAWKMeCZ3h4ZSPnAcW5VBtRFyLd6gBEf6GgJU2FHXDA6i1DnQTd6h8R3VU5AkbGcWSNhtSwNNPgaD48gpjkl'), false);
|
||||
await walletBase!.validateAddress(
|
||||
'8AeRgkWZsMJhAWKMeCZ3h4ZSPnAcW5VBtRFyLd6gBEf6GgJU2FHXDA6i1DnQTd6h8R3VU5AkbGcWSNhtSwNNPgaD48gp4nn'),
|
||||
false);
|
||||
expect(
|
||||
await walletBase!.validateAddress('8AeRgkWZsMJhAWKMeCZ3h4ZSPnAcW5VBtRFyLd6gBEf6GgJU2FHXDA6i1DnQTd6h8R3VU5AkbGcWSNhtSwNNPgaD48gp4nn'), false);
|
||||
await walletBase!.validateAddress(
|
||||
'84kYPuZ1eaVKGQhf26QPNWbSLQG16BywXdLYYShVrPNMLAUAWce5vcpRc78FxwRphrG6Cda7faCKdUMr8fUCH3peHPenvHy'),
|
||||
true);
|
||||
expect(
|
||||
await walletBase!.validateAddress('84kYPuZ1eaVKGQhf26QPNWbSLQG16BywXdLYYShVrPNMLAUAWce5vcpRc78FxwRphrG6Cda7faCKdUMr8fUCH3peHPenvHy'), true);
|
||||
await walletBase!.validateAddress(
|
||||
'8asdfuZ1eaVKGQhf26QPNWbSLQG16BywXdLYYShVrPNMLAUAWce5vcpRc78FxwRphrG6Cda7faCKdUMr8fUCH3peHPenjkl'),
|
||||
false);
|
||||
expect(
|
||||
await walletBase!.validateAddress('8asdfuZ1eaVKGQhf26QPNWbSLQG16BywXdLYYShVrPNMLAUAWce5vcpRc78FxwRphrG6Cda7faCKdUMr8fUCH3peHPenjkl'), false);
|
||||
expect(
|
||||
await walletBase!.validateAddress('44kYPuZ1eaVKGQhf26QPNWbSLQG16BywXdLYYShVrPNMLAUAWce5vcpRc78FxwRphrG6Cda7faCKdUMr8fUCH3peHPenvHy'), false);
|
||||
await walletBase!.validateAddress(
|
||||
'44kYPuZ1eaVKGQhf26QPNWbSLQG16BywXdLYYShVrPNMLAUAWce5vcpRc78FxwRphrG6Cda7faCKdUMr8fUCH3peHPenvHy'),
|
||||
false);
|
||||
});
|
||||
});
|
||||
/*
|
||||
|
@ -229,6 +231,6 @@ Future<String> pathForWalletDir(
|
|||
}
|
||||
|
||||
Future<String> pathForWallet(
|
||||
{required String name, required WalletType type}) async =>
|
||||
{required String name, required WalletType type}) async =>
|
||||
await pathForWalletDir(name: name, type: type)
|
||||
.then((path) => path + '/$name');
|
||||
|
|
|
@ -103,7 +103,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
NamecoinWallet? mainnetWallet;
|
||||
|
@ -132,7 +132,7 @@ void main() {
|
|||
mainnetWallet?.addressType(
|
||||
address: "N673DDbjPcrNgJmrhJ1xQXF9LLizQzvjEs"),
|
||||
DerivePathType.bip44);
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(tracker);
|
||||
|
@ -144,7 +144,7 @@ void main() {
|
|||
mainnetWallet?.addressType(
|
||||
address: "nc1q6k4x8ye6865z3rc8zkt8gyu52na7njqt6hsk4v"),
|
||||
DerivePathType.bip84);
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(tracker);
|
||||
|
@ -156,7 +156,7 @@ void main() {
|
|||
() => mainnetWallet?.addressType(
|
||||
address: "tb1qzzlm6mnc8k54mx6akehl8p9ray8r439va5ndyq"),
|
||||
throwsArgumentError);
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(tracker);
|
||||
|
@ -168,7 +168,7 @@ void main() {
|
|||
() => mainnetWallet?.addressType(
|
||||
address: "mpMk94ETazqonHutyC1v6ajshgtP8oiFKU"),
|
||||
throwsArgumentError);
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(tracker);
|
||||
|
@ -180,7 +180,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
NamecoinWallet? nmc;
|
||||
|
@ -208,7 +208,7 @@ void main() {
|
|||
when(client?.ping()).thenAnswer((_) async => false);
|
||||
final bool? result = await nmc?.testNetworkConnection();
|
||||
expect(result, false);
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verify(client?.ping()).called(1);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
|
@ -219,7 +219,7 @@ void main() {
|
|||
when(client?.ping()).thenThrow(Exception);
|
||||
final bool? result = await nmc?.testNetworkConnection();
|
||||
expect(result, false);
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verify(client?.ping()).called(1);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
|
@ -230,7 +230,7 @@ void main() {
|
|||
when(client?.ping()).thenAnswer((_) async => true);
|
||||
final bool? result = await nmc?.testNetworkConnection();
|
||||
expect(result, true);
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verify(client?.ping()).called(1);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
|
@ -245,7 +245,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
NamecoinWallet? nmc;
|
||||
|
@ -271,7 +271,7 @@ void main() {
|
|||
|
||||
test("get networkType main", () async {
|
||||
expect(Coin.namecoin, Coin.namecoin);
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(priceAPI);
|
||||
|
@ -289,7 +289,7 @@ void main() {
|
|||
secureStore: secureStore,
|
||||
);
|
||||
expect(Coin.namecoin, Coin.namecoin);
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(priceAPI);
|
||||
|
@ -297,7 +297,7 @@ void main() {
|
|||
|
||||
test("get cryptoCurrency", () async {
|
||||
expect(Coin.namecoin, Coin.namecoin);
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(priceAPI);
|
||||
|
@ -305,7 +305,7 @@ void main() {
|
|||
|
||||
test("get coinName", () async {
|
||||
expect(Coin.namecoin, Coin.namecoin);
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(priceAPI);
|
||||
|
@ -313,7 +313,7 @@ void main() {
|
|||
|
||||
test("get coinTicker", () async {
|
||||
expect(Coin.namecoin, Coin.namecoin);
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(priceAPI);
|
||||
|
@ -323,7 +323,7 @@ void main() {
|
|||
expect(Coin.namecoin, Coin.namecoin);
|
||||
nmc?.walletName = "new name";
|
||||
expect(nmc?.walletName, "new name");
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(priceAPI);
|
||||
|
@ -338,7 +338,7 @@ void main() {
|
|||
expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 1699), 712);
|
||||
expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 2000), 712);
|
||||
expect(nmc?.estimateTxFee(vSize: 356, feeRatePerKB: 12345), 4628);
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(priceAPI);
|
||||
|
@ -372,7 +372,7 @@ void main() {
|
|||
verify(client?.estimateFee(blocks: 1)).called(1);
|
||||
verify(client?.estimateFee(blocks: 5)).called(1);
|
||||
verify(client?.estimateFee(blocks: 20)).called(1);
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(priceAPI);
|
||||
|
@ -409,7 +409,7 @@ void main() {
|
|||
verify(client?.estimateFee(blocks: 1)).called(1);
|
||||
verify(client?.estimateFee(blocks: 5)).called(1);
|
||||
verify(client?.estimateFee(blocks: 20)).called(1);
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(priceAPI);
|
||||
|
@ -440,7 +440,7 @@ void main() {
|
|||
// verify(client?.estimateFee(blocks: 1)).called(1);
|
||||
// verify(client?.estimateFee(blocks: 5)).called(1);
|
||||
// verify(client?.estimateFee(blocks: 20)).called(1);
|
||||
// expect(secureStore?.interactions, 0);
|
||||
// expect(secureStore.interactions, 0);
|
||||
// verifyNoMoreInteractions(client);
|
||||
// verifyNoMoreInteractions(cachedClient);
|
||||
// verifyNoMoreInteractions(tracker);
|
||||
|
@ -457,7 +457,7 @@ void main() {
|
|||
MockElectrumX? client;
|
||||
MockCachedElectrumX? cachedClient;
|
||||
MockPriceAPI? priceAPI;
|
||||
FakeSecureStorage? secureStore;
|
||||
late FakeSecureStorage secureStore;
|
||||
MockTransactionNotificationTracker? tracker;
|
||||
|
||||
NamecoinWallet? nmc;
|
||||
|
@ -504,7 +504,7 @@ void main() {
|
|||
// test("initializeWallet no network", () async {
|
||||
// when(client?.ping()).thenAnswer((_) async => false);
|
||||
// expect(await nmc?.initializeWallet(), false);
|
||||
// expect(secureStore?.interactions, 0);
|
||||
// expect(secureStore.interactions, 0);
|
||||
// verify(client?.ping()).called(1);
|
||||
// verifyNoMoreInteractions(client);
|
||||
// verifyNoMoreInteractions(cachedClient);
|
||||
|
@ -515,7 +515,7 @@ void main() {
|
|||
// when(client?.ping()).thenThrow(Exception("Network connection failed"));
|
||||
// final wallets = await Hive.openBox(testWalletId);
|
||||
// expect(await nmc?.initializeExisting(), false);
|
||||
// expect(secureStore?.interactions, 0);
|
||||
// expect(secureStore.interactions, 0);
|
||||
// verify(client?.ping()).called(1);
|
||||
// verifyNoMoreInteractions(client);
|
||||
// verifyNoMoreInteractions(cachedClient);
|
||||
|
@ -539,7 +539,7 @@ void main() {
|
|||
|
||||
expectLater(() => nmc?.initializeExisting(), throwsA(isA<Exception>()))
|
||||
.then((_) {
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
// verify(client?.ping()).called(1);
|
||||
// verify(client?.getServerFeatures()).called(1);
|
||||
verifyNoMoreInteractions(client);
|
||||
|
@ -560,13 +560,13 @@ void main() {
|
|||
"hash_function": "sha256",
|
||||
"services": []
|
||||
});
|
||||
await secureStore?.write(
|
||||
await secureStore.write(
|
||||
key: "${testWalletId}_mnemonic", value: "some mnemonic");
|
||||
|
||||
final wallets = await Hive.openBox(testWalletId);
|
||||
expectLater(() => nmc?.initializeExisting(), throwsA(isA<Exception>()))
|
||||
.then((_) {
|
||||
expect(secureStore?.interactions, 1);
|
||||
expect(secureStore.interactions, 1);
|
||||
// verify(client?.ping()).called(1);
|
||||
// verify(client?.getServerFeatures()).called(1);
|
||||
verifyNoMoreInteractions(client);
|
||||
|
@ -603,7 +603,7 @@ void main() {
|
|||
|
||||
verify(client?.getServerFeatures()).called(1);
|
||||
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(priceAPI);
|
||||
|
@ -623,7 +623,7 @@ void main() {
|
|||
"services": []
|
||||
});
|
||||
|
||||
await secureStore?.write(
|
||||
await secureStore.write(
|
||||
key: "${testWalletId}_mnemonic", value: "some mnemonic words");
|
||||
|
||||
bool hasThrown = false;
|
||||
|
@ -640,7 +640,7 @@ void main() {
|
|||
|
||||
verify(client?.getServerFeatures()).called(1);
|
||||
|
||||
expect(secureStore?.interactions, 2);
|
||||
expect(secureStore.interactions, 2);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(priceAPI);
|
||||
|
@ -691,10 +691,10 @@ void main() {
|
|||
verify(client?.getBatchHistory(args: historyBatchArgs4)).called(1);
|
||||
verify(client?.getBatchHistory(args: historyBatchArgs5)).called(1);
|
||||
|
||||
expect(secureStore?.interactions, 20);
|
||||
expect(secureStore?.writes, 7);
|
||||
expect(secureStore?.reads, 13);
|
||||
expect(secureStore?.deletes, 0);
|
||||
expect(secureStore.interactions, 20);
|
||||
expect(secureStore.writes, 7);
|
||||
expect(secureStore.reads, 13);
|
||||
expect(secureStore.deletes, 0);
|
||||
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
|
@ -814,10 +814,10 @@ void main() {
|
|||
true);
|
||||
}
|
||||
|
||||
expect(secureStore?.interactions, 14);
|
||||
expect(secureStore?.writes, 7);
|
||||
expect(secureStore?.reads, 7);
|
||||
expect(secureStore?.deletes, 0);
|
||||
expect(secureStore.interactions, 14);
|
||||
expect(secureStore.writes, 7);
|
||||
expect(secureStore.reads, 7);
|
||||
expect(secureStore.deletes, 0);
|
||||
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
|
@ -911,17 +911,17 @@ void main() {
|
|||
final preChangeIndexP2SH = await wallet.get('changeIndexP2SH');
|
||||
final preChangeIndexP2WPKH = await wallet.get('changeIndexP2WPKH');
|
||||
final preUtxoData = await wallet.get('latest_utxo_model');
|
||||
final preReceiveDerivationsStringP2PKH = await secureStore?.read(
|
||||
final preReceiveDerivationsStringP2PKH = await secureStore.read(
|
||||
key: "${testWalletId}_receiveDerivationsP2PKH");
|
||||
final preChangeDerivationsStringP2PKH = await secureStore?.read(
|
||||
key: "${testWalletId}_changeDerivationsP2PKH");
|
||||
final preReceiveDerivationsStringP2SH = await secureStore?.read(
|
||||
key: "${testWalletId}_receiveDerivationsP2SH");
|
||||
final preChangeDerivationsStringP2PKH =
|
||||
await secureStore.read(key: "${testWalletId}_changeDerivationsP2PKH");
|
||||
final preReceiveDerivationsStringP2SH =
|
||||
await secureStore.read(key: "${testWalletId}_receiveDerivationsP2SH");
|
||||
final preChangeDerivationsStringP2SH =
|
||||
await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH");
|
||||
final preReceiveDerivationsStringP2WPKH = await secureStore?.read(
|
||||
await secureStore.read(key: "${testWalletId}_changeDerivationsP2SH");
|
||||
final preReceiveDerivationsStringP2WPKH = await secureStore.read(
|
||||
key: "${testWalletId}_receiveDerivationsP2WPKH");
|
||||
final preChangeDerivationsStringP2WPKH = await secureStore?.read(
|
||||
final preChangeDerivationsStringP2WPKH = await secureStore.read(
|
||||
key: "${testWalletId}_changeDerivationsP2WPKH");
|
||||
|
||||
// destroy the data that the rescan will fix
|
||||
|
@ -943,17 +943,17 @@ void main() {
|
|||
await wallet.put('changeIndexP2PKH', 123);
|
||||
await wallet.put('changeIndexP2SH', 123);
|
||||
await wallet.put('changeIndexP2WPKH', 123);
|
||||
await secureStore?.write(
|
||||
await secureStore.write(
|
||||
key: "${testWalletId}_receiveDerivationsP2PKH", value: "{}");
|
||||
await secureStore?.write(
|
||||
await secureStore.write(
|
||||
key: "${testWalletId}_changeDerivationsP2PKH", value: "{}");
|
||||
await secureStore?.write(
|
||||
await secureStore.write(
|
||||
key: "${testWalletId}_receiveDerivationsP2SH", value: "{}");
|
||||
await secureStore?.write(
|
||||
await secureStore.write(
|
||||
key: "${testWalletId}_changeDerivationsP2SH", value: "{}");
|
||||
await secureStore?.write(
|
||||
await secureStore.write(
|
||||
key: "${testWalletId}_receiveDerivationsP2WPKH", value: "{}");
|
||||
await secureStore?.write(
|
||||
await secureStore.write(
|
||||
key: "${testWalletId}_changeDerivationsP2WPKH", value: "{}");
|
||||
|
||||
bool hasThrown = false;
|
||||
|
@ -980,17 +980,17 @@ void main() {
|
|||
final changeIndexP2SH = await wallet.get('changeIndexP2SH');
|
||||
final changeIndexP2WPKH = await wallet.get('changeIndexP2WPKH');
|
||||
final utxoData = await wallet.get('latest_utxo_model');
|
||||
final receiveDerivationsStringP2PKH = await secureStore?.read(
|
||||
final receiveDerivationsStringP2PKH = await secureStore.read(
|
||||
key: "${testWalletId}_receiveDerivationsP2PKH");
|
||||
final changeDerivationsStringP2PKH = await secureStore?.read(
|
||||
key: "${testWalletId}_changeDerivationsP2PKH");
|
||||
final receiveDerivationsStringP2SH = await secureStore?.read(
|
||||
key: "${testWalletId}_receiveDerivationsP2SH");
|
||||
final changeDerivationsStringP2PKH =
|
||||
await secureStore.read(key: "${testWalletId}_changeDerivationsP2PKH");
|
||||
final receiveDerivationsStringP2SH =
|
||||
await secureStore.read(key: "${testWalletId}_receiveDerivationsP2SH");
|
||||
final changeDerivationsStringP2SH =
|
||||
await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH");
|
||||
final receiveDerivationsStringP2WPKH = await secureStore?.read(
|
||||
await secureStore.read(key: "${testWalletId}_changeDerivationsP2SH");
|
||||
final receiveDerivationsStringP2WPKH = await secureStore.read(
|
||||
key: "${testWalletId}_receiveDerivationsP2WPKH");
|
||||
final changeDerivationsStringP2WPKH = await secureStore?.read(
|
||||
final changeDerivationsStringP2WPKH = await secureStore.read(
|
||||
key: "${testWalletId}_changeDerivationsP2WPKH");
|
||||
|
||||
expect(preReceivingAddressesP2PKH, receivingAddressesP2PKH);
|
||||
|
@ -1082,9 +1082,9 @@ void main() {
|
|||
//
|
||||
// argCount.forEach((key, value) => print("arg: $key\ncount: $value"));
|
||||
|
||||
expect(secureStore?.writes, 25);
|
||||
expect(secureStore?.reads, 32);
|
||||
expect(secureStore?.deletes, 6);
|
||||
expect(secureStore.writes, 25);
|
||||
expect(secureStore.reads, 32);
|
||||
expect(secureStore.deletes, 6);
|
||||
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
|
@ -1182,17 +1182,17 @@ void main() {
|
|||
final preChangeIndexP2SH = await wallet.get('changeIndexP2SH');
|
||||
final preChangeIndexP2WPKH = await wallet.get('changeIndexP2WPKH');
|
||||
final preUtxoData = await wallet.get('latest_utxo_model');
|
||||
final preReceiveDerivationsStringP2PKH = await secureStore?.read(
|
||||
final preReceiveDerivationsStringP2PKH = await secureStore.read(
|
||||
key: "${testWalletId}_receiveDerivationsP2PKH");
|
||||
final preChangeDerivationsStringP2PKH = await secureStore?.read(
|
||||
key: "${testWalletId}_changeDerivationsP2PKH");
|
||||
final preReceiveDerivationsStringP2SH = await secureStore?.read(
|
||||
key: "${testWalletId}_receiveDerivationsP2SH");
|
||||
final preChangeDerivationsStringP2PKH =
|
||||
await secureStore.read(key: "${testWalletId}_changeDerivationsP2PKH");
|
||||
final preReceiveDerivationsStringP2SH =
|
||||
await secureStore.read(key: "${testWalletId}_receiveDerivationsP2SH");
|
||||
final preChangeDerivationsStringP2SH =
|
||||
await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH");
|
||||
final preReceiveDerivationsStringP2WPKH = await secureStore?.read(
|
||||
await secureStore.read(key: "${testWalletId}_changeDerivationsP2SH");
|
||||
final preReceiveDerivationsStringP2WPKH = await secureStore.read(
|
||||
key: "${testWalletId}_receiveDerivationsP2WPKH");
|
||||
final preChangeDerivationsStringP2WPKH = await secureStore?.read(
|
||||
final preChangeDerivationsStringP2WPKH = await secureStore.read(
|
||||
key: "${testWalletId}_changeDerivationsP2WPKH");
|
||||
|
||||
when(client?.getBatchHistory(args: historyBatchArgs0))
|
||||
|
@ -1222,17 +1222,17 @@ void main() {
|
|||
final changeIndexP2SH = await wallet.get('changeIndexP2SH');
|
||||
final changeIndexP2WPKH = await wallet.get('changeIndexP2WPKH');
|
||||
final utxoData = await wallet.get('latest_utxo_model');
|
||||
final receiveDerivationsStringP2PKH = await secureStore?.read(
|
||||
final receiveDerivationsStringP2PKH = await secureStore.read(
|
||||
key: "${testWalletId}_receiveDerivationsP2PKH");
|
||||
final changeDerivationsStringP2PKH = await secureStore?.read(
|
||||
key: "${testWalletId}_changeDerivationsP2PKH");
|
||||
final receiveDerivationsStringP2SH = await secureStore?.read(
|
||||
key: "${testWalletId}_receiveDerivationsP2SH");
|
||||
final changeDerivationsStringP2PKH =
|
||||
await secureStore.read(key: "${testWalletId}_changeDerivationsP2PKH");
|
||||
final receiveDerivationsStringP2SH =
|
||||
await secureStore.read(key: "${testWalletId}_receiveDerivationsP2SH");
|
||||
final changeDerivationsStringP2SH =
|
||||
await secureStore?.read(key: "${testWalletId}_changeDerivationsP2SH");
|
||||
final receiveDerivationsStringP2WPKH = await secureStore?.read(
|
||||
await secureStore.read(key: "${testWalletId}_changeDerivationsP2SH");
|
||||
final receiveDerivationsStringP2WPKH = await secureStore.read(
|
||||
key: "${testWalletId}_receiveDerivationsP2WPKH");
|
||||
final changeDerivationsStringP2WPKH = await secureStore?.read(
|
||||
final changeDerivationsStringP2WPKH = await secureStore.read(
|
||||
key: "${testWalletId}_changeDerivationsP2WPKH");
|
||||
|
||||
expect(preReceivingAddressesP2PKH, receivingAddressesP2PKH);
|
||||
|
@ -1296,9 +1296,9 @@ void main() {
|
|||
verify(cachedClient?.clearSharedTransactionCache(coin: Coin.namecoin))
|
||||
.called(1);
|
||||
|
||||
expect(secureStore?.writes, 19);
|
||||
expect(secureStore?.reads, 32);
|
||||
expect(secureStore?.deletes, 12);
|
||||
expect(secureStore.writes, 19);
|
||||
expect(secureStore.reads, 32);
|
||||
expect(secureStore.deletes, 12);
|
||||
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
|
@ -1366,21 +1366,21 @@ void main() {
|
|||
height: 4000);
|
||||
|
||||
// modify addresses to properly mock data to build a tx
|
||||
final rcv44 = await secureStore?.read(
|
||||
final rcv44 = await secureStore.read(
|
||||
key: testWalletId + "_receiveDerivationsP2PKH");
|
||||
await secureStore?.write(
|
||||
await secureStore.write(
|
||||
key: testWalletId + "_receiveDerivationsP2PKH",
|
||||
value: rcv44?.replaceFirst("1RMSPixoLPuaXuhR2v4HsUMcRjLncKDaw",
|
||||
"16FuTPaeRSPVxxCnwQmdyx2PQWxX6HWzhQ"));
|
||||
final rcv49 = await secureStore?.read(
|
||||
key: testWalletId + "_receiveDerivationsP2SH");
|
||||
await secureStore?.write(
|
||||
final rcv49 =
|
||||
await secureStore.read(key: testWalletId + "_receiveDerivationsP2SH");
|
||||
await secureStore.write(
|
||||
key: testWalletId + "_receiveDerivationsP2SH",
|
||||
value: rcv49?.replaceFirst("3AV74rKfibWmvX34F99yEvUcG4LLQ9jZZk",
|
||||
"36NvZTcMsMowbt78wPzJaHHWaNiyR73Y4g"));
|
||||
final rcv84 = await secureStore?.read(
|
||||
final rcv84 = await secureStore.read(
|
||||
key: testWalletId + "_receiveDerivationsP2WPKH");
|
||||
await secureStore?.write(
|
||||
await secureStore.write(
|
||||
key: testWalletId + "_receiveDerivationsP2WPKH",
|
||||
value: rcv84?.replaceFirst(
|
||||
"bc1qggtj4ka8jsaj44hhd5mpamx7mp34m2d3w7k0m0",
|
||||
|
@ -1436,10 +1436,10 @@ void main() {
|
|||
true);
|
||||
}
|
||||
|
||||
expect(secureStore?.interactions, 20);
|
||||
expect(secureStore?.writes, 10);
|
||||
expect(secureStore?.reads, 10);
|
||||
expect(secureStore?.deletes, 0);
|
||||
expect(secureStore.interactions, 20);
|
||||
expect(secureStore.writes, 10);
|
||||
expect(secureStore.reads, 10);
|
||||
expect(secureStore.deletes, 0);
|
||||
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
|
@ -1456,7 +1456,7 @@ void main() {
|
|||
|
||||
expect(didThrow, true);
|
||||
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(priceAPI);
|
||||
|
@ -1472,7 +1472,7 @@ void main() {
|
|||
|
||||
expect(didThrow, true);
|
||||
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(priceAPI);
|
||||
|
@ -1492,7 +1492,7 @@ void main() {
|
|||
rawTx: "a string", requestID: anyNamed("requestID")))
|
||||
.called(1);
|
||||
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(priceAPI);
|
||||
|
@ -1513,7 +1513,7 @@ void main() {
|
|||
rawTx: "a string", requestID: anyNamed("requestID")))
|
||||
.called(1);
|
||||
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(priceAPI);
|
||||
|
@ -1538,7 +1538,7 @@ void main() {
|
|||
rawTx: "a string", requestID: anyNamed("requestID")))
|
||||
.called(1);
|
||||
|
||||
expect(secureStore?.interactions, 0);
|
||||
expect(secureStore.interactions, 0);
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
verifyNoMoreInteractions(tracker);
|
||||
|
@ -1658,10 +1658,10 @@ void main() {
|
|||
true);
|
||||
}
|
||||
|
||||
expect(secureStore?.interactions, 14);
|
||||
expect(secureStore?.writes, 7);
|
||||
expect(secureStore?.reads, 7);
|
||||
expect(secureStore?.deletes, 0);
|
||||
expect(secureStore.interactions, 14);
|
||||
expect(secureStore.writes, 7);
|
||||
expect(secureStore.reads, 7);
|
||||
expect(secureStore.deletes, 0);
|
||||
|
||||
verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
|
@ -1726,10 +1726,10 @@ void main() {
|
|||
verify(client?.getBatchHistory(args: map)).called(1);
|
||||
}
|
||||
|
||||
expect(secureStore?.interactions, 14);
|
||||
expect(secureStore?.writes, 7);
|
||||
expect(secureStore?.reads, 7);
|
||||
expect(secureStore?.deletes, 0);
|
||||
expect(secureStore.interactions, 14);
|
||||
expect(secureStore.writes, 7);
|
||||
expect(secureStore.reads, 7);
|
||||
expect(secureStore.deletes, 0);
|
||||
|
||||
// verifyNoMoreInteractions(client);
|
||||
verifyNoMoreInteractions(cachedClient);
|
||||
|
|
|
@ -465,6 +465,22 @@ class MockCachedElectrumX extends _i1.Mock implements _i7.CachedElectrumX {
|
|||
_i6.Future<Map<String, dynamic>>.value(<String, dynamic>{}),
|
||||
) as _i6.Future<Map<String, dynamic>>);
|
||||
@override
|
||||
String base64ToHex(String? source) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#base64ToHex,
|
||||
[source],
|
||||
),
|
||||
returnValue: '',
|
||||
) as String);
|
||||
@override
|
||||
String base64ToReverseHex(String? source) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#base64ToReverseHex,
|
||||
[source],
|
||||
),
|
||||
returnValue: '',
|
||||
) as String);
|
||||
@override
|
||||
_i6.Future<Map<String, dynamic>> getTransaction({
|
||||
required String? txHash,
|
||||
required _i8.Coin? coin,
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'dart:core';
|
||||
import 'dart:core' as core;
|
||||
import 'dart:io';
|
||||
import 'dart:math';
|
||||
|
||||
|
@ -19,14 +18,12 @@ import 'package:hive/hive.dart';
|
|||
import 'package:hive_test/hive_test.dart';
|
||||
import 'package:mockito/annotations.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
import 'package:shared_preferences/shared_preferences.dart';
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart';
|
||||
|
||||
import 'wownero_wallet_test_data.dart';
|
||||
|
||||
FakeSecureStorage? storage;
|
||||
WalletService? walletService;
|
||||
SharedPreferences? prefs;
|
||||
KeyService? keysStorage;
|
||||
WowneroWalletBase? walletBase;
|
||||
late WalletCreationService _walletCreationService;
|
||||
|
@ -41,7 +38,6 @@ WalletType type = WalletType.wownero;
|
|||
@GenerateMocks([])
|
||||
void main() async {
|
||||
storage = FakeSecureStorage();
|
||||
prefs = await SharedPreferences.getInstance();
|
||||
keysStorage = KeyService(storage!);
|
||||
WalletInfo walletInfo = WalletInfo.external(
|
||||
id: '',
|
||||
|
@ -102,7 +98,6 @@ void main() async {
|
|||
|
||||
_walletCreationService = WalletCreationService(
|
||||
secureStorage: storage,
|
||||
sharedPreferences: prefs,
|
||||
walletService: walletService,
|
||||
keyService: keysStorage,
|
||||
);
|
||||
|
@ -127,19 +122,24 @@ void main() async {
|
|||
walletBase = wallet as WowneroWalletBase;
|
||||
|
||||
expect(
|
||||
await walletBase!.validateAddress(wallet.walletAddresses.address ?? ''), true);
|
||||
await walletBase!
|
||||
.validateAddress(wallet.walletAddresses.address ?? ''),
|
||||
true);
|
||||
} catch (_) {
|
||||
hasThrown = true;
|
||||
}
|
||||
expect(hasThrown, false);
|
||||
|
||||
// Address validation
|
||||
expect(await walletBase!.validateAddress(''), false);
|
||||
expect(
|
||||
await walletBase!.validateAddress(''), false);
|
||||
await walletBase!.validateAddress(
|
||||
'Wo3jmHvTMLwE6h29fpgcb8PbJSpaKuqM7XTXVfiiu8bLCZsJvrQCbQSJR48Vo3BWNQKsMsXZ4VixndXTH25QtorC27NCjmsEi'),
|
||||
true);
|
||||
expect(
|
||||
await walletBase!.validateAddress('Wo3jmHvTMLwE6h29fpgcb8PbJSpaKuqM7XTXVfiiu8bLCZsJvrQCbQSJR48Vo3BWNQKsMsXZ4VixndXTH25QtorC27NCjmsEi'), true);
|
||||
expect(
|
||||
await walletBase!.validateAddress('WasdfHvTMLwE6h29fpgcb8PbJSpaKuqM7XTXVfiiu8bLCZsJvrQCbQSJR48Vo3BWNQKsMsXZ4VixndXTH25QtorC27NCjmjkl'), false);
|
||||
await walletBase!.validateAddress(
|
||||
'WasdfHvTMLwE6h29fpgcb8PbJSpaKuqM7XTXVfiiu8bLCZsJvrQCbQSJR48Vo3BWNQKsMsXZ4VixndXTH25QtorC27NCjmjkl'),
|
||||
false);
|
||||
|
||||
walletBase?.close();
|
||||
walletBase = wallet as WowneroWalletBase;
|
||||
|
@ -174,7 +174,6 @@ void main() async {
|
|||
|
||||
_walletCreationService = WalletCreationService(
|
||||
secureStorage: storage,
|
||||
sharedPreferences: prefs,
|
||||
walletService: walletService,
|
||||
keyService: keysStorage,
|
||||
);
|
||||
|
@ -248,7 +247,6 @@ void main() async {
|
|||
|
||||
_walletCreationService = WalletCreationService(
|
||||
secureStorage: storage,
|
||||
sharedPreferences: prefs,
|
||||
walletService: walletService,
|
||||
keyService: keysStorage,
|
||||
);
|
||||
|
@ -312,7 +310,6 @@ void main() async {
|
|||
|
||||
_walletCreationService = WalletCreationService(
|
||||
secureStorage: storage,
|
||||
sharedPreferences: prefs,
|
||||
walletService: walletService,
|
||||
keyService: keysStorage,
|
||||
);
|
||||
|
@ -367,6 +364,6 @@ Future<String> pathForWalletDir(
|
|||
}
|
||||
|
||||
Future<String> pathForWallet(
|
||||
{required String name, required WalletType type}) async =>
|
||||
{required String name, required WalletType type}) async =>
|
||||
await pathForWalletDir(name: name, type: type)
|
||||
.then((path) => path + '/$name');
|
||||
|
|
|
@ -141,7 +141,8 @@ void main() {
|
|||
);
|
||||
|
||||
setUp(() async {
|
||||
await NodeService().updateDefaults();
|
||||
await NodeService(secureStorageInterface: FakeSecureStorage())
|
||||
.updateDefaults();
|
||||
});
|
||||
|
||||
test("setPrimaryNodeFor and getPrimaryNodeFor", () async {
|
||||
|
|
|
@ -32,7 +32,7 @@ void main() {
|
|||
});
|
||||
|
||||
test("get walletNames", () async {
|
||||
final service = WalletsService();
|
||||
final service = WalletsService(secureStorageInterface: FakeSecureStorage());
|
||||
expect((await service.walletNames).toString(),
|
||||
'{wallet_id: WalletInfo: {"name":"My Firo Wallet","id":"wallet_id","coin":"bitcoin"}, wallet_id2: WalletInfo: {"name":"wallet2","id":"wallet_id2","coin":"bitcoin"}}');
|
||||
});
|
||||
|
@ -40,13 +40,13 @@ void main() {
|
|||
test("get null wallet names", () async {
|
||||
final wallets = await Hive.openBox<dynamic>('wallets');
|
||||
await wallets.put('names', null);
|
||||
final service = WalletsService();
|
||||
final service = WalletsService(secureStorageInterface: FakeSecureStorage());
|
||||
expect(await service.walletNames, <String, WalletInfo>{});
|
||||
expect((await service.walletNames).toString(), '{}');
|
||||
});
|
||||
|
||||
test("rename wallet to same name", () async {
|
||||
final service = WalletsService();
|
||||
final service = WalletsService(secureStorageInterface: FakeSecureStorage());
|
||||
expect(
|
||||
await service.renameWallet(
|
||||
from: "My Firo Wallet",
|
||||
|
@ -58,7 +58,7 @@ void main() {
|
|||
});
|
||||
|
||||
test("rename wallet to new name", () async {
|
||||
final service = WalletsService();
|
||||
final service = WalletsService(secureStorageInterface: FakeSecureStorage());
|
||||
expect(
|
||||
await service.renameWallet(
|
||||
from: "My Firo Wallet",
|
||||
|
@ -71,7 +71,7 @@ void main() {
|
|||
});
|
||||
|
||||
test("attempt rename wallet to another existing name", () async {
|
||||
final service = WalletsService();
|
||||
final service = WalletsService(secureStorageInterface: FakeSecureStorage());
|
||||
expect(
|
||||
await service.renameWallet(
|
||||
from: "My Firo Wallet",
|
||||
|
@ -83,7 +83,7 @@ void main() {
|
|||
});
|
||||
|
||||
test("add new wallet name", () async {
|
||||
final service = WalletsService();
|
||||
final service = WalletsService(secureStorageInterface: FakeSecureStorage());
|
||||
expect(
|
||||
await service.addNewWallet(
|
||||
name: "wallet3", coin: Coin.bitcoin, shouldNotifyListeners: false),
|
||||
|
@ -92,7 +92,7 @@ void main() {
|
|||
});
|
||||
|
||||
test("add duplicate wallet name fails", () async {
|
||||
final service = WalletsService();
|
||||
final service = WalletsService(secureStorageInterface: FakeSecureStorage());
|
||||
expect(
|
||||
await service.addNewWallet(
|
||||
name: "wallet2", coin: Coin.bitcoin, shouldNotifyListeners: false),
|
||||
|
@ -103,27 +103,27 @@ void main() {
|
|||
test("check for duplicates when null names", () async {
|
||||
final wallets = await Hive.openBox<dynamic>('wallets');
|
||||
await wallets.put('names', null);
|
||||
final service = WalletsService();
|
||||
final service = WalletsService(secureStorageInterface: FakeSecureStorage());
|
||||
expect(await service.checkForDuplicate("anything"), false);
|
||||
});
|
||||
|
||||
test("check for duplicates when some names with no matches", () async {
|
||||
final service = WalletsService();
|
||||
final service = WalletsService(secureStorageInterface: FakeSecureStorage());
|
||||
expect(await service.checkForDuplicate("anything"), false);
|
||||
});
|
||||
|
||||
test("check for duplicates when some names with a match", () async {
|
||||
final service = WalletsService();
|
||||
final service = WalletsService(secureStorageInterface: FakeSecureStorage());
|
||||
expect(await service.checkForDuplicate("wallet2"), true);
|
||||
});
|
||||
|
||||
test("get existing wallet id", () async {
|
||||
final service = WalletsService();
|
||||
final service = WalletsService(secureStorageInterface: FakeSecureStorage());
|
||||
expect(await service.getWalletId("wallet2"), "wallet_id2");
|
||||
});
|
||||
|
||||
test("get non existent wallet id", () async {
|
||||
final service = WalletsService();
|
||||
final service = WalletsService(secureStorageInterface: FakeSecureStorage());
|
||||
expectLater(await service.getWalletId("wallet 99"), null);
|
||||
});
|
||||
|
||||
|
|
|
@ -3,12 +3,12 @@
|
|||
// Do not manually edit this file.
|
||||
|
||||
// ignore_for_file: no_leading_underscores_for_library_prefixes
|
||||
import 'dart:async' as _i4;
|
||||
import 'dart:async' as _i3;
|
||||
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart' as _i2;
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart' as _i4;
|
||||
import 'package:mockito/mockito.dart' as _i1;
|
||||
import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'
|
||||
as _i3;
|
||||
as _i2;
|
||||
|
||||
// ignore_for_file: type=lint
|
||||
// ignore_for_file: avoid_redundant_argument_values
|
||||
|
@ -21,43 +21,24 @@ import 'package:stackwallet/utilities/flutter_secure_storage_interface.dart'
|
|||
// ignore_for_file: camel_case_types
|
||||
// ignore_for_file: subtype_of_sealed_class
|
||||
|
||||
class _FakeFlutterSecureStorage_0 extends _i1.SmartFake
|
||||
implements _i2.FlutterSecureStorage {
|
||||
_FakeFlutterSecureStorage_0(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
) : super(
|
||||
parent,
|
||||
parentInvocation,
|
||||
);
|
||||
}
|
||||
|
||||
/// A class which mocks [SecureStorageWrapper].
|
||||
///
|
||||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockSecureStorageWrapper extends _i1.Mock
|
||||
implements _i3.SecureStorageWrapper {
|
||||
implements _i2.SecureStorageWrapper {
|
||||
MockSecureStorageWrapper() {
|
||||
_i1.throwOnMissingStub(this);
|
||||
}
|
||||
|
||||
@override
|
||||
_i2.FlutterSecureStorage get secureStore => (super.noSuchMethod(
|
||||
Invocation.getter(#secureStore),
|
||||
returnValue: _FakeFlutterSecureStorage_0(
|
||||
this,
|
||||
Invocation.getter(#secureStore),
|
||||
),
|
||||
) as _i2.FlutterSecureStorage);
|
||||
@override
|
||||
_i4.Future<String?> read({
|
||||
_i3.Future<String?> read({
|
||||
required String? key,
|
||||
_i2.IOSOptions? iOptions,
|
||||
_i2.AndroidOptions? aOptions,
|
||||
_i2.LinuxOptions? lOptions,
|
||||
_i2.WebOptions? webOptions,
|
||||
_i2.MacOsOptions? mOptions,
|
||||
_i2.WindowsOptions? wOptions,
|
||||
_i4.IOSOptions? iOptions,
|
||||
_i4.AndroidOptions? aOptions,
|
||||
_i4.LinuxOptions? lOptions,
|
||||
_i4.WebOptions? webOptions,
|
||||
_i4.MacOsOptions? mOptions,
|
||||
_i4.WindowsOptions? wOptions,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
|
@ -73,18 +54,18 @@ class MockSecureStorageWrapper extends _i1.Mock
|
|||
#wOptions: wOptions,
|
||||
},
|
||||
),
|
||||
returnValue: _i4.Future<String?>.value(),
|
||||
) as _i4.Future<String?>);
|
||||
returnValue: _i3.Future<String?>.value(),
|
||||
) as _i3.Future<String?>);
|
||||
@override
|
||||
_i4.Future<void> write({
|
||||
_i3.Future<void> write({
|
||||
required String? key,
|
||||
required String? value,
|
||||
_i2.IOSOptions? iOptions,
|
||||
_i2.AndroidOptions? aOptions,
|
||||
_i2.LinuxOptions? lOptions,
|
||||
_i2.WebOptions? webOptions,
|
||||
_i2.MacOsOptions? mOptions,
|
||||
_i2.WindowsOptions? wOptions,
|
||||
_i4.IOSOptions? iOptions,
|
||||
_i4.AndroidOptions? aOptions,
|
||||
_i4.LinuxOptions? lOptions,
|
||||
_i4.WebOptions? webOptions,
|
||||
_i4.MacOsOptions? mOptions,
|
||||
_i4.WindowsOptions? wOptions,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
|
@ -101,18 +82,18 @@ class MockSecureStorageWrapper extends _i1.Mock
|
|||
#wOptions: wOptions,
|
||||
},
|
||||
),
|
||||
returnValue: _i4.Future<void>.value(),
|
||||
returnValueForMissingStub: _i4.Future<void>.value(),
|
||||
) as _i4.Future<void>);
|
||||
returnValue: _i3.Future<void>.value(),
|
||||
returnValueForMissingStub: _i3.Future<void>.value(),
|
||||
) as _i3.Future<void>);
|
||||
@override
|
||||
_i4.Future<void> delete({
|
||||
_i3.Future<void> delete({
|
||||
required String? key,
|
||||
_i2.IOSOptions? iOptions,
|
||||
_i2.AndroidOptions? aOptions,
|
||||
_i2.LinuxOptions? lOptions,
|
||||
_i2.WebOptions? webOptions,
|
||||
_i2.MacOsOptions? mOptions,
|
||||
_i2.WindowsOptions? wOptions,
|
||||
_i4.IOSOptions? iOptions,
|
||||
_i4.AndroidOptions? aOptions,
|
||||
_i4.LinuxOptions? lOptions,
|
||||
_i4.WebOptions? webOptions,
|
||||
_i4.MacOsOptions? mOptions,
|
||||
_i4.WindowsOptions? wOptions,
|
||||
}) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
|
@ -128,7 +109,7 @@ class MockSecureStorageWrapper extends _i1.Mock
|
|||
#wOptions: wOptions,
|
||||
},
|
||||
),
|
||||
returnValue: _i4.Future<void>.value(),
|
||||
returnValueForMissingStub: _i4.Future<void>.value(),
|
||||
) as _i4.Future<void>);
|
||||
returnValue: _i3.Future<void>.value(),
|
||||
returnValueForMissingStub: _i3.Future<void>.value(),
|
||||
) as _i3.Future<void>);
|
||||
}
|
||||
|
|
|
@ -166,7 +166,7 @@ class _FakeElectrumXNode_11 extends _i1.SmartFake
|
|||
}
|
||||
|
||||
class _FakeFlutterSecureStorageInterface_12 extends _i1.SmartFake
|
||||
implements _i12.FlutterSecureStorageInterface {
|
||||
implements _i12.SecureStorageInterface {
|
||||
_FakeFlutterSecureStorageInterface_12(
|
||||
Object parent,
|
||||
Invocation parentInvocation,
|
||||
|
@ -681,6 +681,14 @@ class MockBitcoinWallet extends _i1.Mock implements _i19.BitcoinWallet {
|
|||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
set cachedTxData(_i8.TransactionData? _cachedTxData) => super.noSuchMethod(
|
||||
Invocation.setter(
|
||||
#cachedTxData,
|
||||
_cachedTxData,
|
||||
),
|
||||
returnValueForMissingStub: null,
|
||||
);
|
||||
@override
|
||||
bool get isActive => (super.noSuchMethod(
|
||||
Invocation.getter(#isActive),
|
||||
returnValue: false,
|
||||
|
@ -1063,6 +1071,16 @@ class MockBitcoinWallet extends _i1.Mock implements _i19.BitcoinWallet {
|
|||
returnValueForMissingStub: _i16.Future<void>.value(),
|
||||
) as _i16.Future<void>);
|
||||
@override
|
||||
_i16.Future<void> updateSentCachedTxData(Map<String, dynamic>? txData) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#updateSentCachedTxData,
|
||||
[txData],
|
||||
),
|
||||
returnValue: _i16.Future<void>.value(),
|
||||
returnValueForMissingStub: _i16.Future<void>.value(),
|
||||
) as _i16.Future<void>);
|
||||
@override
|
||||
bool validateAddress(String? address) => (super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#validateAddress,
|
||||
|
@ -1380,14 +1398,13 @@ class MockLocaleService extends _i1.Mock implements _i20.LocaleService {
|
|||
/// See the documentation for Mockito's code generation for more information.
|
||||
class MockNodeService extends _i1.Mock implements _i3.NodeService {
|
||||
@override
|
||||
_i12.FlutterSecureStorageInterface get secureStorageInterface =>
|
||||
(super.noSuchMethod(
|
||||
_i12.SecureStorageInterface get secureStorageInterface => (super.noSuchMethod(
|
||||
Invocation.getter(#secureStorageInterface),
|
||||
returnValue: _FakeFlutterSecureStorageInterface_12(
|
||||
this,
|
||||
Invocation.getter(#secureStorageInterface),
|
||||
),
|
||||
) as _i12.FlutterSecureStorageInterface);
|
||||
) as _i12.SecureStorageInterface);
|
||||
@override
|
||||
List<_i21.NodeModel> get primaryNodes => (super.noSuchMethod(
|
||||
Invocation.getter(#primaryNodes),
|
||||
|
@ -2291,4 +2308,14 @@ class MockCoinServiceAPI extends _i1.Mock implements _i13.CoinServiceAPI {
|
|||
),
|
||||
returnValue: _i16.Future<bool>.value(false),
|
||||
) as _i16.Future<bool>);
|
||||
@override
|
||||
_i16.Future<void> updateSentCachedTxData(Map<String, dynamic>? txData) =>
|
||||
(super.noSuchMethod(
|
||||
Invocation.method(
|
||||
#updateSentCachedTxData,
|
||||
[txData],
|
||||
),
|
||||
returnValue: _i16.Future<void>.value(),
|
||||
returnValueForMissingStub: _i16.Future<void>.value(),
|
||||
) as _i16.Future<void>);
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue