Skip to content

Commit

Permalink
added temporary voice messages
Browse files Browse the repository at this point in the history
related to #1261

Signed-off-by: Daniel Standfest <[email protected]>
  • Loading branch information
Daniel Standfest committed Dec 16, 2024
1 parent 3019dcf commit 365e2c7
Show file tree
Hide file tree
Showing 16 changed files with 304 additions and 60 deletions.
10 changes: 10 additions & 0 deletions NextcloudTalk.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,10 @@
DA66583127B6B24E00B46B11 /* UserProfileTableViewController+Utils.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA66583027B6B24E00B46B11 /* UserProfileTableViewController+Utils.swift */; };
DA75580F278EEA1000A48A1B /* SettingsTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA75580E278EEA1000A48A1B /* SettingsTableViewController.swift */; };
DA8801A227A2DA00009EF248 /* UserProfileTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = DA8801A127A2DA00009EF248 /* UserProfileTableViewController.swift */; };
F644A2DD2CE287FA00E2ED81 /* ChatFileUploader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F644A2DC2CE287FA00E2ED81 /* ChatFileUploader.swift */; };
F644A2DF2CE28C8D00E2ED81 /* NCChatFileStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FF4DA7F2C023FF300C1B952 /* NCChatFileStatus.swift */; };
F644A2E02CE28C9A00E2ED81 /* NCChatFileStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FF4DA7F2C023FF300C1B952 /* NCChatFileStatus.swift */; };
F644A2E12CE28CA500E2ED81 /* NCChatFileStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1FF4DA7F2C023FF300C1B952 /* NCChatFileStatus.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -1207,6 +1211,7 @@
DA66583027B6B24E00B46B11 /* UserProfileTableViewController+Utils.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UserProfileTableViewController+Utils.swift"; sourceTree = "<group>"; };
DA75580E278EEA1000A48A1B /* SettingsTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingsTableViewController.swift; sourceTree = "<group>"; };
DA8801A127A2DA00009EF248 /* UserProfileTableViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UserProfileTableViewController.swift; sourceTree = "<group>"; };
F644A2DC2CE287FA00E2ED81 /* ChatFileUploader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatFileUploader.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -2148,6 +2153,7 @@
1F35F8FA2AEEDBC600044BDA /* ChatViewControllerExtension.swift */,
2C4230F62B207AB00013E1FA /* ContextChatViewController.swift */,
1F0B0A712BA264540073FF8D /* MentionSuggestion.swift */,
F644A2DC2CE287FA00E2ED81 /* ChatFileUploader.swift */,
);
name = Chat;
sourceTree = "<group>";
Expand Down Expand Up @@ -2801,6 +2807,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F644A2E12CE28CA500E2ED81 /* NCChatFileStatus.swift in Sources */,
1F1B504B2B90CF0C00B0F2F4 /* FederatedCapabilities.m in Sources */,
1F77A5F22AB9A436007B6037 /* EmojiUtils.swift in Sources */,
1F77A5FA2AB9A4DF007B6037 /* NCMessageLocationParameter.m in Sources */,
Expand Down Expand Up @@ -3090,6 +3097,7 @@
2CB6ACBC26385A3800D3D641 /* ShareLocationViewController.m in Sources */,
2C04249B2CA33681004772F6 /* AudioPlayerView.swift in Sources */,
1F1B0F462BE047CE003FD766 /* InteractionControlling.swift in Sources */,
F644A2DD2CE287FA00E2ED81 /* ChatFileUploader.swift in Sources */,
1FDCC3D429EBF6E700DEB39B /* AvatarImageView.swift in Sources */,
1FB78E262B6AE5A600B0D69D /* FederationInvitation.swift in Sources */,
1FDFC94D2BA50B9100670DF4 /* UIFontExtension.swift in Sources */,
Expand Down Expand Up @@ -3117,6 +3125,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F644A2E02CE28C9A00E2ED81 /* NCChatFileStatus.swift in Sources */,
1F4DD3ED2571C688007DC98E /* EmojiUtils.swift in Sources */,
1F35F8EB2AEEBC1100044BDA /* UIResponder+SLKAdditions.m in Sources */,
2C62B02424C1BDCF007E460A /* NCAppBranding.m in Sources */,
Expand Down Expand Up @@ -3207,6 +3216,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
F644A2DF2CE28C8D00E2ED81 /* NCChatFileStatus.swift in Sources */,
2C1ABDCF257E939600AEDFB6 /* NCContact.m in Sources */,
2CC001DC24A37AD400A20167 /* NCAppBranding.m in Sources */,
2C4446D42658147900DF1DBC /* TalkAccount.m in Sources */,
Expand Down
4 changes: 2 additions & 2 deletions NextcloudTalk/BaseChatTableViewCell+Audio.swift
Original file line number Diff line number Diff line change
Expand Up @@ -30,11 +30,11 @@ extension BaseChatTableViewCell {
}

func audioPlayerPlayButtonPressed() {
guard let audioFileParameter = message?.file() else {
guard let audioFile = message else {
return
}

self.delegate?.cellWants(toPlayAudioFile: audioFileParameter)
self.delegate?.cellWants(toPlayAudioFile: audioFile)
}

func audioPlayerPauseButtonPressed() {
Expand Down
2 changes: 1 addition & 1 deletion NextcloudTalk/BaseChatTableViewCell.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ protocol BaseChatTableViewCellDelegate: AnyObject {

func cellWants(toOpenLocation geoLocationRichObject: GeoLocationRichObject)

func cellWants(toPlayAudioFile fileParameter: NCMessageFileParameter)
func cellWants(toPlayAudioFile message: NCChatMessage)
func cellWants(toPauseAudioFile fileParameter: NCMessageFileParameter)
func cellWants(toChangeProgress progress: CGFloat, fromAudioFile fileParameter: NCMessageFileParameter)

Expand Down
167 changes: 123 additions & 44 deletions NextcloudTalk/BaseChatViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -465,7 +465,7 @@ import QuickLook

// MARK: - Temporary messages

internal func createTemporaryMessage(message: String, replyTo parentMessage: NCChatMessage?, messageParameters: String, silently: Bool) -> NCChatMessage {
internal func createTemporaryMessage(message: String, replyTo parentMessage: NCChatMessage?, messageParameters: String, silently: Bool, isVoiceMessage: Bool) -> NCChatMessage {
let temporaryMessage = NCChatMessage()
let activeAccount = NCDatabaseManager.sharedInstance().activeAccount()

Expand All @@ -475,14 +475,41 @@ import QuickLook
temporaryMessage.actorType = "users"
temporaryMessage.timestamp = Int(Date().timeIntervalSince1970)
temporaryMessage.token = room.token
temporaryMessage.message = self.replaceMentionsDisplayNamesWithMentionsKeysInMessage(message: message, parameters: messageParameters)

let referenceId = "temp-\(Date().timeIntervalSince1970 * 1000)"
temporaryMessage.referenceId = NCUtils.sha1(fromString: referenceId)
temporaryMessage.internalId = referenceId
temporaryMessage.isTemporary = true
temporaryMessage.parentId = parentMessage?.internalId
temporaryMessage.messageParametersJSONString = messageParameters

if isVoiceMessage {
var messageParametersDict = [String: Any]()
let parameterId = UUID().uuidString

temporaryMessage.message = message
temporaryMessage.messageType = kMessageTypeVoiceMessage

let fileParameterDict: [String: Any] = [
"id": parameterId,
"type": "file",
"name": message,
"path": messageParameters,
"fileId": parameterId,
"fileName": message,
"filePath": messageParameters,
"fileLocalPath": messageParameters
]

messageParametersDict["file"] = fileParameterDict

if let jsonData = try? JSONSerialization.data(withJSONObject: messageParametersDict, options: []) {
let messageParametersJSONString = String(data: jsonData, encoding: .utf8) ?? ""
temporaryMessage.messageParametersJSONString = messageParametersJSONString
}
} else {
temporaryMessage.messageParametersJSONString = messageParameters
temporaryMessage.message = self.replaceMentionsDisplayNamesWithMentionsKeysInMessage(message: message, parameters: messageParameters)
}
temporaryMessage.isSilent = silently
temporaryMessage.isMarkdownMessage = NCDatabaseManager.sharedInstance().roomHasTalkCapability(kCapabilityMarkdownMessages, for: self.room)

Expand Down Expand Up @@ -954,8 +981,25 @@ import QuickLook
self.removeUnreadMessagesSeparator()

self.removePermanentlyTemporaryMessage(temporaryMessage: message)
let originalMessage = self.replaceMessageMentionsKeysWithMentionsDisplayNames(message: message.message, parameters: message.messageParametersJSONString ?? "")
self.sendChatMessage(message: originalMessage, withParentMessage: message.parent, messageParameters: message.messageParametersJSONString ?? "", silently: message.isSilent)
guard var originalMessage = message.message else { return }
if message.messageType != kMessageTypeVoiceMessage {
originalMessage = self.replaceMessageMentionsKeysWithMentionsDisplayNames(message: message.message, parameters: message.messageParametersJSONString ?? "")
self.sendChatMessage(message: originalMessage, withParentMessage: message.parent, messageParameters: message.messageParametersJSONString ?? "", silently: message.isSilent)
} else {
let activeAccount = NCDatabaseManager.sharedInstance().activeAccount()
if NCDatabaseManager.sharedInstance().roomHasTalkCapability(kCapabilityChatReferenceId, for: room) {
self.appendTemporaryMessage(temporaryMessage: message)
}
NCAPIController.sharedInstance().uniqueNameForFileUpload(withName: originalMessage, originalName: true, for: activeAccount, withCompletionBlock: { fileServerURL, fileServerPath, _, _ in
if let fileServerURL, let fileServerPath {
let talkMetaData: [String: String] = ["messageType": "voice-message"]

self.uploadFileAtPath(localPath: message.file().fileStatus!.fileLocalPath!, withFileServerURL: fileServerURL, andFileServerPath: fileServerPath, withMetaData: talkMetaData, temporaryMessage: message)
} else {
NSLog("Could not find unique name for voice message file.")
}
})
}
}

func didPressCopy(for message: NCChatMessage) {
Expand Down Expand Up @@ -1461,7 +1505,7 @@ import QuickLook

NCAPIController.sharedInstance().uniqueNameForFileUpload(withName: contactFileName, originalName: true, for: activeAccount) { fileServerURL, fileServerPath, _, _ in
if let fileServerURL, let fileServerPath {
self.uploadFileAtPath(localPath: url.path, withFileServerURL: fileServerURL, andFileServerPath: fileServerPath, withMetaData: nil)
self.uploadFileAtPath(localPath: url.path, withFileServerURL: fileServerURL, andFileServerPath: fileServerPath, withMetaData: nil, temporaryMessage: nil)
} else {
print("Could not find unique name for contact file")
}
Expand Down Expand Up @@ -1567,6 +1611,7 @@ import QuickLook
}

func shareVoiceMessage() {
guard let recorder = self.recorder else { return }
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH-mm-ss"
let dateString = dateFormatter.string(from: Date())
Expand All @@ -1590,52 +1635,76 @@ import QuickLook
audioFileName += ".mp3"

let activeAccount = NCDatabaseManager.sharedInstance().activeAccount()
let chatFileController = NCChatFileController()
chatFileController.initDownloadDirectory(for: activeAccount)

let tempDirectoryURL = URL(fileURLWithPath: chatFileController.tempDirectoryPath)
let destinationFilePath = tempDirectoryURL.appendingPathComponent(audioFileName).path

let temporaryMessage = self.createTemporaryMessage(
message: audioFileName,
replyTo: nil,
messageParameters: "\(destinationFilePath)",
silently: false,
isVoiceMessage: true
)

let movedFileToTemporaryDirectory = chatFileController.moveFileToTemporaryDirectory(
fromSourcePath: recorder.url.path,
destinationPath: destinationFilePath
)

if !movedFileToTemporaryDirectory {
print("Failed to move voice-message to temporary directory.")
return
}

if movedFileToTemporaryDirectory, NCDatabaseManager.sharedInstance().roomHasTalkCapability(kCapabilityChatReferenceId, for: room) {
self.appendTemporaryMessage(temporaryMessage: temporaryMessage)
}

NCAPIController.sharedInstance().uniqueNameForFileUpload(withName: audioFileName, originalName: true, for: activeAccount, withCompletionBlock: { fileServerURL, fileServerPath, _, _ in
if let fileServerURL, let fileServerPath, let recorder = self.recorder {
if let fileServerURL, let fileServerPath {
let talkMetaData: [String: String] = ["messageType": "voice-message"]
self.uploadFileAtPath(localPath: recorder.url.path, withFileServerURL: fileServerURL, andFileServerPath: fileServerPath, withMetaData: talkMetaData)

self.uploadFileAtPath(localPath: destinationFilePath, withFileServerURL: fileServerURL, andFileServerPath: fileServerPath, withMetaData: talkMetaData, temporaryMessage: temporaryMessage)
} else {
NSLog("Could not find unique name for voice message file.")
}
})
}

func uploadFileAtPath(localPath: String, withFileServerURL fileServerURL: String, andFileServerPath fileServerPath: String, withMetaData talkMetaData: [String: String]?) {
let activeAccount = NCDatabaseManager.sharedInstance().activeAccount()
NCAPIController.sharedInstance().setupNCCommunication(for: activeAccount)

NextcloudKit.shared.upload(serverUrlFileName: fileServerURL, fileNameLocalPath: localPath, taskHandler: { _ in
NSLog("Upload task")
}, progressHandler: { progress in
NSLog("Progress:%f", progress.fractionCompleted)
}, completionHandler: { _, _, _, _, _, _, _, error in
NSLog("Upload completed with error code: %ld", error.errorCode)

if error.errorCode == 0 {
NCAPIController.sharedInstance().shareFileOrFolder(for: activeAccount, atPath: fileServerPath, toRoom: self.room.token, talkMetaData: talkMetaData, withCompletionBlock: { error in
if error != nil {
NSLog("Failed to share voice message")
}
})
} else if error.errorCode == 404 || error.errorCode == 409 {
NCAPIController.sharedInstance().checkOrCreateAttachmentFolder(for: activeAccount, withCompletionBlock: { created, _ in
if created {
self.uploadFileAtPath(localPath: localPath, withFileServerURL: fileServerURL, andFileServerPath: fileServerPath, withMetaData: talkMetaData)
} else {
NSLog("Failed to check or create attachment folder")
}
})
} else if error.errorCode == 507 {
let alert = UIAlertController(title: NSLocalizedString("Upload failed", comment: ""),
message: error.errorDescription,
preferredStyle: .alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("OK", comment: ""), style: .default))
self.present(alert, animated: true)
NSLog("Failed to upload voice message due to missing user storage quota")
} else {
NSLog("Failed upload voice message")
func uploadFileAtPath(localPath: String, withFileServerURL fileServerURL: String, andFileServerPath fileServerPath: String, withMetaData talkMetaData: [String: String]?, temporaryMessage: NCChatMessage?) {

ChatFileUploader.uploadFile(localPath: localPath,
fileServerURL: fileServerURL,
fileServerPath: fileServerPath,
talkMetaData: talkMetaData,
temporaryMessage: temporaryMessage,
room: self.room) { statusCode, errorMessage in
DispatchQueue.main.async {
switch statusCode {
case 200:
NSLog("Successfully uploaded and shared voice message")
case 401:
NSLog("No active account found")
NCUserInterfaceController.sharedInstance().presentAlert(withTitle: NSLocalizedString("Upload failed", comment: ""), withMessage: NSLocalizedString("No active account found", comment: ""))
case 403:
NSLog("Failed to share voice message")
NCUserInterfaceController.sharedInstance().presentAlert(withTitle: NSLocalizedString("Upload failed", comment: ""), withMessage: NSLocalizedString("Failed to share recording", comment: ""))
case 404, 409:
NSLog("Failed to check or create attachment folder")
NCUserInterfaceController.sharedInstance().presentAlert(withTitle: NSLocalizedString("Upload failed", comment: ""), withMessage: NSLocalizedString("Failed to check or create attachment folder", comment: ""))
case 507:
NSLog("User storage quota exceeded")
NCUserInterfaceController.sharedInstance().presentAlert(withTitle: NSLocalizedString("Upload failed", comment: ""),
withMessage: NSLocalizedString("User storage quota exceeded", comment: ""))
default:
NSLog("Failed upload voice message with error code \(statusCode)")
NCUserInterfaceController.sharedInstance().presentAlert(withTitle: NSLocalizedString("Upload failed", comment: ""), withMessage: NSLocalizedString("Unknown error occurred", comment: ""))
}
}
})
}
}

// MARK: - AVAudioRecorder Delegate
Expand Down Expand Up @@ -3236,12 +3305,22 @@ import QuickLook

// MARK: - VoiceMessageTableViewCellDelegate

public func cellWants(toPlayAudioFile fileParameter: NCMessageFileParameter) {
public func cellWants(toPlayAudioFile message: NCChatMessage) {
guard let fileParameter = message.file() else {
print("No file for message found")
return
}

if fileParameter.fileStatus != nil && fileParameter.fileStatus?.isDownloading ?? false {
print("File already downloading -> skipping new download")
return
}

if let fileStatus = fileParameter.fileStatus, fileStatus.fileLocalPath != nil && FileManager.default.fileExists(atPath: fileParameter.fileStatus?.fileLocalPath ?? "") {
self.setupVoiceMessagePlayer(with: fileParameter.fileStatus!)
return
}

if let voiceMessagesPlayer = self.voiceMessagesPlayer,
let playerAudioFileStatus = self.playerAudioFileStatus,
!voiceMessagesPlayer.isPlaying,
Expand Down
Loading

0 comments on commit 365e2c7

Please sign in to comment.