diff --git a/FinniversKit/FinniversKit.xcodeproj/project.pbxproj b/FinniversKit/FinniversKit.xcodeproj/project.pbxproj index 2cfc266b18..c37562da4c 100644 --- a/FinniversKit/FinniversKit.xcodeproj/project.pbxproj +++ b/FinniversKit/FinniversKit.xcodeproj/project.pbxproj @@ -282,7 +282,6 @@ 9F213D4043DC51660E6EF81B /* FullscreenGalleryTransitionAware.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F21354AF1CEB17C6CD55DCE /* FullscreenGalleryTransitionAware.swift */; }; 9F213D5FD69FD3EAE67A4D2D /* FullscreenImageViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F21379B5A6F7C76368BD8AF /* FullscreenImageViewController.swift */; }; 9F213EA8026933194D7483E0 /* FullscreenImageView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9F213568D13E929BBB70CF2F /* FullscreenImageView.swift */; }; - A109F8682D5B7D7100EF42AC /* UIApplicationExtensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A109F8672D5B7D6C00EF42AC /* UIApplicationExtensions.swift */; }; AADED71C223FE25500647C50 /* UIDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = AADED71B223FE25500647C50 /* UIDevice.swift */; }; ADC5C9704E980F30DB92ECF6 /* CollapsibleContentView+Style.swift in Sources */ = {isa = PBXBuildFile; fileRef = ADC5CE145A903142865FA082 /* CollapsibleContentView+Style.swift */; }; AF91BB97202C74D0003E6366 /* BroadcastItem.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF91BB96202C74D0003E6366 /* BroadcastItem.swift */; }; @@ -725,7 +724,6 @@ 9F213B88B6D6E66371A88079 /* FullscreenGalleryTransitionPresenterDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FullscreenGalleryTransitionPresenterDelegate.swift; sourceTree = ""; }; 9F213CB3556A74594DB59E93 /* KeyboardNotificationInfoTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = KeyboardNotificationInfoTest.swift; sourceTree = ""; }; 9F213F9DEE0BF048DD9B29FB /* GalleryPreviewView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GalleryPreviewView.swift; sourceTree = ""; }; - A109F8672D5B7D6C00EF42AC /* UIApplicationExtensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIApplicationExtensions.swift; sourceTree = ""; }; AADED71B223FE25500647C50 /* UIDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UIDevice.swift; sourceTree = ""; }; ADC5CE145A903142865FA082 /* CollapsibleContentView+Style.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CollapsibleContentView+Style.swift"; sourceTree = ""; }; AF91BB96202C74D0003E6366 /* BroadcastItem.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BroadcastItem.swift; sourceTree = ""; }; @@ -1533,7 +1531,6 @@ 44898D5A1FE5B9C200F6017B /* UIKit */ = { isa = PBXGroup; children = ( - A109F8672D5B7D6C00EF42AC /* UIApplicationExtensions.swift */, DAE6A55A21CA523A00837BFA /* Core Graphics */, 441D699A1FEA947600CD919A /* Layout.swift */, 441D69991FEA947500CD919A /* LayoutHelpers.swift */, @@ -3377,7 +3374,6 @@ 44587019213FA344009187BE /* RegisterViewModel.swift in Sources */, 9BEB287F231D488000D28BAD /* TitleValueSliderView.swift in Sources */, 178006B02B99F0FF0027DD97 /* CharacterSet+HTML.swift in Sources */, - A109F8682D5B7D7100EF42AC /* UIApplicationExtensions.swift in Sources */, 172E7502290FC86B00956AC2 /* HTMLText.swift in Sources */, CF5CA71222F85A94007C4124 /* NeighborhoodProfileHeaderView.swift in Sources */, 441FE435209A24E500B04EF1 /* StandardAdRecommendationViewModel.swift in Sources */, diff --git a/FinniversKit/Sources/Components/KeyValueGridView/KeyValueGridView.swift b/FinniversKit/Sources/Components/KeyValueGridView/KeyValueGridView.swift index abcc4a61bf..6451c02610 100644 --- a/FinniversKit/Sources/Components/KeyValueGridView/KeyValueGridView.swift +++ b/FinniversKit/Sources/Components/KeyValueGridView/KeyValueGridView.swift @@ -17,6 +17,8 @@ public class KeyValueGridView: UIView { private var titleStyle: Warp.Typography = .body private var valueStyle: Warp.Typography = .bodyStrong private lazy var verticalStackView = UIStackView(axis: .vertical, spacing: Warp.Spacing.spacing200, alignment: .leading, distribution: .equalSpacing, withAutoLayout: true) + private weak var activeTooltipView: UIView? + private weak var activeInfoButton: UIView? // MARK: - Initializers @@ -113,7 +115,7 @@ public class KeyValueGridView: UIView { ]) infoButton.addAction(UIAction(handler: { [weak self] action in guard let view = action.sender as? UIView else { return } - self?.showTooltip(infoText, from: view) + self?.toggleTooltip(infoText, from: infoButton) }), for: .touchUpInside) titleContainer.addArrangedSubview(infoButton) @@ -155,32 +157,47 @@ public class KeyValueGridView: UIView { return stackView } + private func toggleTooltip(_ text: String, from infoButton: UIView) { + if let activeTooltip = activeTooltipView, activeInfoButton === infoButton { + dismissTooltip() + } else { + dismissTooltip() + showTooltip(text, from: infoButton) + } + } + private func showTooltip(_ text: String, from sourceView: UIView) { - guard let keyWindow = UIApplication.shared.firstWindow else { return } - - let overlayView = UIView(frame: keyWindow.bounds) - keyWindow.addSubview(overlayView) - let tooltipView = Warp.Tooltip(title: text, arrowEdge: .bottom).uiView tooltipView.translatesAutoresizingMaskIntoConstraints = false - overlayView.addSubview(tooltipView) - - /// Convert the sourceView’s frame to keyWindow coordinates for positioning - let sourceFrame = sourceView.convert(sourceView.bounds, to: keyWindow) + tooltipView.isUserInteractionEnabled = true + + addSubview(tooltipView) + + // Convert the button’s frame to the KeyValueGridView’s coordinate system + let buttonFrameInSelf = sourceView.convert(sourceView.bounds, to: self) NSLayoutConstraint.activate([ - tooltipView.centerXAnchor.constraint(equalTo: overlayView.leftAnchor, constant: sourceFrame.midX), - tooltipView.bottomAnchor.constraint(equalTo: overlayView.topAnchor, constant: sourceFrame.minY - Warp.Spacing.spacing100), - tooltipView.leadingAnchor.constraint(greaterThanOrEqualTo: overlayView.leadingAnchor, constant: Warp.Spacing.spacing200), - tooltipView.trailingAnchor.constraint(lessThanOrEqualTo: overlayView.trailingAnchor, constant: -Warp.Spacing.spacing200) + tooltipView.topAnchor.constraint(equalTo: self.topAnchor, constant: buttonFrameInSelf.maxY - Warp.Spacing.spacing50), + tooltipView.centerXAnchor.constraint(equalTo: self.leftAnchor, constant: buttonFrameInSelf.midX), + tooltipView.leadingAnchor.constraint(greaterThanOrEqualTo: self.leadingAnchor, constant: Warp.Spacing.spacing100), + tooltipView.trailingAnchor.constraint(lessThanOrEqualTo: self.trailingAnchor, constant: -Warp.Spacing.spacing100) ]) - let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissOverlay(_:))) - overlayView.addGestureRecognizer(tapGesture) - } + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTooltipTap(_:))) + tooltipView.addGestureRecognizer(tapGesture) - @objc private func dismissOverlay(_ sender: UITapGestureRecognizer) { - sender.view?.removeFromSuperview() + activeTooltipView = tooltipView + activeInfoButton = sourceView + } + + @objc private func handleTooltipTap(_ gesture: UITapGestureRecognizer) { + dismissTooltip() + } + + private func dismissTooltip() { + activeTooltipView?.removeFromSuperview() + activeTooltipView = nil + activeInfoButton = nil } } diff --git a/FinniversKit/Sources/Extensions/UIKit/UIApplicationExtensions.swift b/FinniversKit/Sources/Extensions/UIKit/UIApplicationExtensions.swift deleted file mode 100644 index 9808e6eddb..0000000000 --- a/FinniversKit/Sources/Extensions/UIKit/UIApplicationExtensions.swift +++ /dev/null @@ -1,10 +0,0 @@ -import UIKit - -extension UIApplication { - public var firstWindow: UIWindow? { - if let scene = UIApplication.shared.connectedScenes.first as? UIWindowScene { - return scene.windows.first { $0.isKeyWindow } - } - return nil - } -}