Skip to content

Commit af176fa

Browse files
2 parents 9342177 + 713852d commit af176fa

1 file changed

Lines changed: 104 additions & 36 deletions

File tree

lib/main.dart

Lines changed: 104 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
import 'package:flutter/material.dart';
2+
import 'package:flutter/services.dart';
3+
24
import 'package:go_router/go_router.dart';
5+
import 'package:netshare/ui/common_view/confirm_dialog.dart';
6+
import 'package:provider/provider.dart';
7+
38
import 'package:netshare/config/styles.dart';
49
import 'package:netshare/di/di.dart';
510
import 'package:netshare/plugin_management/plugins.dart';
@@ -13,34 +18,40 @@ import 'package:netshare/ui/receive/receive_widget.dart';
1318
import 'package:netshare/ui/send/send_widget.dart';
1419
import 'package:netshare/ui/server/server_widget.dart';
1520
import 'package:netshare/util/utility_functions.dart';
16-
import 'package:provider/provider.dart';
17-
1821
import 'package:netshare/config/constants.dart';
1922
import 'package:netshare/ui/send/uploading_widget.dart';
2023

2124
void main() async {
2225
WidgetsFlutterBinding.ensureInitialized();
2326
await initPlugins();
2427
setupDI();
25-
runApp(MyApp());
28+
runApp(const MyApp());
2629
}
2730

28-
class MyApp extends StatelessWidget {
31+
final GlobalKey<NavigatorState> _navigatorKey = GlobalKey<NavigatorState>();
32+
33+
class MyApp extends StatefulWidget {
34+
const MyApp({super.key});
35+
36+
@override
37+
State<MyApp> createState() => _MyAppState();
38+
}
2939

30-
MyApp({super.key});
40+
class _MyAppState extends State<MyApp> {
3141

3242
final GoRouter _router = GoRouter(
43+
navigatorKey: _navigatorKey,
3344
errorBuilder: (BuildContext context, GoRouterState state) => ErrorWidget(state.error!),
3445
routes: <GoRoute>[
3546
GoRoute(
3647
path: mRootPath,
37-
redirect: (context, state) {
38-
if(UtilityFunctions.isMobile) {
39-
return '/$mClientPath';
40-
} else {
41-
return '/$mServerPath';
42-
}
43-
},
48+
redirect: (context, state) {
49+
if (UtilityFunctions.isMobile) {
50+
return '/$mClientPath';
51+
} else {
52+
return '/$mServerPath';
53+
}
54+
},
4455
),
4556
GoRoute(
4657
name: mNavigationPath,
@@ -56,33 +67,34 @@ class MyApp extends StatelessWidget {
5667
name: mClientPath,
5768
path: '/$mClientPath',
5869
builder: (context, state) => const ClientWidget(),
59-
routes: [
60-
GoRoute(
61-
name: mSendPath,
62-
path: mSendPath,
63-
builder: (BuildContext context, GoRouterState state) => const SendWidget(),
64-
routes: [
65-
GoRoute(
66-
name: mUploadingPath,
67-
path: mUploadingPath,
68-
builder: (context, state) => const UploadingWidget(),
69-
)
70-
],
71-
),
72-
GoRoute(
73-
name: mReceivePath,
74-
path: mReceivePath,
75-
builder: (BuildContext context, GoRouterState state) => const ReceiveWidget(),
76-
),
77-
GoRoute(
78-
name: mScanningPath,
79-
path: mScanningPath,
80-
builder: (BuildContext context, GoRouterState state) => const ScanQRWidget(),
81-
),
82-
],
70+
routes: [
71+
GoRoute(
72+
name: mSendPath,
73+
path: mSendPath,
74+
builder: (BuildContext context, GoRouterState state) => const SendWidget(),
75+
routes: [
76+
GoRoute(
77+
name: mUploadingPath,
78+
path: mUploadingPath,
79+
builder: (context, state) => const UploadingWidget(),
80+
)
81+
],
82+
),
83+
GoRoute(
84+
name: mReceivePath,
85+
path: mReceivePath,
86+
builder: (BuildContext context, GoRouterState state) => const ReceiveWidget(),
87+
),
88+
GoRoute(
89+
name: mScanningPath,
90+
path: mScanningPath,
91+
builder: (BuildContext context, GoRouterState state) => const ScanQRWidget(),
92+
),
93+
],
8394
),
8495
],
8596
);
97+
bool _isKeyboardListenerEnabled = true;
8698

8799
@override
88100
Widget build(BuildContext context) {
@@ -101,7 +113,63 @@ class MyApp extends StatelessWidget {
101113
colorScheme: ColorScheme.fromSeed(seedColor: seedColor, background: backgroundColor),
102114
),
103115
routerConfig: _router,
116+
builder: (context, child) {
117+
// Handle keyboard listener here
118+
RawKeyboard.instance.addListener((RawKeyEvent value) => _handleKeyEvent(value));
119+
return child ?? const SizedBox.shrink();
120+
},
104121
),
105122
);
106123
}
124+
125+
void _handleKeyEvent(RawKeyEvent value) async {
126+
if (!_isKeyboardListenerEnabled) return;
127+
128+
// If user pressed Command/Control + W keys, quit the app
129+
if (value.isMetaPressed && value.logicalKey == LogicalKeyboardKey.keyW ||
130+
value.isControlPressed && value.logicalKey == LogicalKeyboardKey.keyW) {
131+
132+
if(_navigatorKey.currentContext == null) return;
133+
134+
// show confirm dialog
135+
_showQuitAppConfirmationDialog(_navigatorKey.currentContext!, (confirmCallback) {
136+
if (confirmCallback) {
137+
SystemNavigator.pop(); // Quit the app
138+
}
139+
// listen keyboard again
140+
_isKeyboardListenerEnabled = true;
141+
});
142+
}
143+
}
144+
145+
void _showQuitAppConfirmationDialog(BuildContext context, Function(bool)? confirmCallback) {
146+
// Disable the keyboard listener.
147+
_isKeyboardListenerEnabled = false;
148+
149+
showDialog(
150+
barrierDismissible: false,
151+
context: context,
152+
builder: (dialogContext) {
153+
return ConfirmDialog(
154+
dialogWidth: MediaQuery.of(dialogContext).size.width / 2,
155+
header: Text(
156+
'Quit App',
157+
style: Theme.of(dialogContext).textTheme.headlineMedium?.copyWith(
158+
fontSize: 18.0,
159+
fontWeight: FontWeight.bold,
160+
),
161+
textAlign: TextAlign.center,
162+
),
163+
body: const Text(
164+
'Are you sure you want to quit the app?',
165+
textAlign: TextAlign.center,
166+
),
167+
cancelButtonTitle: 'No',
168+
okButtonTitle: 'Yes, I\'m sure',
169+
onCancel: () => confirmCallback?.call(false),
170+
onConfirm: () => confirmCallback?.call(true),
171+
);
172+
},
173+
);
174+
}
107175
}

0 commit comments

Comments
 (0)