Skip to content

Commit

Permalink
Deprecate just-in-time navigation pop APIs for Android Predictive Back
Browse files Browse the repository at this point in the history
Tests completed for:
- [x] HomePage
- [x] BreezAvatarDialog
- [x] PaymentOptionsPage
- [x] promptError (error_dialog.dart)
- [x] LockScreen
- [x] EnterMnemonicsPage
- [x] PaymentRequestDialog
- [x] UserApp
on Android
  • Loading branch information
erdemyerebasmaz committed Nov 16, 2023
1 parent 044090b commit 978f5aa
Show file tree
Hide file tree
Showing 9 changed files with 88 additions and 88 deletions.
31 changes: 25 additions & 6 deletions lib/routes/home/home_page.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import 'dart:io';

import 'package:breez_translations/breez_translations_locales.dart';
import 'package:c_breez/handlers/check_version_handler.dart';
import 'package:c_breez/handlers/connectivity_handler.dart';
import 'package:c_breez/handlers/handler.dart';
Expand All @@ -7,11 +10,11 @@ import 'package:c_breez/handlers/payment_result_handler.dart';
import 'package:c_breez/routes/home/account_page.dart';
import 'package:c_breez/routes/home/widgets/app_bar/home_app_bar.dart';
import 'package:c_breez/routes/home/widgets/bottom_actions_bar/bottom_actions_bar.dart';
import 'package:c_breez/routes/home/widgets/close_popup.dart';
import 'package:c_breez/routes/home/widgets/drawer/home_drawer.dart';
import 'package:c_breez/routes/home/widgets/fade_in_widget.dart';
import 'package:c_breez/routes/home/widgets/qr_action_button.dart';
import 'package:c_breez/routes/security/auto_lock_mixin.dart';
import 'package:c_breez/widgets/error_dialog.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/scheduler.dart';
Expand Down Expand Up @@ -69,11 +72,27 @@ class HomeState extends State<Home> with AutoLockMixin, HandlerContextProvider {
final themeData = Theme.of(context);
final mediaSize = MediaQuery.of(context).size;

return WillPopScope(
onWillPop: willPopCallback(
context,
canCancel: () => _scaffoldKey.currentState?.isDrawerOpen ?? false,
),
return PopScope(
canPop: false,
onPopInvoked: (_) async {
// Only close drawer if it's open
final NavigatorState navigator = Navigator.of(context);
if (_scaffoldKey.currentState?.isDrawerOpen ?? false) {
navigator.pop();
return;
}

// If drawer is not open, prompt user to approve exiting the app
final texts = context.texts();
final bool? shouldPop = await promptAreYouSure(
context,
texts.close_popup_title,
Text(texts.close_popup_message),
);
if (shouldPop ?? false) {
exit(0);
}
},
child: SizedBox(
height: mediaSize.height,
width: mediaSize.width,
Expand Down
28 changes: 0 additions & 28 deletions lib/routes/home/widgets/close_popup.dart

This file was deleted.

5 changes: 3 additions & 2 deletions lib/routes/home/widgets/drawer/breez_avatar_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ class BreezAvatarDialogState extends State<BreezAvatarDialog> {

@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () => Future.value(!isUploading),
return PopScope(
canPop: !isUploading,
child: StatefulBuilder(
builder: (context, setState) {
final texts = context.texts();
Expand Down Expand Up @@ -139,6 +139,7 @@ class BreezAvatarDialogState extends State<BreezAvatarDialog> {
setState(() {
isUploading = true;
});
await Future.delayed(const Duration(seconds: 15));
var userName = nameInputController.text.isNotEmpty
? nameInputController.text
: userBloc.state.profileSettings.name;
Expand Down
28 changes: 11 additions & 17 deletions lib/routes/initial_walkthrough/mnemonics/enter_mnemonics_page.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import 'dart:async';

import 'package:breez_translations/breez_translations_locales.dart';
import 'package:c_breez/routes/initial_walkthrough/mnemonics/widgets/restore_form_page.dart';
import 'package:c_breez/widgets/back_button.dart' as back_button;
Expand All @@ -26,8 +24,17 @@ class EnterMnemonicsPageState extends State<EnterMnemonicsPage> {
final texts = context.texts();
final query = MediaQuery.of(context);

return WillPopScope(
onWillPop: _onWillPop,
return PopScope(
canPop: _currentPage == 1,
onPopInvoked: (_) async {
if (_currentPage > 1) {
FocusScope.of(context).requestFocus(FocusNode());
setState(() {
_currentPage--;
});
return;
}
},
child: Scaffold(
appBar: AppBar(
automaticallyImplyLeading: false,
Expand Down Expand Up @@ -68,17 +75,4 @@ class EnterMnemonicsPageState extends State<EnterMnemonicsPage> {
),
);
}

Future<bool> _onWillPop() async {
if (_currentPage == 1) {
return true;
} else if (_currentPage > 1) {
FocusScope.of(context).requestFocus(FocusNode());
setState(() {
_currentPage--;
});
return false;
}
return false;
}
}
7 changes: 5 additions & 2 deletions lib/routes/payment_options/payment_options_page.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,11 @@ class PaymentOptionsPage extends StatelessWidget {
final themeData = Theme.of(context);
final bloc = context.read<PaymentOptionsBloc>();

return WillPopScope(
onWillPop: () => bloc.cancelEditing().then((_) => true),
return PopScope(
canPop: true,
onPopInvoked: (_) async {
await bloc.cancelEditing();
},
child: Scaffold(
appBar: AppBar(
key: GlobalKey<ScaffoldState>(),
Expand Down
5 changes: 2 additions & 3 deletions lib/routes/security/lock_screen.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ import 'package:c_breez/bloc/security/security_state.dart';
import 'package:c_breez/routes/security/widget/pin_code_widget.dart';
import 'package:c_breez/theme/breez_light_theme.dart';
import 'package:c_breez/widgets/route.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:hydrated_bloc/hydrated_bloc.dart';
Expand All @@ -26,8 +25,8 @@ class LockScreen extends StatelessWidget {
final texts = context.texts();
final navigator = Navigator.of(context);

return WillPopScope(
onWillPop: () => SynchronousFuture(false),
return PopScope(
canPop: false,
child: Scaffold(
body: BlocBuilder<SecurityBloc, SecurityState>(
builder: (context, state) {
Expand Down
6 changes: 2 additions & 4 deletions lib/user_app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -128,10 +128,8 @@ class UserApp extends StatelessWidget {
);
case '/':
return FadeInRoute(
builder: (_) => WillPopScope(
onWillPop: () async {
return !await _homeNavigatorKey.currentState!.maybePop();
},
builder: (_) => NavigatorPopHandler(
onPop: () => _homeNavigatorKey.currentState!.pop(),
child: Navigator(
initialRoute: "/",
key: _homeNavigatorKey,
Expand Down
5 changes: 2 additions & 3 deletions lib/widgets/error_dialog.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,14 @@ Future<void> promptError(
final themeData = Theme.of(context);

bool canPop = !disableBack;
Future<bool> canPopCallback() => Future.value(canPop);

return showDialog<void>(
useRootNavigator: false,
context: context,
barrierDismissible: false, // user must tap button!
builder: (BuildContext context) {
return WillPopScope(
onWillPop: canPopCallback,
return PopScope(
canPop: canPop,
child: AlertDialog(
contentPadding: const EdgeInsets.fromLTRB(16.0, 16.0, 16.0, 0.0),
title: title == null ? null : Text(title),
Expand Down
61 changes: 38 additions & 23 deletions lib/widgets/payment_dialogs/payment_request_dialog.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import 'dart:async';

import 'package:c_breez/bloc/account/account_bloc.dart';
import 'package:c_breez/models/invoice.dart';
import 'package:c_breez/widgets/payment_dialogs/payment_confirmation_dialog.dart';
Expand Down Expand Up @@ -35,77 +33,94 @@ class PaymentRequestDialog extends StatefulWidget {
}

class PaymentRequestDialogState extends State<PaymentRequestDialog> {
late AccountBloc accountBloc;
PaymentRequestState? _state;
String? _amountToPayStr;
int? _amountToPay;

ModalRoute? _currentRoute;

@override
void initState() {
super.initState();
accountBloc = context.read<AccountBloc>();
_state = PaymentRequestState.PAYMENT_REQUEST;
}

@override
Widget build(BuildContext context) {
return WillPopScope(
onWillPop: () => _onWillPop(context),
child: showPaymentRequestDialog(context),
);
void didChangeDependencies() {
super.didChangeDependencies();
_currentRoute ??= ModalRoute.of(context);
}

Future<bool> _onWillPop(BuildContext context) async {
if (_state == PaymentRequestState.PROCESSING_PAYMENT) return false;
context.read<AccountBloc>().cancelPayment(widget.invoice.bolt11);
return true;
@override
Widget build(BuildContext context) {
return PopScope(
canPop: false,
onPopInvoked: (_) async {
if (_state == PaymentRequestState.PROCESSING_PAYMENT) {
return;
} else {
final NavigatorState navigator = Navigator.of(context);
accountBloc.cancelPayment(widget.invoice.bolt11);
if (_currentRoute != null && _currentRoute!.isActive) {
navigator.removeRoute(_currentRoute!);
}
return;
}
},
child: showPaymentRequestDialog(),
);
}

Widget showPaymentRequestDialog(BuildContext context) {
Widget showPaymentRequestDialog() {
const double minHeight = 220;

if (_state == PaymentRequestState.PROCESSING_PAYMENT) {
return ProcessingPaymentDialog(
firstPaymentItemKey: widget.firstPaymentItemKey,
minHeight: minHeight,
paymentFunc: () => context
.read<AccountBloc>()
.sendPayment(widget.invoice.bolt11, widget.invoice.amountMsat == 0 ? _amountToPay! * 1000 : null),
onStateChange: (state) => _onStateChange(context, state),
paymentFunc: () => accountBloc.sendPayment(
widget.invoice.bolt11,
widget.invoice.amountMsat == 0 ? _amountToPay! * 1000 : null,
),
onStateChange: (state) => _onStateChange(state),
);
} else if (_state == PaymentRequestState.WAITING_FOR_CONFIRMATION) {
return PaymentConfirmationDialog(
widget.invoice.bolt11,
_amountToPay!,
_amountToPayStr!,
() => _onStateChange(context, PaymentRequestState.USER_CANCELLED),
() => _onStateChange(PaymentRequestState.USER_CANCELLED),
(bolt11, amount) => setState(() {
_amountToPay = amount;
_onStateChange(context, PaymentRequestState.PROCESSING_PAYMENT);
_onStateChange(PaymentRequestState.PROCESSING_PAYMENT);
}),
minHeight,
);
} else {
return PaymentRequestInfoDialog(
widget.invoice,
() => _onStateChange(context, PaymentRequestState.USER_CANCELLED),
() => _onStateChange(context, PaymentRequestState.WAITING_FOR_CONFIRMATION),
() => _onStateChange(PaymentRequestState.USER_CANCELLED),
() => _onStateChange(PaymentRequestState.WAITING_FOR_CONFIRMATION),
(bolt11, amount) {
_amountToPay = amount;
_onStateChange(context, PaymentRequestState.PROCESSING_PAYMENT);
_onStateChange(PaymentRequestState.PROCESSING_PAYMENT);
},
(map) => _setAmountToPay(map),
minHeight,
);
}
}

void _onStateChange(BuildContext context, PaymentRequestState state) {
void _onStateChange(PaymentRequestState state) {
if (state == PaymentRequestState.PAYMENT_COMPLETED) {
Navigator.of(context).pop();
return;
}
if (state == PaymentRequestState.USER_CANCELLED) {
Navigator.of(context).pop();
context.read<AccountBloc>().cancelPayment(widget.invoice.bolt11);
accountBloc.cancelPayment(widget.invoice.bolt11);
return;
}
setState(() {
Expand Down

0 comments on commit 978f5aa

Please sign in to comment.