Files
damus/damus/Views/Relays/RelayPicView.swift
Daniel D’Aquino 823c2565da Fix unclickable elements
The introduction of iOS 18 brought a new bug that made `KFAnimatedImage`
not recognize tap gestures and become unclickable. (https://github.com/onevcat/Kingfisher/issues/2295)

This commit addresses the issue with a workaround found here:
https://github.com/onevcat/Kingfisher/issues/2046#issuecomment-1554068070

The workaround was suggested by the author of the library to fix a
slightly different issue, but that property seems to work for our
purposes.

The issue is addressed by adding a `contentShape` property to usages
of `KFAnimatedImage`, in order to make them clickable. A custom modifier
was created to make the solution less obscure and more obvious.

Furthermore, one empty tap gesture handler was removed as it was
preventing other tap gesture handlers on the image carousel from being
triggered on iOS 18

Testing
-------

PASS

Configurations:
- iPhone 13 mini on iOS 18.0
- iPhone SE simulator on iOS 17.5
Damus: This commit
Coverage:
- Check that the following views are clickable:
    - Images in the carousel
    - Profile picture on notes
    - Profile picture on thread comments
    - Profile picture on profile page

Changelog-Fixed: Fix items that became unclickable on iOS 18
Closes: https://github.com/damus-io/damus/issues/2342
Closes: https://github.com/damus-io/damus/issues/2370
Signed-off-by: Daniel D’Aquino <daniel@daquino.me>
2024-09-20 20:02:24 -07:00

131 lines
3.8 KiB
Swift

//
// RelayPicView.swift
// damus
//
// Created by eric on 9/2/23.
//
import SwiftUI
import Kingfisher
struct FailedRelayImage: View {
let url: URL?
var body: some View {
let abbrv = String(url?.host()?.first?.uppercased() ?? "R")
Text(abbrv)
.font(.system(size: 40, weight: .bold))
}
}
struct InnerRelayPicView: View {
let url: URL?
let size: CGFloat
let highlight: Highlight
let disable_animation: Bool
@State var failedImage: Bool = false
func Placeholder(url: URL?) -> some View {
ZStack {
RoundedRectangle(cornerRadius: 15)
.frame(width: size, height: size)
.foregroundColor(DamusColors.adaptableGrey)
.overlay(RoundedRectangle(cornerRadius: 15).stroke(highlight_color(highlight), lineWidth: pfp_line_width(highlight)))
.padding(2)
FailedRelayImage(url: url)
}
}
var body: some View {
ZStack {
Color(uiColor: .secondarySystemBackground)
if let url {
KFAnimatedImage(url)
.imageContext(.pfp, disable_animation: disable_animation)
.onFailure { _ in
failedImage = true
}
.cancelOnDisappear(true)
.configure { view in
view.framePreloadCount = 3
}
.placeholder { _ in
Placeholder(url: url)
}
.scaledToFit()
.kfClickable()
} else {
FailedRelayImage(url: nil)
}
}
.frame(width: size, height: size)
.clipShape(RoundedRectangle(cornerRadius: 15))
.overlay(RoundedRectangle(cornerRadius: 15).stroke(.gray.opacity(0.5), lineWidth: 0.5))
}
}
struct RelayPicView: View {
let relay: RelayURL
let icon: String?
let size: CGFloat
let highlight: Highlight
let disable_animation: Bool
init(relay: RelayURL, icon: String? = nil, size: CGFloat, highlight: Highlight, disable_animation: Bool) {
self.relay = relay
self.icon = icon
self.size = size
self.highlight = highlight
self.disable_animation = disable_animation
}
var relay_url: URL? {
get_relay_url(relay: relay, icon: icon)
}
var body: some View {
InnerRelayPicView(url: relay_url, size: size, highlight: highlight, disable_animation: disable_animation)
}
}
func extract_tld(_ host: String) -> String {
let parts = host.split(separator: ".")
if parts.count >= 3 {
let last_3 = parts.suffix(3)
if parts[1] == "co" && parts[2] == "uk" {
return String(last_3.joined(separator: "."))
} else {
return String(parts.suffix(2).joined(separator: "."))
}
} else if parts.count == 2 {
return host
}
return host
}
func get_relay_url(relay: RelayURL, icon: String?) -> URL? {
var favicon = relay.absoluteString + "/favicon.ico"
let tld = extract_tld(relay.absoluteString)
if tld != relay.absoluteString {
favicon = "https://" + tld + "/favicon.ico"
}
let pic = icon ?? favicon
return URL(string: pic)
}
struct RelayPicView_Previews: PreviewProvider {
static var previews: some View {
VStack {
RelayPicView(relay: RelayURL("wss://relay.damus.io")!, size: 55, highlight: .none, disable_animation: false)
RelayPicView(relay: RelayURL("wss://nostr.wine")!, size: 55, highlight: .none, disable_animation: false)
RelayPicView(relay: RelayURL("wss://nos.lol")!, size: 55, highlight: .none, disable_animation: false)
RelayPicView(relay: RelayURL("wss://fail.com")!, size: 55, highlight: .none, disable_animation: false)
}
}
}