mirror of
https://github.com/cypherstack/stack_wallet.git
synced 2024-12-22 19:39:22 +00:00
Show old campfire wallets
This commit is contained in:
parent
929e334063
commit
29708b1534
10 changed files with 426 additions and 109 deletions
|
@ -8,7 +8,6 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
import 'package:tuple/tuple.dart';
|
||||
|
||||
|
@ -40,14 +39,18 @@ class DbVersionMigrator with WalletDB {
|
|||
int fromVersion, {
|
||||
required SecureStorageInterface secureStore,
|
||||
}) async {
|
||||
if (AppConfig.appName == "Campfire" && fromVersion < 12) {
|
||||
// safe to skip to v11 for campfire
|
||||
fromVersion = 11;
|
||||
}
|
||||
Logging.instance.log(
|
||||
"Running migrate fromVersion $fromVersion",
|
||||
level: LogLevel.Warning,
|
||||
);
|
||||
switch (fromVersion) {
|
||||
case 0:
|
||||
await Hive.openBox<dynamic>(DB.boxNameAllWalletsData);
|
||||
await Hive.openBox<dynamic>(DB.boxNamePrefs);
|
||||
await DB.instance.hive.openBox<dynamic>(DB.boxNameAllWalletsData);
|
||||
await DB.instance.hive.openBox<dynamic>(DB.boxNamePrefs);
|
||||
final walletsService = WalletsService();
|
||||
final nodeService = NodeService(secureStorageInterface: secureStore);
|
||||
final prefs = Prefs.instance;
|
||||
|
@ -61,8 +64,8 @@ class DbVersionMigrator with WalletDB {
|
|||
// only instantiate client if there are firo wallets
|
||||
if (walletInfoList.values
|
||||
.any((element) => element.coinIdentifier == firo.identifier)) {
|
||||
await Hive.openBox<NodeModel>(DB.boxNameNodeModels);
|
||||
await Hive.openBox<NodeModel>(DB.boxNamePrimaryNodes);
|
||||
await DB.instance.hive.openBox<NodeModel>(DB.boxNameNodeModels);
|
||||
await DB.instance.hive.openBox<NodeModel>(DB.boxNamePrimaryNodes);
|
||||
final node =
|
||||
nodeService.getPrimaryNodeFor(currency: firo) ?? firo.defaultNode;
|
||||
final List<ElectrumXNode> failovers = nodeService
|
||||
|
@ -106,7 +109,7 @@ class DbVersionMigrator with WalletDB {
|
|||
for (final walletInfo in walletInfoList.values) {
|
||||
// migrate each firo wallet's lelantus coins
|
||||
if (walletInfo.coinIdentifier == firo.identifier) {
|
||||
await Hive.openBox<dynamic>(walletInfo.walletId);
|
||||
await DB.instance.hive.openBox<dynamic>(walletInfo.walletId);
|
||||
final _lelantusCoins = DB.instance.get<dynamic>(
|
||||
boxName: walletInfo.walletId,
|
||||
key: '_lelantus_coins',
|
||||
|
@ -157,8 +160,8 @@ class DbVersionMigrator with WalletDB {
|
|||
return await migrate(1, secureStore: secureStore);
|
||||
|
||||
case 1:
|
||||
await Hive.openBox<ExchangeTransaction>(DB.boxNameTrades);
|
||||
await Hive.openBox<Trade>(DB.boxNameTradesV2);
|
||||
await DB.instance.hive.openBox<ExchangeTransaction>(DB.boxNameTrades);
|
||||
await DB.instance.hive.openBox<Trade>(DB.boxNameTradesV2);
|
||||
final trades =
|
||||
DB.instance.values<ExchangeTransaction>(boxName: DB.boxNameTrades);
|
||||
|
||||
|
@ -184,7 +187,7 @@ class DbVersionMigrator with WalletDB {
|
|||
return await migrate(2, secureStore: secureStore);
|
||||
|
||||
case 2:
|
||||
await Hive.openBox<dynamic>(DB.boxNamePrefs);
|
||||
await DB.instance.hive.openBox<dynamic>(DB.boxNamePrefs);
|
||||
final prefs = Prefs.instance;
|
||||
await prefs.init();
|
||||
if (!(await prefs.isExternalCallsSet())) {
|
||||
|
@ -233,8 +236,8 @@ class DbVersionMigrator with WalletDB {
|
|||
|
||||
case 5:
|
||||
// migrate
|
||||
await Hive.openBox<dynamic>("theme");
|
||||
await Hive.openBox<dynamic>(DB.boxNamePrefs);
|
||||
await DB.instance.hive.openBox<dynamic>("theme");
|
||||
await DB.instance.hive.openBox<dynamic>(DB.boxNamePrefs);
|
||||
|
||||
final themeName =
|
||||
DB.instance.get<dynamic>(boxName: "theme", key: "colorScheme")
|
||||
|
@ -347,7 +350,7 @@ class DbVersionMigrator with WalletDB {
|
|||
|
||||
case 8:
|
||||
// migrate
|
||||
await Hive.openBox<dynamic>(DB.boxNameAllWalletsData);
|
||||
await DB.instance.hive.openBox<dynamic>(DB.boxNameAllWalletsData);
|
||||
final walletsService = WalletsService();
|
||||
final walletInfoList = await walletsService.walletNames;
|
||||
await MainDB.instance.initMainDB();
|
||||
|
@ -443,8 +446,8 @@ class DbVersionMigrator with WalletDB {
|
|||
}
|
||||
|
||||
Future<void> _v4(SecureStorageInterface secureStore) async {
|
||||
await Hive.openBox<dynamic>(DB.boxNameAllWalletsData);
|
||||
await Hive.openBox<dynamic>(DB.boxNamePrefs);
|
||||
await DB.instance.hive.openBox<dynamic>(DB.boxNameAllWalletsData);
|
||||
await DB.instance.hive.openBox<dynamic>(DB.boxNamePrefs);
|
||||
final walletsService = WalletsService();
|
||||
final prefs = Prefs.instance;
|
||||
final walletInfoList = await walletsService.walletNames;
|
||||
|
@ -455,7 +458,7 @@ class DbVersionMigrator with WalletDB {
|
|||
final info = walletInfoList[walletId]!;
|
||||
assert(info.walletId == walletId);
|
||||
|
||||
final walletBox = await Hive.openBox<dynamic>(info.walletId);
|
||||
final walletBox = await DB.instance.hive.openBox<dynamic>(info.walletId);
|
||||
|
||||
const receiveAddressesPrefix = "receivingAddresses";
|
||||
const changeAddressesPrefix = "changeAddresses";
|
||||
|
@ -560,7 +563,7 @@ class DbVersionMigrator with WalletDB {
|
|||
}
|
||||
|
||||
Future<void> _v7(SecureStorageInterface secureStore) async {
|
||||
await Hive.openBox<dynamic>(DB.boxNameAllWalletsData);
|
||||
await DB.instance.hive.openBox<dynamic>(DB.boxNameAllWalletsData);
|
||||
final walletsService = WalletsService();
|
||||
final walletInfoList = await walletsService.walletNames;
|
||||
await MainDB.instance.initMainDB();
|
||||
|
@ -601,7 +604,8 @@ class DbVersionMigrator with WalletDB {
|
|||
}
|
||||
|
||||
Future<void> _v9() async {
|
||||
final addressBookBox = await Hive.openBox<dynamic>(DB.boxNameAddressBook);
|
||||
final addressBookBox =
|
||||
await DB.instance.hive.openBox<dynamic>(DB.boxNameAddressBook);
|
||||
await MainDB.instance.initMainDB();
|
||||
|
||||
final keys = List<String>.from(addressBookBox.keys);
|
||||
|
@ -649,8 +653,8 @@ class DbVersionMigrator with WalletDB {
|
|||
}
|
||||
|
||||
Future<void> _v10(SecureStorageInterface secureStore) async {
|
||||
await Hive.openBox<dynamic>(DB.boxNameAllWalletsData);
|
||||
await Hive.openBox<dynamic>(DB.boxNamePrefs);
|
||||
await DB.instance.hive.openBox<dynamic>(DB.boxNameAllWalletsData);
|
||||
await DB.instance.hive.openBox<dynamic>(DB.boxNamePrefs);
|
||||
final walletsService = WalletsService();
|
||||
final prefs = Prefs.instance;
|
||||
final walletInfoList = await walletsService.walletNames;
|
||||
|
@ -669,7 +673,7 @@ class DbVersionMigrator with WalletDB {
|
|||
.walletIdEqualTo(walletId)
|
||||
.countSync() ==
|
||||
0) {
|
||||
final walletBox = await Hive.openBox<dynamic>(walletId);
|
||||
final walletBox = await DB.instance.hive.openBox<dynamic>(walletId);
|
||||
|
||||
final hiveLCoins = DB.instance.get<dynamic>(
|
||||
boxName: walletId,
|
||||
|
|
|
@ -11,7 +11,8 @@
|
|||
import 'dart:isolate';
|
||||
|
||||
import 'package:cw_core/wallet_info.dart' as xmr;
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:hive/hive.dart' show Box;
|
||||
import 'package:hive/src/hive_impl.dart';
|
||||
import 'package:mutex/mutex.dart';
|
||||
|
||||
import '../../app_config.dart';
|
||||
|
@ -24,6 +25,8 @@ import '../../utilities/logger.dart';
|
|||
import '../../wallets/crypto_currency/crypto_currency.dart';
|
||||
|
||||
class DB {
|
||||
final hive = HiveImpl();
|
||||
|
||||
// legacy (required for migrations)
|
||||
@Deprecated("Left over for migration from old versions of Stack Wallet")
|
||||
static const String boxNameAddressBook = "addressBook";
|
||||
|
@ -104,52 +107,52 @@ class DB {
|
|||
|
||||
// open hive boxes
|
||||
Future<void> init() async {
|
||||
if (Hive.isBoxOpen(boxNameDBInfo)) {
|
||||
_boxDBInfo = Hive.box<dynamic>(boxNameDBInfo);
|
||||
if (hive.isBoxOpen(boxNameDBInfo)) {
|
||||
_boxDBInfo = hive.box<dynamic>(boxNameDBInfo);
|
||||
} else {
|
||||
_boxDBInfo = await Hive.openBox<dynamic>(boxNameDBInfo);
|
||||
_boxDBInfo = await hive.openBox<dynamic>(boxNameDBInfo);
|
||||
}
|
||||
await Hive.openBox<String>(boxNameWalletsToDeleteOnStart);
|
||||
await hive.openBox<String>(boxNameWalletsToDeleteOnStart);
|
||||
|
||||
if (Hive.isBoxOpen(boxNamePrefs)) {
|
||||
_boxPrefs = Hive.box<dynamic>(boxNamePrefs);
|
||||
if (hive.isBoxOpen(boxNamePrefs)) {
|
||||
_boxPrefs = hive.box<dynamic>(boxNamePrefs);
|
||||
} else {
|
||||
_boxPrefs = await Hive.openBox<dynamic>(boxNamePrefs);
|
||||
_boxPrefs = await hive.openBox<dynamic>(boxNamePrefs);
|
||||
}
|
||||
|
||||
if (Hive.isBoxOpen(boxNameNodeModels)) {
|
||||
_boxNodeModels = Hive.box<NodeModel>(boxNameNodeModels);
|
||||
if (hive.isBoxOpen(boxNameNodeModels)) {
|
||||
_boxNodeModels = hive.box<NodeModel>(boxNameNodeModels);
|
||||
} else {
|
||||
_boxNodeModels = await Hive.openBox<NodeModel>(boxNameNodeModels);
|
||||
_boxNodeModels = await hive.openBox<NodeModel>(boxNameNodeModels);
|
||||
}
|
||||
|
||||
if (Hive.isBoxOpen(boxNamePrimaryNodes)) {
|
||||
_boxPrimaryNodes = Hive.box<NodeModel>(boxNamePrimaryNodes);
|
||||
if (hive.isBoxOpen(boxNamePrimaryNodes)) {
|
||||
_boxPrimaryNodes = hive.box<NodeModel>(boxNamePrimaryNodes);
|
||||
} else {
|
||||
_boxPrimaryNodes = await Hive.openBox<NodeModel>(boxNamePrimaryNodes);
|
||||
_boxPrimaryNodes = await hive.openBox<NodeModel>(boxNamePrimaryNodes);
|
||||
}
|
||||
|
||||
if (Hive.isBoxOpen(boxNameAllWalletsData)) {
|
||||
_boxAllWalletsData = Hive.box<dynamic>(boxNameAllWalletsData);
|
||||
if (hive.isBoxOpen(boxNameAllWalletsData)) {
|
||||
_boxAllWalletsData = hive.box<dynamic>(boxNameAllWalletsData);
|
||||
} else {
|
||||
_boxAllWalletsData = await Hive.openBox<dynamic>(boxNameAllWalletsData);
|
||||
_boxAllWalletsData = await hive.openBox<dynamic>(boxNameAllWalletsData);
|
||||
}
|
||||
|
||||
_boxNotifications =
|
||||
await Hive.openBox<NotificationModel>(boxNameNotifications);
|
||||
await hive.openBox<NotificationModel>(boxNameNotifications);
|
||||
_boxWatchedTransactions =
|
||||
await Hive.openBox<NotificationModel>(boxNameWatchedTransactions);
|
||||
await hive.openBox<NotificationModel>(boxNameWatchedTransactions);
|
||||
_boxWatchedTrades =
|
||||
await Hive.openBox<NotificationModel>(boxNameWatchedTrades);
|
||||
_boxTradesV2 = await Hive.openBox<Trade>(boxNameTradesV2);
|
||||
_boxTradeNotes = await Hive.openBox<String>(boxNameTradeNotes);
|
||||
_boxTradeLookup = await Hive.openBox<TradeWalletLookup>(boxNameTradeLookup);
|
||||
await hive.openBox<NotificationModel>(boxNameWatchedTrades);
|
||||
_boxTradesV2 = await hive.openBox<Trade>(boxNameTradesV2);
|
||||
_boxTradeNotes = await hive.openBox<String>(boxNameTradeNotes);
|
||||
_boxTradeLookup = await hive.openBox<TradeWalletLookup>(boxNameTradeLookup);
|
||||
_walletInfoSource =
|
||||
await Hive.openBox<xmr.WalletInfo>(xmr.WalletInfo.boxName);
|
||||
_boxFavoriteWallets = await Hive.openBox<String>(boxNameFavoriteWallets);
|
||||
await hive.openBox<xmr.WalletInfo>(xmr.WalletInfo.boxName);
|
||||
_boxFavoriteWallets = await hive.openBox<String>(boxNameFavoriteWallets);
|
||||
|
||||
await Future.wait([
|
||||
Hive.openBox<dynamic>(boxNamePriceCache),
|
||||
hive.openBox<dynamic>(boxNamePriceCache),
|
||||
_loadWalletBoxes(),
|
||||
]);
|
||||
}
|
||||
|
@ -177,12 +180,12 @@ class DB {
|
|||
);
|
||||
|
||||
for (final entry in mapped.entries) {
|
||||
if (Hive.isBoxOpen(entry.value.walletId)) {
|
||||
if (hive.isBoxOpen(entry.value.walletId)) {
|
||||
_walletBoxes[entry.value.walletId] =
|
||||
Hive.box<dynamic>(entry.value.walletId);
|
||||
hive.box<dynamic>(entry.value.walletId);
|
||||
} else {
|
||||
_walletBoxes[entry.value.walletId] =
|
||||
await Hive.openBox<dynamic>(entry.value.walletId);
|
||||
await hive.openBox<dynamic>(entry.value.walletId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -192,7 +195,7 @@ class DB {
|
|||
_txCacheBoxes.remove(currency.identifier);
|
||||
}
|
||||
return _txCacheBoxes[currency.identifier] ??=
|
||||
await Hive.openBox<dynamic>(_boxNameTxCache(currency: currency));
|
||||
await hive.openBox<dynamic>(_boxNameTxCache(currency: currency));
|
||||
}
|
||||
|
||||
Future<void> closeTxCacheBox({required CryptoCurrency currency}) async {
|
||||
|
@ -206,7 +209,7 @@ class DB {
|
|||
_setCacheBoxes.remove(currency.identifier);
|
||||
}
|
||||
return _setCacheBoxes[currency.identifier] ??=
|
||||
await Hive.openBox<dynamic>(_boxNameSetCache(currency: currency));
|
||||
await hive.openBox<dynamic>(_boxNameSetCache(currency: currency));
|
||||
}
|
||||
|
||||
Future<void> closeAnonymitySetCacheBox({
|
||||
|
@ -222,7 +225,7 @@ class DB {
|
|||
_usedSerialsCacheBoxes.remove(currency.identifier);
|
||||
}
|
||||
return _usedSerialsCacheBoxes[currency.identifier] ??=
|
||||
await Hive.openBox<dynamic>(
|
||||
await hive.openBox<dynamic>(
|
||||
_boxNameUsedSerialsCache(currency: currency),
|
||||
);
|
||||
}
|
||||
|
@ -252,7 +255,7 @@ class DB {
|
|||
if (_walletBoxes[walletId] != null) {
|
||||
throw Exception("Attempted overwrite of existing wallet box!");
|
||||
}
|
||||
_walletBoxes[walletId] = await Hive.openBox<dynamic>(walletId);
|
||||
_walletBoxes[walletId] = await hive.openBox<dynamic>(walletId);
|
||||
}
|
||||
|
||||
Future<void> removeWalletBox({required String walletId}) async {
|
||||
|
@ -264,19 +267,19 @@ class DB {
|
|||
// reads
|
||||
|
||||
List<dynamic> keys<T>({required String boxName}) =>
|
||||
Hive.box<T>(boxName).keys.toList(growable: false);
|
||||
hive.box<T>(boxName).keys.toList(growable: false);
|
||||
|
||||
List<T> values<T>({required String boxName}) =>
|
||||
Hive.box<T>(boxName).values.toList(growable: false);
|
||||
hive.box<T>(boxName).values.toList(growable: false);
|
||||
|
||||
T? get<T>({
|
||||
required String boxName,
|
||||
required dynamic key,
|
||||
}) =>
|
||||
Hive.box<T>(boxName).get(key);
|
||||
hive.box<T>(boxName).get(key);
|
||||
|
||||
bool containsKey<T>({required String boxName, required dynamic key}) =>
|
||||
Hive.box<T>(boxName).containsKey(key);
|
||||
hive.box<T>(boxName).containsKey(key);
|
||||
|
||||
// writes
|
||||
|
||||
|
@ -286,33 +289,33 @@ class DB {
|
|||
required T value,
|
||||
}) async =>
|
||||
await mutex
|
||||
.protect(() async => await Hive.box<T>(boxName).put(key, value));
|
||||
.protect(() async => await hive.box<T>(boxName).put(key, value));
|
||||
|
||||
Future<void> add<T>({required String boxName, required T value}) async =>
|
||||
await mutex.protect(() async => await Hive.box<T>(boxName).add(value));
|
||||
await mutex.protect(() async => await hive.box<T>(boxName).add(value));
|
||||
|
||||
Future<void> addAll<T>({
|
||||
required String boxName,
|
||||
required Iterable<T> values,
|
||||
}) async =>
|
||||
await mutex
|
||||
.protect(() async => await Hive.box<T>(boxName).addAll(values));
|
||||
.protect(() async => await hive.box<T>(boxName).addAll(values));
|
||||
|
||||
Future<void> delete<T>({
|
||||
required dynamic key,
|
||||
required String boxName,
|
||||
}) async =>
|
||||
await mutex.protect(() async => await Hive.box<T>(boxName).delete(key));
|
||||
await mutex.protect(() async => await hive.box<T>(boxName).delete(key));
|
||||
|
||||
Future<void> deleteAll<T>({required String boxName}) async {
|
||||
await mutex.protect(() async {
|
||||
final box = await Hive.openBox<T>(boxName);
|
||||
final box = await hive.openBox<T>(boxName);
|
||||
await box.clear();
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> deleteBoxFromDisk({required String boxName}) async =>
|
||||
await mutex.protect(() async => await Hive.deleteBoxFromDisk(boxName));
|
||||
await mutex.protect(() async => await hive.deleteBoxFromDisk(boxName));
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
Future<bool> deleteEverything() async {
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import 'dart:convert';
|
||||
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
import '../app_config.dart';
|
||||
|
@ -24,7 +23,8 @@ Future<void> migrateWalletsToIsar({
|
|||
await MainDB.instance.isar
|
||||
.writeTxn(() async => await MainDB.instance.isar.transactionV2s.clear());
|
||||
|
||||
final allWalletsBox = await Hive.openBox<dynamic>(DB.boxNameAllWalletsData);
|
||||
final allWalletsBox =
|
||||
await DB.instance.hive.openBox<dynamic>(DB.boxNameAllWalletsData);
|
||||
|
||||
final names = DB.instance
|
||||
.get<dynamic>(boxName: DB.boxNameAllWalletsData, key: 'names') as Map?;
|
||||
|
@ -55,7 +55,9 @@ Future<void> migrateWalletsToIsar({
|
|||
// Get current ordered list of favourite wallet Ids
|
||||
//
|
||||
final List<String> favourites =
|
||||
(await Hive.openBox<String>(DB.boxNameFavoriteWallets)).values.toList();
|
||||
(await DB.instance.hive.openBox<String>(DB.boxNameFavoriteWallets))
|
||||
.values
|
||||
.toList();
|
||||
|
||||
final List<(WalletInfo, WalletInfoMeta)> newInfo = [];
|
||||
final List<TokenWalletInfo> tokenInfo = [];
|
||||
|
@ -65,7 +67,7 @@ Future<void> migrateWalletsToIsar({
|
|||
// Convert each old info into the new Isar WalletInfo
|
||||
//
|
||||
for (final old in oldInfo) {
|
||||
final walletBox = await Hive.openBox<dynamic>(old.walletId);
|
||||
final walletBox = await DB.instance.hive.openBox<dynamic>(old.walletId);
|
||||
|
||||
//
|
||||
// First handle transaction notes
|
||||
|
@ -212,9 +214,9 @@ Future<void> migrateWalletsToIsar({
|
|||
}
|
||||
|
||||
Future<void> _cleanupOnSuccess({required List<String> walletIds}) async {
|
||||
await Hive.deleteBoxFromDisk(DB.boxNameFavoriteWallets);
|
||||
await Hive.deleteBoxFromDisk(DB.boxNameAllWalletsData);
|
||||
await DB.instance.hive.deleteBoxFromDisk(DB.boxNameFavoriteWallets);
|
||||
await DB.instance.hive.deleteBoxFromDisk(DB.boxNameAllWalletsData);
|
||||
for (final walletId in walletIds) {
|
||||
await Hive.deleteBoxFromDisk(walletId);
|
||||
await DB.instance.hive.deleteBoxFromDisk(walletId);
|
||||
}
|
||||
}
|
||||
|
|
79
lib/db/special_migrations.dart
Normal file
79
lib/db/special_migrations.dart
Normal file
|
@ -0,0 +1,79 @@
|
|||
import 'dart:io';
|
||||
|
||||
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
|
||||
import 'package:hive/hive.dart' show Box;
|
||||
import 'package:hive/src/hive_impl.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
||||
import '../app_config.dart';
|
||||
import '../utilities/util.dart';
|
||||
import 'hive/db.dart';
|
||||
|
||||
abstract class CampfireMigration {
|
||||
static const _didRunKey = "campfire_one_time_migration_done_key";
|
||||
|
||||
static bool get didRun =>
|
||||
DB.instance.get<dynamic>(
|
||||
boxName: DB.boxNameDBInfo,
|
||||
key: _didRunKey,
|
||||
) as bool? ??
|
||||
false;
|
||||
|
||||
static Future<void> setDidRun() async {
|
||||
await DB.instance.put<dynamic>(
|
||||
boxName: DB.boxNameDBInfo,
|
||||
key: _didRunKey,
|
||||
value: true,
|
||||
);
|
||||
}
|
||||
|
||||
static bool get hasOldWallets =>
|
||||
!didRun && (_wallets?.get("names") as Map?)?.isNotEmpty == true;
|
||||
|
||||
static late final FlutterSecureStorage? _secureStore;
|
||||
static late final Box<dynamic>? _wallets;
|
||||
|
||||
static Future<void> init() async {
|
||||
if (didRun || Util.isDesktop) {
|
||||
return;
|
||||
}
|
||||
final Directory appDirectory = await getApplicationDocumentsDirectory();
|
||||
|
||||
final file = File("${appDirectory.path}/wallets.hive");
|
||||
|
||||
if (await file.exists()) {
|
||||
final myHive = HiveImpl();
|
||||
myHive.init(appDirectory.path);
|
||||
_wallets = await myHive.openBox<dynamic>('wallets');
|
||||
_secureStore = const FlutterSecureStorage();
|
||||
} else {
|
||||
await setDidRun();
|
||||
}
|
||||
}
|
||||
|
||||
static Future<List<(String, List<String>)>> fetch() async {
|
||||
if (didRun ||
|
||||
Util.isDesktop ||
|
||||
AppConfig.appName != "Campfire" ||
|
||||
_wallets == null) {
|
||||
return [];
|
||||
}
|
||||
|
||||
final names = _wallets!.get("names");
|
||||
|
||||
final List<(String, List<String>)> results = [];
|
||||
if (names is Map) {
|
||||
for (final entry in names.entries) {
|
||||
final name = entry.key as String;
|
||||
final id = entry.value as String;
|
||||
final mnemonic = await _secureStore!.read(key: "${id}_mnemonic");
|
||||
|
||||
if (mnemonic != null) {
|
||||
results.add((name, mnemonic.split(" ")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
}
|
|
@ -25,7 +25,6 @@ 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';
|
||||
import 'package:keyboard_dismisser/keyboard_dismisser.dart';
|
||||
import 'package:path_provider/path_provider.dart';
|
||||
|
@ -35,6 +34,7 @@ import 'app_config.dart';
|
|||
import 'db/db_version_migration.dart';
|
||||
import 'db/hive/db.dart';
|
||||
import 'db/isar/main_db.dart';
|
||||
import 'db/special_migrations.dart';
|
||||
import 'db/sqlite/firo_cache.dart';
|
||||
import 'models/exchange/change_now/exchange_transaction.dart';
|
||||
import 'models/exchange/change_now/exchange_transaction_status.dart';
|
||||
|
@ -44,6 +44,7 @@ import 'models/models.dart';
|
|||
import 'models/node_model.dart';
|
||||
import 'models/notification_model.dart';
|
||||
import 'models/trade_wallet_lookup.dart';
|
||||
import 'pages/campfire_migrate_view.dart';
|
||||
import 'pages/home_view/home_view.dart';
|
||||
import 'pages/intro_view.dart';
|
||||
import 'pages/loading_view.dart';
|
||||
|
@ -142,52 +143,59 @@ void main(List<String> args) async {
|
|||
}
|
||||
|
||||
// Registering Transaction Model Adapters
|
||||
Hive.registerAdapter(TransactionDataAdapter());
|
||||
Hive.registerAdapter(TransactionChunkAdapter());
|
||||
Hive.registerAdapter(TransactionAdapter());
|
||||
Hive.registerAdapter(InputAdapter());
|
||||
Hive.registerAdapter(OutputAdapter());
|
||||
DB.instance.hive.registerAdapter(TransactionDataAdapter());
|
||||
DB.instance.hive.registerAdapter(TransactionChunkAdapter());
|
||||
DB.instance.hive.registerAdapter(TransactionAdapter());
|
||||
DB.instance.hive.registerAdapter(InputAdapter());
|
||||
DB.instance.hive.registerAdapter(OutputAdapter());
|
||||
|
||||
// Registering Utxo Model Adapters
|
||||
Hive.registerAdapter(UtxoDataAdapter());
|
||||
Hive.registerAdapter(UtxoObjectAdapter());
|
||||
Hive.registerAdapter(StatusAdapter());
|
||||
DB.instance.hive.registerAdapter(UtxoDataAdapter());
|
||||
DB.instance.hive.registerAdapter(UtxoObjectAdapter());
|
||||
DB.instance.hive.registerAdapter(StatusAdapter());
|
||||
|
||||
// Registering Lelantus Model Adapters
|
||||
Hive.registerAdapter(LelantusCoinAdapter());
|
||||
DB.instance.hive.registerAdapter(LelantusCoinAdapter());
|
||||
|
||||
// notification model adapter
|
||||
Hive.registerAdapter(NotificationModelAdapter());
|
||||
DB.instance.hive.registerAdapter(NotificationModelAdapter());
|
||||
|
||||
// change now trade adapters
|
||||
Hive.registerAdapter(ExchangeTransactionAdapter());
|
||||
Hive.registerAdapter(ExchangeTransactionStatusAdapter());
|
||||
DB.instance.hive.registerAdapter(ExchangeTransactionAdapter());
|
||||
DB.instance.hive.registerAdapter(ExchangeTransactionStatusAdapter());
|
||||
|
||||
Hive.registerAdapter(TradeAdapter());
|
||||
DB.instance.hive.registerAdapter(TradeAdapter());
|
||||
|
||||
// reference lookup data adapter
|
||||
Hive.registerAdapter(TradeWalletLookupAdapter());
|
||||
DB.instance.hive.registerAdapter(TradeWalletLookupAdapter());
|
||||
|
||||
// node model adapter
|
||||
Hive.registerAdapter(NodeModelAdapter());
|
||||
DB.instance.hive.registerAdapter(NodeModelAdapter());
|
||||
|
||||
Hive.registerAdapter(NodeAdapter());
|
||||
DB.instance.hive.registerAdapter(NodeAdapter());
|
||||
|
||||
if (!Hive.isAdapterRegistered(WalletInfoAdapter().typeId)) {
|
||||
Hive.registerAdapter(WalletInfoAdapter());
|
||||
if (!DB.instance.hive.isAdapterRegistered(WalletInfoAdapter().typeId)) {
|
||||
DB.instance.hive.registerAdapter(WalletInfoAdapter());
|
||||
}
|
||||
|
||||
Hive.registerAdapter(WalletTypeAdapter());
|
||||
DB.instance.hive.registerAdapter(WalletTypeAdapter());
|
||||
|
||||
Hive.registerAdapter(UnspentCoinsInfoAdapter());
|
||||
await Hive.initFlutter(
|
||||
DB.instance.hive.registerAdapter(UnspentCoinsInfoAdapter());
|
||||
|
||||
DB.instance.hive.init(
|
||||
(await StackFileSystem.applicationHiveDirectory()).path,
|
||||
);
|
||||
|
||||
await Hive.openBox<dynamic>(DB.boxNameDBInfo);
|
||||
await Hive.openBox<dynamic>(DB.boxNamePrefs);
|
||||
await DB.instance.hive.openBox<dynamic>(DB.boxNameDBInfo);
|
||||
await DB.instance.hive.openBox<dynamic>(DB.boxNamePrefs);
|
||||
await Prefs.instance.init();
|
||||
|
||||
if (AppConfig.appName == "Campfire" &&
|
||||
!Util.isDesktop &&
|
||||
!CampfireMigration.didRun) {
|
||||
await CampfireMigration.init();
|
||||
}
|
||||
|
||||
// TODO:
|
||||
// This should be moved to happen during the loading animation instead of
|
||||
// showing a blank screen for 4-10 seconds.
|
||||
|
@ -792,7 +800,13 @@ class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
|
|||
biometricsCancelButtonString: "Cancel",
|
||||
);
|
||||
} else {
|
||||
return const IntroView();
|
||||
if (AppConfig.appName == "Campfire" &&
|
||||
!CampfireMigration.didRun &&
|
||||
CampfireMigration.hasOldWallets) {
|
||||
return const CampfireMigrateView();
|
||||
} else {
|
||||
return const IntroView();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// CURRENTLY DISABLED as cannot be animated
|
||||
|
|
210
lib/pages/campfire_migrate_view.dart
Normal file
210
lib/pages/campfire_migrate_view.dart
Normal file
|
@ -0,0 +1,210 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import '../db/special_migrations.dart';
|
||||
import '../themes/stack_colors.dart';
|
||||
import '../utilities/text_styles.dart';
|
||||
import '../utilities/util.dart';
|
||||
import '../widgets/app_icon.dart';
|
||||
import '../widgets/background.dart';
|
||||
import '../widgets/custom_buttons/blue_text_button.dart';
|
||||
import '../widgets/custom_buttons/checkbox_text_button.dart';
|
||||
import '../widgets/desktop/primary_button.dart';
|
||||
import '../widgets/loading_indicator.dart';
|
||||
import '../widgets/rounded_container.dart';
|
||||
import 'add_wallet_views/new_wallet_recovery_phrase_view/sub_widgets/mnemonic_table.dart';
|
||||
import 'intro_view.dart';
|
||||
|
||||
class CampfireMigrateView extends StatelessWidget {
|
||||
const CampfireMigrateView({super.key});
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Background(
|
||||
child: Scaffold(
|
||||
backgroundColor: Theme.of(context).extension<StackColors>()!.background,
|
||||
body: SafeArea(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
const Padding(
|
||||
padding: EdgeInsets.only(right: 16),
|
||||
child: AppIcon(
|
||||
width: 50,
|
||||
height: 50,
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: Text(
|
||||
"Your old Campfire wallets are listed below. "
|
||||
"If you would like to keep them then copy the mnemonics "
|
||||
"somewhere safe so you can restore them.",
|
||||
style: STextStyles.w600_12(context),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
Expanded(
|
||||
child: Column(
|
||||
children: [
|
||||
Expanded(
|
||||
child: FutureBuilder(
|
||||
future: CampfireMigration.fetch(),
|
||||
builder: (context, snapshot) {
|
||||
if (snapshot.connectionState ==
|
||||
ConnectionState.done) {
|
||||
final count = (snapshot.data?.length ?? 0) + 1;
|
||||
|
||||
return ListView.separated(
|
||||
itemCount: count,
|
||||
separatorBuilder: (_, __) => const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
itemBuilder: (_, index) => index == count - 1
|
||||
? const _ContinueButtonGroup()
|
||||
: _CampfireWallet(
|
||||
mnemonic: snapshot.data![index].$2,
|
||||
name: snapshot.data![index].$1,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
return const Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
mainAxisAlignment: MainAxisAlignment.center,
|
||||
children: [
|
||||
LoadingIndicator(
|
||||
width: 100,
|
||||
height: 100,
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _ContinueButtonGroup extends StatefulWidget {
|
||||
const _ContinueButtonGroup({super.key});
|
||||
|
||||
@override
|
||||
State<_ContinueButtonGroup> createState() => _ContinueButtonGroupState();
|
||||
}
|
||||
|
||||
class _ContinueButtonGroupState extends State<_ContinueButtonGroup> {
|
||||
bool _checked = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Column(
|
||||
children: [
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
CheckboxTextButton(
|
||||
label: "I have saved all my mnemonics and double checked each one",
|
||||
onChanged: (value) {
|
||||
setState(() {
|
||||
_checked = value;
|
||||
});
|
||||
},
|
||||
),
|
||||
const SizedBox(
|
||||
height: 16,
|
||||
),
|
||||
PrimaryButton(
|
||||
enabled: _checked,
|
||||
label: "Continue",
|
||||
onPressed: () {
|
||||
CampfireMigration.setDidRun();
|
||||
// could do pushReplacementNamed but we won't show this again on next run anyways
|
||||
Navigator.of(context).pushNamed(
|
||||
IntroView.routeName,
|
||||
);
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _CampfireWallet extends StatefulWidget {
|
||||
const _CampfireWallet({
|
||||
super.key,
|
||||
required this.name,
|
||||
required this.mnemonic,
|
||||
});
|
||||
|
||||
final String name;
|
||||
final List<String> mnemonic;
|
||||
|
||||
@override
|
||||
State<_CampfireWallet> createState() => _CampfireWalletState();
|
||||
}
|
||||
|
||||
class _CampfireWalletState extends State<_CampfireWallet> {
|
||||
bool _show = false;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return RoundedContainer(
|
||||
color: Theme.of(context).extension<StackColors>()!.background,
|
||||
borderColor: Theme.of(context).extension<StackColors>()!.textDark,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.center,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: [
|
||||
Text(
|
||||
widget.name,
|
||||
style: STextStyles.w500_14(context),
|
||||
),
|
||||
CustomTextButton(
|
||||
text: "Copy mnemonic",
|
||||
onTap: () => Clipboard.setData(
|
||||
ClipboardData(
|
||||
text: widget.mnemonic.join(" "),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(
|
||||
height: 10,
|
||||
),
|
||||
_show
|
||||
? MnemonicTable(
|
||||
words: widget.mnemonic,
|
||||
isDesktop: Util.isDesktop,
|
||||
)
|
||||
: Padding(
|
||||
padding: const EdgeInsets.all(16),
|
||||
child: PrimaryButton(
|
||||
label: "Show mnemonic",
|
||||
onPressed: () => setState(() => _show = true),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
|
@ -13,7 +13,6 @@ import 'dart:io';
|
|||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_riverpod/flutter_riverpod.dart';
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:isar/isar.dart';
|
||||
|
||||
import '../../db/hive/db.dart';
|
||||
|
@ -52,7 +51,7 @@ class _ForgotPasswordDesktopViewState
|
|||
final appRoot = await StackFileSystem.applicationRootDirectory();
|
||||
|
||||
try {
|
||||
await Hive.close();
|
||||
await DB.instance.hive.close();
|
||||
if (Platform.isWindows) {
|
||||
final xmrDir = Directory("${appRoot.path}/wallets");
|
||||
if (xmrDir.existsSync()) {
|
||||
|
|
|
@ -8,9 +8,10 @@
|
|||
*
|
||||
*/
|
||||
|
||||
import 'package:hive/hive.dart';
|
||||
import 'package:hive/hive.dart' show Box;
|
||||
import 'package:stack_wallet_backup/secure_storage.dart';
|
||||
|
||||
import '../db/hive/db.dart';
|
||||
import 'logger.dart';
|
||||
|
||||
const String kBoxNameDesktopData = "desktopData";
|
||||
|
@ -185,7 +186,7 @@ class DPS {
|
|||
Future<void> _put({required String key, required String value}) async {
|
||||
Box<String>? box;
|
||||
try {
|
||||
box = await Hive.openBox<String>(kBoxNameDesktopData);
|
||||
box = await DB.instance.hive.openBox<String>(kBoxNameDesktopData);
|
||||
await box.put(key, value);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
|
@ -201,7 +202,7 @@ class DPS {
|
|||
String? value;
|
||||
Box<String>? box;
|
||||
try {
|
||||
box = await Hive.openBox<String>(kBoxNameDesktopData);
|
||||
box = await DB.instance.hive.openBox<String>(kBoxNameDesktopData);
|
||||
value = box.get(key);
|
||||
} catch (e, s) {
|
||||
Logging.instance.log(
|
||||
|
@ -217,6 +218,6 @@ class DPS {
|
|||
/// Dangerous. Used in one place and should not be called anywhere else.
|
||||
@Deprecated("Don't use this if at all possible")
|
||||
Future<void> deleteBox() async {
|
||||
await Hive.deleteBoxFromDisk(kBoxNameDesktopData);
|
||||
await DB.instance.hive.deleteBoxFromDisk(kBoxNameDesktopData);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,9 @@ abstract class StackFileSystem {
|
|||
_overrideDirSet = true;
|
||||
}
|
||||
|
||||
static bool get _createSubDirs =>
|
||||
Util.isDesktop || AppConfig.appName == "Campfire";
|
||||
|
||||
static Future<Directory> applicationRootDirectory() async {
|
||||
Directory appDirectory;
|
||||
|
||||
|
@ -80,7 +83,7 @@ abstract class StackFileSystem {
|
|||
|
||||
static Future<Directory> applicationIsarDirectory() async {
|
||||
final root = await applicationRootDirectory();
|
||||
if (Util.isDesktop) {
|
||||
if (_createSubDirs) {
|
||||
final dir = Directory("${root.path}/isar");
|
||||
if (!dir.existsSync()) {
|
||||
await dir.create();
|
||||
|
@ -94,7 +97,7 @@ abstract class StackFileSystem {
|
|||
// Not used in general now. See applicationFiroCacheSQLiteDirectory()
|
||||
// static Future<Directory> applicationSQLiteDirectory() async {
|
||||
// final root = await applicationRootDirectory();
|
||||
// if (Util.isDesktop) {
|
||||
// if (_createSubDirs) {
|
||||
// final dir = Directory("${root.path}/sqlite");
|
||||
// if (!dir.existsSync()) {
|
||||
// await dir.create();
|
||||
|
@ -107,7 +110,7 @@ abstract class StackFileSystem {
|
|||
|
||||
static Future<Directory> applicationTorDirectory() async {
|
||||
final root = await applicationRootDirectory();
|
||||
if (Util.isDesktop) {
|
||||
if (_createSubDirs) {
|
||||
final dir = Directory("${root.path}/tor");
|
||||
if (!dir.existsSync()) {
|
||||
await dir.create();
|
||||
|
@ -120,7 +123,7 @@ abstract class StackFileSystem {
|
|||
|
||||
static Future<Directory> applicationFiroCacheSQLiteDirectory() async {
|
||||
final root = await applicationRootDirectory();
|
||||
if (Util.isDesktop) {
|
||||
if (_createSubDirs) {
|
||||
final dir = Directory("${root.path}/sqlite/firo_cache");
|
||||
if (!dir.existsSync()) {
|
||||
await dir.create(recursive: true);
|
||||
|
@ -133,7 +136,7 @@ abstract class StackFileSystem {
|
|||
|
||||
static Future<Directory> applicationHiveDirectory() async {
|
||||
final root = await applicationRootDirectory();
|
||||
if (Util.isDesktop) {
|
||||
if (_createSubDirs) {
|
||||
final dir = Directory("${root.path}/hive");
|
||||
if (!dir.existsSync()) {
|
||||
await dir.create();
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'package:flutter/material.dart';
|
||||
import 'package:hive_flutter/hive_flutter.dart';
|
||||
|
||||
import '../../db/hive/db.dart';
|
||||
import '../../utilities/assets.dart';
|
||||
|
@ -17,7 +16,8 @@ const _kOneTimeTorHasBeenAddedDialogWasShown =
|
|||
Future<void> showOneTimeTorHasBeenAddedDialogIfRequired(
|
||||
BuildContext context,
|
||||
) async {
|
||||
final box = await Hive.openBox<bool>(DB.boxNameOneTimeDialogsShown);
|
||||
final box =
|
||||
await DB.instance.hive.openBox<bool>(DB.boxNameOneTimeDialogsShown);
|
||||
|
||||
if (!box.get(
|
||||
_kOneTimeTorHasBeenAddedDialogWasShown,
|
||||
|
@ -48,7 +48,9 @@ class _TorHasBeenAddedDialogState extends State<_TorHasBeenAddedDialog> {
|
|||
}
|
||||
_lock = true;
|
||||
try {
|
||||
final box = await Hive.openBox<bool>(DB.boxNameOneTimeDialogsShown);
|
||||
final box = await DB.instance.hive.openBox<bool>(
|
||||
DB.boxNameOneTimeDialogsShown,
|
||||
);
|
||||
await box.put(_kOneTimeTorHasBeenAddedDialogWasShown, true);
|
||||
} catch (_) {
|
||||
//
|
||||
|
|
Loading…
Reference in a new issue