diff --git a/src/apps/SettingsWindow/Resources/Assets.xcassets/notification-window.imageset/Contents.json b/src/apps/SettingsWindow/Resources/Assets.xcassets/notification-window.imageset/Contents.json new file mode 100644 index 000000000..e054ed80a --- /dev/null +++ b/src/apps/SettingsWindow/Resources/Assets.xcassets/notification-window.imageset/Contents.json @@ -0,0 +1,12 @@ +{ + "images" : [ + { + "filename" : "notification-window.png", + "idiom" : "universal" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/src/apps/SettingsWindow/Resources/Assets.xcassets/notification-window.imageset/notification-window.png b/src/apps/SettingsWindow/Resources/Assets.xcassets/notification-window.imageset/notification-window.png new file mode 100644 index 000000000..e36b9aa29 Binary files /dev/null and b/src/apps/SettingsWindow/Resources/Assets.xcassets/notification-window.imageset/notification-window.png differ diff --git a/src/apps/SettingsWindow/src/View/ContentMainView.swift b/src/apps/SettingsWindow/src/View/ContentMainView.swift index e3d37431e..4bf140eea 100644 --- a/src/apps/SettingsWindow/src/View/ContentMainView.swift +++ b/src/apps/SettingsWindow/src/View/ContentMainView.swift @@ -8,7 +8,8 @@ enum NavigationTag: String { case devices case virtualKeyboard case profiles - case ui + case ui1 + case ui2 case update case misc case uninstall @@ -141,14 +142,25 @@ struct ContentMainView: View { Button( action: { - contentViewStates.navigationSelection = .ui + contentViewStates.navigationSelection = .ui1 }, label: { - SidebarLabelView(text: "UI", systemImage: "switch.2", padding: 2.0) + SidebarLabelView(text: "UI #1", systemImage: "switch.2", padding: 2.0) } ) .sidebarButtonStyle( - selected: contentViewStates.navigationSelection == .ui) + selected: contentViewStates.navigationSelection == .ui1) + + Button( + action: { + contentViewStates.navigationSelection = .ui2 + }, + label: { + SidebarLabelView(text: "UI #2", systemImage: "switch.2", padding: 2.0) + } + ) + .sidebarButtonStyle( + selected: contentViewStates.navigationSelection == .ui2) } Divider() @@ -261,8 +273,10 @@ struct ContentMainView: View { VirtualKeyboardView() case .profiles: ProfilesView() - case .ui: - UIView() + case .ui1: + UI1View() + case .ui2: + UI2View() case .update: UpdateView() case .misc: diff --git a/src/apps/SettingsWindow/src/View/UI1View.swift b/src/apps/SettingsWindow/src/View/UI1View.swift new file mode 100644 index 000000000..0dd96bcdf --- /dev/null +++ b/src/apps/SettingsWindow/src/View/UI1View.swift @@ -0,0 +1,98 @@ +import SwiftUI + +struct UI1View: View { + @ObservedObject private var settings = LibKrbn.Settings.shared + + var body: some View { + VStack(alignment: .leading, spacing: 24.0) { + GroupBox(label: Text("Menu bar")) { + VStack(alignment: .leading, spacing: 12.0) { + HStack { + Toggle(isOn: $settings.showIconInMenuBar) { + Text("Show icon in menu bar (Default: on)") + } + .switchToggleStyle() + + Spacer() + } + + HStack { + Toggle(isOn: $settings.showProfileNameInMenuBar) { + Text("Show profile name in menu bar (Default: off)") + } + .switchToggleStyle() + + Spacer() + } + + HStack { + Toggle(isOn: $settings.askForConfirmationBeforeQuitting) { + Text("Ask for confirmation when quitting (Default: on)") + } + .switchToggleStyle() + + Spacer() + } + + } + .padding(6.0) + } + + GroupBox(label: Text("Karabiner Notification Window")) { + VStack(alignment: .leading, spacing: 12.0) { + HStack { + Toggle(isOn: $settings.enableNotificationWindow) { + Text("Enable Karabiner Notification Window (Default: on)") + } + .switchToggleStyle() + + Spacer() + } + + HStack { + Toggle(isOn: $settings.virtualHIDKeyboardIndicateStickyModifierKeysState) { + Text("Indicate sticky modifier keys state (Default: on)") + } + .switchToggleStyle() + + Spacer() + } + + VStack(alignment: .leading, spacing: 12.0) { + Label( + "What is the Karabiner Notification Window?", + systemImage: "lightbulb" + ) + VStack(alignment: .leading, spacing: 0.0) { + Text( + "Karabiner Notification Window is a window that displays messages, located at the bottom right of the screen. " + ) + Text( + "It is used for temporary alerts, displaying the status of sticky modifiers, and showing messages for some complex modifications." + ) + } + + Image(decorative: "notification-window") + .resizable() + .aspectRatio(contentMode: .fit) + .frame(height: 150) + + } + .padding() + .foregroundColor(Color.warningForeground) + .background(Color.warningBackground) + } + .padding(6.0) + } + + Spacer() + } + .padding() + } +} + +struct UI1View_Previews: PreviewProvider { + static var previews: some View { + UI1View() + } +} diff --git a/src/apps/SettingsWindow/src/View/UIView.swift b/src/apps/SettingsWindow/src/View/UI2View.swift similarity index 60% rename from src/apps/SettingsWindow/src/View/UIView.swift rename to src/apps/SettingsWindow/src/View/UI2View.swift index 8725e78ef..22330cc84 100644 --- a/src/apps/SettingsWindow/src/View/UIView.swift +++ b/src/apps/SettingsWindow/src/View/UI2View.swift @@ -1,58 +1,10 @@ import SwiftUI -struct UIView: View { +struct UI2View: View { @ObservedObject private var appIcons = AppIcons.shared - @ObservedObject private var settings = LibKrbn.Settings.shared var body: some View { VStack(alignment: .leading, spacing: 24.0) { - GroupBox(label: Text("Menu bar")) { - VStack(alignment: .leading, spacing: 12.0) { - HStack { - Toggle(isOn: $settings.showIconInMenuBar) { - Text("Show icon in menu bar (Default: on)") - } - .switchToggleStyle() - - Spacer() - } - - HStack { - Toggle(isOn: $settings.showProfileNameInMenuBar) { - Text("Show profile name in menu bar (Default: off)") - } - .switchToggleStyle() - - Spacer() - } - - HStack { - Toggle(isOn: $settings.askForConfirmationBeforeQuitting) { - Text("Ask for confirmation when quitting (Default: on)") - } - .switchToggleStyle() - - Spacer() - } - - } - .padding(6.0) - } - - GroupBox(label: Text("Sticky modifier keys")) { - VStack(alignment: .leading, spacing: 12.0) { - HStack { - Toggle(isOn: $settings.virtualHIDKeyboardIndicateStickyModifierKeysState) { - Text("Indicate sticky modifier keys state (Default: on)") - } - .switchToggleStyle() - - Spacer() - } - } - .padding(6.0) - } - GroupBox(label: Text("App icon")) { VStack(alignment: .leading, spacing: 12.0) { VStack { @@ -113,8 +65,8 @@ struct UIView: View { } } -struct UIView_Previews: PreviewProvider { +struct UI2View_Previews: PreviewProvider { static var previews: some View { - UIView() + UI2View() } } diff --git a/src/apps/share/swift/LibKrbn/Settings.swift b/src/apps/share/swift/LibKrbn/Settings.swift index b3638e0ba..3486b438a 100644 --- a/src/apps/share/swift/LibKrbn/Settings.swift +++ b/src/apps/share/swift/LibKrbn/Settings.swift @@ -119,6 +119,8 @@ extension LibKrbn { showIconInMenuBar = libkrbn_core_configuration_get_global_configuration_show_in_menu_bar() showProfileNameInMenuBar = libkrbn_core_configuration_get_global_configuration_show_profile_name_in_menu_bar() + enableNotificationWindow = + libkrbn_core_configuration_get_global_configuration_enable_notification_window() askForConfirmationBeforeQuitting = libkrbn_core_configuration_get_global_configuration_ask_for_confirmation_before_quitting() unsafeUI = libkrbn_core_configuration_get_global_configuration_unsafe_ui() @@ -649,6 +651,17 @@ extension LibKrbn { } } + @Published var enableNotificationWindow: Bool = false { + didSet { + if didSetEnabled { + libkrbn_core_configuration_set_global_configuration_enable_notification_window( + enableNotificationWindow + ) + save() + } + } + } + @Published var askForConfirmationBeforeQuitting: Bool = false { didSet { if didSetEnabled { diff --git a/src/core/console_user_server/include/console_user_server/components_manager.hpp b/src/core/console_user_server/include/console_user_server/components_manager.hpp index 7ce1bafd9..5d153a07c 100644 --- a/src/core/console_user_server/include/console_user_server/components_manager.hpp +++ b/src/core/console_user_server/include/console_user_server/components_manager.hpp @@ -209,15 +209,16 @@ class components_manager final : public pqrs::dispatcher::extra::dispatcher_clie void start_child_components(void) { configuration_monitor_ = std::make_shared(constants::get_user_core_configuration_file_path(), geteuid()); + configuration_monitor_->core_configuration_updated.connect([](auto&& weak_core_configuration) { + if (auto c = weak_core_configuration.lock()) { + launchctl_utility::manage_notification_window(c->get_global_configuration().get_enable_notification_window()); + } + }); // menu_process_manager_ menu_process_manager_ = std::make_unique(configuration_monitor_); - // Restart NotificationWindow - - launchctl_utility::restart_notification_window(); - // Run MultitouchExtension application_launcher::launch_multitouch_extension(true); diff --git a/src/lib/libkrbn/include/libkrbn/libkrbn.h b/src/lib/libkrbn/include/libkrbn/libkrbn.h index 1ed25de87..73cc18a77 100644 --- a/src/lib/libkrbn/include/libkrbn/libkrbn.h +++ b/src/lib/libkrbn/include/libkrbn/libkrbn.h @@ -83,6 +83,8 @@ bool libkrbn_core_configuration_get_global_configuration_show_in_menu_bar(void); void libkrbn_core_configuration_set_global_configuration_show_in_menu_bar(bool value); bool libkrbn_core_configuration_get_global_configuration_show_profile_name_in_menu_bar(void); void libkrbn_core_configuration_set_global_configuration_show_profile_name_in_menu_bar(bool value); +bool libkrbn_core_configuration_get_global_configuration_enable_notification_window(void); +void libkrbn_core_configuration_set_global_configuration_enable_notification_window(bool value); bool libkrbn_core_configuration_get_global_configuration_ask_for_confirmation_before_quitting(void); void libkrbn_core_configuration_set_global_configuration_ask_for_confirmation_before_quitting(bool value); bool libkrbn_core_configuration_get_global_configuration_unsafe_ui(void); diff --git a/src/lib/libkrbn/src/libkrbn_configuration.cpp b/src/lib/libkrbn/src/libkrbn_configuration.cpp index aa37ee08b..cfc0a4fd1 100644 --- a/src/lib/libkrbn/src/libkrbn_configuration.cpp +++ b/src/lib/libkrbn/src/libkrbn_configuration.cpp @@ -98,6 +98,19 @@ void libkrbn_core_configuration_set_global_configuration_show_profile_name_in_me } } +bool libkrbn_core_configuration_get_global_configuration_enable_notification_window(void) { + if (auto c = get_current_core_configuration()) { + return c->get_global_configuration().get_enable_notification_window(); + } + return false; +} + +void libkrbn_core_configuration_set_global_configuration_enable_notification_window(bool value) { + if (auto c = get_current_core_configuration()) { + return c->get_global_configuration().set_enable_notification_window(value); + } +} + bool libkrbn_core_configuration_get_global_configuration_ask_for_confirmation_before_quitting(void) { if (auto c = get_current_core_configuration()) { return c->get_global_configuration().get_ask_for_confirmation_before_quitting(); diff --git a/src/share/core_configuration/details/global_configuration.hpp b/src/share/core_configuration/details/global_configuration.hpp index 7fcc7feb1..a5d93ae24 100644 --- a/src/share/core_configuration/details/global_configuration.hpp +++ b/src/share/core_configuration/details/global_configuration.hpp @@ -7,10 +7,13 @@ namespace core_configuration { namespace details { class global_configuration final { public: + static constexpr bool enable_notification_window_default_value = true; + global_configuration(const nlohmann::json& json) : json_(json), check_for_updates_on_startup_(true), show_in_menu_bar_(true), show_profile_name_in_menu_bar_(false), + enable_notification_window_(enable_notification_window_default_value), ask_for_confirmation_before_quitting(true), unsafe_ui_(false) { if (auto v = pqrs::json::find(json, "check_for_updates_on_startup")) { @@ -25,6 +28,10 @@ class global_configuration final { show_profile_name_in_menu_bar_ = *v; } + if (auto v = pqrs::json::find(json, "enable_notification_window")) { + enable_notification_window_ = *v; + } + if (auto v = pqrs::json::find(json, "ask_for_confirmation_before_quitting")) { ask_for_confirmation_before_quitting = *v; } @@ -39,6 +46,11 @@ class global_configuration final { j["check_for_updates_on_startup"] = check_for_updates_on_startup_; j["show_in_menu_bar"] = show_in_menu_bar_; j["show_profile_name_in_menu_bar"] = show_profile_name_in_menu_bar_; + + if (enable_notification_window_ != enable_notification_window_default_value) { + j["enable_notification_window"] = enable_notification_window_; + } + j["ask_for_confirmation_before_quitting"] = ask_for_confirmation_before_quitting; j["unsafe_ui"] = unsafe_ui_; return j; @@ -65,6 +77,13 @@ class global_configuration final { show_profile_name_in_menu_bar_ = value; } + bool get_enable_notification_window(void) const { + return enable_notification_window_; + } + void set_enable_notification_window(bool value) { + enable_notification_window_ = value; + } + bool get_ask_for_confirmation_before_quitting(void) const { return ask_for_confirmation_before_quitting; } @@ -84,6 +103,7 @@ class global_configuration final { bool check_for_updates_on_startup_; bool show_in_menu_bar_; bool show_profile_name_in_menu_bar_; + bool enable_notification_window_; bool ask_for_confirmation_before_quitting; bool unsafe_ui_; }; diff --git a/tests/src/core_configuration/src/global_configuration_test.hpp b/tests/src/core_configuration/src/global_configuration_test.hpp index 7f4a6088d..7e01d0743 100644 --- a/tests/src/core_configuration/src/global_configuration_test.hpp +++ b/tests/src/core_configuration/src/global_configuration_test.hpp @@ -13,6 +13,7 @@ void run_global_configuration_test(void) { expect(global_configuration.get_check_for_updates_on_startup() == true); expect(global_configuration.get_show_in_menu_bar() == true); expect(global_configuration.get_show_profile_name_in_menu_bar() == false); + expect(global_configuration.get_enable_notification_window() == true); expect(global_configuration.get_ask_for_confirmation_before_quitting() == true); expect(global_configuration.get_unsafe_ui() == false); } @@ -23,6 +24,7 @@ void run_global_configuration_test(void) { {"check_for_updates_on_startup", false}, {"show_in_menu_bar", false}, {"show_profile_name_in_menu_bar", true}, + {"enable_notification_window", false}, {"ask_for_confirmation_before_quitting", false}, {"unsafe_ui", true}, }; @@ -30,6 +32,7 @@ void run_global_configuration_test(void) { expect(global_configuration.get_check_for_updates_on_startup() == false); expect(global_configuration.get_show_in_menu_bar() == false); expect(global_configuration.get_show_profile_name_in_menu_bar() == true); + expect(global_configuration.get_enable_notification_window() == false); expect(global_configuration.get_ask_for_confirmation_before_quitting() == false); expect(global_configuration.get_unsafe_ui() == true); } @@ -40,12 +43,14 @@ void run_global_configuration_test(void) { {"check_for_updates_on_startup", nlohmann::json::array()}, {"show_in_menu_bar", 0}, {"show_profile_name_in_menu_bar", nlohmann::json::object()}, + {"enable_notification_window", nlohmann::json::object()}, {"unsafe_ui", false}, }; krbn::core_configuration::details::global_configuration global_configuration(json); expect(global_configuration.get_check_for_updates_on_startup() == true); expect(global_configuration.get_show_in_menu_bar() == true); expect(global_configuration.get_show_profile_name_in_menu_bar() == false); + expect(global_configuration.get_enable_notification_window() == true); expect(global_configuration.get_ask_for_confirmation_before_quitting() == true); expect(global_configuration.get_unsafe_ui() == false); }