Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added temporary voice messages #1874

Merged
merged 3 commits into from
Dec 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions NextcloudTalk.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -599,6 +599,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 @@ -1179,6 +1183,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 PBXFileSystemSynchronizedBuildFileExceptionSet section */
Expand Down Expand Up @@ -2144,6 +2149,7 @@
1F35F8FA2AEEDBC600044BDA /* ChatViewControllerExtension.swift */,
2C4230F62B207AB00013E1FA /* ContextChatViewController.swift */,
1F0B0A712BA264540073FF8D /* MentionSuggestion.swift */,
F644A2DC2CE287FA00E2ED81 /* ChatFileUploader.swift */,
1F2058292CEA404F00AAA673 /* AiSummaryViewController.swift */,
1F20582B2CEA405700AAA673 /* AiSummaryViewController.xib */,
1F205B9F2CEE1B8800AAA673 /* AiSummaryController.swift */,
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 @@ -3087,6 +3094,7 @@
2CB6ACBC26385A3800D3D641 /* ShareLocationViewController.m in Sources */,
2C04249B2CA33681004772F6 /* AudioPlayerView.swift in Sources */,
1F1B0F462BE047CE003FD766 /* InteractionControlling.swift in Sources */,
F644A2DD2CE287FA00E2ED81 /* ChatFileUploader.swift in Sources */,
2CF338E12CED388B0029CACC /* AvatarView.swift in Sources */,
1FDCC3D429EBF6E700DEB39B /* AvatarImageView.swift in Sources */,
1FB78E262B6AE5A600B0D69D /* FederationInvitation.swift in Sources */,
Expand Down Expand Up @@ -3115,6 +3123,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 @@ -3202,6 +3211,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
177 changes: 130 additions & 47 deletions NextcloudTalk/BaseChatViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -506,7 +506,7 @@ import SwiftUI

// 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()

temporaryMessage.accountId = self.account.accountId
Expand All @@ -515,14 +515,41 @@ import SwiftUI
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
DanielStandfest marked this conversation as resolved.
Show resolved Hide resolved

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 @@ -991,8 +1018,25 @@ import SwiftUI
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 @@ -1521,7 +1565,7 @@ import SwiftUI

NCAPIController.sharedInstance().uniqueNameForFileUpload(withName: contactFileName, originalName: true, for: self.account) { 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 @@ -1695,6 +1739,7 @@ import SwiftUI
}

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 @@ -1717,51 +1762,79 @@ import SwiftUI

audioFileName += ".mp3"

NCAPIController.sharedInstance().uniqueNameForFileUpload(withName: audioFileName, originalName: true, for: self.account, withCompletionBlock: { fileServerURL, fileServerPath, _, _ in
if let fileServerURL, let fileServerPath, let recorder = self.recorder {
let talkMetaData: [String: String] = ["messageType": "voice-message"]
self.uploadFileAtPath(localPath: recorder.url.path, withFileServerURL: fileServerURL, andFileServerPath: fileServerPath, withMetaData: talkMetaData)
} else {
NSLog("Could not find unique name for voice message file.")
let activeAccount = NCDatabaseManager.sharedInstance().activeAccount()
let chatFileController = NCChatFileController()
chatFileController.initDownloadDirectory(for: activeAccount)

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

if 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
}
})
}

func uploadFileAtPath(localPath: String, withFileServerURL fileServerURL: String, andFileServerPath fileServerPath: String, withMetaData talkMetaData: [String: String]?) {
NCAPIController.sharedInstance().setupNCCommunication(for: self.account)
if movedFileToTemporaryDirectory, NCDatabaseManager.sharedInstance().roomHasTalkCapability(kCapabilityChatReferenceId, for: room) {
self.appendTemporaryMessage(temporaryMessage: temporaryMessage)
}

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)
NCAPIController.sharedInstance().uniqueNameForFileUpload(withName: audioFileName, originalName: true, for: activeAccount, withCompletionBlock: { fileServerURL, fileServerPath, _, _ in
if let fileServerURL, let fileServerPath {
let talkMetaData: [String: String] = ["messageType": "voice-message"]

if error.errorCode == 0 {
NCAPIController.sharedInstance().shareFileOrFolder(for: self.account, 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: self.account, 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")
self.uploadFileAtPath(localPath: destinationFilePath, withFileServerURL: fileServerURL, andFileServerPath: fileServerPath, withMetaData: talkMetaData, temporaryMessage: temporaryMessage)
} else {
NSLog("Could not find unique name for voice message file.")
}
})
} else {
print("Temporary message could not be created")
}
}

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 @@ -3415,12 +3488,22 @@ import SwiftUI

// 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
Loading