* 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:
Matthew Fosse
2024-05-08 03:00:01 +03:00
committed by GitHub
parent e5be737236
commit baad7f7469
46 changed files with 486 additions and 195 deletions
@@ -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;
+9 -1
View File
@@ -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;
}
+40 -75
View File
@@ -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();
}
}
+27 -7
View File
@@ -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());
});