Skip to content

Commit

Permalink
feat: add will pop scope compat and mini ui
Browse files Browse the repository at this point in the history
  • Loading branch information
alextekartik committed Dec 11, 2023
1 parent 8022ffe commit 5cb780a
Show file tree
Hide file tree
Showing 19 changed files with 402 additions and 18 deletions.
2 changes: 2 additions & 0 deletions .github/dependabot.yml
Original file line number Diff line number Diff line change
Expand Up @@ -158,3 +158,5 @@ updates:
directory: "/"
schedule:
interval: "monthly"
labels:
- autosubmit
1 change: 1 addition & 0 deletions app_common/lib/common_utils_import.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export 'package:tekartik_common_utils/common_utils_import.dart';
13 changes: 12 additions & 1 deletion app_common/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@ environment:
dependencies:
flutter:
sdk: flutter
tekartik_app_common_utils:
git:
url: https://github.com/tekartik/app_common_utils.dart
ref: dart3a
path: app
version: '>=0.1.0'
tekartik_common_utils:
git:
url: https://github.com/tekartik/common_utils.dart
ref: dart3a
version: '>=0.15.2'
tekartik_lints_flutter:
git:
url: https://github.com/tekartik/common_flutter.dart
Expand All @@ -19,7 +30,7 @@ dependencies:
dev_dependencies:
flutter_test:
sdk: flutter
flutter_lints: ^2.0.0
flutter_lints: '>=2.0.0'

# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
Expand Down
11 changes: 11 additions & 0 deletions app_widget/lib/mini_ui.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
export 'src/confirm_dialog.dart' show muiConfirm;
export 'src/mini_ui_menu.dart'
show
MuiItem,
MuiScreenWidget,
muiItem,
muiMenu,
showMuiMenu,
muiScreenWidget,
muiBuildContext;
export 'src/snack.dart' show muiSnack;
68 changes: 68 additions & 0 deletions app_widget/lib/src/confirm_dialog.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import 'package:flutter/material.dart';

class DialogButton extends StatelessWidget {
final String text;
final VoidCallback onPressed;
final bool isPrimary;

const DialogButton(
{super.key,
required this.text,
required this.onPressed,
this.isPrimary = false});

@override
Widget build(BuildContext context) {
return ElevatedButton(
onPressed: onPressed,
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 4.0, horizontal: 4.0),
child: Text(
text,
style: TextStyle(
color: isPrimary ? Colors.white : Colors.white,
fontWeight: FontWeight.bold),
),
),
);
}
}

Future<bool> muiConfirm(BuildContext context,
{String message = 'Confirm operation'}) async {
return await (showDialog<bool>(
context: context,
builder: (BuildContext context) {
// return object of type Dialog
return AlertDialog(
actionsPadding: const EdgeInsets.only(
bottom: 16, left: 16, right: 16, top: 8),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisSize: MainAxisSize.min,
children: [
const SizedBox(
height: 16,
),
Text(message,
style: const TextStyle(fontWeight: FontWeight.bold)),
],
),
actions: <Widget>[
DialogButton(
text: 'Yes',
isPrimary: true,
onPressed: () async {
Navigator.of(context).pop(true);
}),
DialogButton(
text: 'No',
onPressed: () {
Navigator.of(context).pop(false);
},
),
],
);
})) ??
false;
}
92 changes: 92 additions & 0 deletions app_widget/lib/src/mini_ui_menu.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import 'package:flutter/material.dart';
import 'package:tekartik_app_flutter_common_utils/common_utils_import.dart';

class MuiMenuContext {}

class _MuiMenuContext implements MuiMenuContext {
final _MuiMenuContext? parent;
final List<MuiItem> items = [];
_MuiMenuContext({this.parent});
}

_MuiMenuContext? _context;
BuildContext? _muiBuildContext;
BuildContext get muiBuildContext {
assert(_muiBuildContext != null,
'muiBuildContext must be called in a muiMenu context');
return _muiBuildContext!;
}

Future<T?> showMuiMenu<T>(
BuildContext context, String name, void Function() body) async {
var muiMenuContext = muiMenu(name, body) as _MuiMenuContext;
var result =
await Navigator.of(context).push<Object?>(MaterialPageRoute(builder: (_) {
return MuiScreenWidget(name: name, items: muiMenuContext.items);
}));
return castAsOrNull<T>(result);
}

void muiItem(String name, void Function() body) {
assert(_context != null, 'muiItem must be called in a muiMenu context');
_context!.items.add(MuiItem(name, body));
}

MuiScreenWidget muiScreenWidget(String name, void Function() body) {
var muiMenuContext = muiMenu(name, body) as _MuiMenuContext;
return MuiScreenWidget(name: name, items: muiMenuContext.items);
}

MuiMenuContext muiMenu(String name, void Function() body) {
var parent = _context;
try {
if (parent != null) {
muiItem(name, () {
showMuiMenu<Object?>(muiBuildContext, name, body).unawait();
});
return parent;
} else {
var context = _context = _MuiMenuContext(parent: parent);
body();
return context;
}
} finally {
_context = parent;
}
}

class MuiItem {
final String name;
final VoidCallback callback;

MuiItem(this.name, this.callback);
}

class MuiScreenWidget extends StatefulWidget {
final MuiMenuContext? context;
final String name;
final List<MuiItem> items;
const MuiScreenWidget(
{super.key, required this.items, required this.name, this.context});

@override
State<MuiScreenWidget> createState() => _MuiScreenWidgetState();
}

class _MuiScreenWidgetState extends State<MuiScreenWidget> {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text(widget.name)),
body: ListView(children: [
for (var item in widget.items)
ListTile(
title: Text(item.name),
onTap: () {
_muiBuildContext = context;
item.callback();
},
)
]));
}
}
9 changes: 9 additions & 0 deletions app_widget/lib/src/snack.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import 'package:flutter/material.dart';

Future<void> muiSnack(BuildContext context, String message) async {
ScaffoldMessenger.of(context)
..hideCurrentSnackBar()
..showSnackBar(SnackBar(
content: Text(message),
));
}
35 changes: 35 additions & 0 deletions app_widget/lib/src/will_pop_scope_compat.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import 'package:flutter/widgets.dart';

typedef WillPopCallbackCompat = Future<bool> Function();

/// Basic compat layer
class WillPopScopeCompat extends StatelessWidget {
final Widget child;

const WillPopScopeCompat({super.key, required this.child, this.onWillPop});

/// Called to veto attempts by the user to dismiss the enclosing [ModalRoute].
///
/// If the callback returns a Future that resolves to false, the enclosing
/// route will not be popped.
final WillPopCallbackCompat? onWillPop;

@override
Widget build(BuildContext context) {
return PopScope(
canPop: false,
onPopInvoked: (invoked) async {
if (invoked) {
return;
}
var willPop = (await onWillPop?.call() ?? false);
if (willPop) {
if (context.mounted) {
Navigator.of(context).pop();
}
}
},
child: child,
);
}
}
2 changes: 2 additions & 0 deletions app_widget/lib/will_pop_scope_compat.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export 'src/will_pop_scope_compat.dart'
show WillPopScopeCompat, WillPopCallbackCompat;
17 changes: 6 additions & 11 deletions app_widget/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,27 +9,22 @@ environment:
dependencies:
flutter:
sdk: flutter
tekartik_app_common_utils:
tekartik_app_flutter_common_utils:
git:
url: https://github.com/tekartik/app_common_utils.dart
url: https://github.com/tekartik/app_flutter_utils.dart
ref: dart3a
path: app
path: app_common
version: '>=0.1.0'

dev_dependencies:
flutter_test:
sdk: flutter
process_run:
dev_test: '>=0.13.3+11'
tekartik_lints_flutter:
git:
url: https://github.com/tekartik/common_flutter.dart
ref: dart3a
path: packages/lints_flutter
version: '>=0.1.0'

dependency_overrides:

dependency_overrides:
tekartik_app_flutter_common_utils:
path: ../app_common

# For information on the generic Dart part of this file, see the
# following page: https://dart.dev/tools/pub/pubspec
Expand Down
24 changes: 24 additions & 0 deletions app_widget/test/mini_ui_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:tekartik_app_flutter_widget/mini_ui.dart';

void main() {
testWidgets('MuiScreenWidget', (WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
home: muiScreenWidget(
'title',
() {
muiItem('item', () {});
},
)));

expect(find.text('title'), findsOneWidget);
expect(find.text('item'), findsOneWidget);
});

test('test', () {
muiMenu('menu', () {
muiItem('item', () {});
});
});
}
5 changes: 0 additions & 5 deletions app_widget/tool/run_ci.dart

This file was deleted.

2 changes: 2 additions & 0 deletions example/widget_test_app_lib/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,5 @@ build/
!**/ios/**/default.pbxuser
!**/ios/**/default.perspectivev3
!/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages
/.metadata
/linux/
3 changes: 3 additions & 0 deletions example/widget_test_app_lib/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# widget_test_app_lib

Flutter lib for widgets
4 changes: 4 additions & 0 deletions example/widget_test_app_lib/lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,12 @@ import 'package:tekartik_app_flutter_widget/app_widget.dart';
import 'package:tekartik_app_platform/app_platform.dart';
import 'package:tekartik_test_menu_flutter/test.dart';
import 'package:tekartik_test_menu_flutter/test_menu_flutter.dart';
import 'package:tekartik_widget_test_app_lib/mini_ui_test_menu.dart';
import 'package:tekartik_widget_test_app_lib/will_pop_scope_compat_menu.dart';

void defineMenu() {
menuWillPopScopeCompat();
menuMinuUi();
menu('widget', () {
//devPrint('MAIN_');
Widget centeredProgressScreen({ThemeData? themeData}) {
Expand Down
47 changes: 47 additions & 0 deletions example/widget_test_app_lib/lib/mini_ui_test_menu.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import 'package:flutter/material.dart';
import 'package:tekartik_app_flutter_common_utils/common_utils_import.dart';
import 'package:tekartik_app_flutter_widget/mini_ui.dart';
import 'package:tekartik_test_menu_flutter/test.dart';

void menuMinuUi() {
menu('Mini ui', () {
item('showMuiMenu', () async {
var result = await showMuiMenu<Object?>(
castAsNullable(buildContext)!, 'simple', () {
muiItem('Pop', () => Navigator.of(muiBuildContext).pop(null));
muiItem('Pop Some text',
() => Navigator.of(muiBuildContext).pop('Some text'));
muiItem('Snack Some text', () {
muiSnack(muiBuildContext, 'Some text');
});
});
write('result: $result');
});

item('subMenu', () async {
var result = await showMuiMenu<Object?>(
castAsNullable(buildContext)!, 'simple', () {
muiItem('Pop', () => Navigator.of(muiBuildContext).pop(null));

muiMenu('sub', () {
muiItem('Pop Sub', () => Navigator.of(muiBuildContext).pop(null));
muiItem('Pop Sub Some text',
() => Navigator.of(muiBuildContext).pop('Sub Some text'));

muiItem('showMuiMenu', () async {
var result = await showMuiMenu<Object?>(
castAsNullable(buildContext)!, 'simple', () {
muiItem('Pop', () => Navigator.of(muiBuildContext).pop(null));
muiItem('Pop Some text',
() => Navigator.of(muiBuildContext).pop('Some text'));
});
write('result: $result');
});
});
muiItem('Pop Some text',
() => Navigator.of(muiBuildContext).pop('Some text'));
});
write('result: $result');
});
});
}
Loading

0 comments on commit 5cb780a

Please sign in to comment.