Jonny Borges

fix dismissible tests

1 import 'package:flutter/material.dart'; 1 import 'package:flutter/material.dart';
2 import 'package:get/get.dart'; 2 import 'package:get/get.dart';
3 3
4 -// void main() {  
5 -// runApp(const MyApp());  
6 -// }  
7 -  
8 -// class MyApp extends StatelessWidget {  
9 -// const MyApp({Key? key}) : super(key: key);  
10 -  
11 -// @override  
12 -// Widget build(BuildContext context) {  
13 -// return GetMaterialApp(  
14 -// theme: ThemeData(useMaterial3: true),  
15 -// debugShowCheckedModeBanner: false,  
16 -// enableLog: true,  
17 -// logWriterCallback: Logger.write,  
18 -// initialRoute: AppPages.INITIAL,  
19 -// getPages: AppPages.routes,  
20 -// locale: TranslationService.locale,  
21 -// fallbackLocale: TranslationService.fallbackLocale,  
22 -// translations: TranslationService(),  
23 -// );  
24 -// }  
25 -// }  
26 -  
27 -/// Nav 2 snippet  
28 void main() { 4 void main() {
29 - runApp(const MyApp()); 5 + runApp(MyApp());
30 } 6 }
31 7
32 class MyApp extends StatelessWidget { 8 class MyApp extends StatelessWidget {
33 - const MyApp({Key? key}) : super(key: key);  
34 - 9 +// This widget is the root of your application.
35 @override 10 @override
36 Widget build(BuildContext context) { 11 Widget build(BuildContext context) {
37 return GetMaterialApp( 12 return GetMaterialApp(
38 - getPages: [  
39 - GetPage(  
40 - participatesInRootNavigator: true,  
41 - name: '/first',  
42 - page: () => const First()),  
43 - GetPage(  
44 - name: '/second',  
45 - page: () => const Second(),  
46 - transition: Transition.downToUp, 13 + title: 'Scaffold demo',
  14 + theme: ThemeData(
  15 + primarySwatch: Colors.blue,
47 ), 16 ),
48 - GetPage(  
49 - name: '/third',  
50 - page: () => const Third(),  
51 - ),  
52 - ], 17 + home: MyHomePage(),
53 debugShowCheckedModeBanner: false, 18 debugShowCheckedModeBanner: false,
54 ); 19 );
55 } 20 }
56 } 21 }
57 22
58 -class FirstController extends GetxController {  
59 - @override  
60 - void onClose() {  
61 - print('on close first');  
62 - super.onClose();  
63 - }  
64 -}  
65 -  
66 -class First extends StatelessWidget {  
67 - const First({Key? key}) : super(key: key);  
68 - 23 +class MyHomePage extends StatelessWidget {
69 @override 24 @override
70 Widget build(BuildContext context) { 25 Widget build(BuildContext context) {
71 - print('First rebuild');  
72 - Get.put(FirstController());  
73 return Scaffold( 26 return Scaffold(
74 appBar: AppBar( 27 appBar: AppBar(
75 - title: const Text('page one'),  
76 - leading: IconButton(  
77 - icon: const Icon(Icons.more),  
78 - onPressed: () {  
79 - Get.snackbar(  
80 - 'title',  
81 - "message",  
82 - mainButton:  
83 - TextButton(onPressed: () {}, child: const Text('button')),  
84 - isDismissible: false,  
85 - );  
86 - // print('THEME CHANGED');  
87 - // Get.changeTheme(  
88 - // Get.isDarkMode ? ThemeData.light() : ThemeData.dark());  
89 - }, 28 + title: Text('Test'),
  29 + centerTitle: true,
  30 + backgroundColor: Colors.green,
90 ), 31 ),
91 - ),  
92 - body: Center(  
93 - child: SizedBox(  
94 - height: 300,  
95 - width: 300, 32 + bottomNavigationBar: SizedBox(
  33 + width: double.infinity,
96 child: ElevatedButton( 34 child: ElevatedButton(
  35 + child: Text('Tap me when Snackbar appears'),
97 onPressed: () { 36 onPressed: () {
98 - Get.toNamed('/second?id=123'); 37 + print('This should clicked');
99 }, 38 },
100 - child: const Text('next screen'),  
101 ), 39 ),
102 ), 40 ),
103 - ),  
104 - );  
105 - }  
106 -}  
107 -  
108 -class SecondController extends GetxController {  
109 - final textEdit = TextEditingController();  
110 - @override  
111 - void onClose() {  
112 - print('on close second');  
113 - textEdit.dispose();  
114 - super.onClose();  
115 - }  
116 -}  
117 -  
118 -class Second extends StatelessWidget {  
119 - const Second({Key? key}) : super(key: key);  
120 -  
121 - @override  
122 - Widget build(BuildContext context) {  
123 - final controller = Get.put(SecondController());  
124 - print('second rebuild');  
125 - return Scaffold(  
126 - appBar: AppBar(  
127 - title: Text('page two ${Get.parameters["id"]}'),  
128 - ),  
129 body: Center( 41 body: Center(
130 - child: Column(  
131 - children: [  
132 - Expanded(  
133 - child: TextField(  
134 - controller: controller.textEdit,  
135 - )),  
136 - SizedBox(  
137 - height: 300,  
138 - width: 300,  
139 child: ElevatedButton( 42 child: ElevatedButton(
140 - onPressed: () {},  
141 - child: const Text('next screen'),  
142 - ),  
143 - ),  
144 - ],  
145 - ),  
146 - ), 43 + child: Text('Open Snackbar'),
  44 + onPressed: () {
  45 + Get.snackbar(
  46 + "Snackbar Showed",
  47 + "Please click the button on BottomNavigationBar",
  48 + icon: Icon(Icons.check, color: Colors.green),
  49 + backgroundColor: Colors.white,
  50 + snackStyle: SnackStyle.floating,
  51 + borderRadius: 20,
  52 + isDismissible: false,
  53 + snackPosition: SnackPosition.bottom,
  54 + margin: EdgeInsets.fromLTRB(50, 15, 50, 15),
147 ); 55 );
148 - }  
149 -}  
150 -  
151 -class Third extends StatelessWidget {  
152 - const Third({Key? key}) : super(key: key);  
153 -  
154 - @override  
155 - Widget build(BuildContext context) {  
156 - return Scaffold(  
157 - backgroundColor: Colors.red,  
158 - appBar: AppBar(  
159 - title: const Text('page three'),  
160 - ),  
161 - body: Center(  
162 - child: SizedBox(  
163 - height: 300,  
164 - width: 300,  
165 - child: ElevatedButton(  
166 - onPressed: () {},  
167 - child: const Text('go to first screen'),  
168 - ), 56 + },
169 ), 57 ),
170 ), 58 ),
171 ); 59 );
@@ -341,13 +341,12 @@ class GetRootState extends State<GetRoot> with WidgetsBindingObserver { @@ -341,13 +341,12 @@ class GetRootState extends State<GetRoot> with WidgetsBindingObserver {
341 void onClose() { 341 void onClose() {
342 config.onDispose?.call(); 342 config.onDispose?.call();
343 Get.clearTranslations(); 343 Get.clearTranslations();
  344 + config.snackBarQueue.disposeControllers();
344 RouterReportManager.instance.clearRouteKeys(); 345 RouterReportManager.instance.clearRouteKeys();
345 RouterReportManager.dispose(); 346 RouterReportManager.dispose();
346 Get.resetInstance(clearRouteBindings: true); 347 Get.resetInstance(clearRouteBindings: true);
347 _controller = null; 348 _controller = null;
348 ambiguate(Engine.instance)!.removeObserver(this); 349 ambiguate(Engine.instance)!.removeObserver(this);
349 - config.snackBarQueue.cancelAllJobs();  
350 - config.snackBarQueue.disposeControllers();  
351 } 350 }
352 351
353 @override 352 @override
@@ -19,6 +19,13 @@ class GetSnackBar extends StatefulWidget { @@ -19,6 +19,13 @@ class GetSnackBar extends StatefulWidget {
19 /// The title displayed to the user 19 /// The title displayed to the user
20 final String? title; 20 final String? title;
21 21
  22 + /// Defines how the snack bar area, including margin, will behave during hit testing.
  23 + ///
  24 + /// If this property is null and [margin] is not null, then [HitTestBehavior.deferToChild] is used by default.
  25 + ///
  26 + /// Please refer to [HitTestBehavior] for a detailed explanation of every behavior.
  27 + final HitTestBehavior? hitTestBehavior;
  28 +
22 /// The direction in which the SnackBar can be dismissed. 29 /// The direction in which the SnackBar can be dismissed.
23 /// 30 ///
24 /// Default is [DismissDirection.down] when 31 /// Default is [DismissDirection.down] when
@@ -203,6 +210,7 @@ class GetSnackBar extends StatefulWidget { @@ -203,6 +210,7 @@ class GetSnackBar extends StatefulWidget {
203 this.overlayColor = Colors.transparent, 210 this.overlayColor = Colors.transparent,
204 this.userInputForm, 211 this.userInputForm,
205 this.snackbarStatus, 212 this.snackbarStatus,
  213 + this.hitTestBehavior,
206 }) : super(key: key); 214 }) : super(key: key);
207 215
208 @override 216 @override
@@ -245,6 +245,7 @@ class SnackbarController { @@ -245,6 +245,7 @@ class SnackbarController {
245 snackbar.onHover?.call(snackbar, SnackHoverState.entered), 245 snackbar.onHover?.call(snackbar, SnackHoverState.entered),
246 onExit: (_) => snackbar.onHover?.call(snackbar, SnackHoverState.exited), 246 onExit: (_) => snackbar.onHover?.call(snackbar, SnackHoverState.exited),
247 child: GestureDetector( 247 child: GestureDetector(
  248 + behavior: snackbar.hitTestBehavior ?? HitTestBehavior.deferToChild,
248 onTap: snackbar.onTap != null 249 onTap: snackbar.onTap != null
249 ? () => snackbar.onTap?.call(snackbar) 250 ? () => snackbar.onTap?.call(snackbar)
250 : null, 251 : null,
@@ -263,6 +264,7 @@ class SnackbarController { @@ -263,6 +264,7 @@ class SnackbarController {
263 264
264 Widget _getDismissibleSnack(Widget child) { 265 Widget _getDismissibleSnack(Widget child) {
265 return Dismissible( 266 return Dismissible(
  267 + behavior: snackbar.hitTestBehavior ?? HitTestBehavior.opaque,
266 direction: snackbar.dismissDirection ?? _getDefaultDismissDirection(), 268 direction: snackbar.dismissDirection ?? _getDefaultDismissDirection(),
267 resizeDuration: null, 269 resizeDuration: null,
268 confirmDismiss: (_) { 270 confirmDismiss: (_) {
@@ -382,10 +384,19 @@ class SnackBarQueue { @@ -382,10 +384,19 @@ class SnackBarQueue {
382 _snackbarList.clear(); 384 _snackbarList.clear();
383 } 385 }
384 386
385 - Future<void> disposeControllers() async { 387 + void disposeControllers() {
  388 + if (_currentSnackbar != null) {
  389 + _currentSnackbar?._removeOverlay();
  390 + _currentSnackbar?._controller.dispose();
  391 + _snackbarList.remove(_currentSnackbar);
  392 + }
  393 +
  394 + _queue.cancelAllJobs();
  395 +
386 for (var element in _snackbarList) { 396 for (var element in _snackbarList) {
387 element._controller.dispose(); 397 element._controller.dispose();
388 } 398 }
  399 + _snackbarList.clear();
389 } 400 }
390 401
391 Future<void> closeCurrentJob() async { 402 Future<void> closeCurrentJob() async {
@@ -107,13 +107,15 @@ void main() { @@ -107,13 +107,15 @@ void main() {
107 }); 107 });
108 108
109 testWidgets("test snackbar dismissible", (tester) async { 109 testWidgets("test snackbar dismissible", (tester) async {
110 - const dismissDirection = DismissDirection.vertical; 110 + const dismissDirection = DismissDirection.down;
111 const snackBarTapTarget = Key('snackbar-tap-target'); 111 const snackBarTapTarget = Key('snackbar-tap-target');
112 112
113 const GetSnackBar getBar = GetSnackBar( 113 const GetSnackBar getBar = GetSnackBar(
  114 + key: ValueKey('dismissible'),
114 message: 'bar1', 115 message: 'bar1',
115 duration: Duration(seconds: 2), 116 duration: Duration(seconds: 2),
116 isDismissible: true, 117 isDismissible: true,
  118 + snackPosition: SnackPosition.bottom,
117 dismissDirection: dismissDirection, 119 dismissDirection: dismissDirection,
118 ); 120 );
119 121
@@ -149,14 +151,14 @@ void main() { @@ -149,14 +151,14 @@ void main() {
149 await tester.tap(find.byKey(snackBarTapTarget)); 151 await tester.tap(find.byKey(snackBarTapTarget));
150 await tester.pumpAndSettle(); 152 await tester.pumpAndSettle();
151 153
152 - // expect(Get.isSnackbarOpen, true);  
153 - // await tester.pump(const Duration(milliseconds: 500));  
154 - // expect(find.byWidget(getBar), findsOneWidget);  
155 - // await tester.ensureVisible(find.byWidget(getBar));  
156 - // await tester.drag(find.byWidget(getBar), const Offset(0.0, 50.0));  
157 - // await tester.pump(const Duration(milliseconds: 500));  
158 -  
159 - // expect(Get.isSnackbarOpen, false); 154 + expect(Get.isSnackbarOpen, true);
  155 + await tester.pump(const Duration(milliseconds: 500));
  156 + expect(find.byWidget(getBar), findsOneWidget);
  157 + await tester.ensureVisible(find.byWidget(getBar));
  158 + await tester.drag(find.byType(Dismissible), const Offset(0.0, 50.0));
  159 + await tester.pumpAndSettle();
  160 + await tester.pump(const Duration(milliseconds: 500));
  161 + expect(Get.isSnackbarOpen, false);
160 }); 162 });
161 163
162 testWidgets("test snackbar onTap", (tester) async { 164 testWidgets("test snackbar onTap", (tester) async {