add cache photo
This commit is contained in:
parent
ff2061f86e
commit
aa157031a1
@ -1,5 +1,8 @@
|
||||
import Foundation
|
||||
import SwiftUICore
|
||||
import Security
|
||||
import UIKit
|
||||
import Combine
|
||||
|
||||
|
||||
//let username = "user1"
|
||||
@ -111,3 +114,117 @@ class KeychainService {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AvatarCacheService {
|
||||
static let shared = AvatarCacheService()
|
||||
private let fileManager = FileManager.default
|
||||
private var baseCacheDirectory: URL? {
|
||||
fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first?.appendingPathComponent("avatar_cache")
|
||||
}
|
||||
|
||||
private init() {}
|
||||
|
||||
private func cacheDirectory(for userId: String) -> URL? {
|
||||
baseCacheDirectory?.appendingPathComponent(userId)
|
||||
}
|
||||
|
||||
private func filePath(forKey key: String, userId: String) -> URL? {
|
||||
cacheDirectory(for: userId)?.appendingPathComponent(key)
|
||||
}
|
||||
|
||||
func getImage(forKey key: String, userId: String) -> UIImage? {
|
||||
guard let url = filePath(forKey: key, userId: userId),
|
||||
fileManager.fileExists(atPath: url.path),
|
||||
let data = try? Data(contentsOf: url) else {
|
||||
return nil
|
||||
}
|
||||
return UIImage(data: data)
|
||||
}
|
||||
|
||||
func saveImage(_ image: UIImage, forKey key: String, userId: String) {
|
||||
guard let directory = cacheDirectory(for: userId),
|
||||
let url = filePath(forKey: key, userId: userId),
|
||||
let data = image.jpegData(compressionQuality: 0.8) else {
|
||||
return
|
||||
}
|
||||
|
||||
if !fileManager.fileExists(atPath: directory.path) {
|
||||
try? fileManager.createDirectory(at: directory, withIntermediateDirectories: true, attributes: nil)
|
||||
}
|
||||
|
||||
try? data.write(to: url)
|
||||
}
|
||||
|
||||
func clearCache(forUserId userId: String) {
|
||||
guard let directory = cacheDirectory(for: userId) else { return }
|
||||
try? fileManager.removeItem(at: directory)
|
||||
}
|
||||
|
||||
func clearAllCache() {
|
||||
guard let directory = baseCacheDirectory else { return }
|
||||
try? fileManager.removeItem(at: directory)
|
||||
}
|
||||
}
|
||||
|
||||
class ImageLoader: ObservableObject {
|
||||
@Published var image: UIImage?
|
||||
|
||||
private let url: URL
|
||||
private let fileId: String
|
||||
private let userId: String
|
||||
private var cancellable: AnyCancellable?
|
||||
private let cache = AvatarCacheService.shared
|
||||
|
||||
init(url: URL, fileId: String, userId: String) {
|
||||
self.url = url
|
||||
self.fileId = fileId
|
||||
self.userId = userId
|
||||
}
|
||||
|
||||
deinit {
|
||||
cancellable?.cancel()
|
||||
}
|
||||
|
||||
func load() {
|
||||
if let cachedImage = cache.getImage(forKey: fileId, userId: userId) {
|
||||
self.image = cachedImage
|
||||
return
|
||||
}
|
||||
|
||||
cancellable = URLSession.shared.dataTaskPublisher(for: url)
|
||||
.map { UIImage(data: $0.data) }
|
||||
.replaceError(with: nil)
|
||||
.receive(on: DispatchQueue.main)
|
||||
.sink { [weak self] loadedImage in
|
||||
guard let self = self, let image = loadedImage else { return }
|
||||
self.image = image
|
||||
self.cache.saveImage(image, forKey: self.fileId, userId: self.userId)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct CachedAvatarView<Placeholder: View>: View {
|
||||
@StateObject private var loader: ImageLoader
|
||||
private let placeholder: Placeholder
|
||||
|
||||
init(url: URL, fileId: String, userId: String, @ViewBuilder placeholder: () -> Placeholder) {
|
||||
self.placeholder = placeholder()
|
||||
_loader = StateObject(wrappedValue: ImageLoader(url: url, fileId: fileId, userId: userId))
|
||||
}
|
||||
|
||||
var body: some View {
|
||||
content
|
||||
.onAppear(perform: loader.load)
|
||||
}
|
||||
|
||||
private var content: some View {
|
||||
Group {
|
||||
if let image = loader.image {
|
||||
Image(uiImage: image)
|
||||
.resizable()
|
||||
} else {
|
||||
placeholder
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1035,28 +1035,13 @@ private struct ChatRowView: View {
|
||||
|
||||
var body: some View {
|
||||
HStack(spacing: 12) {
|
||||
if #available(iOS 15.0, *) {
|
||||
if let url = avatarUrl {
|
||||
AsyncImage(url: url) { phase in
|
||||
switch phase {
|
||||
case .empty:
|
||||
if let url = avatarUrl, let fileId = chat.chatData?.avatars?.current?.fileId, let loggedInUserId = currentUserId {
|
||||
CachedAvatarView(url: url, fileId: fileId, userId: loggedInUserId) {
|
||||
placeholderAvatar
|
||||
case .success(let image):
|
||||
image
|
||||
.resizable()
|
||||
}
|
||||
.aspectRatio(contentMode: .fill)
|
||||
.frame(width: avatarSize, height: avatarSize)
|
||||
.clipShape(Circle())
|
||||
case .failure:
|
||||
placeholderAvatar
|
||||
@unknown default:
|
||||
placeholderAvatar
|
||||
}
|
||||
}
|
||||
.frame(width: avatarSize, height: avatarSize)
|
||||
} else {
|
||||
placeholderAvatar
|
||||
}
|
||||
} else {
|
||||
placeholderAvatar
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user