This commit is contained in:
fmodf 2024-07-13 16:23:03 +02:00
parent d2b536509a
commit ae7a13e92b
3 changed files with 82 additions and 25 deletions

View file

@ -4,12 +4,21 @@ import UIKit
final class FileMiddleware { final class FileMiddleware {
static let shared = FileMiddleware() static let shared = FileMiddleware()
private var downloadingMessageIDs = ThreadSafeSet<String>()
func middleware(state _: AppState, action: AppAction) -> AnyPublisher<AppAction, Never> { func middleware(state _: AppState, action: AppAction) -> AnyPublisher<AppAction, Never> {
switch action { switch action {
case .conversationAction(.messagesUpdated(let messages)): case .conversationAction(.messagesUpdated(let messages)):
return Future { promise in return Future { [weak self] promise in
guard let wSelf = self else {
promise(.success(.empty))
return
}
for message in messages where message.attachmentRemotePath != nil && message.attachmentLocalPath == nil { for message in messages where message.attachmentRemotePath != nil && message.attachmentLocalPath == nil {
if wSelf.downloadingMessageIDs.contains(message.id) {
continue
}
wSelf.downloadingMessageIDs.insert(message.id)
DispatchQueue.main.async { DispatchQueue.main.async {
// swiftlint:disable:next force_unwrapping // swiftlint:disable:next force_unwrapping
store.dispatch(.fileAction(.downloadAttachmentFile(id: message.id, attachmentRemotePath: message.attachmentRemotePath!))) store.dispatch(.fileAction(.downloadAttachmentFile(id: message.id, attachmentRemotePath: message.attachmentRemotePath!)))
@ -34,14 +43,19 @@ final class FileMiddleware {
}.eraseToAnyPublisher() }.eraseToAnyPublisher()
case .fileAction(.attachmentFileDownloaded(let id, let localUrl)): case .fileAction(.attachmentFileDownloaded(let id, let localUrl)):
return Just(.fileAction(.createAttachmentThumbnail(id: id, localUrl: localUrl))) return Future { [weak self] promise in
self?.downloadingMessageIDs.remove(id)
promise(.success(.fileAction(.createAttachmentThumbnail(id: id, localUrl: localUrl))))
}
.eraseToAnyPublisher() .eraseToAnyPublisher()
case .fileAction(.createAttachmentThumbnail(let id, let localUrl)): case .fileAction(.createAttachmentThumbnail(let id, let localUrl)):
return Future { promise in return Future { [weak self] promise in
if let thumbnailUrl = FileProcessing.shared.createThumbnail(id: id, localUrl: localUrl) { if let thumbnailUrl = FileProcessing.shared.createThumbnail(id: id, localUrl: localUrl) {
self?.downloadingMessageIDs.remove(id)
promise(.success(.fileAction(.attachmentThumbnailCreated(id: id, thumbnailUrl: thumbnailUrl)))) promise(.success(.fileAction(.attachmentThumbnailCreated(id: id, thumbnailUrl: thumbnailUrl))))
} else { } else {
self?.downloadingMessageIDs.remove(id)
promise(.success(.empty)) promise(.success(.empty))
} }
} }

View file

@ -0,0 +1,26 @@
import Foundation
class ThreadSafeSet<T: Hashable> {
private var set: Set<T> = []
private let accessQueue = DispatchQueue(label: "com.example.ThreadSafeSet")
func insert(_ newElement: T) {
_ = accessQueue.sync {
set.insert(newElement)
}
}
func remove(_ element: T) {
_ = accessQueue.sync {
set.remove(element)
}
}
var elements: Set<T> {
accessQueue.sync { set }
}
func contains(_ element: T) -> Bool {
accessQueue.sync { set.contains(element) }
}
}

View file

@ -70,6 +70,9 @@ private struct AttachmentView: View {
let message: Message let message: Message
var body: some View { var body: some View {
if message.attachmentDownloadFailed {
failed
} else {
switch message.attachmentType { switch message.attachmentType {
case .image: case .image:
if let thumbnail = thumbnail() { if let thumbnail = thumbnail() {
@ -95,6 +98,7 @@ private struct AttachmentView: View {
placeholder placeholder
} }
} }
}
@ViewBuilder private var placeholder: some View { @ViewBuilder private var placeholder: some View {
Rectangle() Rectangle()
@ -113,6 +117,19 @@ private struct AttachmentView: View {
} }
} }
@ViewBuilder private var failed: some View {
Rectangle()
.foregroundColor(.Material.Background.dark)
.frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize)
.overlay {
ZStack {
Image(systemName: "exclamationmark.triangle")
.font(.body1)
.foregroundColor(.Rainbow.red500)
}
}
}
private func progressImageName(_ type: MessageAttachmentType) -> String { private func progressImageName(_ type: MessageAttachmentType) -> String {
switch type { switch type {
case .image: case .image: