From d03c4f299b58c19fcf6e9ecfd3a501fe070b24b1 Mon Sep 17 00:00:00 2001 From: TSI-amrutwaghmare <96108296+TSI-amrutwaghmare@users.noreply.github.com> Date: Mon, 23 Oct 2023 16:49:46 +0530 Subject: [PATCH 1/4] NMC 2261 - Audio record and upload customisation --- .../NextcloudUnitTests/AudioUploadTests.swift | 52 +++ .../NCAudioRecorderViewController.swift | 4 +- .../Create cloud/FolderPathCustomCell.swift | 33 ++ .../Create cloud/FolderPathCustomCell.xib | 74 ++++ .../NCCreateFormUploadVoiceNote.storyboard | 112 ++++++ .../NCCreateFormUploadVoiceNote.swift | 359 ++++++++++++++++++ .../Main/Create cloud/TextTableViewCell.swift | 94 +++++ .../Main/Create cloud/TextTableViewCell.xib | 82 ++++ 8 files changed, 808 insertions(+), 2 deletions(-) create mode 100644 Tests/NextcloudUnitTests/AudioUploadTests.swift create mode 100644 iOSClient/Main/Create cloud/FolderPathCustomCell.swift create mode 100644 iOSClient/Main/Create cloud/FolderPathCustomCell.xib create mode 100644 iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.storyboard create mode 100644 iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift create mode 100644 iOSClient/Main/Create cloud/TextTableViewCell.swift create mode 100644 iOSClient/Main/Create cloud/TextTableViewCell.xib diff --git a/Tests/NextcloudUnitTests/AudioUploadTests.swift b/Tests/NextcloudUnitTests/AudioUploadTests.swift new file mode 100644 index 0000000000..2ea01a8085 --- /dev/null +++ b/Tests/NextcloudUnitTests/AudioUploadTests.swift @@ -0,0 +1,52 @@ +// +// AudioUploadTests.swift +// NextcloudTests +// +// Created by A200020526 on 13/06/23. +// Copyright © 2023 Marino Faggiana. All rights reserved. +// + +import XCTest +@testable import Nextcloud + +final class AudioUploadTests: XCTestCase { + var viewController:NCAudioRecorderViewController? + + override func setUpWithError() throws { + // Put setup code here. This method is called before the invocation of each test method in the class. + // Step 1. Create an instance of UIStoryboard + let viewController = UIStoryboard(name: "NCAudioRecorderViewController", bundle: nil).instantiateInitialViewController() as? NCAudioRecorderViewController + // Step 3. Make the viewDidLoad() execute. + viewController?.loadViewIfNeeded() + } + + override func tearDownWithError() throws { + // Put teardown code here. This method is called after the invocation of each test method in the class. + viewController = nil + } + + func testExample() throws { + // This is an example of a functional test case. + // Use XCTAssert and related functions to verify your tests produce the correct results. + // Any test you write for XCTest can be annotated as throws and async. + // Mark your test throws to produce an unexpected failure when your test encounters an uncaught error. + // Mark your test async to allow awaiting for asynchronous code to complete. Check the results with assertions afterwards. + } + + func testPerformanceExample() throws { + // This is an example of a performance test case. + self.measure { + // Put the code you want to measure the time of here. + } + } + + func testAudioMeterUpdateAfterDb(){ + viewController?.audioMeterDidUpdate(0.5) + XCTAssertNotNil(!(viewController?.durationLabel.text?.isEmpty ?? false)) + } + + func testStartRecorder(){ + viewController?.startStop() + XCTAssertEqual(viewController?.recording.state, nil, "Test start audio recorder") + } +} diff --git a/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift b/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift index ce6572903c..75f3e88bce 100644 --- a/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift +++ b/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift @@ -54,7 +54,7 @@ class NCAudioRecorderViewController: UIViewController, NCAudioRecorderDelegate { view.backgroundColor = .clear contentContainerView.backgroundColor = UIColor.lightGray - voiceRecordHUD.fillColor = UIColor.green + voiceRecordHUD.fillColor = NCBrandColor.shared.progressColorGreen60 Task { self.fileName = await NCNetworking.shared.createFileName(fileNameBase: NSLocalizedString("_untitled_", comment: "") + ".m4a", account: self.session.account, serverUrl: controller.currentServerUrl()) @@ -134,7 +134,7 @@ class NCAudioRecorderViewController: UIViewController, NCAudioRecorderDelegate { } voiceRecordHUD.update(CGFloat(rate)) - voiceRecordHUD.fillColor = UIColor.green + voiceRecordHUD.fillColor = NCBrandColor.shared.progressColorGreen60 let formatter = DateComponentsFormatter() formatter.allowedUnits = [.second] diff --git a/iOSClient/Main/Create cloud/FolderPathCustomCell.swift b/iOSClient/Main/Create cloud/FolderPathCustomCell.swift new file mode 100644 index 0000000000..b7ba63f9ef --- /dev/null +++ b/iOSClient/Main/Create cloud/FolderPathCustomCell.swift @@ -0,0 +1,33 @@ +// +// FolderPathCustomCell.swift +// Nextcloud +// +// Created by Sumit on 28/04/21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// + +import Foundation + +class FolderPathCustomCell: XLFormButtonCell{ + + @IBOutlet weak var photoLabel: UILabel! + @IBOutlet weak var folderImage: UIImageView! + @IBOutlet weak var bottomLineView: UIView! + + override func awakeFromNib() { + super.awakeFromNib() + } + + override func configure() { + super.configure() + } + + override func update() { + super.update() + if (rowDescriptor.tag == "PhotoButtonDestinationFolder"){ + bottomLineView.isHidden = true + }else{ + bottomLineView.isHidden = false + } + } +} diff --git a/iOSClient/Main/Create cloud/FolderPathCustomCell.xib b/iOSClient/Main/Create cloud/FolderPathCustomCell.xib new file mode 100644 index 0000000000..a231ae7c72 --- /dev/null +++ b/iOSClient/Main/Create cloud/FolderPathCustomCell.xib @@ -0,0 +1,74 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.storyboard b/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.storyboard new file mode 100644 index 0000000000..1b5344ccee --- /dev/null +++ b/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.storyboard @@ -0,0 +1,112 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift b/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift new file mode 100644 index 0000000000..22354160c0 --- /dev/null +++ b/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift @@ -0,0 +1,359 @@ +// +// NCCreateFormUploadVoiceNote.swift +// Nextcloud +// +// Created by Marino Faggiana on 9/03/2019. +// Copyright © 2019 Marino Faggiana. All rights reserved. +// +// Author Marino Faggiana +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . +// + +import UIKit +import NextcloudKit + +class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAudioPlayerDelegate, NCCreateFormUploadConflictDelegate { + + @IBOutlet weak var buttonPlayStop: UIButton! + @IBOutlet weak var labelTimer: UILabel! + @IBOutlet weak var labelDuration: UILabel! + @IBOutlet weak var progressView: UIProgressView! + + private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! + let utilityFileSystem = NCUtilityFileSystem() + let utility = NCUtility() + private var serverUrl = "" + private var titleServerUrl = "" + private var fileName = "" + private var fileNamePath = "" + private var durationPlayer: TimeInterval = 0 + private var counterSecondPlayer: TimeInterval = 0 + + private var audioPlayer: AVAudioPlayer! + private var timer = Timer() + + var cellBackgoundColor = UIColor.secondarySystemGroupedBackground + + // MARK: - View Life Cycle + + override func viewDidLoad() { + super.viewDidLoad() + + self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_cancel_", comment: ""), style: UIBarButtonItem.Style.plain, target: self, action: #selector(cancel)) + self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_save_", comment: ""), style: UIBarButtonItem.Style.plain, target: self, action: #selector(save)) + self.navigationItem.leftBarButtonItem?.tintColor = NCBrandColor.shared.brand + self.navigationItem.rightBarButtonItem?.tintColor = NCBrandColor.shared.brand + + self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none + + view.backgroundColor = .systemGroupedBackground + tableView.backgroundColor = .systemGroupedBackground + cellBackgoundColor = .secondarySystemGroupedBackground + + self.title = NSLocalizedString("_voice_memo_title_", comment: "") + + // Button Play Stop + buttonPlayStop.setImage(UIImage(named: "audioPlay")!.image(color: NCBrandColor.shared.iconColor, size: 100), for: .normal) + + // Progress view + progressView.progress = 0 + progressView.progressTintColor = NCBrandColor.shared.customer + progressView.trackTintColor = .white + progressView.layer.borderWidth = 1 + progressView.layer.cornerRadius = 5.0 + progressView.layer.borderColor = NCBrandColor.shared.customer.cgColor + + labelTimer.textColor = .label + labelDuration.textColor = .label + + initializeForm() + } + + override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + + updateTimerUI() + } + + override func viewDidDisappear(_ animated: Bool) { + super.viewDidDisappear(animated) + + if audioPlayer.isPlaying { + stop() + } + } + + public func setup(serverUrl: String, fileNamePath: String, fileName: String) { + + if serverUrl == utilityFileSystem.getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId) { + titleServerUrl = "/" + } else { + titleServerUrl = (serverUrl as NSString).lastPathComponent + } + + self.fileName = fileName + self.serverUrl = serverUrl + self.fileNamePath = fileNamePath + + // player + do { + try audioPlayer = AVAudioPlayer(contentsOf: URL(fileURLWithPath: fileNamePath)) + audioPlayer.prepareToPlay() + audioPlayer.delegate = self + durationPlayer = TimeInterval(audioPlayer.duration) + } catch { + buttonPlayStop.isEnabled = false + } + } + + // MARK: XLForm + + func initializeForm() { + + let form: XLFormDescriptor = XLFormDescriptor() as XLFormDescriptor + form.rowNavigationOptions = XLFormRowNavigationOptions.stopDisableRow + + var section: XLFormSectionDescriptor + var row: XLFormRowDescriptor + + // Section: Destination Folder + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_save_path_", comment: "").uppercased()) + section.footerTitle = "" + form.addFormSection(section) + + XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCFolderCustomCellType"] = FolderPathCustomCell.self + + row = XLFormRowDescriptor(tag: "ButtonDestinationFolder", rowType: "kNMCFolderCustomCellType", title: self.titleServerUrl) + row.cellConfig["backgroundColor"] = UIColor.secondarySystemGroupedBackground + row.action.formSelector = #selector(changeDestinationFolder(_:)) + row.cellConfig["folderImage.image"] = UIImage(named: "folder_nmcloud")?.image(color: NCBrandColor.shared.brandElement, size: 25) + row.cellConfig["photoLabel.textAlignment"] = NSTextAlignment.right.rawValue + row.cellConfig["photoLabel.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["photoLabel.textColor"] = UIColor.label //photos + if(self.titleServerUrl == "/"){ + row.cellConfig["photoLabel.text"] = NSLocalizedString("_prefix_upload_path_", comment: "") + }else{ + row.cellConfig["photoLabel.text"] = self.titleServerUrl + } + row.cellConfig["textLabel.text"] = "" + section.addFormRow(row) + + // Section: File Name + + XLFormViewController.cellClassesForRowDescriptorTypes()["kMyAppCustomCellType"] = TextTableViewCell.self + + section = XLFormSectionDescriptor.formSection(withTitle: NSLocalizedString("_filename_", comment: "").uppercased()) + form.addFormSection(section) + + row = XLFormRowDescriptor(tag: "fileName", rowType: "kMyAppCustomCellType", title: NSLocalizedString("_filename_", comment: "")) + row.cellClass = TextTableViewCell.self + row.cellConfigAtConfigure["backgroundColor"] = UIColor.secondarySystemGroupedBackground; + row.cellConfig["fileNameTextField.textAlignment"] = NSTextAlignment.left.rawValue + row.cellConfig["fileNameTextField.font"] = UIFont.systemFont(ofSize: 15.0) + row.cellConfig["fileNameTextField.textColor"] = UIColor.label + row.cellConfig["fileNameTextField.text"] = self.fileName + section.addFormRow(row) + + self.form = form + } + + override func formRowDescriptorValueHasChanged(_ formRow: XLFormRowDescriptor!, oldValue: Any!, newValue: Any!) { + + super.formRowDescriptorValueHasChanged(formRow, oldValue: oldValue, newValue: newValue) + + if formRow.tag == "fileName" { + + self.form.delegate = nil + + if let fileNameNew = formRow.value as? String { + self.fileName = utility.removeForbiddenCharacters(fileNameNew) + } + + + self.form.delegate = self + } + } + + // MARK: TableViewDelegate + + override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int) { + let header = view as? UITableViewHeaderFooterView + header?.textLabel?.font = UIFont.systemFont(ofSize: 13.0) + header?.textLabel?.textColor = .gray + header?.tintColor = cellBackgoundColor + } + + // MARK: - Action + + func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], indexPath: [IndexPath], overwrite: Bool, copy: Bool, move: Bool) { + + if serverUrl != nil { + + self.serverUrl = serverUrl! + + if serverUrl == utilityFileSystem.getHomeServer(urlBase: appDelegate.urlBase, userId: appDelegate.userId) { + self.titleServerUrl = "/" + } else { + self.titleServerUrl = (serverUrl! as NSString).lastPathComponent + } + + // Update + let row: XLFormRowDescriptor = self.form.formRow(withTag: "ButtonDestinationFolder")! + row.cellConfig["photoLabel.text"] = self.titleServerUrl + self.updateFormRow(row) + } + } + + @objc func save() { + + let rowFileName: XLFormRowDescriptor = self.form.formRow(withTag: "fileName")! + guard let name = (rowFileName.value as? String)?.trimmingCharacters(in: .whitespaces) else { + let alert = UIAlertController(title: "", message: NSLocalizedString("_prompt_insert_file_name", comment: ""), preferredStyle: .alert) + alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .cancel, handler: nil)) + self.present(alert, animated: true) + return + } + let ext = (name as NSString).pathExtension.uppercased() + var fileNameSave = "" + + if ext.isEmpty { + fileNameSave = name + ".m4a" + } else { + fileNameSave = (name as NSString).deletingPathExtension + ".m4a" + } + + let metadataForUpload = NCManageDatabase.shared.createMetadata(account: self.appDelegate.account, user: self.appDelegate.user, userId: self.appDelegate.userId, fileName: fileNameSave, fileNameView: fileNameSave, ocId: UUID().uuidString, serverUrl: self.serverUrl, urlBase: self.appDelegate.urlBase, url: "", contentType: "") + + metadataForUpload.session = NCNetworking.shared.sessionUploadBackground + metadataForUpload.sessionSelector = NCGlobal.shared.selectorUploadFile + metadataForUpload.status = NCGlobal.shared.metadataStatusWaitUpload + metadataForUpload.size = utilityFileSystem.getFileSize(filePath: fileNamePath) + + if NCManageDatabase.shared.getMetadataConflict(account: appDelegate.account, serverUrl: serverUrl, fileNameView: fileNameSave) != nil { + + guard let conflict = UIStoryboard(name: "NCCreateFormUploadConflict", bundle: nil).instantiateInitialViewController() as? NCCreateFormUploadConflict else { return } + + conflict.textLabelDetailNewFile = NSLocalizedString("_now_", comment: "") + conflict.serverUrl = serverUrl + conflict.metadatasUploadInConflict = [metadataForUpload] + conflict.delegate = self + + self.present(conflict, animated: true, completion: nil) + + } else { + + dismissAndUpload(metadataForUpload) + } + } + + func dismissCreateFormUploadConflict(metadatas: [tableMetadata]?) { + + if let metadatas, metadatas.count > 0 { + DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { + self.dismissAndUpload(metadatas[0]) + } + } + } + + func dismissAndUpload(_ metadata: tableMetadata) { + + utilityFileSystem.copyFile(atPath: self.fileNamePath, toPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)) + + NCNetworkingProcessUpload.shared.createProcessUploads(metadatas: [metadata], completion: { _ in }) + + self.dismiss(animated: true, completion: nil) + } + + @objc func cancel() { + + try? FileManager.default.removeItem(atPath: fileNamePath) + self.dismiss(animated: true, completion: nil) + } + + @objc func changeDestinationFolder(_ sender: XLFormRowDescriptor) { + + self.deselectFormRow(sender) + + let storyboard = UIStoryboard(name: "NCSelect", bundle: nil) + if let navigationController = storyboard.instantiateInitialViewController() as? UINavigationController, + let viewController = navigationController.topViewController as? NCSelect { + + viewController.delegate = self + viewController.typeOfCommandView = .selectCreateFolder + viewController.includeDirectoryE2EEncryption = true + + self.present(navigationController, animated: true, completion: nil) + } + } + + // MARK: Player - Timer + + func updateTimerUI() { + labelTimer.text = String().formatSecondsToString(counterSecondPlayer) + labelDuration.text = String().formatSecondsToString(durationPlayer) + progressView.progress = Float(counterSecondPlayer / durationPlayer) + } + + @objc func updateTimer() { + counterSecondPlayer += 1 + updateTimerUI() + } + + @IBAction func playStop(_ sender: Any) { + + if audioPlayer.isPlaying { + + stop() + + } else { + + start() + } + } + + func start() { + + audioPlayer.prepareToPlay() + audioPlayer.play() + + timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(updateTimer), userInfo: nil, repeats: true) + + buttonPlayStop.setImage(UIImage(named: "stop")!.image(color: UIColor.systemGray, size: 100), for: .normal) + } + + func stop() { + + audioPlayer.currentTime = 0.0 + audioPlayer.stop() + + timer.invalidate() + counterSecondPlayer = 0 + progressView.progress = 0 + updateTimerUI() + + buttonPlayStop.setImage(UIImage(named: "audioPlay")!.image(color: UIColor.systemGray, size: 100), for: .normal) + } + + func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) { + + timer.invalidate() + counterSecondPlayer = 0 + progressView.progress = 0 + updateTimerUI() + + buttonPlayStop.setImage(UIImage(named: "audioPlay")!.image(color: UIColor.systemGray, size: 100), for: .normal) + } +} diff --git a/iOSClient/Main/Create cloud/TextTableViewCell.swift b/iOSClient/Main/Create cloud/TextTableViewCell.swift new file mode 100644 index 0000000000..11116a2ff5 --- /dev/null +++ b/iOSClient/Main/Create cloud/TextTableViewCell.swift @@ -0,0 +1,94 @@ +// +// TextTableViewCell.swift +// Nextcloud +// +// Created by Ashu on 23/04/21. +// Copyright © 2021 Marino Faggiana. All rights reserved. +// + +import UIKit + +class TextTableViewCell: XLFormBaseCell, UITextFieldDelegate { + + @IBOutlet weak var fileNameTextField: UITextField! + @IBOutlet weak var topLineView: UIView! + + override func awakeFromNib() { + super.awakeFromNib() + // Initialization code + + fileNameTextField.delegate = self + topLineView.backgroundColor = UIColor.secondarySystemBackground + + } + + override func setSelected(_ selected: Bool, animated: Bool) { + super.setSelected(selected, animated: animated) + + // Configure the view for the selected state + } + + override func configure() { + super.configure() + } + + override func update() { + super.update() + if (rowDescriptor.tag == "maskFileName"){ + topLineView.isHidden = true + }else{ + topLineView.isHidden = false + } + + fileNameTextField.tintColor = UIColor.systemGray + fileNameTextField.selectedTextRange = fileNameTextField.textRange(from: fileNameTextField.beginningOfDocument, to: fileNameTextField.endOfDocument) + } + + func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { + + if fileNameTextField == textField { + if let rowDescriptor = rowDescriptor, let text = self.fileNameTextField.text { + + if (text + " ").isEmpty == false { + rowDescriptor.value = self.fileNameTextField.text! + string + } else { + rowDescriptor.value = nil + } + } + } + + self.formViewController().textField(textField, shouldChangeCharactersIn: range, replacementString: string) + + return true + } + + func textFieldShouldReturn(_ textField: UITextField) -> Bool { + self.formViewController()?.textFieldShouldReturn(fileNameTextField) + return true + } + + func textFieldShouldClear(_ textField: UITextField) -> Bool { + self.formViewController()?.textFieldShouldClear(fileNameTextField) + rowDescriptor.value = nil + + self.formViewController().textField(textField, shouldChangeCharactersIn: NSRange.init().self, replacementString: "") + return true + } + + override class func formDescriptorCellHeight(for rowDescriptor: XLFormRowDescriptor!) -> CGFloat { + return 45 + } +} + +extension UITextField { + @IBInspectable var placeholderColor: UIColor { + get { + return attributedPlaceholder?.attribute(.foregroundColor, at: 0, effectiveRange: nil) as? UIColor ?? .clear + } + set { + guard let attributedPlaceholder = attributedPlaceholder else { return } + let attributes: [NSAttributedString.Key: UIColor] = [.foregroundColor: newValue] + self.attributedPlaceholder = NSAttributedString(string: attributedPlaceholder.string, attributes: attributes) + } + } +} diff --git a/iOSClient/Main/Create cloud/TextTableViewCell.xib b/iOSClient/Main/Create cloud/TextTableViewCell.xib new file mode 100644 index 0000000000..e4be37d230 --- /dev/null +++ b/iOSClient/Main/Create cloud/TextTableViewCell.xib @@ -0,0 +1,82 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 5f0a9a80acb161c7fae74dbc85f06e83bd1ac5c0 Mon Sep 17 00:00:00 2001 From: TSI-amrutwaghmare <96108296+TSI-amrutwaghmare@users.noreply.github.com> Date: Wed, 10 Jan 2024 14:06:22 +0530 Subject: [PATCH 2/4] NMC 2261 - Empty filename alert issue --- .../Main/Create cloud/NCCreateFormUploadVoiceNote.swift | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift b/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift index 22354160c0..f833e106dc 100644 --- a/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift +++ b/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift @@ -180,6 +180,8 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud if let fileNameNew = formRow.value as? String { self.fileName = utility.removeForbiddenCharacters(fileNameNew) + } else { + self.fileName = "" } @@ -218,9 +220,8 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud } @objc func save() { - - let rowFileName: XLFormRowDescriptor = self.form.formRow(withTag: "fileName")! - guard let name = (rowFileName.value as? String)?.trimmingCharacters(in: .whitespaces) else { + let name = self.fileName + guard name.trimmingCharacters(in: .whitespaces) != "" else { let alert = UIAlertController(title: "", message: NSLocalizedString("_prompt_insert_file_name", comment: ""), preferredStyle: .alert) alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .cancel, handler: nil)) self.present(alert, animated: true) From 3cf12f1411e9449a1a5dd4855230594adcc5ddd5 Mon Sep 17 00:00:00 2001 From: TSI-amrutwaghmare <96108296+TSI-amrutwaghmare@users.noreply.github.com> Date: Wed, 10 Apr 2024 14:46:33 +0530 Subject: [PATCH 3/4] NMC 2261 - Save audio screen update after removed by nextcloud version 5.0 --- .../NCAudioRecorderViewController.swift | 31 +++++++++++-------- .../NCCreateFormUploadVoiceNote.swift | 2 +- 2 files changed, 19 insertions(+), 14 deletions(-) diff --git a/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift b/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift index 75f3e88bce..81da1faee4 100644 --- a/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift +++ b/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift @@ -30,6 +30,7 @@ import QuartzCore import NextcloudKit class NCAudioRecorderViewController: UIViewController, NCAudioRecorderDelegate { + @IBOutlet weak var contentContainerView: UIView! @IBOutlet weak var durationLabel: UILabel! @IBOutlet weak var startStopLabel: UILabel! @@ -42,6 +43,7 @@ class NCAudioRecorderViewController: UIViewController, NCAudioRecorderDelegate { var session: NCSession.Session { NCSession.shared.getSession(controller: controller) } + let appDelegate = (UIApplication.shared.delegate as? AppDelegate)! // MARK: - View Life Cycle @@ -56,16 +58,14 @@ class NCAudioRecorderViewController: UIViewController, NCAudioRecorderDelegate { contentContainerView.backgroundColor = UIColor.lightGray voiceRecordHUD.fillColor = NCBrandColor.shared.progressColorGreen60 - Task { - self.fileName = await NCNetworking.shared.createFileName(fileNameBase: NSLocalizedString("_untitled_", comment: "") + ".m4a", account: self.session.account, serverUrl: controller.currentServerUrl()) - recording = NCAudioRecorder(to: self.fileName) - recording.delegate = self - do { - try self.recording.prepare() - startStopLabel.text = NSLocalizedString("_voice_memo_start_", comment: "") - } catch { - print(error) - } + self.fileName = NCUtilityFileSystem().createFileNameDate(NSLocalizedString("_voice_memo_filename_", comment: ""), ext: "m4a") + recording = NCAudioRecorder(to: self.fileName) + recording.delegate = self + do { + try self.recording.prepare() + startStopLabel.text = NSLocalizedString("_voice_memo_start_", comment: "") + } catch { + print(error) } } @@ -83,8 +83,12 @@ class NCAudioRecorderViewController: UIViewController, NCAudioRecorderDelegate { if recording.state == .record { recording.stop() voiceRecordHUD.update(0.0) - dismiss(animated: true) { - self.uploadMetadata() + dismiss(animated: true) { [self] in + guard let navigationController = UIStoryboard(name: "NCCreateFormUploadVoiceNote", bundle: nil).instantiateInitialViewController() as? UINavigationController, + let viewController = navigationController.topViewController as? NCCreateFormUploadVoiceNote else { return } + navigationController.modalPresentationStyle = .formSheet + viewController.setup(serverUrl: self.appDelegate.activeServerUrl, fileNamePath: NSTemporaryDirectory() + self.fileName, fileName: self.fileName) + self.appDelegate.window?.rootViewController?.present(navigationController, animated: true) } } else { do { @@ -148,7 +152,8 @@ class NCAudioRecorderViewController: UIViewController, NCAudioRecorderDelegate { } open class NCAudioRecorder: NSObject { - public enum State: Int { + + @objc public enum State: Int { case none, record, play } diff --git a/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift b/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift index f833e106dc..e4ea9c323c 100644 --- a/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift +++ b/iOSClient/Main/Create cloud/NCCreateFormUploadVoiceNote.swift @@ -273,7 +273,7 @@ class NCCreateFormUploadVoiceNote: XLFormViewController, NCSelectDelegate, AVAud utilityFileSystem.copyFile(atPath: self.fileNamePath, toPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)) - NCNetworkingProcessUpload.shared.createProcessUploads(metadatas: [metadata], completion: { _ in }) + NCNetworkingProcess.shared.createProcessUploads(metadatas: [metadata], completion: { _ in }) self.dismiss(animated: true, completion: nil) } From 871b1d0a743588158d8ebb23ccb5f70eef960967 Mon Sep 17 00:00:00 2001 From: harshada-15-tsys Date: Wed, 9 Apr 2025 17:06:20 +0530 Subject: [PATCH 4/4] NMC 2261 - Audio recorder and upload customisation --- Nextcloud.xcodeproj/project.pbxproj | 37 +++++++++++++++++++ .../NCAudioRecorderViewController.swift | 6 +-- 2 files changed, 40 insertions(+), 3 deletions(-) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index e214b2f751..d84b7b173c 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -92,6 +92,17 @@ AFCE353527E4ED5900FEA6C2 /* DateFormatter+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */; }; AFCE353727E4ED7B00FEA6C2 /* NCShareCells.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */; }; AFCE353927E5DE0500FEA6C2 /* Shareable.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353827E5DE0400FEA6C2 /* Shareable.swift */; }; + AFCE353927E5DE0500FEA6C2 /* NCShare+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */; }; + B543154E2DA6913C00981E7E /* AudioUploadTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = B543154D2DA6913C00981E7E /* AudioUploadTests.swift */; }; + B54315552DA6929700981E7E /* NCCreateFormUploadVoiceNote.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54315522DA6929700981E7E /* NCCreateFormUploadVoiceNote.swift */; }; + B543155A2DA6929700981E7E /* NCCreateFormUploadVoiceNote.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B54315512DA6929700981E7E /* NCCreateFormUploadVoiceNote.storyboard */; }; + B543155B2DA6929700981E7E /* NCCreateFormUploadVoiceNote.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54315522DA6929700981E7E /* NCCreateFormUploadVoiceNote.swift */; }; + B543155C2DA6929700981E7E /* FolderPathCustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B543154F2DA6929700981E7E /* FolderPathCustomCell.swift */; }; + B543155D2DA6929700981E7E /* TextTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B54315532DA6929700981E7E /* TextTableViewCell.swift */; }; + B543155E2DA6929700981E7E /* TextTableViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B54315542DA6929700981E7E /* TextTableViewCell.xib */; }; + B543155F2DA6929700981E7E /* FolderPathCustomCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B54315502DA6929700981E7E /* FolderPathCustomCell.xib */; }; + B54315602DA6929700981E7E /* NCCreateFormUploadVoiceNote.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B54315512DA6929700981E7E /* NCCreateFormUploadVoiceNote.storyboard */; }; + C04E2F232A17BB4D001BAD85 /* FilesIntegrationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C04E2F222A17BB4D001BAD85 /* FilesIntegrationTests.swift */; }; D575039F27146F93008DC9DC /* String+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7A0D1342591FBC5008F8A13 /* String+Extension.swift */; }; D5B6AA7827200C7200D49C24 /* NCActivityTableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */; }; F310B1EF2BA862F1001C42F5 /* NCViewerMedia+VisionKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = F310B1EE2BA862F1001C42F5 /* NCViewerMedia+VisionKit.swift */; }; @@ -1329,6 +1340,14 @@ AFCE353427E4ED5900FEA6C2 /* DateFormatter+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "DateFormatter+Extension.swift"; sourceTree = ""; }; AFCE353627E4ED7B00FEA6C2 /* NCShareCells.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareCells.swift; sourceTree = ""; }; AFCE353827E5DE0400FEA6C2 /* Shareable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shareable.swift; sourceTree = ""; }; + AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCShare+Helper.swift"; sourceTree = ""; }; + B543154D2DA6913C00981E7E /* AudioUploadTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioUploadTests.swift; sourceTree = ""; }; + B543154F2DA6929700981E7E /* FolderPathCustomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderPathCustomCell.swift; sourceTree = ""; }; + B54315502DA6929700981E7E /* FolderPathCustomCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = FolderPathCustomCell.xib; sourceTree = ""; }; + B54315512DA6929700981E7E /* NCCreateFormUploadVoiceNote.storyboard */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; path = NCCreateFormUploadVoiceNote.storyboard; sourceTree = ""; }; + B54315522DA6929700981E7E /* NCCreateFormUploadVoiceNote.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCCreateFormUploadVoiceNote.swift; sourceTree = ""; }; + B54315532DA6929700981E7E /* TextTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TextTableViewCell.swift; sourceTree = ""; }; + B54315542DA6929700981E7E /* TextTableViewCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = TextTableViewCell.xib; sourceTree = ""; }; C0046CDA2A17B98400D87C9D /* NextcloudUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; C04E2F202A17BB4D001BAD85 /* NextcloudIntegrationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = NextcloudIntegrationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D5B6AA7727200C7200D49C24 /* NCActivityTableViewCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCActivityTableViewCell.swift; sourceTree = ""; }; @@ -2117,6 +2136,8 @@ isa = PBXGroup; children = ( AA52EB452D42AC5A0089C348 /* Placeholder.swift */, + B543154D2DA6913C00981E7E /* AudioUploadTests.swift */, + AF8ED1FB2757821000B8DBC4 /* NextcloudUnitTests.swift */, ); path = NextcloudUnitTests; sourceTree = ""; @@ -3194,6 +3215,12 @@ F7DFB7E9219C5A0500680748 /* Create cloud */ = { isa = PBXGroup; children = ( + B543154F2DA6929700981E7E /* FolderPathCustomCell.swift */, + B54315502DA6929700981E7E /* FolderPathCustomCell.xib */, + B54315512DA6929700981E7E /* NCCreateFormUploadVoiceNote.storyboard */, + B54315522DA6929700981E7E /* NCCreateFormUploadVoiceNote.swift */, + B54315532DA6929700981E7E /* TextTableViewCell.swift */, + B54315542DA6929700981E7E /* TextTableViewCell.xib */, F7FA7FFD2C0F4F3B0072FC60 /* Upload Assets */, F7A509242C26BD5D00326106 /* NCCreateDocument.swift */, F704B5E22430AA6F00632F5F /* NCCreateFormUploadConflict.storyboard */, @@ -3913,6 +3940,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + B543155A2DA6929700981E7E /* NCCreateFormUploadVoiceNote.storyboard in Resources */, F714803B262EBE3900693E51 /* MainInterface.storyboard in Resources */, F7148054262ED51000693E51 /* NCListCell.xib in Resources */, F7D57C8626317BDA00DE301D /* NCAccountRequest.storyboard in Resources */, @@ -4006,6 +4034,9 @@ F70753F72542A9C000972D44 /* NCViewerMediaPage.storyboard in Resources */, F7F4F10627ECDBDB008676F9 /* Inconsolata-Medium.ttf in Resources */, F7AC934A296193050002BC0F /* Reasons to use Nextcloud.pdf in Resources */, + B543155E2DA6929700981E7E /* TextTableViewCell.xib in Resources */, + B543155F2DA6929700981E7E /* FolderPathCustomCell.xib in Resources */, + B54315602DA6929700981E7E /* NCCreateFormUploadVoiceNote.storyboard in Resources */, F7A60F87292D215000FCE1F2 /* NCShareAccounts.storyboard in Resources */, F761856A29E98543006EB3B0 /* NCIntro.storyboard in Resources */, F719D9E0288D37A300762E33 /* NCColorPicker.storyboard in Resources */, @@ -4142,6 +4173,7 @@ files = ( AA52EB472D42AC9E0089C348 /* Placeholder.swift in Sources */, F372087D2BAB4C0F006B5430 /* TestConstants.swift in Sources */, + B543154E2DA6913C00981E7E /* AudioUploadTests.swift in Sources */, F78E2D6C29AF02DB0024D4F3 /* Database.swift in Sources */, F7817CFE29801A3500FFBC65 /* Data+Extension.swift in Sources */, ); @@ -4350,6 +4382,8 @@ F33EE6F52BF4C9B200CA1A51 /* PKCS12.swift in Sources */, F77DD6AB2C5CC093009448FB /* NCSession.swift in Sources */, F76D364728A4F8BF00214537 /* NCActivityIndicator.swift in Sources */, + F73EF7CA2B0225610087E6E9 /* NCManageDatabase+PhotoLibrary.swift in Sources */, + B54315552DA6929700981E7E /* NCCreateFormUploadVoiceNote.swift in Sources */, F7BFFD2A2C8854200029A201 /* NCHud.swift in Sources */, F749B654297B0F2400087535 /* NCManageDatabase+Avatar.swift in Sources */, AF22B208277B4E4C00DAB0CC /* NCCreateFormUploadConflictCell.swift in Sources */, @@ -4696,6 +4730,9 @@ F3C587AE2D47E4FE004532DB /* PHAssetCollectionThumbnailLoader.swift in Sources */, F78F74362163781100C2ADAD /* NCTrash.swift in Sources */, F39298972A3B12CB00509762 /* BaseNCMoreCell.swift in Sources */, + B543155B2DA6929700981E7E /* NCCreateFormUploadVoiceNote.swift in Sources */, + B543155C2DA6929700981E7E /* FolderPathCustomCell.swift in Sources */, + B543155D2DA6929700981E7E /* TextTableViewCell.swift in Sources */, AF2D7C7C2742556F00ADF566 /* NCShareLinkCell.swift in Sources */, F7E41316294A19B300839300 /* UIView+Extension.swift in Sources */, F7C30E00291BD2610017149B /* NCNetworkingE2EERename.swift in Sources */, diff --git a/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift b/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift index 81da1faee4..974168d979 100644 --- a/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift +++ b/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift @@ -87,8 +87,8 @@ class NCAudioRecorderViewController: UIViewController, NCAudioRecorderDelegate { guard let navigationController = UIStoryboard(name: "NCCreateFormUploadVoiceNote", bundle: nil).instantiateInitialViewController() as? UINavigationController, let viewController = navigationController.topViewController as? NCCreateFormUploadVoiceNote else { return } navigationController.modalPresentationStyle = .formSheet - viewController.setup(serverUrl: self.appDelegate.activeServerUrl, fileNamePath: NSTemporaryDirectory() + self.fileName, fileName: self.fileName) - self.appDelegate.window?.rootViewController?.present(navigationController, animated: true) + viewController.setup(serverUrl: controller.currentServerUrl(), fileNamePath: NSTemporaryDirectory() + self.fileName, fileName: self.fileName) + UIApplication.shared.firstWindow?.rootViewController?.present(navigationController, animated: true) } } else { do { @@ -110,7 +110,7 @@ class NCAudioRecorderViewController: UIViewController, NCAudioRecorderDelegate { url: "", contentType: "", session: self.session, - sceneIdentifier: self.controller?.sceneIdentifier) + sceneIdentifier: self.appDelegate.sceneIdentifier) metadata.session = NCNetworking.shared.sessionUploadBackground metadata.sessionSelector = NCGlobal.shared.selectorUploadFile