stack_wallet/lib/main.dart

824 lines
29 KiB
Dart
Raw Normal View History

2023-05-26 21:21:16 +00:00
/*
* This file is part of Stack Wallet.
*
* Copyright (c) 2023 Cypher Stack
* All Rights Reserved.
* The code is distributed under GPLv3 license, see LICENSE file for details.
* Generated by Cypher Stack on 2023-05-26
*
*/
2022-08-26 08:11:35 +00:00
import 'dart:async';
import 'dart:io';
import 'dart:math';
2022-08-26 08:11:35 +00:00
import 'package:coinlib_flutter/coinlib_flutter.dart';
2022-08-26 08:11:35 +00:00
import 'package:cw_core/node.dart';
import 'package:cw_core/pathForWallet.dart';
2022-08-26 08:11:35 +00:00
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cw_core/wallet_info.dart';
import 'package:cw_core/wallet_type.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_libmonero/monero/monero.dart';
2022-09-27 08:09:31 +00:00
import 'package:flutter_libmonero/wownero/wownero.dart';
2022-08-26 08:11:35 +00:00
import 'package:flutter_riverpod/flutter_riverpod.dart';
2022-11-09 22:43:26 +00:00
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
2022-08-26 08:11:35 +00:00
import 'package:google_fonts/google_fonts.dart';
import 'package:isar/isar.dart';
import 'package:keyboard_dismisser/keyboard_dismisser.dart';
import 'package:path_provider/path_provider.dart';
2024-05-23 15:20:11 +00:00
import 'package:window_size/window_size.dart';
import 'app_config.dart';
import 'db/db_version_migration.dart';
import 'db/hive/db.dart';
import 'db/isar/main_db.dart';
2024-06-10 22:50:26 +00:00
import 'db/special_migrations.dart';
2024-05-29 19:29:45 +00:00
import 'db/sqlite/firo_cache.dart';
import 'models/exchange/change_now/exchange_transaction.dart';
import 'models/exchange/change_now/exchange_transaction_status.dart';
import 'models/exchange/response_objects/trade.dart';
import 'models/isar/models/isar_models.dart';
import 'models/models.dart';
import 'models/node_model.dart';
import 'models/notification_model.dart';
import 'models/trade_wallet_lookup.dart';
2024-06-10 22:50:26 +00:00
import 'pages/campfire_migrate_view.dart';
import 'pages/home_view/home_view.dart';
import 'pages/intro_view.dart';
import 'pages/loading_view.dart';
import 'pages/pinpad_views/create_pin_view.dart';
import 'pages/pinpad_views/lock_screen_view.dart';
import 'pages/settings_views/global_settings_view/stack_backup_views/restore_from_encrypted_string_view.dart';
import 'pages_desktop_specific/password/desktop_login_view.dart';
import 'providers/db/main_db_provider.dart';
import 'providers/desktop/storage_crypto_handler_provider.dart';
import 'providers/global/auto_swb_service_provider.dart';
import 'providers/global/base_currencies_provider.dart';
2022-08-26 08:11:35 +00:00
// import 'package:stackwallet/providers/global/has_authenticated_start_state_provider.dart';
import 'providers/global/trades_service_provider.dart';
import 'providers/providers.dart';
import 'route_generator.dart';
2023-01-24 21:28:11 +00:00
// import 'package:stackwallet/services/buy/buy_data_loading_service.dart';
import 'services/debug_service.dart';
import 'services/exchange/exchange_data_loading_service.dart';
import 'services/locale_service.dart';
import 'services/node_service.dart';
import 'services/notifications_api.dart';
import 'services/notifications_service.dart';
import 'services/tor_service.dart';
import 'services/trade_service.dart';
import 'themes/theme_providers.dart';
import 'themes/theme_service.dart';
import 'utilities/constants.dart';
import 'utilities/enums/backup_frequency_type.dart';
import 'utilities/flutter_secure_storage_interface.dart';
import 'utilities/logger.dart';
import 'utilities/prefs.dart';
import 'utilities/stack_file_system.dart';
import 'utilities/util.dart';
import 'wallets/isar/providers/all_wallets_info_provider.dart';
import 'widgets/crypto_notifications.dart';
2022-08-26 08:11:35 +00:00
final openedFromSWBFileStringStateProvider =
StateProvider<String?>((ref) => null);
// main() is the entry point to the app. It initializes Hive (local database),
// runs the MyApp widget and checks for new users, caching the value in the
// miscellaneous box for later use
void main(List<String> args) async {
2023-05-23 23:47:52 +00:00
WidgetsFlutterBinding.ensureInitialized();
if (Util.isDesktop && args.length == 2 && args.first == "-d") {
2024-05-23 15:20:11 +00:00
StackFileSystem.setDesktopOverrideDir(args.last);
}
// Tell flutter_libmonero how to get access to the application dir
FS.setApplicationRootDirectoryFunction(
StackFileSystem.applicationRootDirectory,
);
// TODO set any other external libs file paths (bad external lib design workaround)
2024-05-23 15:20:11 +00:00
final loadCoinlibFuture = loadCoinlib();
2022-09-24 21:20:58 +00:00
GoogleFonts.config.allowRuntimeFetching = false;
2022-10-28 18:03:52 +00:00
if (Platform.isIOS) {
Util.libraryPath = await getLibraryDirectory();
}
2022-11-28 18:46:35 +00:00
Screen? screen;
if (Platform.isLinux || (Util.isDesktop && !Platform.isIOS)) {
2022-11-28 18:46:35 +00:00
screen = await getCurrentScreen();
Util.screenWidth = screen?.frame.width;
}
if (Util.isDesktop && !Platform.isIOS) {
setWindowTitle(AppConfig.appName);
setWindowMinSize(const Size(1220, 100));
setWindowMaxSize(Size.infinite);
2022-11-28 18:46:35 +00:00
final screenHeight = screen?.frame.height;
2023-09-11 22:27:44 +00:00
if (screenHeight != null) {
// starting to height be 3/4 screen height or 900, whichever is smaller
final height = min<double>(screenHeight * 0.75, 900);
setWindowFrame(
Rect.fromLTWH(0, 0, 1220, height),
);
}
}
2022-08-26 08:11:35 +00:00
// FlutterNativeSplash.preserve(widgetsBinding: widgetsBinding);
2022-09-01 09:06:47 +00:00
if (!(Logging.isArmLinux || Logging.isTestEnv)) {
2022-09-01 08:51:06 +00:00
final isar = await Isar.open(
[LogSchema],
2022-11-12 22:04:16 +00:00
directory: (await StackFileSystem.applicationIsarDirectory()).path,
2022-09-01 08:51:06 +00:00
inspector: false,
2023-02-11 00:41:21 +00:00
maxSizeMiB: 512,
2022-09-01 08:51:06 +00:00
);
await Logging.instance.init(isar);
await DebugService.instance.init(isar);
2022-08-26 08:11:35 +00:00
2022-09-01 08:51:06 +00:00
// clear out all info logs on startup. No need to await and block
unawaited(DebugService.instance.deleteLogsOlderThan());
2022-09-01 08:51:06 +00:00
}
2022-08-26 08:11:35 +00:00
// Registering Transaction Model Adapters
2024-06-10 22:50:26 +00:00
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());
2022-08-26 08:11:35 +00:00
// Registering Utxo Model Adapters
2024-06-10 22:50:26 +00:00
DB.instance.hive.registerAdapter(UtxoDataAdapter());
DB.instance.hive.registerAdapter(UtxoObjectAdapter());
DB.instance.hive.registerAdapter(StatusAdapter());
2022-08-26 08:11:35 +00:00
// Registering Lelantus Model Adapters
2024-06-10 22:50:26 +00:00
DB.instance.hive.registerAdapter(LelantusCoinAdapter());
2022-08-26 08:11:35 +00:00
// notification model adapter
2024-06-10 22:50:26 +00:00
DB.instance.hive.registerAdapter(NotificationModelAdapter());
2022-08-26 08:11:35 +00:00
// change now trade adapters
2024-06-10 22:50:26 +00:00
DB.instance.hive.registerAdapter(ExchangeTransactionAdapter());
DB.instance.hive.registerAdapter(ExchangeTransactionStatusAdapter());
2022-08-26 08:11:35 +00:00
2024-06-10 22:50:26 +00:00
DB.instance.hive.registerAdapter(TradeAdapter());
2022-10-03 00:55:54 +00:00
2022-08-26 08:11:35 +00:00
// reference lookup data adapter
2024-06-10 22:50:26 +00:00
DB.instance.hive.registerAdapter(TradeWalletLookupAdapter());
2022-08-26 08:11:35 +00:00
// node model adapter
2024-06-10 22:50:26 +00:00
DB.instance.hive.registerAdapter(NodeModelAdapter());
2022-08-26 08:11:35 +00:00
2024-06-10 22:50:26 +00:00
DB.instance.hive.registerAdapter(NodeAdapter());
2022-08-26 08:11:35 +00:00
2024-06-10 22:50:26 +00:00
if (!DB.instance.hive.isAdapterRegistered(WalletInfoAdapter().typeId)) {
DB.instance.hive.registerAdapter(WalletInfoAdapter());
2022-09-27 08:09:31 +00:00
}
2022-08-26 08:11:35 +00:00
2024-06-10 22:50:26 +00:00
DB.instance.hive.registerAdapter(WalletTypeAdapter());
2022-08-26 08:11:35 +00:00
2024-06-10 22:50:26 +00:00
DB.instance.hive.registerAdapter(UnspentCoinsInfoAdapter());
DB.instance.hive.init(
2024-05-27 23:56:22 +00:00
(await StackFileSystem.applicationHiveDirectory()).path,
);
2022-08-26 08:11:35 +00:00
2024-06-10 22:50:26 +00:00
await DB.instance.hive.openBox<dynamic>(DB.boxNameDBInfo);
await DB.instance.hive.openBox<dynamic>(DB.boxNamePrefs);
2023-03-20 22:02:20 +00:00
await Prefs.instance.init();
2022-11-09 22:43:26 +00:00
2024-06-10 22:50:26 +00:00
if (AppConfig.appName == "Campfire" &&
!Util.isDesktop &&
!CampfireMigration.didRun) {
await CampfireMigration.init();
}
2023-09-08 13:53:06 +00:00
// TODO:
// This should be moved to happen during the loading animation instead of
// showing a blank screen for 4-10 seconds.
// Some refactoring will need to be done here to make sure we don't make any
// network calls before starting up tor
2023-08-07 17:06:44 +00:00
if (Prefs.instance.useTor) {
2023-09-15 19:51:20 +00:00
TorService.sharedInstance.init(
torDataDirPath: (await StackFileSystem.applicationTorDirectory()).path,
);
2023-08-07 16:46:34 +00:00
await TorService.sharedInstance.start();
}
2023-07-04 00:25:18 +00:00
await StackFileSystem.initThemesDir();
2024-05-29 19:29:45 +00:00
await FiroCacheCoordinator.init();
2023-07-04 00:25:18 +00:00
2023-01-18 14:07:25 +00:00
// Desktop migrate handled elsewhere (currently desktop_login_view.dart)
2022-11-09 22:43:26 +00:00
if (!Util.isDesktop) {
2024-05-27 23:56:22 +00:00
final int dbVersion = DB.instance.get<dynamic>(
boxName: DB.boxNameDBInfo,
key: "hive_data_version",
) as int? ??
2022-11-09 22:43:26 +00:00
0;
2023-05-15 20:21:09 +00:00
if (dbVersion < Constants.currentDataVersion) {
2022-11-09 22:43:26 +00:00
try {
await DbVersionMigrator().migrate(
dbVersion,
secureStore: const SecureStorageWrapper(
store: FlutterSecureStorage(),
isDesktop: false,
),
);
} catch (e, s) {
2024-05-27 23:56:22 +00:00
Logging.instance.log(
"Cannot migrate mobile database\n$e $s",
level: LogLevel.Error,
printFullLength: true,
);
2022-11-09 22:43:26 +00:00
}
2022-10-19 22:51:50 +00:00
}
}
2022-08-26 08:11:35 +00:00
2024-05-01 14:42:54 +00:00
monero.onStartup();
wownero.onStartup();
2022-08-26 08:11:35 +00:00
// SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
// overlays: [SystemUiOverlay.bottom]);
await NotificationApi.init();
await loadCoinlibFuture;
await MainDB.instance.initMainDB();
ThemeService.instance.init(MainDB.instance);
// check and update or install default themes
await ThemeService.instance.checkDefaultThemesOnStartup();
2023-06-07 14:36:47 +00:00
// verify current user preference theme and revert to default
// if problems are found to prevent app being unusable
if (!(await ThemeService.instance
.verifyInstalled(themeId: Prefs.instance.themeId))) {
Prefs.instance.themeId = "light";
2023-05-10 14:53:46 +00:00
}
2023-06-07 14:36:47 +00:00
// verify current user preference light brightness theme and revert to default
// if problems are found to prevent app being unusable
if (!(await ThemeService.instance
.verifyInstalled(themeId: Prefs.instance.systemBrightnessLightThemeId))) {
Prefs.instance.systemBrightnessLightThemeId = "light";
}
// verify current user preference dark brightness theme and revert to default
// if problems are found to prevent app being unusable
if (!(await ThemeService.instance
.verifyInstalled(themeId: Prefs.instance.systemBrightnessDarkThemeId))) {
Prefs.instance.systemBrightnessDarkThemeId = "dark";
2023-05-10 14:53:46 +00:00
}
2022-08-26 08:11:35 +00:00
runApp(const ProviderScope(child: MyApp()));
}
/// MyApp initialises relevant services with a MultiProvider
class MyApp extends StatelessWidget {
2024-05-27 23:56:22 +00:00
const MyApp({super.key});
2022-08-26 08:11:35 +00:00
@override
Widget build(BuildContext context) {
final localeService = LocaleService();
localeService.loadLocale();
return const KeyboardDismisser(
2023-05-09 18:01:55 +00:00
child: MaterialAppWithTheme(),
2022-08-26 08:11:35 +00:00
);
}
}
// Sidenote: MaterialAppWithTheme and InitView are only separated for clarity. No other reason.
class MaterialAppWithTheme extends ConsumerStatefulWidget {
const MaterialAppWithTheme({
2024-05-27 23:56:22 +00:00
super.key,
});
2022-08-26 08:11:35 +00:00
@override
ConsumerState<MaterialAppWithTheme> createState() =>
_MaterialAppWithThemeState();
}
class _MaterialAppWithThemeState extends ConsumerState<MaterialAppWithTheme>
with WidgetsBindingObserver {
static const platform = MethodChannel("STACK_WALLET_RESTORE");
final GlobalKey<NavigatorState> navigatorKey = GlobalKey<NavigatorState>();
// late final Wallets _wallets;
// late final Prefs _prefs;
2022-08-26 08:11:35 +00:00
late final NotificationsService _notificationsService;
late final NodeService _nodeService;
late final TradesService _tradesService;
late final Completer<void> loadingCompleter;
2022-08-26 16:38:33 +00:00
bool didLoad = false;
2022-11-11 15:31:01 +00:00
bool didLoadShared = false;
2022-11-04 19:32:02 +00:00
bool _desktopHasPassword = false;
2022-08-26 16:38:33 +00:00
Future<void> loadShared() async {
2022-11-11 15:31:01 +00:00
if (didLoadShared) {
return;
}
didLoadShared = true;
await DB.instance.init();
await ref.read(prefsChangeNotifierProvider).init();
2022-11-25 23:14:06 +00:00
final familiarity = ref.read(prefsChangeNotifierProvider).familiarity + 1;
ref.read(prefsChangeNotifierProvider).familiarity = familiarity;
Constants.exchangeForExperiencedUsers(familiarity);
if (Util.isDesktop) {
_desktopHasPassword =
await ref.read(storageCryptoHandlerProvider).hasPassword();
}
}
2022-08-26 08:11:35 +00:00
Future<void> load() async {
2022-10-28 18:03:52 +00:00
try {
if (didLoad) {
return;
}
didLoad = true;
if (!Util.isDesktop) {
await loadShared();
2022-11-04 19:32:02 +00:00
}
2023-04-24 14:36:12 +00:00
ref.read(applicationThemesDirectoryPathProvider.notifier).state =
2023-07-04 00:25:18 +00:00
StackFileSystem.themesDir!.path;
2022-10-28 18:03:52 +00:00
_notificationsService = ref.read(notificationsProvider);
_nodeService = ref.read(nodeServiceChangeNotifierProvider);
_tradesService = ref.read(tradesServiceProvider);
NotificationApi.prefs = ref.read(prefsChangeNotifierProvider);
2022-10-28 18:03:52 +00:00
NotificationApi.notificationsService = _notificationsService;
unawaited(ref.read(baseCurrenciesProvider).update());
await _nodeService.updateDefaults();
await _notificationsService.init(
nodeService: _nodeService,
tradesService: _tradesService,
prefs: ref.read(prefsChangeNotifierProvider),
2022-10-28 18:03:52 +00:00
);
ref.read(priceAnd24hChangeNotifierProvider).start(true);
await ref.read(pWallets).load(
ref.read(prefsChangeNotifierProvider),
ref.read(mainDBProvider),
);
2022-10-28 18:03:52 +00:00
loadingCompleter.complete();
// TODO: this should probably run unawaited. Keep commented out for now as proper community nodes ui hasn't been implemented yet
// unawaited(_nodeService.updateCommunityNodes());
if (AppConfig.hasFeature(AppFeature.swap)) {
await ExchangeDataLoadingService.instance.initDB();
// run without awaiting
if (ref.read(prefsChangeNotifierProvider).externalCalls &&
await ref.read(prefsChangeNotifierProvider).isExternalCallsSet()) {
if (Constants.enableExchange) {
await ExchangeDataLoadingService.instance.setCurrenciesIfEmpty(
ref.read(efCurrencyPairProvider),
ref.read(efRateTypeProvider),
);
unawaited(ExchangeDataLoadingService.instance.loadAll());
}
// if (Constants.enableBuy) {
// unawaited(BuyDataLoadingService().loadAll(ref));
// }
2023-01-12 00:13:34 +00:00
}
2022-10-28 18:03:52 +00:00
}
2022-10-04 14:46:22 +00:00
if (ref.read(prefsChangeNotifierProvider).isAutoBackupEnabled) {
switch (ref.read(prefsChangeNotifierProvider).backupFrequencyType) {
2022-10-28 18:03:52 +00:00
case BackupFrequencyType.everyTenMinutes:
ref.read(autoSWBServiceProvider).startPeriodicBackupTimer(
2024-05-27 23:56:22 +00:00
duration: const Duration(minutes: 10),
);
2022-10-28 18:03:52 +00:00
break;
case BackupFrequencyType.everyAppStart:
unawaited(ref.read(autoSWBServiceProvider).doBackup());
break;
case BackupFrequencyType.afterClosingAWallet:
// ignore this case here
break;
}
2022-08-26 08:11:35 +00:00
}
// ref
// .read(prefsChangeNotifierProvider)
// .userID; // Just reading the ref should set it if it's not already set
// We shouldn't need to do this, instead only generating an ID when (or if) the userID is looked up when creating a quote
2022-10-28 18:03:52 +00:00
} catch (e, s) {
Logger.print("$e $s", normalLength: false);
2022-08-26 08:11:35 +00:00
}
}
@override
void initState() {
String themeId;
2023-03-20 22:02:20 +00:00
if (ref.read(prefsChangeNotifierProvider).enableSystemBrightness) {
final brightness = WidgetsBinding.instance.window.platformBrightness;
2023-03-20 22:02:20 +00:00
switch (brightness) {
case Brightness.dark:
themeId =
ref.read(prefsChangeNotifierProvider).systemBrightnessDarkThemeId;
2023-03-20 22:02:20 +00:00
break;
case Brightness.light:
themeId = ref
.read(prefsChangeNotifierProvider)
.systemBrightnessLightThemeId;
2023-03-20 22:02:20 +00:00
break;
}
} else {
themeId = ref.read(prefsChangeNotifierProvider).themeId;
2022-09-23 14:33:44 +00:00
}
2022-08-26 08:11:35 +00:00
loadingCompleter = Completer();
WidgetsBinding.instance.addObserver(this);
// load locale and prefs
ref
.read(localeServiceChangeNotifierProvider.notifier)
.loadLocale(notify: false);
WidgetsBinding.instance.addPostFrameCallback((_) async {
//Add themes path to provider
ref.read(applicationThemesDirectoryPathProvider.notifier).state =
2023-07-04 00:25:18 +00:00
StackFileSystem.themesDir!.path;
ref.read(themeProvider.state).state = ref.read(pThemeService).getTheme(
themeId: themeId,
)!;
if (Platform.isAndroid) {
// fetch open file if it exists
await getOpenFile();
2022-08-26 08:11:35 +00:00
if (ref.read(openedFromSWBFileStringStateProvider.state).state !=
null) {
// waiting for loading to complete before going straight to restore if the app was opened via file
await loadingCompleter.future;
2022-08-26 08:11:35 +00:00
await goToRestoreSWB(
2024-05-27 23:56:22 +00:00
ref.read(openedFromSWBFileStringStateProvider.state).state!,
);
ref.read(openedFromSWBFileStringStateProvider.state).state = null;
}
// ref.read(shouldShowLockscreenOnResumeStateProvider.state).state = false;
}
});
2022-08-26 08:11:35 +00:00
WidgetsBinding.instance.window.onPlatformBrightnessChanged = () {
String themeId;
switch (WidgetsBinding.instance.window.platformBrightness) {
case Brightness.dark:
themeId =
ref.read(prefsChangeNotifierProvider).systemBrightnessDarkThemeId;
break;
case Brightness.light:
themeId = ref
.read(prefsChangeNotifierProvider)
.systemBrightnessLightThemeId;
break;
}
WidgetsBinding.instance.addPostFrameCallback((_) {
2023-03-21 00:08:45 +00:00
if (ref.read(prefsChangeNotifierProvider).enableSystemBrightness) {
ref.read(themeProvider.state).state =
ref.read(pThemeService).getTheme(
themeId: themeId,
)!;
2023-03-21 00:08:45 +00:00
}
});
};
2022-08-26 08:11:35 +00:00
super.initState();
}
@override
dispose() {
WidgetsBinding.instance.removeObserver(this);
super.dispose();
}
@override
void didChangeLocales(List<Locale>? locales) {
ref.read(localeServiceChangeNotifierProvider).loadLocale();
super.didChangeLocales(locales);
}
2022-08-26 08:11:35 +00:00
@override
void didChangeAppLifecycleState(AppLifecycleState state) async {
debugPrint("didChangeAppLifecycleState: ${state.name}");
if (state == AppLifecycleState.resumed) {}
switch (state) {
case AppLifecycleState.inactive:
break;
case AppLifecycleState.paused:
break;
case AppLifecycleState.resumed:
if (Platform.isAndroid) {
// fetch open file if it exists
await getOpenFile();
// go straight to restore if the app was resumed via file
if (ref.read(openedFromSWBFileStringStateProvider.state).state !=
null) {
await goToRestoreSWB(
2024-05-27 23:56:22 +00:00
ref.read(openedFromSWBFileStringStateProvider.state).state!,
);
ref.read(openedFromSWBFileStringStateProvider.state).state = null;
}
2022-08-26 08:11:35 +00:00
}
// if (ref.read(hasAuthenticatedOnStartStateProvider.state).state &&
// ref.read(shouldShowLockscreenOnResumeStateProvider.state).state) {
// final now = DateTime.now().toUtc().millisecondsSinceEpoch ~/ 1000;
//
// if (now - _prefs.lastUnlocked > _prefs.lastUnlockedTimeout) {
// ref.read(shouldShowLockscreenOnResumeStateProvider.state).state =
// false;
// Navigator.of(navigatorKey.currentContext!).push(
// MaterialPageRoute<dynamic>(
// builder: (_) => LockscreenView(
// routeOnSuccess: "",
// popOnSuccess: true,
// biometricsAuthenticationTitle: "Unlock Stack",
// biometricsLocalizedReason:
// "Unlock your stack wallet using biometrics",
// biometricsCancelButtonString: "Cancel",
// onSuccess: () {
// ref
// .read(shouldShowLockscreenOnResumeStateProvider.state)
// .state = true;
// },
// ),
// ),
// );
// }
// }
break;
case AppLifecycleState.detached:
break;
2024-01-18 19:17:29 +00:00
case AppLifecycleState.hidden:
break;
2022-08-26 08:11:35 +00:00
}
}
/// should only be called on android currently
2022-08-26 08:11:35 +00:00
Future<void> getOpenFile() async {
// update provider with new file content state
ref.read(openedFromSWBFileStringStateProvider.state).state =
await platform.invokeMethod("getOpenFile");
// call reset to clear cached value
await resetOpenPath();
Logging.instance.log(
2024-05-27 23:56:22 +00:00
"This is the .swb content from intent: ${ref.read(openedFromSWBFileStringStateProvider.state).state}",
level: LogLevel.Info,
);
2022-08-26 08:11:35 +00:00
}
/// should only be called on android currently
2022-08-26 08:11:35 +00:00
Future<void> resetOpenPath() async {
await platform.invokeMethod("resetOpenPath");
}
Future<void> goToRestoreSWB(String encrypted) async {
if (!ref.read(prefsChangeNotifierProvider).hasPin) {
2022-08-26 08:11:35 +00:00
await Navigator.of(navigatorKey.currentContext!)
.pushNamed(CreatePinView.routeName, arguments: true)
.then((value) {
if (value is! bool || value == false) {
Navigator.of(navigatorKey.currentContext!).pushNamed(
2024-05-27 23:56:22 +00:00
RestoreFromEncryptedStringView.routeName,
arguments: encrypted,
);
2022-08-26 08:11:35 +00:00
}
});
} else {
2024-05-27 23:56:22 +00:00
unawaited(
Navigator.push(
navigatorKey.currentContext!,
RouteGenerator.getRoute(
shouldUseMaterialRoute: RouteGenerator.useMaterialPageRoute,
builder: (_) => LockscreenView(
showBackButton: true,
routeOnSuccess: RestoreFromEncryptedStringView.routeName,
routeOnSuccessArguments: encrypted,
biometricsCancelButtonString: "CANCEL",
biometricsLocalizedReason:
"Authenticate to restore ${AppConfig.appName} backup",
biometricsAuthenticationTitle:
"Restore ${AppConfig.prefix} backup",
),
settings: const RouteSettings(name: "/swbrestorelockscreen"),
2022-08-26 08:11:35 +00:00
),
),
2024-05-27 23:56:22 +00:00
);
2022-08-26 08:11:35 +00:00
}
}
InputBorder _buildOutlineInputBorder(Color color) {
return OutlineInputBorder(
borderSide: BorderSide(
width: 1,
color: color,
),
borderRadius: BorderRadius.circular(Constants.size.circularBorderRadius),
);
}
@override
Widget build(BuildContext context) {
debugPrint("BUILD: $runtimeType");
// ref.listen(shouldShowLockscreenOnResumeStateProvider, (previous, next) {
// Logging.instance.log("shouldShowLockscreenOnResumeStateProvider set to: $next",
// addToDebugMessagesDB: false);
// });
2023-04-24 14:36:12 +00:00
final colorScheme = ref.watch(colorProvider.state).state;
2022-09-22 22:17:21 +00:00
2022-08-26 08:11:35 +00:00
return MaterialApp(
key: GlobalKey(),
navigatorKey: navigatorKey,
title: AppConfig.appName,
2022-08-26 08:11:35 +00:00
onGenerateRoute: RouteGenerator.generateRoute,
theme: ThemeData(
2022-09-22 22:17:21 +00:00
extensions: [colorScheme],
highlightColor: colorScheme.highlight,
2023-03-17 22:10:22 +00:00
brightness: colorScheme.brightness,
2022-08-26 08:11:35 +00:00
fontFamily: GoogleFonts.inter().fontFamily,
2022-09-22 22:17:21 +00:00
unselectedWidgetColor: colorScheme.radioButtonBorderDisabled,
// textTheme: GoogleFonts.interTextTheme().copyWith(
// button: STextStyles.button(context),
// subtitle1: STextStyles.field(context).copyWith(
// color: colorScheme.textDark,
// ),
// ),
2022-08-26 08:11:35 +00:00
radioTheme: const RadioThemeData(
splashRadius: 0,
materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
),
// splashFactory: NoSplash.splashFactory,
splashColor: Colors.transparent,
buttonTheme: ButtonThemeData(
2022-09-22 22:17:21 +00:00
splashColor: colorScheme.splash,
2022-08-26 08:11:35 +00:00
),
textButtonTheme: TextButtonThemeData(
style: ButtonStyle(
// splashFactory: NoSplash.splashFactory,
2022-09-22 22:17:21 +00:00
overlayColor: MaterialStateProperty.all(colorScheme.splash),
2022-08-26 08:11:35 +00:00
minimumSize: MaterialStateProperty.all<Size>(const Size(46, 46)),
2022-09-22 22:17:21 +00:00
// textStyle: MaterialStateProperty.all<TextStyle>(
// STextStyles.button(context)),
foregroundColor:
MaterialStateProperty.all(colorScheme.buttonTextSecondary),
2022-09-21 00:46:07 +00:00
backgroundColor: MaterialStateProperty.all<Color>(
2024-05-27 23:56:22 +00:00
colorScheme.buttonBackSecondary,
),
2022-08-26 08:11:35 +00:00
shape: MaterialStateProperty.all<OutlinedBorder>(
RoundedRectangleBorder(
// 1000 to be relatively sure it keeps its pill shape
borderRadius: BorderRadius.circular(1000),
),
),
),
),
2022-09-22 22:17:21 +00:00
primaryColor: colorScheme.accentColorDark,
primarySwatch: Util.createMaterialColor(colorScheme.accentColorDark),
2022-08-26 08:11:35 +00:00
checkboxTheme: CheckboxThemeData(
splashRadius: 0,
shape: RoundedRectangleBorder(
borderRadius:
BorderRadius.circular(Constants.size.checkboxBorderRadius),
),
checkColor: MaterialStateColor.resolveWith(
(state) {
if (state.contains(MaterialState.selected)) {
2022-09-22 22:17:21 +00:00
return colorScheme.checkboxIconChecked;
2022-08-26 08:11:35 +00:00
}
2022-09-22 22:17:21 +00:00
return colorScheme.checkboxBGChecked;
2022-08-26 08:11:35 +00:00
},
),
fillColor: MaterialStateColor.resolveWith(
(states) {
if (states.contains(MaterialState.selected)) {
2022-09-22 22:17:21 +00:00
return colorScheme.checkboxBGChecked;
2022-08-26 08:11:35 +00:00
}
2022-09-22 22:17:21 +00:00
return colorScheme.checkboxBorderEmpty;
2022-08-26 08:11:35 +00:00
},
),
),
2022-09-21 00:46:07 +00:00
appBarTheme: AppBarTheme(
2022-08-26 08:11:35 +00:00
centerTitle: false,
2022-09-22 22:17:21 +00:00
color: colorScheme.background,
surfaceTintColor: colorScheme.background,
2022-08-26 08:11:35 +00:00
elevation: 0,
),
inputDecorationTheme: InputDecorationTheme(
2022-09-22 22:17:21 +00:00
focusColor: colorScheme.textFieldDefaultBG,
fillColor: colorScheme.textFieldDefaultBG,
2022-08-26 08:11:35 +00:00
filled: true,
contentPadding: const EdgeInsets.symmetric(
vertical: 6,
horizontal: 12,
),
2022-09-22 22:17:21 +00:00
// labelStyle: STextStyles.fieldLabel(context),
// hintStyle: STextStyles.fieldLabel(context),
enabledBorder:
_buildOutlineInputBorder(colorScheme.textFieldDefaultBG),
focusedBorder:
_buildOutlineInputBorder(colorScheme.textFieldDefaultBG),
errorBorder: _buildOutlineInputBorder(colorScheme.textFieldDefaultBG),
disabledBorder:
_buildOutlineInputBorder(colorScheme.textFieldDefaultBG),
focusedErrorBorder:
_buildOutlineInputBorder(colorScheme.textFieldDefaultBG),
2022-08-26 08:11:35 +00:00
),
),
2023-05-09 18:01:55 +00:00
home: CryptoNotifications(
child: Util.isDesktop
? FutureBuilder(
future: loadShared(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
if (_desktopHasPassword) {
String? startupWalletId;
if (ref
.read(prefsChangeNotifierProvider)
.gotoWalletOnStartup) {
startupWalletId = ref
.read(prefsChangeNotifierProvider)
.startupWalletId;
}
return DesktopLoginView(
startupWalletId: startupWalletId,
load: load,
);
} else {
return const IntroView();
}
} else {
2023-05-09 18:01:55 +00:00
return const LoadingView();
}
2023-05-09 18:01:55 +00:00
},
)
: FutureBuilder(
future: load(),
builder: (BuildContext context, AsyncSnapshot<void> snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
// FlutterNativeSplash.remove();
if (ref.read(pAllWalletsInfo).isNotEmpty ||
2023-05-09 18:01:55 +00:00
ref.read(prefsChangeNotifierProvider).hasPin) {
// return HomeView();
String? startupWalletId;
if (ref
.read(prefsChangeNotifierProvider)
.gotoWalletOnStartup) {
startupWalletId = ref
.read(prefsChangeNotifierProvider)
.startupWalletId;
}
return LockscreenView(
isInitialAppLogin: true,
routeOnSuccess: HomeView.routeName,
routeOnSuccessArguments: startupWalletId,
2024-05-15 22:20:14 +00:00
biometricsAuthenticationTitle:
"Unlock ${AppConfig.prefix}",
2023-05-09 18:01:55 +00:00
biometricsLocalizedReason:
2024-05-15 22:20:14 +00:00
"Unlock your ${AppConfig.appName} using biometrics",
2023-05-09 18:01:55 +00:00
biometricsCancelButtonString: "Cancel",
);
} else {
2024-06-10 22:50:26 +00:00
if (AppConfig.appName == "Campfire" &&
!CampfireMigration.didRun &&
CampfireMigration.hasOldWallets) {
return const CampfireMigrateView();
} else {
return const IntroView();
}
}
} else {
2023-05-09 18:01:55 +00:00
// CURRENTLY DISABLED as cannot be animated
// technically not needed as FlutterNativeSplash will overlay
// anything returned here until the future completes but
// FutureBuilder requires you to return something
return const LoadingView();
}
2023-05-09 18:01:55 +00:00
},
),
),
2022-08-26 08:11:35 +00:00
);
}
}