From 708467d9e9a55b432cbbf6201ddbf251d1f8aa46 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/2] 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 90b733388e..a3e0ae1a6e 100644
--- a/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift
+++ b/iOSClient/AudioRecorder/NCAudioRecorderViewController.swift
@@ -51,7 +51,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.appDelegate.account, serverUrl: self.appDelegate.activeServerUrl)
@@ -135,7 +135,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 cfc4c428b0ef72f718e328f0112069722980d7bb 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/2] 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)