wip
This commit is contained in:
parent
14a83ca1d8
commit
9c5c54e09e
|
@ -1,10 +1,10 @@
|
|||
import Foundation
|
||||
|
||||
enum FileAction: Stateable {
|
||||
case downloadAttachmentFile(id: String, attachmentRemotePath: URL)
|
||||
case attachmentFileDownloaded(id: String, localUrl: URL)
|
||||
case downloadingAttachmentFileFailed(id: String, reason: String)
|
||||
case downloadAttachmentFile(messageId: String, attachmentRemotePath: URL)
|
||||
case attachmentFileDownloaded(messageId: String, localName: String)
|
||||
case downloadingAttachmentFileFailed(messageId: String, reason: String)
|
||||
|
||||
case createAttachmentThumbnail(id: String, localUrl: URL)
|
||||
case attachmentThumbnailCreated(id: String, thumbnailUrl: URL)
|
||||
case createAttachmentThumbnail(messageId: String, localName: String)
|
||||
case attachmentThumbnailCreated(messageId: String, thumbnailName: String)
|
||||
}
|
||||
|
|
|
@ -59,9 +59,9 @@ extension Database {
|
|||
table.column("pending", .boolean).notNull()
|
||||
table.column("sentError", .boolean).notNull()
|
||||
table.column("attachmentType", .integer)
|
||||
table.column("attachmentLocalPath", .text)
|
||||
table.column("attachmentLocalName", .text)
|
||||
table.column("attachmentRemotePath", .text)
|
||||
table.column("attachmentThumbnailPath", .text)
|
||||
table.column("attachmentThumbnailName", .text)
|
||||
table.column("attachmentDownloadFailed", .boolean).notNull().defaults(to: false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,19 +14,18 @@ final class FileProcessing {
|
|||
return subdirectoryURL
|
||||
}
|
||||
|
||||
func createThumbnail(localUrl: URL) -> URL? {
|
||||
let fileExtension = localUrl.pathExtension
|
||||
let fileNameWithoutExtension = localUrl.deletingPathExtension().lastPathComponent
|
||||
let thumbnailFileName = fileNameWithoutExtension + "_thumb." + fileExtension
|
||||
func createThumbnail(localName: String) -> String? {
|
||||
let thumbnailFileName = "thumb_\(localName)"
|
||||
let thumbnailUrl = FileProcessing.fileFolder.appendingPathComponent(thumbnailFileName)
|
||||
let localUrl = FileProcessing.fileFolder.appendingPathComponent(localName)
|
||||
|
||||
// check if thumbnail already exists
|
||||
if FileManager.default.fileExists(atPath: thumbnailUrl.path) {
|
||||
return thumbnailUrl
|
||||
return thumbnailFileName
|
||||
}
|
||||
|
||||
// create thumbnail if not exists
|
||||
switch localUrl.lastPathComponent.attachmentType {
|
||||
switch localName.attachmentType {
|
||||
case .image:
|
||||
guard let image = UIImage(contentsOfFile: localUrl.path) else { return nil }
|
||||
let targetSize = CGSize(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize)
|
||||
|
@ -34,7 +33,7 @@ final class FileProcessing {
|
|||
guard let data = thumbnail.pngData() else { return nil }
|
||||
do {
|
||||
try data.write(to: thumbnailUrl)
|
||||
return thumbnailUrl
|
||||
return thumbnailFileName
|
||||
} catch {
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ final class DatabaseMiddleware {
|
|||
.store(in: &cancellables)
|
||||
}
|
||||
|
||||
// swiftlint:disable:next function_body_length
|
||||
// swiftlint:disable:next function_body_length cyclomatic_complexity
|
||||
func middleware(state _: AppState, action: AppAction) -> AnyPublisher<AppAction, Never> {
|
||||
switch action {
|
||||
// MARK: Accounts
|
||||
|
@ -309,7 +309,7 @@ final class DatabaseMiddleware {
|
|||
}
|
||||
.eraseToAnyPublisher()
|
||||
|
||||
case .fileAction(.attachmentFileDownloaded(let id, let localUrl)):
|
||||
case .fileAction(.attachmentFileDownloaded(let id, let localName)):
|
||||
return Future<AppAction, Never> { promise in
|
||||
Task(priority: .background) { [weak self] in
|
||||
guard let database = self?.database else {
|
||||
|
@ -321,7 +321,7 @@ final class DatabaseMiddleware {
|
|||
_ = try database._db.write { db in
|
||||
try Message
|
||||
.filter(Column("id") == id)
|
||||
.updateAll(db, Column("attachmentLocalPath").set(to: localUrl), Column("attachmentDownloadFailed").set(to: false))
|
||||
.updateAll(db, Column("attachmentLocalName").set(to: localName), Column("attachmentDownloadFailed").set(to: false))
|
||||
}
|
||||
promise(.success(.empty))
|
||||
} catch {
|
||||
|
@ -332,7 +332,7 @@ final class DatabaseMiddleware {
|
|||
}
|
||||
.eraseToAnyPublisher()
|
||||
|
||||
case .fileAction(.attachmentThumbnailCreated(let id, let thumbnailUrl)):
|
||||
case .fileAction(.attachmentThumbnailCreated(let id, let thumbnailName)):
|
||||
return Future<AppAction, Never> { promise in
|
||||
Task(priority: .background) { [weak self] in
|
||||
guard let database = self?.database else {
|
||||
|
@ -344,7 +344,7 @@ final class DatabaseMiddleware {
|
|||
_ = try database._db.write { db in
|
||||
try Message
|
||||
.filter(Column("id") == id)
|
||||
.updateAll(db, Column("attachmentThumbnailPath").set(to: thumbnailUrl))
|
||||
.updateAll(db, Column("attachmentThumbnailName").set(to: thumbnailName))
|
||||
}
|
||||
promise(.success(.empty))
|
||||
} catch {
|
||||
|
|
|
@ -21,7 +21,7 @@ final class FileMiddleware {
|
|||
wSelf.downloadingMessageIDs.insert(message.id)
|
||||
DispatchQueue.main.async {
|
||||
// swiftlint:disable:next force_unwrapping
|
||||
store.dispatch(.fileAction(.downloadAttachmentFile(id: message.id, attachmentRemotePath: message.attachmentRemotePath!)))
|
||||
store.dispatch(.fileAction(.downloadAttachmentFile(messageId: message.id, attachmentRemotePath: message.attachmentRemotePath!)))
|
||||
}
|
||||
}
|
||||
promise(.success(.empty))
|
||||
|
@ -29,31 +29,32 @@ final class FileMiddleware {
|
|||
|
||||
case .fileAction(.downloadAttachmentFile(let id, let attachmentRemotePath)):
|
||||
return Future { promise in
|
||||
let localUrl = FileProcessing.fileFolder.appendingPathComponent(id).appendingPathExtension(attachmentRemotePath.pathExtension)
|
||||
let localName = "\(id)_\(UUID().uuidString)\(attachmentRemotePath.lastPathComponent)"
|
||||
let localUrl = FileProcessing.fileFolder.appendingPathComponent(localName)
|
||||
DownloadManager.shared.enqueueDownload(from: attachmentRemotePath, to: localUrl) { error in
|
||||
DispatchQueue.main.async {
|
||||
if let error {
|
||||
store.dispatch(.fileAction(.downloadingAttachmentFileFailed(id: id, reason: error.localizedDescription)))
|
||||
store.dispatch(.fileAction(.downloadingAttachmentFileFailed(messageId: id, reason: error.localizedDescription)))
|
||||
} else {
|
||||
store.dispatch(.fileAction(.attachmentFileDownloaded(id: id, localUrl: localUrl)))
|
||||
store.dispatch(.fileAction(.attachmentFileDownloaded(messageId: id, localName: localName)))
|
||||
}
|
||||
}
|
||||
}
|
||||
promise(.success(.empty))
|
||||
}.eraseToAnyPublisher()
|
||||
|
||||
case .fileAction(.attachmentFileDownloaded(let id, let localUrl)):
|
||||
case .fileAction(.attachmentFileDownloaded(let id, let localName)):
|
||||
return Future { [weak self] promise in
|
||||
self?.downloadingMessageIDs.remove(id)
|
||||
promise(.success(.fileAction(.createAttachmentThumbnail(id: id, localUrl: localUrl))))
|
||||
promise(.success(.fileAction(.createAttachmentThumbnail(messageId: id, localName: localName))))
|
||||
}
|
||||
.eraseToAnyPublisher()
|
||||
|
||||
case .fileAction(.createAttachmentThumbnail(let id, let localUrl)):
|
||||
case .fileAction(.createAttachmentThumbnail(let id, let localName)):
|
||||
return Future { [weak self] promise in
|
||||
if let thumbnailUrl = FileProcessing.shared.createThumbnail(localUrl: localUrl) {
|
||||
if let thumbnailName = FileProcessing.shared.createThumbnail(localName: localName) {
|
||||
self?.downloadingMessageIDs.remove(id)
|
||||
promise(.success(.fileAction(.attachmentThumbnailCreated(id: id, thumbnailUrl: thumbnailUrl))))
|
||||
promise(.success(.fileAction(.attachmentThumbnailCreated(messageId: id, thumbnailName: thumbnailName))))
|
||||
} else {
|
||||
self?.downloadingMessageIDs.remove(id)
|
||||
promise(.success(.empty))
|
||||
|
|
|
@ -42,9 +42,9 @@ struct Message: DBStorable, Equatable {
|
|||
let sentError: Bool
|
||||
|
||||
var attachmentType: MessageAttachmentType?
|
||||
var attachmentLocalPath: URL?
|
||||
var attachmentLocalName: String?
|
||||
var attachmentRemotePath: URL?
|
||||
var attachmentThumbnailPath: URL?
|
||||
var attachmentThumbnailName: String?
|
||||
var attachmentDownloadFailed: Bool = false
|
||||
}
|
||||
|
||||
|
@ -96,9 +96,9 @@ extension Message {
|
|||
pending: false,
|
||||
sentError: false,
|
||||
attachmentType: nil,
|
||||
attachmentLocalPath: nil,
|
||||
attachmentLocalName: nil,
|
||||
attachmentRemotePath: nil,
|
||||
attachmentThumbnailPath: nil,
|
||||
attachmentThumbnailName: nil,
|
||||
attachmentDownloadFailed: false
|
||||
)
|
||||
if let oob = martinMessage.oob {
|
||||
|
@ -108,3 +108,15 @@ extension Message {
|
|||
return msg
|
||||
}
|
||||
}
|
||||
|
||||
extension Message {
|
||||
var attachmentLocalPath: URL? {
|
||||
guard let attachmentLocalName = attachmentLocalName else { return nil }
|
||||
return FileProcessing.fileFolder.appendingPathComponent(attachmentLocalName)
|
||||
}
|
||||
|
||||
var attachmentThumbnailPath: URL? {
|
||||
guard let attachmentThumbnailName = attachmentThumbnailName else { return nil }
|
||||
return FileProcessing.fileFolder.appendingPathComponent(attachmentThumbnailName)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,8 +88,6 @@ private struct AttachmentView: View {
|
|||
if let file = message.attachmentLocalPath {
|
||||
VideoPlayerView(url: file)
|
||||
.frame(width: Const.attachmentPreviewSize, height: Const.attachmentPreviewSize)
|
||||
.cornerRadius(Const.attachmentPreviewSize / 10)
|
||||
.overlay(RoundedRectangle(cornerRadius: Const.attachmentPreviewSize / 10).stroke(Color.Material.Shape.separator, lineWidth: 1))
|
||||
} else {
|
||||
placeholder
|
||||
}
|
||||
|
@ -135,7 +133,7 @@ private struct AttachmentView: View {
|
|||
}
|
||||
.onTapGesture {
|
||||
if let url = message.attachmentRemotePath {
|
||||
store.dispatch(.fileAction(.downloadAttachmentFile(id: message.id, attachmentRemotePath: url)))
|
||||
store.dispatch(.fileAction(.downloadAttachmentFile(messageId: message.id, attachmentRemotePath: url)))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -160,12 +158,14 @@ private struct AttachmentView: View {
|
|||
}
|
||||
}
|
||||
|
||||
// TODO: Make video player better!
|
||||
private struct VideoPlayerView: UIViewControllerRepresentable {
|
||||
let url: URL
|
||||
|
||||
func makeUIViewController(context _: Context) -> AVPlayerViewController {
|
||||
let controller = AVPlayerViewController()
|
||||
controller.player = AVPlayer(url: url)
|
||||
controller.allowsPictureInPicturePlayback = true
|
||||
return controller
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue