mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-17 05:41:29 +02:00
94 files changed, -5926 net lines. No stubs, no generators, no dead enum
values, no orphan switch branches. Removed for principled reasons (we
do not ship these chains) and to make the codebase smaller and friendlier
to contribute to.
What's gone:
- lib/{solana,tron,zano,decred,zcash,haven}/ directories
- lib/exchange/provider/jupiter_exchange_provider.dart (Solana-only)
- lib/entities/haven_seed_store.dart
- WalletType.{solana,tron,zano,decred,zcash,haven} enum values
(HiveField IDs are pinned: Wownero stays at 12, all surviving types
keep their IDs, so existing user-saved wallets deserialize unchanged)
- All ~70 lib/ files that imported the removed chain stubs or branched
on the removed WalletType values
- backupSeeds(Box<HavenSeedStore>) abstract method + Wownero implementation
- Jupiter exchange branches in send/exchange view models
- TronGrid usage settings, Zano alias lookups, Zcash transparent address
handling, Decred default-spv-nodes branches, Haven seed migration
What stays (intentional):
- CryptoCurrency.{xhv,sol,trx,dcr,zano,zec} enum entries in cw_core —
they're still used as exchange/swap currency identifiers in
address_validator.dart and elsewhere. The wallet types are gone but
the *currencies* are still tradeable through Trocador.
- cw_core/spl_token.dart and cw_core/tron_token.dart Hive adapters in
main.dart — the tokens still register as Hive types for backwards-
compat with any old box data.
- lib/buy/{moonpay,robinhood,onramper,dfx,kryptonim,meld}/ provider
source files (just stripped of solana/tron/etc references; providers
themselves remain dormant per provider_types.dart).
Pinned-ID note: WalletType enum now has gaps in @HiveField IDs (4, 10,
11, 13, 14, 18 removed). This is deliberate — re-using a freed ID later
would mis-deserialize old hive boxes. Don't renumber.
Bundled config / CI hasn't changed; configure.dart was already free of
these chains in commit 4eb7db0b7.
560 lines
19 KiB
Dart
560 lines
19 KiB
Dart
import 'dart:async';
|
|
import 'dart:io';
|
|
import 'dart:ui';
|
|
|
|
import 'package:hash_wallet/anonpay/anonpay_invoice_info.dart';
|
|
import 'package:hash_wallet/app_scroll_behavior.dart';
|
|
import 'package:hash_wallet/core/auth_service.dart';
|
|
import 'package:hash_wallet/core/background_sync.dart';
|
|
import 'package:hash_wallet/core/node_switching_service.dart';
|
|
import 'package:hash_wallet/core/reset_service.dart';
|
|
import 'package:hash_wallet/core/secure_storage.dart';
|
|
import 'package:hash_wallet/core/trade_monitor.dart';
|
|
import 'package:hash_wallet/di.dart';
|
|
import 'package:hash_wallet/entities/contact.dart';
|
|
import 'package:hash_wallet/entities/default_settings_migration.dart';
|
|
import 'package:hash_wallet/entities/get_encryption_key.dart';
|
|
import 'package:hash_wallet/entities/language_service.dart';
|
|
import 'package:hash_wallet/entities/template.dart';
|
|
import 'package:hash_wallet/entities/transaction_description.dart';
|
|
import 'package:hash_wallet/exchange/exchange_template.dart';
|
|
import 'package:hash_wallet/exchange/trade_legacy.dart';
|
|
import 'package:hash_wallet/generated/i18n.dart';
|
|
import 'package:hash_wallet/locales/locale.dart';
|
|
import 'package:hash_wallet/order/order.dart';
|
|
import 'package:hash_wallet/reactions/bootstrap.dart';
|
|
import 'package:hash_wallet/router.dart' as Router;
|
|
import 'package:hash_wallet/routes.dart';
|
|
import 'package:hash_wallet/src/screens/root/root.dart';
|
|
import 'package:hash_wallet/store/app_store.dart';
|
|
import 'package:hash_wallet/store/authentication_store.dart';
|
|
import 'package:hash_wallet/store/settings_store.dart';
|
|
import 'package:hash_wallet/test_asset_bundles.dart';
|
|
import 'package:hash_wallet/themes/utils/theme_provider.dart';
|
|
import 'package:hash_wallet/utils/device_info.dart';
|
|
import 'package:hash_wallet/utils/exception_handler.dart';
|
|
import 'package:hash_wallet/utils/feature_flag.dart';
|
|
import 'package:hash_wallet/utils/responsive_layout_util.dart';
|
|
import 'package:hash_wallet/view_model/link_view_model.dart';
|
|
import 'package:cw_core/address_info.dart';
|
|
import 'package:cw_core/cake_hive.dart';
|
|
import 'package:cw_core/db/sqlite.dart';
|
|
import 'package:cw_core/erc20_token.dart';
|
|
import 'package:cw_core/hive_type_ids.dart';
|
|
import 'package:cw_core/key.dart';
|
|
import 'package:cw_core/mweb_utxo.dart';
|
|
import 'package:cw_core/node.dart';
|
|
import 'package:cw_core/payjoin_session.dart';
|
|
import 'package:cw_core/root_dir.dart';
|
|
import 'package:cw_core/spl_token.dart';
|
|
import 'package:cw_core/tron_token.dart';
|
|
import 'package:cw_core/unspent_coins_info.dart';
|
|
import 'package:cw_core/utils/print_verbose.dart';
|
|
import 'package:cw_core/utils/proxy_logger/memory_proxy_logger.dart';
|
|
import 'package:cw_core/utils/proxy_wrapper.dart';
|
|
import 'package:cw_core/utils/tor/abstract.dart';
|
|
import 'package:cw_core/wallet_info.dart';
|
|
import 'package:cw_core/wallet_type.dart';
|
|
import 'package:cw_core/window_size.dart';
|
|
import 'package:flutter/foundation.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:flutter/services.dart';
|
|
import 'package:flutter_daemon/flutter_daemon.dart';
|
|
import 'package:flutter_mobx/flutter_mobx.dart';
|
|
import 'package:hive/hive.dart';
|
|
import 'package:quick_actions/quick_actions.dart';
|
|
import 'package:logging/logging.dart';
|
|
import 'package:shared_preferences/shared_preferences.dart';
|
|
import 'package:trezor_connect/trezor_connect.dart';
|
|
|
|
final navigatorKey = GlobalKey<NavigatorState>();
|
|
final rootKey = GlobalKey<RootState>();
|
|
final RouteObserver<PageRoute<dynamic>> routeObserver = RouteObserver<PageRoute<dynamic>>();
|
|
final quickActionsStream = StreamController<Uri?>.broadcast();
|
|
|
|
Future<void> main({Key? topLevelKey}) async {
|
|
await runAppWithZone(topLevelKey: topLevelKey);
|
|
}
|
|
|
|
Future<void> runAppWithZone({Key? topLevelKey}) async {
|
|
bool isAppRunning = false;
|
|
|
|
await runZonedGuarded(() async {
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
|
|
final Completer<String?> initialShortcutCompleter = Completer<String?>();
|
|
|
|
// Quick Actions plugin supports only iOS/Android platforms
|
|
if (Platform.isIOS || Platform.isAndroid) {
|
|
const QuickActions quickActions = QuickActions();
|
|
|
|
quickActions.initialize((String shortcutType) {
|
|
// Complete the completer only once (for cold starts)
|
|
if (!initialShortcutCompleter.isCompleted) {
|
|
initialShortcutCompleter.complete(shortcutType);
|
|
}
|
|
|
|
// Convert the shortcut type to a URI and add it to the stream
|
|
final uri = Uri.parse('hashwallet://quickaction/$shortcutType');
|
|
quickActionsStream.sink.add(uri);
|
|
});
|
|
|
|
quickActions.setShortcutItems(<ShortcutItem>[
|
|
const ShortcutItem(
|
|
type: 'send', icon: 'send', localizedTitle: 'Send', localizedSubtitle: 'Send funds'),
|
|
const ShortcutItem(
|
|
type: 'receive',
|
|
icon: 'receive',
|
|
localizedTitle: 'Receive',
|
|
localizedSubtitle: 'Receive funds')
|
|
]);
|
|
|
|
// Fallback in case the initial shortcut is not received (normal cold start)
|
|
Future<void>.delayed(const Duration(milliseconds: 500), () {
|
|
if (!initialShortcutCompleter.isCompleted) {
|
|
initialShortcutCompleter.complete(null);
|
|
}
|
|
});
|
|
} else {
|
|
initialShortcutCompleter.complete(null);
|
|
}
|
|
|
|
final initialQuickAction = await initialShortcutCompleter.future;
|
|
FlutterError.onError = ExceptionHandler.onError;
|
|
|
|
/// A callback that is invoked when an unhandled error occurs in the root
|
|
/// isolate.
|
|
PlatformDispatcher.instance.onError = (error, stack) {
|
|
ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stack));
|
|
|
|
return true;
|
|
};
|
|
|
|
await FlutterDaemon().unmarkBackgroundSync();
|
|
await initDb();
|
|
|
|
try {
|
|
CakeTor.instance = await CakeTorInstance.getInstance();
|
|
} catch (e) {
|
|
printV("Failed to initialize tor: $e");
|
|
}
|
|
|
|
try {
|
|
await linuxSymlinkSharedPreferences();
|
|
} catch (e) {
|
|
printV("Failed to symlink linux preferences: $e");
|
|
}
|
|
|
|
await initializeAppAtRoot();
|
|
|
|
if (kDebugMode) {
|
|
final appDocDir = await getAppDir();
|
|
|
|
final ledgerFile = File('${appDocDir.path}/ledger_log.txt');
|
|
if (!ledgerFile.existsSync()) ledgerFile.createSync();
|
|
Logger.root.onRecord.listen((event) async {
|
|
final content = ledgerFile.readAsStringSync();
|
|
ledgerFile.writeAsStringSync("$content\n${event.message}");
|
|
});
|
|
}
|
|
|
|
if (FeatureFlag.hasDevOptions) {
|
|
ProxyWrapper.logger = MemoryProxyLogger();
|
|
}
|
|
|
|
// Basically when we're running a test
|
|
if (topLevelKey != null) {
|
|
runApp(
|
|
DefaultAssetBundle(
|
|
bundle: TestAssetBundle(),
|
|
child: App(
|
|
key: topLevelKey,
|
|
initialQuickAction: initialQuickAction,
|
|
quickActionsStream: quickActionsStream.stream),
|
|
),
|
|
);
|
|
} else {
|
|
runApp(App(
|
|
key: topLevelKey,
|
|
initialQuickAction: initialQuickAction,
|
|
quickActionsStream: quickActionsStream.stream));
|
|
}
|
|
|
|
isAppRunning = true;
|
|
}, (error, stackTrace) async {
|
|
if (!isAppRunning) {
|
|
runApp(
|
|
TopLevelErrorWidget(error: error, stackTrace: stackTrace),
|
|
);
|
|
}
|
|
|
|
await ExceptionHandler.onError(FlutterErrorDetails(exception: error, stack: stackTrace));
|
|
});
|
|
}
|
|
|
|
Future<void> initializeAppAtRoot({bool reInitializing = false}) async {
|
|
if (!reInitializing) await setDefaultMinimumWindowSize();
|
|
await CakeHive.close();
|
|
await initializeAppConfigs();
|
|
}
|
|
|
|
Future<void> initializeAppConfigs({bool loadWallet = true}) async {
|
|
setRootDirFromEnv();
|
|
final appDir = await getAppDir();
|
|
CakeHive.init(appDir.path);
|
|
|
|
if (!CakeHive.isAdapterRegistered(Contact.typeId)) {
|
|
CakeHive.registerAdapter(ContactAdapter());
|
|
}
|
|
|
|
if (!CakeHive.isAdapterRegistered(Node.typeId)) {
|
|
CakeHive.registerAdapter(NodeAdapter());
|
|
}
|
|
|
|
if (!CakeHive.isAdapterRegistered(TransactionDescription.typeId)) {
|
|
CakeHive.registerAdapter(TransactionDescriptionAdapter());
|
|
}
|
|
|
|
if (!CakeHive.isAdapterRegistered(AddressInfo.typeId)) {
|
|
CakeHive.registerAdapter(AddressInfoAdapter());
|
|
}
|
|
|
|
if (!CakeHive.isAdapterRegistered(WALLET_TYPE_TYPE_ID)) {
|
|
CakeHive.registerAdapter(WalletTypeAdapter());
|
|
}
|
|
|
|
if (!CakeHive.isAdapterRegistered(Template.typeId)) {
|
|
CakeHive.registerAdapter(TemplateAdapter());
|
|
}
|
|
|
|
if (!CakeHive.isAdapterRegistered(ExchangeTemplate.typeId)) {
|
|
CakeHive.registerAdapter(ExchangeTemplateAdapter());
|
|
}
|
|
|
|
if (!CakeHive.isAdapterRegistered(Order.typeId)) {
|
|
CakeHive.registerAdapter(OrderAdapter());
|
|
}
|
|
|
|
if (!CakeHive.isAdapterRegistered(UnspentCoinsInfo.typeId)) {
|
|
CakeHive.registerAdapter(UnspentCoinsInfoAdapter());
|
|
}
|
|
|
|
if (!CakeHive.isAdapterRegistered(AnonpayInvoiceInfo.typeId)) {
|
|
CakeHive.registerAdapter(AnonpayInvoiceInfoAdapter());
|
|
}
|
|
|
|
if (!CakeHive.isAdapterRegistered(MwebUtxo.typeId)) {
|
|
CakeHive.registerAdapter(MwebUtxoAdapter());
|
|
}
|
|
|
|
if (!CakeHive.isAdapterRegistered(PayjoinSession.typeId)) {
|
|
CakeHive.registerAdapter(PayjoinSessionAdapter());
|
|
}
|
|
|
|
if (!CakeHive.isAdapterRegistered(Erc20Token.typeId)) {
|
|
CakeHive.registerAdapter(Erc20TokenAdapter());
|
|
}
|
|
|
|
if (!CakeHive.isAdapterRegistered(SPLToken.typeId)) {
|
|
CakeHive.registerAdapter(SPLTokenAdapter());
|
|
}
|
|
|
|
if (!CakeHive.isAdapterRegistered(TronToken.typeId)) {
|
|
CakeHive.registerAdapter(TronTokenAdapter());
|
|
}
|
|
await performHiveMigration();
|
|
|
|
final secureStorage = secureStorageShared;
|
|
final transactionDescriptionsBoxKey =
|
|
await getEncryptionKey(secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
|
|
final ordersBoxKey = await getEncryptionKey(secureStorage: secureStorage, forKey: Order.boxKey);
|
|
final contacts = await CakeHive.openBox<Contact>(Contact.boxName);
|
|
final nodes = await CakeHive.openBox<Node>(Node.boxName);
|
|
final powNodes =
|
|
await CakeHive.openBox<Node>(Node.boxName + "pow"); // must be different from Node.boxName
|
|
final transactionDescriptions = await CakeHive.openBox<TransactionDescription>(
|
|
TransactionDescription.boxName,
|
|
encryptionKey: transactionDescriptionsBoxKey);
|
|
await performTradeHiveMigration(secureStorage);
|
|
|
|
final orders = await CakeHive.openBox<Order>(Order.boxName, encryptionKey: ordersBoxKey);
|
|
final templates = await CakeHive.openBox<Template>(Template.boxName);
|
|
final exchangeTemplates = await CakeHive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
|
|
final anonpayInvoiceInfo = await CakeHive.openBox<AnonpayInvoiceInfo>(AnonpayInvoiceInfo.boxName);
|
|
final unspentCoinsInfoSource = await CakeHive.openBox<UnspentCoinsInfo>(UnspentCoinsInfo.boxName);
|
|
final payjoinSessionSource = await CakeHive.openBox<PayjoinSession>(PayjoinSession.boxName);
|
|
|
|
await initialSetup(
|
|
loadWallet: loadWallet,
|
|
sharedPreferences: await SharedPreferences.getInstance(),
|
|
nodes: nodes,
|
|
powNodes: powNodes,
|
|
contactSource: contacts,
|
|
ordersSource: orders,
|
|
unspentCoinsInfoSource: unspentCoinsInfoSource,
|
|
// fiatConvertationService: fiatConvertationService,
|
|
templates: templates,
|
|
exchangeTemplates: exchangeTemplates,
|
|
transactionDescriptions: transactionDescriptions,
|
|
secureStorage: secureStorage,
|
|
payjoinSessionSource: payjoinSessionSource,
|
|
anonpayInvoiceInfo: anonpayInvoiceInfo,
|
|
initialMigrationVersion: 65,
|
|
);
|
|
}
|
|
|
|
Future<void> initialSetup({
|
|
required bool loadWallet,
|
|
required SharedPreferences sharedPreferences,
|
|
required Box<Node> nodes,
|
|
required Box<Node> powNodes,
|
|
required Box<Contact> contactSource,
|
|
required Box<Order> ordersSource,
|
|
// required FiatConvertationService fiatConvertationService,
|
|
required Box<Template> templates,
|
|
required Box<ExchangeTemplate> exchangeTemplates,
|
|
required Box<TransactionDescription> transactionDescriptions,
|
|
required SecureStorage secureStorage,
|
|
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfo,
|
|
required Box<UnspentCoinsInfo> unspentCoinsInfoSource,
|
|
required Box<PayjoinSession> payjoinSessionSource,
|
|
required int initialMigrationVersion,
|
|
}) async {
|
|
LanguageService.loadLocaleList();
|
|
await defaultSettingsMigration(
|
|
secureStorage: secureStorage,
|
|
version: initialMigrationVersion,
|
|
sharedPreferences: sharedPreferences,
|
|
contactSource: contactSource,
|
|
nodes: nodes,
|
|
powNodes: powNodes,
|
|
);
|
|
await setup(
|
|
nodeSource: nodes,
|
|
powNodeSource: powNodes,
|
|
contactSource: contactSource,
|
|
ordersSource: ordersSource,
|
|
templates: templates,
|
|
exchangeTemplates: exchangeTemplates,
|
|
transactionDescriptionBox: transactionDescriptions,
|
|
anonpayInvoiceInfoSource: anonpayInvoiceInfo,
|
|
unspentCoinsInfoSource: unspentCoinsInfoSource,
|
|
payjoinSessionSource: payjoinSessionSource,
|
|
navigatorKey: navigatorKey,
|
|
secureStorage: secureStorage,
|
|
);
|
|
|
|
await getIt.get<ResetService>().resetAuthDataOnNewInstall(sharedPreferences);
|
|
|
|
await bootstrapOffline();
|
|
final settingsStore = getIt<SettingsStore>();
|
|
if (!settingsStore.currentBuiltinTor) {
|
|
bootstrapOnline(navigatorKey, loadWallet: loadWallet);
|
|
}
|
|
}
|
|
|
|
class App extends StatefulWidget {
|
|
App({this.key, this.initialQuickAction, required this.quickActionsStream});
|
|
|
|
final Key? key;
|
|
final String? initialQuickAction;
|
|
final Stream<Uri?> quickActionsStream;
|
|
@override
|
|
AppState createState() => AppState();
|
|
}
|
|
|
|
class AppState extends State<App> with SingleTickerProviderStateMixin {
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return Observer(
|
|
builder: (BuildContext context) {
|
|
final appStore = getIt.get<AppStore>();
|
|
final authService = getIt.get<AuthService>();
|
|
final linkViewModel = getIt.get<LinkViewModel>();
|
|
final tradeMonitor = getIt.get<TradeMonitor>();
|
|
final nodeSwitchingService = getIt.get<NodeSwitchingService>();
|
|
final settingsStore = appStore.settingsStore;
|
|
final statusBarColor = Colors.transparent;
|
|
final authenticationStore = getIt.get<AuthenticationStore>();
|
|
final initialRoute = authenticationStore.state == AuthenticationState.uninitialized
|
|
? Routes.welcome
|
|
: settingsStore.currentBuiltinTor
|
|
? Routes.startTor
|
|
: Routes.login;
|
|
final currentTheme = appStore.themeStore.currentTheme;
|
|
final statusBarBrightness =
|
|
currentTheme.type == currentTheme.isDark ? Brightness.light : Brightness.dark;
|
|
final statusBarIconBrightness =
|
|
currentTheme.type == currentTheme.isDark ? Brightness.light : Brightness.dark;
|
|
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
|
|
statusBarColor: statusBarColor,
|
|
statusBarBrightness: statusBarBrightness,
|
|
statusBarIconBrightness: statusBarIconBrightness));
|
|
|
|
final appRouteObserver = AppRouteObserver();
|
|
|
|
return Root(
|
|
key: widget.key ?? rootKey,
|
|
appStore: appStore,
|
|
initialQuickAction: widget.initialQuickAction,
|
|
quickActionsStream: widget.quickActionsStream,
|
|
authenticationStore: authenticationStore,
|
|
navigatorKey: navigatorKey,
|
|
authService: authService,
|
|
linkViewModel: linkViewModel,
|
|
tradeMonitor: tradeMonitor,
|
|
nodeSwitchingService: nodeSwitchingService,
|
|
trezorConnect: getIt<TrezorConnect>(),
|
|
child: ThemeProvider(
|
|
themeStore: appStore.themeStore,
|
|
materialAppBuilder: (context, theme, darkTheme, themeMode) => MaterialApp(
|
|
navigatorObservers: [routeObserver, appRouteObserver],
|
|
navigatorKey: navigatorKey,
|
|
debugShowCheckedModeBanner: false,
|
|
builder: (context, child) => MediaQuery(
|
|
data: MediaQuery.of(context).copyWith(textScaler: TextScaler.noScaling),
|
|
child: child!),
|
|
theme: theme,
|
|
darkTheme: darkTheme,
|
|
themeMode: themeMode,
|
|
localizationsDelegates: localizationDelegates,
|
|
supportedLocales: S.delegate.supportedLocales,
|
|
locale: Locale(appStore.settingsStore.languageCode),
|
|
onGenerateRoute: (settings) => Router.createRoute(settings),
|
|
initialRoute: initialRoute,
|
|
scrollBehavior: AppScrollBehavior(),
|
|
home: _Home(),
|
|
),
|
|
),
|
|
);
|
|
},
|
|
);
|
|
}
|
|
}
|
|
|
|
class _Home extends StatefulWidget {
|
|
const _Home();
|
|
|
|
@override
|
|
State<_Home> createState() => _HomeState();
|
|
}
|
|
|
|
class _HomeState extends State<_Home> {
|
|
@override
|
|
void didChangeDependencies() {
|
|
_setOrientation(context);
|
|
|
|
super.didChangeDependencies();
|
|
}
|
|
|
|
void _setOrientation(BuildContext context) {
|
|
if (!DeviceInfo.instance.isDesktop) {
|
|
if (responsiveLayoutUtil.shouldRenderMobileUI) {
|
|
SystemChrome.setPreferredOrientations(
|
|
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
|
|
} else {
|
|
SystemChrome.setPreferredOrientations(
|
|
[DeviceOrientation.landscapeLeft, DeviceOrientation.landscapeRight]);
|
|
}
|
|
}
|
|
}
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return const SizedBox.shrink();
|
|
}
|
|
}
|
|
|
|
class TopLevelErrorWidget extends StatelessWidget {
|
|
const TopLevelErrorWidget({
|
|
required this.error,
|
|
required this.stackTrace,
|
|
super.key,
|
|
});
|
|
|
|
final Object error;
|
|
final StackTrace stackTrace;
|
|
|
|
@override
|
|
Widget build(BuildContext context) {
|
|
return MaterialApp(
|
|
debugShowCheckedModeBanner: false,
|
|
scrollBehavior: AppScrollBehavior(),
|
|
home: Scaffold(
|
|
body: SingleChildScrollView(
|
|
child: Container(
|
|
margin: EdgeInsets.only(top: 50, left: 20, right: 20, bottom: 20),
|
|
child: Column(
|
|
children: [
|
|
Text(
|
|
'Error:\n${error.toString()}',
|
|
style: Theme.of(context).textTheme.bodyLarge!.copyWith(
|
|
fontSize: 22,
|
|
),
|
|
),
|
|
Text(
|
|
'Stack trace:\n${stackTrace.toString()}',
|
|
style: Theme.of(context).textTheme.bodyMedium!.copyWith(
|
|
fontSize: 16,
|
|
),
|
|
),
|
|
],
|
|
),
|
|
),
|
|
),
|
|
),
|
|
);
|
|
}
|
|
}
|
|
|
|
@pragma('vm:entry-point')
|
|
Future<void> backgroundSync() async {
|
|
bool shouldUnmark = false;
|
|
try {
|
|
printV("Background sync triggered");
|
|
printV("- WidgetsFlutterBinding.ensureInitialized()");
|
|
WidgetsFlutterBinding.ensureInitialized();
|
|
printV("- DartPluginRegistrant.ensureInitialized()");
|
|
DartPluginRegistrant.ensureInitialized();
|
|
printV("- FlutterDaemon.markBackgroundSync()");
|
|
final val = await FlutterDaemon().markBackgroundSync();
|
|
if (val) {
|
|
printV("Background sync already in progress");
|
|
return;
|
|
}
|
|
shouldUnmark = true;
|
|
printV("Starting background sync");
|
|
final backgroundSync = BackgroundSync();
|
|
await initializeAppConfigs(loadWallet: false);
|
|
await backgroundSync.sync();
|
|
printV("Background sync completed");
|
|
} finally {
|
|
if (shouldUnmark) {
|
|
printV("Unmarking background sync");
|
|
await FlutterDaemon().unmarkBackgroundSync();
|
|
} else {
|
|
printV("Not unmarking background sync");
|
|
}
|
|
}
|
|
}
|
|
|
|
class AppRouteObserver extends RouteObserver<PageRoute<dynamic>> {
|
|
final AppStore appStore = getIt.get<AppStore>();
|
|
|
|
@override
|
|
void didPush(Route<dynamic> route, Route<dynamic>? previousRoute) {
|
|
super.didPush(route, previousRoute);
|
|
if (route is PageRoute) {
|
|
appStore.currentRouteName = route.settings.name;
|
|
}
|
|
}
|
|
|
|
@override
|
|
void didPop(Route<dynamic> route, Route<dynamic>? previousRoute) {
|
|
super.didPop(route, previousRoute);
|
|
if (previousRoute is PageRoute) {
|
|
appStore.currentRouteName = previousRoute.settings.name;
|
|
}
|
|
}
|
|
}
|