mirror of
https://github.com/bitwarden/ios.git
synced 2025-12-11 13:54:06 -06:00
117 lines
2.8 KiB
Swift
117 lines
2.8 KiB
Swift
import Combine
|
|
import Foundation
|
|
import SwiftUI
|
|
|
|
/// Image view to be used on watchOS < 8
|
|
///
|
|
/// - Note: Based on: https://stackoverflow.com/questions/60710997/images-disappear-in-list-as-i-scroll-swiftui-swift
|
|
///
|
|
struct ImageView<PlaceholderView: View>: View {
|
|
@ObservedObject var imageLoader: ImageLoader
|
|
var imgMaxWidth: CGFloat
|
|
var imgMaxHeight: CGFloat
|
|
var placeholder: PlaceholderView
|
|
|
|
init(
|
|
withURL url: String,
|
|
maxWidth mw: CGFloat,
|
|
maxHeight mh: CGFloat,
|
|
@ViewBuilder _ placeholder: () -> PlaceholderView,
|
|
) {
|
|
imageLoader = ImageLoader(urlString: url)
|
|
imgMaxWidth = mw
|
|
imgMaxHeight = mh
|
|
self.placeholder = placeholder()
|
|
}
|
|
|
|
var body: some View {
|
|
if imageLoader.image == nil {
|
|
placeholder
|
|
} else {
|
|
Image(uiImage: imageLoader.image!)
|
|
.resizable()
|
|
.aspectRatio(contentMode: .fit)
|
|
.frame(maxWidth: imgMaxWidth, maxHeight: imgMaxHeight)
|
|
}
|
|
}
|
|
}
|
|
|
|
class ImageLoader: ObservableObject {
|
|
@Published var image: UIImage?
|
|
var urlString: String?
|
|
var imageCache = ImageCache.getImageCache()
|
|
|
|
init(urlString: String?) {
|
|
self.urlString = urlString
|
|
loadImage()
|
|
}
|
|
|
|
func loadImage() {
|
|
if loadImageFromCache() {
|
|
return
|
|
}
|
|
|
|
loadImageFromUrl()
|
|
}
|
|
|
|
func loadImageFromCache() -> Bool {
|
|
guard let urlString else {
|
|
return false
|
|
}
|
|
|
|
guard let cacheImage = imageCache.get(forKey: urlString) else {
|
|
return false
|
|
}
|
|
|
|
image = cacheImage
|
|
return true
|
|
}
|
|
|
|
func loadImageFromUrl() {
|
|
guard let urlString else {
|
|
return
|
|
}
|
|
|
|
let url = URL(string: urlString)!
|
|
let task = URLSession.shared.dataTask(with: url, completionHandler: getImageFromResponse(data:response:error:))
|
|
task.resume()
|
|
}
|
|
|
|
func getImageFromResponse(data: Data?, response _: URLResponse?, error: Error?) {
|
|
guard error == nil else {
|
|
return
|
|
}
|
|
guard let data else {
|
|
return
|
|
}
|
|
|
|
DispatchQueue.main.async {
|
|
guard let loadedImage = UIImage(data: data) else {
|
|
return
|
|
}
|
|
|
|
self.imageCache.set(forKey: self.urlString!, image: loadedImage)
|
|
self.image = loadedImage
|
|
}
|
|
}
|
|
}
|
|
|
|
class ImageCache {
|
|
var cache = NSCache<NSString, UIImage>()
|
|
|
|
func get(forKey: String) -> UIImage? {
|
|
cache.object(forKey: NSString(string: forKey))
|
|
}
|
|
|
|
func set(forKey: String, image: UIImage) {
|
|
cache.setObject(image, forKey: NSString(string: forKey))
|
|
}
|
|
}
|
|
|
|
extension ImageCache {
|
|
private static var imageCache = ImageCache()
|
|
static func getImageCache() -> ImageCache {
|
|
imageCache
|
|
}
|
|
}
|