Skip to content

Commit

Permalink
feat: add Ctrl+Q shortcut to quit the app
Browse files Browse the repository at this point in the history
Follows Linux conventions.
  • Loading branch information
Merrit committed Jan 4, 2024
1 parent a65e6c9 commit 53381a6
Show file tree
Hide file tree
Showing 14 changed files with 133 additions and 25 deletions.
37 changes: 20 additions & 17 deletions lib/app.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'package:window_manager/window_manager.dart';
import '../apps_list/apps_list.dart';
import '../logs/log_page.dart';
import '../theme/theme.dart';
import 'hotkey/hotkey.dart';
import 'loading/loading_page.dart';
import 'settings/settings.dart';
import 'window/app_window.dart';
Expand Down Expand Up @@ -88,23 +89,25 @@ class _AppState extends State<App> with TrayListener, WindowListener {

@override
Widget build(BuildContext context) {
return BlocBuilder<ThemeCubit, ThemeState>(
builder: (context, state) {
return MaterialApp(
title: 'Nyrna',
debugShowCheckedModeBanner: false,
theme: state.themeData,
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
routes: {
LoadingPage.id: (context) => const LoadingPage(),
LogPage.id: (context) => LogPage(),
AppsListPage.id: (context) => const AppsListPage(),
SettingsPage.id: (conext) => SettingsPage(),
},
home: const LoadingPage(),
);
},
return AppShortcuts(
child: BlocBuilder<ThemeCubit, ThemeState>(
builder: (context, state) {
return MaterialApp(
title: 'Nyrna',
debugShowCheckedModeBanner: false,
theme: state.themeData,
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
routes: {
LoadingPage.id: (context) => const LoadingPage(),
LogPage.id: (context) => LogPage(),
AppsListPage.id: (context) => const AppsListPage(),
SettingsPage.id: (conext) => SettingsPage(),
},
home: const LoadingPage(),
);
},
),
);
}
}
2 changes: 1 addition & 1 deletion lib/apps_list/cubit/apps_list_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import 'package:freezed_annotation/freezed_annotation.dart';
import '../../../settings/cubit/settings_cubit.dart';
import '../../active_window/active_window.dart';
import '../../app_version/app_version.dart';
import '../../hotkey/hotkey_service.dart';
import '../../hotkey/global/hotkey_service.dart';
import '../../logs/logs.dart';
import '../../native_platform/native_platform.dart';
import '../../storage/storage_repository.dart';
Expand Down
1 change: 1 addition & 0 deletions lib/hotkey/global/global.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export 'hotkey_service.dart';
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import 'dart:async';

import 'package:hotkey_manager/hotkey_manager.dart';

import '../logs/logs.dart';
import '../../logs/logs.dart';

/// The default hotkey to use if none is set.
final HotKey defaultHotkey = HotKey(KeyCode.pause);

/// Handles global (system-wide) hotkeys.
class HotkeyService {
/// Stream that fires when a hotkey is triggered.
///
Expand Down
2 changes: 2 additions & 0 deletions lib/hotkey/hotkey.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export 'global/global.dart';
export 'in_app/in_app.dart';
57 changes: 57 additions & 0 deletions lib/hotkey/in_app/app_shortcuts.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';

import '../../logs/logging_manager.dart';
import 'shortcuts_manager.dart';

/// Shortcuts that are available everywhere in the app.
///
/// This widget is to be wrapped around the widget intended as a route,
/// or the entire MaterialApp.
class AppShortcuts extends StatelessWidget {
final Widget child;

AppShortcuts({
super.key,
required this.child,
});

final _shortcuts = <ShortcutActivator, Intent>{
const SingleActivator(
LogicalKeyboardKey.keyQ,
control: true,
): const QuitIntent(),
};

final _actions = <Type, Action<Intent>>{
QuitIntent: QuitAction(),
};

@override
Widget build(BuildContext context) {
return Shortcuts.manager(
manager: LoggingShortcutManager(shortcuts: _shortcuts),
child: Actions(
dispatcher: LoggingActionDispatcher(),
actions: _actions,
child: child,
),
);
}
}

/// An intent that is bound to QuitAction in order to quit this application.
class QuitIntent extends Intent {
const QuitIntent();
}

/// An action that is bound to QuitIntent in order to quit this application.
class QuitAction extends Action<QuitIntent> {
@override
Object? invoke(QuitIntent intent) {
log.i('Quit requested, exiting.');
exit(0);
}
}
2 changes: 2 additions & 0 deletions lib/hotkey/in_app/in_app.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export 'app_shortcuts.dart';
export 'shortcuts_manager.dart';
42 changes: 42 additions & 0 deletions lib/hotkey/in_app/shortcuts_manager.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import 'package:flutter/material.dart';

import '../../logs/logging_manager.dart';

/// A ShortcutManager that logs all keys that it handles.
class LoggingShortcutManager extends ShortcutManager {
LoggingShortcutManager({required super.shortcuts});

@override
KeyEventResult handleKeypress(BuildContext context, RawKeyEvent event) {
final KeyEventResult result = super.handleKeypress(context, event);

if (result == KeyEventResult.handled) {
log.i('''Handled shortcut
Shortcut: $event
Context: $context
''');
}

return result;
}
}

/// An ActionDispatcher that logs all the actions that it invokes.
class LoggingActionDispatcher extends ActionDispatcher {
@override
Object? invokeAction(
covariant Action<Intent> action,
covariant Intent intent, [
BuildContext? context,
]) {
log.i('''
Action invoked:
Action: $action($intent)
From: $context
''');

super.invokeAction(action, intent, context);

return null;
}
}
2 changes: 1 addition & 1 deletion lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import 'app_version/app_version.dart';
import 'apps_list/apps_list.dart';
import 'argument_parser/argument_parser.dart';
import 'autostart/autostart_service.dart';
import 'hotkey/hotkey_service.dart';
import 'hotkey/global/hotkey_service.dart';
import 'logs/logs.dart';
import 'native_platform/native_platform.dart';
import 'settings/cubit/settings_cubit.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/settings/cubit/settings_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import 'package:hotkey_manager/hotkey_manager.dart';

import '../../autostart/autostart_service.dart';
import '../../core/core.dart';
import '../../hotkey/hotkey_service.dart';
import '../../hotkey/global/hotkey_service.dart';
import '../../logs/logging_manager.dart';
import '../../storage/storage_repository.dart';

Expand Down
2 changes: 1 addition & 1 deletion lib/settings/widgets/integration_section.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:hotkey_manager/hotkey_manager.dart';

import '../../apps_list/apps_list.dart';
import '../../hotkey/hotkey_service.dart';
import '../../hotkey/global/hotkey_service.dart';
import '../../theme/styles.dart';
import '../settings.dart';

Expand Down
2 changes: 1 addition & 1 deletion test/apps_list/cubit/apps_list_cubit_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:nyrna/app_version/app_version.dart';
import 'package:nyrna/apps_list/apps_list.dart';
import 'package:nyrna/hotkey/hotkey_service.dart';
import 'package:nyrna/hotkey/global/hotkey_service.dart';
import 'package:nyrna/logs/logs.dart';
import 'package:nyrna/native_platform/native_platform.dart';
import 'package:nyrna/settings/settings.dart';
Expand Down
2 changes: 1 addition & 1 deletion test/apps_list/widgets/window_tile_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:nyrna/app_version/app_version.dart';
import 'package:nyrna/apps_list/apps_list.dart';
import 'package:nyrna/hotkey/hotkey_service.dart';
import 'package:nyrna/hotkey/global/hotkey_service.dart';
import 'package:nyrna/native_platform/native_platform.dart';
import 'package:nyrna/settings/settings.dart';
import 'package:nyrna/storage/storage_repository.dart';
Expand Down
2 changes: 1 addition & 1 deletion test/settings/cubit/settings_cubit_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import 'package:mockito/annotations.dart';
import 'package:mockito/mockito.dart';
import 'package:nyrna/apps_list/cubit/apps_list_cubit.dart';
import 'package:nyrna/autostart/autostart_service.dart';
import 'package:nyrna/hotkey/hotkey_service.dart';
import 'package:nyrna/hotkey/global/hotkey_service.dart';
import 'package:nyrna/settings/settings.dart';
import 'package:nyrna/storage/storage_repository.dart';
import 'package:nyrna/window/app_window.dart';
Expand Down

0 comments on commit 53381a6

Please sign in to comment.