cake_wallet/lib/main.dart

396 lines
13 KiB
Dart
Raw Normal View History

import 'dart:async';
2022-11-23 21:02:18 +00:00
import 'dart:convert';
import 'dart:io';
import 'dart:isolate';
2021-12-24 12:37:24 +00:00
import 'package:cake_wallet/bitcoin/bitcoin.dart';
2022-12-13 15:19:31 +00:00
import 'package:cake_wallet/core/auth_service.dart';
import 'package:cake_wallet/entities/language_service.dart';
import 'package:cake_wallet/buy/order.dart';
2022-11-25 16:59:47 +00:00
import 'package:cake_wallet/entities/preferences_key.dart';
Ionia (#437) * Initial ionia service * Ionia manage card UI (#374) * design ui for cakepay * Add manage cards page ui * create auth ui for ionia * add authentication logic * implement user create card * Add ionia merchant sevic * Add anypay. Add purschase gift card. * display virtual card (#385) * display virtual card * fix formatting * Remove IoniaMerchantService from IoniaViewModel * Add hex and txKey for monero pending transaction. * Changed monero version and monero repo to cake tech. * Add anypay payment. Add filter by search for ionia, add get purchased items for ionia. * Fix for get transactions for hidden addresses for electrum wallet * Add ionia categories. * Add anypay commited info for payments. * Update UI with new fixes (#400) * Change ionia base url. Add exception throwing for error messaging for some of ionia calls. * CW-102 fix logic for ionia issues (#403) * refactor tips (#406) * refactor tips * refactor ionia tips implementation * Cw 115 implement gift cards list for ionia (#405) * Implement show purchased cards * fix padding * Fixes for getting of purchased gift cards. * Implement gift card details screen (#408) * Implement gift card details screen * Add redeem for ionia gift cards * Fix navigation after ionia opt redirection. * Fix update gift cards list. * Add payment status update for ionia. * Add usage instruction to gift card. * Add copy for ionia gift card info. * Change version for Cake Wallet ios. * Add localisation (#414) * Fixes for fiat amounts for ionia. * CW-128 marketplace screen text changes (#416) * Change text on marketplace * fix build issues * fix build * UI fixes for ionia. * UI fixes for ionia. (#421) * CW-129 ionia welcome screen text changes (#418) * update welcome text * Update localization * Cw 133 (#422) * UI fixes for ionia. * Fixes for display card item on gift cards screen. * Fix signup page (#419) * Changed tips for ionia. * Cw 132 (#425) * UI fixes for ionia. * Changed tips for ionia. * Cw 131 (#426) * UI fixes for ionia. * Changed tips for ionia. * Fixes for IoniaBuyGiftCardDetailPage screen. Renamed 'Manage Cards' to 'Gift Cards'. Hide discount badge label for 0 discount. * Change ionia heading font style (#427) * Fix for AddressResolver in di * Changed build number for Cake Wallet ios. * fix currency format for card details and routing for mark as redeemed (#431) * fix terms and condition overflow in ionia (#430) * fix terms and condition scroll * fix color issues * reuse * refactor widget * Remove IoniaTokenService * Change api for ionia to staging * Update versions for Cake Wallet for android and ios. * Fixes for instructions. Remove diplay error on payment status screen. * Change build versions for Cake Wallet * Add ionia sign in. * Update for discounts and statuses for ionia merch. * Fixes for qr/barcode on ionia gift card screen. * Fixed formatting for display ionia discounts. * Fix merchant.discount.toStringAsFixed issue * Add savingsPercentage to ionia merch discount. * Change build number for Cake Wallet ios and android. * Disable ionia for haven (#440) Co-authored-by: Godwin Asuquo <41484542+godilite@users.noreply.github.com>
2022-07-28 17:03:16 +00:00
import 'package:cake_wallet/ionia/ionia_category.dart';
import 'package:cake_wallet/ionia/ionia_merchant.dart';
2022-11-29 12:03:14 +00:00
import 'package:cake_wallet/src/widgets/alert_with_two_actions.dart';
import 'package:cake_wallet/store/yat/yat_store.dart';
2022-11-25 16:59:47 +00:00
import 'package:cake_wallet/themes/theme_list.dart';
2022-11-29 12:03:14 +00:00
import 'package:cake_wallet/utils/show_pop_up.dart';
import 'package:flutter/foundation.dart';
2020-09-28 15:47:43 +00:00
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_mailer/flutter_mailer.dart';
2020-09-28 15:47:43 +00:00
import 'package:hive/hive.dart';
2020-06-20 07:10:00 +00:00
import 'package:cake_wallet/di.dart';
2020-01-04 19:31:52 +00:00
import 'package:path_provider/path_provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
2020-09-28 15:47:43 +00:00
import 'package:flutter_localizations/flutter_localizations.dart';
2020-01-04 19:31:52 +00:00
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
2020-09-28 15:47:43 +00:00
import 'package:flutter_mobx/flutter_mobx.dart';
2021-01-15 17:41:30 +00:00
import 'package:cake_wallet/themes/theme_base.dart';
2020-10-19 11:20:24 +00:00
import 'package:cake_wallet/router.dart' as Router;
2020-09-28 15:47:43 +00:00
import 'package:cake_wallet/routes.dart';
import 'package:cake_wallet/generated/i18n.dart';
import 'package:cake_wallet/reactions/bootstrap.dart';
import 'package:cake_wallet/store/app_store.dart';
import 'package:cake_wallet/store/authentication_store.dart';
import 'package:cake_wallet/entities/transaction_description.dart';
2020-09-21 11:50:26 +00:00
import 'package:cake_wallet/entities/get_encryption_key.dart';
import 'package:cake_wallet/entities/contact.dart';
2021-12-24 12:37:24 +00:00
import 'package:cw_core/node.dart';
import 'package:cw_core/wallet_info.dart';
2020-09-21 11:50:26 +00:00
import 'package:cake_wallet/entities/default_settings_migration.dart';
2021-12-24 12:37:24 +00:00
import 'package:cw_core/wallet_type.dart';
2020-09-21 11:50:26 +00:00
import 'package:cake_wallet/entities/template.dart';
2020-09-28 15:47:43 +00:00
import 'package:cake_wallet/exchange/trade.dart';
2020-09-21 11:50:26 +00:00
import 'package:cake_wallet/exchange/exchange_template.dart';
2020-09-28 15:47:43 +00:00
import 'package:cake_wallet/src/screens/root/root.dart';
import 'package:uni_links/uni_links.dart';
2021-12-24 12:37:24 +00:00
import 'package:cw_core/unspent_coins_info.dart';
import 'package:cake_wallet/monero/monero.dart';
import 'package:cake_wallet/wallet_type_utils.dart';
2020-09-14 12:08:33 +00:00
final navigatorKey = GlobalKey<NavigatorState>();
2021-11-02 09:17:24 +00:00
final rootKey = GlobalKey<RootState>();
final RouteObserver<PageRoute> routeObserver = RouteObserver<PageRoute>();
bool hasError = false;
2020-09-14 12:08:33 +00:00
2021-01-15 17:41:30 +00:00
Future<void> main() async {
2022-11-23 16:06:09 +00:00
await runZonedGuarded(() async {
2020-11-08 20:44:09 +00:00
WidgetsFlutterBinding.ensureInitialized();
2020-01-04 19:31:52 +00:00
2022-11-23 21:02:18 +00:00
FlutterError.onError = (errorDetails) {
_onError(errorDetails);
2022-11-25 16:59:47 +00:00
};
/// A callback that is invoked when an unhandled error occurs in the root
/// isolate.
2022-11-23 21:02:18 +00:00
PlatformDispatcher.instance.onError = (error, stack) {
_onError(FlutterErrorDetails(exception: error, stack: stack));
2022-11-23 21:02:18 +00:00
return true;
};
2020-11-08 20:44:09 +00:00
final appDir = await getApplicationDocumentsDirectory();
2021-01-15 17:41:30 +00:00
await Hive.close();
2020-11-08 20:44:09 +00:00
Hive.init(appDir.path);
2021-01-15 17:41:30 +00:00
if (!Hive.isAdapterRegistered(Contact.typeId)) {
Hive.registerAdapter(ContactAdapter());
}
if (!Hive.isAdapterRegistered(Node.typeId)) {
Hive.registerAdapter(NodeAdapter());
}
if (!Hive.isAdapterRegistered(TransactionDescription.typeId)) {
Hive.registerAdapter(TransactionDescriptionAdapter());
}
if (!Hive.isAdapterRegistered(Trade.typeId)) {
Hive.registerAdapter(TradeAdapter());
}
if (!Hive.isAdapterRegistered(WalletInfo.typeId)) {
Hive.registerAdapter(WalletInfoAdapter());
}
if (!Hive.isAdapterRegistered(walletTypeTypeId)) {
Hive.registerAdapter(WalletTypeAdapter());
}
if (!Hive.isAdapterRegistered(Template.typeId)) {
Hive.registerAdapter(TemplateAdapter());
}
if (!Hive.isAdapterRegistered(ExchangeTemplate.typeId)) {
Hive.registerAdapter(ExchangeTemplateAdapter());
}
if (!Hive.isAdapterRegistered(Order.typeId)) {
Hive.registerAdapter(OrderAdapter());
}
if (!isMoneroOnly && !Hive.isAdapterRegistered(UnspentCoinsInfo.typeId)) {
Hive.registerAdapter(UnspentCoinsInfoAdapter());
}
2020-11-08 20:44:09 +00:00
final secureStorage = FlutterSecureStorage();
final transactionDescriptionsBoxKey = await getEncryptionKey(
secureStorage: secureStorage, forKey: TransactionDescription.boxKey);
final tradesBoxKey = await getEncryptionKey(
secureStorage: secureStorage, forKey: Trade.boxKey);
final ordersBoxKey = await getEncryptionKey(
secureStorage: secureStorage, forKey: Order.boxKey);
2020-11-08 20:44:09 +00:00
final contacts = await Hive.openBox<Contact>(Contact.boxName);
final nodes = await Hive.openBox<Node>(Node.boxName);
final transactionDescriptions = await Hive.openBox<TransactionDescription>(
TransactionDescription.boxName,
encryptionKey: transactionDescriptionsBoxKey);
final trades =
2021-01-15 17:41:30 +00:00
await Hive.openBox<Trade>(Trade.boxName, encryptionKey: tradesBoxKey);
final orders =
await Hive.openBox<Order>(Order.boxName, encryptionKey: ordersBoxKey);
2020-11-08 20:44:09 +00:00
final walletInfoSource = await Hive.openBox<WalletInfo>(WalletInfo.boxName);
final templates = await Hive.openBox<Template>(Template.boxName);
final exchangeTemplates =
2021-01-15 17:41:30 +00:00
await Hive.openBox<ExchangeTemplate>(ExchangeTemplate.boxName);
2022-10-12 17:09:57 +00:00
Box<UnspentCoinsInfo>? unspentCoinsInfoSource;
if (!isMoneroOnly) {
unspentCoinsInfoSource = await Hive.openBox<UnspentCoinsInfo>(UnspentCoinsInfo.boxName);
}
2021-11-02 09:17:24 +00:00
2020-11-08 20:44:09 +00:00
await initialSetup(
sharedPreferences: await SharedPreferences.getInstance(),
nodes: nodes,
walletInfoSource: walletInfoSource,
contactSource: contacts,
tradesSource: trades,
ordersSource: orders,
unspentCoinsInfoSource: unspentCoinsInfoSource,
2020-11-08 20:44:09 +00:00
// fiatConvertationService: fiatConvertationService,
templates: templates,
exchangeTemplates: exchangeTemplates,
transactionDescriptions: transactionDescriptions,
2021-01-15 17:41:30 +00:00
secureStorage: secureStorage,
initialMigrationVersion: 19);
2020-11-08 20:44:09 +00:00
runApp(App());
2022-11-25 16:59:47 +00:00
}, (error, stackTrace) async {
2022-11-29 12:03:14 +00:00
_onError(FlutterErrorDetails(exception: error, stack: stackTrace));
2022-11-23 16:06:09 +00:00
});
2020-01-04 19:31:52 +00:00
}
2022-11-23 21:02:18 +00:00
void _saveException(String? error, StackTrace? stackTrace) async {
2022-11-25 16:59:47 +00:00
final appDocDir = await getApplicationDocumentsDirectory();
final file = File('${appDocDir.path}/error.txt');
2022-11-23 21:02:18 +00:00
final exception = {
"${DateTime.now()}": {
"Error": error,
"StackTrace": stackTrace.toString(),
2022-11-23 21:02:18 +00:00
}
};
2022-11-25 16:59:47 +00:00
const String separator =
'''\n\n==========================================================
==========================================================\n\n''';
await file.writeAsString(
jsonEncode(exception) + separator,
mode: FileMode.append,
);
}
void _sendExceptionFile() async {
try {
final appDocDir = await getApplicationDocumentsDirectory();
final file = File('${appDocDir.path}/error.txt');
final MailOptions mailOptions = MailOptions(
subject: 'Mobile App Issue',
recipients: ['support@cakewallet.com'],
attachments: [file.path],
);
final result = await FlutterMailer.send(mailOptions);
// Clear file content if the error was sent or saved.
// On android we can't know if it was sent or saved
if (result.name == MailerResponse.sent.name ||
result.name == MailerResponse.saved.name ||
result.name == MailerResponse.android.name) {
file.writeAsString("", mode: FileMode.write);
}
} catch (e, s) {
_saveException(e.toString(), s);
}
2022-11-23 21:02:18 +00:00
}
void _onError(FlutterErrorDetails errorDetails) {
_saveException(errorDetails.exception.toString(), errorDetails.stack);
if (hasError) {
return;
}
hasError = true;
2022-11-29 12:03:14 +00:00
WidgetsBinding.instance.addPostFrameCallback(
(timeStamp) async {
await showPopUp<void>(
2022-11-29 12:03:14 +00:00
context: navigatorKey.currentContext!,
builder: (context) {
return AlertWithTwoActions(
isDividerExist: true,
alertTitle: S.of(context).error,
alertContent: S.of(context).error_dialog_content,
2022-11-29 12:03:14 +00:00
rightButtonText: S.of(context).send,
leftButtonText: S.of(context).do_not_send,
actionRightButton: () {
2022-11-29 12:03:14 +00:00
Navigator.of(context).pop();
_sendExceptionFile();
2022-11-29 12:03:14 +00:00
},
actionLeftButton: () {
Navigator.of(context).pop();
},
);
},
);
hasError = false;
2022-11-29 12:03:14 +00:00
},
);
}
2021-01-15 17:41:30 +00:00
Future<void> initialSetup(
2022-10-12 17:09:57 +00:00
{required SharedPreferences sharedPreferences,
required Box<Node> nodes,
required Box<WalletInfo> walletInfoSource,
required Box<Contact> contactSource,
required Box<Trade> tradesSource,
required Box<Order> ordersSource,
// required FiatConvertationService fiatConvertationService,
required Box<Template> templates,
required Box<ExchangeTemplate> exchangeTemplates,
required Box<TransactionDescription> transactionDescriptions,
required FlutterSecureStorage secureStorage,
Box<UnspentCoinsInfo>? unspentCoinsInfoSource,
int initialMigrationVersion = 15}) async {
LanguageService.loadLocaleList();
2020-01-04 19:31:52 +00:00
await defaultSettingsMigration(
2021-01-15 17:41:30 +00:00
secureStorage: secureStorage,
2020-01-04 19:31:52 +00:00
version: initialMigrationVersion,
sharedPreferences: sharedPreferences,
2020-09-23 18:26:10 +00:00
walletInfoSource: walletInfoSource,
contactSource: contactSource,
tradeSource: tradesSource,
2020-01-04 19:31:52 +00:00
nodes: nodes);
2020-07-06 20:09:03 +00:00
await setup(
walletInfoSource: walletInfoSource,
nodeSource: nodes,
contactSource: contactSource,
tradesSource: tradesSource,
templates: templates,
2020-11-06 18:54:00 +00:00
exchangeTemplates: exchangeTemplates,
transactionDescriptionBox: transactionDescriptions,
ordersSource: ordersSource,
Ionia (#437) * Initial ionia service * Ionia manage card UI (#374) * design ui for cakepay * Add manage cards page ui * create auth ui for ionia * add authentication logic * implement user create card * Add ionia merchant sevic * Add anypay. Add purschase gift card. * display virtual card (#385) * display virtual card * fix formatting * Remove IoniaMerchantService from IoniaViewModel * Add hex and txKey for monero pending transaction. * Changed monero version and monero repo to cake tech. * Add anypay payment. Add filter by search for ionia, add get purchased items for ionia. * Fix for get transactions for hidden addresses for electrum wallet * Add ionia categories. * Add anypay commited info for payments. * Update UI with new fixes (#400) * Change ionia base url. Add exception throwing for error messaging for some of ionia calls. * CW-102 fix logic for ionia issues (#403) * refactor tips (#406) * refactor tips * refactor ionia tips implementation * Cw 115 implement gift cards list for ionia (#405) * Implement show purchased cards * fix padding * Fixes for getting of purchased gift cards. * Implement gift card details screen (#408) * Implement gift card details screen * Add redeem for ionia gift cards * Fix navigation after ionia opt redirection. * Fix update gift cards list. * Add payment status update for ionia. * Add usage instruction to gift card. * Add copy for ionia gift card info. * Change version for Cake Wallet ios. * Add localisation (#414) * Fixes for fiat amounts for ionia. * CW-128 marketplace screen text changes (#416) * Change text on marketplace * fix build issues * fix build * UI fixes for ionia. * UI fixes for ionia. (#421) * CW-129 ionia welcome screen text changes (#418) * update welcome text * Update localization * Cw 133 (#422) * UI fixes for ionia. * Fixes for display card item on gift cards screen. * Fix signup page (#419) * Changed tips for ionia. * Cw 132 (#425) * UI fixes for ionia. * Changed tips for ionia. * Cw 131 (#426) * UI fixes for ionia. * Changed tips for ionia. * Fixes for IoniaBuyGiftCardDetailPage screen. Renamed 'Manage Cards' to 'Gift Cards'. Hide discount badge label for 0 discount. * Change ionia heading font style (#427) * Fix for AddressResolver in di * Changed build number for Cake Wallet ios. * fix currency format for card details and routing for mark as redeemed (#431) * fix terms and condition overflow in ionia (#430) * fix terms and condition scroll * fix color issues * reuse * refactor widget * Remove IoniaTokenService * Change api for ionia to staging * Update versions for Cake Wallet for android and ios. * Fixes for instructions. Remove diplay error on payment status screen. * Change build versions for Cake Wallet * Add ionia sign in. * Update for discounts and statuses for ionia merch. * Fixes for qr/barcode on ionia gift card screen. * Fixed formatting for display ionia discounts. * Fix merchant.discount.toStringAsFixed issue * Add savingsPercentage to ionia merch discount. * Change build number for Cake Wallet ios and android. * Disable ionia for haven (#440) Co-authored-by: Godwin Asuquo <41484542+godilite@users.noreply.github.com>
2022-07-28 17:03:16 +00:00
unspentCoinsInfoSource: unspentCoinsInfoSource,
);
2021-01-15 17:41:30 +00:00
await bootstrap(navigatorKey);
2021-12-24 12:37:24 +00:00
monero?.onStartup();
2020-01-04 19:31:52 +00:00
}
class App extends StatefulWidget {
@override
AppState createState() => AppState();
}
class AppState extends State<App> with SingleTickerProviderStateMixin {
2022-10-12 17:09:57 +00:00
AppState()
: yatStore = getIt.get<YatStore>() {
SystemChrome.setPreferredOrientations(
[DeviceOrientation.portraitUp, DeviceOrientation.portraitDown]);
}
YatStore yatStore;
2022-10-12 17:09:57 +00:00
StreamSubscription? stream;
@override
void initState() {
super.initState();
2022-01-12 13:32:23 +00:00
//_handleIncomingLinks();
//_handleInitialUri();
}
Future<void> _handleInitialUri() async {
try {
final uri = await getInitialUri();
2021-11-02 09:17:24 +00:00
print('uri: $uri');
if (uri == null) {
return;
}
if (!mounted) return;
2022-01-12 13:32:23 +00:00
//_fetchEmojiFromUri(uri);
} catch (e) {
if (!mounted) return;
print(e.toString());
}
}
void _handleIncomingLinks() {
if (!kIsWeb) {
2022-10-12 17:09:57 +00:00
stream = getUriLinksStream().listen((Uri? uri) {
2021-11-02 09:17:24 +00:00
print('uri: $uri');
if (!mounted) return;
2022-01-12 13:32:23 +00:00
//_fetchEmojiFromUri(uri);
}, onError: (Object error) {
if (!mounted) return;
print('Error: $error');
});
}
}
void _fetchEmojiFromUri(Uri uri) {
//final queryParameters = uri.queryParameters;
//if (queryParameters?.isEmpty ?? true) {
// return;
//}
//final emoji = queryParameters['eid'];
//final refreshToken = queryParameters['refresh_token'];
//if ((emoji?.isEmpty ?? true)||(refreshToken?.isEmpty ?? true)) {
// return;
//}
//yatStore.emoji = emoji;
//yatStore.refreshToken = refreshToken;
//yatStore.emojiIncommingSC.add(emoji);
}
@override
Widget build(BuildContext context) {
return Observer(builder: (BuildContext context) {
2022-10-12 17:09:57 +00:00
final appStore = getIt.get<AppStore>();
2022-12-13 15:19:31 +00:00
final authService = getIt.get<AuthService>();
2022-10-12 17:09:57 +00:00
final settingsStore = appStore.settingsStore;
final statusBarColor = Colors.transparent;
final authenticationStore = getIt.get<AuthenticationStore>();
final initialRoute =
authenticationStore.state == AuthenticationState.uninitialized
? Routes.disclaimer
: Routes.login;
final currentTheme = settingsStore.currentTheme;
final statusBarBrightness = currentTheme.type == ThemeType.dark
? Brightness.light
: Brightness.dark;
final statusBarIconBrightness = currentTheme.type == ThemeType.dark
? Brightness.light
: Brightness.dark;
SystemChrome.setSystemUIOverlayStyle(SystemUiOverlayStyle(
statusBarColor: statusBarColor,
statusBarBrightness: statusBarBrightness,
statusBarIconBrightness: statusBarIconBrightness));
return Root(
2021-11-02 09:17:24 +00:00
key: rootKey,
2022-10-12 17:09:57 +00:00
appStore: appStore,
authenticationStore: authenticationStore,
navigatorKey: navigatorKey,
2022-12-13 15:19:31 +00:00
authService: authService,
child: MaterialApp(
navigatorObservers: [routeObserver],
navigatorKey: navigatorKey,
debugShowCheckedModeBanner: false,
theme: settingsStore.theme,
localizationsDelegates: [
S.delegate,
GlobalCupertinoLocalizations.delegate,
GlobalMaterialLocalizations.delegate,
GlobalWidgetsLocalizations.delegate,
],
supportedLocales: S.delegate.supportedLocales,
locale: Locale(settingsStore.languageCode),
onGenerateRoute: (settings) => Router.createRoute(settings),
initialRoute: initialRoute,
));
});
}
}