TM-SGNL-iOS/SignalServiceKit/VoiceMessage/VoiceMessageInterruptedDraftStore.swift
TeleMessage developers dde0620daf initial commit
2025-05-03 12:28:28 -07:00

94 lines
3.8 KiB
Swift

//
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//
import Foundation
public class VoiceMessageInterruptedDraftStore {
private init() { }
public static let draftVoiceMessageDirectory = URL(
fileURLWithPath: "draft-voice-messages",
isDirectory: true,
relativeTo: URL(
fileURLWithPath: CurrentAppContext().appSharedDataDirectoryPath(),
isDirectory: true
)
)
public enum Constants {
public static let audioFilename = "voice-memo.\(VoiceMessageConstants.fileExtension)"
public static let waveformFilename = "waveform.dat"
}
// MARK: -
private static func directoryUrl(relativePath: String) -> URL {
return URL(fileURLWithPath: relativePath, isDirectory: true, relativeTo: Self.draftVoiceMessageDirectory)
}
private static func directoryPath(threadUniqueId: String, transaction: SDSAnyReadTransaction) -> String? {
keyValueStore.getString(threadUniqueId, transaction: transaction.asV2Read)
}
public static func directoryUrl(threadUniqueId: String, transaction: SDSAnyReadTransaction) -> URL? {
guard let relativePath = directoryPath(threadUniqueId: threadUniqueId, transaction: transaction) else {
return nil
}
return directoryUrl(relativePath: relativePath)
}
// MARK: -
private static var keyValueStore: KeyValueStore { .init(collection: "DraftVoiceMessage") }
public static func hasDraft(for thread: TSThread, transaction: SDSAnyReadTransaction) -> Bool {
hasDraft(for: thread.uniqueId, transaction: transaction)
}
public static func hasDraft(for threadUniqueId: String, transaction: SDSAnyReadTransaction) -> Bool {
keyValueStore.getString(threadUniqueId, transaction: transaction.asV2Read) != nil
}
public static func allDraftFilePaths(transaction: SDSAnyReadTransaction) -> Set<String> {
return Set(keyValueStore.allKeys(transaction: transaction.asV2Read).compactMap { (threadUniqueId) -> [String]? in
guard let directoryPath = self.directoryPath(threadUniqueId: threadUniqueId, transaction: transaction) else {
return nil
}
return [
directoryPath.appendingPathComponent(Constants.audioFilename),
directoryPath.appendingPathComponent(Constants.waveformFilename)
]
}.reduce([], +))
}
public static func clearDraft(for thread: TSThread, transaction: SDSAnyWriteTransaction) {
clearDraft(for: thread.uniqueId, transaction: transaction)
}
public static func clearDraft(for threadUniqueId: String, transaction: SDSAnyWriteTransaction) {
if let directoryUrl = self.directoryUrl(threadUniqueId: threadUniqueId, transaction: transaction) {
do {
try OWSFileSystem.deleteFileIfExists(url: directoryUrl)
} catch {
owsFailDebug("Failed to delete voice memo draft")
}
}
keyValueStore.removeValue(forKey: threadUniqueId, transaction: transaction.asV2Write)
}
public static func saveDraft(audioFileUrl: URL, threadUniqueId: String, transaction: SDSAnyWriteTransaction) -> URL {
let relativeDirectoryPath = UUID().uuidString
keyValueStore.setString(relativeDirectoryPath, key: threadUniqueId, transaction: transaction.asV2Write)
let directoryUrl = directoryUrl(relativePath: relativeDirectoryPath)
do {
OWSFileSystem.ensureDirectoryExists(directoryUrl.path)
try OWSFileSystem.moveFile(from: audioFileUrl, to: directoryUrl.appendingPathComponent(Constants.audioFilename))
} catch {
owsFailDebug("Failed to move voice memo draft")
}
return directoryUrl
}
}