From 7295de0bde03789a75e00ae482ba7af1ac365a2c Mon Sep 17 00:00:00 2001 From: Keeyou Date: Mon, 19 Aug 2024 17:18:15 +0800 Subject: [PATCH] mac: add display realtime status (ui) Related: #1064. --- src/config/config.cpp | 8 ++ src/config/config_core.cpp | 4 + src/config/config_core.hpp | 5 + src/mac/Base.lproj/Main.storyboard | 160 +++++++++++++++++------------ src/mac/YassAppDelegate.h | 5 +- src/mac/YassAppDelegate.mm | 23 ++--- src/mac/YassViewController.h | 3 + src/mac/YassViewController.mm | 24 ++++- src/mac/YassWindowController.h | 7 +- src/mac/YassWindowController.mm | 46 +++++++-- src/mac/en.lproj/Main.strings | 4 + src/mac/zh-Hans.lproj/Main.strings | 4 + 12 files changed, 197 insertions(+), 96 deletions(-) diff --git a/src/config/config.cpp b/src/config/config.cpp index 3d79a26c2..ffb40728c 100644 --- a/src/config/config.cpp +++ b/src/config/config.cpp @@ -77,6 +77,10 @@ bool ReadConfig() { } config_impl->Read("tls13_early_data", &FLAGS_tls13_early_data); +#if BUILDFLAG(IS_MAC) + config_impl->Read("ui_display_realtime_status", &FLAGS_ui_display_realtime_status); +#endif + /* close fields */ config_impl->Close(); @@ -145,6 +149,10 @@ bool SaveConfig() { } all_fields_written &= config_impl->Write("tls13_early_data", FLAGS_tls13_early_data); +#if BUILDFLAG(IS_MAC) + all_fields_written &= config_impl->Write("ui_display_realtime_status", FLAGS_ui_display_realtime_status); +#endif + all_fields_written &= config_impl->Close(); return all_fields_written; diff --git a/src/config/config_core.cpp b/src/config/config_core.cpp index ef9562917..06bf2e0ee 100644 --- a/src/config/config_core.cpp +++ b/src/config/config_core.cpp @@ -148,3 +148,7 @@ ABSL_FLAG(CipherMethodFlag, method, CipherMethodFlag(CRYPTO_DEFAULT), kCipherMet ABSL_FLAG(uint32_t, parallel_max, 512, "Maximum concurrency for parallel connections"); ABSL_FLAG(RateFlag, limit_rate, RateFlag(0), "Limit transfer speed to RATE"); + +#if BUILDFLAG(IS_MAC) +ABSL_FLAG(bool, ui_display_realtime_status, true, "Display Realtime Status in Status Bar (UI)"); +#endif diff --git a/src/config/config_core.hpp b/src/config/config_core.hpp index 0f4ceb181..b2fd525c5 100644 --- a/src/config/config_core.hpp +++ b/src/config/config_core.hpp @@ -6,6 +6,7 @@ #include #include +#include #include #include #include @@ -36,4 +37,8 @@ bool AbslParseFlag(absl::string_view text, RateFlag* flag, std::string* err); std::string AbslUnparseFlag(const RateFlag&); +#if BUILDFLAG(IS_MAC) +ABSL_DECLARE_FLAG(bool, ui_display_realtime_status); +#endif + #endif // H_CONFIG_CONFIG_CORE diff --git a/src/mac/Base.lproj/Main.storyboard b/src/mac/Base.lproj/Main.storyboard index 8cea59964..5bac7f6cf 100644 --- a/src/mac/Base.lproj/Main.storyboard +++ b/src/mac/Base.lproj/Main.storyboard @@ -75,11 +75,11 @@ - + - + @@ -88,6 +88,7 @@ + @@ -109,6 +110,7 @@ + @@ -118,8 +120,8 @@ - - + + @@ -128,8 +130,8 @@ - - + + @@ -139,8 +141,8 @@ - - + + @@ -149,8 +151,8 @@ - - + + @@ -160,7 +162,7 @@ - - + + @@ -181,8 +183,8 @@ - - + + @@ -196,8 +198,8 @@ - - + + @@ -206,8 +208,8 @@ - - + + @@ -217,8 +219,8 @@ - - + + @@ -227,8 +229,8 @@ - - + + @@ -241,8 +243,8 @@ - - + + @@ -251,8 +253,8 @@ - - + + @@ -265,8 +267,8 @@ - - + + @@ -275,8 +277,8 @@ - - + + @@ -286,7 +288,7 @@ - - + + @@ -307,8 +309,8 @@ - - + + @@ -322,8 +324,8 @@ - - + + @@ -332,8 +334,8 @@ - - + + @@ -343,8 +345,8 @@ - - + + @@ -353,8 +355,8 @@ - - + + @@ -364,8 +366,8 @@ - - + + @@ -374,8 +376,8 @@ - - + + @@ -385,8 +387,8 @@ - - + + @@ -395,8 +397,8 @@ - - + + @@ -409,8 +411,8 @@ - - + + @@ -420,7 +422,7 @@ + + + + + + + + + + + + + + @@ -466,6 +491,7 @@ + @@ -484,7 +510,7 @@ - + @@ -515,7 +541,7 @@ - + @@ -534,7 +560,7 @@ - + @@ -544,7 +570,7 @@ - + @@ -555,7 +581,7 @@ - + @@ -565,7 +591,7 @@ - + @@ -576,7 +602,7 @@ - + @@ -586,7 +612,7 @@ - + @@ -597,7 +623,7 @@ - + diff --git a/src/mac/YassAppDelegate.h b/src/mac/YassAppDelegate.h index 5e6e03e36..089badd7e 100644 --- a/src/mac/YassAppDelegate.h +++ b/src/mac/YassAppDelegate.h @@ -8,12 +8,11 @@ enum YASSState { STOPPED, STARTED, STARTING, START_FAILED, STOPPING }; -@class YassViewController; @interface YassAppDelegate : NSObject - (enum YASSState)getState; - (NSString*)getStatus; -- (void)OnStart:(YassViewController*)viewController; -- (void)OnStop:(YassViewController*)viewController withOption:(BOOL)quiet; +- (void)OnStart; +- (void)OnStop:(BOOL)quiet; @end diff --git a/src/mac/YassAppDelegate.mm b/src/mac/YassAppDelegate.mm index 3c0b75d35..60e8a716f 100644 --- a/src/mac/YassAppDelegate.mm +++ b/src/mac/YassAppDelegate.mm @@ -22,7 +22,7 @@ #include "version.h" @interface YassAppDelegate () -- (std::string)SaveConfig:(YassViewController*)viewController; +- (std::string)SaveConfig; - (void)OnStarted; - (void)OnStartFailed:(std::string)error_msg; - (void)OnStopped; @@ -44,7 +44,7 @@ - (void)applicationDidFinishLaunching:(NSNotification*)aNotification { - (void)applicationWillTerminate:(NSNotification*)aNotification { LOG(WARNING) << "Application exiting"; - [self OnStop:nil withOption:TRUE]; + [self OnStop:TRUE]; } - (BOOL)applicationSupportsSecureRestorableState:(NSApplication*)app { @@ -116,9 +116,9 @@ - (NSString*)getStatus { return SysUTF8ToNSString(ss.str()); } -- (void)OnStart:(YassViewController*)viewController { +- (void)OnStart { state_ = STARTING; - auto err_msg = [self SaveConfig:viewController]; + auto err_msg = [self SaveConfig]; if (!err_msg.empty()) { [self OnStartFailed:err_msg]; return; @@ -147,7 +147,7 @@ - (void)OnStart:(YassViewController*)viewController { worker_.Start(std::move(callback)); } -- (void)OnStop:(YassViewController*)viewController withOption:(BOOL)quiet { +- (void)OnStop:(BOOL)quiet { state_ = STOPPING; absl::AnyInvocable callback; @@ -165,8 +165,7 @@ - (void)OnStarted { state_ = STARTED; config::SaveConfig(); - YassWindowController* windowController = - (YassWindowController*)NSApplication.sharedApplication.mainWindow.windowController; + YassWindowController* windowController = [YassWindowController instance]; [windowController Started]; } @@ -174,8 +173,7 @@ - (void)OnStartFailed:(std::string)error_msg { state_ = START_FAILED; error_msg_ = error_msg; - YassWindowController* windowController = - (YassWindowController*)NSApplication.sharedApplication.mainWindow.windowController; + YassWindowController* windowController = [YassWindowController instance]; [windowController StartFailed]; NSAlert* alert = [[NSAlert alloc] init]; alert.messageText = @(error_msg.c_str()); @@ -186,12 +184,13 @@ - (void)OnStartFailed:(std::string)error_msg { - (void)OnStopped { state_ = STOPPED; - YassWindowController* windowController = - (YassWindowController*)NSApplication.sharedApplication.mainWindow.windowController; + YassWindowController* windowController = [YassWindowController instance]; [windowController Stopped]; } -- (std::string)SaveConfig:(YassViewController*)viewController { +- (std::string)SaveConfig { + YassViewController* viewController = [YassViewController instance]; + auto server_host = SysNSStringToUTF8(viewController.serverHost.stringValue); auto server_sni = SysNSStringToUTF8(viewController.serverSNI.stringValue); auto server_port = SysNSStringToUTF8(viewController.serverPort.stringValue); diff --git a/src/mac/YassViewController.h b/src/mac/YassViewController.h index 2aba62d83..0d8c67994 100644 --- a/src/mac/YassViewController.h +++ b/src/mac/YassViewController.h @@ -28,6 +28,9 @@ @property(weak) IBOutlet NSTextField* timeout; @property(weak) IBOutlet NSButton* autoStart; @property(weak) IBOutlet NSButton* systemProxy; +@property(weak) IBOutlet NSButton* displayStatus; + ++ (YassViewController* __weak)instance; @end #endif // YASS_MAC_VIEW_CONTROLLER diff --git a/src/mac/YassViewController.mm b/src/mac/YassViewController.mm index 244455c0e..3dd6b4e29 100644 --- a/src/mac/YassViewController.mm +++ b/src/mac/YassViewController.mm @@ -17,6 +17,8 @@ #include "mac/YassWindowController.h" #include "mac/utils.h" +static YassViewController* __weak _instance; + @interface YassViewController () @end @@ -24,8 +26,13 @@ @implementation YassViewController { bool should_startup_at_app_load; } ++ (YassViewController* __weak)instance { + return _instance; +} + - (void)viewDidLoad { [super viewDidLoad]; + _instance = self; [self.cipherMethod removeAllItems]; NSString* methodStrings[] = { @@ -101,6 +108,12 @@ - (IBAction)OnSystemProxyChecked:(id)sender { }); } +- (IBAction)OnDisplayStatusClicked:(id)sender { + YassWindowController* windowController = [YassWindowController instance]; + bool enable = self.displayStatus.state == NSControlStateValueOn; + [windowController toggleDisplayStatus:enable]; +} + - (void)OnStart { [self.startButton setEnabled:FALSE]; [self.stopButton setEnabled:FALSE]; @@ -118,16 +131,16 @@ - (void)OnStart { [self.limitRate setEnabled:FALSE]; [self.timeout setEnabled:FALSE]; - YassWindowController* windowController = (YassWindowController*)self.view.window.windowController; - [windowController OnStart:self]; + YassWindowController* windowController = [YassWindowController instance]; + [windowController OnStart]; } - (void)OnStop { [self.startButton setEnabled:FALSE]; [self.stopButton setEnabled:FALSE]; - YassWindowController* windowController = (YassWindowController*)self.view.window.windowController; - [windowController OnStop:self]; + YassWindowController* windowController = [YassWindowController instance]; + [windowController OnStop]; } - (void)Started { @@ -184,6 +197,9 @@ - (void)LoadChanges { self.dotHost.stringValue = SysUTF8ToNSString(absl::GetFlag(FLAGS_dot_host)); self.limitRate.stringValue = SysUTF8ToNSString(std::string(absl::GetFlag(FLAGS_limit_rate))); self.timeout.intValue = absl::GetFlag(FLAGS_connect_timeout); + + BOOL enable_status_bar = absl::GetFlag(FLAGS_ui_display_realtime_status) ? TRUE : FALSE; + self.displayStatus.state = enable_status_bar ? NSControlStateValueOn : NSControlStateValueOff; } @end diff --git a/src/mac/YassWindowController.h b/src/mac/YassWindowController.h index 598604a8f..9ed5f4e8b 100644 --- a/src/mac/YassWindowController.h +++ b/src/mac/YassWindowController.h @@ -8,11 +8,14 @@ @class YassViewController; @interface YassWindowController : NSWindowController -- (void)OnStart:(YassViewController*)viewController; -- (void)OnStop:(YassViewController*)viewController; +- (void)OnStart; +- (void)OnStop; - (void)Started; - (void)StartFailed; - (void)Stopped; +- (void)toggleDisplayStatus:(BOOL)enable; + ++ (YassWindowController* __weak)instance; @end #endif // YASS_MAC_WINDOW_CONTROLLER diff --git a/src/mac/YassWindowController.mm b/src/mac/YassWindowController.mm index 15625572e..d7e093f6e 100644 --- a/src/mac/YassWindowController.mm +++ b/src/mac/YassWindowController.mm @@ -17,7 +17,10 @@ #import "mac/YassViewController.h" #include "mac/utils.h" +static YassWindowController* __weak _instance; + @interface YassWindowController () +- (void)toggleDisplayStatusInternal:(BOOL)enable; @end @implementation YassWindowController { @@ -33,8 +36,14 @@ @implementation YassWindowController { BOOL hide_on_closed_; } ++ (YassWindowController* __weak)instance { + return _instance; +} + - (void)windowDidLoad { [super windowDidLoad]; + _instance = self; + [self refreshTimerExceeded]; y_status_bar_item_ = [[NSStatusBar systemStatusBar] statusItemWithLength:NSSquareStatusItemLength]; @@ -45,7 +54,8 @@ - (void)windowDidLoad { [y_status_bar_item_.button sendActionOn:NSEventMaskLeftMouseDown | NSEventMaskRightMouseDown | NSEventMaskOtherMouseDown]; - status_bar_item_ = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; + BOOL enable_status_bar = absl::GetFlag(FLAGS_ui_display_realtime_status) ? TRUE : FALSE; + [self toggleDisplayStatusInternal:enable_status_bar]; hide_on_closed_ = FALSE; } @@ -77,6 +87,10 @@ - (void)statusItemClicked { } - (void)UpdateStatusBar { + if (status_bar_item_ == nil) { + status_bar_text_ = nil; + return; + } NSString* next_status_bar_text = [self getStatusMessage]; // prevent deep copy on unchanged title if ([next_status_bar_text isEqualToString:status_bar_text_]) { @@ -131,33 +145,49 @@ - (void)refreshTimerExceeded { repeats:NO]; } -- (void)OnStart:(YassViewController*)viewController { +- (void)OnStart { YassAppDelegate* appDelegate = (YassAppDelegate*)NSApplication.sharedApplication.delegate; - [appDelegate OnStart:viewController]; + [appDelegate OnStart]; } -- (void)OnStop:(YassViewController*)viewController { +- (void)OnStop { YassAppDelegate* appDelegate = (YassAppDelegate*)NSApplication.sharedApplication.delegate; - [appDelegate OnStop:viewController withOption:FALSE]; + [appDelegate OnStop:FALSE]; } - (void)Started { [self UpdateStatusBar]; - YassViewController* viewController = (YassViewController*)self.contentViewController; + YassViewController* viewController = [YassViewController instance]; [viewController Started]; } - (void)StartFailed { [self UpdateStatusBar]; - YassViewController* viewController = (YassViewController*)self.contentViewController; + YassViewController* viewController = [YassViewController instance]; [viewController StartFailed]; } - (void)Stopped { [self UpdateStatusBar]; - YassViewController* viewController = (YassViewController*)self.contentViewController; + YassViewController* viewController = [YassViewController instance]; [viewController Stopped]; } +- (void)toggleDisplayStatus:(BOOL)enable { + [self toggleDisplayStatusInternal:enable]; + absl::SetFlag(&FLAGS_ui_display_realtime_status, (enable == TRUE ? true : false)); + config::SaveConfig(); +} + +- (void)toggleDisplayStatusInternal:(BOOL)enable { + if (enable && status_bar_item_ == nil) { + status_bar_item_ = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength]; + [self UpdateStatusBar]; + } else if (enable == FALSE && status_bar_item_ != nil) { + status_bar_item_ = nil; + status_bar_text_ = nil; + } +} + @end diff --git a/src/mac/en.lproj/Main.strings b/src/mac/en.lproj/Main.strings index 8f35c14ba..60a695fbb 100644 --- a/src/mac/en.lproj/Main.strings +++ b/src/mac/en.lproj/Main.strings @@ -102,3 +102,7 @@ "zY6-tD-aUd.title" = "Timeout"; "bxG-gg-LTc.title" = "Server SNI"; + +"mw5-nB-ary.title" = "Display Realtime Status"; + +"71A-aG-Rt6.title" = "Enable"; diff --git a/src/mac/zh-Hans.lproj/Main.strings b/src/mac/zh-Hans.lproj/Main.strings index f92f3ba9d..af113df37 100644 --- a/src/mac/zh-Hans.lproj/Main.strings +++ b/src/mac/zh-Hans.lproj/Main.strings @@ -102,3 +102,7 @@ "zY6-tD-aUd.title" = "超时时间"; "bxG-gg-LTc.title" = "服务器名称指示"; + +"mw5-nB-ary.title" = "显示实时状态"; + +"71A-aG-Rt6.title" = "启用";