diff --git a/lib/db/db_version_migration.dart b/lib/db/db_version_migration.dart index b5da9f505..1415803e4 100644 --- a/lib/db/db_version_migration.dart +++ b/lib/db/db_version_migration.dart @@ -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(DB.boxNameAllWalletsData); - await Hive.openBox(DB.boxNamePrefs); + await DB.instance.hive.openBox(DB.boxNameAllWalletsData); + await DB.instance.hive.openBox(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(DB.boxNameNodeModels); - await Hive.openBox(DB.boxNamePrimaryNodes); + await DB.instance.hive.openBox(DB.boxNameNodeModels); + await DB.instance.hive.openBox(DB.boxNamePrimaryNodes); final node = nodeService.getPrimaryNodeFor(currency: firo) ?? firo.defaultNode; final List 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(walletInfo.walletId); + await DB.instance.hive.openBox(walletInfo.walletId); final _lelantusCoins = DB.instance.get( 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(DB.boxNameTrades); - await Hive.openBox(DB.boxNameTradesV2); + await DB.instance.hive.openBox(DB.boxNameTrades); + await DB.instance.hive.openBox(DB.boxNameTradesV2); final trades = DB.instance.values(boxName: DB.boxNameTrades); @@ -184,7 +187,7 @@ class DbVersionMigrator with WalletDB { return await migrate(2, secureStore: secureStore); case 2: - await Hive.openBox(DB.boxNamePrefs); + await DB.instance.hive.openBox(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("theme"); - await Hive.openBox(DB.boxNamePrefs); + await DB.instance.hive.openBox("theme"); + await DB.instance.hive.openBox(DB.boxNamePrefs); final themeName = DB.instance.get(boxName: "theme", key: "colorScheme") @@ -347,7 +350,7 @@ class DbVersionMigrator with WalletDB { case 8: // migrate - await Hive.openBox(DB.boxNameAllWalletsData); + await DB.instance.hive.openBox(DB.boxNameAllWalletsData); final walletsService = WalletsService(); final walletInfoList = await walletsService.walletNames; await MainDB.instance.initMainDB(); @@ -443,8 +446,8 @@ class DbVersionMigrator with WalletDB { } Future _v4(SecureStorageInterface secureStore) async { - await Hive.openBox(DB.boxNameAllWalletsData); - await Hive.openBox(DB.boxNamePrefs); + await DB.instance.hive.openBox(DB.boxNameAllWalletsData); + await DB.instance.hive.openBox(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(info.walletId); + final walletBox = await DB.instance.hive.openBox(info.walletId); const receiveAddressesPrefix = "receivingAddresses"; const changeAddressesPrefix = "changeAddresses"; @@ -560,7 +563,7 @@ class DbVersionMigrator with WalletDB { } Future _v7(SecureStorageInterface secureStore) async { - await Hive.openBox(DB.boxNameAllWalletsData); + await DB.instance.hive.openBox(DB.boxNameAllWalletsData); final walletsService = WalletsService(); final walletInfoList = await walletsService.walletNames; await MainDB.instance.initMainDB(); @@ -601,7 +604,8 @@ class DbVersionMigrator with WalletDB { } Future _v9() async { - final addressBookBox = await Hive.openBox(DB.boxNameAddressBook); + final addressBookBox = + await DB.instance.hive.openBox(DB.boxNameAddressBook); await MainDB.instance.initMainDB(); final keys = List.from(addressBookBox.keys); @@ -649,8 +653,8 @@ class DbVersionMigrator with WalletDB { } Future _v10(SecureStorageInterface secureStore) async { - await Hive.openBox(DB.boxNameAllWalletsData); - await Hive.openBox(DB.boxNamePrefs); + await DB.instance.hive.openBox(DB.boxNameAllWalletsData); + await DB.instance.hive.openBox(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(walletId); + final walletBox = await DB.instance.hive.openBox(walletId); final hiveLCoins = DB.instance.get( boxName: walletId, diff --git a/lib/db/hive/db.dart b/lib/db/hive/db.dart index 2e9b5435b..1e4c670e1 100644 --- a/lib/db/hive/db.dart +++ b/lib/db/hive/db.dart @@ -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 init() async { - if (Hive.isBoxOpen(boxNameDBInfo)) { - _boxDBInfo = Hive.box(boxNameDBInfo); + if (hive.isBoxOpen(boxNameDBInfo)) { + _boxDBInfo = hive.box(boxNameDBInfo); } else { - _boxDBInfo = await Hive.openBox(boxNameDBInfo); + _boxDBInfo = await hive.openBox(boxNameDBInfo); } - await Hive.openBox(boxNameWalletsToDeleteOnStart); + await hive.openBox(boxNameWalletsToDeleteOnStart); - if (Hive.isBoxOpen(boxNamePrefs)) { - _boxPrefs = Hive.box(boxNamePrefs); + if (hive.isBoxOpen(boxNamePrefs)) { + _boxPrefs = hive.box(boxNamePrefs); } else { - _boxPrefs = await Hive.openBox(boxNamePrefs); + _boxPrefs = await hive.openBox(boxNamePrefs); } - if (Hive.isBoxOpen(boxNameNodeModels)) { - _boxNodeModels = Hive.box(boxNameNodeModels); + if (hive.isBoxOpen(boxNameNodeModels)) { + _boxNodeModels = hive.box(boxNameNodeModels); } else { - _boxNodeModels = await Hive.openBox(boxNameNodeModels); + _boxNodeModels = await hive.openBox(boxNameNodeModels); } - if (Hive.isBoxOpen(boxNamePrimaryNodes)) { - _boxPrimaryNodes = Hive.box(boxNamePrimaryNodes); + if (hive.isBoxOpen(boxNamePrimaryNodes)) { + _boxPrimaryNodes = hive.box(boxNamePrimaryNodes); } else { - _boxPrimaryNodes = await Hive.openBox(boxNamePrimaryNodes); + _boxPrimaryNodes = await hive.openBox(boxNamePrimaryNodes); } - if (Hive.isBoxOpen(boxNameAllWalletsData)) { - _boxAllWalletsData = Hive.box(boxNameAllWalletsData); + if (hive.isBoxOpen(boxNameAllWalletsData)) { + _boxAllWalletsData = hive.box(boxNameAllWalletsData); } else { - _boxAllWalletsData = await Hive.openBox(boxNameAllWalletsData); + _boxAllWalletsData = await hive.openBox(boxNameAllWalletsData); } _boxNotifications = - await Hive.openBox(boxNameNotifications); + await hive.openBox(boxNameNotifications); _boxWatchedTransactions = - await Hive.openBox(boxNameWatchedTransactions); + await hive.openBox(boxNameWatchedTransactions); _boxWatchedTrades = - await Hive.openBox(boxNameWatchedTrades); - _boxTradesV2 = await Hive.openBox(boxNameTradesV2); - _boxTradeNotes = await Hive.openBox(boxNameTradeNotes); - _boxTradeLookup = await Hive.openBox(boxNameTradeLookup); + await hive.openBox(boxNameWatchedTrades); + _boxTradesV2 = await hive.openBox(boxNameTradesV2); + _boxTradeNotes = await hive.openBox(boxNameTradeNotes); + _boxTradeLookup = await hive.openBox(boxNameTradeLookup); _walletInfoSource = - await Hive.openBox(xmr.WalletInfo.boxName); - _boxFavoriteWallets = await Hive.openBox(boxNameFavoriteWallets); + await hive.openBox(xmr.WalletInfo.boxName); + _boxFavoriteWallets = await hive.openBox(boxNameFavoriteWallets); await Future.wait([ - Hive.openBox(boxNamePriceCache), + hive.openBox(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(entry.value.walletId); + hive.box(entry.value.walletId); } else { _walletBoxes[entry.value.walletId] = - await Hive.openBox(entry.value.walletId); + await hive.openBox(entry.value.walletId); } } } @@ -192,7 +195,7 @@ class DB { _txCacheBoxes.remove(currency.identifier); } return _txCacheBoxes[currency.identifier] ??= - await Hive.openBox(_boxNameTxCache(currency: currency)); + await hive.openBox(_boxNameTxCache(currency: currency)); } Future closeTxCacheBox({required CryptoCurrency currency}) async { @@ -206,7 +209,7 @@ class DB { _setCacheBoxes.remove(currency.identifier); } return _setCacheBoxes[currency.identifier] ??= - await Hive.openBox(_boxNameSetCache(currency: currency)); + await hive.openBox(_boxNameSetCache(currency: currency)); } Future closeAnonymitySetCacheBox({ @@ -222,7 +225,7 @@ class DB { _usedSerialsCacheBoxes.remove(currency.identifier); } return _usedSerialsCacheBoxes[currency.identifier] ??= - await Hive.openBox( + await hive.openBox( _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(walletId); + _walletBoxes[walletId] = await hive.openBox(walletId); } Future removeWalletBox({required String walletId}) async { @@ -264,19 +267,19 @@ class DB { // reads List keys({required String boxName}) => - Hive.box(boxName).keys.toList(growable: false); + hive.box(boxName).keys.toList(growable: false); List values({required String boxName}) => - Hive.box(boxName).values.toList(growable: false); + hive.box(boxName).values.toList(growable: false); T? get({ required String boxName, required dynamic key, }) => - Hive.box(boxName).get(key); + hive.box(boxName).get(key); bool containsKey({required String boxName, required dynamic key}) => - Hive.box(boxName).containsKey(key); + hive.box(boxName).containsKey(key); // writes @@ -286,33 +289,33 @@ class DB { required T value, }) async => await mutex - .protect(() async => await Hive.box(boxName).put(key, value)); + .protect(() async => await hive.box(boxName).put(key, value)); Future add({required String boxName, required T value}) async => - await mutex.protect(() async => await Hive.box(boxName).add(value)); + await mutex.protect(() async => await hive.box(boxName).add(value)); Future addAll({ required String boxName, required Iterable values, }) async => await mutex - .protect(() async => await Hive.box(boxName).addAll(values)); + .protect(() async => await hive.box(boxName).addAll(values)); Future delete({ required dynamic key, required String boxName, }) async => - await mutex.protect(() async => await Hive.box(boxName).delete(key)); + await mutex.protect(() async => await hive.box(boxName).delete(key)); Future deleteAll({required String boxName}) async { await mutex.protect(() async { - final box = await Hive.openBox(boxName); + final box = await hive.openBox(boxName); await box.clear(); }); } Future deleteBoxFromDisk({required String boxName}) async => - await mutex.protect(() async => await Hive.deleteBoxFromDisk(boxName)); + await mutex.protect(() async => await hive.deleteBoxFromDisk(boxName)); /////////////////////////////////////////////////////////////////////////// Future deleteEverything() async { diff --git a/lib/db/migrate_wallets_to_isar.dart b/lib/db/migrate_wallets_to_isar.dart index 474924997..11ae18e0a 100644 --- a/lib/db/migrate_wallets_to_isar.dart +++ b/lib/db/migrate_wallets_to_isar.dart @@ -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 migrateWalletsToIsar({ await MainDB.instance.isar .writeTxn(() async => await MainDB.instance.isar.transactionV2s.clear()); - final allWalletsBox = await Hive.openBox(DB.boxNameAllWalletsData); + final allWalletsBox = + await DB.instance.hive.openBox(DB.boxNameAllWalletsData); final names = DB.instance .get(boxName: DB.boxNameAllWalletsData, key: 'names') as Map?; @@ -55,7 +55,9 @@ Future migrateWalletsToIsar({ // Get current ordered list of favourite wallet Ids // final List favourites = - (await Hive.openBox(DB.boxNameFavoriteWallets)).values.toList(); + (await DB.instance.hive.openBox(DB.boxNameFavoriteWallets)) + .values + .toList(); final List<(WalletInfo, WalletInfoMeta)> newInfo = []; final List tokenInfo = []; @@ -65,7 +67,7 @@ Future migrateWalletsToIsar({ // Convert each old info into the new Isar WalletInfo // for (final old in oldInfo) { - final walletBox = await Hive.openBox(old.walletId); + final walletBox = await DB.instance.hive.openBox(old.walletId); // // First handle transaction notes @@ -212,9 +214,9 @@ Future migrateWalletsToIsar({ } Future _cleanupOnSuccess({required List 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); } } diff --git a/lib/db/special_migrations.dart b/lib/db/special_migrations.dart new file mode 100644 index 000000000..1092cfc1b --- /dev/null +++ b/lib/db/special_migrations.dart @@ -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( + boxName: DB.boxNameDBInfo, + key: _didRunKey, + ) as bool? ?? + false; + + static Future setDidRun() async { + await DB.instance.put( + 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? _wallets; + + static Future 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('wallets'); + _secureStore = const FlutterSecureStorage(); + } else { + await setDidRun(); + } + } + + static Future)>> fetch() async { + if (didRun || + Util.isDesktop || + AppConfig.appName != "Campfire" || + _wallets == null) { + return []; + } + + final names = _wallets!.get("names"); + + final List<(String, List)> 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; + } +} diff --git a/lib/main.dart b/lib/main.dart index 68d1fe48c..09ad6f068 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -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 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(DB.boxNameDBInfo); - await Hive.openBox(DB.boxNamePrefs); + await DB.instance.hive.openBox(DB.boxNameDBInfo); + await DB.instance.hive.openBox(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 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 diff --git a/lib/pages/campfire_migrate_view.dart b/lib/pages/campfire_migrate_view.dart new file mode 100644 index 000000000..b70a30279 --- /dev/null +++ b/lib/pages/campfire_migrate_view.dart @@ -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()!.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 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()!.background, + borderColor: Theme.of(context).extension()!.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), + ), + ), + ], + ), + ); + } +} diff --git a/lib/pages_desktop_specific/password/delete_password_warning_view.dart b/lib/pages_desktop_specific/password/delete_password_warning_view.dart index 7708c2230..1eab70a5a 100644 --- a/lib/pages_desktop_specific/password/delete_password_warning_view.dart +++ b/lib/pages_desktop_specific/password/delete_password_warning_view.dart @@ -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()) { diff --git a/lib/utilities/desktop_password_service.dart b/lib/utilities/desktop_password_service.dart index 323be414b..3852a8695 100644 --- a/lib/utilities/desktop_password_service.dart +++ b/lib/utilities/desktop_password_service.dart @@ -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 _put({required String key, required String value}) async { Box? box; try { - box = await Hive.openBox(kBoxNameDesktopData); + box = await DB.instance.hive.openBox(kBoxNameDesktopData); await box.put(key, value); } catch (e, s) { Logging.instance.log( @@ -201,7 +202,7 @@ class DPS { String? value; Box? box; try { - box = await Hive.openBox(kBoxNameDesktopData); + box = await DB.instance.hive.openBox(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 deleteBox() async { - await Hive.deleteBoxFromDisk(kBoxNameDesktopData); + await DB.instance.hive.deleteBoxFromDisk(kBoxNameDesktopData); } } diff --git a/lib/utilities/stack_file_system.dart b/lib/utilities/stack_file_system.dart index 579db5de0..53e382ff0 100644 --- a/lib/utilities/stack_file_system.dart +++ b/lib/utilities/stack_file_system.dart @@ -29,6 +29,9 @@ abstract class StackFileSystem { _overrideDirSet = true; } + static bool get _createSubDirs => + Util.isDesktop || AppConfig.appName == "Campfire"; + static Future applicationRootDirectory() async { Directory appDirectory; @@ -80,7 +83,7 @@ abstract class StackFileSystem { static Future 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 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 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 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 applicationHiveDirectory() async { final root = await applicationRootDirectory(); - if (Util.isDesktop) { + if (_createSubDirs) { final dir = Directory("${root.path}/hive"); if (!dir.existsSync()) { await dir.create(); diff --git a/lib/widgets/onetime_popups/tor_has_been_add_dialog.dart b/lib/widgets/onetime_popups/tor_has_been_add_dialog.dart index ab03f5ae0..9709c46b3 100644 --- a/lib/widgets/onetime_popups/tor_has_been_add_dialog.dart +++ b/lib/widgets/onetime_popups/tor_has_been_add_dialog.dart @@ -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 showOneTimeTorHasBeenAddedDialogIfRequired( BuildContext context, ) async { - final box = await Hive.openBox(DB.boxNameOneTimeDialogsShown); + final box = + await DB.instance.hive.openBox(DB.boxNameOneTimeDialogsShown); if (!box.get( _kOneTimeTorHasBeenAddedDialogWasShown, @@ -48,7 +48,9 @@ class _TorHasBeenAddedDialogState extends State<_TorHasBeenAddedDialog> { } _lock = true; try { - final box = await Hive.openBox(DB.boxNameOneTimeDialogsShown); + final box = await DB.instance.hive.openBox( + DB.boxNameOneTimeDialogsShown, + ); await box.put(_kOneTimeTorHasBeenAddedDialogWasShown, true); } catch (_) { //