diff --git a/VoidLink/Images.xcassets/gamecontroller.circle.regular.imageset/Contents.json b/VoidLink/Images.xcassets/gamecontroller.circle.regular.imageset/Contents.json new file mode 100644 index 00000000..bb128f53 --- /dev/null +++ b/VoidLink/Images.xcassets/gamecontroller.circle.regular.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "gamecontroller.circle.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/VoidLink/Images.xcassets/gamecontroller.circle.regular.imageset/gamecontroller.circle.svg b/VoidLink/Images.xcassets/gamecontroller.circle.regular.imageset/gamecontroller.circle.svg new file mode 100644 index 00000000..71c89fea --- /dev/null +++ b/VoidLink/Images.xcassets/gamecontroller.circle.regular.imageset/gamecontroller.circle.svg @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/VoidLink/Images.xcassets/gamecontroller.circle.tag.imageset/Contents.json b/VoidLink/Images.xcassets/gamecontroller.circle.tag.imageset/Contents.json new file mode 100644 index 00000000..d9d22101 --- /dev/null +++ b/VoidLink/Images.xcassets/gamecontroller.circle.tag.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "gamecontroller.circle.tag.svg", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/VoidLink/Images.xcassets/gamecontroller.circle.tag.imageset/gamecontroller.circle.tag.svg b/VoidLink/Images.xcassets/gamecontroller.circle.tag.imageset/gamecontroller.circle.tag.svg new file mode 100644 index 00000000..f3971993 --- /dev/null +++ b/VoidLink/Images.xcassets/gamecontroller.circle.tag.imageset/gamecontroller.circle.tag.svg @@ -0,0 +1,12 @@ + + + + + + + + + + diff --git a/VoidLink/Input/OnScreenWidgetView.swift b/VoidLink/Input/OnScreenWidgetView.swift index 65334486..84bf585a 100644 --- a/VoidLink/Input/OnScreenWidgetView.swift +++ b/VoidLink/Input/OnScreenWidgetView.swift @@ -19,6 +19,7 @@ import ObjectiveC.runtime @objc public static var mapping: [Int16:OnScreenWidgetView] = [:] @objc public static var isRestoring: Bool = false @objc public static var hasRestoredFromAutoDock: Bool = false + @objc public static var autoDockRestoreInitByViewResize: Bool = false @objc public static func set(widget:OnScreenWidgetView, for key:Int16) { mapping[key] = widget } @@ -694,12 +695,12 @@ import ObjectiveC.runtime private func tweakAlpha(tweakBorderAlpha:Bool, tweakLabelAlpha:Bool = true){ // setup default border from self.backgroundAlpha - let realBackgroundAlpha = abs(self.backgroundAlpha) - 0.18 // offset to be consistent with legacy onScreen controller layer opacity + let realBackgroundAlpha = max(abs(self.backgroundAlpha) - 0.18, 0) // offset to be consistent with legacy onScreen controller layer opacity self.backgroundColor = UIColor(white:self.backgroundAlpha>0 ? 0.1 : 0.9, alpha: realBackgroundAlpha) // offset to be consistent with legacy onScreen controller layer opacity if tweakBorderAlpha { - borderAlpha = realBackgroundAlpha * 1.01 - defaultBorderColor = UIColor(white: self.backgroundAlpha>0 ? 0.1 : 0.9, alpha: abs(borderAlpha)).cgColor + borderAlpha = realBackgroundAlpha * 1.005 * (self.backgroundAlpha>0 ? 1 : -1) + defaultBorderColor = UIColor(white: borderAlpha>0 ? 0.1 : 0.9, alpha: abs(borderAlpha)).cgColor self.layer.borderColor = defaultBorderColor } @@ -824,6 +825,9 @@ import ObjectiveC.runtime private func setSquareWidgetCornerRadius(){ let shortSideLen = min(self.layer.bounds.size.width, self.layer.bounds.size.height) self.layer.cornerRadius = shortSideLen/2 < 16 ? shortSideLen/3.2 : 16 + if #available(iOS 13.0, *) { + self.layer.cornerCurve = .continuous + } } func containsNonLatin(_ text: String) -> Bool { @@ -866,6 +870,7 @@ import ObjectiveC.runtime ) label.attributedText = attr label.textAlignment = .center + label.baselineAdjustment = .alignCenters } private func setupView() { @@ -900,7 +905,6 @@ import ObjectiveC.runtime self.translatesAutoresizingMaskIntoConstraints = true // this is mandatory to prevent unexpected key view location change - self.setSquareWidgetCornerRadius() self.layer.borderWidth = self.borderWidth self.tweakAlpha(tweakBorderAlpha: false, tweakLabelAlpha: false) @@ -927,7 +931,7 @@ import ObjectiveC.runtime label.isHidden = self.widgetLabel.uppercased() == self.touchPadString // allow touchPad label to be display if it's different from touchPad cmdString } } - + if !self.functionalButtonString.isEmpty{ self.layer.borderWidth = self.borderWidth } @@ -935,11 +939,10 @@ import ObjectiveC.runtime if self.shape == "round" { //setup round buttons self.layer.cornerRadius = self.frame.width/2 - // self.layer.borderWidth = self.borderWidth label.minimumScaleFactor = 0.15 // Adjust the scale factor for oscButtons } if self.shape == "square" || self.shape == "largeSquare" { - //just do nothing here + self.setSquareWidgetCornerRadius() } @@ -1809,6 +1812,9 @@ import ObjectiveC.runtime buttonDownVisualEffectLayer.borderColor = standardHighlightColor.cgColor buttonDownVisualEffectLayer.frame = self.bounds.insetBy(dx: -buttonDownVisualEffectLayer.borderWidth, dy: -buttonDownVisualEffectLayer.borderWidth) // Adjust the inset as needed buttonDownVisualEffectLayer.cornerRadius = self.layer.cornerRadius + buttonDownVisualEffectLayer.borderWidth + if self.shape == "square" {if #available(iOS 13.0, *) { + buttonDownVisualEffectLayer.cornerCurve = .continuous + }} buttonDownVisualEffectLayer.backgroundColor = UIColor.clear.cgColor; buttonDownVisualEffectLayer.fillColor = UIColor.clear.cgColor; @@ -3379,6 +3385,10 @@ import ObjectiveC.runtime completion: {_ in self.autoDockIsDocked = false self.restartAutoDockCountdown() + if OnScreenWidgetView.autoDockRestoreInitByViewResize { + OnScreenWidgetView.autoDockRestoreInitByViewResize = false + OnScreenWidgetView.hasRestoredFromAutoDock = false + } } ) } diff --git a/VoidLink/Localization/Localizable.xcstrings b/VoidLink/Localization/Localizable.xcstrings index d00f6317..cd7df14a 100644 --- a/VoidLink/Localization/Localizable.xcstrings +++ b/VoidLink/Localization/Localizable.xcstrings @@ -5488,7 +5488,7 @@ }, "zh-Hant" : { "stringUnit" : { - "state" : "needs_review", + "state" : "translated", "value" : "- 螢幕控制項佈局(包含虛擬手把、虛擬按鍵等),以及設定選單中標記 [手把圖示] 的選項(如體感控制參數),皆保存在遊戲配置中。\n\n- 串流過程中,由螢幕 %@ 邊緣向內滑動 %@ 螢幕寬度,即可在工具箱選單中開啟[切換遊戲配置]" } }, diff --git a/VoidLink/Utility/GenericUtils.swift b/VoidLink/Utility/GenericUtils.swift index 2f2e2b38..760e66ed 100644 --- a/VoidLink/Utility/GenericUtils.swift +++ b/VoidLink/Utility/GenericUtils.swift @@ -269,7 +269,11 @@ import UIKit return UIScreen.main.bounds.height } - + @objc static var iOS18Available: Bool { + if #available(iOS 18.0, *) {return true} + else {return false} + } + @objc(parentViewControllerForView:) static func parentViewController(for view: UIView?) -> UIViewController? { var responder: UIResponder? = view diff --git a/VoidLink/ViewControllers/MainFrameViewController.m b/VoidLink/ViewControllers/MainFrameViewController.m index 2757cbbe..c09cf510 100644 --- a/VoidLink/ViewControllers/MainFrameViewController.m +++ b/VoidLink/ViewControllers/MainFrameViewController.m @@ -1613,16 +1613,28 @@ static NSMutableSet* hostList; [_profilesButton setAction:@selector(profilesButtonTapped)]; if (@available(iOS 13.0, *)) { [_profilesButton setTitle:nil]; - UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:GenericUtils.liquidGlassEnabled ? 20.5 : 23 weight:UIImageSymbolWeightRegular ]; - UIImage *image = [[UIImage systemImageNamed:@"gamecontroller.circle" withConfiguration:config] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; - [_profilesButton setImage:image]; - _profilesButton.imageInsets = GenericUtils.liquidGlassEnabled ? UIEdgeInsetsMake(0, 0, 0, 0.55) : UIEdgeInsetsMake(10, 10, 0, 0); - if(GenericUtils.liquidGlassEnabled){ - // if(@available(iOS 26.0, *)) _settingsButton.hidesSharedBackground = YES; + + UIImageSymbolConfiguration *config; + UIImage *image; + if(GenericUtils.iOS18Available){ + config = [UIImageSymbolConfiguration configurationWithPointSize:GenericUtils.liquidGlassEnabled ? 20.5 : 23 weight:UIImageSymbolWeightRegular ]; + image = [[UIImage systemImageNamed: @"gamecontroller.circle" withConfiguration:config] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + [_profilesButton setImage:image]; + _profilesButton.imageInsets = GenericUtils.liquidGlassEnabled ? UIEdgeInsetsMake(0, 0, 0, 0.55) : UIEdgeInsetsMake(10, 10, 0, 0); + if(GenericUtils.liquidGlassEnabled){ + _profilesButton.tintColor = ThemeManager.appPrimaryColor; + } + } + else{ + image = [[UIImage imageNamed: @"gamecontroller.circle.regular"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + [_profilesButton setImage:image]; + _profilesButton.imageInsets = UIEdgeInsetsMake(-1.5, 0, -1.5, 0); _profilesButton.tintColor = ThemeManager.appPrimaryColor; } + + } else { - [_profilesButton setTitle:[LocalizationHelper localizedStringForKey:@"Settings"]]; + [_profilesButton setTitle:[LocalizationHelper localizedStringForKey:@"Game Profile"]]; } if (@available(iOS 26.0, *)) { diff --git a/VoidLink/ViewControllers/SettingsViewController.m b/VoidLink/ViewControllers/SettingsViewController.m index 37fb98fa..b5bc10a0 100644 --- a/VoidLink/ViewControllers/SettingsViewController.m +++ b/VoidLink/ViewControllers/SettingsViewController.m @@ -1507,15 +1507,23 @@ BOOL isCustomResolution(int resolutionSelected) { button = [UIButton buttonWithType:UIButtonTypeSystem]; if (@available(iOS 13.0, *)) { if(stack.isGameProfileSetting){ - UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:14.5 weight:UIImageSymbolWeightRegular]; - [button setImage:[UIImage systemImageNamed:@"gamecontroller.circle" withConfiguration:config] forState:UIControlStateNormal]; + UIImage* image; + if(GenericUtils.iOS18Available){ + UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:14.5 weight:UIImageSymbolWeightRegular]; + image = [UIImage systemImageNamed:@"gamecontroller.circle" withConfiguration:config]; + } + else{ + image = [[UIImage imageNamed: @"gamecontroller.circle.tag"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate]; + } + + [button setImage:image forState:UIControlStateNormal]; } else{ UIImageSymbolConfiguration *config = [UIImageSymbolConfiguration configurationWithPointSize:13.5 weight:UIImageSymbolWeightMedium]; [button setImage:[UIImage systemImageNamed:@"info.circle" withConfiguration:config] forState:UIControlStateNormal]; } } else { - [button setTitle:@"info" forState:UIControlStateNormal]; + [button setTitle:stack.isGameProfileSetting ? @"game" : @"info" forState:UIControlStateNormal]; button.titleLabel.font = [UIFont systemFontOfSize:13 weight:UIFontWeightBold]; button.titleLabel.accessibilityIdentifier = @"infoButton"; } diff --git a/VoidLink/ViewControllers/StreamFrameViewController.m b/VoidLink/ViewControllers/StreamFrameViewController.m index 41b1e928..6fe07200 100644 --- a/VoidLink/ViewControllers/StreamFrameViewController.m +++ b/VoidLink/ViewControllers/StreamFrameViewController.m @@ -551,6 +551,11 @@ name:UIKeyboardWillHideNotification object:nil]; + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(keyboardDidHide) + name:UIKeyboardDidHideNotification + object:nil]; + [safeTimer start]; #endif } @@ -767,7 +772,12 @@ [_streamView keyboardWillHide]; } -- (void)handleAbnormalKeyboards:(NSNotification *)notification{ +- (void)keyboardDidHide{ + _streamView.bounds = _deviceWindow.bounds; + _streamView.frame = _deviceWindow.frame; +} + +- (void)handleNonStandardKeyboard:(NSNotification *)notification{ [_streamView handleNonStandardKeyboard:notification]; } @@ -1757,7 +1767,10 @@ } dispatch_time_t delayTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)); dispatch_after(delayTime, dispatch_get_main_queue(), ^{ - if(widget.autoDockEnabled) [widget restoreFromAutoDockWithAnimated:true]; + if(widget.autoDockEnabled){ + OnScreenWidgetView.autoDockRestoreInitByViewResize = true; + [widget restoreFromAutoDockWithAnimated:true]; + } }); [coordinator animateAlongsideTransition:^(id _Nonnull context) {