Show old campfire wallets

This commit is contained in:
julian 2024-06-10 16:50:26 -06:00
parent 929e334063
commit 29708b1534
10 changed files with 426 additions and 109 deletions

View file

@ -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,

View file

@ -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 {

View file

@ -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);
}
}

View 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;
}
}

View file

@ -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

View 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),
),
),
],
),
);
}
}

View file

@ -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()) {

View file

@ -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);
}
}

View file

@ -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();

View file

@ -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 (_) {
//