From a1f87c0fb8f688e62ef5931b2e71a57e413400c1 Mon Sep 17 00:00:00 2001 From: Yanan Li <1474700628@qq.com> Date: Mon, 25 Nov 2024 19:49:31 +0800 Subject: [PATCH 1/5] add status bar icon visibility option --- .../LMPreferenceStatusBarViewController.m | 54 ++++++++++++++++--- .../Resources/Base.lproj/Localizable.strings | 1 + Lemon/Resources/en.lproj/Localizable.strings | 1 + .../zh-Hans.lproj/Localizable.strings | 1 + 4 files changed, 51 insertions(+), 6 deletions(-) diff --git a/Lemon/Preference/LMPreferenceStatusBarViewController.m b/Lemon/Preference/LMPreferenceStatusBarViewController.m index 576840dec..6345d3025 100644 --- a/Lemon/Preference/LMPreferenceStatusBarViewController.m +++ b/Lemon/Preference/LMPreferenceStatusBarViewController.m @@ -65,14 +65,42 @@ - (void)viewWillLayout{ } [LMAppThemeHelper setDivideLineColorFor:_bootMonitorLineView]; } --(void)initView{ - NSTextField *showStatusBarIconText = [self buildLabel:NSLocalizedStringFromTableInBundle(@"PreferenceViewController_setupViews_bootMonitorTitle _16", nil, [NSBundle bundleForClass:[self class]], @"") font:[NSFont systemFontOfSize:14] color:[LMAppThemeHelper getTitleColor]]; +-(void)initView { + NSTextField *showStatusBarIconText = [self buildLabel:NSLocalizedStringFromTableInBundle(@"PreferenceViewController_toggleStatusBarVisibility", nil, [NSBundle bundleForClass:[self class]], @"Toggle status bar visibility") font:[NSFont systemFontOfSize:14] color:[LMAppThemeHelper getTitleColor]]; + + __weak typeof(self) weakSelf = self; + // 状态栏显示设置 + COSwitch *statusBarVisibilitySwitch = [[COSwitch alloc] init]; + statusBarVisibilitySwitch.on = (_myStatusType & STATUS_TYPE_GLOBAL) > 0 ? YES : NO; + [statusBarVisibilitySwitch setOnValueChanged:^(COSwitch *button) { + dispatch_async(dispatch_get_main_queue(), ^{ + button.isEnable = NO; + NSLog(@"statusBarVisibilitySwitch setOnValueChanged: %d", button.on); + + if (button.on) { + NSLog(@"preference:global=%d", button.on); + + weakSelf.myStatusType |= STATUS_TYPE_GLOBAL; + [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithInteger:weakSelf.myStatusType] forKey:kLemonShowMonitorCfg]; + } else { + NSLog(@"preference:global=%d", button.on); + + weakSelf.myStatusType &= ~STATUS_TYPE_GLOBAL; + [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithInteger:weakSelf.myStatusType] forKey:kLemonShowMonitorCfg]; + } + + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ + button.isEnable = YES; + }); + }); + }]; + + NSTextField *showStatusBarIconOnBootText = [self buildLabel:NSLocalizedStringFromTableInBundle(@"PreferenceViewController_setupViews_bootMonitorTitle _16", nil, [NSBundle bundleForClass:[self class]], @"") font:[NSFont systemFontOfSize:14] color:[LMAppThemeHelper getTitleColor]]; // 状态栏开机启动项设置 _myStatusType = [[[NSUserDefaults standardUserDefaults] objectForKey:kLemonShowMonitorCfg] integerValue]; COSwitch *bootMonitorSwitch = [[COSwitch alloc] init]; bootMonitorSwitch.on = (_myStatusType & STATUS_TYPE_BOOTSHOW) > 0 ? YES : NO; - __weak typeof(self) weakSelf = self; [bootMonitorSwitch setOnValueChanged:^(COSwitch *button) { dispatch_async(dispatch_get_main_queue(), ^{ button.isEnable = NO; @@ -134,6 +162,8 @@ -(void)initView{ [self.view addSubview:showStatusBarIconText]; + [self.view addSubview:statusBarVisibilitySwitch]; + [self.view addSubview:showStatusBarIconOnBootText]; [self.view addSubview:bootMonitorSwitch]; [self.view addSubview:bootMonitorLineView]; @@ -151,21 +181,33 @@ -(void)initView{ NSView *cView = self.view; - // 状态栏自启设置 [showStatusBarIconText mas_makeConstraints:^(MASConstraintMaker *make) { make.top.equalTo(cView).offset(20); make.leading.equalTo(cView).offset(29); }]; - [bootMonitorSwitch mas_makeConstraints:^(MASConstraintMaker *make) { + [statusBarVisibilitySwitch mas_makeConstraints:^(MASConstraintMaker *make) { make.centerY.equalTo(showStatusBarIconText.mas_centerY); make.right.equalTo(cView).offset(-30); make.width.equalTo(@(40)); make.height.equalTo(@(19)); }]; + + // 状态栏自启设置 + [showStatusBarIconOnBootText mas_makeConstraints:^(MASConstraintMaker *make) { + make.top.equalTo(showStatusBarIconText.mas_bottom).offset(20); + make.leading.equalTo(cView).offset(29); + }]; + + [bootMonitorSwitch mas_makeConstraints:^(MASConstraintMaker *make) { + make.centerY.equalTo(showStatusBarIconOnBootText.mas_centerY); + make.right.equalTo(cView).offset(-30); + make.width.equalTo(@(40)); + make.height.equalTo(@(19)); + }]; [bootMonitorLineView mas_makeConstraints:^(MASConstraintMaker *make) { - make.top.equalTo(showStatusBarIconText.mas_bottom).offset(20); + make.top.equalTo(showStatusBarIconOnBootText.mas_bottom).offset(20); make.centerX.equalTo(cView); make.width.equalTo(cView); make.height.equalTo(@(1)); diff --git a/Lemon/Resources/Base.lproj/Localizable.strings b/Lemon/Resources/Base.lproj/Localizable.strings index d4bcd4ef3..b8f8844e3 100644 --- a/Lemon/Resources/Base.lproj/Localizable.strings +++ b/Lemon/Resources/Base.lproj/Localizable.strings @@ -26,6 +26,7 @@ "PreferenceViewController_setupViews_1553049563_14" = "Fan\n speed"; "PreferenceViewController_setupViews_1553049563_15" = "Network\n speed"; "PreferenceViewController_setupViews_bootMonitorTitle _16" = "Show icons on menu bar on startup"; +"PreferenceViewController_toggleStatusBarVisibility" = "Show status bar icons"; "About_windowAboutTitle_lemon" = "About Lemon Cleaner"; "Appdelegate_about_windowAboutTitle_lemonlite" = "About Lemon Cleaner"; "AppDelegate_fetchResearchChannel_notification_1" = "Close"; diff --git a/Lemon/Resources/en.lproj/Localizable.strings b/Lemon/Resources/en.lproj/Localizable.strings index 3348ea7eb..45e8c1345 100644 --- a/Lemon/Resources/en.lproj/Localizable.strings +++ b/Lemon/Resources/en.lproj/Localizable.strings @@ -28,6 +28,7 @@ "PreferenceViewController_setupViews_1553049563_16" = "CPU\n usage"; "PreferenceViewController_setupViews_1553049563_17" = "GPU\n usage"; "PreferenceViewController_setupViews_bootMonitorTitle _16" = "Show icons on menu bar on startup"; +"PreferenceViewController_toggleStatusBarVisibility" = "Show status bar icons"; "About_windowAboutTitle_lemon" = "About Lemon Cleaner"; "Appdelegate_about_windowAboutTitle_lemonlite" = "About Lemon Cleaner Lite"; "AppDelegate_fetchResearchChannel_notification_1" = "Close"; diff --git a/Lemon/Resources/zh-Hans.lproj/Localizable.strings b/Lemon/Resources/zh-Hans.lproj/Localizable.strings index c56fd212d..fc15a6d3b 100644 --- a/Lemon/Resources/zh-Hans.lproj/Localizable.strings +++ b/Lemon/Resources/zh-Hans.lproj/Localizable.strings @@ -28,6 +28,7 @@ "PreferenceViewController_setupViews_1553049563_16" = "CPU占用"; "PreferenceViewController_setupViews_1553049563_17" = "GPU占用"; "PreferenceViewController_setupViews_bootMonitorTitle _16" = "开机时显示状态栏图标"; +"PreferenceViewController_toggleStatusBarVisibility" = "显示状态栏图标"; "About_windowAboutTitle_lemon" = "关于腾讯柠檬清理"; "Appdelegate_about_windowAboutTitle_lemonlite" = "关于Lemon Cleaner Lite"; "AppDelegate_fetchResearchChannel_notification_1" = "关闭"; From 22fc53f0619d4ac4edfadda9cbec0f4c6d97593f Mon Sep 17 00:00:00 2001 From: Yanan Li <1474700628@qq.com> Date: Mon, 25 Nov 2024 20:04:13 +0800 Subject: [PATCH 2/5] update localizable --- Lemon/Resources/Base.lproj/Localizable.strings | 2 +- Lemon/Resources/en.lproj/Localizable.strings | 2 +- Lemon/Resources/zh-Hans.lproj/Localizable.strings | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Lemon/Resources/Base.lproj/Localizable.strings b/Lemon/Resources/Base.lproj/Localizable.strings index b8f8844e3..b9feb6b50 100644 --- a/Lemon/Resources/Base.lproj/Localizable.strings +++ b/Lemon/Resources/Base.lproj/Localizable.strings @@ -25,7 +25,7 @@ "PreferenceViewController_setupViews_1553049563_13" = "CPU\n temperature"; "PreferenceViewController_setupViews_1553049563_14" = "Fan\n speed"; "PreferenceViewController_setupViews_1553049563_15" = "Network\n speed"; -"PreferenceViewController_setupViews_bootMonitorTitle _16" = "Show icons on menu bar on startup"; +"PreferenceViewController_setupViews_bootMonitorTitle _16" = "Show on startup"; "PreferenceViewController_toggleStatusBarVisibility" = "Show status bar icons"; "About_windowAboutTitle_lemon" = "About Lemon Cleaner"; "Appdelegate_about_windowAboutTitle_lemonlite" = "About Lemon Cleaner"; diff --git a/Lemon/Resources/en.lproj/Localizable.strings b/Lemon/Resources/en.lproj/Localizable.strings index 45e8c1345..8156703bd 100644 --- a/Lemon/Resources/en.lproj/Localizable.strings +++ b/Lemon/Resources/en.lproj/Localizable.strings @@ -27,7 +27,7 @@ "PreferenceViewController_setupViews_1553049563_15" = "Network\n speed"; "PreferenceViewController_setupViews_1553049563_16" = "CPU\n usage"; "PreferenceViewController_setupViews_1553049563_17" = "GPU\n usage"; -"PreferenceViewController_setupViews_bootMonitorTitle _16" = "Show icons on menu bar on startup"; +"PreferenceViewController_setupViews_bootMonitorTitle _16" = "Show on startup"; "PreferenceViewController_toggleStatusBarVisibility" = "Show status bar icons"; "About_windowAboutTitle_lemon" = "About Lemon Cleaner"; "Appdelegate_about_windowAboutTitle_lemonlite" = "About Lemon Cleaner Lite"; diff --git a/Lemon/Resources/zh-Hans.lproj/Localizable.strings b/Lemon/Resources/zh-Hans.lproj/Localizable.strings index fc15a6d3b..5fd9f7570 100644 --- a/Lemon/Resources/zh-Hans.lproj/Localizable.strings +++ b/Lemon/Resources/zh-Hans.lproj/Localizable.strings @@ -27,7 +27,7 @@ "PreferenceViewController_setupViews_1553049563_15" = "网速"; "PreferenceViewController_setupViews_1553049563_16" = "CPU占用"; "PreferenceViewController_setupViews_1553049563_17" = "GPU占用"; -"PreferenceViewController_setupViews_bootMonitorTitle _16" = "开机时显示状态栏图标"; +"PreferenceViewController_setupViews_bootMonitorTitle _16" = "开机时显示"; "PreferenceViewController_toggleStatusBarVisibility" = "显示状态栏图标"; "About_windowAboutTitle_lemon" = "关于腾讯柠檬清理"; "Appdelegate_about_windowAboutTitle_lemonlite" = "关于Lemon Cleaner Lite"; From 8e2af86eeb514fe3d64810fc59f376e424e7c9e4 Mon Sep 17 00:00:00 2001 From: Yanan Li <1474700628@qq.com> Date: Mon, 25 Nov 2024 21:58:36 +0800 Subject: [PATCH 3/5] update monitor --- .../LemonMonitor/LemonMonitor/Monitor/LMMonitorController.m | 5 +++++ localPod/QMUICommon/QMUICommon/Classes/COSwitch.m | 3 +++ 2 files changed, 8 insertions(+) diff --git a/Tools/LemonMonitor/LemonMonitor/Monitor/LMMonitorController.m b/Tools/LemonMonitor/LemonMonitor/Monitor/LMMonitorController.m index bf6c77a19..291e57b6a 100644 --- a/Tools/LemonMonitor/LemonMonitor/Monitor/LMMonitorController.m +++ b/Tools/LemonMonitor/LemonMonitor/Monitor/LMMonitorController.m @@ -618,6 +618,11 @@ -(void)receivedStatusChanged:(NSNotification *)notification NSInteger type = 0; NSDictionary* dict = notification.userInfo; type = ((NSNumber*)dict[@"type"]).integerValue; + if ((type & STATUS_TYPE_GLOBAL) == 0) + { + [[NSApplication sharedApplication] terminate:nil]; + return; + } [statusView setStatusType:type]; [[McStatMonitor shareMonitor] setTrayType:type]; // NSLog(@"receivedStatusChanged type=%lu", type); diff --git a/localPod/QMUICommon/QMUICommon/Classes/COSwitch.m b/localPod/QMUICommon/QMUICommon/Classes/COSwitch.m index fc93f639d..26e5a4e2d 100755 --- a/localPod/QMUICommon/QMUICommon/Classes/COSwitch.m +++ b/localPod/QMUICommon/QMUICommon/Classes/COSwitch.m @@ -238,6 +238,9 @@ - (void)mouseDown:(NSEvent *)theEvent - (void)mouseEntered:(NSEvent *)theEvent { + if (!self.isEnable) { + return; + } if (self.isAnimator) { [NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) { context.duration = 0.1; From a8606fb9149ea087f39a7927ae9100de9e48a4ea Mon Sep 17 00:00:00 2001 From: Yanan Li <1474700628@qq.com> Date: Mon, 25 Nov 2024 21:58:53 +0800 Subject: [PATCH 4/5] notify monitor --- .../LMPreferenceStatusBarViewController.m | 69 +++++++++++++------ 1 file changed, 49 insertions(+), 20 deletions(-) diff --git a/Lemon/Preference/LMPreferenceStatusBarViewController.m b/Lemon/Preference/LMPreferenceStatusBarViewController.m index 6345d3025..1599be816 100644 --- a/Lemon/Preference/LMPreferenceStatusBarViewController.m +++ b/Lemon/Preference/LMPreferenceStatusBarViewController.m @@ -7,6 +7,7 @@ // #import "LMPreferenceStatusBarViewController.h" +#import "LemonDaemonConst.h" #import #import #import @@ -66,57 +67,76 @@ - (void)viewWillLayout{ [LMAppThemeHelper setDivideLineColorFor:_bootMonitorLineView]; } -(void)initView { - NSTextField *showStatusBarIconText = [self buildLabel:NSLocalizedStringFromTableInBundle(@"PreferenceViewController_toggleStatusBarVisibility", nil, [NSBundle bundleForClass:[self class]], @"Toggle status bar visibility") font:[NSFont systemFontOfSize:14] color:[LMAppThemeHelper getTitleColor]]; + NSTextField *showStatusBarIconOnBootText = [self buildLabel:NSLocalizedStringFromTableInBundle(@"PreferenceViewController_setupViews_bootMonitorTitle _16", nil, [NSBundle bundleForClass:[self class]], @"") font:[NSFont systemFontOfSize:14] color:[LMAppThemeHelper getTitleColor]]; + + // 状态栏开机启动项设置 + _myStatusType = [[[NSUserDefaults standardUserDefaults] objectForKey:kLemonShowMonitorCfg] integerValue]; __weak typeof(self) weakSelf = self; - // 状态栏显示设置 - COSwitch *statusBarVisibilitySwitch = [[COSwitch alloc] init]; - statusBarVisibilitySwitch.on = (_myStatusType & STATUS_TYPE_GLOBAL) > 0 ? YES : NO; - [statusBarVisibilitySwitch setOnValueChanged:^(COSwitch *button) { + COSwitch *bootMonitorSwitch = [[COSwitch alloc] init]; + bootMonitorSwitch.on = (_myStatusType & STATUS_TYPE_BOOTSHOW) > 0 ? YES : NO; + bootMonitorSwitch.wantsLayer = YES; + bootMonitorSwitch.isEnable = (_myStatusType & STATUS_TYPE_GLOBAL) > 0 ? YES : NO; + bootMonitorSwitch.layer.opacity = (_myStatusType & STATUS_TYPE_GLOBAL) > 0 ? 1 : 0.5; + [bootMonitorSwitch setOnValueChanged:^(COSwitch *button) { dispatch_async(dispatch_get_main_queue(), ^{ button.isEnable = NO; - NSLog(@"statusBarVisibilitySwitch setOnValueChanged: %d", button.on); + NSLog(@"monitorSwitch setOnValueChanged: %d", button.on); if (button.on) { NSLog(@"preference:global=%d", button.on); - weakSelf.myStatusType |= STATUS_TYPE_GLOBAL; + weakSelf.myStatusType |= STATUS_TYPE_BOOTSHOW; [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithInteger:weakSelf.myStatusType] forKey:kLemonShowMonitorCfg]; } else { NSLog(@"preference:global=%d", button.on); - - weakSelf.myStatusType &= ~STATUS_TYPE_GLOBAL; + + weakSelf.myStatusType &= ~STATUS_TYPE_BOOTSHOW; [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithInteger:weakSelf.myStatusType] forKey:kLemonShowMonitorCfg]; } - dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ button.isEnable = YES; }); }); }]; - NSTextField *showStatusBarIconOnBootText = [self buildLabel:NSLocalizedStringFromTableInBundle(@"PreferenceViewController_setupViews_bootMonitorTitle _16", nil, [NSBundle bundleForClass:[self class]], @"") font:[NSFont systemFontOfSize:14] color:[LMAppThemeHelper getTitleColor]]; - // 状态栏开机启动项设置 - _myStatusType = [[[NSUserDefaults standardUserDefaults] objectForKey:kLemonShowMonitorCfg] integerValue]; - COSwitch *bootMonitorSwitch = [[COSwitch alloc] init]; - bootMonitorSwitch.on = (_myStatusType & STATUS_TYPE_BOOTSHOW) > 0 ? YES : NO; - [bootMonitorSwitch setOnValueChanged:^(COSwitch *button) { + NSTextField *showStatusBarIconText = [self buildLabel:NSLocalizedStringFromTableInBundle(@"PreferenceViewController_toggleStatusBarVisibility", nil, [NSBundle bundleForClass:[self class]], @"Toggle status bar visibility") font:[NSFont systemFontOfSize:14] color:[LMAppThemeHelper getTitleColor]]; + + // 状态栏显示设置 + COSwitch *statusBarVisibilitySwitch = [[COSwitch alloc] init]; + statusBarVisibilitySwitch.on = (_myStatusType & STATUS_TYPE_GLOBAL) > 0 ? YES : NO; + [statusBarVisibilitySwitch setOnValueChanged:^(COSwitch *button) { dispatch_async(dispatch_get_main_queue(), ^{ button.isEnable = NO; - NSLog(@"monitorSwitch setOnValueChanged: %d", button.on); + NSLog(@"statusBarVisibilitySwitch setOnValueChanged: %d", button.on); if (button.on) { NSLog(@"preference:global=%d", button.on); - weakSelf.myStatusType |= STATUS_TYPE_BOOTSHOW; + weakSelf.myStatusType |= STATUS_TYPE_GLOBAL; [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithInteger:weakSelf.myStatusType] forKey:kLemonShowMonitorCfg]; + + [self openMonitor]; + + bootMonitorSwitch.isEnable = YES; + bootMonitorSwitch.layer.opacity = 1.0; } else { NSLog(@"preference:global=%d", button.on); - weakSelf.myStatusType &= ~STATUS_TYPE_BOOTSHOW; + weakSelf.myStatusType &= ~STATUS_TYPE_GLOBAL; [[NSUserDefaults standardUserDefaults] setObject:[NSNumber numberWithInteger:weakSelf.myStatusType] forKey:kLemonShowMonitorCfg]; + + // 去掉开机启动,并且设置为不可修改 + bootMonitorSwitch.on = NO; + bootMonitorSwitch.isEnable = NO; + bootMonitorSwitch.layer.opacity = 0.5; } + + // send to monitor process + NSDictionary* dict = @{@"type":[NSNumber numberWithInteger: [weakSelf myStatusType]]}; + [[NSDistributedNotificationCenter defaultCenter] postNotificationName:kStatusChangedNotification object:nil userInfo:dict deliverImmediately:YES]; + dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ button.isEnable = YES; }); @@ -126,7 +146,6 @@ -(void)initView { NSView* bootMonitorLineView = [[NSView alloc] init]; self.bootMonitorLineView = bootMonitorLineView; - // 状态栏图标显示 NSTextField *tfMonitorTitle = [self buildLabel:NSLocalizedStringFromTableInBundle(@"PreferenceViewController_setupViews_tfMonitorTitle _9", nil, [NSBundle bundleForClass:[self class]], @"") font:[NSFont systemFontOfSize:14] color:[LMAppThemeHelper getTitleColor]]; NSImageView *monitorImageView = [[NSImageView alloc] init]; @@ -298,6 +317,16 @@ -(void)initView { } +-(void)openMonitor{ + NSLog(@"%s, open monitor", __FUNCTION__); + NSError *error = NULL; + NSRunningApplication *app = [[NSWorkspace sharedWorkspace] launchApplicationAtURL:[NSURL fileURLWithPath:MONITOR_APP_PATH] + options:NSWorkspaceLaunchWithoutAddingToRecents | NSWorkspaceLaunchWithoutActivation + configuration:@{NSWorkspaceLaunchConfigurationArguments: @[[NSString stringWithFormat:@"%lu", LemonMonitorRunningMenu]]} + error:&error]; + NSLog(@"%s, open lemon monitor: %@, %@",__FUNCTION__, app, error); +} + -(NSView*)getOptionView:(NSString*)image :(NSString*)tittle :(NSInteger)type { // From 4da86497966906148f8eaa5d05b79c0731fc24d5 Mon Sep 17 00:00:00 2001 From: Yanan Li <1474700628@qq.com> Date: Tue, 26 Nov 2024 12:40:21 +0800 Subject: [PATCH 5/5] shutdown monitor at startup if user explicitly disable menubar icon --- .../LemonMonitor/Monitor/LMMonitorController.m | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/Tools/LemonMonitor/LemonMonitor/Monitor/LMMonitorController.m b/Tools/LemonMonitor/LemonMonitor/Monitor/LMMonitorController.m index 291e57b6a..47e1feb2b 100644 --- a/Tools/LemonMonitor/LemonMonitor/Monitor/LMMonitorController.m +++ b/Tools/LemonMonitor/LemonMonitor/Monitor/LMMonitorController.m @@ -106,6 +106,13 @@ - (id)init -(void)setupData { + NSNumber *type = [[NSUserDefaults standardUserDefaults] objectForKey:kLemonShowMonitorCfg]; + if (([type integerValue] & STATUS_TYPE_GLOBAL) == 0) { + // 直接关闭进程(如果用户关闭了显示状态栏的开关) + [[NSApplication sharedApplication] terminate:nil]; + return; + } + _upSpeedHistory = [[QMValueHistory alloc] initWithCapacity:32]; _downSpeedHistory = [[QMValueHistory alloc] initWithCapacity:32]; dataCenter = [QMDataCenter defaultCenter];