From a1a70fcca283c23065e488746dba095b2b2efe41 Mon Sep 17 00:00:00 2001 From: True Zhuanjia Date: Thu, 16 Apr 2026 14:31:21 +0800 Subject: [PATCH] - tool box menu improvements - autoDock improvements - live gamepad overlay close button --- .../AbstractGamepadOverlayWidgetView.swift | 137 +++++++++++++++++- VoidLink/Input/CustomOSC/OSCProfile.m | 2 +- VoidLink/Input/OnScreenWidgetView.swift | 26 ++-- VoidLink/Input/StreamView.m | 10 +- VoidLink/Utility/GenericUtils.swift | 20 ++- .../StreamFrameViewController.h | 3 +- .../StreamFrameViewController.m | 17 +++ .../ToolboxViewController.swift | 28 +++- 8 files changed, 214 insertions(+), 29 deletions(-) diff --git a/VoidLink/Input/AbstractGamepadOverlayWidgetView.swift b/VoidLink/Input/AbstractGamepadOverlayWidgetView.swift index c58f398f..d305d1d6 100644 --- a/VoidLink/Input/AbstractGamepadOverlayWidgetView.swift +++ b/VoidLink/Input/AbstractGamepadOverlayWidgetView.swift @@ -9,6 +9,12 @@ import UIKit import SwiftUI +@objc +protocol AbstractGamepadOverlayCloseButtonDelegate: AnyObject { + @objc(toggleGamepadOverlayWithOverlayEnabled:) + func toggleGamepadOverlay(withOverlayEnabled overlayEnabled: Bool) +} + private enum AbstractGamepadOverlayPersistence { private static let defaults = UserDefaults.standard @@ -126,6 +132,14 @@ private struct AbstractGamepadOverlayBridgeView: View { @available(iOS 13.0, *) @objc final class AbstractGamepadOverlayView: UIView { + private enum CloseButtonMetrics { + static let size: CGFloat = 40 + static let topInset: CGFloat = -10 + static let trailingInset: CGFloat = 0 + static let symbolPointSize: CGFloat = 16 + static let hideDelay: TimeInterval = 3 + } + private enum OverlayMaskMetrics { static let widthRatio: CGFloat = 0.85 static let heightRatio: CGFloat = 1.03 @@ -149,9 +163,12 @@ final class AbstractGamepadOverlayView: UIView { private var panStartCenter: CGPoint = .zero private var activeGestureCount = 0 private var didRestorePersistedState = false + private var hideCloseButtonWorkItem: DispatchWorkItem? private let minWidth: CGFloat = 70 private let maxWidth: CGFloat = 520 private let doubleTapWidths: [CGFloat] = [GenericUtils.isIPhone() ? 90 : 130, GenericUtils.isIPhone() ? 165 : 200] + private lazy var closeButton: UIButton = makeCloseButton() + @objc weak var closeButtonDelegate: AbstractGamepadOverlayCloseButtonDelegate? @objc init(frame: CGRect, usesPlayStationFaceButtons: Bool) { self.usesPlayStationFaceButtons = usesPlayStationFaceButtons @@ -189,16 +206,17 @@ final class AbstractGamepadOverlayView: UIView { backgroundColor = .clear clipsToBounds = false isMultipleTouchEnabled = true - layer.mask = visualMaskLayer applyScale(forTargetWidth: initialDisplayWidth) addSubview(hostingController.view) + addSubview(closeButton) installGesturesIfNeeded() } override func layoutSubviews() { super.layoutSubviews() hostedView?.frame = bounds + layoutCloseButton() updateVisualMask() restorePersistedStateIfNeeded() } @@ -237,17 +255,21 @@ final class AbstractGamepadOverlayView: UIView { @objc private func handleSingleTap(_ recognizer: UITapGestureRecognizer) { guard recognizer.state == .ended else { return } + registerUserInteraction() presentFirstTouchTipIfNeeded() + scheduleCloseButtonHideIfNeeded() } @objc private func handlePan(_ recognizer: UIPanGestureRecognizer) { guard let superview else { return } switch recognizer.state { case .began: + registerUserInteraction() presentFirstTouchTipIfNeeded() beginGestureSession() panStartCenter = center case .changed, .ended: + registerUserInteraction() let translation = recognizer.translation(in: superview) center = CGPoint(x: panStartCenter.x + translation.x, y: panStartCenter.y + translation.y) if recognizer.state == .ended { @@ -263,10 +285,12 @@ final class AbstractGamepadOverlayView: UIView { @objc private func handlePinch(_ recognizer: UIPinchGestureRecognizer) { switch recognizer.state { case .began: + registerUserInteraction() presentFirstTouchTipIfNeeded() beginGestureSession() pinchBaseWidth = frame.width case .changed, .ended: + registerUserInteraction() let nextWidth = max(minWidth, min(maxWidth, pinchBaseWidth * recognizer.scale)) applyScale(forTargetWidth: nextWidth) if recognizer.state == .ended { @@ -281,14 +305,17 @@ final class AbstractGamepadOverlayView: UIView { @objc private func handleDoubleTap(_ recognizer: UITapGestureRecognizer) { guard recognizer.state == .ended else { return } + registerUserInteraction() presentFirstTouchTipIfNeeded() applyScale(forTargetWidth: nextDoubleTapWidth()) persistState() + scheduleCloseButtonHideIfNeeded() } private func updateVisualMask() { guard bounds.width > 1, bounds.height > 1 else { visualMaskLayer.path = nil + hostedView?.layer.mask = nil return } @@ -325,16 +352,32 @@ final class AbstractGamepadOverlayView: UIView { ) ) visualMaskLayer.path = path.cgPath + hostedView?.layer.mask = visualMaskLayer } override func point(inside point: CGPoint, with event: UIEvent?) -> Bool { bounds.contains(point) } - override func touchesBegan(_ touches: Set, with event: UIEvent?) {} - override func touchesMoved(_ touches: Set, with event: UIEvent?) {} - override func touchesEnded(_ touches: Set, with event: UIEvent?) {} - override func touchesCancelled(_ touches: Set, with event: UIEvent?) {} + override func touchesBegan(_ touches: Set, with event: UIEvent?) { + super.touchesBegan(touches, with: event) + registerUserInteraction() + } + + override func touchesMoved(_ touches: Set, with event: UIEvent?) { + super.touchesMoved(touches, with: event) + registerUserInteraction() + } + + override func touchesEnded(_ touches: Set, with event: UIEvent?) { + super.touchesEnded(touches, with: event) + scheduleCloseButtonHideIfNeeded() + } + + override func touchesCancelled(_ touches: Set, with event: UIEvent?) { + super.touchesCancelled(touches, with: event) + scheduleCloseButtonHideIfNeeded() + } private func restorePersistedStateIfNeeded() { guard !didRestorePersistedState, @@ -354,6 +397,11 @@ final class AbstractGamepadOverlayView: UIView { activeGestureCount += 1 } + @objc func registerUserInteraction() { + showCloseButton() + cancelPendingCloseButtonHide() + } + private func presentFirstTouchTipIfNeeded() { guard GenericUtils.isFirstLaunchGamepadOverlayFeature() else { return } guard let presentingViewController = nearestViewController() else { return } @@ -383,6 +431,7 @@ final class AbstractGamepadOverlayView: UIView { activeGestureCount = max(0, activeGestureCount - 1) guard activeGestureCount == 0 else { return } persistState() + scheduleCloseButtonHideIfNeeded() } private func persistState() { @@ -407,6 +456,79 @@ final class AbstractGamepadOverlayView: UIView { let targetScale = clampedWidth / baseRenderWidth transform = CGAffineTransform(scaleX: targetScale, y: targetScale) } + + private func makeCloseButton() -> UIButton { + let button = UIButton(type: .system) + button.tintColor = UIColor.black.withAlphaComponent(0.66) + button.backgroundColor = UIColor.white.withAlphaComponent(0.78) + button.layer.borderWidth = 1 + button.layer.borderColor = UIColor.white.withAlphaComponent(0.9).cgColor + button.layer.shadowColor = UIColor.black.withAlphaComponent(0.05).cgColor + button.layer.shadowOpacity = 1 + button.layer.shadowRadius = 4 + button.layer.shadowOffset = CGSize(width: 0, height: 2) + button.alpha = 0 + button.isHidden = true + button.adjustsImageWhenHighlighted = false + button.addTarget(self, action: #selector(handleCloseButtonTap), for: .touchUpInside) + + let configuration = UIImage.SymbolConfiguration(pointSize: CloseButtonMetrics.symbolPointSize, weight: .bold) + button.setImage(UIImage(systemName: "xmark", withConfiguration: configuration), for: .normal) + return button + } + + private func layoutCloseButton() { + let size = CGFloat(Int(CloseButtonMetrics.size/2))*2 + closeButton.frame = CGRect( + x: bounds.width - CloseButtonMetrics.trailingInset - size, + y: CloseButtonMetrics.topInset, + width: size, + height: size + ) + closeButton.layer.cornerRadius = size * 0.5 + } + + private func showCloseButton() { + closeButton.isHidden = false + guard closeButton.alpha < 1 else { return } + UIView.animate(withDuration: 0.18) { + self.closeButton.alpha = 1 + } + } + + private func hideCloseButton() { + guard !closeButton.isHidden else { return } + UIView.animate( + withDuration: 0.18, + animations: { + self.closeButton.alpha = 0 + }, + completion: { _ in + self.closeButton.isHidden = true + } + ) + } + + private func cancelPendingCloseButtonHide() { + hideCloseButtonWorkItem?.cancel() + hideCloseButtonWorkItem = nil + } + + @objc func scheduleCloseButtonHideIfNeeded() { + guard activeGestureCount == 0 else { return } + cancelPendingCloseButtonHide() + let workItem = DispatchWorkItem { [weak self] in + self?.hideCloseButton() + self?.hideCloseButtonWorkItem = nil + } + hideCloseButtonWorkItem = workItem + DispatchQueue.main.asyncAfter(deadline: .now() + CloseButtonMetrics.hideDelay, execute: workItem) + } + + @objc private func handleCloseButtonTap() { + cancelPendingCloseButtonHide() + closeButtonDelegate?.toggleGamepadOverlay(withOverlayEnabled: false) + } } @available(iOS 13.0, *) @@ -415,4 +537,9 @@ extension AbstractGamepadOverlayView: UIGestureRecognizerDelegate { (gestureRecognizer is UIPanGestureRecognizer && otherGestureRecognizer is UIPinchGestureRecognizer) || (gestureRecognizer is UIPinchGestureRecognizer && otherGestureRecognizer is UIPanGestureRecognizer) } + + func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldReceive touch: UITouch) -> Bool { + guard let touchedView = touch.view else { return true } + return touchedView !== closeButton && !touchedView.isDescendant(of: closeButton) + } } diff --git a/VoidLink/Input/CustomOSC/OSCProfile.m b/VoidLink/Input/CustomOSC/OSCProfile.m index a57fbffd..29d6e781 100644 --- a/VoidLink/Input/CustomOSC/OSCProfile.m +++ b/VoidLink/Input/CustomOSC/OSCProfile.m @@ -114,7 +114,7 @@ self.reverseGyroHoldButton = [decoder containsValueForKey:@"reverseGyroHoldButton"] ? [decoder decodeBoolForKey:@"reverseGyroHoldButton"] : false; self.controllerGyroSwitchHold = [decoder containsValueForKey:@"controllerGyroSwitchHold"] ? [decoder decodeIntForKey:@"controllerGyroSwitchHold"] : ControllerButtonNull; self.controllerGyroSwitchToggle = [decoder containsValueForKey:@"controllerGyroSwitchToggle"] ? [decoder decodeIntForKey:@"controllerGyroSwitchToggle"] : ControllerButtonNull; - self.gamepadOverlayEnabled = [decoder containsValueForKey:@"gamepadOverlayEnabled"] ? [decoder decodeBoolForKey:@"gamepadOverlayEnabled"] : true; + self.gamepadOverlayEnabled = [decoder containsValueForKey:@"gamepadOverlayEnabled"] ? [decoder decodeBoolForKey:@"gamepadOverlayEnabled"] : false; self.pressureCurvePoints = [decoder containsValueForKey:@"pressureCurvePoints"] diff --git a/VoidLink/Input/OnScreenWidgetView.swift b/VoidLink/Input/OnScreenWidgetView.swift index 4a026a61..65334486 100644 --- a/VoidLink/Input/OnScreenWidgetView.swift +++ b/VoidLink/Input/OnScreenWidgetView.swift @@ -143,6 +143,7 @@ import ObjectiveC.runtime // for movable buttons during streaming @objc public var relocatedDuringStreaming: Bool = false + @objc static var relocatedDuringStreaming: Bool = false // for all touchPad or buttons hybrid with touchPads @objc public var hasMinStickOffset: Bool = false @@ -847,7 +848,7 @@ import ObjectiveC.runtime case "DISABLETOUCH": self.nonEditableWidgetLabel = SwiftLocalizationHelper.localizedString(forKey: touchDisabledFLag ? "=EnableTouch" : "=DisableTouch" ) case "GAMEPADOVERLAY": - self.nonEditableWidgetLabel = SwiftLocalizationHelper.localizedString(forKey: gamepadOverlayFLag ? "=GamepadOverlayOn" : "=GamepadOverlayOff" ) + self.nonEditableWidgetLabel = SwiftLocalizationHelper.localizedString(forKey: OnScreenWidgetView.gamepadOverlayFLag ? "=GamepadOverlayOn" : "=GamepadOverlayOff" ) default: nonEditableWidgetLabel = "" } @@ -2715,13 +2716,13 @@ import ObjectiveC.runtime self.functionalButtonDelegate?.toggleTouch(disabled: touchDisabledFLag) } - @objc var gamepadOverlayFLag:Bool = false + @objc static var gamepadOverlayFLag:Bool = false private func gamepadOverlayButtonUp(){ self.relocatedDuringStreaming = true - gamepadOverlayFLag = !gamepadOverlayFLag + OnScreenWidgetView.gamepadOverlayFLag = !OnScreenWidgetView.gamepadOverlayFLag self.setupAtrributedText() if #available(iOS 13.0, *) { - self.functionalButtonDelegate?.toggleGamepadOverlay(overlayEnabled: gamepadOverlayFLag) + self.functionalButtonDelegate?.toggleGamepadOverlay(overlayEnabled: OnScreenWidgetView.gamepadOverlayFLag) } } @@ -3093,6 +3094,7 @@ import ObjectiveC.runtime private static let autoDockExposedThickness: CGFloat = 22 private static let autoDockVerticalInset: CGFloat = 12 @objc var autoDockIdleDuration: TimeInterval = 0 + @objc var storedAutoDockIdleDuration: TimeInterval = 0 private static let autoDockInitialAlpha: CGFloat = 0.8 @objc var autoDockSettledAlpha: CGFloat = 0.2 private static let autoDockSettledAlphaDelay: TimeInterval = 2 @@ -3123,8 +3125,8 @@ import ObjectiveC.runtime private var autoDockDockedCenter: CGPoint? private var autoDockDockedToBottomEdge: Bool = false private var autoDockDistance: CGFloat = 3 - private var autoDockIsDocked: Bool = false - private var autoDockEnabled: Bool = false + @objc var autoDockIsDocked: Bool = false + @objc var autoDockEnabled: Bool = false private var autoDockSettledAlphaTimer: Timer? private var autoDockOriginalBoundsSize: CGSize = .zero @@ -3174,7 +3176,7 @@ import ObjectiveC.runtime autoDockRestartCountdownIfNeeded() } - @objc public func setAutoDockEnabled(_ enabled: Bool) { + @objc public func setAutoDock(enabled: Bool) { autoDockEnabled = enabled if enabled { OnScreenWidgetView.installAutoDockIfNeeded() @@ -3212,7 +3214,7 @@ import ObjectiveC.runtime autoDockRestoreWidget(animated: animated) } - private func autoDockStopCountdown() { + @objc func autoDockStopCountdown() { autoDockTimer?.invalidate() autoDockTimer = nil } @@ -3285,6 +3287,8 @@ import ObjectiveC.runtime private func autoDockWidgetToNearestEdge() { guard autoDockEnabled else {return} + autoDockIdleDuration = storedAutoDockIdleDuration + if !folded { restartAutoDockCountdown() return @@ -3342,7 +3346,10 @@ import ObjectiveC.runtime } private func autoDockRestoreWidget(animated: Bool) { - guard autoDockIsDocked else { return } + guard autoDockIsDocked else { + restartAutoDockCountdown() + return + } let restoreCenter = storedCenter OnScreenWidgetView.hasRestoredFromAutoDock = true autoDockStopCountdown() @@ -3475,6 +3482,7 @@ import ObjectiveC.runtime || abs(widget.backgroundAlpha) < 0.1){ widget.highlightBorder(highlighted: false) } + if widget.hasNonEditableLabel {widget.setupAtrributedText()} }) } } diff --git a/VoidLink/Input/StreamView.m b/VoidLink/Input/StreamView.m index 1320ba30..57c05c09 100644 --- a/VoidLink/Input/StreamView.m +++ b/VoidLink/Input/StreamView.m @@ -603,7 +603,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; if(!hasFolderStateChanged) hasFolderStateChanged = widget.folded != widget.persistedFolded; } - if(relocatedWidgetSequences.count == 0 && !hasFolderStateChanged) return; + if(relocatedWidgetSequences.count == 0 && !hasFolderStateChanged && !OnScreenWidgetView.relocatedDuringStreaming) return; NSLog(@"relocatedWidgetSequences.count %lu, hasFolderStateChanged %d %F", relocatedWidgetSequences.count, hasFolderStateChanged, CACurrentMediaTime()); oscProfileMan = [OSCProfilesManager sharedManager:self->_streamFrameTopLayerView.bounds]; @@ -651,7 +651,9 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; if(![self isOnScreenWidgetEnabled]) return; OnScreenWidgetView.buttonVisualFeedbackEnabled = self->settings.buttonVisualFeedback; - + OnScreenWidgetView.gamepadOverlayFLag = oscProfile.gamepadOverlayEnabled; + OnScreenWidgetView.relocatedDuringStreaming = false; + bool hasLegacyWidget = false; if(reload && !OnScreenWidgetView.editMode){ // remove all keyboard widget views first @@ -675,6 +677,7 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; widgetView.sequenceSet = buttonState.sequenceSet; widgetView.parentSequence = buttonState.parentSequence; widgetView.autoDockIdleDuration = buttonState.autoDockTimer; + widgetView.storedAutoDockIdleDuration = widgetView.autoDockIdleDuration; widgetView.autoDockSettledAlpha = buttonState.dockedAlpha; widgetView.folded = buttonState.folded; widgetView.persistedFolded = buttonState.folded; @@ -723,10 +726,9 @@ static const double X1_MOUSE_SPEED_DIVISOR = 2.5; [widgetView setupAutoTapTimer]; [widgetView setupInertialScrollerWithFps:self->settings.framerate.intValue]; - widgetView.gamepadOverlayFLag = oscProfile.gamepadOverlayEnabled; [widgetView setupAtrributedText]; - if(widgetView.isFolder && widgetView.parentSequence<0 && widgetView.autoDockIdleDuration>0) [widgetView setAutoDockEnabled:true]; + if(widgetView.isFolder && widgetView.parentSequence<0 && widgetView.autoDockIdleDuration>0) [widgetView setAutoDockWithEnabled:true]; if(sequenceGenerated){ // NSLog(@"widgetView.sequence %d %f", widgetView.sequence, CACurrentMediaTime()); diff --git a/VoidLink/Utility/GenericUtils.swift b/VoidLink/Utility/GenericUtils.swift index 5804fd38..b640b116 100644 --- a/VoidLink/Utility/GenericUtils.swift +++ b/VoidLink/Utility/GenericUtils.swift @@ -213,16 +213,20 @@ import Foundation return CGFloat(Double(str) ?? 0) } - @available(iOS 13.0, *) @objc static func isLandscape() -> Bool { - guard let windowScene = UIApplication.shared.connectedScenes - .compactMap({ $0 as? UIWindowScene }) - .first(where: { $0.activationState == .foregroundActive }) - else { - return false + if #available(iOS 13.0, *) { + guard let windowScene = UIApplication.shared.connectedScenes + .compactMap({ $0 as? UIWindowScene }) + .first(where: { $0.activationState == .foregroundActive }) + else {return false} + return windowScene.interfaceOrientation.isLandscape } - - return windowScene.interfaceOrientation.isLandscape + else {return GenericUtils.screenWidth > GenericUtils.screenHeight} + } + + @objc static func viewIsLandscape(_ view: UIView?) -> Bool { + guard let view else {return false} + return view.bounds.width > view.bounds.height } @objc static var screenWidth: CGFloat { diff --git a/VoidLink/ViewControllers/StreamFrameViewController.h b/VoidLink/ViewControllers/StreamFrameViewController.h index 6871c98d..b2e9b309 100644 --- a/VoidLink/ViewControllers/StreamFrameViewController.h +++ b/VoidLink/ViewControllers/StreamFrameViewController.h @@ -28,7 +28,7 @@ @interface StreamFrameViewController : GCEventViewController #else -@interface StreamFrameViewController : UIViewController +@interface StreamFrameViewController : UIViewController #endif @property (nonatomic, strong) StreamManager* streamMan; @@ -48,6 +48,7 @@ - (void)setUserInteractionEnabledForStreamView:(bool)enabled; - (bool)shallDisableGyroHotSwitch; - (void)loadGameProfileConfigs:(OSCProfile* )profile; +- (void)toggleGamepadOverlayWithOverlayEnabled:(BOOL)overlayEnabled API_AVAILABLE(ios(13.0)); - (void)loadAbstractGamepadOverlayIfNeeded API_AVAILABLE(ios(13.0)); @end diff --git a/VoidLink/ViewControllers/StreamFrameViewController.m b/VoidLink/ViewControllers/StreamFrameViewController.m index bd5ee412..fd7f447c 100644 --- a/VoidLink/ViewControllers/StreamFrameViewController.m +++ b/VoidLink/ViewControllers/StreamFrameViewController.m @@ -45,6 +45,7 @@ - (id)initWithRefreshRate:(float)arg1 videoDynamicRange:(int)arg2; @end + @implementation StreamFrameViewController { ControllerSupport *_controllerSupport; TemporarySettings *_settings; @@ -1750,6 +1751,16 @@ for(OnScreenWidgetView* widget in OnScreenWidgetView.mapping.allValues){ CGPoint oldCenter = widget.center; CGPoint oldStoredCenter = widget.storedCenter; + + if(widget.autoDockEnabled){ + widget.autoDockIdleDuration = fmax(widget.autoDockIdleDuration, 2.0); + [widget autoDockStopCountdown]; + } + 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]; + }); + [coordinator animateAlongsideTransition:^(id _Nonnull context) { widget.center = CGPointMake(oldCenter.x * scaleX,oldCenter.y * scaleY); widget.storedCenter = CGPointMake(oldStoredCenter.x * scaleX,oldStoredCenter.y * scaleY); @@ -1793,6 +1804,9 @@ } - (void)toggleGamepadOverlayWithOverlayEnabled:(BOOL)overlayEnabled API_AVAILABLE(ios(13.0)){ + OnScreenWidgetView.gamepadOverlayFLag = overlayEnabled; + OnScreenWidgetView.relocatedDuringStreaming = true; + if(overlayEnabled) [self loadAbstractGamepadOverlayIfNeeded]; else { [_virtualGamepadOverlay removeFromSuperview]; @@ -1819,9 +1833,12 @@ CGRect overlayFrame = CGRectMake(0, 0, standardWidth, standardhHeight); AbstractGamepadOverlayView *overlayView = [[AbstractGamepadOverlayView alloc] initWithFrame:overlayFrame usesPlayStationFaceButtons:!usesXboxFaceButtons]; + overlayView.closeButtonDelegate = self; overlayView.center = CGPointMake(self.view.bounds.size.width-standardWidth/2-20, self.view.bounds.size.height-standardhHeight/2-20); overlayView.userInteractionEnabled = YES; [self.view addSubview:overlayView]; + [overlayView registerUserInteraction]; + [overlayView scheduleCloseButtonHideIfNeeded]; self->_virtualGamepadOverlay = overlayView; }); diff --git a/VoidLink/ViewControllers/ToolboxViewController.swift b/VoidLink/ViewControllers/ToolboxViewController.swift index 6796f456..4a27fc3b 100644 --- a/VoidLink/ViewControllers/ToolboxViewController.swift +++ b/VoidLink/ViewControllers/ToolboxViewController.swift @@ -83,6 +83,19 @@ import UIKit //setupConstraints() } + public override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { + super.viewWillTransition(to: size, with: coordinator) + + DispatchQueue.main.asyncAfter(deadline: .now()+0.2) { + self.pinButton.isHidden = !GenericUtils.viewIsLandscape(self.view) && GenericUtils.isIPhone() + } + + view.setNeedsUpdateConstraints() + coordinator.animate(alongsideTransition: { _ in + self.view.layoutIfNeeded() + }) + } + private func setupViews() { contentView = UIView(frame: self.view.frame) @@ -129,6 +142,7 @@ import UIKit contentView.addSubview(editButton) // contentView.addSubview(exitButton) contentView.addSubview(pinButton) + pinButton.isHidden = !GenericUtils.isLandscape() self.view.addSubview(contentView) @@ -149,6 +163,18 @@ import UIKit private func isIPhone()->Bool { return UIDevice.current.userInterfaceIdiom == .phone } + + private func contentWidthMultiplier() -> CGFloat { + /* + if isIPhone() && GenericUtils.viewIsLandscape(self.view) { + return 0.85 + }*/ + + return isIPhone() + ? (GenericUtils.viewIsLandscape(self.view) ? 0.6 : 0.85) + : (GenericUtils.viewIsLandscape(self.view) ? 0.6 : 0.85) + } + @objc public func setupConstraints() { @@ -167,7 +193,7 @@ import UIKit NSLayoutConstraint.activate([ // Set the width and height of the view - contentView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: isIPhone() ? 0.6 : 0.52), + contentView.widthAnchor.constraint(equalTo: view.widthAnchor, multiplier: contentWidthMultiplier()), contentView.heightAnchor.constraint(equalTo: view.heightAnchor, multiplier: 0.93), // Set the width and height of the view //view.leadingAnchor.constraint(equalTo: view.superview!.leadingAnchor, constant: 60),