Files
damus/damus/Views/BannerImageView.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

115 lines
3.6 KiB
Swift

//
// BannerImageView.swift
// damus
//
// Created by Jason Jōb on 2023-01-10.
//
import SwiftUI
import Kingfisher
struct EditBannerImageView: View {
var damus_state: DamusState
@ObservedObject var viewModel: ImageUploadingObserver
let callback: (URL?) -> Void
let defaultImage = UIImage(named: "damoose") ?? UIImage()
@State var banner_image: URL? = nil
var body: some View {
ZStack {
Color(uiColor: .systemBackground)
KFAnimatedImage(get_banner_url(banner: banner_image?.absoluteString, pubkey: damus_state.pubkey, profiles: damus_state.profiles))
.imageContext(.banner, disable_animation: damus_state.settings.disable_animation)
.configure { view in
view.framePreloadCount = .max
}
.placeholder { _ in
Color(uiColor: .secondarySystemBackground)
}
.onFailureImage(defaultImage)
.kfClickable()
EditPictureControl(uploader: damus_state.settings.default_media_uploader, pubkey: damus_state.pubkey, image_url: $banner_image, uploadObserver: viewModel, callback: callback)
}
}
}
struct InnerBannerImageView: View {
let disable_animation: Bool
let url: URL?
let defaultImage = UIImage(named: "damoose") ?? UIImage()
var body: some View {
ZStack {
Color(uiColor: .systemBackground)
if (url != nil) {
KFAnimatedImage(url)
.imageContext(.banner, disable_animation: disable_animation)
.configure { view in
view.framePreloadCount = 3
}
.placeholder { _ in
Color(uiColor: .secondarySystemBackground)
}
.onFailureImage(defaultImage)
.kfClickable()
} else {
Image(uiImage: defaultImage).resizable()
}
}
}
}
struct BannerImageView: View {
let disable_animation: Bool
let pubkey: Pubkey
let profiles: Profiles
@State var banner: String?
init(pubkey: Pubkey, profiles: Profiles, disable_animation: Bool, banner: String? = nil) {
self.pubkey = pubkey
self.profiles = profiles
self._banner = State(initialValue: banner)
self.disable_animation = disable_animation
}
var body: some View {
InnerBannerImageView(disable_animation: disable_animation, url: get_banner_url(banner: banner, pubkey: pubkey, profiles: profiles))
.onReceive(handle_notify(.profile_updated)) { updated in
guard updated.pubkey == self.pubkey,
let profile_txn = profiles.lookup(id: updated.pubkey)
else {
return
}
let profile = profile_txn.unsafeUnownedValue
if let bannerImage = profile?.banner, bannerImage != self.banner {
self.banner = bannerImage
}
}
}
}
func get_banner_url(banner: String?, pubkey: Pubkey, profiles: Profiles) -> URL? {
let bannerUrlString = banner ?? profiles.lookup(id: pubkey)?.map({ p in p?.banner }).value ?? ""
if let url = URL(string: bannerUrlString) {
return url
}
return nil
}
struct BannerImageView_Previews: PreviewProvider {
static var previews: some View {
BannerImageView(
pubkey: test_pubkey,
profiles: make_preview_profiles(test_pubkey),
disable_animation: false
)
}
}