mirror of
https://github.com/Such-Software/hash-wallet.git
synced 2026-10-20 06:08:34 +02:00
Nano-GPT (#1336)
* init * updates * nano updates * updates * updates * [skipci] wip deep link changes * fix deep links * minor fix * add reminder message on buy and exchange routes * [skip ci] font fixes * review updates * [skip ci] minor fix * save * fixes * minor code cleanup * minor potential fix
This commit is contained in:
+85
-60
@@ -26,6 +26,7 @@ import 'package:cake_wallet/entities/contact.dart';
|
||||
import 'package:cake_wallet/entities/contact_record.dart';
|
||||
import 'package:cake_wallet/entities/exchange_api_mode.dart';
|
||||
import 'package:cake_wallet/entities/parse_address_from_domain.dart';
|
||||
import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||
import 'package:cake_wallet/tron/tron.dart';
|
||||
import 'package:cake_wallet/src/screens/transaction_details/rbf_details_page.dart';
|
||||
import 'package:cw_core/receive_page_option.dart';
|
||||
@@ -268,6 +269,7 @@ Future<void> setup({
|
||||
required Box<UnspentCoinsInfo> unspentCoinsInfoSource,
|
||||
required Box<AnonpayInvoiceInfo> anonpayInvoiceInfoSource,
|
||||
required FlutterSecureStorage secureStorage,
|
||||
required GlobalKey<NavigatorState> navigatorKey,
|
||||
}) async {
|
||||
_walletInfoSource = walletInfoSource;
|
||||
_nodeSource = nodeSource;
|
||||
@@ -429,68 +431,89 @@ Future<void> setup({
|
||||
),
|
||||
);
|
||||
|
||||
getIt.registerFactory<AuthPage>(() {
|
||||
return AuthPage(getIt.get<AuthViewModel>(),
|
||||
getIt.registerLazySingleton<LinkViewModel>(() {
|
||||
return LinkViewModel(
|
||||
appStore: getIt.get<AppStore>(),
|
||||
settingsStore: getIt.get<SettingsStore>(),
|
||||
authenticationStore: getIt.get<AuthenticationStore>(),
|
||||
navigatorKey: navigatorKey,
|
||||
);
|
||||
});
|
||||
|
||||
getIt.registerFactory<AuthPage>(instanceName: 'login', () {
|
||||
return AuthPage(getIt.get<AuthViewModel>(), closable: false,
|
||||
onAuthenticationFinished: (isAuthenticated, AuthPageState authPageState) {
|
||||
if (!isAuthenticated) {
|
||||
return;
|
||||
} else {
|
||||
final authStore = getIt.get<AuthenticationStore>();
|
||||
final appStore = getIt.get<AppStore>();
|
||||
final useTotp = appStore.settingsStore.useTOTP2FA;
|
||||
final shouldUseTotp2FAToAccessWallets =
|
||||
appStore.settingsStore.shouldRequireTOTP2FAForAccessingWallet;
|
||||
if (useTotp && shouldUseTotp2FAToAccessWallets) {
|
||||
authPageState.close(
|
||||
route: Routes.totpAuthCodePage,
|
||||
arguments: TotpAuthArgumentsModel(
|
||||
isForSetup: false,
|
||||
isClosable: false,
|
||||
onTotpAuthenticationFinished: (bool isAuthenticatedSuccessfully,
|
||||
TotpAuthCodePageState totpAuthPageState) async {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
if (appStore.wallet != null) {
|
||||
authStore.allowed();
|
||||
return;
|
||||
}
|
||||
|
||||
totpAuthPageState.changeProcessText('Loading the wallet');
|
||||
|
||||
if (loginError != null) {
|
||||
totpAuthPageState.changeProcessText('ERROR: ${loginError.toString()}');
|
||||
}
|
||||
|
||||
ReactionDisposer? _reaction;
|
||||
_reaction = reaction((_) => appStore.wallet, (Object? _) {
|
||||
_reaction?.reaction.dispose();
|
||||
authStore.allowed();
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
if (appStore.wallet != null) {
|
||||
authStore.allowed();
|
||||
return;
|
||||
}
|
||||
|
||||
authPageState.changeProcessText('Loading the wallet');
|
||||
|
||||
if (loginError != null) {
|
||||
authPageState.changeProcessText('ERROR: ${loginError.toString()}');
|
||||
}
|
||||
|
||||
ReactionDisposer? _reaction;
|
||||
_reaction = reaction((_) => appStore.wallet, (Object? _) {
|
||||
_reaction?.reaction.dispose();
|
||||
authStore.allowed();
|
||||
});
|
||||
}
|
||||
}
|
||||
}, closable: false);
|
||||
}, instanceName: 'login');
|
||||
final authStore = getIt.get<AuthenticationStore>();
|
||||
final appStore = getIt.get<AppStore>();
|
||||
final useTotp = appStore.settingsStore.useTOTP2FA;
|
||||
final shouldUseTotp2FAToAccessWallets =
|
||||
appStore.settingsStore.shouldRequireTOTP2FAForAccessingWallet;
|
||||
if (useTotp && shouldUseTotp2FAToAccessWallets) {
|
||||
authPageState.close(
|
||||
route: Routes.totpAuthCodePage,
|
||||
arguments: TotpAuthArgumentsModel(
|
||||
isForSetup: false,
|
||||
isClosable: false,
|
||||
onTotpAuthenticationFinished:
|
||||
(bool isAuthenticatedSuccessfully, TotpAuthCodePageState totpAuthPageState) async {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
if (appStore.wallet != null) {
|
||||
authStore.allowed();
|
||||
return;
|
||||
}
|
||||
|
||||
totpAuthPageState.changeProcessText('Loading the wallet');
|
||||
|
||||
if (loginError != null) {
|
||||
totpAuthPageState.changeProcessText('ERROR: ${loginError.toString()}');
|
||||
}
|
||||
|
||||
ReactionDisposer? _reaction;
|
||||
_reaction = reaction((_) => appStore.wallet, (Object? _) {
|
||||
_reaction?.reaction.dispose();
|
||||
authStore.allowed();
|
||||
});
|
||||
},
|
||||
),
|
||||
);
|
||||
} else {
|
||||
// wallet is already loaded:
|
||||
if (appStore.wallet != null) {
|
||||
// goes to the dashboard:
|
||||
authStore.allowed();
|
||||
// trigger any deep links:
|
||||
final linkViewModel = getIt.get<LinkViewModel>();
|
||||
if (linkViewModel.currentLink != null) {
|
||||
linkViewModel.handleLink();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// load the wallet:
|
||||
|
||||
authPageState.changeProcessText('Loading the wallet');
|
||||
|
||||
if (loginError != null) {
|
||||
authPageState.changeProcessText('ERROR: ${loginError.toString()}');
|
||||
}
|
||||
|
||||
ReactionDisposer? _reaction;
|
||||
_reaction = reaction((_) => appStore.wallet, (Object? _) {
|
||||
_reaction?.reaction.dispose();
|
||||
authStore.allowed();
|
||||
final linkViewModel = getIt.get<LinkViewModel>();
|
||||
if (linkViewModel.currentLink != null) {
|
||||
linkViewModel.handleLink();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
getIt.registerSingleton<BottomSheetService>(BottomSheetServiceImpl());
|
||||
|
||||
@@ -849,8 +872,10 @@ Future<void> setup({
|
||||
tradesStore: getIt.get<TradesStore>(),
|
||||
sendViewModel: getIt.get<SendViewModel>()));
|
||||
|
||||
getIt.registerFactory(
|
||||
() => ExchangePage(getIt.get<ExchangeViewModel>(), getIt.get<AuthService>()));
|
||||
getIt.registerFactoryParam<ExchangePage, PaymentRequest?, void>(
|
||||
(PaymentRequest? paymentRequest, __) {
|
||||
return ExchangePage(getIt.get<ExchangeViewModel>(), getIt.get<AuthService>(), paymentRequest);
|
||||
});
|
||||
|
||||
getIt.registerFactory(() => ExchangeConfirmPage(tradesStore: getIt.get<TradesStore>()));
|
||||
|
||||
|
||||
+17
-12
@@ -7,6 +7,7 @@ import 'package:cake_wallet/locales/locale.dart';
|
||||
import 'package:cake_wallet/store/yat/yat_store.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/exception_handler.dart';
|
||||
import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||
import 'package:cw_core/address_info.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cw_core/hive_type_ids.dart';
|
||||
@@ -205,18 +206,20 @@ Future<void> initialSetup(
|
||||
nodes: nodes,
|
||||
powNodes: powNodes);
|
||||
await setup(
|
||||
walletInfoSource: walletInfoSource,
|
||||
nodeSource: nodes,
|
||||
powNodeSource: powNodes,
|
||||
contactSource: contactSource,
|
||||
tradesSource: tradesSource,
|
||||
templates: templates,
|
||||
exchangeTemplates: exchangeTemplates,
|
||||
transactionDescriptionBox: transactionDescriptions,
|
||||
ordersSource: ordersSource,
|
||||
anonpayInvoiceInfoSource: anonpayInvoiceInfo,
|
||||
unspentCoinsInfoSource: unspentCoinsInfoSource,
|
||||
secureStorage: secureStorage);
|
||||
walletInfoSource: walletInfoSource,
|
||||
nodeSource: nodes,
|
||||
powNodeSource: powNodes,
|
||||
contactSource: contactSource,
|
||||
tradesSource: tradesSource,
|
||||
templates: templates,
|
||||
exchangeTemplates: exchangeTemplates,
|
||||
transactionDescriptionBox: transactionDescriptions,
|
||||
ordersSource: ordersSource,
|
||||
anonpayInvoiceInfoSource: anonpayInvoiceInfo,
|
||||
unspentCoinsInfoSource: unspentCoinsInfoSource,
|
||||
secureStorage: secureStorage,
|
||||
navigatorKey: navigatorKey,
|
||||
);
|
||||
await bootstrap(navigatorKey);
|
||||
monero?.onStartup();
|
||||
}
|
||||
@@ -287,6 +290,7 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
|
||||
return Observer(builder: (BuildContext context) {
|
||||
final appStore = getIt.get<AppStore>();
|
||||
final authService = getIt.get<AuthService>();
|
||||
final linkViewModel = getIt.get<LinkViewModel>();
|
||||
final settingsStore = appStore.settingsStore;
|
||||
final statusBarColor = Colors.transparent;
|
||||
final authenticationStore = getIt.get<AuthenticationStore>();
|
||||
@@ -309,6 +313,7 @@ class AppState extends State<App> with SingleTickerProviderStateMixin {
|
||||
authenticationStore: authenticationStore,
|
||||
navigatorKey: navigatorKey,
|
||||
authService: authService,
|
||||
linkViewModel: linkViewModel,
|
||||
child: MaterialApp(
|
||||
navigatorObservers: [routeObserver],
|
||||
navigatorKey: navigatorKey,
|
||||
|
||||
+11
-10
@@ -221,7 +221,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||
return CupertinoPageRoute<void>(
|
||||
builder: (_) => getIt.get<SetupPinCodePage>(
|
||||
param1: (PinCodeState<PinCodeWidget> context, dynamic _) =>
|
||||
Navigator.of(context.context).pushNamed(Routes.restoreWalletFromHardwareWallet, arguments: false),
|
||||
Navigator.of(context.context)
|
||||
.pushNamed(Routes.restoreWalletFromHardwareWallet, arguments: false),
|
||||
),
|
||||
fullscreenDialog: true,
|
||||
);
|
||||
@@ -231,9 +232,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||
builder: (_) => ConnectDevicePage(
|
||||
ConnectDevicePageParams(
|
||||
walletType: availableWalletTypes.first,
|
||||
onConnectDevice: (BuildContext context, _) =>
|
||||
Navigator.of(context).pushNamed(Routes.chooseHardwareWalletAccount,
|
||||
arguments: [availableWalletTypes.first]),
|
||||
onConnectDevice: (BuildContext context, _) => Navigator.of(context).pushNamed(
|
||||
Routes.chooseHardwareWalletAccount,
|
||||
arguments: [availableWalletTypes.first]),
|
||||
),
|
||||
getIt.get<LedgerViewModel>(),
|
||||
));
|
||||
@@ -243,9 +244,8 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||
param1: (BuildContext context, WalletType type) {
|
||||
final arguments = ConnectDevicePageParams(
|
||||
walletType: type,
|
||||
onConnectDevice: (BuildContext context, _) =>
|
||||
Navigator.of(context).pushNamed(Routes.chooseHardwareWalletAccount,
|
||||
arguments: [type]),
|
||||
onConnectDevice: (BuildContext context, _) => Navigator.of(context)
|
||||
.pushNamed(Routes.chooseHardwareWalletAccount, arguments: [type]),
|
||||
);
|
||||
|
||||
Navigator.of(context).pushNamed(Routes.connectDevices, arguments: arguments);
|
||||
@@ -308,8 +308,7 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||
case Routes.bumpFeePage:
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true,
|
||||
builder: (_) =>
|
||||
getIt.get<RBFDetailsPage>(param1: settings.arguments as TransactionInfo));
|
||||
builder: (_) => getIt.get<RBFDetailsPage>(param1: settings.arguments as TransactionInfo));
|
||||
|
||||
case Routes.newSubaddress:
|
||||
return CupertinoPageRoute<void>(
|
||||
@@ -461,7 +460,9 @@ Route<dynamic> createRoute(RouteSettings settings) {
|
||||
|
||||
case Routes.exchange:
|
||||
return CupertinoPageRoute<void>(
|
||||
fullscreenDialog: true, builder: (_) => getIt.get<ExchangePage>());
|
||||
fullscreenDialog: true,
|
||||
builder: (_) => getIt.get<ExchangePage>(param1: settings.arguments as PaymentRequest?),
|
||||
);
|
||||
|
||||
case Routes.exchangeTemplate:
|
||||
return CupertinoPageRoute<void>(builder: (_) => getIt.get<ExchangeTemplatePage>());
|
||||
|
||||
@@ -59,12 +59,15 @@ class MarketPlacePage extends StatelessWidget {
|
||||
// ),
|
||||
SizedBox(height: 20),
|
||||
DashBoardRoundedCardWidget(
|
||||
onTap: () => launchUrl(
|
||||
Uri.https("buy.cakepay.com"),
|
||||
mode: LaunchMode.externalApplication,
|
||||
),
|
||||
title: S.of(context).cake_pay_web_cards_title,
|
||||
subTitle: S.of(context).cake_pay_web_cards_subtitle,
|
||||
onTap: () => _launchMarketPlaceUrl("buy.cakepay.com"),
|
||||
),
|
||||
const SizedBox(height: 20),
|
||||
DashBoardRoundedCardWidget(
|
||||
title: "NanoGPT",
|
||||
subTitle: S.of(context).nanogpt_subtitle,
|
||||
onTap: () => _launchMarketPlaceUrl("cake.nano-gpt.com"),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -76,6 +79,17 @@ class MarketPlacePage extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
void _launchMarketPlaceUrl(String url) async {
|
||||
try {
|
||||
launchUrl(
|
||||
Uri.https(url),
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Remove ionia flow/files if we will discard it
|
||||
void _navigatorToGiftCardsPage(BuildContext context) {
|
||||
final walletType = dashboardViewModel.type;
|
||||
|
||||
@@ -10,6 +10,7 @@ import 'package:cake_wallet/src/widgets/add_template_button.dart';
|
||||
import 'package:cake_wallet/themes/extensions/send_page_theme.dart';
|
||||
import 'package:cake_wallet/themes/theme_base.dart';
|
||||
import 'package:cake_wallet/utils/debounce.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:cake_wallet/utils/responsive_layout_util.dart';
|
||||
import 'package:cw_core/sync_status.dart';
|
||||
import 'package:cw_core/wallet_type.dart';
|
||||
@@ -43,7 +44,7 @@ import 'package:cake_wallet/src/screens/exchange/widgets/present_provider_picker
|
||||
import 'package:cake_wallet/src/screens/dashboard/widgets/sync_indicator_icon.dart';
|
||||
|
||||
class ExchangePage extends BasePage {
|
||||
ExchangePage(this.exchangeViewModel, this.authService) {
|
||||
ExchangePage(this.exchangeViewModel, this.authService, this.initialPaymentRequest) {
|
||||
depositWalletName = exchangeViewModel.depositCurrency == CryptoCurrency.xmr
|
||||
? exchangeViewModel.wallet.name
|
||||
: null;
|
||||
@@ -54,6 +55,7 @@ class ExchangePage extends BasePage {
|
||||
|
||||
final ExchangeViewModel exchangeViewModel;
|
||||
final AuthService authService;
|
||||
final PaymentRequest? initialPaymentRequest;
|
||||
final depositKey = GlobalKey<ExchangeCardState>();
|
||||
final receiveKey = GlobalKey<ExchangeCardState>();
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
@@ -543,6 +545,12 @@ class ExchangePage extends BasePage {
|
||||
// amount: depositAmountController.text);
|
||||
});
|
||||
|
||||
if (initialPaymentRequest != null) {
|
||||
exchangeViewModel.receiveCurrency = CryptoCurrency.fromString(initialPaymentRequest!.scheme);
|
||||
exchangeViewModel.depositAmount = initialPaymentRequest!.amount;
|
||||
exchangeViewModel.receiveAddress = initialPaymentRequest!.address;
|
||||
}
|
||||
|
||||
_isReactionsSet = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@ import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||
import 'package:cake_wallet/utils/device_info.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:cake_wallet/view_model/link_view_model.dart';
|
||||
import 'package:cw_core/wallet_base.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
@@ -25,6 +26,7 @@ class Root extends StatefulWidget {
|
||||
required this.child,
|
||||
required this.navigatorKey,
|
||||
required this.authService,
|
||||
required this.linkViewModel,
|
||||
}) : super(key: key);
|
||||
|
||||
final AuthenticationStore authenticationStore;
|
||||
@@ -32,6 +34,7 @@ class Root extends StatefulWidget {
|
||||
final GlobalKey<NavigatorState> navigatorKey;
|
||||
final AuthService authService;
|
||||
final Widget child;
|
||||
final LinkViewModel linkViewModel;
|
||||
|
||||
@override
|
||||
RootState createState() => RootState();
|
||||
@@ -53,7 +56,6 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
||||
StreamSubscription<Uri?>? stream;
|
||||
ReactionDisposer? _walletReactionDisposer;
|
||||
ReactionDisposer? _deepLinksReactionDisposer;
|
||||
Uri? launchUri;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -98,7 +100,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
||||
void handleDeepLinking(Uri? uri) async {
|
||||
if (uri == null || !mounted) return;
|
||||
|
||||
launchUri = uri;
|
||||
widget.linkViewModel.currentLink = uri;
|
||||
|
||||
bool requireAuth = await widget.authService.requireAuth();
|
||||
|
||||
@@ -112,7 +114,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
||||
(AuthenticationState state) {
|
||||
if (state == AuthenticationState.allowed) {
|
||||
if (widget.appStore.wallet == null) {
|
||||
waitForWalletInstance(context, launchUri!);
|
||||
waitForWalletInstance(context);
|
||||
} else {
|
||||
_navigateToDeepLinkScreen();
|
||||
}
|
||||
@@ -150,6 +152,8 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// this only happens when the app has been in the background for some time
|
||||
// this does NOT trigger when the app is started from the "closed" state!
|
||||
if (_isInactive && !_postFrameCallback && _requestAuth) {
|
||||
_postFrameCallback = true;
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
@@ -158,40 +162,38 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
||||
arguments: (bool isAuthenticatedSuccessfully, AuthPageState auth) {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
final useTotp = widget.appStore.settingsStore.useTOTP2FA;
|
||||
final shouldUseTotp2FAToAccessWallets =
|
||||
widget.appStore.settingsStore.shouldRequireTOTP2FAForAccessingWallet;
|
||||
if (useTotp && shouldUseTotp2FAToAccessWallets) {
|
||||
_reset();
|
||||
auth.close(
|
||||
route: Routes.totpAuthCodePage,
|
||||
arguments: TotpAuthArgumentsModel(
|
||||
onTotpAuthenticationFinished:
|
||||
(bool isAuthenticatedSuccessfully, TotpAuthCodePageState totpAuth) {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
_reset();
|
||||
totpAuth.close(
|
||||
route: widget.linkViewModel.getRouteToGo(),
|
||||
arguments: widget.linkViewModel.getRouteArgs(),
|
||||
);
|
||||
widget.linkViewModel.currentLink = null;
|
||||
},
|
||||
isForSetup: false,
|
||||
isClosable: false,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
final useTotp = widget.appStore.settingsStore.useTOTP2FA;
|
||||
final shouldUseTotp2FAToAccessWallets =
|
||||
widget.appStore.settingsStore.shouldRequireTOTP2FAForAccessingWallet;
|
||||
if (useTotp && shouldUseTotp2FAToAccessWallets) {
|
||||
_reset();
|
||||
auth.close(
|
||||
route: Routes.totpAuthCodePage,
|
||||
arguments: TotpAuthArgumentsModel(
|
||||
onTotpAuthenticationFinished:
|
||||
(bool isAuthenticatedSuccessfully, TotpAuthCodePageState totpAuth) {
|
||||
if (!isAuthenticatedSuccessfully) {
|
||||
return;
|
||||
}
|
||||
_reset();
|
||||
totpAuth.close(
|
||||
route: _getRouteToGo(),
|
||||
arguments:
|
||||
isWalletConnectLink ? launchUri : PaymentRequest.fromUri(launchUri),
|
||||
);
|
||||
launchUri = null;
|
||||
},
|
||||
isForSetup: false,
|
||||
isClosable: false,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
_reset();
|
||||
auth.close(
|
||||
route: _getRouteToGo(),
|
||||
arguments: isWalletConnectLink ? launchUri : PaymentRequest.fromUri(launchUri),
|
||||
);
|
||||
launchUri = null;
|
||||
}
|
||||
_reset();
|
||||
auth.close(
|
||||
route: widget.linkViewModel.getRouteToGo(),
|
||||
arguments: widget.linkViewModel.getRouteArgs(),
|
||||
);
|
||||
widget.linkViewModel.currentLink = null;
|
||||
}
|
||||
},
|
||||
);
|
||||
@@ -216,36 +218,7 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
||||
_isInactiveController.add(value);
|
||||
}
|
||||
|
||||
bool _isValidPaymentUri() => launchUri?.path.isNotEmpty ?? false;
|
||||
|
||||
bool get isWalletConnectLink => launchUri?.authority == 'wc';
|
||||
|
||||
String? _getRouteToGo() {
|
||||
if (isWalletConnectLink) {
|
||||
if (isEVMCompatibleChain(widget.appStore.wallet!.type)) {
|
||||
_nonETHWalletErrorToast(S.current.switchToEVMCompatibleWallet);
|
||||
return null;
|
||||
}
|
||||
return Routes.walletConnectConnectionsListing;
|
||||
} else if (_isValidPaymentUri()) {
|
||||
return Routes.send;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _nonETHWalletErrorToast(String message) async {
|
||||
Fluttertoast.showToast(
|
||||
msg: message,
|
||||
toastLength: Toast.LENGTH_LONG,
|
||||
gravity: ToastGravity.SNACKBAR,
|
||||
backgroundColor: Colors.black,
|
||||
textColor: Colors.white,
|
||||
fontSize: 16.0,
|
||||
);
|
||||
}
|
||||
|
||||
void waitForWalletInstance(BuildContext context, Uri tempLaunchUri) {
|
||||
void waitForWalletInstance(BuildContext context) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
if (context.mounted) {
|
||||
_walletReactionDisposer = reaction(
|
||||
@@ -263,14 +236,6 @@ class RootState extends State<Root> with WidgetsBindingObserver {
|
||||
}
|
||||
|
||||
void _navigateToDeepLinkScreen() {
|
||||
if (_getRouteToGo() != null) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
widget.navigatorKey.currentState?.pushNamed(
|
||||
_getRouteToGo()!,
|
||||
arguments: isWalletConnectLink ? launchUri : PaymentRequest.fromUri(launchUri),
|
||||
);
|
||||
launchUri = null;
|
||||
});
|
||||
}
|
||||
widget.linkViewModel.handleLink();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,6 +35,8 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter_mobx/flutter_mobx.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
import 'package:smooth_page_indicator/smooth_page_indicator.dart';
|
||||
import 'package:cw_core/crypto_currency.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class SendPage extends BasePage {
|
||||
SendPage({
|
||||
@@ -420,12 +422,10 @@ class SendPage extends BasePage {
|
||||
}
|
||||
|
||||
reaction((_) => sendViewModel.state, (ExecutionState state) {
|
||||
|
||||
if (dialogContext != null && dialogContext?.mounted == true) {
|
||||
Navigator.of(dialogContext!).pop();
|
||||
}
|
||||
|
||||
|
||||
if (state is FailureState) {
|
||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||
showPopUp<void>(
|
||||
@@ -460,10 +460,10 @@ class SendPage extends BasePage {
|
||||
outputs: sendViewModel.outputs,
|
||||
rightButtonText: S.of(_dialogContext).send,
|
||||
leftButtonText: S.of(_dialogContext).cancel,
|
||||
actionRightButton: () {
|
||||
actionRightButton: () async {
|
||||
Navigator.of(_dialogContext).pop();
|
||||
sendViewModel.commitTransaction();
|
||||
showPopUp<void>(
|
||||
await showPopUp<void>(
|
||||
context: context,
|
||||
builder: (BuildContext _dialogContext) {
|
||||
return Observer(builder: (_) {
|
||||
@@ -481,12 +481,14 @@ class SendPage extends BasePage {
|
||||
sendViewModel.selectedCryptoCurrency.toString());
|
||||
|
||||
final waitMessage = sendViewModel.walletType == WalletType.solana
|
||||
? '. ${S.of(_dialogContext).waitFewSecondForTxUpdate}' : '';
|
||||
? '. ${S.of(_dialogContext).waitFewSecondForTxUpdate}'
|
||||
: '';
|
||||
|
||||
final newContactMessage = newContactAddress != null
|
||||
? '\n${S.of(_dialogContext).add_contact_to_address_book}' : '';
|
||||
? '\n${S.of(_dialogContext).add_contact_to_address_book}'
|
||||
: '';
|
||||
|
||||
final alertContent =
|
||||
String alertContent =
|
||||
"$successMessage$waitMessage$newContactMessage";
|
||||
|
||||
if (newContactAddress != null) {
|
||||
@@ -509,6 +511,10 @@ class SendPage extends BasePage {
|
||||
newContactAddress = null;
|
||||
});
|
||||
} else {
|
||||
if (initialPaymentRequest?.callbackMessage?.isNotEmpty ??
|
||||
false) {
|
||||
alertContent = initialPaymentRequest!.callbackMessage!;
|
||||
}
|
||||
return AlertWithOneAction(
|
||||
alertTitle: '',
|
||||
alertContent: alertContent,
|
||||
@@ -523,6 +529,20 @@ class SendPage extends BasePage {
|
||||
return Offstage();
|
||||
});
|
||||
});
|
||||
if (state is TransactionCommitted) {
|
||||
if (initialPaymentRequest?.callbackUrl?.isNotEmpty ?? false) {
|
||||
// wait a second so it's not as jarring:
|
||||
await Future.delayed(Duration(seconds: 1));
|
||||
try {
|
||||
launchUrl(
|
||||
Uri.parse(initialPaymentRequest!.callbackUrl!),
|
||||
mode: LaunchMode.externalApplication,
|
||||
);
|
||||
} catch (e) {
|
||||
print(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
actionLeftButton: () => Navigator.of(_dialogContext).pop());
|
||||
});
|
||||
|
||||
@@ -1,19 +1,29 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/nano/nano.dart';
|
||||
|
||||
class PaymentRequest {
|
||||
PaymentRequest(this.address, this.amount, this.note, this.scheme);
|
||||
PaymentRequest(this.address, this.amount, this.note, this.scheme, {this.callbackUrl, this.callbackMessage});
|
||||
|
||||
factory PaymentRequest.fromUri(Uri? uri) {
|
||||
var address = "";
|
||||
var amount = "";
|
||||
var note = "";
|
||||
var scheme = "";
|
||||
String? callbackUrl;
|
||||
String? callbackMessage;
|
||||
|
||||
if (uri != null) {
|
||||
address = uri.path;
|
||||
address = uri.queryParameters['address'] ?? uri.path;
|
||||
amount = uri.queryParameters['tx_amount'] ?? uri.queryParameters['amount'] ?? "";
|
||||
note = uri.queryParameters['tx_description'] ?? uri.queryParameters['message'] ?? "";
|
||||
scheme = uri.scheme;
|
||||
callbackUrl = uri.queryParameters['callback'];
|
||||
callbackMessage = uri.queryParameters['callbackMessage'];
|
||||
}
|
||||
|
||||
if (scheme == "nano-gpt") {
|
||||
// treat as nano so filling out the address works:
|
||||
scheme = "nano";
|
||||
}
|
||||
|
||||
if (nano != null) {
|
||||
@@ -26,11 +36,20 @@ class PaymentRequest {
|
||||
}
|
||||
}
|
||||
|
||||
return PaymentRequest(address, amount, note, scheme);
|
||||
return PaymentRequest(
|
||||
address,
|
||||
amount,
|
||||
note,
|
||||
scheme,
|
||||
callbackUrl: callbackUrl,
|
||||
callbackMessage: callbackMessage,
|
||||
);
|
||||
}
|
||||
|
||||
final String address;
|
||||
final String amount;
|
||||
final String note;
|
||||
final String scheme;
|
||||
final String? callbackUrl;
|
||||
final String? callbackMessage;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,118 @@
|
||||
import 'package:cake_wallet/generated/i18n.dart';
|
||||
import 'package:cake_wallet/reactions/wallet_connect.dart';
|
||||
import 'package:cake_wallet/routes.dart';
|
||||
import 'package:cake_wallet/store/app_store.dart';
|
||||
import 'package:cake_wallet/store/authentication_store.dart';
|
||||
import 'package:cake_wallet/store/settings_store.dart';
|
||||
import 'package:cake_wallet/utils/payment_request.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:fluttertoast/fluttertoast.dart';
|
||||
import 'package:mobx/mobx.dart';
|
||||
|
||||
part 'link_view_model.g.dart';
|
||||
|
||||
class LinkViewModel = LinkViewModelBase with _$LinkViewModel;
|
||||
|
||||
abstract class LinkViewModelBase with Store {
|
||||
LinkViewModelBase({
|
||||
required this.settingsStore,
|
||||
required this.appStore,
|
||||
required this.authenticationStore,
|
||||
required this.navigatorKey,
|
||||
}) {}
|
||||
|
||||
final SettingsStore settingsStore;
|
||||
final AppStore appStore;
|
||||
final AuthenticationStore authenticationStore;
|
||||
final GlobalKey<NavigatorState> navigatorKey;
|
||||
Uri? currentLink;
|
||||
|
||||
bool get _isValidPaymentUri => currentLink?.path.isNotEmpty ?? false;
|
||||
bool get isWalletConnectLink => currentLink?.authority == 'wc';
|
||||
bool get isNanoGptLink => currentLink?.scheme == 'nano-gpt';
|
||||
|
||||
String? getRouteToGo() {
|
||||
if (isWalletConnectLink) {
|
||||
if (!isEVMCompatibleChain(appStore.wallet!.type)) {
|
||||
_errorToast(S.current.switchToEVMCompatibleWallet);
|
||||
return null;
|
||||
}
|
||||
return Routes.walletConnectConnectionsListing;
|
||||
}
|
||||
|
||||
if (authenticationStore.state == AuthenticationState.uninitialized) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (isNanoGptLink) {
|
||||
switch (currentLink?.authority ?? '') {
|
||||
case "exchange":
|
||||
return Routes.exchange;
|
||||
case "send":
|
||||
return Routes.send;
|
||||
case "buy":
|
||||
return Routes.buySellPage;
|
||||
}
|
||||
}
|
||||
|
||||
if (_isValidPaymentUri) {
|
||||
return Routes.send;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
dynamic getRouteArgs() {
|
||||
if (isWalletConnectLink) {
|
||||
return currentLink;
|
||||
}
|
||||
|
||||
if (isNanoGptLink) {
|
||||
switch (currentLink?.authority ?? '') {
|
||||
case "exchange":
|
||||
case "send":
|
||||
return PaymentRequest.fromUri(currentLink);
|
||||
case "buy":
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (_isValidPaymentUri) {
|
||||
return PaymentRequest.fromUri(currentLink);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
Future<void> _errorToast(String message, {double fontSize = 16}) async {
|
||||
Fluttertoast.showToast(
|
||||
msg: message,
|
||||
toastLength: Toast.LENGTH_LONG,
|
||||
gravity: ToastGravity.SNACKBAR,
|
||||
backgroundColor: Colors.black,
|
||||
textColor: Colors.white,
|
||||
fontSize: fontSize,
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> handleLink() async {
|
||||
String? route = getRouteToGo();
|
||||
dynamic args = getRouteArgs();
|
||||
if (route != null) {
|
||||
if (appStore.wallet == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isNanoGptLink) {
|
||||
if (route == Routes.buySellPage || route == Routes.exchange) {
|
||||
await _errorToast(S.current.nano_gpt_thanks_message, fontSize: 14);
|
||||
}
|
||||
}
|
||||
currentLink = null;
|
||||
navigatorKey.currentState?.pushNamed(
|
||||
route,
|
||||
arguments: args,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user