Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

dev #109

Merged
merged 8 commits into from
Sep 23, 2024
Merged

dev #109

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 21 additions & 6 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:helpers/helpers.dart';
import 'package:http/http.dart' as http;

import 'src/app.dart';
import 'src/app/app.dart';
import 'src/dbus/dbus_interface.dart';
import 'src/emoji/cubit/emoji_cubit.dart';
import 'src/emoji/emoji_service.dart';
import 'src/helpers/helpers.dart';
Expand All @@ -26,6 +28,14 @@ import 'src/updates/updates.dart';
import 'src/window/app_window.dart';

void main(List<String> args) async {
GoogleFonts.config.allowRuntimeFetching = false;

// Add the Google Fonts license to the LicenseRegistry.
LicenseRegistry.addLicense(() async* {
final license = await rootBundle.loadString('fonts/OFL.txt');
yield LicenseEntryWithLineBreaks(['google_fonts'], license);
});

WidgetsFlutterBinding.ensureInitialized();

/// Initial configuration for the app locale.
Expand All @@ -36,9 +46,7 @@ void main(List<String> args) async {
const String.fromEnvironment('VERBOSE') == 'true';

await LoggingManager.initialize(verbose: verbose);
await closeExistingSessions();

GoogleFonts.config.allowRuntimeFetching = false;
await activateExistingSession();

// Initialize the storage service.
final storageService = StorageService();
Expand All @@ -54,7 +62,9 @@ void main(List<String> args) async {
// Initialize the settings service.
final settingsService = SettingsService(storageService);

final appWindow = await AppWindow.initialize();
final appWindow = AppWindow();
await appWindow.initialize();

final systemTray = await SystemTray.initialize(appWindow);

final appCubit = AppCubit(
Expand All @@ -74,13 +84,18 @@ void main(List<String> args) async {
);

// Initialize Visibility Shortcut (Depends on Settings Service)
if (platformIsLinuxX11() && appWindow != null) hotKeyService.initHotkeyRegistration(appWindow);
if (platformIsLinuxX11()) hotKeyService.initHotkeyRegistration(appWindow);

if (defaultTargetPlatform.isLinux) {
final dbusInterface = DBusInterface(appWindow);
await dbusInterface.initialize();
}

// Run the app and pass in the state controllers.
runApp(
MultiRepositoryProvider(
providers: [
if (appWindow != null) RepositoryProvider.value(value: appWindow),
RepositoryProvider.value(value: appWindow),
RepositoryProvider.value(value: settingsService),
],
child: MultiBlocProvider(
Expand Down
2 changes: 1 addition & 1 deletion lib/src/app/cubit/app_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ class AppCubit extends Cubit<AppState> {
if (closeToTray) {
return;
} else {
await _appWindow!.dispose();
_appWindow.dispose();
await hotKeyService.unregisterBindings();
exit(0);
}
Expand Down
8 changes: 8 additions & 0 deletions lib/src/dbus/codes.merritt.FeelingFinder.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
<node>
<interface name="codes.merritt.FeelingFinder">
<method name="toggleWindow">
<arg type="b" direction="out"/>
</method>
</interface>
</node>
74 changes: 74 additions & 0 deletions lib/src/dbus/dbus_interface.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import 'package:dbus/dbus.dart';

import '../core/core.dart';
import '../window/app_window.dart';

/// DBus interface that enables communication with the app via D-Bus.
class DBusInterface extends DBusObject {
final AppWindow _appWindow;

static const _dbusObjectPath = DBusObjectPath.unchecked('/');

DBusInterface(this._appWindow) : super(_dbusObjectPath);

Future<void> initialize() async {
final client = DBusClient.session();
await client.requestName(kPackageId, flags: {DBusRequestNameFlag.replaceExisting});
await client.registerObject(this);
}

/// Allows hiding, showing, and focusing the app window via D-Bus.
///
/// Allows commanding the window from the command line & Wayland (where global hotkeys are not yet
/// supported).
Future<DBusMethodResponse> _toggleWindow() async {
await _appWindow.toggleVisible();
return DBusMethodSuccessResponse([const DBusBoolean(true)]);
}

@override
List<DBusIntrospectInterface> introspect() {
return [
DBusIntrospectInterface('codes.merritt.FeelingFinder', methods: [
DBusIntrospectMethod(
'toggleWindow',
args: [DBusIntrospectArgument(DBusSignature('b'), DBusArgumentDirection.out)],
)
])
];
}

@override
Future<DBusMethodResponse> handleMethodCall(DBusMethodCall methodCall) async {
if (methodCall.interface == 'codes.merritt.FeelingFinder') {
if (methodCall.name == 'toggleWindow') {
if (methodCall.values.isNotEmpty) {
return DBusMethodErrorResponse.invalidArgs();
}
return _toggleWindow();
} else {
return DBusMethodErrorResponse.unknownMethod();
}
} else {
return DBusMethodErrorResponse.unknownInterface();
}
}

@override
Future<DBusMethodResponse> getProperty(String interface, String name) async {
if (interface == 'codes.merritt.FeelingFinder') {
return DBusMethodErrorResponse.unknownProperty();
} else {
return DBusMethodErrorResponse.unknownProperty();
}
}

@override
Future<DBusMethodResponse> setProperty(String interface, String name, DBusValue value) async {
if (interface == 'codes.merritt.FeelingFinder') {
return DBusMethodErrorResponse.unknownProperty();
} else {
return DBusMethodErrorResponse.unknownProperty();
}
}
}
2 changes: 1 addition & 1 deletion lib/src/emoji/cubit/emoji_cubit.dart
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ class EmojiCubit extends Cubit<EmojiState> {

if (shouldExitApp) {
log.i('Exiting app after copying emoji');
await LoggingManager.instance.close();
LoggingManager.instance.close();
await hotKeyService.unregisterBindings();
exit(0);
}
Expand Down
23 changes: 22 additions & 1 deletion lib/src/emoji/widgets/search_bar_widget.dart
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,29 @@ class _SearchBarWidgetState extends State<SearchBarWidget> {
),
],
searchController: searchController,
barHintText: 'Type to search',
barHintText: 'Search',
viewHintText: 'Search for emoji',
barTrailing: const [
// Hint that Ctrl + F can be used to search.
Text.rich(
TextSpan(
children: [
TextSpan(text: 'Ctrl'),
WidgetSpan(
child: Padding(
padding: EdgeInsets.symmetric(horizontal: 8.0),
child: Text('+'),
),
),
TextSpan(text: 'F'),
],
),
style: TextStyle(
fontSize: 18.0,
color: Colors.grey,
),
),
],
suggestionsBuilder: (context, controller) {
return [
BlocBuilder<EmojiCubit, EmojiState>(
Expand Down
43 changes: 43 additions & 0 deletions lib/src/helpers/activate_exiting_sessions.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import 'dart:io';

import 'package:dbus/dbus.dart';

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

/// If the app is already running, activate the existing session and exit this one.
Future<void> activateExistingSession() async {
if (Platform.isLinux) await _activateLinuxSession();
}

Future<void> _activateLinuxSession() async {
final client = DBusClient.session();
final object = DBusRemoteObject(
client,
name: kPackageId,
path: DBusObjectPath('/'),
);

try {
// Check if the D-Bus object exists.
// If it does, the app is already running.
await object.introspect();
} on Exception catch (e) {
log.t('App is not already running: $e');
return;
}

// If we've made it this far, the app is already running.
try {
// Toggle the window visibility for the existing session, then exit this one.
final response = await object.callMethod(
'codes.merritt.FeelingFinder',
'toggleWindow',
[],
);
log.i('Toggling window visibility for existing session: $response');
exit(0);
} on Exception catch (e) {
log.e('Failed to toggle window visibility for existing session: $e');
}
}
45 changes: 0 additions & 45 deletions lib/src/helpers/close_exiting_sessions.dart

This file was deleted.

2 changes: 1 addition & 1 deletion lib/src/helpers/helpers.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import 'dart:io' show Platform;

import 'package:flutter/foundation.dart' show kIsWeb;

export 'close_exiting_sessions.dart';
export 'activate_exiting_sessions.dart';

/// Convenience function to check if the app is running on a desktop computer.
///
Expand Down
8 changes: 7 additions & 1 deletion lib/src/localization/strings.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
"settings": {
"title": "Settings",
"closeToTray": "Close to system tray",
"copyCommand": "Copy command",
"theme": "Theme",
"systemTheme": "System",
"lightTheme": "Light",
Expand All @@ -30,9 +31,14 @@
"donate": "Donate",
"homepage": "Homepage",
"currentVersion": "Current version",
"shortcut": "Shortcut",
"shortcutExplanation": "A keyboard shortcut can be used to toggle the visibility of the app",
"builtInShortcut": "Built-in Shortcut",
"shortcutInstructionsHeader": "Manual Shortcut",
"shortcutInstructions": "Requires manual setup, but works on Wayland and is the most reliable.\n\n1. Open your system settings\n2. Go to Keyboard Shortcuts\n3. Add a new shortcut\n4. Set the command to:\n\n ```\ndbus-send --session --print-reply --dest=codes.merritt.FeelingFinder / codes.merritt.FeelingFinder.toggleWindow\n```\n5. Set the shortcut to your desired key combination",
"hotkeyToggle": "Toggle visibility with a keyboard shortcut",
"shortcutUsage": "Press {modifierKey} + {actionKey} to use the shortcut",
"startHiddenInTray": "Start hidden in system tray"
},
"searchHintText": "Type to search"
"searchHintText": "Search"
}
Loading
Loading