From 054773b0fafbeb7eb7201d59c55f67d54d302507 Mon Sep 17 00:00:00 2001
From: TSI-amrutwaghmare <96108296+TSI-amrutwaghmare@users.noreply.github.com>
Date: Mon, 27 Nov 2023 17:19:30 +0530
Subject: [PATCH 1/6] NMC 1997 - Sharing customisation
NMC 1997 - Merging conflict resolve after nextcloud version 4.9.2 release
NMC 1992 - Remove configuration changes
NMC 1992 - Removed unused files
NMC 1992 - Sharing changes update after NC 5.2
NMC 1992 - Removed project configuration file changes
---
Tests/NextcloudUnitTests/SharingTest.swift | 232 +++++
.../Extensions/DateFormatter+Extension.swift | 9 +
iOSClient/Extensions/UIButton+Extension.swift | 23 +-
.../Extensions/UIToolbar+Extension.swift | 14 +
iOSClient/Extensions/UIView+Extension.swift | 33 +
iOSClient/Menu/NCShare+Menu.swift | 49 +-
iOSClient/NCGlobal.swift | 9 +
iOSClient/Networking/NCDownloadAction.swift | 579 +++++++++++++
.../Scan document/PasswordInputField.swift | 75 ++
.../Scan document/PasswordInputField.xib | 70 ++
.../Share/Advanced/NCFilePermissionCell.swift | 91 ++
.../Share/Advanced/NCFilePermissionCell.xib | 95 ++
.../Advanced/NCFilePermissionEditCell.swift | 176 ++++
.../Advanced/NCFilePermissionEditCell.xib | 108 +++
.../Advanced/NCShareAdvancePermission.swift | 814 ++++++++++++++++--
.../NCShareAdvancePermissionFooter.swift | 18 +-
.../NCShareAdvancePermissionFooter.xib | 79 +-
.../NCShareAdvancePermissionHeader.xib | 84 ++
.../Advanced/NCShareHeaderCustomCell.swift | 30 +
.../Advanced/NCShareHeaderCustomCell.xib | 42 +
.../Advanced/NCShareNewUserAddComment.swift | 115 ++-
.../Share/Advanced/NCShareTextInputCell.swift | 151 ++++
.../Share/Advanced/NCShareTextInputCell.xib | 80 ++
iOSClient/Share/NCSearchUserDropDownCell.xib | 10 +-
iOSClient/Share/NCShare+Helper.swift | 113 +++
iOSClient/Share/NCShare+NCCellDelegate.swift | 6 +-
iOSClient/Share/NCShare.storyboard | 392 ++++-----
iOSClient/Share/NCShare.swift | 291 +++++--
iOSClient/Share/NCShareCommon.swift | 47 +-
iOSClient/Share/NCShareEmailFieldCell.swift | 89 ++
iOSClient/Share/NCShareEmailFieldCell.xib | 128 +++
iOSClient/Share/NCShareHeader.swift | 62 +-
iOSClient/Share/NCShareHeaderView.xib | 247 +++---
iOSClient/Share/NCShareLinkCell.swift | 68 +-
iOSClient/Share/NCShareNetworking.swift | 15 +
iOSClient/Share/NCSharePaging.swift | 130 +--
iOSClient/Share/NCShareUserCell.swift | 55 +-
.../Share/ShareDownloadLimitNetwork.swift | 146 ++++
iOSClient/Utility/NCUtility.swift | 7 +
39 files changed, 4098 insertions(+), 684 deletions(-)
create mode 100644 Tests/NextcloudUnitTests/SharingTest.swift
create mode 100644 iOSClient/Networking/NCDownloadAction.swift
create mode 100644 iOSClient/Scan document/PasswordInputField.swift
create mode 100644 iOSClient/Scan document/PasswordInputField.xib
create mode 100644 iOSClient/Share/Advanced/NCFilePermissionCell.swift
create mode 100644 iOSClient/Share/Advanced/NCFilePermissionCell.xib
create mode 100644 iOSClient/Share/Advanced/NCFilePermissionEditCell.swift
create mode 100644 iOSClient/Share/Advanced/NCFilePermissionEditCell.xib
create mode 100644 iOSClient/Share/Advanced/NCShareAdvancePermissionHeader.xib
create mode 100644 iOSClient/Share/Advanced/NCShareHeaderCustomCell.swift
create mode 100644 iOSClient/Share/Advanced/NCShareHeaderCustomCell.xib
create mode 100644 iOSClient/Share/Advanced/NCShareTextInputCell.swift
create mode 100644 iOSClient/Share/Advanced/NCShareTextInputCell.xib
create mode 100644 iOSClient/Share/NCShare+Helper.swift
create mode 100644 iOSClient/Share/NCShareEmailFieldCell.swift
create mode 100644 iOSClient/Share/NCShareEmailFieldCell.xib
create mode 100644 iOSClient/Share/ShareDownloadLimitNetwork.swift
diff --git a/Tests/NextcloudUnitTests/SharingTest.swift b/Tests/NextcloudUnitTests/SharingTest.swift
new file mode 100644
index 0000000000..66d94dbfbb
--- /dev/null
+++ b/Tests/NextcloudUnitTests/SharingTest.swift
@@ -0,0 +1,232 @@
+//
+// SharingTest.swift
+// NextcloudTests
+//
+// Created by A200020526 on 07/06/23.
+// Copyright © 2023 Marino Faggiana. All rights reserved.
+//
+
+import XCTest
+@testable import Nextcloud
+final class SharingTest: XCTestCase {
+
+ var button: UIButton?
+ var ncShare: NCShare?
+
+ override func setUpWithError() throws {
+ // Put setup code here. This method is called before the invocation of each test method in the class.
+ super.setUp()
+ button = UIButton()
+ ncShare = NCShare()
+ }
+
+ override func tearDownWithError() throws {
+ // Put teardown code here. This method is called after the invocation of each test method in the class.
+ button = nil
+ ncShare = nil
+ super.tearDown()
+ }
+
+ 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.
+ }
+ }
+
+
+ //Date exntesion test case
+ func testTomorrow() {
+ let tomorrow = Date.tomorrow
+ let expectedTomorrow = Calendar.current.date(byAdding: .day, value: 1, to: Date())!
+ XCTAssertEqual(tomorrow.extendedIso8601String, expectedTomorrow.extendedIso8601String, "Tomorrow date should be correct.")
+ }
+ func testToday() {
+ let today = Date.today
+ let currentDate = Date()
+ XCTAssertEqual(today.extendedIso8601String, currentDate.extendedIso8601String, "Today date should be correct.")
+ }
+
+ func testDayAfter() {
+ let date = Date()
+ let dayAfter = date.dayAfter
+ let expectedDayAfter = Calendar.current.date(byAdding: .day, value: 1, to: date)!
+ XCTAssertEqual(dayAfter.extendedIso8601String, expectedDayAfter.extendedIso8601String, "Day after date should be correct.")
+ }
+
+ //Date Formatter extension Test Case
+ func testShareExpDate() {
+ let dateFormatter = DateFormatter.shareExpDate
+
+ XCTAssertEqual(dateFormatter.formatterBehavior, .behavior10_4, "Formatter behavior should be correct.")
+ XCTAssertEqual(dateFormatter.dateStyle, .medium, "Date style should be correct.")
+ XCTAssertEqual(dateFormatter.dateFormat, NCShareAdvancePermission.displayDateFormat, "Date format should be correct.")
+ }
+
+ //Button Extension test case
+ func testSetBackgroundColor() {
+ // Arrange
+ let color = UIColor.red
+ let state: UIControl.State = .normal
+
+ // Act
+ button?.setBackgroundColor(color, for: state)
+
+ // Assert
+ XCTAssertNotNil(button?.currentBackgroundImage, "Button background image not nil")
+ }
+
+ func testSetBackgroundColorForDifferentStates() {
+ // Arrange
+
+ let selectedColor = UIColor.green
+
+ // Act
+ button?.isSelected = true
+ button?.setBackgroundColor(selectedColor, for: .selected)
+
+ // Assert
+ XCTAssertNotNil(button?.currentBackgroundImage, "Button background image not nil")
+ button?.isSelected = false
+ XCTAssertNil(button?.currentBackgroundImage,"Button background image will be nil")
+ button?.isHighlighted = true
+ XCTAssertNil(button?.currentBackgroundImage, "Button background image will be nil")
+ }
+
+ //UIView extension shadow test case
+ func testAddShadowWithLocation() {
+ // Create a UIView instance
+ let view = UIView()
+
+ // Set the shadow with bottom location
+ view.addShadow(location: .bottom, height: 2, color: .red, opacity: 0.4, radius: 2)
+
+ // Verify that the shadow offset is set correctly for the bottom location
+ let bottomShadowOffset = view.layer.shadowOffset
+ XCTAssertEqual(bottomShadowOffset, CGSize(width: 0, height: 2), "Shadow offset not set correctly for bottom location")
+
+ // Verify that the shadow color is set correctly
+ let shadowColor = view.layer.shadowColor
+ XCTAssertEqual(shadowColor, UIColor.red.cgColor, "Shadow color not set correctly")
+
+ // Verify that the shadow opacity is set correctly
+ let shadowOpacity = view.layer.shadowOpacity
+ XCTAssertEqual(shadowOpacity, 0.4, "Shadow opacity not set correctly")
+
+ // Verify that the shadow radius is set correctly
+ let shadowRadius = view.layer.shadowRadius
+ XCTAssertEqual(shadowRadius, 2.0, "Shadow radius not set correctly")
+ }
+
+ func testAddShadowWithOffset() {
+ // Create a UIView instance
+ let view = UIView()
+
+ // Set the shadow with a custom offset
+ view.addShadow(offset: CGSize(width: 0, height: -4), color: .blue, opacity: 0.6, radius: 3)
+
+ // Verify that the shadow offset is set correctly
+ let shadowOffset = view.layer.shadowOffset
+ XCTAssertEqual(shadowOffset, CGSize(width: 0, height: -4), "Shadow offset not set correctly")
+
+ // Verify that the shadow color is set correctly
+ let shadowColor = view.layer.shadowColor
+ XCTAssertEqual(shadowColor, UIColor.blue.cgColor, "Shadow color not set correctly")
+
+ // Verify that the shadow opacity is set correctly
+ let shadowOpacity = view.layer.shadowOpacity
+ XCTAssertEqual(shadowOpacity, 0.6, "Shadow opacity not set correctly")
+
+ // Verify that the shadow radius is set correctly
+ let shadowRadius = view.layer.shadowRadius
+ XCTAssertEqual(shadowRadius, 3.0, "Shadow radius not set correctly")
+ }
+
+ func testAddShadowForLocation() {
+ // Create a UIView instance
+ let view = UIView()
+
+ // Add shadow to the bottom
+ view.addShadow(location: .bottom, color: UIColor.black)
+
+ // Verify that the shadow properties are set correctly for the bottom location
+ XCTAssertEqual(view.layer.shadowOffset, CGSize(width: 0, height: 2), "Shadow offset not set correctly for bottom location")
+ XCTAssertEqual(view.layer.shadowColor, UIColor.black.cgColor, "Shadow color not set correctly for bottom location")
+ XCTAssertEqual(view.layer.shadowOpacity, 0.4, "Shadow opacity not set correctly for bottom location")
+ XCTAssertEqual(view.layer.shadowRadius, 2.0, "Shadow radius not set correctly for bottom location")
+
+ // Add shadow to the top
+ view.addShadow(location: .top)
+
+ // Verify that the shadow properties are set correctly for the top location
+ XCTAssertEqual(view.layer.shadowOffset, CGSize(width: 0, height: -2), "Shadow offset not set correctly for top location")
+ XCTAssertEqual(view.layer.shadowColor, NCBrandColor.shared.customerDarkGrey.cgColor, "Shadow color not set correctly for top location")
+ XCTAssertEqual(view.layer.shadowOpacity, 0.4, "Shadow opacity not set correctly for top location")
+ XCTAssertEqual(view.layer.shadowRadius, 2.0, "Shadow radius not set correctly for top location")
+ }
+
+ func testAddShadowForOffset() {
+ // Create a UIView instance
+ let view = UIView()
+
+ // Add shadow with custom offset
+ view.addShadow(offset: CGSize(width: 2, height: 2))
+
+ // Verify that the shadow properties are set correctly for the custom offset
+ XCTAssertEqual(view.layer.shadowOffset, CGSize(width: 2, height: 2), "Shadow offset not set correctly for custom offset")
+ XCTAssertEqual(view.layer.shadowColor, UIColor.black.cgColor, "Shadow color not set correctly for custom offset")
+ XCTAssertEqual(view.layer.shadowOpacity, 0.5, "Shadow opacity not set correctly for custom offset")
+ XCTAssertEqual(view.layer.shadowRadius, 5.0, "Shadow radius not set correctly for custom offset")
+ }
+
+
+ func testHasUploadPermission() {
+ // Create an instance of NCShare
+ let share = NCShare()
+
+ // Define the input parameters
+ let tableShareWithUploadPermission = tableShare()
+ tableShareWithUploadPermission.permissions = NCGlobal.shared.permissionMaxFileShare
+
+ let tableShareWithoutUploadPermission = tableShare()
+ tableShareWithoutUploadPermission.permissions = NCGlobal.shared.permissionReadShare
+
+ // Call the hasUploadPermission function
+ let hasUploadPermission1 = share.hasUploadPermission(tableShare: tableShareWithUploadPermission)
+ let hasUploadPermission2 = share.hasUploadPermission(tableShare: tableShareWithoutUploadPermission)
+
+ // Verify the results
+ XCTAssertTrue(hasUploadPermission1, "hasUploadPermission returned false for a tableShare with upload permission")
+ XCTAssertFalse(hasUploadPermission2, "hasUploadPermission returned true for a tableShare without upload permission")
+ }
+
+ func testGetImageShareType() {
+ let sut = NCShareCommon() // Replace with the actual class containing the getImageShareType function
+
+ // Test case 1: SHARE_TYPE_USER
+ let shareType1 = sut.SHARE_TYPE_USER
+ let result1 = sut.getImageShareType(shareType: shareType1)
+ XCTAssertEqual(result1, UIImage(named: "shareTypeEmail")?.imageColor(NCBrandColor.shared.label))
+
+ // Test case 2: SHARE_TYPE_GROUP
+ let shareType2 = sut.SHARE_TYPE_GROUP
+ let result2 = sut.getImageShareType(shareType: shareType2)
+ XCTAssertEqual(result2, UIImage(named: "shareTypeGroup")?.imageColor(NCBrandColor.shared.label))
+
+ // Test case 3: SHARE_TYPE_LINK
+ let shareType3 = sut.SHARE_TYPE_LINK
+ let result3 = sut.getImageShareType(shareType: shareType3)
+ XCTAssertEqual(result3, UIImage(named: "shareTypeLink")?.imageColor(NCBrandColor.shared.label))
+
+ // Test case 4: SHARE_TYPE_EMAIL (with isDropDown=false)
+ let shareType4 = sut.SHARE_TYPE_EMAIL
+ let result4 = sut.getImageShareType(shareType: shareType4)
+ XCTAssertEqual(result4, UIImage(named: "shareTypeUser")?.imageColor(NCBrandColor.shared.label))
+
+ // Test case 5: SHARE_TYPE_EMAIL (with isDropDown=true)
+ let shareType5 = sut.SHARE_TYPE_EMAIL
+ let isDropDown5 = true
+ let result5 = sut.getImageShareType(shareType: shareType5, isDropDown: isDropDown5)
+ XCTAssertEqual(result5, UIImage(named: "email")?.imageColor(NCBrandColor.shared.label))
+ }
+}
diff --git a/iOSClient/Extensions/DateFormatter+Extension.swift b/iOSClient/Extensions/DateFormatter+Extension.swift
index dceb24e7e7..5d6a004843 100644
--- a/iOSClient/Extensions/DateFormatter+Extension.swift
+++ b/iOSClient/Extensions/DateFormatter+Extension.swift
@@ -29,6 +29,15 @@ extension DateFormatter {
let dateFormatter = DateFormatter()
dateFormatter.formatterBehavior = .behavior10_4
dateFormatter.dateStyle = .medium
+ dateFormatter.dateFormat = NCShareAdvancePermission.displayDateFormat
return dateFormatter
}()
}
+
+extension Date {
+ static var tomorrow: Date { return Date().dayAfter }
+ static var today: Date {return Date()}
+ var dayAfter: Date {
+ return Calendar.current.date(byAdding: .day, value: 1, to: Date())!
+ }
+}
diff --git a/iOSClient/Extensions/UIButton+Extension.swift b/iOSClient/Extensions/UIButton+Extension.swift
index 8050c15444..3f51b3e365 100644
--- a/iOSClient/Extensions/UIButton+Extension.swift
+++ b/iOSClient/Extensions/UIButton+Extension.swift
@@ -25,12 +25,21 @@ extension UIButton {
}
func hideSpinnerAndShowButton() {
- let spinnerTag = Int(bitPattern: Unmanaged.passUnretained(self).toOpaque())
- let spinner = self.superview?.subviews.first(where: { view -> Bool in
- return view.isKind(of: UIActivityIndicatorView.self) && view.tag == spinnerTag
- })
+ let spinnerTag = Int(bitPattern: Unmanaged.passUnretained(self).toOpaque())
+ let spinner = self.superview?.subviews.first(where: { view -> Bool in
+ return view.isKind(of: UIActivityIndicatorView.self) && view.tag == spinnerTag
+ })
- spinner?.removeFromSuperview()
- self.isHidden = false
- }
+ spinner?.removeFromSuperview()
+ self.isHidden = false
+ }
+
+ func setBackgroundColor(_ color: UIColor, for forState: UIControl.State) {
+ UIGraphicsBeginImageContext(CGSize(width: 1, height: 1))
+ UIGraphicsGetCurrentContext()!.setFillColor(color.cgColor)
+ UIGraphicsGetCurrentContext()!.fill(CGRect(x: 0, y: 0, width: 1, height: 1))
+ let colorImage = UIGraphicsGetImageFromCurrentImageContext()
+ UIGraphicsEndImageContext()
+ self.setBackgroundImage(colorImage, for: forState)
+ }
}
diff --git a/iOSClient/Extensions/UIToolbar+Extension.swift b/iOSClient/Extensions/UIToolbar+Extension.swift
index 1cf1f6f86b..c457f56493 100644
--- a/iOSClient/Extensions/UIToolbar+Extension.swift
+++ b/iOSClient/Extensions/UIToolbar+Extension.swift
@@ -58,6 +58,20 @@ extension UIToolbar {
])
return view
}
+
+ static func doneToolbar(completion: @escaping () -> Void) -> UIToolbar {
+ let doneToolbar: UIToolbar = UIToolbar(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
+ doneToolbar.barStyle = .default
+
+ let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
+ let done: UIBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .done) {
+ completion()
+ }
+ let items = [flexSpace, done]
+ doneToolbar.items = items
+ doneToolbar.sizeToFit()
+ return doneToolbar
+ }
}
// https://stackoverflow.com/a/67985180/9506784
diff --git a/iOSClient/Extensions/UIView+Extension.swift b/iOSClient/Extensions/UIView+Extension.swift
index 193198ec46..71084ad547 100644
--- a/iOSClient/Extensions/UIView+Extension.swift
+++ b/iOSClient/Extensions/UIView+Extension.swift
@@ -24,10 +24,43 @@
import Foundation
import UIKit
+enum VerticalLocation: String {
+ case bottom
+ case top
+}
+
extension UIView {
func makeCircularBackground(withColor backgroundColor: UIColor) {
self.backgroundColor = backgroundColor
self.layer.cornerRadius = self.frame.size.width / 2
self.layer.masksToBounds = true
}
+
+ var parentTabBarController: UITabBarController? {
+ var responder: UIResponder? = self
+ while let nextResponder = responder?.next {
+ if let tabBarController = nextResponder as? UITabBarController {
+ return tabBarController
+ }
+ responder = nextResponder
+ }
+ return nil
+ }
+
+ func addShadow(location: VerticalLocation, height: CGFloat = 2, color: UIColor = NCBrandColor.shared.customerDarkGrey, opacity: Float = 0.4, radius: CGFloat = 2) {
+ switch location {
+ case .bottom:
+ addShadow(offset: CGSize(width: 0, height: height), color: color, opacity: opacity, radius: radius)
+ case .top:
+ addShadow(offset: CGSize(width: 0, height: -height), color: color, opacity: opacity, radius: radius)
+ }
+ }
+
+ func addShadow(offset: CGSize, color: UIColor = .black, opacity: Float = 0.5, radius: CGFloat = 5.0) {
+ self.layer.masksToBounds = false
+ self.layer.shadowColor = color.cgColor
+ self.layer.shadowOffset = offset
+ self.layer.shadowOpacity = opacity
+ self.layer.shadowRadius = radius
+ }
}
diff --git a/iOSClient/Menu/NCShare+Menu.swift b/iOSClient/Menu/NCShare+Menu.swift
index f4cc7a23fd..83ef4c5791 100644
--- a/iOSClient/Menu/NCShare+Menu.swift
+++ b/iOSClient/Menu/NCShare+Menu.swift
@@ -36,8 +36,17 @@ extension NCShare {
title: NSLocalizedString("_share_add_sharelink_", comment: ""),
icon: utility.loadImage(named: "plus", colors: [NCBrandColor.shared.iconImageColor]),
sender: sender,
+// func toggleShareMenu(for share: tableShare, sendMail: Bool, folder: Bool, sender: Any) {
+//
+// var actions = [NCMenuAction]()
+//
+// if !folder {
+// actions.append(
+// NCMenuAction(
+// title: NSLocalizedString("_open_in_", comment: ""),
+// icon: utility.loadImage(named: "viewInFolder").imageColor(NCBrandColor.shared.brandElement),
action: { _ in
- self.makeNewLinkShare()
+ NCShareCommon().copyLink(link: share.url, viewController: self, sender: sender)
}
)
)
@@ -45,16 +54,20 @@ extension NCShare {
actions.append(
NCMenuAction(
- title: NSLocalizedString("_details_", comment: ""),
- icon: utility.loadImage(named: "pencil", colors: [NCBrandColor.shared.iconImageColor]),
+ title: NSLocalizedString("_advance_permissions_", comment: ""),
+ icon: utility.loadImage(named: "rename").imageColor(NCBrandColor.shared.brandElement),
accessibilityIdentifier: "shareMenu/details",
sender: sender,
+// title: NSLocalizedString("_details_", comment: ""),
+// icon: utility.loadImage(named: "pencil", colors: [NCBrandColor.shared.iconImageColor]),
+// accessibilityIdentifier: "shareMenu/details",
+
action: { _ in
guard
let advancePermission = UIStoryboard(name: "NCShare", bundle: nil).instantiateViewController(withIdentifier: "NCShareAdvancePermission") as? NCShareAdvancePermission,
let navigationController = self.navigationController, !share.isInvalidated else { return }
advancePermission.networking = self.networking
- advancePermission.share = tableShare(value: share)
+ advancePermission.share = share
advancePermission.oldTableShare = tableShare(value: share)
advancePermission.metadata = self.metadata
@@ -66,12 +79,29 @@ extension NCShare {
}
)
)
-
+
+ if sendMail {
+ actions.append(
+ NCMenuAction(
+ title: NSLocalizedString("_send_new_email_", comment: ""),
+ icon: NCUtility().loadImage(named: "email").imageColor(NCBrandColor.shared.brandElement),
+ action: { menuAction in
+ let storyboard = UIStoryboard(name: "NCShare", bundle: nil)
+ guard let viewNewUserComment = storyboard.instantiateViewController(withIdentifier: "NCShareNewUserAddComment") as? NCShareNewUserAddComment else { return }
+ viewNewUserComment.metadata = self.metadata
+ viewNewUserComment.share = tableShare(value: share)
+ viewNewUserComment.networking = self.networking
+ self.navigationController?.pushViewController(viewNewUserComment, animated: true)
+ }
+ )
+ )
+ }
+
actions.append(
NCMenuAction(
title: NSLocalizedString("_share_unshare_", comment: ""),
destructive: true,
- icon: utility.loadImage(named: "person.2.slash"),
+ icon: utility.loadImage(named: "trash").imageColor(NCBrandColor.shared.brandElement),
sender: sender,
action: { _ in
Task {
@@ -110,9 +140,12 @@ extension NCShare {
}
),
NCMenuAction(
- title: NSLocalizedString("_share_editing_", comment: ""),
+// title: NSLocalizedString("_share_editing_", comment: ""),
+ title: isDirectory ? NSLocalizedString("_share_allow_upload_", comment: "") : NSLocalizedString("_share_editing_", comment: ""),
icon: utility.loadImage(named: "pencil", colors: [NCBrandColor.shared.iconImageColor]),
selected: hasUploadPermission(tableShare: share),
+// icon: UIImage(),
+// selected: hasUploadPermission(tableShare: tableShare),
on: false,
sender: sender,
action: { _ in
@@ -155,7 +188,7 @@ extension NCShare {
}
), at: 2)
}
-
+
self.presentMenu(with: actions, sender: sender)
}
diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift
index 51df24b68c..ffc823e651 100644
--- a/iOSClient/NCGlobal.swift
+++ b/iOSClient/NCGlobal.swift
@@ -281,6 +281,15 @@ final class NCGlobal: Sendable {
let notificationCenterEnableSwipeGesture = "enableSwipeGesture"
let notificationCenterDisableSwipeGesture = "disableSwipeGesture"
+
+ let notificationCenterShareViewIn = "ShareViewIn"
+ let notificationCenterShareAdvancePermission = "ShareAdvancePermission"
+ let notificationCenterShareSendEmail = "ShareSendEmail"
+ let notificationCenterShareUnshare = "ShareUnshare"
+ let notificationCenterStatusReadOnly = "statusReadOnly"
+ let notificationCenterStatusEditing = "statusEditing"
+ let notificationCenterStatusFileDrop = "statusFileDrop"
+
let notificationCenterPlayerIsPlaying = "playerIsPlaying"
let notificationCenterPlayerStoppedPlaying = "playerStoppedPlaying"
diff --git a/iOSClient/Networking/NCDownloadAction.swift b/iOSClient/Networking/NCDownloadAction.swift
new file mode 100644
index 0000000000..3bb2c23f67
--- /dev/null
+++ b/iOSClient/Networking/NCDownloadAction.swift
@@ -0,0 +1,579 @@
+// SPDX-FileCopyrightText: Nextcloud GmbH
+// SPDX-FileCopyrightText: 2020 Marino Faggiana
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+import UIKit
+import NextcloudKit
+import Queuer
+import SVGKit
+import Photos
+import Alamofire
+
+class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSelectDelegate, NCTransferDelegate {
+ static let shared = NCDownloadAction()
+
+ var viewerQuickLook: NCViewerQuickLook?
+ var documentController: UIDocumentInteractionController?
+ let utilityFileSystem = NCUtilityFileSystem()
+ let utility = NCUtility()
+ let database = NCManageDatabase.shared
+ let global = NCGlobal.shared
+ var sceneIdentifier: String = ""
+
+ override private init() { }
+
+ func setup(sceneIdentifier: String) {
+ self.sceneIdentifier = sceneIdentifier
+
+ NCNetworking.shared.addDelegate(self)
+ }
+
+ // MARK: - Download
+
+ func transferChange(status: String, metadata: tableMetadata, error: NKError) {
+ DispatchQueue.main.async {
+ switch status {
+ /// DOWNLOADED
+ case self.global.networkingStatusDownloaded:
+ self.downloadedFile(metadata: metadata, error: error)
+ default:
+ break
+ }
+ }
+ }
+
+ func downloadedFile(metadata: tableMetadata, error: NKError) {
+ guard error == .success else {
+ return
+ }
+ /// Select UIWindowScene active in serverUrl
+ var controller: NCMainTabBarController?
+ let windowScenes = UIApplication.shared.connectedScenes.compactMap { $0 as? UIWindowScene }
+ if windowScenes.count == 1 {
+ controller = UIApplication.shared.firstWindow?.rootViewController as? NCMainTabBarController
+ } else if let sceneIdentifier = metadata.sceneIdentifier,
+ let tabBarController = SceneManager.shared.getController(sceneIdentifier: sceneIdentifier) {
+ controller = tabBarController
+ } else {
+ for windowScene in windowScenes {
+ if let rootViewController = windowScene.keyWindow?.rootViewController as? NCMainTabBarController,
+ rootViewController.currentServerUrl() == metadata.serverUrl {
+ controller = rootViewController
+ break
+ }
+ }
+ }
+ guard let controller else { return }
+
+ switch metadata.sessionSelector {
+ case NCGlobal.shared.selectorLoadFileQuickLook:
+
+ let fileNamePath = self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
+ let fileNameTemp = NSTemporaryDirectory() + metadata.fileNameView
+ let viewerQuickLook = NCViewerQuickLook(with: URL(fileURLWithPath: fileNameTemp), isEditingEnabled: true, metadata: metadata)
+ if let image = UIImage(contentsOfFile: fileNamePath) {
+ if let data = image.jpegData(compressionQuality: 1) {
+ do {
+ try data.write(to: URL(fileURLWithPath: fileNameTemp))
+ } catch {
+ return
+ }
+ }
+ let navigationController = UINavigationController(rootViewController: viewerQuickLook)
+ navigationController.modalPresentationStyle = .fullScreen
+ controller.present(navigationController, animated: true)
+ } else {
+ self.utilityFileSystem.copyFile(atPath: fileNamePath, toPath: fileNameTemp)
+ controller.present(viewerQuickLook, animated: true)
+ }
+
+ case NCGlobal.shared.selectorLoadFileView:
+ guard !isAppInBackground
+ else {
+ return
+ }
+
+ if metadata.contentType.contains("opendocument") && !self.utility.isTypeFileRichDocument(metadata) {
+ self.openActivityViewController(selectedMetadata: [metadata], controller: controller, sender: nil)
+ } else if metadata.classFile == NKTypeClassFile.compress.rawValue || metadata.classFile == NKTypeClassFile.unknow.rawValue {
+ self.openActivityViewController(selectedMetadata: [metadata], controller: controller, sender: nil)
+ } else {
+ if let viewController = controller.currentViewController() {
+ let image = self.utility.getImage(ocId: metadata.ocId, etag: metadata.etag, ext: NCGlobal.shared.previewExt1024)
+ NCViewer().view(viewController: viewController, metadata: metadata, image: image)
+ }
+ }
+
+ case NCGlobal.shared.selectorOpenIn:
+ guard !isAppInBackground
+ else {
+ return
+ }
+
+ self.openActivityViewController(selectedMetadata: [metadata], controller: controller, sender: nil)
+
+ case NCGlobal.shared.selectorSaveAlbum:
+
+ self.saveAlbum(metadata: metadata, controller: controller)
+
+ case NCGlobal.shared.selectorSaveAsScan:
+
+ self.saveAsScan(metadata: metadata, controller: controller)
+
+ case NCGlobal.shared.selectorOpenDetail:
+ NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterOpenMediaDetail, userInfo: ["ocId": metadata.ocId])
+
+ default:
+ let applicationHandle = NCApplicationHandle()
+ applicationHandle.downloadedFile(selector: metadata.sessionSelector, metadata: metadata)
+ }
+ }
+
+ // MARK: -
+
+ func setMetadataAvalableOffline(_ metadata: tableMetadata, isOffline: Bool) async {
+ if isOffline {
+ if metadata.directory {
+ await self.database.setDirectoryAsync(serverUrl: metadata.serverUrlFileName, offline: false, metadata: metadata)
+ let predicate = NSPredicate(format: "account == %@ AND serverUrl BEGINSWITH %@ AND sessionSelector == %@ AND status == %d", metadata.account, metadata.serverUrlFileName, NCGlobal.shared.selectorSynchronizationOffline, NCGlobal.shared.metadataStatusWaitDownload)
+ if let metadatas = await database.getMetadatasAsync(predicate: predicate) {
+ await database.clearMetadatasSessionAsync(metadatas: metadatas)
+ }
+ } else {
+ await database.setOffLocalFileAsync(ocId: metadata.ocId)
+ }
+ } else if metadata.directory {
+ await database.setDirectoryAsync(serverUrl: metadata.serverUrlFileName, offline: true, metadata: metadata)
+ await self.database.cleanTablesOcIds(account: metadata.account)
+ await NCNetworking.shared.synchronization(account: metadata.account, serverUrl: metadata.serverUrlFileName, metadatasInDownload: nil)
+ } else {
+ var metadatasSynchronizationOffline: [tableMetadata] = []
+ metadatasSynchronizationOffline.append(metadata)
+ if let metadata = await database.getMetadataLivePhotoAsync(metadata: metadata) {
+ metadatasSynchronizationOffline.append(metadata)
+ }
+ await database.addLocalFileAsync(metadata: metadata, offline: true)
+ for metadata in metadatasSynchronizationOffline {
+ await database.setMetadataSessionInWaitDownloadAsync(ocId: metadata.ocId,
+ session: NCNetworking.shared.sessionDownloadBackground,
+ selector: NCGlobal.shared.selectorSynchronizationOffline)
+ }
+ }
+ }
+
+ // MARK: -
+
+ @MainActor
+ func viewerFile(account: String, fileId: String, viewController: UIViewController) async {
+ var downloadRequest: DownloadRequest?
+ let hud = NCHud(viewController.tabBarController?.view)
+
+ if let metadata = await database.getMetadataFromFileIdAsync(fileId) {
+ do {
+ let attr = try FileManager.default.attributesOfItem(atPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView))
+ let fileSize = attr[FileAttributeKey.size] as? UInt64 ?? 0
+ if fileSize > 0 {
+ NCViewer().view(viewController: viewController, metadata: metadata)
+ return
+ }
+ } catch {
+ print("Error: \(error)")
+ }
+ }
+
+ hud.initHudRing(tapToCancelDetailText: true) {
+ if let request = downloadRequest {
+ request.cancel()
+ }
+ }
+
+ let resultsFile = await NextcloudKit.shared.getFileFromFileIdAsync(fileId: fileId, account: account)
+ hud.dismiss()
+ guard resultsFile.error == .success, let file = resultsFile.file else {
+ NCContentPresenter().showError(error: resultsFile.error)
+ return
+ }
+
+ let isDirectoryE2EE = await self.utilityFileSystem.isDirectoryE2EEAsync(file: file)
+ let metadata = await self.database.convertFileToMetadataAsync(file, isDirectoryE2EE: isDirectoryE2EE)
+ await self.database.addMetadataAsync(metadata)
+
+ let fileNameLocalPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
+
+ if metadata.isAudioOrVideo {
+ NCViewer().view(viewController: viewController, metadata: metadata)
+ return
+ }
+
+ hud.show()
+ let download = await NextcloudKit.shared.downloadAsync(serverUrlFileName: metadata.serverUrlFileName, fileNameLocalPath: fileNameLocalPath, account: account) { request in
+ downloadRequest = request
+ } taskHandler: { task in
+ Task {
+ await self.database.setMetadataSessionAsync(ocId: metadata.ocId,
+ sessionTaskIdentifier: task.taskIdentifier,
+ status: self.global.metadataStatusDownloading)
+ }
+ } progressHandler: { progress in
+ hud.progress(progress.fractionCompleted)
+ }
+
+ hud.dismiss()
+ await self.database.setMetadataSessionAsync(ocId: metadata.ocId,
+ session: "",
+ sessionTaskIdentifier: 0,
+ sessionError: "",
+ status: self.global.metadataStatusNormal,
+ etag: download.etag)
+
+ if download.nkError == .success {
+ await self.database.addLocalFileAsync(metadata: metadata)
+ NCViewer().view(viewController: viewController, metadata: metadata)
+ }
+ }
+
+ // MARK: -
+
+ func openShare(viewController: UIViewController, metadata: tableMetadata, page: NCBrandOptions.NCInfoPagingTab) {
+ var page = page
+ let capabilities = NKCapabilities.shared.getCapabilitiesBlocking(for: metadata.account)
+
+ NCActivityIndicator.shared.start(backgroundView: viewController.view)
+ NCNetworking.shared.readFile(serverUrlFileName: metadata.serverUrlFileName, account: metadata.account, queue: .main) { _, metadata, error in
+ NCActivityIndicator.shared.stop()
+
+ if let metadata = metadata, error == .success {
+ let shareNavigationController = UIStoryboard(name: "NCShare", bundle: nil).instantiateInitialViewController() as? UINavigationController
+ let shareViewController = shareNavigationController?.topViewController as? NCSharePaging
+
+ for value in NCBrandOptions.NCInfoPagingTab.allCases {
+ pages.append(value)
+ }
+
+ if capabilities.activity.isEmpty, let idx = pages.firstIndex(of: .activity) {
+ pages.remove(at: idx)
+ }
+ if !metadata.isSharable(), let idx = pages.firstIndex(of: .sharing) {
+ pages.remove(at: idx)
+ }
+
+ (pages, page) = NCApplicationHandle().filterPages(pages: pages, page: page, metadata: metadata)
+
+ shareViewController?.pages = pages
+// let shareViewController = shareNavigationController?.topViewController as? NCShare
+ shareViewController?.metadata = metadata
+ shareNavigationController?.modalPresentationStyle = .formSheet
+ if let shareNavigationController = shareNavigationController {
+ viewController.present(shareNavigationController, animated: true, completion: nil)
+ }
+ }
+ }
+ }
+
+ // MARK: - Open Activity [Share] ...
+
+ func openActivityViewController(selectedMetadata: [tableMetadata], controller: NCMainTabBarController?, sender: Any?) {
+ guard let controller else { return }
+ let metadatas = selectedMetadata.filter({ !$0.directory })
+ var urls: [URL] = []
+ var downloadMetadata: [(tableMetadata, URL)] = []
+
+ for metadata in metadatas {
+ let fileURL = URL(fileURLWithPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView))
+ if utilityFileSystem.fileProviderStorageExists(metadata) {
+ urls.append(fileURL)
+ } else {
+ downloadMetadata.append((metadata, fileURL))
+ }
+ }
+
+ let processor = ParallelWorker(n: 5, titleKey: "_downloading_", totalTasks: downloadMetadata.count, controller: controller)
+ for (metadata, url) in downloadMetadata {
+ processor.execute { completion in
+ Task {
+ guard let metadata = await self.database.setMetadataSessionInWaitDownloadAsync(ocId: metadata.ocId,
+ session: NCNetworking.shared.sessionDownload,
+ selector: "",
+ sceneIdentifier: controller.sceneIdentifier) else {
+ return completion()
+ }
+
+ NCNetworking.shared.download(metadata: metadata) {
+ } progressHandler: { progress in
+ processor.hud.progress(progress.fractionCompleted)
+ } completion: { _, _ in
+ if self.utilityFileSystem.fileProviderStorageExists(metadata) { urls.append(url) }
+ completion()
+ }
+ }
+ }
+ }
+
+ processor.completeWork {
+ guard !urls.isEmpty else { return }
+ let activityViewController = UIActivityViewController(activityItems: urls, applicationActivities: nil)
+
+ // iPad
+ if let popover = activityViewController.popoverPresentationController {
+ if let view = sender as? UIView {
+ popover.sourceView = view
+ popover.sourceRect = view.bounds
+ } else {
+ popover.sourceView = controller.view
+ popover.sourceRect = CGRect(x: controller.view.bounds.midX,
+ y: controller.view.bounds.midY,
+ width: 0,
+ height: 0)
+ popover.permittedArrowDirections = []
+ }
+ }
+
+ controller.present(activityViewController, animated: true)
+ }
+ }
+
+ // MARK: - Save as scan
+
+ func saveAsScan(metadata: tableMetadata, controller: NCMainTabBarController?) {
+ let fileNamePath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
+ let fileNameDestination = utilityFileSystem.createFileName("scan.png", fileDate: Date(), fileType: PHAssetMediaType.image, notUseMask: true)
+ let fileNamePathDestination = utilityFileSystem.directoryScan + "/" + fileNameDestination
+
+ utilityFileSystem.copyFile(atPath: fileNamePath, toPath: fileNamePathDestination)
+
+ if let navigationController = UIStoryboard(name: "NCScan", bundle: nil).instantiateInitialViewController() {
+ navigationController.modalPresentationStyle = UIModalPresentationStyle.pageSheet
+ let viewController = navigationController.presentedViewController as? NCScan
+ viewController?.serverUrl = controller?.currentServerUrl()
+ viewController?.controller = controller
+ controller?.present(navigationController, animated: true, completion: nil)
+ }
+ }
+
+ // MARK: - Save photo
+
+ func saveAlbum(metadata: tableMetadata, controller: NCMainTabBarController?) {
+ let fileNamePath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
+
+ NCAskAuthorization().askAuthorizationPhotoLibrary(controller: controller) { hasPermission in
+ guard hasPermission else {
+ let error = NKError(errorCode: NCGlobal.shared.errorFileNotSaved, errorDescription: "_access_photo_not_enabled_msg_")
+ return NCContentPresenter().messageNotification("_access_photo_not_enabled_", error: error, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error)
+ }
+
+ let errorSave = NKError(errorCode: NCGlobal.shared.errorFileNotSaved, errorDescription: "_file_not_saved_cameraroll_")
+
+ do {
+ if metadata.isImage {
+ let data = try Data(contentsOf: URL(fileURLWithPath: fileNamePath))
+ PHPhotoLibrary.shared().performChanges({
+ let assetRequest = PHAssetCreationRequest.forAsset()
+ assetRequest.addResource(with: .photo, data: data, options: nil)
+ }) { success, _ in
+ if !success {
+ NCContentPresenter().messageNotification("_save_selected_files_", error: errorSave, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error)
+ }
+ }
+ } else if metadata.isVideo {
+ PHPhotoLibrary.shared().performChanges({
+ PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: URL(fileURLWithPath: fileNamePath))
+ }) { success, _ in
+ if !success {
+ NCContentPresenter().messageNotification("_save_selected_files_", error: errorSave, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error)
+ }
+ }
+ } else {
+ NCContentPresenter().messageNotification("_save_selected_files_", error: errorSave, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error)
+ return
+ }
+ } catch {
+ NCContentPresenter().messageNotification("_save_selected_files_", error: errorSave, delay: NCGlobal.shared.dismissAfterSecond, type: NCContentPresenter.messageType.error)
+ }
+ }
+ }
+
+ // MARK: - Copy & Paste
+
+ func pastePasteboard(serverUrl: String, account: String, controller: NCMainTabBarController?) {
+ var fractionCompleted: Float = 0
+ let processor = ParallelWorker(n: 5, titleKey: "_status_uploading_", totalTasks: nil, controller: controller)
+
+ func uploadPastePasteboard(fileName: String, serverUrlFileName: String, fileNameLocalPath: String, serverUrl: String, completion: @escaping () -> Void) {
+ NextcloudKit.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, account: account) { _ in
+ } progressHandler: { progress in
+ if Float(progress.fractionCompleted) > fractionCompleted || fractionCompleted == 0 {
+ processor.hud.progress(progress.fractionCompleted)
+ fractionCompleted = Float(progress.fractionCompleted)
+ }
+ } completionHandler: { account, ocId, etag, _, _, _, error in
+ if error == .success && etag != nil && ocId != nil {
+ let toPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(ocId!, fileNameView: fileName)
+ self.utilityFileSystem.moveFile(atPath: fileNameLocalPath, toPath: toPath)
+ self.database.addLocalFile(account: account, etag: etag!, ocId: ocId!, fileName: fileName)
+ NCNetworking.shared.notifyAllDelegates { delegate in
+ delegate.transferRequestData(serverUrl: serverUrl)
+ }
+ } else {
+ NCContentPresenter().showError(error: error)
+ }
+ fractionCompleted = 0
+ completion()
+ }
+ }
+
+ for (index, items) in UIPasteboard.general.items.enumerated() {
+ for item in items {
+ let results = NKFilePropertyResolver().resolve(inUTI: item.key, account: account)
+ guard let data = UIPasteboard.general.data(forPasteboardType: item.key, inItemSet: IndexSet([index]))?.first else {
+ continue
+ }
+ let fileName = results.name + "_" + NCKeychain().incrementalNumber + "." + results.ext
+ let serverUrlFileName = serverUrl + "/" + fileName
+ let ocIdUpload = UUID().uuidString
+ let fileNameLocalPath = utilityFileSystem.getDirectoryProviderStorageOcId(ocIdUpload, fileNameView: fileName)
+ do { try data.write(to: URL(fileURLWithPath: fileNameLocalPath)) } catch { continue }
+ processor.execute { completion in
+ uploadPastePasteboard(fileName: fileName, serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, serverUrl: serverUrl, completion: completion)
+ }
+ }
+ }
+ processor.completeWork()
+ }
+
+ // MARK: -
+
+ func openFileViewInFolder(serverUrl: String, fileNameBlink: String?, fileNameOpen: String?, sceneIdentifier: String) {
+ guard let controller = SceneManager.shared.getController(sceneIdentifier: sceneIdentifier),
+ let navigationController = controller.viewControllers?.first as? UINavigationController
+ else { return }
+ let session = NCSession.shared.getSession(controller: controller)
+ var serverUrlPush = self.utilityFileSystem.getHomeServer(session: session)
+
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
+ navigationController.popToRootViewController(animated: false)
+ controller.selectedIndex = 0
+ if serverUrlPush == serverUrl,
+ let viewController = navigationController.topViewController as? NCFiles {
+ viewController.blinkCell(fileName: fileNameBlink)
+ viewController.openFile(fileName: fileNameOpen)
+ return
+ }
+
+ let diffDirectory = serverUrl.replacingOccurrences(of: serverUrlPush, with: "")
+ var subDirs = diffDirectory.split(separator: "/")
+
+ while serverUrlPush != serverUrl, !subDirs.isEmpty {
+
+ guard let dir = subDirs.first else { return }
+ serverUrlPush = serverUrlPush + "/" + dir
+
+ if let viewController = controller.navigationCollectionViewCommon.first(where: { $0.navigationController == navigationController && $0.serverUrl == serverUrlPush})?.viewController as? NCFiles, viewController.isViewLoaded {
+ viewController.fileNameBlink = fileNameBlink
+ viewController.fileNameOpen = fileNameOpen
+ navigationController.pushViewController(viewController, animated: false)
+ } else {
+ if let viewController: NCFiles = UIStoryboard(name: "NCFiles", bundle: nil).instantiateInitialViewController() as? NCFiles {
+ viewController.serverUrl = serverUrlPush
+ viewController.titleCurrentFolder = String(dir)
+ viewController.navigationItem.backButtonTitle = viewController.titleCurrentFolder
+
+ controller.navigationCollectionViewCommon.append(NavigationCollectionViewCommon(serverUrl: serverUrlPush, navigationController: navigationController, viewController: viewController))
+
+ if serverUrlPush == serverUrl {
+ viewController.fileNameBlink = fileNameBlink
+ viewController.fileNameOpen = fileNameOpen
+ }
+ navigationController.pushViewController(viewController, animated: false)
+ }
+ }
+ subDirs.remove(at: 0)
+ }
+ }
+ }
+
+ // MARK: - NCSelect + Delegate
+
+ func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool, session: NCSession.Session) {
+ if let serverUrl, !items.isEmpty {
+ if copy {
+ for case let metadata as tableMetadata in items {
+ if metadata.status != NCGlobal.shared.metadataStatusNormal, metadata.status != NCGlobal.shared.metadataStatusWaitCopy {
+ continue
+ }
+
+ NCNetworking.shared.copyMetadata(metadata, serverUrlTo: serverUrl, overwrite: overwrite)
+ }
+
+ } else if move {
+ for case let metadata as tableMetadata in items {
+ if metadata.status != NCGlobal.shared.metadataStatusNormal, metadata.status != NCGlobal.shared.metadataStatusWaitMove {
+ continue
+ }
+
+ NCNetworking.shared.moveMetadata(metadata, serverUrlTo: serverUrl, overwrite: overwrite)
+ }
+ }
+ }
+ }
+
+ func openSelectView(items: [tableMetadata], controller: NCMainTabBarController?) {
+ let session = NCSession.shared.getSession(controller: controller)
+ let navigationController = UIStoryboard(name: "NCSelect", bundle: nil).instantiateInitialViewController() as? UINavigationController
+ let topViewController = navigationController?.topViewController as? NCSelect
+ var listViewController = [NCSelect]()
+ var copyItems: [tableMetadata] = []
+ let capabilities = NKCapabilities.shared.getCapabilitiesBlocking(for: controller?.account ?? "")
+
+ for item in items {
+ if let fileNameError = FileNameValidator.checkFileName(item.fileNameView, account: controller?.account, capabilities: capabilities) {
+ controller?.present(UIAlertController.warning(message: "\(fileNameError.errorDescription) \(NSLocalizedString("_please_rename_file_", comment: ""))"), animated: true)
+ return
+ }
+ copyItems.append(item)
+ }
+
+ let homeUrl = utilityFileSystem.getHomeServer(session: session)
+ var serverUrl = copyItems[0].serverUrl
+
+ // Setup view controllers such that the current view is of the same directory the items to be copied are in
+ while true {
+ // If not in the topmost directory, create a new view controller and set correct title.
+ // If in the topmost directory, use the default view controller as the base.
+ var viewController: NCSelect?
+ if serverUrl != homeUrl {
+ viewController = UIStoryboard(name: "NCSelect", bundle: nil).instantiateViewController(withIdentifier: "NCSelect.storyboard") as? NCSelect
+ if viewController == nil {
+ return
+ }
+ viewController!.titleCurrentFolder = (serverUrl as NSString).lastPathComponent
+ } else {
+ viewController = topViewController
+ }
+ guard let vc = viewController else { return }
+
+ vc.delegate = self
+ vc.typeOfCommandView = .copyMove
+ vc.items = copyItems
+ vc.serverUrl = serverUrl
+ vc.session = session
+
+ vc.navigationItem.backButtonTitle = vc.titleCurrentFolder
+ listViewController.insert(vc, at: 0)
+
+ if serverUrl != homeUrl {
+ if let path = utilityFileSystem.deleteLastPath(serverUrlPath: serverUrl) {
+ serverUrl = path
+ }
+ } else {
+ break
+ }
+ }
+
+ navigationController?.setViewControllers(listViewController, animated: false)
+ navigationController?.modalPresentationStyle = .formSheet
+
+ if let navigationController = navigationController {
+ controller?.present(navigationController, animated: true, completion: nil)
+ }
+ }
+}
diff --git a/iOSClient/Scan document/PasswordInputField.swift b/iOSClient/Scan document/PasswordInputField.swift
new file mode 100644
index 0000000000..c2b893324b
--- /dev/null
+++ b/iOSClient/Scan document/PasswordInputField.swift
@@ -0,0 +1,75 @@
+//
+// PasswordInputField.swift
+// Nextcloud
+//
+// Created by Sumit on 10/06/21.
+// Copyright © 2021 Marino Faggiana. All rights reserved.
+//
+
+import Foundation
+
+class PasswordInputField: XLFormBaseCell,UITextFieldDelegate {
+
+ @IBOutlet weak var fileNameInputTextField: UITextField!
+ @IBOutlet weak var separatorBottom: UIView!
+
+ override func awakeFromNib() {
+ super.awakeFromNib()
+ // Initialization code
+ fileNameInputTextField.isSecureTextEntry = true
+ fileNameInputTextField.delegate = self
+ separatorBottom.backgroundColor = NCBrandColor.shared.systemGray4
+ self.selectionStyle = .none
+ fileNameInputTextField.inputAccessoryView = UIToolbar.doneToolbar {
+ self.fileNameInputTextField.resignFirstResponder()
+ }
+ }
+
+ override func setSelected(_ selected: Bool, animated: Bool) {
+ super.setSelected(selected, animated: animated)
+
+ // Configure the view for the selected state
+ }
+
+ override func configure() {
+ super.configure()
+ // fileNameInputTextField.isEnabled = false
+
+ }
+
+ override func update() {
+ super.update()
+ }
+
+ func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
+
+ if fileNameInputTextField == textField {
+ if let rowDescriptor = rowDescriptor, let text = self.fileNameInputTextField.text {
+
+ if (text + " ").isEmpty == false {
+ rowDescriptor.value = self.fileNameInputTextField.text! + string
+ } else {
+ rowDescriptor.value = nil
+ }
+ }
+ }
+
+ self.formViewController().textField(textField, shouldChangeCharactersIn: range, replacementString: string)
+
+ return true
+ }
+
+ func textFieldShouldReturn(_ textField: UITextField) -> Bool {
+ self.formViewController()?.textFieldShouldReturn(fileNameInputTextField)
+ return true
+ }
+
+ func textFieldShouldClear(_ textField: UITextField) -> Bool {
+ self.formViewController()?.textFieldShouldClear(fileNameInputTextField)
+ return true
+ }
+
+ override class func formDescriptorCellHeight(for rowDescriptor: XLFormRowDescriptor!) -> CGFloat {
+ return 45
+ }
+}
diff --git a/iOSClient/Scan document/PasswordInputField.xib b/iOSClient/Scan document/PasswordInputField.xib
new file mode 100644
index 0000000000..26914e0760
--- /dev/null
+++ b/iOSClient/Scan document/PasswordInputField.xib
@@ -0,0 +1,70 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iOSClient/Share/Advanced/NCFilePermissionCell.swift b/iOSClient/Share/Advanced/NCFilePermissionCell.swift
new file mode 100644
index 0000000000..4e5ec77f72
--- /dev/null
+++ b/iOSClient/Share/Advanced/NCFilePermissionCell.swift
@@ -0,0 +1,91 @@
+//
+// NCFilePermissionCell.swift
+// Nextcloud
+//
+// Created by T-systems on 17/08/21.
+// Copyright © 2021 Marino Faggiana. All rights reserved.
+//
+
+import UIKit
+
+class NCFilePermissionCell: XLFormButtonCell {
+
+ @IBOutlet weak var seperator: UIView!
+ @IBOutlet weak var titleLabel: UILabel!
+ @IBOutlet weak var imageCheck: UIImageView!
+ @IBOutlet weak var seperatorBelow: UIView!
+ @IBOutlet weak var seperatorBelowFull: UIView!
+ @IBOutlet weak var titleLabelBottom: UILabel!
+
+ override func awakeFromNib() {
+ super.awakeFromNib()
+ self.selectionStyle = .none
+ self.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+ self.titleLabel.textColor = NCBrandColor.shared.label
+ NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil)
+ }
+
+ @objc func changeTheming() {
+ self.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+ self.titleLabel.textColor = NCBrandColor.shared.label
+ self.titleLabelBottom.textColor = NCBrandColor.shared.iconColor
+ }
+
+ override func configure() {
+ super.configure()
+ }
+
+
+ override func update() {
+ super.update()
+ self.selectionStyle = .none
+ if rowDescriptor.tag == "NCFilePermissionCellSharing" || rowDescriptor.tag == "NCFilePermissionCellAdvanceTxt" {
+ self.seperator.isHidden = true
+ self.seperatorBelowFull.isHidden = true
+ self.seperatorBelow.isHidden = true
+ self.titleLabel.font = UIFont.boldSystemFont(ofSize: 17)
+ self.titleLabelBottom.font = UIFont.boldSystemFont(ofSize: 17)
+ }
+ if rowDescriptor.tag == "kNMCFilePermissionCellEditing" {
+ self.seperator.isHidden = true
+// self.seperatorBelowFull.isHidden = true
+ }
+
+ if rowDescriptor.tag == "NCFilePermissionCellFileDrop" {
+ self.seperator.isHidden = true
+ self.seperatorBelow.isHidden = false
+ self.seperatorBelowFull.isHidden = true
+ }
+
+ if rowDescriptor.tag == "kNMCFilePermissionEditCellEditingCanShare" {
+ self.seperator.isHidden = true
+ self.seperatorBelowFull.isHidden = false
+ }
+
+ if rowDescriptor.tag == "kNMCFilePermissionCellEditingMsg" {
+ self.seperator.isHidden = true
+ self.seperatorBelow.isHidden = true
+ self.seperatorBelowFull.isHidden = false
+ }
+
+ if rowDescriptor.tag == "kNMCFilePermissionCellFiledropMessage" {
+ self.seperator.isHidden = true
+ self.seperatorBelow.isHidden = true
+ self.seperatorBelowFull.isHidden = false
+ self.imageCheck.isHidden = true
+ }
+ }
+
+ @objc func switchChanged(mySwitch: UISwitch) {
+ self.rowDescriptor.value = mySwitch.isOn
+ }
+
+ override func formDescriptorCellDidSelected(withForm controller: XLFormViewController!) {
+ self.selectionStyle = .none
+ }
+
+ override class func formDescriptorCellHeight(for rowDescriptor: XLFormRowDescriptor!) -> CGFloat {
+ return 44.0
+ }
+
+}
diff --git a/iOSClient/Share/Advanced/NCFilePermissionCell.xib b/iOSClient/Share/Advanced/NCFilePermissionCell.xib
new file mode 100644
index 0000000000..e40c22e14d
--- /dev/null
+++ b/iOSClient/Share/Advanced/NCFilePermissionCell.xib
@@ -0,0 +1,95 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iOSClient/Share/Advanced/NCFilePermissionEditCell.swift b/iOSClient/Share/Advanced/NCFilePermissionEditCell.swift
new file mode 100644
index 0000000000..b32d66a74f
--- /dev/null
+++ b/iOSClient/Share/Advanced/NCFilePermissionEditCell.swift
@@ -0,0 +1,176 @@
+//
+// NCFilePermissionEditCell.swift
+// Nextcloud
+//
+// Created by T-systems on 10/08/21.
+// Copyright © 2021 Marino Faggiana. All rights reserved.
+//
+
+import UIKit
+
+class NCFilePermissionEditCell: XLFormBaseCell, UITextFieldDelegate {
+
+ @IBOutlet weak var seperator: UIView!
+ @IBOutlet weak var seperatorMiddle: UIView!
+ @IBOutlet weak var seperatorBottom: UIView!
+ @IBOutlet weak var titleLabel: UILabel!
+ @IBOutlet weak var switchControl: UISwitch!
+ @IBOutlet weak var cellTextField: UITextField!
+ @IBOutlet weak var buttonLinkLabel: UIButton!
+ let datePicker = UIDatePicker()
+ var expirationDateText: String!
+ var expirationDate: NSDate!
+
+ override func awakeFromNib() {
+ super.awakeFromNib()
+ self.cellTextField.delegate = self
+ self.cellTextField.isEnabled = false
+ self.selectionStyle = .none
+ switchControl.addTarget(self, action: #selector(switchChanged), for: UIControl.Event.valueChanged)
+ self.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+ self.titleLabel.textColor = NCBrandColor.shared.label
+ self.cellTextField.attributedPlaceholder = NSAttributedString(string: "",
+ attributes: [NSAttributedString.Key.foregroundColor: NCBrandColor.shared.fileFolderName])
+ self.cellTextField.textColor = NCBrandColor.shared.singleTitleColorButton
+ NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil)
+ }
+
+ @objc func changeTheming() {
+ self.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+ self.titleLabel.textColor = NCBrandColor.shared.iconColor
+ }
+
+ override func configure() {
+ super.configure()
+ }
+
+ override func update() {
+ super.update()
+
+ if rowDescriptor.tag == "kNMCFilePermissionCellEditingCanShare" {
+ self.seperatorMiddle.isHidden = true
+ self.seperatorBottom.isHidden = true
+ self.cellTextField.isHidden = true
+ }
+ if rowDescriptor.tag == "kNMCFilePermissionEditCellLinkLabel" {
+ self.switchControl.isHidden = true
+ self.cellTextField.isEnabled = true
+ self.seperatorBottom.isHidden = true
+ }
+ if rowDescriptor.tag == "kNMCFilePermissionEditCellLinkLabel" {
+ self.switchControl.isHidden = true
+ }
+
+ if rowDescriptor.tag == "kNMCFilePermissionEditCellExpiration" {
+ self.seperator.isHidden = true
+ setDatePicker(sender: self.cellTextField)
+ }
+
+ if rowDescriptor.tag == "kNMCFilePermissionEditPasswordCellWithText" {
+ self.seperatorMiddle.isHidden = true
+ self.seperator.isHidden = true
+ }
+
+ if rowDescriptor.tag == "kNMCFilePermissionEditCellHideDownload" {
+ self.seperator.isHidden = true
+ self.seperatorMiddle.isHidden = true
+ }
+
+ if rowDescriptor.tag == "kNMCFilePermissionEditCellEditingCanShare" {
+ self.seperator.isHidden = true
+ self.seperatorBottom.isHidden = true
+ }
+ }
+
+ @objc func switchChanged(mySwitch: UISwitch) {
+ let isOn = mySwitch.isOn
+ if isOn {
+ //on
+ self.rowDescriptor.value = isOn
+ self.cellTextField.isEnabled = true
+ cellTextField.delegate = self
+ } else {
+ self.rowDescriptor.value = isOn
+ self.cellTextField.isEnabled = false
+ if rowDescriptor.tag == "kNMCFilePermissionEditCellExpiration" || rowDescriptor.tag == "kNMCFilePermissionEditCellPassword" {
+ self.cellTextField.text = ""
+ }
+ }
+ if rowDescriptor.tag == "kNMCFilePermissionEditPasswordCellWithText" {
+ seperatorBottom.isHidden = isOn
+ seperatorMiddle.isHidden = !isOn
+ }
+ if rowDescriptor.tag == "kNMCFilePermissionEditCellExpiration" {
+ seperatorBottom.isHidden = isOn
+ seperatorMiddle.isHidden = !isOn
+ }
+ }
+
+ func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
+ if self.cellTextField == textField {
+ if let rowDescriptor = rowDescriptor, let text = self.cellTextField.text {
+
+ if (text + " ").isEmpty == false {
+ rowDescriptor.value = self.cellTextField.text! + string
+ } else {
+ rowDescriptor.value = nil
+ }
+ }
+ }
+
+ self.formViewController().textField(textField, shouldChangeCharactersIn: range, replacementString: string)
+ return true
+ }
+
+ func textFieldShouldReturn(_ textField: UITextField) -> Bool {
+ self.formViewController()?.textFieldShouldReturn(textField)
+ return true
+ }
+
+ func textFieldShouldClear(_ textField: UITextField) -> Bool {
+ self.formViewController()?.textFieldShouldClear(textField)
+ return true
+ }
+
+ override class func formDescriptorCellHeight(for rowDescriptor: XLFormRowDescriptor!) -> CGFloat {
+ return 30
+ }
+
+ override func formDescriptorCellDidSelected(withForm controller: XLFormViewController!) {
+ self.selectionStyle = .none
+ }
+
+ func setDatePicker(sender: UITextField) {
+ //Format Date
+ datePicker.datePickerMode = .date
+ datePicker.minimumDate = Date()
+ //ToolBar
+ let toolbar = UIToolbar();
+ toolbar.sizeToFit()
+ let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .plain, target: self, action: #selector(doneDatePicker));
+ let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
+ let cancelButton = UIBarButtonItem(title: NSLocalizedString("_cancel_", comment: ""), style: .plain, target: self, action: #selector(cancelDatePicker));
+
+ toolbar.setItems([doneButton,spaceButton,cancelButton], animated: false)
+
+ sender.inputAccessoryView = toolbar
+ sender.inputView = datePicker
+ }
+
+ @objc func doneDatePicker() {
+ let dateFormatter = DateFormatter()
+ dateFormatter.formatterBehavior = .behavior10_4
+ dateFormatter.dateStyle = .medium
+ self.expirationDateText = dateFormatter.string(from: datePicker.date as Date)
+
+ dateFormatter.dateFormat = "YYYY-MM-dd HH:mm:ss"
+ self.expirationDate = datePicker.date as NSDate
+ self.cellTextField.text = self.expirationDateText
+ self.rowDescriptor.value = self.expirationDate
+ self.cellTextField.endEditing(true)
+ }
+
+ @objc func cancelDatePicker() {
+ self.cellTextField.endEditing(true)
+ }
+}
diff --git a/iOSClient/Share/Advanced/NCFilePermissionEditCell.xib b/iOSClient/Share/Advanced/NCFilePermissionEditCell.xib
new file mode 100644
index 0000000000..2a7aa3ac63
--- /dev/null
+++ b/iOSClient/Share/Advanced/NCFilePermissionEditCell.xib
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift
index f07ae37f0c..43fe39133d 100644
--- a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift
+++ b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift
@@ -27,6 +27,46 @@ import SVGKit
import CloudKit
class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDelegate, NCShareNavigationTitleSetting {
+//class NCShareAdvancePermission: XLFormViewController, NCShareAdvanceFotterDelegate, NCShareDetail {
+ func dismissShareAdvanceView(shouldSave: Bool) {
+ if shouldSave {
+ self.oldTableShare?.permissions = self.permission ?? (self.oldTableShare?.permissions ?? 0)
+ self.share.permissions = self.permission ?? (self.oldTableShare?.permissions ?? 0)
+ if isNewShare {
+ let storyboard = UIStoryboard(name: "NCShare", bundle: nil)
+ guard let viewNewUserComment = storyboard.instantiateViewController(withIdentifier: "NCShareNewUserAddComment") as? NCShareNewUserAddComment else { return }
+ viewNewUserComment.metadata = self.metadata
+ viewNewUserComment.share = self.share
+ viewNewUserComment.networking = self.networking
+ self.navigationController?.pushViewController(viewNewUserComment, animated: true)
+ } else {
+ if let downloadSwitchCell = getDownloadLimitSwitchCell() {
+ let isDownloadLimitOn = downloadSwitchCell.switchControl.isOn
+ if !isDownloadLimitOn {
+ setDownloadLimit(deleteLimit: true, limit: "")
+ } else {
+ let downloadLimitInputCell = getDownloadLimitInputCell()
+ let enteredDownloadLimit = downloadLimitInputCell?.cellTextField.text ?? ""
+ if enteredDownloadLimit.isEmpty {
+ showDownloadLimitError(message: NSLocalizedString("_share_download_limit_alert_empty_", comment: ""))
+ return
+ }
+ if let num = Int(enteredDownloadLimit), num < 1 {
+ showDownloadLimitError(message: NSLocalizedString("_share_download_limit_alert_zero_", comment: ""))
+ return
+ }
+ setDownloadLimit(deleteLimit: false, limit: enteredDownloadLimit)
+ }
+ }
+
+ networking?.updateShare(option: share)
+ navigationController?.popViewController(animated: true)
+ }
+ } else {
+ navigationController?.popViewController(animated: true)
+ }
+ }
+
let database = NCManageDatabase.shared
var oldTableShare: tableShare?
@@ -56,7 +96,14 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
var shareConfig: NCShareConfig!
var networking: NCShareNetworking?
-
+ let tableViewBottomInset: CGFloat = 80.0
+ lazy var shareType: Int = {
+ isNewShare ? share.shareType : oldTableShare?.shareType ?? NCShareCommon().SHARE_TYPE_USER
+ }()
+ static let displayDateFormat = "dd. MMM. yyyy"
+ var downloadLimit: DownloadLimit?
+ var permission: Int?
+
override func viewDidLoad() {
super.viewDidLoad()
self.shareConfig = NCShareConfig(parentMetadata: metadata, share: share)
@@ -78,10 +125,19 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
tableView.estimatedRowHeight = tableView.rowHeight
tableView.rowHeight = UITableView.automaticDimension
+
self.setNavigationTitle()
- self.navigationItem.hidesBackButton = true
- // disable pull to dimiss
+ // disbale pull to dimiss
isModalInPresentation = true
+ self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
+ self.permission = oldTableShare?.permissions
+ initializeForm()
+ changeTheming()
+ getDownloadLimit()
+ NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil)
+ NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
+
+ NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
}
override func viewWillLayoutSubviews() {
@@ -90,32 +146,60 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
setupHeaderView()
setupFooterView()
}
+
+ override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
+ if (UIDevice.current.userInterfaceIdiom == .phone), UIDevice().hasNotch {
+ let isLandscape = UIDevice.current.orientation.isLandscape
+ let tableViewWidth = isLandscape ? view.bounds.width - 80 : view.bounds.width
+ tableView.frame = CGRect(x: isLandscape ? 40 : 0, y: tableView.frame.minY, width: tableViewWidth, height: tableView.bounds.height)
+ tableView.layoutIfNeeded()
+ }
+ }
+
+ @objc func keyboardWillShow(_ notification:Notification) {
+ if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
+ tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height + 60, right: 0)
+ }
+ }
+
+ @objc func keyboardWillHide(_ notification:Notification) {
+ if ((notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {
+ tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: tableViewBottomInset, right: 0)
+ }
+ }
+ @objc func changeTheming() {
+ tableView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+ self.view.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+ self.navigationController?.navigationBar.tintColor = NCBrandColor.shared.customer
+ tableView.reloadData()
+ }
+
func setupFooterView() {
guard let footerView = (Bundle.main.loadNibNamed("NCShareAdvancePermissionFooter", owner: self, options: nil)?.first as? NCShareAdvancePermissionFooter) else { return }
footerView.setupUI(delegate: self, account: metadata.account)
// tableFooterView can't use auto layout directly
- let container = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 120))
- container.addSubview(footerView)
- tableView.tableFooterView = container
+ footerView.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 100)
+ self.view.addSubview(footerView)
footerView.translatesAutoresizingMaskIntoConstraints = false
- footerView.bottomAnchor.constraint(equalTo: container.bottomAnchor).isActive = true
- footerView.heightAnchor.constraint(equalTo: container.heightAnchor).isActive = true
- footerView.widthAnchor.constraint(equalTo: container.widthAnchor).isActive = true
+ footerView.bottomAnchor.constraint(equalTo: view.bottomAnchor).isActive = true
+ footerView.leftAnchor.constraint(equalTo: view.leftAnchor).isActive = true
+ footerView.rightAnchor.constraint(equalTo: view.rightAnchor).isActive = true
+ footerView.heightAnchor.constraint(equalToConstant: 100).isActive = true
+ tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: tableViewBottomInset, right: 0)
+
}
func setupHeaderView() {
guard let headerView = (Bundle.main.loadNibNamed("NCShareHeader", owner: self, options: nil)?.first as? NCShareHeader) else { return }
headerView.setupUI(with: metadata)
-
- let container = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: 220))
- container.addSubview(headerView)
- tableView.tableHeaderView = container
+ headerView.ocId = metadata.ocId
+ headerView.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 190)
+ self.tableView.tableHeaderView = headerView
headerView.translatesAutoresizingMaskIntoConstraints = false
- headerView.topAnchor.constraint(equalTo: container.topAnchor).isActive = true
- headerView.heightAnchor.constraint(equalTo: container.heightAnchor).isActive = true
- headerView.widthAnchor.constraint(equalTo: container.widthAnchor).isActive = true
+ headerView.heightAnchor.constraint(equalToConstant: 190).isActive = true
+ headerView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
@@ -149,8 +233,357 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
noteCell.detailTextLabel?.numberOfLines = 0
return noteCell
}
- if let cell = cell as? NCShareDateCell { cell.onReload = tableView.reloadData }
- return cell
+ }
+
+ func initializeForm() {
+ let form : XLFormDescriptor
+ var section : XLFormSectionDescriptor
+ var row : XLFormRowDescriptor
+
+ form = XLFormDescriptor(title: "Other Cells")
+
+ //Sharing
+ section = XLFormSectionDescriptor.formSection(withTitle: "")
+ XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCFilePermissionCell"] = NCFilePermissionCell.self
+ row = XLFormRowDescriptor(tag: "NCFilePermissionCellSharing", rowType: "kNMCFilePermissionCell", title: "")
+ row.cellConfig["titleLabel.text"] = NSLocalizedString("_sharing_", comment: "")
+ row.height = 44
+ section.addFormRow(row)
+
+ //PERMISSION
+ XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCShareHeaderCustomCell"] = NCShareHeaderCustomCell.self
+ row = XLFormRowDescriptor(tag: "kNMCShareHeaderCustomCell", rowType: "kNMCShareHeaderCustomCell", title: NSLocalizedString("_PERMISSIONS_", comment: ""))
+ row.height = 26
+ row.cellConfig["titleLabel.text"] = NSLocalizedString("_PERMISSIONS_", comment: "")
+ section.addFormRow(row)
+
+ //read only
+ XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCFilePermissionCell"] = NCFilePermissionCell.self
+ row = XLFormRowDescriptor(tag: "NCFilePermissionCellRead", rowType: "kNMCFilePermissionCell", title: NSLocalizedString("_PERMISSIONS_", comment: ""))
+ row.cellConfig["titleLabel.text"] = NSLocalizedString("_share_read_only_", comment: "")
+ row.height = 44
+
+ if let permission = self.permission, !CCUtility.isAnyPermission(toEdit: permission), permission != NCGlobal.shared.permissionCreateShare {
+ row.cellConfig["imageCheck.image"] = UIImage(named: "success")!.image(color: NCBrandColor.shared.customer, size: 25.0)
+ }
+ if isNewShare {
+ row.cellConfig["imageCheck.image"] = UIImage(named: "success")!.image(color: NCBrandColor.shared.customer, size: 25.0)
+ self.permission = NCGlobal.shared.permissionReadShare
+ }
+ section.addFormRow(row)
+
+ //editing
+ XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCFilePermissionCell"] = NCFilePermissionCell.self
+
+ row = XLFormRowDescriptor(tag: "kNMCFilePermissionCellEditing", rowType: "kNMCFilePermissionCell", title: NSLocalizedString("_PERMISSIONS_", comment: ""))
+ row.cellConfig["titleLabel.text"] = NSLocalizedString("_share_allow_editing_", comment: "")
+ row.height = 44
+ if let permission = self.permission {
+ if CCUtility.isAnyPermission(toEdit: permission), permission != NCGlobal.shared.permissionCreateShare {
+ row.cellConfig["imageCheck.image"] = UIImage(named: "success")!.image(color: NCBrandColor.shared.customer, size: 25.0)
+ }
+ }
+ let enabled = NCShareCommon().isEditingEnabled(isDirectory: metadata.directory, fileExtension: metadata.fileExtension, shareType: shareType) || checkIsCollaboraFile()
+ row.cellConfig["titleLabel.textColor"] = enabled ? NCBrandColor.shared.label : NCBrandColor.shared.systemGray
+ row.disabled = !enabled
+ section.addFormRow(row)
+
+ if !enabled {
+ row = XLFormRowDescriptor(tag: "kNMCFilePermissionCellEditingMsg", rowType: "kNMCFilePermissionCell", title: NSLocalizedString("_PERMISSIONS_", comment: ""))
+ row.cellConfig["titleLabel.text"] = NSLocalizedString("share_editing_message", comment: "")
+ row.cellConfig["titleLabel.textColor"] = NCBrandColor.shared.gray60
+ row.height = 80
+ section.addFormRow(row)
+ }
+
+ //file drop
+ if isFileDropOptionVisible() {
+ XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCFilePermissionCell"] = NCFilePermissionCell.self
+ row = XLFormRowDescriptor(tag: "NCFilePermissionCellFileDrop", rowType: "kNMCFilePermissionCell", title: NSLocalizedString("_PERMISSIONS_", comment: ""))
+ row.cellConfig["titleLabel.text"] = NSLocalizedString("_share_file_drop_", comment: "")
+ if self.permission == NCGlobal.shared.permissionCreateShare {
+ row.cellConfig["imageCheck.image"] = UIImage(named: "success")!.image(color: NCBrandColor.shared.customer, size: 25.0)
+ }
+ row.height = 44
+ section.addFormRow(row)
+
+ //sammelbox message
+ XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCFilePermissionCell"] = NCFilePermissionCell.self
+
+ row = XLFormRowDescriptor(tag: "kNMCFilePermissionCellFiledropMessage", rowType: "kNMCFilePermissionCell", title: NSLocalizedString("_PERMISSIONS_", comment: ""))
+ row.cellConfig["titleLabel.text"] = NSLocalizedString("_file_drop_message_", comment: "")
+ row.cellConfig["titleLabel.textColor"] = NCBrandColor.shared.gray60
+ row.cellConfig["imageCheck.image"] = UIImage()
+ row.height = 84
+ section.addFormRow(row)
+ }
+
+ //empty cell
+ XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCXLFormBaseCell"] = NCSeparatorCell.self
+ row = XLFormRowDescriptor(tag: "kNMCXLFormBaseCell", rowType: "kNMCXLFormBaseCell", title: NSLocalizedString("", comment: ""))
+ row.height = 16
+ section.addFormRow(row)
+
+ //ADVANCE PERMISSION
+ XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCFilePermissionCell"] = NCFilePermissionCell.self
+
+ row = XLFormRowDescriptor(tag: "NCFilePermissionCellAdvanceTxt", rowType: "kNMCFilePermissionCell", title: NSLocalizedString("_PERMISSIONS_", comment: ""))
+ row.cellConfig["titleLabel.text"] = NSLocalizedString("_advance_permissions_", comment: "")
+ row.height = 52
+ section.addFormRow(row)
+
+ if isLinkShare() {
+ //link label section header
+
+ // Custom Link label
+ XLFormViewController.cellClassesForRowDescriptorTypes()["kNCShareTextInputCell"] = NCShareTextInputCell.self
+ row = XLFormRowDescriptor(tag: "kNCShareTextInputCellCustomLinkField", rowType: "kNCShareTextInputCell", title: "")
+ row.cellConfig["cellTextField.placeholder"] = NSLocalizedString("_custom_link_label", comment: "")
+ row.cellConfig["cellTextField.text"] = oldTableShare?.label
+ row.cellConfig["cellTextField.textAlignment"] = NSTextAlignment.left.rawValue
+ row.cellConfig["cellTextField.font"] = UIFont.systemFont(ofSize: 15.0)
+ row.cellConfig["cellTextField.textColor"] = NCBrandColor.shared.label
+ row.height = 44
+ section.addFormRow(row)
+ }
+
+ //can reshare
+ if isCanReshareOptionVisible() {
+ XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCFilePermissionEditCell"] = NCFilePermissionEditCell.self
+
+ row = XLFormRowDescriptor(tag: "kNMCFilePermissionEditCellEditingCanShare", rowType: "kNMCFilePermissionEditCell", title: "")
+ row.cellConfig["switchControl.onTintColor"] = NCBrandColor.shared.customer
+ row.cellClass = NCFilePermissionEditCell.self
+ row.cellConfig["titleLabel.text"] = NSLocalizedString("_share_can_reshare_", comment: "")
+ row.height = 44
+ section.addFormRow(row)
+ }
+
+ //hide download
+ if isHideDownloadOptionVisible() {
+
+ XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCFilePermissionEditCell"] = NCFilePermissionEditCell.self
+ row = XLFormRowDescriptor(tag: "kNMCFilePermissionEditCellHideDownload", rowType: "kNMCFilePermissionEditCell", title: NSLocalizedString("_PERMISSIONS_", comment: ""))
+ row.cellConfig["titleLabel.text"] = NSLocalizedString("_share_hide_download_", comment: "")
+ row.cellConfig["switchControl.onTintColor"] = NCBrandColor.shared.customer
+ row.cellClass = NCFilePermissionEditCell.self
+ row.height = 44
+ section.addFormRow(row)
+ }
+
+ //password
+ if isPasswordOptionsVisible() {
+
+ // Set password
+ XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCFilePermissionEditCell"] = NCFilePermissionEditCell.self
+ row = XLFormRowDescriptor(tag: "kNMCFilePermissionEditPasswordCellWithText", rowType: "kNMCFilePermissionEditCell", title: NSLocalizedString("_PERMISSIONS_", comment: ""))
+ row.cellConfig["titleLabel.text"] = NSLocalizedString("_set_password_", comment: "")
+ row.cellConfig["switchControl.onTintColor"] = NCBrandColor.shared.customer
+ row.cellClass = NCFilePermissionEditCell.self
+ row.height = 44
+ section.addFormRow(row)
+
+ // enter password input field
+ XLFormViewController.cellClassesForRowDescriptorTypes()["NMCSetPasswordCustomInputField"] = PasswordInputField.self
+ row = XLFormRowDescriptor(tag: "SetPasswordInputField", rowType: "NMCSetPasswordCustomInputField", title: NSLocalizedString("_filename_", comment: ""))
+ row.cellClass = PasswordInputField.self
+ row.cellConfig["fileNameInputTextField.placeholder"] = NSLocalizedString("_password_", comment: "")
+ row.cellConfig["fileNameInputTextField.textAlignment"] = NSTextAlignment.left.rawValue
+ row.cellConfig["fileNameInputTextField.font"] = UIFont.systemFont(ofSize: 15.0)
+ row.cellConfig["fileNameInputTextField.textColor"] = NCBrandColor.shared.label
+ row.cellConfig["backgroundColor"] = NCBrandColor.shared.secondarySystemGroupedBackground
+ row.height = 44
+ let hasPassword = oldTableShare?.password != nil && !oldTableShare!.password.isEmpty
+ row.hidden = NSNumber.init(booleanLiteral: !hasPassword)
+ section.addFormRow(row)
+ }
+
+ //expiration
+
+ // expiry date switch
+ XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCFilePermissionEditCell"] = NCFilePermissionEditCell.self
+ row = XLFormRowDescriptor(tag: "kNMCFilePermissionEditCellExpiration", rowType: "kNMCFilePermissionEditCell", title: NSLocalizedString("_share_expiration_date_", comment: ""))
+ row.cellConfig["titleLabel.text"] = NSLocalizedString("_share_expiration_date_", comment: "")
+ row.cellConfig["switchControl.onTintColor"] = NCBrandColor.shared.customer
+ row.cellClass = NCFilePermissionEditCell.self
+ row.height = 44
+ section.addFormRow(row)
+
+ // set expiry date field
+ XLFormViewController.cellClassesForRowDescriptorTypes()["kNCShareTextInputCell"] = NCShareTextInputCell.self
+ row = XLFormRowDescriptor(tag: "NCShareTextInputCellExpiry", rowType: "kNCShareTextInputCell", title: "")
+ row.cellClass = NCShareTextInputCell.self
+ row.cellConfig["cellTextField.placeholder"] = NSLocalizedString("_share_expiration_date_placeholder_", comment: "")
+ if !isNewShare {
+ if let date = oldTableShare?.expirationDate {
+ row.cellConfig["cellTextField.text"] = DateFormatter.shareExpDate.string(from: date as Date)
+ }
+ }
+ row.cellConfig["cellTextField.textAlignment"] = NSTextAlignment.left.rawValue
+ row.cellConfig["cellTextField.font"] = UIFont.systemFont(ofSize: 15.0)
+ row.cellConfig["cellTextField.textColor"] = NCBrandColor.shared.label
+ if let date = oldTableShare?.expirationDate {
+ row.cellConfig["cellTextField.text"] = DateFormatter.shareExpDate.string(from: date as Date)
+ }
+ row.height = 44
+ let hasExpiry = oldTableShare?.expirationDate != nil
+ row.hidden = NSNumber.init(booleanLiteral: !hasExpiry)
+ section.addFormRow(row)
+
+ if isDownloadLimitVisible() {
+ // DownloadLimit switch
+ XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCFilePermissionEditCell"] = NCFilePermissionEditCell.self
+ row = XLFormRowDescriptor(tag: "kNMCFilePermissionEditCellDownloadLimit", rowType: "kNMCFilePermissionEditCell", title: NSLocalizedString("_share_download_limit_", comment: ""))
+ row.cellConfig["titleLabel.text"] = NSLocalizedString("_share_download_limit_", comment: "")
+ row.cellConfig["switchControl.onTintColor"] = NCBrandColor.shared.customer
+ row.cellClass = NCFilePermissionEditCell.self
+ row.height = 44
+ section.addFormRow(row)
+
+ // set Download Limit field
+ XLFormViewController.cellClassesForRowDescriptorTypes()["kNCShareTextInputCell"] = NCShareTextInputCell.self
+ row = XLFormRowDescriptor(tag: "NCShareTextInputCellDownloadLimit", rowType: "kNCShareTextInputCell", title: "")
+ row.cellClass = NCShareTextInputCell.self
+ row.cellConfig["cellTextField.placeholder"] = NSLocalizedString("_share_download_limit_placeholder_", comment: "")
+ row.cellConfig["cellTextField.textAlignment"] = NSTextAlignment.left.rawValue
+ row.cellConfig["cellTextField.font"] = UIFont.systemFont(ofSize: 15.0)
+ row.cellConfig["cellTextField.textColor"] = NCBrandColor.shared.label
+ row.height = 44
+ let downloadLimitSet = downloadLimit?.limit != nil
+ row.hidden = NSNumber.init(booleanLiteral: !downloadLimitSet)
+ if let value = downloadLimit?.limit {
+ row.cellConfig["cellTextField.text"] = "\(value)"
+ }
+ section.addFormRow(row)
+
+ XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCFilePermissionCell"] = NCFilePermissionCell.self
+ row = XLFormRowDescriptor(tag: "kNMCDownloadLimitCell", rowType: "kNMCFilePermissionCell", title: "")
+ row.cellClass = NCFilePermissionCell.self
+ row.height = 44
+ if downloadLimit?.limit != nil {
+ row.cellConfig["titleLabel.text"] = NSLocalizedString("_share_remaining_download_", comment: "") + " \(downloadLimit?.count ?? 0)"
+ }
+ row.cellConfig["titleLabel.textColor"] = NCBrandColor.shared.systemGray
+ row.disabled = true
+ row.hidden = NSNumber.init(booleanLiteral: !downloadLimitSet)
+ section.addFormRow(row)
+ }
+
+ form.addFormSection(section)
+ self.form = form
+ }
+
+ func reloadForm() {
+ self.form.delegate = nil
+ self.tableView.reloadData()
+ self.form.delegate = self
+ }
+
+ func updateDownloadLimitUI() {
+ if let value = downloadLimit?.limit {
+ if let downloadLimitSwitchField: XLFormRowDescriptor = self.form.formRow(withTag: "kNMCFilePermissionEditCellDownloadLimit") {
+ if let indexPath = self.form.indexPath(ofFormRow: downloadLimitSwitchField) {
+ let cell = tableView.cellForRow(at: indexPath) as? NCFilePermissionEditCell
+ cell?.switchControl.isOn = true
+ }
+
+ if let downloadLimitInputField: XLFormRowDescriptor = self.form.formRow(withTag: "NCShareTextInputCellDownloadLimit") {
+ downloadLimitInputField.hidden = false
+ if let indexPath = self.form.indexPath(ofFormRow: downloadLimitInputField) {
+ let cell = tableView.cellForRow(at: indexPath) as? NCShareTextInputCell
+ cell?.cellTextField.text = "\(value)"
+ }
+ }
+
+ if let downloadLimitInputField: XLFormRowDescriptor = self.form.formRow(withTag: "kNMCDownloadLimitCell") {
+ downloadLimitInputField.hidden = false
+ if let indexPath = self.form.indexPath(ofFormRow: downloadLimitInputField) {
+ let cell = tableView.cellForRow(at: indexPath) as? NCFilePermissionCell
+ cell?.titleLabel.text = NSLocalizedString("_share_remaining_download_", comment: "") + " \(downloadLimit?.count ?? 0)"
+ }
+ }
+ }
+ }
+ }
+
+ func getDownloadLimitSwitchCell() -> NCFilePermissionEditCell? {
+ if let downloadLimitSwitchField: XLFormRowDescriptor = self.form.formRow(withTag: "kNMCFilePermissionEditCellDownloadLimit") {
+ if let indexPath = self.form.indexPath(ofFormRow: downloadLimitSwitchField) {
+ let cell = tableView.cellForRow(at: indexPath) as? NCFilePermissionEditCell
+ return cell
+ }
+ }
+ return nil
+ }
+
+ func getDownloadLimitInputCell() -> NCShareTextInputCell? {
+ if let downloadLimitInputField: XLFormRowDescriptor = self.form.formRow(withTag: "NCShareTextInputCellDownloadLimit") {
+ if let indexPath = self.form.indexPath(ofFormRow: downloadLimitInputField) {
+ let cell = tableView.cellForRow(at: indexPath) as? NCShareTextInputCell
+ return cell
+ }
+ }
+ return nil
+ }
+
+ // MARK: - Row Descriptor Value Changed
+
+ override func didSelectFormRow(_ formRow: XLFormRowDescriptor!) {
+ guard let metadata = self.metadata else { return }
+
+ switch formRow.tag {
+ case "NCFilePermissionCellRead":
+
+ let value = CCUtility.getPermissionsValue(byCanEdit: false, andCanCreate: false, andCanChange: false, andCanDelete: false, andCanShare: canReshareTheShare(), andIsFolder: metadata.directory)
+ self.permission = value
+// self.permissions = "RDNVCK"
+ metadata.permissions = "RDNVCK"
+ if let row : XLFormRowDescriptor = self.form.formRow(withTag: "NCFilePermissionCellRead") {
+ row.cellConfig["imageCheck.image"] = UIImage(named: "success")!.image(color: NCBrandColor.shared.customer, size: 25.0)
+ if let row1 : XLFormRowDescriptor = self.form.formRow(withTag: "kNMCFilePermissionCellEditing") {
+ row1.cellConfig["imageCheck.image"] = UIImage(named: "success")!.image(color: .clear, size: 25.0)
+ }
+ if let row2 : XLFormRowDescriptor = self.form.formRow(withTag: "NCFilePermissionCellFileDrop") {
+ row2.cellConfig["imageCheck.image"] = UIImage(named: "success")!.image(color: .clear, size: 25.0)
+ }
+ }
+
+ self.reloadForm()
+ break
+ case "kNMCFilePermissionCellEditing":
+ let value = CCUtility.getPermissionsValue(byCanEdit: true, andCanCreate: true, andCanChange: true, andCanDelete: true, andCanShare: canReshareTheShare(), andIsFolder: metadata.directory)
+ self.permission = value
+// self.permissions = "RGDNV"
+ metadata.permissions = "RGDNV"
+ if let row : XLFormRowDescriptor = self.form.formRow(withTag: "NCFilePermissionCellRead") {
+ row.cellConfig["imageCheck.image"] = UIImage(named: "success")!.image(color: .clear, size: 25.0)
+ }
+ if let row1 : XLFormRowDescriptor = self.form.formRow(withTag: "kNMCFilePermissionCellEditing") {
+ row1.cellConfig["imageCheck.image"] = UIImage(named: "success")!.image(color: NCBrandColor.shared.customer, size: 25.0)
+ }
+ if let row2 : XLFormRowDescriptor = self.form.formRow(withTag: "NCFilePermissionCellFileDrop") {
+ row2.cellConfig["imageCheck.image"] = UIImage(named: "success")!.image(color: .clear, size: 25.0)
+ }
+ self.reloadForm()
+ break
+ case "NCFilePermissionCellFileDrop":
+ self.permission = NCGlobal.shared.permissionCreateShare
+// self.permissions = "RGDNVCK"
+ metadata.permissions = "RGDNVCK"
+ if let row : XLFormRowDescriptor = self.form.formRow(withTag: "NCFilePermissionCellRead") {
+ row.cellConfig["imageCheck.image"] = UIImage(named: "success")!.image(color: .clear, size: 25.0)
+ }
+ if let row1 : XLFormRowDescriptor = self.form.formRow(withTag: "kNMCFilePermissionCellEditing") {
+ row1.cellConfig["imageCheck.image"] = UIImage(named: "success")!.image(color: .clear, size: 25.0)
+ }
+ if let row2 : XLFormRowDescriptor = self.form.formRow(withTag: "NCFilePermissionCellFileDrop") {
+ row2.cellConfig["imageCheck.image"] = UIImage(named: "success")!.image(color: NCBrandColor.shared.customer, size: 25.0)
+ }
+ self.reloadForm()
+ break
+ default:
+ break
+ }
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
@@ -159,57 +592,293 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
guard let cellConfig = cellConfig as? NCAdvancedPermission else {
cellConfig.didSelect(for: share)
tableView.reloadData()
+ }
+ }
+
+ func canReshareTheShare() -> Bool {
+ if let permissionValue = self.permission {
+ let canReshare = CCUtility.isPermission(toCanShare: permissionValue)
+ return canReshare
+ } else {
+ return false
+ }
+ }
+
+ override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
+ if let advancePermissionHeaderRow: XLFormRowDescriptor = self.form.formRow(withTag: "NCFilePermissionCellAdvanceTxt") {
+ if let advancePermissionHeaderRowIndexPath = form.indexPath(ofFormRow: advancePermissionHeaderRow), indexPath == advancePermissionHeaderRowIndexPath {
+ let cell = cell as? NCFilePermissionCell
+ cell?.seperatorBelowFull.isHidden = isLinkShare()
+ }
+ }
+
+ //can Reshare
+ if let canReshareRow: XLFormRowDescriptor = self.form.formRow(withTag: "kNMCFilePermissionEditCellEditingCanShare") {
+ if let canReShareRowIndexPath = form.indexPath(ofFormRow: canReshareRow), indexPath == canReShareRowIndexPath {
+ let cell = cell as? NCFilePermissionEditCell
+ // Can reshare (file)
+ if let permissionValue = self.permission {
+ let canReshare = CCUtility.isPermission(toCanShare: permissionValue)
+ cell?.switchControl.isOn = canReshare
+ } else {
+ //new share
+ cell?.switchControl.isOn = false
+ }
+ }
+ }
+ //hide download
+ if let hideDownloadRow: XLFormRowDescriptor = self.form.formRow(withTag: "kNMCFilePermissionEditCellHideDownload"){
+ if let hideDownloadRowIndexPath = form.indexPath(ofFormRow: hideDownloadRow), indexPath == hideDownloadRowIndexPath {
+ let cell = cell as? NCFilePermissionEditCell
+ cell?.switchControl.isOn = oldTableShare?.hideDownload ?? false
+ cell?.titleLabel.isEnabled = !(self.permission == NCGlobal.shared.permissionCreateShare)
+ cell?.switchControl.isEnabled = !(self.permission == NCGlobal.shared.permissionCreateShare)
+ cell?.isUserInteractionEnabled = !(self.permission == NCGlobal.shared.permissionCreateShare)
+ }
+
+ // set password
+ if let setPassword : XLFormRowDescriptor = self.form.formRow(withTag: "kNMCFilePermissionEditPasswordCellWithText") {
+ if let setPasswordIndexPath = self.form.indexPath(ofFormRow: setPassword), indexPath == setPasswordIndexPath {
+ let passwordCell = cell as? NCFilePermissionEditCell
+ if let password = oldTableShare?.password {
+ passwordCell?.switchControl.isOn = !password.isEmpty
+ } else {
+ passwordCell?.switchControl.isOn = false
+ }
+ }
+ }
+ }
+
+ //updateExpiryDateSwitch
+ if let expiryRow : XLFormRowDescriptor = self.form.formRow(withTag: "kNMCFilePermissionEditCellExpiration") {
+ if let expiryIndexPath = self.form.indexPath(ofFormRow: expiryRow), indexPath == expiryIndexPath {
+ let cell = cell as? NCFilePermissionEditCell
+ if oldTableShare?.expirationDate != nil {
+ cell?.switchControl.isOn = true
+ } else {
+ //new share
+ cell?.switchControl.isOn = false
+ }
+ }
+ }
+
+ //SetDownloadLimitSwitch
+ if let limitRow : XLFormRowDescriptor = self.form.formRow(withTag: "kNMCFilePermissionEditCellDownloadLimit") {
+ if let expiryIndexPath = self.form.indexPath(ofFormRow: limitRow), indexPath == expiryIndexPath {
+ let cell = cell as? NCFilePermissionEditCell
+ cell?.switchControl.isOn = downloadLimit?.limit != nil
+ }
+ }
+
+ //SetDownloadLimitSwitch
+ if let downloadlimitFieldRow : XLFormRowDescriptor = self.form.formRow(withTag: "NCShareTextInputCellDownloadLimit") {
+ if let downloadlimitIndexPath = self.form.indexPath(ofFormRow: downloadlimitFieldRow), indexPath == downloadlimitIndexPath {
+ let cell = cell as? NCShareTextInputCell
+ cell?.cellTextField.text = "\(downloadLimit?.limit ?? 0)"
+ }
+ }
+
+ //SetDownloadLimitSwitch
+ if downloadLimit?.count != nil {
+ if let downloadlimitFieldRow : XLFormRowDescriptor = self.form.formRow(withTag: "kNMCDownloadLimitCell") {
+ if let downloadlimitIndexPath = self.form.indexPath(ofFormRow: downloadlimitFieldRow), indexPath == downloadlimitIndexPath {
+ let cell = cell as? NCFilePermissionCell
+ cell?.titleLabel.text = NSLocalizedString("_share_remaining_download_", comment: "") + " \(downloadLimit?.count ?? 0)"
+ cell?.seperatorBelowFull.isHidden = true
+ cell?.seperatorBelow.isHidden = true
+ }
+ }
+ }
+ }
+
+ override func formRowDescriptorValueHasChanged(_ formRow: XLFormRowDescriptor!, oldValue: Any!, newValue: Any!) {
+ super.formRowDescriptorValueHasChanged(formRow, oldValue: oldValue, newValue: newValue)
+
+ switch formRow.tag {
+
+ case "kNMCFilePermissionEditCellEditingCanShare":
+ if let value = newValue as? Bool {
+ canReshareValueChanged(isOn: value)
+ }
+
+ case "kNMCFilePermissionEditCellHideDownload":
+ if let value = newValue as? Bool {
+ share.hideDownload = value
+ }
+
+ case "kNMCFilePermissionEditPasswordCellWithText":
+ if let value = newValue as? Bool {
+ if let setPasswordInputField : XLFormRowDescriptor = self.form.formRow(withTag: "SetPasswordInputField") {
+ if let indexPath = self.form.indexPath(ofFormRow: setPasswordInputField) {
+ let cell = tableView.cellForRow(at: indexPath) as? PasswordInputField
+ cell?.fileNameInputTextField.text = ""
+ }
+ share.password = ""
+ setPasswordInputField.hidden = !value
+ }
+ }
+
+ case "kNCShareTextInputCellCustomLinkField":
+ if let label = formRow.value as? String {
+ self.form.delegate = nil
+ share.label = label
+ self.form.delegate = self
+ }
+
+ case "SetPasswordInputField":
+ if let pwd = formRow.value as? String {
+ self.form.delegate = nil
+ share.password = pwd
+ self.form.delegate = self
+ }
+
+ case "kNMCFilePermissionEditCellLinkLabel":
+ if let label = formRow.value as? String {
+ self.form.delegate = nil
+ share.label = label
+ self.form.delegate = self
+ }
+
+ case "kNMCFilePermissionEditCellExpiration":
+ if let value = newValue as? Bool {
+ if let inputField : XLFormRowDescriptor = self.form.formRow(withTag: "NCShareTextInputCellExpiry") {
+ inputField.hidden = !value
+ }
+ }
+
+ case "kNMCFilePermissionEditCellDownloadLimit":
+ if let value = newValue as? Bool {
+ self.downloadLimit = DownloadLimit()
+ self.downloadLimit?.limit = value ? 0 : nil
+ if let inputField : XLFormRowDescriptor = self.form.formRow(withTag: "NCShareTextInputCellDownloadLimit") {
+ inputField.hidden = !value
+ if let indexPath = self.form.indexPath(ofFormRow: inputField) {
+ let cell = tableView.cellForRow(at: indexPath) as? NCShareTextInputCell
+ cell?.cellTextField.text = ""
+ }
+ }
+
+ if let inputField : XLFormRowDescriptor = self.form.formRow(withTag: "kNMCDownloadLimitCell") {
+ inputField.hidden = !value
+ if let indexPath = self.form.indexPath(ofFormRow: inputField) {
+ let cell = tableView.cellForRow(at: indexPath) as? NCFilePermissionCell
+ cell?.seperatorBelowFull.isHidden = true
+ cell?.seperatorBelow.isHidden = true
+ cell?.titleLabel.text = ""
+ }
+ }
+ }
+
+ case "NCShareTextInputCellExpiry":
+ if let exp = formRow.value as? Date {
+ self.form.delegate = nil
+ self.share.expirationDate = exp as NSDate
+ self.form.delegate = self
+ }
+
+ default:
+ break
+ }
+ }
+ //Check file type is collabora
+ func checkIsCollaboraFile() -> Bool {
+ guard let metadata = metadata else {
+ return false
+ }
+
+ // EDITORS
+ let editors = NCUtility().isDirectEditing(account: metadata.account, contentType: metadata.contentType)
+ let availableRichDocument = NCUtility().isRichDocument(metadata)
+
+ // RichDocument: Collabora
+ return (availableRichDocument && editors.count == 0)
+ }
+
+ func isFileDropOptionVisible() -> Bool {
+ return (metadata.directory && (isLinkShare() || isExternalUserShare()))
+ }
+
+ func isLinkShare() -> Bool {
+ return NCShareCommon().isLinkShare(shareType: shareType)
+ }
+
+ func isExternalUserShare() -> Bool {
+ return NCShareCommon().isExternalUserShare(shareType: shareType)
+ }
+
+ func isInternalUser() -> Bool {
+ return NCShareCommon().isInternalUser(shareType: shareType)
+ }
+
+ func isCanReshareOptionVisible() -> Bool {
+ return isInternalUser()
+ }
+
+ func isHideDownloadOptionVisible() -> Bool {
+ return !isInternalUser()
+ }
+
+ func isPasswordOptionsVisible() -> Bool {
+ return !isInternalUser()
+ }
+
+ func isDownloadLimitVisible() -> Bool {
+ return isLinkShare() && !(metadata.directory)
+ }
+
+ func canReshareValueChanged(isOn: Bool) {
+
+ guard let oldTableShare = oldTableShare, let permission = self.permission else {
+ self.permission = isOn ? (self.permission ?? 0) + NCGlobal.shared.permissionShareShare : ((self.permission ?? 0) - NCGlobal.shared.permissionShareShare)
return
}
- switch cellConfig {
- case .limitDownload:
- let storyboard = UIStoryboard(name: "NCShare", bundle: nil)
- guard let viewController = storyboard.instantiateViewController(withIdentifier: "NCShareDownloadLimit") as? NCShareDownloadLimitViewController else { return }
- viewController.downloadLimit = self.downloadLimit
- viewController.metadata = self.metadata
- viewController.share = self.share
- viewController.shareDownloadLimitTableViewControllerDelegate = self
- viewController.onDismiss = tableView.reloadData
- self.navigationController?.pushViewController(viewController, animated: true)
- case .hideDownload:
- share.hideDownload.toggle()
- tableView.reloadData()
- case .expirationDate:
- let cell = tableView.cellForRow(at: indexPath) as? NCShareDateCell
- cell?.textField.becomeFirstResponder()
- cell?.checkMaximumDate(account: metadata.account)
- case .password:
- guard share.password.isEmpty else {
- share.password = ""
- tableView.reloadData()
- return
+ let canEdit = CCUtility.isAnyPermission(toEdit: permission)
+ let canCreate = CCUtility.isPermission(toCanCreate: permission)
+ let canChange = CCUtility.isPermission(toCanChange: permission)
+ let canDelete = CCUtility.isPermission(toCanDelete: permission)
+
+ if metadata.directory {
+ self.permission = CCUtility.getPermissionsValue(byCanEdit: canEdit, andCanCreate: canCreate, andCanChange: canChange, andCanDelete: canDelete, andCanShare: isOn, andIsFolder: metadata.directory)
+ } else {
+ if isOn {
+ if canEdit {
+ self.permission = CCUtility.getPermissionsValue(byCanEdit: true, andCanCreate: true, andCanChange: true, andCanDelete: true, andCanShare: isOn, andIsFolder: metadata.directory)
+ } else {
+ self.permission = CCUtility.getPermissionsValue(byCanEdit: false, andCanCreate: false, andCanChange: false, andCanDelete: false, andCanShare: isOn, andIsFolder: metadata.directory)
+ }
+ } else {
+ if canEdit {
+ self.permission = CCUtility.getPermissionsValue(byCanEdit: true, andCanCreate: true, andCanChange: true, andCanDelete: true, andCanShare: isOn, andIsFolder: metadata.directory)
+ } else {
+ self.permission = CCUtility.getPermissionsValue(byCanEdit: false, andCanCreate: false, andCanChange: false, andCanDelete: false, andCanShare: isOn, andIsFolder: metadata.directory)
+ }
}
let alertController = UIAlertController.password(titleKey: "_share_password_") { password in
self.share.password = password ?? ""
tableView.reloadData()
}
self.present(alertController, animated: true)
- case .note:
- let storyboard = UIStoryboard(name: "NCShare", bundle: nil)
- guard let viewNewUserComment = storyboard.instantiateViewController(withIdentifier: "NCShareNewUserAddComment") as? NCShareNewUserAddComment else { return }
- viewNewUserComment.metadata = self.metadata
- viewNewUserComment.share = self.share
- viewNewUserComment.onDismiss = tableView.reloadData
- self.navigationController?.pushViewController(viewNewUserComment, animated: true)
- case .label:
- let alertController = UIAlertController.withTextField(titleKey: "_share_link_name_") { textField in
- textField.placeholder = cellConfig.title
- textField.text = self.share.label
- } completion: { newValue in
- self.share.label = newValue ?? ""
- self.setNavigationTitle()
- tableView.reloadData()
- }
- self.present(alertController, animated: true)
- case .downloadAndSync:
- share.downloadAndSync.toggle()
- tableView.reloadData()
+// case .note:
+// let storyboard = UIStoryboard(name: "NCShare", bundle: nil)
+// guard let viewNewUserComment = storyboard.instantiateViewController(withIdentifier: "NCShareNewUserAddComment") as? NCShareNewUserAddComment else { return }
+// viewNewUserComment.metadata = self.metadata
+// viewNewUserComment.share = self.share
+// viewNewUserComment.onDismiss = tableView.reloadData
+// self.navigationController?.pushViewController(viewNewUserComment, animated: true)
+// case .label:
+// let alertController = UIAlertController.withTextField(titleKey: "_share_link_name_") { textField in
+// textField.placeholder = cellConfig.title
+// textField.text = self.share.label
+// } completion: { newValue in
+// self.share.label = newValue ?? ""
+// self.setNavigationTitle()
+// tableView.reloadData()
+// }
+// self.present(alertController, animated: true)
+// case .downloadAndSync:
+// share.downloadAndSync.toggle()
+// tableView.reloadData()
}
}
@@ -267,6 +936,31 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
navigationController?.popViewController(animated: true)
}
+
+ func getDownloadLimit() {
+ NCActivityIndicator.shared.start(backgroundView: view)
+ NMCCommunication.shared.getDownloadLimit(token: oldTableShare?.token ?? "") { [weak self] (downloadLimit: DownloadLimit?, error: String) in
+ DispatchQueue.main.async {
+ NCActivityIndicator.shared.stop()
+ if let downloadLimit = downloadLimit {
+ self?.downloadLimit = downloadLimit
+ }
+ self?.updateDownloadLimitUI()
+ }
+ }
+ }
+
+ func setDownloadLimit(deleteLimit: Bool, limit: String) {
+ NMCCommunication.shared.setDownloadLimit(deleteLimit: deleteLimit, limit: limit, token: oldTableShare?.token ?? "") { (success, errorMessage) in
+ print(success)
+ }
+ }
+
+ func showDownloadLimitError(message: String) {
+ let alertController = UIAlertController(title: "", message: message, preferredStyle: .alert)
+ alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { action in }))
+ self.present(alertController, animated: true)
+ }
}
// MARK: - NCShareDownloadLimitTableViewControllerDelegate
diff --git a/iOSClient/Share/Advanced/NCShareAdvancePermissionFooter.swift b/iOSClient/Share/Advanced/NCShareAdvancePermissionFooter.swift
index dfee243827..455b5da0c6 100644
--- a/iOSClient/Share/Advanced/NCShareAdvancePermissionFooter.swift
+++ b/iOSClient/Share/Advanced/NCShareAdvancePermissionFooter.swift
@@ -35,10 +35,11 @@ class NCShareAdvancePermissionFooter: UIView {
func setupUI(delegate: NCShareAdvanceFotterDelegate?, account: String) {
self.delegate = delegate
- backgroundColor = .clear
-
+ buttonCancel.addTarget(self, action: #selector(cancelClicked), for: .touchUpInside)
+ buttonNext.addTarget(self, action: #selector(nextClicked), for: .touchUpInside)
buttonCancel.setTitle(NSLocalizedString("_cancel_", comment: ""), for: .normal)
- buttonCancel.layer.cornerRadius = 25
+ buttonNext.setTitle(NSLocalizedString(delegate?.isNewShare == true ? "_next_" : "_apply_changes_", comment: ""), for: .normal)
+ buttonCancel.layer.cornerRadius = 10
buttonCancel.layer.masksToBounds = true
buttonCancel.layer.borderWidth = 1
buttonCancel.layer.borderColor = NCBrandColor.shared.textColor2.cgColor
@@ -51,7 +52,18 @@ class NCShareAdvancePermissionFooter: UIView {
buttonNext.layer.masksToBounds = true
buttonNext.backgroundColor = NCBrandColor.shared.getElement(account: account)
buttonNext.addTarget(self, action: #selector(nextClicked(_:)), for: .touchUpInside)
+
+ addShadow(location: .top)
+ layer.cornerRadius = 10
+ layer.masksToBounds = true
+ backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+ buttonCancel.setTitleColor(NCBrandColor.shared.label, for: .normal)
+ buttonCancel.layer.borderColor = NCBrandColor.shared.label.cgColor
+ buttonCancel.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+ buttonNext.setBackgroundColor(NCBrandColor.shared.customer, for: .normal)
buttonNext.setTitleColor(.white, for: .normal)
+ buttonNext.layer.cornerRadius = 10
+ buttonNext.layer.masksToBounds = true
}
@objc func cancelClicked(_ sender: Any?) {
diff --git a/iOSClient/Share/Advanced/NCShareAdvancePermissionFooter.xib b/iOSClient/Share/Advanced/NCShareAdvancePermissionFooter.xib
index b4ec72ed06..36b09589ef 100644
--- a/iOSClient/Share/Advanced/NCShareAdvancePermissionFooter.xib
+++ b/iOSClient/Share/Advanced/NCShareAdvancePermissionFooter.xib
@@ -1,67 +1,60 @@
-
+
-
+
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
+
-
+
-
-
-
-
-
-
-
+
+
+
-
-
+
+
-
+
-
-
-
-
-
-
-
-
diff --git a/iOSClient/Share/Advanced/NCShareAdvancePermissionHeader.xib b/iOSClient/Share/Advanced/NCShareAdvancePermissionHeader.xib
new file mode 100644
index 0000000000..161dc96732
--- /dev/null
+++ b/iOSClient/Share/Advanced/NCShareAdvancePermissionHeader.xib
@@ -0,0 +1,84 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iOSClient/Share/Advanced/NCShareHeaderCustomCell.swift b/iOSClient/Share/Advanced/NCShareHeaderCustomCell.swift
new file mode 100644
index 0000000000..cb5dae8c1f
--- /dev/null
+++ b/iOSClient/Share/Advanced/NCShareHeaderCustomCell.swift
@@ -0,0 +1,30 @@
+//
+// NCShareHeaderCustomCell.swift
+// Nextcloud
+//
+// Created by T-systems on 11/08/21.
+// Copyright © 2021 Marino Faggiana. All rights reserved.
+//
+
+import UIKit
+
+class NCShareHeaderCustomCell: XLFormBaseCell {
+
+ @IBOutlet weak var titleLabel: UILabel!
+
+ override func awakeFromNib() {
+ super.awakeFromNib()
+ self.selectionStyle = .none
+ self.backgroundColor = .clear
+ }
+
+ override func configure() {
+ super.configure()
+ }
+
+ override func update() {
+ self.backgroundColor = .clear
+ self.titleLabel.textColor = NCBrandColor.shared.systemGray
+ super.update()
+ }
+}
diff --git a/iOSClient/Share/Advanced/NCShareHeaderCustomCell.xib b/iOSClient/Share/Advanced/NCShareHeaderCustomCell.xib
new file mode 100644
index 0000000000..89ba3781e5
--- /dev/null
+++ b/iOSClient/Share/Advanced/NCShareHeaderCustomCell.xib
@@ -0,0 +1,42 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iOSClient/Share/Advanced/NCShareNewUserAddComment.swift b/iOSClient/Share/Advanced/NCShareNewUserAddComment.swift
index 0c6bb586ef..a7fe311e0c 100644
--- a/iOSClient/Share/Advanced/NCShareNewUserAddComment.swift
+++ b/iOSClient/Share/Advanced/NCShareNewUserAddComment.swift
@@ -1,9 +1,12 @@
//
+//
// NCShareNewUserAddComment.swift
// Nextcloud
//
// Created by TSI-mc on 21/06/21.
-// Copyright © 2022 All rights reserved.
+// Copyright © 2022 Henrik Storch. All rights reserved.
+//
+// Author Henrik Storch
//
// 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
@@ -25,39 +28,60 @@ import NextcloudKit
class NCShareNewUserAddComment: UIViewController, NCShareNavigationTitleSetting {
@IBOutlet weak var headerContainerView: UIView!
- @IBOutlet weak var sharingLabel: UILabel!
- @IBOutlet weak var noteTextField: UITextView!
-
+ @IBOutlet weak var labelSharing: UILabel!
+ @IBOutlet weak var labelNote: UILabel!
+ @IBOutlet weak var commentTextView: UITextView!
+ @IBOutlet weak var btnCancel: UIButton!
+ @IBOutlet weak var btnSendShare: UIButton!
+ @IBOutlet weak var buttonContainerView: UIView!
let contentInsets: CGFloat = 16
- var onDismiss: (() -> Void)?
-
- public var share: Shareable!
+ public var share: NCTableShareable!
public var metadata: tableMetadata!
+ var isNewShare: Bool { share is NCTableShareOptions }
+ var networking: NCShareNetworking?
override func viewDidLoad() {
super.viewDidLoad()
self.setNavigationTitle()
-
- NotificationCenter.default.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillHideNotification, object: nil)
+ NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
+ NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
-
- sharingLabel.text = NSLocalizedString("_share_note_recipient_", comment: "")
-
- noteTextField.textContainerInset = UIEdgeInsets(top: contentInsets, left: contentInsets, bottom: contentInsets, right: contentInsets)
- noteTextField.text = share.note
- let toolbar = UIToolbar.toolbar {
- self.noteTextField.resignFirstResponder()
- self.noteTextField.text = ""
- self.share.note = ""
- } onDone: {
- self.noteTextField.resignFirstResponder()
- self.share.note = self.noteTextField.text
- self.navigationController?.popViewController(animated: true)
+ changeTheming()
+ setupHeader()
+ }
+
+ @objc func changeTheming() {
+ self.view.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+ self.commentTextView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+ commentTextView.textColor = NCBrandColor.shared.label
+ btnCancel.setTitleColor(NCBrandColor.shared.label, for: .normal)
+ btnCancel.layer.borderColor = NCBrandColor.shared.label.cgColor
+ btnCancel.backgroundColor = .clear
+ buttonContainerView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+ btnSendShare.setBackgroundColor(NCBrandColor.shared.customer, for: .normal)
+ btnSendShare.setTitleColor(.white, for: .normal)
+ commentTextView.layer.borderColor = NCBrandColor.shared.label.cgColor
+ commentTextView.layer.borderWidth = 1
+ commentTextView.layer.cornerRadius = 4.0
+ commentTextView.showsVerticalScrollIndicator = false
+ commentTextView.textContainerInset = UIEdgeInsets(top: contentInsets, left: contentInsets, bottom: contentInsets, right: contentInsets)
+ btnCancel.setTitle(NSLocalizedString("_cancel_", comment: ""), for: .normal)
+ btnCancel.layer.cornerRadius = 10
+ btnCancel.layer.masksToBounds = true
+ btnCancel.layer.borderWidth = 1
+ btnSendShare.setTitle(NSLocalizedString("_send_share_", comment: ""), for: .normal)
+ btnSendShare.layer.cornerRadius = 10
+ btnSendShare.layer.masksToBounds = true
+ labelSharing.text = NSLocalizedString("_sharing_", comment: "")
+ labelNote.text = NSLocalizedString("_share_note_recipient_", comment: "")
+ commentTextView.inputAccessoryView = UIToolbar.doneToolbar { [weak self] in
+ self?.commentTextView.resignFirstResponder()
}
-
- noteTextField.inputAccessoryView = toolbar.wrappedSafeAreaContainer
-
- guard let headerView = (Bundle.main.loadNibNamed("NCShareHeader", owner: self, options: nil)?.first as? NCShareHeader) else { return }
+ }
+
+ func setupHeader(){
+ guard let headerView = (Bundle.main.loadNibNamed("NCShareAdvancePermissionHeader", owner: self, options: nil)?.first as? NCShareAdvancePermissionHeader) else { return }
+ headerView.ocId = metadata.ocId
headerContainerView.addSubview(headerView)
headerView.frame = headerContainerView.frame
headerView.translatesAutoresizingMaskIntoConstraints = false
@@ -65,29 +89,48 @@ class NCShareNewUserAddComment: UIViewController, NCShareNavigationTitleSetting
headerView.bottomAnchor.constraint(equalTo: headerContainerView.bottomAnchor).isActive = true
headerView.leftAnchor.constraint(equalTo: headerContainerView.leftAnchor).isActive = true
headerView.rightAnchor.constraint(equalTo: headerContainerView.rightAnchor).isActive = true
-
headerView.setupUI(with: metadata)
}
- override func viewWillDisappear(_ animated: Bool) {
- super.viewWillDisappear(animated)
- share.note = noteTextField.text
- onDismiss?()
+ @IBAction func cancelClicked(_ sender: Any) {
+ self.navigationController?.popToRootViewController(animated: true)
+ }
+
+ @IBAction func sendShareClicked(_ sender: Any) {
+ share.note = commentTextView.text
+ if isNewShare {
+ networking?.createShare(option: share)
+ } else {
+ networking?.updateShare(option: share)
+ }
+ self.navigationController?.popToRootViewController(animated: true)
}
@objc func adjustForKeyboard(notification: Notification) {
guard let keyboardValue = notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue,
- let globalTextViewFrame = noteTextField.superview?.convert(noteTextField.frame, to: nil) else { return }
-
+ let globalTextViewFrame = commentTextView.superview?.convert(commentTextView.frame, to: nil) else { return }
let keyboardScreenEndFrame = keyboardValue.cgRectValue
let portionCovoredByLeyboard = globalTextViewFrame.maxY - keyboardScreenEndFrame.minY
if notification.name == UIResponder.keyboardWillHideNotification || portionCovoredByLeyboard < 0 {
- noteTextField.contentInset = .zero
+ commentTextView.contentInset = .zero
} else {
- noteTextField.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: portionCovoredByLeyboard, right: 0)
+ commentTextView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: portionCovoredByLeyboard, right: 0)
}
+ commentTextView.scrollIndicatorInsets = commentTextView.contentInset
+ }
- noteTextField.scrollIndicatorInsets = noteTextField.contentInset
+ @objc func keyboardWillShow(notification: Notification) {
+ if UIScreen.main.bounds.width <= 375 {
+ if view.frame.origin.y == 0 {
+ self.view.frame.origin.y -= 200
+ }
+ }
+ }
+
+ @objc func keyboardWillHide(notification: Notification) {
+ if view.frame.origin.y != 0 {
+ self.view.frame.origin.y = 0
+ }
}
}
diff --git a/iOSClient/Share/Advanced/NCShareTextInputCell.swift b/iOSClient/Share/Advanced/NCShareTextInputCell.swift
new file mode 100644
index 0000000000..26da27ef03
--- /dev/null
+++ b/iOSClient/Share/Advanced/NCShareTextInputCell.swift
@@ -0,0 +1,151 @@
+//
+// NCShareTextInputCell.swift
+// Nextcloud
+//
+// Created by T-systems on 20/09/21.
+// Copyright © 2021 Kunal. All rights reserved.
+//
+
+import UIKit
+
+class NCShareTextInputCell: XLFormBaseCell, UITextFieldDelegate {
+
+ @IBOutlet weak var seperator: UIView!
+ @IBOutlet weak var seperatorBottom: UIView!
+ @IBOutlet weak var cellTextField: UITextField!
+ @IBOutlet weak var calendarImageView: UIImageView!
+
+ let datePicker = UIDatePicker()
+ var expirationDateText: String!
+ var expirationDate: NSDate!
+
+ override func awakeFromNib() {
+ super.awakeFromNib()
+ self.cellTextField.delegate = self
+ self.cellTextField.isEnabled = true
+ calendarImageView.image = UIImage(named: "calender")?.imageColor(NCBrandColor.shared.brandElement)
+ self.selectionStyle = .none
+ self.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+ self.cellTextField.attributedPlaceholder = NSAttributedString(string: "",
+ attributes: [NSAttributedString.Key.foregroundColor: NCBrandColor.shared.fileFolderName])
+ self.cellTextField.textColor = NCBrandColor.shared.singleTitleColorButton
+ }
+
+ override func configure() {
+ super.configure()
+ }
+
+ override func update() {
+ super.update()
+ calendarImageView.isHidden = rowDescriptor.tag != "NCShareTextInputCellExpiry"
+ if rowDescriptor.tag == "NCShareTextInputCellExpiry" {
+ seperator.isHidden = true
+ setDatePicker(sender: self.cellTextField)
+ } else if rowDescriptor.tag == "NCShareTextInputCellDownloadLimit" {
+ seperator.isHidden = true
+ cellTextField.keyboardType = .numberPad
+ setDoneButton(sender: self.cellTextField)
+ }
+ }
+
+ func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
+ if self.cellTextField == textField {
+ if let rowDescriptor = rowDescriptor, let text = self.cellTextField.text {
+
+ if (text + " ").isEmpty == false {
+ rowDescriptor.value = self.cellTextField.text! + string
+ } else {
+ rowDescriptor.value = nil
+ }
+ }
+ }
+
+ self.formViewController().textField(textField, shouldChangeCharactersIn: range, replacementString: string)
+ return true
+ }
+
+ func textFieldDidEndEditing(_ textField: UITextField) {
+ rowDescriptor.value = cellTextField.text
+ }
+
+ func textFieldShouldReturn(_ textField: UITextField) -> Bool {
+ self.formViewController()?.textFieldShouldReturn(textField)
+ return true
+ }
+
+ func textFieldShouldClear(_ textField: UITextField) -> Bool {
+ self.formViewController()?.textFieldShouldClear(textField)
+ return true
+ }
+
+ override class func formDescriptorCellHeight(for rowDescriptor: XLFormRowDescriptor!) -> CGFloat {
+ return 30
+ }
+
+ override func formDescriptorCellDidSelected(withForm controller: XLFormViewController!) {
+ self.selectionStyle = .none
+ }
+
+ func setDatePicker(sender: UITextField) {
+ //Format Date
+ datePicker.datePickerMode = .date
+ datePicker.minimumDate = Date.tomorrow
+ if #available(iOS 13.4, *) {
+ datePicker.preferredDatePickerStyle = .wheels
+ datePicker.sizeToFit()
+ }
+ //ToolBar
+ let toolbar = UIToolbar();
+ toolbar.sizeToFit()
+ let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .plain, target: self, action: #selector(doneDatePicker));
+ let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
+ let cancelButton = UIBarButtonItem(title: NSLocalizedString("_cancel_", comment: ""), style: .plain, target: self, action: #selector(cancelDatePicker));
+
+ toolbar.setItems([cancelButton, spaceButton, doneButton], animated: false)
+
+ sender.inputAccessoryView = toolbar
+ sender.inputView = datePicker
+ }
+
+ @objc func doneDatePicker() {
+ let dateFormatter = DateFormatter()
+ dateFormatter.formatterBehavior = .behavior10_4
+ dateFormatter.dateStyle = .medium
+ dateFormatter.dateFormat = NCShareAdvancePermission.displayDateFormat
+
+ var expiryDate = dateFormatter.string(from: datePicker.date)
+ expiryDate = expiryDate.replacingOccurrences(of: "..", with: ".")
+ self.expirationDateText = expiryDate
+
+ self.expirationDate = datePicker.date as NSDate
+ self.cellTextField.text = self.expirationDateText
+ self.rowDescriptor.value = self.expirationDate
+ self.cellTextField.endEditing(true)
+ }
+
+ @objc func cancelDatePicker() {
+ self.cellTextField.endEditing(true)
+ }
+
+ func setDoneButton(sender: UITextField) {
+ //ToolBar
+ let toolbar = UIToolbar();
+ toolbar.sizeToFit()
+ let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .plain, target: self, action: #selector(cancelDatePicker));
+ let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
+ toolbar.setItems([spaceButton, doneButton], animated: false)
+ sender.inputAccessoryView = toolbar
+ }
+}
+
+class NCSeparatorCell: XLFormBaseCell {
+ override func awakeFromNib() {
+ super.awakeFromNib()
+ selectionStyle = .none
+ }
+
+ override func update() {
+ super.update()
+ self.selectionStyle = .none
+ }
+}
diff --git a/iOSClient/Share/Advanced/NCShareTextInputCell.xib b/iOSClient/Share/Advanced/NCShareTextInputCell.xib
new file mode 100644
index 0000000000..eaa2f0cd13
--- /dev/null
+++ b/iOSClient/Share/Advanced/NCShareTextInputCell.xib
@@ -0,0 +1,80 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iOSClient/Share/NCSearchUserDropDownCell.xib b/iOSClient/Share/NCSearchUserDropDownCell.xib
index 2ba38c8fa6..6c2ffde821 100755
--- a/iOSClient/Share/NCSearchUserDropDownCell.xib
+++ b/iOSClient/Share/NCSearchUserDropDownCell.xib
@@ -1,9 +1,9 @@
-
+
-
+
@@ -29,12 +29,12 @@
-
+
@@ -58,12 +58,12 @@
+
-
diff --git a/iOSClient/Share/NCShare+Helper.swift b/iOSClient/Share/NCShare+Helper.swift
new file mode 100644
index 0000000000..b08bfa9358
--- /dev/null
+++ b/iOSClient/Share/NCShare+Helper.swift
@@ -0,0 +1,113 @@
+//
+// NCShare+Helper.swift
+// Nextcloud
+//
+// Created by Henrik Storch on 19.03.22.
+// Copyright © 2022 Henrik Storch. All rights reserved.
+//
+// Author Henrik Storch
+//
+// 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
+
+extension tableShare: NCTableShareable { }
+extension NKShare: NCTableShareable { }
+
+protocol NCTableShareable: AnyObject {
+ var shareType: Int { get set }
+ var permissions: Int { get set }
+ var idShare: Int { get set }
+ var shareWith: String { get set }
+ var hideDownload: Bool { get set }
+ var password: String { get set }
+ var label: String { get set }
+ var note: String { get set }
+ var expirationDate: NSDate? { get set }
+ var shareWithDisplayname: String { get set }
+ var attributes: String? { get set }
+}
+
+extension NCTableShareable {
+ var expDateString: String? {
+ guard let date = expirationDate else { return nil }
+ let dateFormatter = DateFormatter()
+ dateFormatter.dateFormat = "YYYY-MM-dd HH:mm:ss"
+ return dateFormatter.string(from: date as Date)
+ }
+
+ func hasChanges(comparedTo other: NCTableShareable) -> Bool {
+ return other.shareType != shareType
+ || other.permissions != permissions
+ || other.hideDownload != hideDownload
+ || other.password != password
+ || other.label != label
+ || other.note != note
+ || other.expirationDate != expirationDate
+ }
+}
+
+class NCTableShareOptions: NCTableShareable {
+
+ var shareType: Int
+ var permissions: Int
+
+ var idShare: Int = 0
+ var shareWith: String = ""
+
+ var hideDownload: Bool = false
+ var password: String = ""
+ var label: String = ""
+ var note: String = ""
+ var expirationDate: NSDate?
+ var shareWithDisplayname: String = ""
+
+ var attributes: String?
+
+ private init(shareType: Int, metadata: tableMetadata, password: String?) {
+ if metadata.e2eEncrypted, NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityE2EEApiVersion == NCGlobal.shared.e2eeVersionV12 {
+ self.permissions = NCPermissions().permissionCreateShare
+ } else {
+ self.permissions = NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityFileSharingDefaultPermission & metadata.sharePermissionsCollaborationServices
+ }
+ self.shareType = shareType
+ if let password = password {
+ self.password = password
+ }
+ }
+
+ convenience init(sharee: NKSharee, metadata: tableMetadata, password: String?) {
+ self.init(shareType: sharee.shareType, metadata: metadata, password: password)
+ self.shareWith = sharee.shareWith
+ }
+
+ static func shareLink(metadata: tableMetadata, password: String?) -> NCTableShareOptions {
+ return NCTableShareOptions(shareType: NCShareCommon().SHARE_TYPE_LINK, metadata: metadata, password: password)
+ }
+}
+
+protocol NCShareDetail {
+ var share: NCTableShareable! { get }
+}
+
+extension NCShareDetail where Self: UIViewController {
+ func setNavigationTitle() {
+ title = NSLocalizedString("_sharing_", comment: "")
+ if share.shareType != NCShareCommon().SHARE_TYPE_LINK {
+ title! = share.shareWithDisplayname.isEmpty ? share.shareWith : share.shareWithDisplayname
+ }
+ }
+}
diff --git a/iOSClient/Share/NCShare+NCCellDelegate.swift b/iOSClient/Share/NCShare+NCCellDelegate.swift
index 76c3bf9dc8..9e8be4757c 100644
--- a/iOSClient/Share/NCShare+NCCellDelegate.swift
+++ b/iOSClient/Share/NCShare+NCCellDelegate.swift
@@ -48,7 +48,8 @@ extension NCShare: NCShareLinkCellDelegate, NCShareUserCellDelegate {
func tapMenu(with tableShare: tableShare?, sender: Any) {
if let tableShare = tableShare {
- self.toggleShareMenu(for: tableShare, sender: sender)
+// self.toggleShareMenu(for: tableShare, sender: sender)
+ self.toggleShareMenu(for: tableShare, sendMail: (tableShare.shareType != NCShareCommon().SHARE_TYPE_LINK), folder: metadata?.directory ?? false, sender: sender)
} else {
self.makeNewLinkShare()
}
@@ -62,5 +63,8 @@ extension NCShare: NCShareLinkCellDelegate, NCShareUserCellDelegate {
func quickStatus(with tableShare: tableShare?, sender: Any) {
guard let tableShare, let metadata else { return }
self.toggleQuickPermissionsMenu(isDirectory: metadata.directory, share: tableShare, sender: sender)
+// guard let tableShare = tableShare,
+// let metadata = metadata else { return }
+// self.toggleUserPermissionMenu(isDirectory: metadata.directory, tableShare: tableShare)
}
}
diff --git a/iOSClient/Share/NCShare.storyboard b/iOSClient/Share/NCShare.storyboard
index 5bf01c2fb8..85c52dc81f 100644
--- a/iOSClient/Share/NCShare.storyboard
+++ b/iOSClient/Share/NCShare.storyboard
@@ -10,289 +10,233 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
+
-
-
+
+
-
-
-
+
+
+
+
-
+
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
+
+
+
+
+
+
+
+
-
+
-
-
-
+
+
+
+
+
+
+
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
+
-
+
+
+
+
+
+
+
-
-
+
+
-
-
-
-
+
+
+
+
+
-
+
-
+
-
+
-
-
+
+
@@ -371,44 +315,22 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift
index 2551fd8558..72ad498de4 100644
--- a/iOSClient/Share/NCShare.swift
+++ b/iOSClient/Share/NCShare.swift
@@ -30,17 +30,11 @@ import NextcloudKit
import MarqueeLabel
import ContactsUI
-class NCShare: UIViewController, NCSharePagingContent {
- @IBOutlet weak var viewContainerConstraint: NSLayoutConstraint!
- @IBOutlet weak var sharedWithYouByView: UIView!
- @IBOutlet weak var sharedWithYouByImage: UIImageView!
- @IBOutlet weak var sharedWithYouByLabel: UILabel!
- @IBOutlet weak var searchFieldTopConstraint: NSLayoutConstraint!
- @IBOutlet weak var searchField: UISearchBar!
- var textField: UIView? { searchField }
+class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent {
+
+ var textField: UITextField? { self.view.viewWithTag(Tag.searchField) as? UITextField }
@IBOutlet weak var tableView: UITableView!
- @IBOutlet weak var btnContact: UIButton!
weak var appDelegate = UIApplication.shared.delegate as? AppDelegate
@@ -72,22 +66,16 @@ class NCShare: UIViewController, NCSharePagingContent {
override func viewDidLoad() {
super.viewDidLoad()
- view.backgroundColor = .systemBackground
-
- viewContainerConstraint.constant = height
- searchFieldTopConstraint.constant = 0
-
- searchField.placeholder = NSLocalizedString("_shareLinksearch_placeholder_", comment: "")
- searchField.autocorrectionType = .no
+ view.backgroundColor = .secondarySystemGroupedBackground
tableView.dataSource = self
tableView.delegate = self
tableView.allowsSelection = false
- tableView.backgroundColor = .systemBackground
- tableView.contentInset = UIEdgeInsets(top: 8, left: 0, bottom: 10, right: 0)
+ tableView.backgroundColor = .secondarySystemGroupedBackground
tableView.register(UINib(nibName: "NCShareLinkCell", bundle: nil), forCellReuseIdentifier: "cellLink")
tableView.register(UINib(nibName: "NCShareUserCell", bundle: nil), forCellReuseIdentifier: "cellUser")
+ tableView.register(UINib(nibName: "NCShareEmailFieldCell", bundle: nil), forCellReuseIdentifier: "NCShareEmailFieldCell")
NotificationCenter.default.addObserver(self, selector: #selector(reloadData), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataNCShare), object: nil)
@@ -116,6 +104,10 @@ class NCShare: UIViewController, NCSharePagingContent {
}
}
+ @objc func exitTapped() {
+ self.dismiss(animated: true, completion: nil)
+ }
+
func makeNewLinkShare() {
guard
let advancePermission = UIStoryboard(name: "NCShare", bundle: nil).instantiateViewController(withIdentifier: "NCShareAdvancePermission") as? NCShareAdvancePermission,
@@ -189,7 +181,48 @@ class NCShare: UIViewController, NCSharePagingContent {
@objc func openShareProfile(_ sender: UITapGestureRecognizer) {
self.showProfileMenu(userId: metadata.ownerId, session: session, sender: sender.view)
}
+
+ @objc func keyboardWillShow(notification: Notification) {
+ if UIDevice.current.userInterfaceIdiom == .phone {
+ if (UIScreen.main.bounds.width < 374 || UIDevice.current.orientation.isLandscape) {
+ if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
+ if view.frame.origin.y == 0 {
+ self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
+ self.view.frame.origin.y -= keyboardSize.height
+ }
+ }
+ } else if UIScreen.main.bounds.height < 850 {
+ if view.frame.origin.y == 0 {
+ self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
+ self.view.frame.origin.y -= 70
+ }
+ } else {
+ if view.frame.origin.y == 0 {
+ self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
+ self.view.frame.origin.y -= 40
+ }
+ }
+ }
+
+ if UIDevice.current.userInterfaceIdiom == .pad, UIDevice.current.orientation.isLandscape {
+ if view.frame.origin.y == 0 {
+ self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
+ self.view.frame.origin.y -= 230
+ }
+ }
+ textField?.layer.borderColor = NCBrandColor.shared.brand.cgColor
+ }
+
+ @objc func keyboardWillHide(notification: Notification) {
+ if view.frame.origin.y != 0 {
+ self.view.frame.origin.y = 0
+ }
+ textField?.layer.borderColor = NCBrandColor.shared.label.cgColor
+ }
+ @objc func appWillEnterForeground(notification: Notification) {
+ reloadData()
+ }
// MARK: -
@objc func reloadData() {
@@ -201,18 +234,64 @@ class NCShare: UIViewController, NCSharePagingContent {
// MARK: - IBAction
@IBAction func searchFieldDidEndOnExit(textField: UITextField) {
- // https://stackoverflow.com/questions/25471114/how-to-validate-an-e-mail-address-in-swift
- func isValidEmail(_ email: String) -> Bool {
-
- let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
- let emailPred = NSPredicate(format: "SELF MATCHES %@", emailRegEx)
- return emailPred.evaluate(with: email)
- }
guard let searchString = textField.text, !searchString.isEmpty else { return }
- if searchString.contains("@"), !isValidEmail(searchString) { return }
+ if searchString.contains("@"), !utility.isValidEmail(searchString) { return }
networking?.getSharees(searchString: searchString)
}
-
+
+ @IBAction func searchFieldDidChange(textField: UITextField) {
+ guard let searchString = textField.text else {return}
+ if searchString.count == 0 {
+ dropDown.hide()
+ } else {
+ networking?.getSharees(searchString: searchString)
+ }
+ }
+
+ @IBAction func createLinkClicked(_ sender: Any) {
+ appDelegate?.adjust.trackEvent(TriggerEvent(CreateLink.rawValue))
+ TealiumHelper.shared.trackEvent(title: "magentacloud-app.sharing.create", data: ["": ""])
+ self.touchUpInsideButtonMenu(sender)
+ }
+
+ @IBAction func touchUpInsideButtonMenu(_ sender: Any) {
+
+ guard let metadata = metadata else { return }
+ let isFilesSharingPublicPasswordEnforced = NCGlobal.shared.capabilityFileSharingPubPasswdEnforced
+ let shares = NCManageDatabase.shared.getTableShares(metadata: metadata)
+
+ if isFilesSharingPublicPasswordEnforced && shares.firstShareLink == nil {
+ let alertController = UIAlertController(title: NSLocalizedString("_enforce_password_protection_", comment: ""), message: "", preferredStyle: .alert)
+ alertController.addTextField { (textField) in
+ textField.isSecureTextEntry = true
+ }
+ alertController.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .default) { (action:UIAlertAction) in })
+ let okAction = UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default) {[weak self] (action:UIAlertAction) in
+ let password = alertController.textFields?.first?.text
+ self?.networking?.createShareLink(password: password ?? "")
+ }
+
+ alertController.addAction(okAction)
+
+ present(alertController, animated: true, completion:nil)
+ } else if shares.firstShareLink == nil {
+ networking?.createShareLink(password: "")
+ } else {
+ networking?.createShareLink(password: "")
+ }
+
+ }
+
+ @IBAction func selectContactClicked(_ sender: Any) {
+ let cnPicker = CNContactPickerViewController()
+ cnPicker.delegate = self
+ cnPicker.displayedPropertyKeys = [CNContactEmailAddressesKey]
+ cnPicker.predicateForEnablingContact = NSPredicate(format: "emailAddresses.@count > 0")
+ cnPicker.predicateForSelectionOfProperty = NSPredicate(format: "emailAddresses.@count > 0")
+
+ self.present(cnPicker, animated: true)
+ }
+
func checkEnforcedPassword(shareType: Int, completion: @escaping (String?) -> Void) {
guard capabilities.fileSharingPubPasswdEnforced,
shareType == NKShare.ShareType.publicLink.rawValue || shareType == NKShare.ShareType.email.rawValue
@@ -231,7 +310,7 @@ class NCShare: UIViewController, NCSharePagingContent {
}
}
-// MARK: - NCShareNetworkingDelegate
+ // MARK: - NCShareNetworkingDelegate
extension NCShare: NCShareNetworkingDelegate {
func readShareCompleted() {
@@ -245,7 +324,10 @@ extension NCShare: NCShareNetworkingDelegate {
}
func unShareCompleted() {
- reloadData()
+// reloadData()
+// NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource)
+ NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare)
+ self.reloadData()
}
func updateShareWithError(idShare: Int) {
@@ -263,18 +345,14 @@ extension NCShare: NCShareNetworkingDelegate {
dropDown = DropDown()
let appearance = DropDown.appearance()
- // Setting up the blur effect
- let blurEffect = UIBlurEffect(style: .light) // You can choose .dark, .extraLight, or .light
- let blurEffectView = UIVisualEffectView(effect: blurEffect)
- blurEffectView.frame = CGRect(x: 0, y: 0, width: 500, height: 20)
-
- appearance.backgroundColor = .systemBackground
+ appearance.backgroundColor = .secondarySystemGroupedBackground
appearance.cornerRadius = 10
- appearance.shadowColor = .black
- appearance.shadowOpacity = 0.2
- appearance.shadowRadius = 30
+ appearance.shadowColor = UIColor(white: 0.5, alpha: 1)
+ appearance.shadowOpacity = 0.9
+ appearance.shadowRadius = 25
appearance.animationduration = 0.25
appearance.textColor = .darkGray
+ appearance.setupMaskedCorners([.layerMaxXMaxYCorner, .layerMinXMaxYCorner])
let account = NCManageDatabase.shared.getTableAccount(account: metadata.account)
let existingShares = NCManageDatabase.shared.getTableShares(metadata: metadata)
@@ -291,10 +369,16 @@ extension NCShare: NCShareNetworkingDelegate {
dropDown.dataSource.append(label)
}
- dropDown.anchorView = searchField
- dropDown.bottomOffset = CGPoint(x: 10, y: searchField.bounds.height)
- dropDown.width = searchField.bounds.width - 20
- dropDown.direction = .bottom
+ dropDown.anchorView = textField
+ dropDown.bottomOffset = CGPoint(x: 0, y: textField?.bounds.height ?? 0)
+ dropDown.width = textField?.bounds.width ?? 0
+ if (UIDevice.current.userInterfaceIdiom == .phone || UIDevice.current.orientation.isLandscape), UIScreen.main.bounds.width < 1111 {
+ dropDown.topOffset = CGPoint(x: 0, y: -(textField?.bounds.height ?? 0))
+ dropDown.direction = .top
+ } else {
+ dropDown.bottomOffset = CGPoint(x: 0, y: (textField?.bounds.height ?? 0) - 80)
+ dropDown.direction = .any
+ }
dropDown.cellNib = UINib(nibName: "NCSearchUserDropDownCell", bundle: nil)
dropDown.customCellConfiguration = { (index: Index, _, cell: DropDownCell) in
@@ -304,6 +388,8 @@ extension NCShare: NCShareNetworkingDelegate {
}
dropDown.selectionAction = { index, _ in
+ self.textField?.text = ""
+ self.textField?.resignFirstResponder()
let sharee = sharees[index]
guard
let advancePermission = UIStoryboard(name: "NCShare", bundle: nil).instantiateViewController(withIdentifier: "NCShareAdvancePermission") as? NCShareAdvancePermission,
@@ -327,6 +413,19 @@ extension NCShare: NCShareNetworkingDelegate {
func downloadLimitSet(to limit: Int, by token: String) {
database.createDownloadLimit(account: metadata.account, count: 0, limit: limit, token: token)
}
+
+ func checkIsCollaboraFile() -> Bool {
+ guard let metadata = metadata else {
+ return false
+ }
+
+ // EDITORS
+ let editors = utility.isDirectEditing(account: metadata.account, contentType: metadata.contentType)
+ let availableRichDocument = utility.isRichDocument(metadata)
+
+ // RichDocument: Collabora
+ return (availableRichDocument && editors.count == 0)
+ }
}
// MARK: - UITableViewDelegate
@@ -334,7 +433,8 @@ extension NCShare: NCShareNetworkingDelegate {
extension NCShare: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
- return 60
+// return 60
+ return indexPath.row == 0 ? UITableView.automaticDimension : 60
}
}
@@ -343,7 +443,7 @@ extension NCShare: UITableViewDelegate {
extension NCShare: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
- return 2
+ return 1
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
@@ -356,10 +456,29 @@ extension NCShare: UITableViewDataSource {
numRows = shares.firstShareLink != nil || canReshare ? 2 : 1
}
}
- return numRows
+ if let shareLink = shares.firstShareLink {
+ shares.share?.insert(shareLink, at: 0)
+ }
+
+ if shares.share != nil {
+ numOfRows = shares.share!.count
+ }
+ return canReshare ? (numOfRows + 1) : numOfRows
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+
+ if indexPath.row == 0 {
+ guard let cell = tableView.dequeueReusableCell(withIdentifier: "NCShareEmailFieldCell", for: indexPath) as? NCShareEmailFieldCell else { return UITableViewCell() }
+ cell.searchField.addTarget(self, action: #selector(searchFieldDidEndOnExit(textField:)), for: .editingDidEndOnExit)
+ cell.searchField.addTarget(self, action: #selector(searchFieldDidChange(textField:)), for: .editingChanged)
+ cell.btnCreateLink.addTarget(self, action: #selector(createLinkClicked(_:)), for: .touchUpInside)
+ cell.btnContact.addTarget(self, action: #selector(selectContactClicked(_:)), for: .touchUpInside)
+ cell.labelNoShare.isHidden = (shares.share?.count ?? 0) > 0
+ cell.heightLabelNoShare.constant = (shares.share?.count ?? 0) > 0 ? 0 : 25
+ return cell
+ }
+
// Setup default share cells
guard indexPath.section != 0 else {
guard let cell = tableView.dequeueReusableCell(withIdentifier: "cellLink", for: indexPath) as? NCShareLinkCell
@@ -388,7 +507,6 @@ extension NCShare: UITableViewDataSource {
if let cell = tableView.dequeueReusableCell(withIdentifier: "cellLink", for: indexPath) as? NCShareLinkCell {
cell.indexPath = indexPath
cell.tableShare = tableShare
- cell.isDirectory = metadata.directory
cell.delegate = self
cell.setupCellUI(titleAppendString: String(shareLinksCount))
if tableShare.shareType == NKShare.ShareType.publicLink.rawValue { shareLinksCount += 1 }
@@ -404,37 +522,104 @@ extension NCShare: UITableViewDataSource {
cell.setupCellUI(userId: session.userId, session: session, metadata: metadata)
return cell
+ } else {
+ // USER / GROUP etc.
+ if let cell = tableView.dequeueReusableCell(withIdentifier: "cellUser", for: indexPath) as? NCShareUserCell {
+ cell.tableShare = tableShare
+ cell.isDirectory = metadata.directory
+ cell.delegate = self
+ cell.setupCellUI(userId: session.userId, session: session, metadata: metadata)
+ // cell.setupCellUI(userId: appDelegate.userId)
+ let isEditingAllowed = shareCommon.isEditingEnabled(isDirectory: directory, fileExtension: metadata?.fileExtension ?? "", shareType: tableShare.shareType)
+ if isEditingAllowed || checkIsCollaboraFile() {
+ cell.btnQuickStatus.isEnabled = true
+ } else {
+ cell.btnQuickStatus.isEnabled = false
+ cell.labelQuickStatus.textColor = NCBrandColor.shared.optionItem
+ cell.imageDownArrow.image = UIImage(named: "downArrow")?.imageColor(NCBrandColor.shared.optionItem)
+ }
+ return cell
+ }
}
}
-
return UITableViewCell()
}
+
+ func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
+ guard let headerView = Bundle.main.loadNibNamed("NCShareHeaderView", owner: self, options: nil)?.first as? NCShareHeaderView else {
+ return UIView()
+ }
+ headerView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+ headerView.fileName.textColor = NCBrandColor.shared.label
+ headerView.labelSharing.textColor = NCBrandColor.shared.label
+ headerView.labelSharingInfo.textColor = NCBrandColor.shared.label
+ headerView.info.textColor = NCBrandColor.shared.systemGray2
+ headerView.ocId = metadata!.ocId
+ headerView.updateCanReshareUI()
+
+
+ if FileManager.default.fileExists(atPath: utilityFileSystem.getDirectoryProviderStorageIconOcId(metadata?.ocId ?? "", etag: metadata?.etag ?? "")) {
+ headerView.fullWidthImageView.image = UIImage(contentsOfFile: utilityFileSystem.getDirectoryProviderStorageIconOcId(metadata?.ocId ?? "", etag: metadata?.etag ?? ""))
+ headerView.fullWidthImageView.contentMode = .scaleAspectFill
+ headerView.imageView.isHidden = true
+ } else {
+ if metadata?.directory ?? false {
+ let image = (metadata?.e2eEncrypted ?? false) ? UIImage(named: "folderEncrypted") : UIImage(named: "folder_nmcloud")
+ headerView.imageView.image = image
+ } else if !(metadata?.iconName.isEmpty ?? false) {
+ headerView.imageView.image = metadata!.fileExtension == "odg" ? UIImage(named: "file-diagram") : UIImage.init(named: metadata!.iconName)
+ } else {
+ headerView.imageView.image = UIImage(named: "file")
+ }
+ }
+
+ headerView.fileName.text = metadata?.fileNameView
+ headerView.fileName.textColor = NCBrandColor.shared.label
+ if metadata!.favorite {
+ headerView.favorite.setImage(utility.loadImage(named: "star.fill", color: NCBrandColor.shared.yellowFavorite, size: 24), for: .normal)
+ } else {
+ headerView.favorite.setImage(utility.loadImage(named: "star.fill", color: NCBrandColor.shared.textInfo, size: 24), for: .normal)
+ }
+ headerView.info.text = utilityFileSystem.transformedSize(metadata!.size) + ", " + utility.dateDiff(metadata!.date as Date)
+ return headerView
+
+ }
+ func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
+ return metadata?.ownerId != appDelegate?.userId ? canReshare ? 400 : 350 : 320
+ }
+ func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
+ return metadata?.ownerId != appDelegate?.userId ? canReshare ? UITableView.automaticDimension : 350 : 320
+ }
}
-// MARK: - CNContactPickerDelegate
+//MARK: CNContactPickerDelegate
extension NCShare: CNContactPickerDelegate {
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
if contact.emailAddresses.count > 1 {
showEmailList(arrEmail: contact.emailAddresses.map({$0.value as String}), sender: picker)
} else if let email = contact.emailAddresses.first?.value as? String {
- searchField?.text = email
+ textField?.text = email
networking?.getSharees(searchString: email)
}
}
-
- func showEmailList(arrEmail: [String], sender: Any?) {
+
+ func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
+ self.keyboardWillHide(notification: Notification(name: Notification.Name("dismiss")))
+ }
+
+ func showEmailList(arrEmail: [String]) {
var actions = [NCMenuAction]()
for email in arrEmail {
actions.append(
NCMenuAction(
title: email,
- icon: utility.loadImage(named: "email", colors: [NCBrandColor.shared.iconImageColor]),
+ icon: utility.loadImage(named: "email").imageColor(NCBrandColor.shared.brandElement),
selected: false,
on: false,
sender: sender,
action: { _ in
- self.searchField?.text = email
+ self.textField?.text = email
self.networking?.getSharees(searchString: email)
}
)
diff --git a/iOSClient/Share/NCShareCommon.swift b/iOSClient/Share/NCShareCommon.swift
index c79dfa9305..751009293d 100644
--- a/iOSClient/Share/NCShareCommon.swift
+++ b/iOSClient/Share/NCShareCommon.swift
@@ -32,7 +32,7 @@ enum NCShareCommon {
let size: CGFloat = 200
let bottomImage = UIImage(named: "circle_fill")!.image(color: colorCircle, size: size / 2)
- let topImage = NCUtility().loadImage(named: imageName, colors: [NCBrandColor.shared.iconImageColor])
+ let topImage = UIImage(named: imageName)!.image(color: .white, size: size / 2)
UIGraphicsBeginImageContextWithOptions(CGSize(width: size, height: size), false, UIScreen.main.scale)
bottomImage.draw(in: CGRect(origin: CGPoint.zero, size: CGSize(width: size, height: size)))
topImage.draw(in: CGRect(origin: CGPoint(x: size / 4, y: size / 4), size: CGSize(width: size / 2, height: size / 2)))
@@ -75,7 +75,50 @@ enum NCShareCommon {
case type.talkConversation.rawValue:
return UIImage(named: "shareTypeRoom")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
default:
- return UIImage(named: "shareTypeUser")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
+ return UIImage(named: "shareTypeUser")?.imageColor(NCBrandColor.shared.label)
}
}
+
+ func isLinkShare(shareType: Int) -> Bool {
+ return shareType == SHARE_TYPE_LINK
+ }
+
+ func isExternalUserShare(shareType: Int) -> Bool {
+ return shareType == SHARE_TYPE_EMAIL
+ }
+
+ func isInternalUser(shareType: Int) -> Bool {
+ return shareType == SHARE_TYPE_USER
+ }
+
+ func isFileTypeAllowedForEditing(fileExtension: String, shareType: Int) -> Bool {
+ if fileExtension == "md" || fileExtension == "txt" {
+ return true
+ } else {
+ return isInternalUser(shareType: shareType)
+ }
+ }
+
+ func isEditingEnabled(isDirectory: Bool, fileExtension: String, shareType: Int) -> Bool {
+ if !isDirectory {//file
+ return isFileTypeAllowedForEditing(fileExtension: fileExtension, shareType: shareType)
+ } else {
+ return true
+ }
+ }
+
+ func isFileDropOptionVisible(isDirectory: Bool, shareType: Int) -> Bool {
+ return (isDirectory && (isLinkShare(shareType: shareType) || isExternalUserShare(shareType: shareType)))
+ }
+
+ func isCurrentUserIsFileOwner(fileOwnerId: String) -> Bool {
+ if let currentUser = NCManageDatabase.shared.getActiveAccount(), currentUser.userId == fileOwnerId {
+ return true
+ }
+ return false
+ }
+
+ func canReshare(withPermission permission: String) -> Bool {
+ return permission.contains(NCGlobal.shared.permissionCanShare)
+ }
}
diff --git a/iOSClient/Share/NCShareEmailFieldCell.swift b/iOSClient/Share/NCShareEmailFieldCell.swift
new file mode 100644
index 0000000000..c39be3b210
--- /dev/null
+++ b/iOSClient/Share/NCShareEmailFieldCell.swift
@@ -0,0 +1,89 @@
+//
+// NCShareEmailFieldCell.swift
+// Nextcloud
+//
+// Created by A200020526 on 01/06/23.
+// Copyright © 2023 Marino Faggiana. All rights reserved.
+//
+
+import UIKit
+
+enum Tag {
+ static let searchField = 999
+}
+
+class NCShareEmailFieldCell: UITableViewCell {
+ @IBOutlet weak var searchField: UITextField!
+ @IBOutlet weak var btnCreateLink: UIButton!
+ @IBOutlet weak var labelYourShare: UILabel!
+ @IBOutlet weak var labelShareByMail: UILabel!
+ @IBOutlet weak var btnContact: UIButton!
+ @IBOutlet weak var labelNoShare: UILabel!
+ @IBOutlet weak var heightLabelNoShare: NSLayoutConstraint!
+
+ override func awakeFromNib() {
+ super.awakeFromNib()
+ // Initialization code
+ setupCell()
+ }
+
+ override func setSelected(_ selected: Bool, animated: Bool) {
+ super.setSelected(selected, animated: animated)
+
+ // Configure the view for the selected state
+ }
+
+ func setupCell(){
+ self.btnCreateLink.setTitle(NSLocalizedString("_create_link_", comment: ""), for: .normal)
+ self.btnCreateLink.layer.cornerRadius = 7
+ self.btnCreateLink.layer.masksToBounds = true
+ self.btnCreateLink.layer.borderWidth = 1
+ self.btnCreateLink.titleLabel?.font = UIFont.systemFont(ofSize: 17)
+ self.btnCreateLink.titleLabel!.adjustsFontSizeToFitWidth = true
+ self.btnCreateLink.titleLabel!.minimumScaleFactor = 0.5
+ self.btnCreateLink.layer.borderColor = NCBrandColor.shared.label.cgColor
+ self.btnCreateLink.setTitleColor(NCBrandColor.shared.label, for: .normal)
+ self.btnCreateLink.backgroundColor = .clear
+
+ self.labelShareByMail.text = NSLocalizedString("personal_share_by_mail", comment: "")
+ self.labelShareByMail.textColor = NCBrandColor.shared.shareByEmailTextColor
+
+ labelYourShare.text = NSLocalizedString("_your_shares_", comment: "")
+
+ searchField.layer.cornerRadius = 5
+ searchField.layer.masksToBounds = true
+ searchField.layer.borderWidth = 1
+ self.searchField.text = ""
+ searchField.attributedPlaceholder = NSAttributedString(string: NSLocalizedString("_shareLinksearch_placeholder_", comment: ""),
+ attributes: [NSAttributedString.Key.foregroundColor: NCBrandColor.shared.gray60])
+ searchField.textColor = NCBrandColor.shared.label
+ searchField.layer.borderColor = NCBrandColor.shared.label.cgColor
+ searchField.tag = Tag.searchField
+ setDoneButton(sender: searchField)
+
+ btnContact.layer.cornerRadius = 5
+ btnContact.layer.masksToBounds = true
+ btnContact.layer.borderWidth = 1
+ btnContact.layer.borderColor = NCBrandColor.shared.label.cgColor
+ btnContact.tintColor = NCBrandColor.shared.label
+ btnContact.setImage(NCUtility().loadImage(named: "contact").image(color: NCBrandColor.shared.label, size: 24), for: .normal)
+ labelNoShare.textColor = NCBrandColor.shared.textInfo
+ labelNoShare.numberOfLines = 0
+ labelNoShare.font = UIFont.systemFont(ofSize: 17)
+ labelNoShare.text = NSLocalizedString("no_shares_created", comment: "")
+ }
+
+ @objc func cancelDatePicker() {
+ self.searchField.endEditing(true)
+ }
+
+ func setDoneButton(sender: UITextField) {
+ //ToolBar
+ let toolbar = UIToolbar();
+ toolbar.sizeToFit()
+ let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .plain, target: self, action: #selector(cancelDatePicker));
+ let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
+ toolbar.setItems([spaceButton, doneButton], animated: false)
+ sender.inputAccessoryView = toolbar
+ }
+}
diff --git a/iOSClient/Share/NCShareEmailFieldCell.xib b/iOSClient/Share/NCShareEmailFieldCell.xib
new file mode 100644
index 0000000000..72cbdfe2d3
--- /dev/null
+++ b/iOSClient/Share/NCShareEmailFieldCell.xib
@@ -0,0 +1,128 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iOSClient/Share/NCShareHeader.swift b/iOSClient/Share/NCShareHeader.swift
index 3d38815179..42e4375b08 100644
--- a/iOSClient/Share/NCShareHeader.swift
+++ b/iOSClient/Share/NCShareHeader.swift
@@ -1,5 +1,5 @@
//
-// NCShareHeader.swift
+// NCShareAdvancePermissionHeader.swift
// Nextcloud
//
// Created by T-systems on 10/08/21.
@@ -22,52 +22,58 @@
//
import UIKit
-import TagListView
-class NCShareHeader: UIView {
+class NCShareAdvancePermissionHeader: UIView {
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var fileName: UILabel!
@IBOutlet weak var info: UILabel!
+ @IBOutlet weak var favorite: UIButton!
@IBOutlet weak var fullWidthImageView: UIImageView!
- @IBOutlet weak var fileNameTopConstraint: NSLayoutConstraint!
- @IBOutlet weak var tagListView: TagListView!
-
- private var heightConstraintWithImage: NSLayoutConstraint?
- private var heightConstraintWithoutImage: NSLayoutConstraint?
-
+ var ocId = ""
+ let utility = NCUtility()
+ let utilityFileSystem = NCUtilityFileSystem()
+
func setupUI(with metadata: tableMetadata) {
let utilityFileSystem = NCUtilityFileSystem()
if let image = NCUtility().getImage(ocId: metadata.ocId, etag: metadata.etag, ext: NCGlobal.shared.previewExt1024, userId: metadata.userId, urlBase: metadata.urlBase) {
fullWidthImageView.image = image
fullWidthImageView.contentMode = .scaleAspectFill
- imageView.image = fullWidthImageView.image
imageView.isHidden = true
} else {
if metadata.directory {
- imageView.image = metadata.e2eEncrypted ? NCImageCache.shared.getFolderEncrypted(account: metadata.account) : NCImageCache.shared.getFolder(account: metadata.account)
+ imageView.image = UIImage.init(named: "folder")
} else if !metadata.iconName.isEmpty {
- imageView.image = NCUtility().loadImage(named: metadata.iconName, useTypeIconFile: true, account: metadata.account)
+ imageView.image = UIImage.init(named: metadata.iconName)
} else {
- imageView.image = NCImageCache.shared.getImageFile()
+ imageView.image = UIImage.init(named: "file")
}
-
- fileNameTopConstraint.constant -= 45
}
-
+ favorite.setNeedsUpdateConstraints()
+ favorite.layoutIfNeeded()
fileName.text = metadata.fileNameView
- fileName.textColor = NCBrandColor.shared.textColor
- info.textColor = NCBrandColor.shared.textColor2
- info.text = utilityFileSystem.transformedSize(metadata.size) + ", " + NCUtility().getRelativeDateTitle(metadata.date as Date)
-
- tagListView.addTags(Array(metadata.tags))
-
- setNeedsLayout()
- layoutIfNeeded()
+ fileName.textColor = NCBrandColor.shared.fileFolderName
+ if metadata.favorite {
+ favorite.setImage(utility.loadImage(named: "star.fill", color: NCBrandColor.shared.yellowFavorite, size: 24), for: .normal)
+ } else {
+ favorite.setImage(utility.loadImage(named: "star.fill", color: NCBrandColor.shared.textInfo, size: 24), for: .normal)
+ }
+ info.textColor = NCBrandColor.shared.optionItem
+ info.text = utilityFileSystem.transformedSize(metadata.size) + ", " + utility.dateDiff(metadata.date as Date)
}
-
- override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
- if fullWidthImageView.image != nil {
- imageView.isHidden = traitCollection.verticalSizeClass != .compact
+
+ @IBAction func touchUpInsideFavorite(_ sender: UIButton) {
+ guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return }
+ NCNetworking.shared.favoriteMetadata(metadata) { error in
+ if error == .success {
+ guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(metadata.ocId) else { return }
+ if metadata.favorite {
+ self.favorite.setImage(self.utility.loadImage(named: "star.fill", color: NCBrandColor.shared.yellowFavorite, size: 24), for: .normal)
+ } else {
+ self.favorite.setImage(self.utility.loadImage(named: "star.fill", color: NCBrandColor.shared.textInfo, size: 24), for: .normal)
+ }
+ } else {
+ NCContentPresenter().showError(error: error)
+ }
}
}
}
diff --git a/iOSClient/Share/NCShareHeaderView.xib b/iOSClient/Share/NCShareHeaderView.xib
index 44b83d3fc7..b7384fb2ec 100644
--- a/iOSClient/Share/NCShareHeaderView.xib
+++ b/iOSClient/Share/NCShareHeaderView.xib
@@ -1,149 +1,176 @@
-
+
-
-
+
-
-
+
+
-
-
+
+
-
-
+
-
-
-
+
+
-
-
+
+
-
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
diff --git a/iOSClient/Share/NCShareLinkCell.swift b/iOSClient/Share/NCShareLinkCell.swift
index 406dc31b0a..e97dea80cf 100644
--- a/iOSClient/Share/NCShareLinkCell.swift
+++ b/iOSClient/Share/NCShareLinkCell.swift
@@ -34,6 +34,16 @@ class NCShareLinkCell: UITableViewCell {
@IBOutlet private weak var copyButton: UIButton!
@IBOutlet weak var imageDownArrow: UIImageView!
+// @IBOutlet weak var imageItem: UIImageView!
+// @IBOutlet weak var labelTitle: UILabel!
+// @IBOutlet weak var buttonCopy: UIButton!
+// @IBOutlet weak var buttonMenu: UIButton!
+// @IBOutlet weak var status: UILabel!
+// @IBOutlet weak var btnQuickStatus: UIButton!
+// @IBOutlet weak var imageDownArrow: UIImageView!
+// @IBOutlet weak var labelQuickStatus: UILabel!
+
+ private let iconShare: CGFloat = 200
var tableShare: tableShare?
var isDirectory = false
weak var delegate: NCShareLinkCellDelegate?
@@ -49,7 +59,8 @@ class NCShareLinkCell: UITableViewCell {
func setupCellUI(titleAppendString: String? = nil) {
var menuImageName = "ellipsis"
-
+ let permissions = NCPermissions()
+
menuButton.isHidden = isInternalLink
descriptionLabel.isHidden = !isInternalLink
copyButton.isHidden = !isInternalLink && tableShare == nil
@@ -57,21 +68,21 @@ class NCShareLinkCell: UITableViewCell {
copyButton.setImage(UIImage(systemName: "doc.on.doc")?.withTintColor(.label, renderingMode: .alwaysOriginal), for: .normal)
copyButton.accessibilityLabel = NSLocalizedString("_copy_", comment: "")
-
+
menuButton.accessibilityLabel = NSLocalizedString("_more_", comment: "")
menuButton.accessibilityIdentifier = "showShareLinkDetails"
-
+
if isInternalLink {
labelTitle.text = NSLocalizedString("_share_internal_link_", comment: "")
descriptionLabel.text = NSLocalizedString("_share_internal_link_des_", comment: "")
imageItem.image = NCUtility().loadImage(named: "square.and.arrow.up.circle.fill", colors: [NCBrandColor.shared.iconImageColor2])
} else {
labelTitle.text = NSLocalizedString("_share_link_", comment: "")
-
+
if let titleAppendString {
labelTitle.text?.append(" (\(titleAppendString))")
}
-
+
if let tableShare = tableShare {
if !tableShare.label.isEmpty {
labelTitle.text? += " (\(tableShare.label))"
@@ -81,15 +92,15 @@ class NCShareLinkCell: UITableViewCell {
menuButton.accessibilityLabel = NSLocalizedString("_add_", comment: "")
menuButton.accessibilityIdentifier = "addShareLink"
}
-
+
imageItem.image = NCUtility().loadImage(named: "link.circle.fill", colors: [NCBrandColor.shared.getElement(account: tableShare?.account)])
menuButton.setImage(NCUtility().loadImage(named: menuImageName, colors: [NCBrandColor.shared.iconImageColor]), for: .normal)
}
-
+
labelTitle.textColor = NCBrandColor.shared.textColor
-
+
statusStackView.isHidden = true
-
+
if let tableShare {
statusStackView.isHidden = false
labelQuickStatus.text = NSLocalizedString("_custom_permissions_", comment: "")
@@ -109,21 +120,52 @@ class NCShareLinkCell: UITableViewCell {
imageItem.image = NCUtility().loadImage(named: "envelope.circle.fill", colors: [NCBrandColor.shared.getElement(account: tableShare.account)])
}
}
-
+
statusStackView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(openQuickStatus)))
labelQuickStatus.textColor = NCBrandColor.shared.customer
imageDownArrow.image = utility.loadImage(named: "arrowtriangle.down.circle", colors: [NCBrandColor.shared.customer])
}
- @IBAction func touchUpCopy(_ sender: Any) {
- delegate?.tapCopy(with: tableShare, sender: sender)
+ override func awakeFromNib() {
+ super.awakeFromNib()
+
+ imageItem.image = UIImage(named: "sharebylink")?.image(color: NCBrandColor.shared.label, size: 30)
+ buttonCopy.setImage(UIImage.init(named: "shareCopy")!.image(color: NCBrandColor.shared.customer, size: 24), for: .normal)
+ buttonMenu.setImage(UIImage.init(named: "shareMenu")!.image(color: NCBrandColor.shared.customer, size: 24), for: .normal)
+ labelQuickStatus.textColor = NCBrandColor.shared.customer
}
- @IBAction func touchUpMenu(_ sender: Any) {
+ func setupCellUI() {
+ guard let tableShare = tableShare else {
+ return
+ }
+ contentView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+ labelTitle.textColor = NCBrandColor.shared.label
+
+ if tableShare.permissions == NCGlobal.shared.permissionCreateShare {
+ labelQuickStatus.text = NSLocalizedString("_share_file_drop_", comment: "")
+ } else {
+ // Read Only
+ if CCUtility.isAnyPermission(toEdit: tableShare.permissions) {
+ labelQuickStatus.text = NSLocalizedString("_share_editing_", comment: "")
+ } else {
+ labelQuickStatus.text = NSLocalizedString("_share_read_only_", comment: "")
+ }
+ }
+ }
+
+ @IBAction func touchUpInsideCopy(_ sender: Any) {
+ delegate?.tapCopy(with: tableShare, sender: sender)
+ }
+
+ @IBAction func touchUpInsideMenu(_ sender: Any) {
delegate?.tapMenu(with: tableShare, sender: sender)
}
@objc func openQuickStatus(_ sender: UITapGestureRecognizer) {
+ }
+
+ @IBAction func quickStatusClicked(_ sender: UIButton) {
delegate?.quickStatus(with: tableShare, sender: sender)
}
}
diff --git a/iOSClient/Share/NCShareNetworking.swift b/iOSClient/Share/NCShareNetworking.swift
index b696bac0e8..998efae846 100644
--- a/iOSClient/Share/NCShareNetworking.swift
+++ b/iOSClient/Share/NCShareNetworking.swift
@@ -113,6 +113,21 @@ class NCShareNetworking: NSObject {
}
}
}
+
+ func createShareLink(password: String?) {
+ NCActivityIndicator.shared.start(backgroundView: view)
+ let filenamePath = utilityFileSystem.getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, userId: metadata.userId)
+ NextcloudKit.shared.createShareLink(path: filenamePath) { [self] account, share, data, error in
+ NCActivityIndicator.shared.stop()
+ if error == .success && share != nil {
+ let home = utilityFileSystem.getHomeServer(urlBase: self.metadata.urlBase, userId: self.metadata.userId)
+ NCManageDatabase.shared.addShare(account: self.metadata.account, home:home, shares: [share!])
+ } else if error != .success{
+ NCContentPresenter().showError(error: error)
+ }
+ self.delegate?.shareCompleted()
+ }
+ }
func createShare(_ shareable: Shareable, downloadLimit: DownloadLimitViewModel) {
NCActivityIndicator.shared.start(backgroundView: view)
diff --git a/iOSClient/Share/NCSharePaging.swift b/iOSClient/Share/NCSharePaging.swift
index fe044d7dad..c069e405ce 100644
--- a/iOSClient/Share/NCSharePaging.swift
+++ b/iOSClient/Share/NCSharePaging.swift
@@ -29,7 +29,7 @@ import MarqueeLabel
import TagListView
protocol NCSharePagingContent {
- var textField: UIView? { get }
+ var textField: UITextField? { get }
}
class NCSharePaging: UIViewController {
@@ -54,16 +54,15 @@ class NCSharePaging: UIViewController {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
- NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground(notification:)), name: UIApplication.didEnterBackgroundNotification, object: nil)
+ NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground(notification:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidEnterBackground), object: nil)
// *** MUST BE THE FIRST ONE ***
pagingViewController.metadata = metadata
pagingViewController.backgroundColor = .systemBackground
pagingViewController.menuBackgroundColor = .systemBackground
pagingViewController.selectedBackgroundColor = .systemBackground
- pagingViewController.indicatorColor = NCBrandColor.shared.getElement(account: metadata.account)
- pagingViewController.textColor = NCBrandColor.shared.textColor
- pagingViewController.selectedTextColor = NCBrandColor.shared.getElement(account: metadata.account)
+ pagingViewController.textColor = .label
+ pagingViewController.selectedTextColor = .label
// Pagination
addChild(pagingViewController)
@@ -75,16 +74,14 @@ class NCSharePaging: UIViewController {
height: 1,
zIndex: Int.max,
spacing: .zero,
- insets: .zero
+ insets: UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
)
- pagingViewController.borderOptions = .visible(height: 1, zIndex: Int.max, insets: .zero)
-
// Contrain the paging view to all edges.
pagingViewController.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
pagingViewController.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
- pagingViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
+ pagingViewController.view.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
pagingViewController.view.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
pagingViewController.view.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor)
])
@@ -98,6 +95,7 @@ class NCSharePaging: UIViewController {
pagingViewController.select(index: 0)
}
+ (pagingViewController.view as? NCSharePagingView)?.setupConstraints()
pagingViewController.reloadMenu()
}
@@ -117,9 +115,9 @@ class NCSharePaging: UIViewController {
self.dismiss(animated: false, completion: nil)
}
-// pagingViewController.menuItemSize = .fixed(
-// width: self.view.bounds.width / CGFloat(self.pages.count),
-// height: 40)
+ pagingViewController.menuItemSize = .fixed(
+ width: self.view.bounds.width / CGFloat(self.pages.count),
+ height: 40)
}
override func viewWillDisappear(_ animated: Bool) {
@@ -134,12 +132,17 @@ class NCSharePaging: UIViewController {
deinit {
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardDidShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
- NotificationCenter.default.removeObserver(self, name: UIApplication.didEnterBackgroundNotification, object: nil)
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
- self.currentVC?.textField?.resignFirstResponder()
+
+ coordinator.animate(alongsideTransition: nil) { _ in
+ self.pagingViewController.menuItemSize = .fixed(
+ width: self.view.bounds.width / CGFloat(self.pages.count),
+ height: 40)
+ self.currentVC?.textField?.resignFirstResponder()
+ }
}
// MARK: - NotificationCenter & Keyboard & TextField
@@ -244,11 +247,11 @@ class NCShareHeaderViewController: PagingViewController {
}
class NCSharePagingView: PagingView {
+
+ static let headerHeight: CGFloat = 90
+ static var tagHeaderHeight: CGFloat = 0
var metadata = tableMetadata()
- let utilityFileSystem = NCUtilityFileSystem()
- let utility = NCUtility()
public var headerHeightConstraint: NSLayoutConstraint?
- var header: NCShareHeader?
// MARK: - View Life Cycle
@@ -261,71 +264,74 @@ class NCSharePagingView: PagingView {
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
-
- override func setupConstraints() {
- guard let headerView = Bundle.main.loadNibNamed("NCShareHeader", owner: self, options: nil)?.first as? NCShareHeader else { return }
- header = headerView
- headerView.backgroundColor = .systemBackground
-
- let dateFormatter = DateFormatter()
- dateFormatter.dateStyle = .short
- dateFormatter.timeStyle = .short
- dateFormatter.locale = Locale.current
-
- headerView.setupUI(with: metadata)
-
- addSubview(headerView)
-
- collectionView.translatesAutoresizingMaskIntoConstraints = false
- headerView.translatesAutoresizingMaskIntoConstraints = false
- pageView.translatesAutoresizingMaskIntoConstraints = false
-
- NSLayoutConstraint.activate([
- collectionView.leadingAnchor.constraint(equalTo: leadingAnchor),
- collectionView.trailingAnchor.constraint(equalTo: trailingAnchor),
- collectionView.heightAnchor.constraint(equalToConstant: options.menuHeight),
- collectionView.topAnchor.constraint(equalTo: headerView.bottomAnchor),
-
- headerView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor),
- headerView.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor),
- headerView.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor),
-
- pageView.leadingAnchor.constraint(equalTo: leadingAnchor),
- pageView.trailingAnchor.constraint(equalTo: trailingAnchor),
- pageView.bottomAnchor.constraint(equalTo: bottomAnchor),
- pageView.topAnchor.constraint(equalTo: headerView.bottomAnchor)
- ])
- }
}
class NCShareHeaderView: UIView {
@IBOutlet weak var imageView: UIImageView!
- @IBOutlet weak var path: MarqueeLabel!
+ @IBOutlet weak var fileName: UILabel!
@IBOutlet weak var info: UILabel!
- @IBOutlet weak var creation: UILabel!
- @IBOutlet weak var upload: UILabel!
@IBOutlet weak var favorite: UIButton!
- @IBOutlet weak var details: UIButton!
- @IBOutlet weak var tagListView: TagListView!
-
+ @IBOutlet weak var labelSharing: UILabel!
+ @IBOutlet weak var labelSharingInfo: UILabel!
+ @IBOutlet weak var fullWidthImageView: UIImageView!
+ @IBOutlet weak var canShareInfoView: UIView!
+ @IBOutlet weak var sharedByLabel: UILabel!
+ @IBOutlet weak var resharingAllowedLabel: UILabel!
+ @IBOutlet weak var sharedByImageView: UIImageView!
+ @IBOutlet weak var constraintTopSharingLabel: NSLayoutConstraint!
+ let utility = NCUtility()
var ocId = ""
override func awakeFromNib() {
super.awakeFromNib()
let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(longTap(_:)))
path.addGestureRecognizer(longGesture)
+ setupUI()
}
+ func setupUI() {
+ labelSharing.text = NSLocalizedString("_sharing_", comment: "")
+ labelSharingInfo.text = NSLocalizedString("_sharing_message_", comment: "")
+
+ if UIScreen.main.bounds.width < 376 {
+ constraintTopSharingLabel.constant = 15
+ }
+ }
+
+ func updateCanReshareUI() {
+ let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId)
+ var isCurrentUser = true
+ if let ownerId = metadata?.ownerId, !ownerId.isEmpty {
+ isCurrentUser = NCShareCommon().isCurrentUserIsFileOwner(fileOwnerId: ownerId)
+ }
+ var canReshare: Bool {
+ guard let metadata = metadata else { return true }
+ return ((metadata.sharePermissionsCollaborationServices & NCGlobal.shared.permissionShareShare) != 0)
+ }
+ canShareInfoView.isHidden = isCurrentUser
+ labelSharingInfo.isHidden = !isCurrentUser
+
+ if !isCurrentUser {
+ sharedByImageView.image = UIImage(named: "cloudUpload")?.image(color: .systemBlue, size: 26)
+ let ownerName = metadata?.ownerDisplayName ?? ""
+ sharedByLabel.text = NSLocalizedString("_shared_with_you_by_", comment: "") + " " + ownerName
+ let resharingAllowedMessage = NSLocalizedString("_share_reshare_allowed_", comment: "") + " " + NSLocalizedString("_sharing_message_", comment: "")
+ let resharingNotAllowedMessage = NSLocalizedString("_share_reshare_not_allowed_", comment: "")
+ resharingAllowedLabel.text = canReshare ? resharingAllowedMessage : resharingNotAllowedMessage
+ }
+ }
+
@IBAction func touchUpInsideFavorite(_ sender: UIButton) {
guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return }
NCNetworking.shared.setStatusWaitFavorite(metadata) { error in
if error == .success {
guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(metadata.ocId) else { return }
- self.favorite.setImage(NCUtility().loadImage(
- named: "star.fill",
- colors: metadata.favorite ? [NCBrandColor.shared.yellowFavorite] : [NCBrandColor.shared.iconImageColor2],
- size: 20), for: .normal)
+ if metadata.favorite {
+ self.favorite.setImage(self.utility.loadImage(named: "star.fill", color: NCBrandColor.shared.yellowFavorite, size: 24), for: .normal)
+ } else {
+ self.favorite.setImage(self.utility.loadImage(named: "star.fill", color: NCBrandColor.shared.textInfo, size: 24), for: .normal)
+ }
} else {
NCContentPresenter().showError(error: error)
}
diff --git a/iOSClient/Share/NCShareUserCell.swift b/iOSClient/Share/NCShareUserCell.swift
index c749a99b5f..5912522ca1 100644
--- a/iOSClient/Share/NCShareUserCell.swift
+++ b/iOSClient/Share/NCShareUserCell.swift
@@ -34,7 +34,8 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol {
@IBOutlet weak var btnQuickStatus: UIButton!
@IBOutlet weak var labelQuickStatus: UILabel!
@IBOutlet weak var imageDownArrow: UIImageView!
-
+ @IBOutlet weak var labelCanEdit: UILabel!
+ @IBOutlet weak var switchCanEdit: UISwitch!
private var index = IndexPath()
var tableShare: tableShare?
@@ -46,9 +47,6 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol {
get { return index }
set { index = newValue }
}
- var fileAvatarImageView: UIImageView? {
- return imageItem
- }
var fileUser: String? {
get { return tableShare?.shareWith }
set {}
@@ -71,28 +69,41 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol {
labelTitle.lineBreakMode = .byTruncatingMiddle
labelTitle.textColor = NCBrandColor.shared.textColor
+ contentView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+
+ labelTitle.text = tableShare.shareWithDisplayname
+ labelTitle.textColor = NCBrandColor.shared.label
isUserInteractionEnabled = true
- labelQuickStatus.isHidden = false
- imageDownArrow.isHidden = false
+ switchCanEdit.isHidden = true
+ labelCanEdit.isHidden = true
buttonMenu.isHidden = false
buttonMenu.accessibilityLabel = NSLocalizedString("_more_", comment: "")
imageItem.image = NCShareCommon.getImageShareType(shareType: tableShare.shareType)
let status = utility.getUserStatus(userIcon: tableShare.userIcon, userStatus: tableShare.userStatus, userMessage: tableShare.userMessage)
- imageStatus.image = status.statusImage
+ imageStatus.image = status.onlineStatus
self.status.text = status.statusMessage
+
+ if CCUtility.isAnyPermission(toEdit: tableShare.permissions) {
+ switchCanEdit.setOn(true, animated: false)
+ } else {
+ switchCanEdit.setOn(false, animated: false)
+ }
// If the initiator or the recipient is not the current user, show the list of sharees without any options to edit it.
if tableShare.uidOwner != userId && tableShare.uidFileOwner != userId {
isUserInteractionEnabled = false
- labelQuickStatus.isHidden = true
- imageDownArrow.isHidden = true
+ switchCanEdit.isHidden = true
+ labelCanEdit.isHidden = true
buttonMenu.isHidden = true
}
btnQuickStatus.accessibilityHint = NSLocalizedString("_user_sharee_footer_", comment: "")
btnQuickStatus.setTitle("", for: .normal)
btnQuickStatus.contentHorizontalAlignment = .left
+ btnQuickStatus.isEnabled = true
+ labelQuickStatus.textColor = NCBrandColor.shared.brand
+ imageDownArrow.image = UIImage(named: "downArrow")?.imageColor(NCBrandColor.shared.brand)
if NCSharePermissions.canEdit(tableShare.permissions, isDirectory: isDirectory) { // Can edit
labelQuickStatus.text = NSLocalizedString("_share_editing_", comment: "")
@@ -132,15 +143,27 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol {
default:
return ""
}
+ if tableShare.permissions == NCGlobal.shared.permissionCreateShare {
+ labelQuickStatus.text = NSLocalizedString("_share_file_drop_", comment: "")
+ } else {
+ // Read Only
+ if CCUtility.isAnyPermission(toEdit: tableShare.permissions) {
+ labelQuickStatus.text = NSLocalizedString("_share_editing_", comment: "")
+ } else {
+ labelQuickStatus.text = NSLocalizedString("_share_read_only_", comment: "")
+ }
+ }
}
override func awakeFromNib() {
super.awakeFromNib()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapAvatarImage(_:)))
imageItem?.addGestureRecognizer(tapGesture)
-
+ buttonMenu.setImage(UIImage.init(named: "shareMenu")!.image(color: NCBrandColor.shared.customer, size: 24), for: .normal)
labelQuickStatus.textColor = NCBrandColor.shared.customer
- imageDownArrow.image = utility.loadImage(named: "arrowtriangle.down.circle", colors: [NCBrandColor.shared.customer])
+ imageDownArrow.image = UIImage(named: "downArrow")?.imageColor(NCBrandColor.shared.customer)
+ switchCanEdit.transform = CGAffineTransform(scaleX: 0.75, y: 0.75)
+ switchCanEdit.onTintColor = NCBrandColor.shared.brandElement
}
@objc func tapAvatarImage(_ sender: UITapGestureRecognizer) {
@@ -191,14 +214,10 @@ class NCSearchUserDropDownCell: DropDownCell, NCCellProtocol {
func setupCell(sharee: NKSharee, session: NCSession.Session) {
let utility = NCUtility()
imageItem.image = NCShareCommon.getImageShareType(shareType: sharee.shareType)
- imageShareeType.image = NCShareCommon.getImageShareType(shareType: sharee.shareType)
+// imageShareeType.image = NCShareCommon.getImageShareType(shareType: sharee.shareType)
+ imageShareeType.image = NCShareCommon().getImageShareType(shareType: sharee.shareType, isDropDown: true)
let status = utility.getUserStatus(userIcon: sharee.userIcon, userStatus: sharee.userStatus, userMessage: sharee.userMessage)
-
- if let statusImage = status.statusImage {
- imageStatus.image = statusImage
- imageStatus.makeCircularBackground(withColor: .systemBackground)
- }
-
+ imageStatus.image = status.onlineStatus
self.status.text = status.statusMessage
if self.status.text?.count ?? 0 > 0 {
centerTitle.constant = -5
diff --git a/iOSClient/Share/ShareDownloadLimitNetwork.swift b/iOSClient/Share/ShareDownloadLimitNetwork.swift
new file mode 100644
index 0000000000..9fadc08515
--- /dev/null
+++ b/iOSClient/Share/ShareDownloadLimitNetwork.swift
@@ -0,0 +1,146 @@
+//
+// ShareDownloadLimitNetwork.swift
+// Nextcloud
+//
+// Created by A118830248 on 11/11/21.
+// Copyright © 2021 Marino Faggiana. All rights reserved.
+//
+
+import Foundation
+import SwiftyJSON
+import NextcloudKit
+import Alamofire
+
+class NMCCommunication: NSObject, XMLParserDelegate {
+
+ public static let shared: NMCCommunication = {
+ let instance = NMCCommunication()
+ return instance
+ }()
+
+ var message = ""
+ var foundCharacters = "";
+ var downloadLimit = DownloadLimit()
+ private lazy var appDelegate = UIApplication.shared.delegate as? AppDelegate
+
+ func getDownloadLimit(token: String, completion: @escaping (_ downloadLimit: DownloadLimit?, _ errorDescription: String) -> Void) {
+ let baseUrl = appDelegate?.urlBase ?? "" // NCBrandOptions.shared.loginBaseUrl
+ let endPoint = "/ocs/v2.php/apps/files_downloadlimit/\(token)/limit"
+ let path = baseUrl+endPoint
+ do {
+ var urlRequest = try URLRequest(url: URL(string: path)!, method: .get)
+ urlRequest.addValue("true", forHTTPHeaderField: "OCS-APIREQUEST")
+
+ let sessionConfiguration = URLSessionConfiguration.default
+ let urlSession = URLSession(configuration: sessionConfiguration)
+
+ let task = urlSession.dataTask(with: urlRequest) { [self] (data, response, error) in
+ guard error == nil else {
+ completion(nil, error?.localizedDescription ?? "")
+ return
+ }
+
+ if let httpResponse = response as? HTTPURLResponse {
+ let statusCode = httpResponse.statusCode
+ print("url: \(String(describing: httpResponse.url))\nStatus Code: \(statusCode)")
+ if httpResponse.statusCode == 200 {
+ let parser = XMLParser(data: data!)
+ parser.delegate = self
+ parser.parse()
+ completion(self.downloadLimit, self.message)
+ } else {
+ completion(nil, "Invalid Response code: \(statusCode)")
+ }
+ } else {
+ completion(nil, error?.localizedDescription ?? "Invalid Response")
+ }
+ }
+ task.resume()
+ } catch {
+ completion(nil, error.localizedDescription)
+ }
+ }
+
+ func setDownloadLimit(deleteLimit: Bool, limit: String, token: String, completion: @escaping (_ success: Bool, _ errorDescription: String) -> Void) {
+ let baseUrl = appDelegate?.urlBase ?? "" //NCBrandOptions.shared.loginBaseUrl
+ let endPoint = "/ocs/v2.php/apps/files_downloadlimit/\(token)/limit"
+ let path = baseUrl+endPoint
+ do {
+
+ let method = deleteLimit ? HTTPMethod.delete : .put
+ var urlRequest = try URLRequest(url: URL(string: path)!, method: method)
+
+ urlRequest.addValue("true", forHTTPHeaderField: "OCS-APIREQUEST")
+ urlRequest.addValue(authorizationToken(), forHTTPHeaderField: "Authorization")
+ urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
+
+ let parameters = ["token": token, "limit": limit]
+
+ let encoder = JSONEncoder()
+ let jsonData = try encoder.encode(parameters)
+ urlRequest.httpBody = jsonData
+
+ let sessionConfiguration = URLSessionConfiguration.default
+ let urlSession = URLSession(configuration: sessionConfiguration)
+
+ let task = urlSession.dataTask(with: urlRequest) { (data, response, error) in
+ guard error == nil else {
+ completion(false, error?.localizedDescription ?? "")
+ return
+ }
+
+ if let httpResponse = response as? HTTPURLResponse {
+ let statusCode = httpResponse.statusCode
+ print("url: \(String(describing: httpResponse.url))\nStatus Code: \(statusCode)")
+ if httpResponse.statusCode == 200 {
+ completion(true, error?.localizedDescription ?? "")
+ } else {
+ completion(false, "Invalid Response code: \(statusCode)")
+ }
+ } else {
+ completion(false, error?.localizedDescription ?? "Invalid Response")
+ }
+ }
+ task.resume()
+ } catch {
+ completion(false, error.localizedDescription)
+ }
+ }
+
+ public func authorizationToken() -> String {
+ let accountDetails = NCManageDatabase.shared.getAllAccount().first
+ let password = NCKeychain().getPassword(account: accountDetails?.account ?? "")
+ let username = accountDetails?.user ?? ""
+ let credential = Data("\(username):\(password)".utf8).base64EncodedString()
+ return ("Basic \(credential)")
+ }
+
+
+ // MARK:- XML Parser Delegate
+ public func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
+
+ }
+ public func parser(_ parser: XMLParser, foundCharacters string: String) {
+ self.foundCharacters += string;
+ }
+
+ public func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
+ if elementName == "limit" {
+ let limit = self.foundCharacters.replacingOccurrences(of: "\n", with: "")
+ self.downloadLimit.limit = Int(limit.trimmingCharacters(in: .whitespaces))
+ }
+ if elementName == "count" {
+ let count = self.foundCharacters.replacingOccurrences(of: "\n", with: "")
+ self.downloadLimit.count = Int(count.trimmingCharacters(in: .whitespaces))
+ }
+ if elementName == "message"{
+ self.message = self.foundCharacters
+ }
+ self.foundCharacters = ""
+ }
+}
+
+struct DownloadLimit: Codable {
+ var limit: Int?
+ var count: Int?
+}
diff --git a/iOSClient/Utility/NCUtility.swift b/iOSClient/Utility/NCUtility.swift
index f025eacb9d..8a7526f446 100644
--- a/iOSClient/Utility/NCUtility.swift
+++ b/iOSClient/Utility/NCUtility.swift
@@ -292,4 +292,11 @@ final class NCUtility: NSObject, Sendable {
return count.formatted(.number.notation(.compactName).locale(Locale(identifier: "en_US")))
}
}
+
+ func isValidEmail(_ email: String) -> Bool {
+
+ let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
+ let emailPred = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
+ return emailPred.evaluate(with: email)
+ }
}
From 3b79c4063a1f99fdc575898649631158af0776c8 Mon Sep 17 00:00:00 2001
From: Amrut Waghmare
Date: Mon, 26 Aug 2024 11:28:46 +0530
Subject: [PATCH 2/6] NMC 1992 - Sharing changes after NC release 5.5.4
---
iOSClient/Activity/NCActivity.swift | 2 +-
.../Advanced/NCShareAdvancePermission.swift | 58 ++++++++++---------
iOSClient/Share/NCShare.swift | 8 +--
iOSClient/Share/NCShareCommon.swift | 2 +-
iOSClient/Share/NCShareHeader.swift | 8 +--
iOSClient/Share/NCShareLinkCell.swift | 9 +--
iOSClient/Share/NCSharePaging.swift | 6 +-
iOSClient/Share/NCShareUserCell.swift | 14 +++--
8 files changed, 56 insertions(+), 51 deletions(-)
diff --git a/iOSClient/Activity/NCActivity.swift b/iOSClient/Activity/NCActivity.swift
index 6098a49209..4fda986171 100644
--- a/iOSClient/Activity/NCActivity.swift
+++ b/iOSClient/Activity/NCActivity.swift
@@ -12,7 +12,7 @@ class NCActivity: UIViewController, NCSharePagingContent {
@IBOutlet weak var tableView: UITableView!
var commentView: NCActivityCommentView?
- var textField: UIView? { commentView?.newCommentField }
+ var textField: UITextField? { commentView?.newCommentField }
var height: CGFloat = 0
var metadata: tableMetadata?
var showComments: Bool = false
diff --git a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift
index 43fe39133d..1609f92054 100644
--- a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift
+++ b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift
@@ -25,6 +25,7 @@ import UIKit
import NextcloudKit
import SVGKit
import CloudKit
+import XLForm
class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDelegate, NCShareNavigationTitleSetting {
//class NCShareAdvancePermission: XLFormViewController, NCShareAdvanceFotterDelegate, NCShareDetail {
@@ -192,7 +193,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
}
func setupHeaderView() {
- guard let headerView = (Bundle.main.loadNibNamed("NCShareHeader", owner: self, options: nil)?.first as? NCShareHeader) else { return }
+ guard let headerView = (Bundle.main.loadNibNamed("NCShareAdvancePermissionHeader", owner: self, options: nil)?.first as? NCShareAdvancePermissionHeader) else { return }
headerView.setupUI(with: metadata)
headerView.ocId = metadata.ocId
headerView.frame = CGRect(x: 0, y: 0, width: self.view.frame.size.width, height: 190)
@@ -239,7 +240,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
let form : XLFormDescriptor
var section : XLFormSectionDescriptor
var row : XLFormRowDescriptor
-
+ let permissions = NCPermissions()
form = XLFormDescriptor(title: "Other Cells")
//Sharing
@@ -263,12 +264,12 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
row.cellConfig["titleLabel.text"] = NSLocalizedString("_share_read_only_", comment: "")
row.height = 44
- if let permission = self.permission, !CCUtility.isAnyPermission(toEdit: permission), permission != NCGlobal.shared.permissionCreateShare {
+ if let permission = self.permission, !permissions.isAnyPermissionToEdit(permission), permission != permissions.permissionCreateShare {
row.cellConfig["imageCheck.image"] = UIImage(named: "success")!.image(color: NCBrandColor.shared.customer, size: 25.0)
}
if isNewShare {
row.cellConfig["imageCheck.image"] = UIImage(named: "success")!.image(color: NCBrandColor.shared.customer, size: 25.0)
- self.permission = NCGlobal.shared.permissionReadShare
+ self.permission = permissions.permissionReadShare
}
section.addFormRow(row)
@@ -279,7 +280,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
row.cellConfig["titleLabel.text"] = NSLocalizedString("_share_allow_editing_", comment: "")
row.height = 44
if let permission = self.permission {
- if CCUtility.isAnyPermission(toEdit: permission), permission != NCGlobal.shared.permissionCreateShare {
+ if permissions.isAnyPermissionToEdit(permission), permission != permissions.permissionCreateShare {
row.cellConfig["imageCheck.image"] = UIImage(named: "success")!.image(color: NCBrandColor.shared.customer, size: 25.0)
}
}
@@ -301,7 +302,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
XLFormViewController.cellClassesForRowDescriptorTypes()["kNMCFilePermissionCell"] = NCFilePermissionCell.self
row = XLFormRowDescriptor(tag: "NCFilePermissionCellFileDrop", rowType: "kNMCFilePermissionCell", title: NSLocalizedString("_PERMISSIONS_", comment: ""))
row.cellConfig["titleLabel.text"] = NSLocalizedString("_share_file_drop_", comment: "")
- if self.permission == NCGlobal.shared.permissionCreateShare {
+ if self.permission == permissions.permissionCreateShare {
row.cellConfig["imageCheck.image"] = UIImage(named: "success")!.image(color: NCBrandColor.shared.customer, size: 25.0)
}
row.height = 44
@@ -530,11 +531,11 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
override func didSelectFormRow(_ formRow: XLFormRowDescriptor!) {
guard let metadata = self.metadata else { return }
-
+ let permissions = NCPermissions()
switch formRow.tag {
case "NCFilePermissionCellRead":
- let value = CCUtility.getPermissionsValue(byCanEdit: false, andCanCreate: false, andCanChange: false, andCanDelete: false, andCanShare: canReshareTheShare(), andIsFolder: metadata.directory)
+ let value = permissions.getPermission(canEdit: false, canCreate: false, canChange: false, canDelete: false, canShare: canReshareTheShare(), isDirectory: metadata.directory)
self.permission = value
// self.permissions = "RDNVCK"
metadata.permissions = "RDNVCK"
@@ -551,7 +552,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
self.reloadForm()
break
case "kNMCFilePermissionCellEditing":
- let value = CCUtility.getPermissionsValue(byCanEdit: true, andCanCreate: true, andCanChange: true, andCanDelete: true, andCanShare: canReshareTheShare(), andIsFolder: metadata.directory)
+ let value = permissions.getPermission(canEdit: true, canCreate: true, canChange: true, canDelete: true, canShare: canReshareTheShare(), isDirectory: metadata.directory)
self.permission = value
// self.permissions = "RGDNV"
metadata.permissions = "RGDNV"
@@ -567,7 +568,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
self.reloadForm()
break
case "NCFilePermissionCellFileDrop":
- self.permission = NCGlobal.shared.permissionCreateShare
+ self.permission = permissions.permissionCreateShare
// self.permissions = "RGDNVCK"
metadata.permissions = "RGDNVCK"
if let row : XLFormRowDescriptor = self.form.formRow(withTag: "NCFilePermissionCellRead") {
@@ -597,7 +598,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
func canReshareTheShare() -> Bool {
if let permissionValue = self.permission {
- let canReshare = CCUtility.isPermission(toCanShare: permissionValue)
+ let canReshare = NCPermissions().isPermissionToCanShare(permissionValue)
return canReshare
} else {
return false
@@ -605,6 +606,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
+ let permissions = NCPermissions()
if let advancePermissionHeaderRow: XLFormRowDescriptor = self.form.formRow(withTag: "NCFilePermissionCellAdvanceTxt") {
if let advancePermissionHeaderRowIndexPath = form.indexPath(ofFormRow: advancePermissionHeaderRow), indexPath == advancePermissionHeaderRowIndexPath {
let cell = cell as? NCFilePermissionCell
@@ -618,7 +620,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
let cell = cell as? NCFilePermissionEditCell
// Can reshare (file)
if let permissionValue = self.permission {
- let canReshare = CCUtility.isPermission(toCanShare: permissionValue)
+ let canReshare = permissions.isPermissionToCanShare(permissionValue)
cell?.switchControl.isOn = canReshare
} else {
//new share
@@ -631,9 +633,9 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
if let hideDownloadRowIndexPath = form.indexPath(ofFormRow: hideDownloadRow), indexPath == hideDownloadRowIndexPath {
let cell = cell as? NCFilePermissionEditCell
cell?.switchControl.isOn = oldTableShare?.hideDownload ?? false
- cell?.titleLabel.isEnabled = !(self.permission == NCGlobal.shared.permissionCreateShare)
- cell?.switchControl.isEnabled = !(self.permission == NCGlobal.shared.permissionCreateShare)
- cell?.isUserInteractionEnabled = !(self.permission == NCGlobal.shared.permissionCreateShare)
+ cell?.titleLabel.isEnabled = !(self.permission == permissions.permissionCreateShare)
+ cell?.switchControl.isEnabled = !(self.permission == permissions.permissionCreateShare)
+// cell?.isUserInteractionEnabled = !(self.permission == permissions.permissionCreateShare)
}
// set password
@@ -787,8 +789,8 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
}
// EDITORS
- let editors = NCUtility().isDirectEditing(account: metadata.account, contentType: metadata.contentType)
- let availableRichDocument = NCUtility().isRichDocument(metadata)
+ let editors = NCUtility().editorsDirectEditing(account: metadata.account, contentType: metadata.contentType)
+ let availableRichDocument = NCUtility().isTypeFileRichDocument(metadata)
// RichDocument: Collabora
return (availableRichDocument && editors.count == 0)
@@ -827,31 +829,31 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
}
func canReshareValueChanged(isOn: Bool) {
-
+ let permissions = NCPermissions()
guard let oldTableShare = oldTableShare, let permission = self.permission else {
- self.permission = isOn ? (self.permission ?? 0) + NCGlobal.shared.permissionShareShare : ((self.permission ?? 0) - NCGlobal.shared.permissionShareShare)
+ self.permission = isOn ? (self.permission ?? 0) + permissions.permissionShareShare : ((self.permission ?? 0) - permissions.permissionShareShare)
return
}
- let canEdit = CCUtility.isAnyPermission(toEdit: permission)
- let canCreate = CCUtility.isPermission(toCanCreate: permission)
- let canChange = CCUtility.isPermission(toCanChange: permission)
- let canDelete = CCUtility.isPermission(toCanDelete: permission)
+ let canEdit = permissions.isAnyPermissionToEdit(permission)
+ let canCreate = permissions.isPermissionToCanCreate(permission)
+ let canChange = permissions.isPermissionToCanChange(permission)
+ let canDelete = permissions.isPermissionToCanDelete(permission)
if metadata.directory {
- self.permission = CCUtility.getPermissionsValue(byCanEdit: canEdit, andCanCreate: canCreate, andCanChange: canChange, andCanDelete: canDelete, andCanShare: isOn, andIsFolder: metadata.directory)
+ self.permission = permissions.getPermission(canEdit: canEdit, canCreate: canCreate, canChange: canChange, canDelete: canDelete, canShare: isOn, isDirectory: metadata.directory)
} else {
if isOn {
if canEdit {
- self.permission = CCUtility.getPermissionsValue(byCanEdit: true, andCanCreate: true, andCanChange: true, andCanDelete: true, andCanShare: isOn, andIsFolder: metadata.directory)
+ self.permission = permissions.getPermission(canEdit: true, canCreate: true, canChange: true, canDelete: true, canShare: isOn, isDirectory: metadata.directory)
} else {
- self.permission = CCUtility.getPermissionsValue(byCanEdit: false, andCanCreate: false, andCanChange: false, andCanDelete: false, andCanShare: isOn, andIsFolder: metadata.directory)
+ self.permission = permissions.getPermission(canEdit: false, canCreate: false, canChange: false, canDelete: false, canShare: isOn, isDirectory: metadata.directory)
}
} else {
if canEdit {
- self.permission = CCUtility.getPermissionsValue(byCanEdit: true, andCanCreate: true, andCanChange: true, andCanDelete: true, andCanShare: isOn, andIsFolder: metadata.directory)
+ self.permission = permissions.getPermission(canEdit: true, canCreate: true, canChange: true, canDelete: true, canShare: isOn, isDirectory: metadata.directory)
} else {
- self.permission = CCUtility.getPermissionsValue(byCanEdit: false, andCanCreate: false, andCanChange: false, andCanDelete: false, andCanShare: isOn, andIsFolder: metadata.directory)
+ self.permission = permissions.getPermission(canEdit: false, canCreate: false, canChange: false, canDelete: false, canShare: isOn, isDirectory: metadata.directory)
}
}
let alertController = UIAlertController.password(titleKey: "_share_password_") { password in
diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift
index 72ad498de4..8164263d9c 100644
--- a/iOSClient/Share/NCShare.swift
+++ b/iOSClient/Share/NCShare.swift
@@ -420,8 +420,8 @@ extension NCShare: NCShareNetworkingDelegate {
}
// EDITORS
- let editors = utility.isDirectEditing(account: metadata.account, contentType: metadata.contentType)
- let availableRichDocument = utility.isRichDocument(metadata)
+ let editors = utility.editorsDirectEditing(account: metadata.account, contentType: metadata.contentType)
+ let availableRichDocument = utility.isTypeFileRichDocument(metadata)
// RichDocument: Collabora
return (availableRichDocument && editors.count == 0)
@@ -576,9 +576,9 @@ extension NCShare: UITableViewDataSource {
headerView.fileName.text = metadata?.fileNameView
headerView.fileName.textColor = NCBrandColor.shared.label
if metadata!.favorite {
- headerView.favorite.setImage(utility.loadImage(named: "star.fill", color: NCBrandColor.shared.yellowFavorite, size: 24), for: .normal)
+ headerView.favorite.setImage(utility.loadImage(named: "star.fill", colors: [NCBrandColor.shared.yellowFavorite], size: 24), for: .normal)
} else {
- headerView.favorite.setImage(utility.loadImage(named: "star.fill", color: NCBrandColor.shared.textInfo, size: 24), for: .normal)
+ headerView.favorite.setImage(utility.loadImage(named: "star.fill", colors: [NCBrandColor.shared.textInfo], size: 24), for: .normal)
}
headerView.info.text = utilityFileSystem.transformedSize(metadata!.size) + ", " + utility.dateDiff(metadata!.date as Date)
return headerView
diff --git a/iOSClient/Share/NCShareCommon.swift b/iOSClient/Share/NCShareCommon.swift
index 751009293d..4f6f1c2052 100644
--- a/iOSClient/Share/NCShareCommon.swift
+++ b/iOSClient/Share/NCShareCommon.swift
@@ -119,6 +119,6 @@ enum NCShareCommon {
}
func canReshare(withPermission permission: String) -> Bool {
- return permission.contains(NCGlobal.shared.permissionCanShare)
+ return permission.contains(NCPermissions().permissionCanShare)
}
}
diff --git a/iOSClient/Share/NCShareHeader.swift b/iOSClient/Share/NCShareHeader.swift
index 42e4375b08..134cc0d017 100644
--- a/iOSClient/Share/NCShareHeader.swift
+++ b/iOSClient/Share/NCShareHeader.swift
@@ -53,9 +53,9 @@ class NCShareAdvancePermissionHeader: UIView {
fileName.text = metadata.fileNameView
fileName.textColor = NCBrandColor.shared.fileFolderName
if metadata.favorite {
- favorite.setImage(utility.loadImage(named: "star.fill", color: NCBrandColor.shared.yellowFavorite, size: 24), for: .normal)
+ favorite.setImage(utility.loadImage(named: "star.fill", colors: [NCBrandColor.shared.yellowFavorite], size: 24), for: .normal)
} else {
- favorite.setImage(utility.loadImage(named: "star.fill", color: NCBrandColor.shared.textInfo, size: 24), for: .normal)
+ favorite.setImage(utility.loadImage(named: "star.fill", colors: [NCBrandColor.shared.textInfo], size: 24), for: .normal)
}
info.textColor = NCBrandColor.shared.optionItem
info.text = utilityFileSystem.transformedSize(metadata.size) + ", " + utility.dateDiff(metadata.date as Date)
@@ -67,9 +67,9 @@ class NCShareAdvancePermissionHeader: UIView {
if error == .success {
guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(metadata.ocId) else { return }
if metadata.favorite {
- self.favorite.setImage(self.utility.loadImage(named: "star.fill", color: NCBrandColor.shared.yellowFavorite, size: 24), for: .normal)
+ self.favorite.setImage(self.utility.loadImage(named: "star.fill", colors: [NCBrandColor.shared.yellowFavorite], size: 24), for: .normal)
} else {
- self.favorite.setImage(self.utility.loadImage(named: "star.fill", color: NCBrandColor.shared.textInfo, size: 24), for: .normal)
+ self.favorite.setImage(self.utility.loadImage(named: "star.fill", colors: [NCBrandColor.shared.textInfo], size: 24), for: .normal)
}
} else {
NCContentPresenter().showError(error: error)
diff --git a/iOSClient/Share/NCShareLinkCell.swift b/iOSClient/Share/NCShareLinkCell.swift
index e97dea80cf..3600ed4a99 100644
--- a/iOSClient/Share/NCShareLinkCell.swift
+++ b/iOSClient/Share/NCShareLinkCell.swift
@@ -128,25 +128,26 @@ class NCShareLinkCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
-
+ buttonMenu.contentMode = .scaleAspectFill
imageItem.image = UIImage(named: "sharebylink")?.image(color: NCBrandColor.shared.label, size: 30)
buttonCopy.setImage(UIImage.init(named: "shareCopy")!.image(color: NCBrandColor.shared.customer, size: 24), for: .normal)
- buttonMenu.setImage(UIImage.init(named: "shareMenu")!.image(color: NCBrandColor.shared.customer, size: 24), for: .normal)
+ buttonMenu.setImage(NCImageCache.images.buttonMore.image(color: NCBrandColor.shared.customer, size: 24), for: .normal)
labelQuickStatus.textColor = NCBrandColor.shared.customer
}
func setupCellUI() {
+ let permissions = NCPermissions()
guard let tableShare = tableShare else {
return
}
contentView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
labelTitle.textColor = NCBrandColor.shared.label
- if tableShare.permissions == NCGlobal.shared.permissionCreateShare {
+ if tableShare.permissions == permissions.permissionCreateShare {
labelQuickStatus.text = NSLocalizedString("_share_file_drop_", comment: "")
} else {
// Read Only
- if CCUtility.isAnyPermission(toEdit: tableShare.permissions) {
+ if permissions.isAnyPermissionToEdit(tableShare.permissions) {
labelQuickStatus.text = NSLocalizedString("_share_editing_", comment: "")
} else {
labelQuickStatus.text = NSLocalizedString("_share_read_only_", comment: "")
diff --git a/iOSClient/Share/NCSharePaging.swift b/iOSClient/Share/NCSharePaging.swift
index c069e405ce..6fa56b56f6 100644
--- a/iOSClient/Share/NCSharePaging.swift
+++ b/iOSClient/Share/NCSharePaging.swift
@@ -307,7 +307,7 @@ class NCShareHeaderView: UIView {
}
var canReshare: Bool {
guard let metadata = metadata else { return true }
- return ((metadata.sharePermissionsCollaborationServices & NCGlobal.shared.permissionShareShare) != 0)
+ return ((metadata.sharePermissionsCollaborationServices & NCPermissions().permissionShareShare) != 0)
}
canShareInfoView.isHidden = isCurrentUser
labelSharingInfo.isHidden = !isCurrentUser
@@ -328,9 +328,9 @@ class NCShareHeaderView: UIView {
if error == .success {
guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(metadata.ocId) else { return }
if metadata.favorite {
- self.favorite.setImage(self.utility.loadImage(named: "star.fill", color: NCBrandColor.shared.yellowFavorite, size: 24), for: .normal)
+ self.favorite.setImage(self.utility.loadImage(named: "star.fill", colors: [NCBrandColor.shared.yellowFavorite], size: 24), for: .normal)
} else {
- self.favorite.setImage(self.utility.loadImage(named: "star.fill", color: NCBrandColor.shared.textInfo, size: 24), for: .normal)
+ self.favorite.setImage(self.utility.loadImage(named: "star.fill", colors: [NCBrandColor.shared.textInfo], size: 24), for: .normal)
}
} else {
NCContentPresenter().showError(error: error)
diff --git a/iOSClient/Share/NCShareUserCell.swift b/iOSClient/Share/NCShareUserCell.swift
index 5912522ca1..f0d9f4e168 100644
--- a/iOSClient/Share/NCShareUserCell.swift
+++ b/iOSClient/Share/NCShareUserCell.swift
@@ -70,7 +70,7 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol {
labelTitle.lineBreakMode = .byTruncatingMiddle
labelTitle.textColor = NCBrandColor.shared.textColor
contentView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
-
+ let permissions = NCPermissions()
labelTitle.text = tableShare.shareWithDisplayname
labelTitle.textColor = NCBrandColor.shared.label
isUserInteractionEnabled = true
@@ -81,10 +81,10 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol {
imageItem.image = NCShareCommon.getImageShareType(shareType: tableShare.shareType)
let status = utility.getUserStatus(userIcon: tableShare.userIcon, userStatus: tableShare.userStatus, userMessage: tableShare.userMessage)
- imageStatus.image = status.onlineStatus
+ imageStatus.image = status.statusImage
self.status.text = status.statusMessage
- if CCUtility.isAnyPermission(toEdit: tableShare.permissions) {
+ if permissions.isAnyPermissionToEdit(tableShare.permissions) {
switchCanEdit.setOn(true, animated: false)
} else {
switchCanEdit.setOn(false, animated: false)
@@ -143,11 +143,11 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol {
default:
return ""
}
- if tableShare.permissions == NCGlobal.shared.permissionCreateShare {
+ if tableShare.permissions == permissions.permissionCreateShare {
labelQuickStatus.text = NSLocalizedString("_share_file_drop_", comment: "")
} else {
// Read Only
- if CCUtility.isAnyPermission(toEdit: tableShare.permissions) {
+ if permissions.isAnyPermissionToEdit(tableShare.permissions) {
labelQuickStatus.text = NSLocalizedString("_share_editing_", comment: "")
} else {
labelQuickStatus.text = NSLocalizedString("_share_read_only_", comment: "")
@@ -160,6 +160,8 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapAvatarImage(_:)))
imageItem?.addGestureRecognizer(tapGesture)
buttonMenu.setImage(UIImage.init(named: "shareMenu")!.image(color: NCBrandColor.shared.customer, size: 24), for: .normal)
+ buttonMenu.contentMode = .scaleAspectFill
+// buttonMenu.setImage(NCImageCache.images.buttonMore.image(color: NCBrandColor.shared.customer, size: 24), for: .normal)
labelQuickStatus.textColor = NCBrandColor.shared.customer
imageDownArrow.image = UIImage(named: "downArrow")?.imageColor(NCBrandColor.shared.customer)
switchCanEdit.transform = CGAffineTransform(scaleX: 0.75, y: 0.75)
@@ -217,7 +219,7 @@ class NCSearchUserDropDownCell: DropDownCell, NCCellProtocol {
// imageShareeType.image = NCShareCommon.getImageShareType(shareType: sharee.shareType)
imageShareeType.image = NCShareCommon().getImageShareType(shareType: sharee.shareType, isDropDown: true)
let status = utility.getUserStatus(userIcon: sharee.userIcon, userStatus: sharee.userStatus, userMessage: sharee.userMessage)
- imageStatus.image = status.onlineStatus
+ imageStatus.image = status.statusImage
self.status.text = status.statusMessage
if self.status.text?.count ?? 0 > 0 {
centerTitle.constant = -5
From 254fa9fdd69276634b32ae377a48e844390ec101 Mon Sep 17 00:00:00 2001
From: TSI-amrutwaghmare <96108296+TSI-amrutwaghmare@users.noreply.github.com>
Date: Mon, 27 Nov 2023 17:19:30 +0530
Subject: [PATCH 3/6] NMC 1997 - Sharing customisation
unused changes
---
iOSClient/Share/NCShare.swift | 38 +++++++++++++++++++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift
index 8164263d9c..af658c711d 100644
--- a/iOSClient/Share/NCShare.swift
+++ b/iOSClient/Share/NCShare.swift
@@ -213,6 +213,44 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
textField?.layer.borderColor = NCBrandColor.shared.brand.cgColor
}
+ @objc func keyboardWillHide(notification: Notification) {
+ if view.frame.origin.y != 0 {
+ self.view.frame.origin.y = 0
+ }
+ textField?.layer.borderColor = NCBrandColor.shared.label.cgColor
+ }
+
+ @objc func keyboardWillShow(notification: Notification) {
+ if UIDevice.current.userInterfaceIdiom == .phone {
+ if (UIScreen.main.bounds.width < 374 || UIDevice.current.orientation.isLandscape) {
+ if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
+ if view.frame.origin.y == 0 {
+ self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
+ self.view.frame.origin.y -= keyboardSize.height
+ }
+ }
+ } else if UIScreen.main.bounds.height < 850 {
+ if view.frame.origin.y == 0 {
+ self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
+ self.view.frame.origin.y -= 70
+ }
+ } else {
+ if view.frame.origin.y == 0 {
+ self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
+ self.view.frame.origin.y -= 40
+ }
+ }
+ }
+
+ if UIDevice.current.userInterfaceIdiom == .pad, UIDevice.current.orientation.isLandscape {
+ if view.frame.origin.y == 0 {
+ self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
+ self.view.frame.origin.y -= 230
+ }
+ }
+ textField?.layer.borderColor = NCBrandColor.shared.brand.cgColor
+ }
+
@objc func keyboardWillHide(notification: Notification) {
if view.frame.origin.y != 0 {
self.view.frame.origin.y = 0
From 999fda2bc5fa0c24ab9d6b51a6f42888849c74e6 Mon Sep 17 00:00:00 2001
From: harshada-15-tsys
Date: Tue, 15 Apr 2025 16:09:15 +0530
Subject: [PATCH 4/6] NMC 1997 - Sharing customisation changes
---
Nextcloud.xcodeproj/project.pbxproj | 69 ++++++++++++++-
iOSClient/Activity/NCActivity.swift | 9 +-
iOSClient/Share/NCShare+Helper.swift | 1 +
iOSClient/Share/NCShare.swift | 113 +++++++++++-------------
iOSClient/Share/NCShareCommon.swift | 2 +-
iOSClient/Share/NCShareHeader.swift | 6 +-
iOSClient/Share/NCShareLinkCell.swift | 2 +-
iOSClient/Share/NCShareNetworking.swift | 14 ++-
iOSClient/Share/NCShareUserCell.swift | 1 -
iOSClient/Utility/NCUtility.swift | 30 ++++++-
10 files changed, 169 insertions(+), 78 deletions(-)
diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj
index 8dd4c5545f..af31c937a7 100644
--- a/Nextcloud.xcodeproj/project.pbxproj
+++ b/Nextcloud.xcodeproj/project.pbxproj
@@ -85,6 +85,24 @@
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 */; };
+ B5E2E6D42DAE52B500AB2EDD /* SharingTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E2E6D32DAE52B500AB2EDD /* SharingTest.swift */; };
+ B5E2E6D72DAE571200AB2EDD /* PasswordInputField.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5E2E6D62DAE571200AB2EDD /* PasswordInputField.xib */; };
+ B5E2E6D82DAE571200AB2EDD /* PasswordInputField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E2E6D52DAE571200AB2EDD /* PasswordInputField.swift */; };
+ B5E2E6DD2DAE573B00AB2EDD /* NCFilePermissionEditCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5E2E6DC2DAE573B00AB2EDD /* NCFilePermissionEditCell.xib */; };
+ B5E2E6DE2DAE573B00AB2EDD /* NCFilePermissionCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5E2E6DA2DAE573B00AB2EDD /* NCFilePermissionCell.xib */; };
+ B5E2E6DF2DAE573B00AB2EDD /* NCFilePermissionCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E2E6D92DAE573B00AB2EDD /* NCFilePermissionCell.swift */; };
+ B5E2E6E02DAE573B00AB2EDD /* NCFilePermissionEditCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E2E6DB2DAE573B00AB2EDD /* NCFilePermissionEditCell.swift */; };
+ B5E2E6E22DAE59CD00AB2EDD /* NCShareAdvancePermissionHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5E2E6E12DAE59CD00AB2EDD /* NCShareAdvancePermissionHeader.xib */; };
+ B5E2E6E72DAE59F000AB2EDD /* NCShareHeaderCustomCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5E2E6E42DAE59F000AB2EDD /* NCShareHeaderCustomCell.xib */; };
+ B5E2E6E82DAE59F000AB2EDD /* NCShareTextInputCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5E2E6E62DAE59F000AB2EDD /* NCShareTextInputCell.xib */; };
+ B5E2E6E92DAE59F000AB2EDD /* NCShareTextInputCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E2E6E52DAE59F000AB2EDD /* NCShareTextInputCell.swift */; };
+ B5E2E6EA2DAE59F000AB2EDD /* NCShareHeaderCustomCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E2E6E32DAE59F000AB2EDD /* NCShareHeaderCustomCell.swift */; };
+ B5E2E6ED2DAE66AF00AB2EDD /* NCShareEmailFieldCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5E2E6EC2DAE66AF00AB2EDD /* NCShareEmailFieldCell.xib */; };
+ B5E2E6EE2DAE66AF00AB2EDD /* NCShareEmailFieldCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E2E6EB2DAE66AF00AB2EDD /* NCShareEmailFieldCell.swift */; };
+ B5E2E6F02DAE6E3F00AB2EDD /* ShareDownloadLimitNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E2E6EF2DAE6E3F00AB2EDD /* ShareDownloadLimitNetwork.swift */; };
+ 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 */; };
F321DA8A2B71205A00DDA0E6 /* NCTrashSelectTabBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = F321DA892B71205A00DDA0E6 /* NCTrashSelectTabBar.swift */; };
@@ -1220,7 +1238,22 @@
AFCE353227E4ED1900FEA6C2 /* UIToolbar+Extension.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIToolbar+Extension.swift"; sourceTree = ""; };
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 = ""; };
+ B5E2E6D32DAE52B500AB2EDD /* SharingTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingTest.swift; sourceTree = ""; };
+ B5E2E6D52DAE571200AB2EDD /* PasswordInputField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordInputField.swift; sourceTree = ""; };
+ B5E2E6D62DAE571200AB2EDD /* PasswordInputField.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PasswordInputField.xib; sourceTree = ""; };
+ B5E2E6D92DAE573B00AB2EDD /* NCFilePermissionCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCFilePermissionCell.swift; sourceTree = ""; };
+ B5E2E6DA2DAE573B00AB2EDD /* NCFilePermissionCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCFilePermissionCell.xib; sourceTree = ""; };
+ B5E2E6DB2DAE573B00AB2EDD /* NCFilePermissionEditCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCFilePermissionEditCell.swift; sourceTree = ""; };
+ B5E2E6DC2DAE573B00AB2EDD /* NCFilePermissionEditCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCFilePermissionEditCell.xib; sourceTree = ""; };
+ B5E2E6E12DAE59CD00AB2EDD /* NCShareAdvancePermissionHeader.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCShareAdvancePermissionHeader.xib; sourceTree = ""; };
+ B5E2E6E32DAE59F000AB2EDD /* NCShareHeaderCustomCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareHeaderCustomCell.swift; sourceTree = ""; };
+ B5E2E6E42DAE59F000AB2EDD /* NCShareHeaderCustomCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCShareHeaderCustomCell.xib; sourceTree = ""; };
+ B5E2E6E52DAE59F000AB2EDD /* NCShareTextInputCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareTextInputCell.swift; sourceTree = ""; };
+ B5E2E6E62DAE59F000AB2EDD /* NCShareTextInputCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCShareTextInputCell.xib; sourceTree = ""; };
+ B5E2E6EB2DAE66AF00AB2EDD /* NCShareEmailFieldCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareEmailFieldCell.swift; sourceTree = ""; };
+ B5E2E6EC2DAE66AF00AB2EDD /* NCShareEmailFieldCell.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = NCShareEmailFieldCell.xib; sourceTree = ""; };
+ B5E2E6EF2DAE6E3F00AB2EDD /* ShareDownloadLimitNetwork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShareDownloadLimitNetwork.swift; 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 = ""; };
@@ -2024,6 +2057,8 @@
isa = PBXGroup;
children = (
AA52EB452D42AC5A0089C348 /* Placeholder.swift */,
+ B5E2E6D32DAE52B500AB2EDD /* SharingTest.swift */,
+ AF8ED1FB2757821000B8DBC4 /* NextcloudUnitTests.swift */,
);
path = NextcloudUnitTests;
sourceTree = "";
@@ -2051,6 +2086,15 @@
isa = PBXGroup;
children = (
AA8D316D2D4123B200FE2775 /* DownloadLimit */,
+ B5E2E6E32DAE59F000AB2EDD /* NCShareHeaderCustomCell.swift */,
+ B5E2E6E42DAE59F000AB2EDD /* NCShareHeaderCustomCell.xib */,
+ B5E2E6E52DAE59F000AB2EDD /* NCShareTextInputCell.swift */,
+ B5E2E6E62DAE59F000AB2EDD /* NCShareTextInputCell.xib */,
+ B5E2E6E12DAE59CD00AB2EDD /* NCShareAdvancePermissionHeader.xib */,
+ B5E2E6D92DAE573B00AB2EDD /* NCFilePermissionCell.swift */,
+ B5E2E6DA2DAE573B00AB2EDD /* NCFilePermissionCell.xib */,
+ B5E2E6DB2DAE573B00AB2EDD /* NCFilePermissionEditCell.swift */,
+ B5E2E6DC2DAE573B00AB2EDD /* NCFilePermissionEditCell.xib */,
AF93471627E2361E002537EE /* NCShareAdvancePermission.swift */,
AF93471827E2361E002537EE /* NCShareAdvancePermissionFooter.swift */,
AF93471427E2361E002537EE /* NCShareAdvancePermissionFooter.xib */,
@@ -2301,6 +2345,9 @@
F728CE741BF6322C00E69702 /* Share */ = {
isa = PBXGroup;
children = (
+ B5E2E6EF2DAE6E3F00AB2EDD /* ShareDownloadLimitNetwork.swift */,
+ B5E2E6EB2DAE66AF00AB2EDD /* NCShareEmailFieldCell.swift */,
+ B5E2E6EC2DAE66AF00AB2EDD /* NCShareEmailFieldCell.xib */,
AF93471327E235EB002537EE /* Advanced */,
F724377A2C10B83E00C7C68D /* NCSharePermissions.swift */,
F3F442ED2DDE292600FD701F /* NCMetadataPermissions.swift */,
@@ -2426,6 +2473,8 @@
F758B41E212C516300515F55 /* Scan document */ = {
isa = PBXGroup;
children = (
+ B5E2E6D52DAE571200AB2EDD /* PasswordInputField.swift */,
+ B5E2E6D62DAE571200AB2EDD /* PasswordInputField.xib */,
F758B457212C564000515F55 /* NCScan.storyboard */,
F758B45D212C569C00515F55 /* NCScanCell.swift */,
F758B45F212C56A400515F55 /* NCScan.swift */,
@@ -3930,9 +3979,14 @@
F758B45A212C564000515F55 /* NCScan.storyboard in Resources */,
F765F73225237E3F00391DBE /* NCRecent.storyboard in Resources */,
F78F74342163757000C2ADAD /* NCTrash.storyboard in Resources */,
+ B5E2E6E72DAE59F000AB2EDD /* NCShareHeaderCustomCell.xib in Resources */,
+ B5E2E6E82DAE59F000AB2EDD /* NCShareTextInputCell.xib in Resources */,
F702F30225EE5D2C008F8E80 /* english.txt in Resources */,
F757CC8C29E82D0500F31428 /* NCGroupfolders.storyboard in Resources */,
F79A65C32191D90F00FF6DCC /* NCSelect.storyboard in Resources */,
+ B5E2E6DD2DAE573B00AB2EDD /* NCFilePermissionEditCell.xib in Resources */,
+ B5E2E6ED2DAE66AF00AB2EDD /* NCShareEmailFieldCell.xib in Resources */,
+ B5E2E6DE2DAE573B00AB2EDD /* NCFilePermissionCell.xib in Resources */,
F7226EDC1EE4089300EBECB1 /* Main.storyboard in Resources */,
AF56C1DC2784856200D8BAE2 /* NCActivityCommentView.xib in Resources */,
F7F4F10B27ECDBDB008676F9 /* Inconsolata-Light.ttf in Resources */,
@@ -3953,9 +4007,11 @@
F723B3DD22FC6D1D00301EFE /* NCShareCommentsCell.xib in Resources */,
F78ACD4B21903F850088454D /* NCTrashListCell.xib in Resources */,
AF93471927E2361E002537EE /* NCShareAdvancePermissionFooter.xib in Resources */,
+ B5E2E6E22DAE59CD00AB2EDD /* NCShareAdvancePermissionHeader.xib in Resources */,
F7725A61251F33BB00D125E0 /* NCFiles.storyboard in Resources */,
F7CBC1232BAC8B0000EC1D55 /* NCSectionFirstHeaderEmptyData.xib in Resources */,
F700510122DF63AC003A3356 /* NCShare.storyboard in Resources */,
+ B5E2E6D72DAE571200AB2EDD /* PasswordInputField.xib in Resources */,
F787704F22E7019900F287A9 /* NCShareLinkCell.xib in Resources */,
F70753F72542A9C000972D44 /* NCViewerMediaPage.storyboard in Resources */,
F7F4F10627ECDBDB008676F9 /* Inconsolata-Medium.ttf in Resources */,
@@ -4084,6 +4140,8 @@
AA52EB472D42AC9E0089C348 /* Placeholder.swift in Sources */,
F372087D2BAB4C0F006B5430 /* TestConstants.swift in Sources */,
F78E2D6C29AF02DB0024D4F3 /* Database.swift in Sources */,
+ B5E2E6D42DAE52B500AB2EDD /* SharingTest.swift in Sources */,
+ F7817CFE29801A3500FFBC65 /* Data+Extension.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -4402,12 +4460,17 @@
370D26AF248A3D7A00121797 /* NCCellProtocol.swift in Sources */,
F32FADA92D1176E3007035E2 /* UIButton+Extension.swift in Sources */,
F768822C2C0DD1E7001CF441 /* NCPreferences.swift in Sources */,
+ F768822C2C0DD1E7001CF441 /* NCKeychain.swift in Sources */,
+ B5E2E6EE2DAE66AF00AB2EDD /* NCShareEmailFieldCell.swift in Sources */,
+ F7BFFD282C8846020029A201 /* NCHud.swift in Sources */,
F71CD6CA2930D7B1006C95C1 /* NCApplicationHandle.swift in Sources */,
F3754A7D2CF87D600009312E /* SetupPasscodeView.swift in Sources */,
F73EF7D72B0226080087E6E9 /* NCManageDatabase+Tip.swift in Sources */,
F3374A842D64AC31002A38F9 /* AssistantLabelStyle.swift in Sources */,
F74BAE172C7E2F4E0028D4FA /* FileProviderDomain.swift in Sources */,
F76882402C0DD30B001CF441 /* ViewOnAppear.swift in Sources */,
+ B5E2E6E92DAE59F000AB2EDD /* NCShareTextInputCell.swift in Sources */,
+ B5E2E6EA2DAE59F000AB2EDD /* NCShareHeaderCustomCell.swift in Sources */,
F790110E21415BF600D7B136 /* NCViewerRichDocument.swift in Sources */,
F78ACD4021903CC20088454D /* NCGridCell.swift in Sources */,
F7D890752BD25C570050B8A6 /* NCCollectionViewCommon+DragDrop.swift in Sources */,
@@ -4548,6 +4611,7 @@
F73EF7BF2B02250B0087E6E9 /* NCManageDatabase+GPS.swift in Sources */,
F39A1EE22D0AF8A400DAD522 /* Albums.swift in Sources */,
F71F6D072B6A6A5E00F1EB15 /* ThreadSafeArray.swift in Sources */,
+ B5E2E6D82DAE571200AB2EDD /* PasswordInputField.swift in Sources */,
F761856C29E98543006EB3B0 /* NCIntroCollectionViewCell.swift in Sources */,
F75DD765290ABB25002EB562 /* Intent.intentdefinition in Sources */,
F7D4BF012CA1831900A5E746 /* NCCollectionViewCommonPinchGesture.swift in Sources */,
@@ -4607,6 +4671,7 @@
AF93474E27E3F212002537EE /* NCShareNewUserAddComment.swift in Sources */,
F7C30DFD291BD0B80017149B /* NCNetworkingE2EEDelete.swift in Sources */,
F77E8C232E79717D00EAE68F /* NCManageDatabase+LivePhoto.swift in Sources */,
+ B5E2E6F02DAE6E3F00AB2EDD /* ShareDownloadLimitNetwork.swift in Sources */,
F76882302C0DD1E7001CF441 /* NCFileNameModel.swift in Sources */,
F7CF06882E1127460063AD04 /* NCManageDatabase+CreateMetadata.swift in Sources */,
F72FD3B5297ED49A00075D28 /* NCManageDatabase+E2EE.swift in Sources */,
@@ -4637,6 +4702,8 @@
AF93471B27E2361E002537EE /* NCShareAdvancePermission.swift in Sources */,
F77BC3ED293E528A005F2B08 /* NCConfigServer.swift in Sources */,
F7A560422AE1593700BE8FD6 /* NCOperationSaveLivePhoto.swift in Sources */,
+ B5E2E6DF2DAE573B00AB2EDD /* NCFilePermissionCell.swift in Sources */,
+ B5E2E6E02DAE573B00AB2EDD /* NCFilePermissionEditCell.swift in Sources */,
F7D1C4AC2C9484FD00EC6D44 /* NCMedia+CollectionViewDataSourcePrefetching.swift in Sources */,
F7D368DF2DAFE19E0037E7C6 /* NCActivityNavigationController.swift in Sources */,
F7A03E332D426115007AA677 /* NCMoreNavigationController.swift in Sources */,
diff --git a/iOSClient/Activity/NCActivity.swift b/iOSClient/Activity/NCActivity.swift
index 4fda986171..f7b6d19b6c 100644
--- a/iOSClient/Activity/NCActivity.swift
+++ b/iOSClient/Activity/NCActivity.swift
@@ -35,6 +35,7 @@ class NCActivity: UIViewController, NCSharePagingContent {
}
}
var dateAutomaticFetch: Date?
+ private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
@MainActor
var session: NCSession.Session {
@@ -96,6 +97,8 @@ class NCActivity: UIViewController, NCSharePagingContent {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
+ appDelegate.activeViewController = self
+ navigationController?.setNavigationBarAppearance()
fetchAll(isInitial: true)
}
@@ -126,14 +129,10 @@ class NCActivity: UIViewController, NCSharePagingContent {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 15)
- label.textColor = NCBrandColor.shared.textColor2
+ label.textColor = UIColor.systemGray
label.textAlignment = .center
label.text = NSLocalizedString("_no_activity_footer_", comment: "")
view.addSubview(label)
- label.translatesAutoresizingMaskIntoConstraints = false
- label.topAnchor.constraint(equalTo: view.topAnchor, constant: 20).isActive = true
- label.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
- label.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
return view
}
diff --git a/iOSClient/Share/NCShare+Helper.swift b/iOSClient/Share/NCShare+Helper.swift
index b08bfa9358..6f98012b78 100644
--- a/iOSClient/Share/NCShare+Helper.swift
+++ b/iOSClient/Share/NCShare+Helper.swift
@@ -92,6 +92,7 @@ class NCTableShareOptions: NCTableShareable {
convenience init(sharee: NKSharee, metadata: tableMetadata, password: String?) {
self.init(shareType: sharee.shareType, metadata: metadata, password: password)
self.shareWith = sharee.shareWith
+ self.shareWithDisplayname = sharee.label
}
static func shareLink(metadata: tableMetadata, password: String?) -> NCTableShareOptions {
diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift
index af658c711d..30cdedb88d 100644
--- a/iOSClient/Share/NCShare.swift
+++ b/iOSClient/Share/NCShare.swift
@@ -181,43 +181,10 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
@objc func openShareProfile(_ sender: UITapGestureRecognizer) {
self.showProfileMenu(userId: metadata.ownerId, session: session, sender: sender.view)
}
-
- @objc func keyboardWillShow(notification: Notification) {
- if UIDevice.current.userInterfaceIdiom == .phone {
- if (UIScreen.main.bounds.width < 374 || UIDevice.current.orientation.isLandscape) {
- if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
- if view.frame.origin.y == 0 {
- self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
- self.view.frame.origin.y -= keyboardSize.height
- }
- }
- } else if UIScreen.main.bounds.height < 850 {
- if view.frame.origin.y == 0 {
- self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
- self.view.frame.origin.y -= 70
- }
- } else {
- if view.frame.origin.y == 0 {
- self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
- self.view.frame.origin.y -= 40
- }
- }
- }
-
- if UIDevice.current.userInterfaceIdiom == .pad, UIDevice.current.orientation.isLandscape {
- if view.frame.origin.y == 0 {
- self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
- self.view.frame.origin.y -= 230
- }
- }
- textField?.layer.borderColor = NCBrandColor.shared.brand.cgColor
- }
-
- @objc func keyboardWillHide(notification: Notification) {
- if view.frame.origin.y != 0 {
- self.view.frame.origin.y = 0
- }
- textField?.layer.borderColor = NCBrandColor.shared.label.cgColor
+
+ @objc func openShareProfile() {
+ guard let metadata = metadata else { return }
+ self.showProfileMenu(userId: metadata.ownerId, session: session)
}
@objc func keyboardWillShow(notification: Notification) {
@@ -266,6 +233,9 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
@objc func reloadData() {
shares = self.database.getTableShares(metadata: metadata)
shareLinksCount = 0
+// if let metadata = metadata {
+// shares = self.database.getTableShares(metadata: metadata)
+// }
tableView.reloadData()
}
@@ -278,12 +248,27 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
}
@IBAction func searchFieldDidChange(textField: UITextField) {
+ NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(searchSharees), object: nil)
guard let searchString = textField.text else {return}
if searchString.count == 0 {
dropDown.hide()
} else {
- networking?.getSharees(searchString: searchString)
+// networking?.getSharees(searchString: searchString)
+ perform(#selector(searchSharees), with: nil, afterDelay: 0.5)
+ }
+ }
+
+ @objc private func searchSharees() {
+ // https://stackoverflow.com/questions/25471114/how-to-validate-an-e-mail-address-in-swift
+ func isValidEmail(_ email: String) -> Bool {
+
+ let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
+ let emailPred = NSPredicate(format: "SELF MATCHES %@", emailRegEx)
+ return emailPred.evaluate(with: email)
}
+ guard let searchString = textField?.text, !searchString.isEmpty else { return }
+ if searchString.contains("@"), !isValidEmail(searchString) { return }
+ networking?.getSharees(searchString: searchString)
}
@IBAction func createLinkClicked(_ sender: Any) {
@@ -295,7 +280,7 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
@IBAction func touchUpInsideButtonMenu(_ sender: Any) {
guard let metadata = metadata else { return }
- let isFilesSharingPublicPasswordEnforced = NCGlobal.shared.capabilityFileSharingPubPasswdEnforced
+ let isFilesSharingPublicPasswordEnforced = NCCapabilities.Capabilities().capabilityFileSharingPubPasswdEnforced
let shares = NCManageDatabase.shared.getTableShares(metadata: metadata)
if isFilesSharingPublicPasswordEnforced && shares.firstShareLink == nil {
@@ -546,19 +531,24 @@ extension NCShare: UITableViewDataSource {
cell.indexPath = indexPath
cell.tableShare = tableShare
cell.delegate = self
- cell.setupCellUI(titleAppendString: String(shareLinksCount))
- if tableShare.shareType == NKShare.ShareType.publicLink.rawValue { shareLinksCount += 1 }
- return cell
- }
- } else {
- // USER / GROUP etc.
- if let cell = tableView.dequeueReusableCell(withIdentifier: "cellUser", for: indexPath) as? NCShareUserCell {
- cell.indexPath = indexPath
- cell.tableShare = tableShare
- cell.isDirectory = metadata.directory
- cell.delegate = self
- cell.setupCellUI(userId: session.userId, session: session, metadata: metadata)
-
+ cell.setupCellUI()
+ if !tableShare.label.isEmpty {
+ cell.labelTitle.text = String(format: NSLocalizedString("_share_linklabel_", comment: ""), tableShare.label)
+ } else {
+ cell.labelTitle.text = directory ? NSLocalizedString("_share_link_folder_", comment: "") : NSLocalizedString("_share_link_file_", comment: "")
+ }
+// cell.setupCellUI(userId: session.userId)
+ let isEditingAllowed = shareCommon.isEditingEnabled(isDirectory: directory, fileExtension: metadata?.fileExtension ?? "", shareType: tableShare.shareType)
+ if isEditingAllowed || directory || checkIsCollaboraFile() {
+ cell.btnQuickStatus.isEnabled = true
+ cell.labelQuickStatus.textColor = NCBrandColor.shared.brand
+ cell.imageDownArrow.image = UIImage(named: "downArrow")?.imageColor(NCBrandColor.shared.brand)
+ } else {
+ cell.btnQuickStatus.isEnabled = false
+ cell.labelQuickStatus.textColor = NCBrandColor.shared.optionItem
+ cell.imageDownArrow.image = UIImage(named: "downArrow")?.imageColor(NCBrandColor.shared.optionItem)
+ }
+
return cell
} else {
// USER / GROUP etc.
@@ -596,18 +586,23 @@ extension NCShare: UITableViewDataSource {
headerView.updateCanReshareUI()
- if FileManager.default.fileExists(atPath: utilityFileSystem.getDirectoryProviderStorageIconOcId(metadata?.ocId ?? "", etag: metadata?.etag ?? "")) {
- headerView.fullWidthImageView.image = UIImage(contentsOfFile: utilityFileSystem.getDirectoryProviderStorageIconOcId(metadata?.ocId ?? "", etag: metadata?.etag ?? ""))
+ if let image = NCUtility().getImage(ocId: metadata.ocId, etag: metadata.etag, ext: NCGlobal.shared.previewExt1024) {
+ headerView.fullWidthImageView.image = image
+// headerView.fullWidthImageView.image = UIImage(contentsOfFile: utilityFileSystem.getDirectoryProviderStorageIconOcId(metadata?.ocId ?? "", etag: metadata?.etag ?? ""))
headerView.fullWidthImageView.contentMode = .scaleAspectFill
headerView.imageView.isHidden = true
} else {
if metadata?.directory ?? false {
- let image = (metadata?.e2eEncrypted ?? false) ? UIImage(named: "folderEncrypted") : UIImage(named: "folder_nmcloud")
+ let image = (metadata?.e2eEncrypted ?? false) ? NCImageCache.shared.getFolderEncrypted() : NCImageCache.shared.getFolder()
headerView.imageView.image = image
} else if !(metadata?.iconName.isEmpty ?? false) {
- headerView.imageView.image = metadata!.fileExtension == "odg" ? UIImage(named: "file-diagram") : UIImage.init(named: metadata!.iconName)
+ if let image = UIImage.init(named: metadata!.iconName) {
+ headerView.imageView.image = metadata!.fileExtension == "odg" ? UIImage(named: "diagram") : image
+ } else {
+ headerView.imageView.image = metadata!.fileExtension == "odg" ? UIImage(named: "diagram") : NCUtility().loadImage(named: metadata.iconName, useTypeIconFile: true, account: metadata.account)
+ }
} else {
- headerView.imageView.image = UIImage(named: "file")
+ headerView.imageView.image = NCImageCache.shared.getImageFile()
}
}
@@ -623,10 +618,10 @@ extension NCShare: UITableViewDataSource {
}
func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
- return metadata?.ownerId != appDelegate?.userId ? canReshare ? 400 : 350 : 320
+ return metadata?.ownerId != session?.userId ? canReshare ? 400 : 350 : 320
}
func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
- return metadata?.ownerId != appDelegate?.userId ? canReshare ? UITableView.automaticDimension : 350 : 320
+ return metadata?.ownerId != session?.userId ? canReshare ? UITableView.automaticDimension : 350 : 320
}
}
diff --git a/iOSClient/Share/NCShareCommon.swift b/iOSClient/Share/NCShareCommon.swift
index 4f6f1c2052..702ad9b592 100644
--- a/iOSClient/Share/NCShareCommon.swift
+++ b/iOSClient/Share/NCShareCommon.swift
@@ -112,7 +112,7 @@ enum NCShareCommon {
}
func isCurrentUserIsFileOwner(fileOwnerId: String) -> Bool {
- if let currentUser = NCManageDatabase.shared.getActiveAccount(), currentUser.userId == fileOwnerId {
+ if let currentUser = NCManageDatabase.shared.getActiveTableAccount(), currentUser.userId == fileOwnerId {
return true
}
return false
diff --git a/iOSClient/Share/NCShareHeader.swift b/iOSClient/Share/NCShareHeader.swift
index 134cc0d017..4556a74516 100644
--- a/iOSClient/Share/NCShareHeader.swift
+++ b/iOSClient/Share/NCShareHeader.swift
@@ -41,11 +41,11 @@ class NCShareAdvancePermissionHeader: UIView {
imageView.isHidden = true
} else {
if metadata.directory {
- imageView.image = UIImage.init(named: "folder")
+ imageView.image = metadata.e2eEncrypted ? NCImageCache.shared.getFolderEncrypted() : NCImageCache.shared.getFolder()
} else if !metadata.iconName.isEmpty {
- imageView.image = UIImage.init(named: metadata.iconName)
+ imageView.image = NCUtility().loadImage(named: metadata.iconName, useTypeIconFile: true, account: metadata.account)
} else {
- imageView.image = UIImage.init(named: "file")
+ imageView.image = NCImageCache.shared.getImageFile()
}
}
favorite.setNeedsUpdateConstraints()
diff --git a/iOSClient/Share/NCShareLinkCell.swift b/iOSClient/Share/NCShareLinkCell.swift
index 3600ed4a99..989d28ae47 100644
--- a/iOSClient/Share/NCShareLinkCell.swift
+++ b/iOSClient/Share/NCShareLinkCell.swift
@@ -131,7 +131,7 @@ class NCShareLinkCell: UITableViewCell {
buttonMenu.contentMode = .scaleAspectFill
imageItem.image = UIImage(named: "sharebylink")?.image(color: NCBrandColor.shared.label, size: 30)
buttonCopy.setImage(UIImage.init(named: "shareCopy")!.image(color: NCBrandColor.shared.customer, size: 24), for: .normal)
- buttonMenu.setImage(NCImageCache.images.buttonMore.image(color: NCBrandColor.shared.customer, size: 24), for: .normal)
+ buttonMenu.setImage(UIImage.init(named: "shareMenu")!.image(color: NCBrandColor.shared.customer, size: 24), for: .normal)
labelQuickStatus.textColor = NCBrandColor.shared.customer
}
diff --git a/iOSClient/Share/NCShareNetworking.swift b/iOSClient/Share/NCShareNetworking.swift
index 998efae846..19eee06f2b 100644
--- a/iOSClient/Share/NCShareNetworking.swift
+++ b/iOSClient/Share/NCShareNetworking.swift
@@ -116,12 +116,15 @@ class NCShareNetworking: NSObject {
func createShareLink(password: String?) {
NCActivityIndicator.shared.start(backgroundView: view)
- let filenamePath = utilityFileSystem.getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, userId: metadata.userId)
- NextcloudKit.shared.createShareLink(path: filenamePath) { [self] account, share, data, error in
+ let filenamePath = utilityFileSystem.getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, session: session)
+ NextcloudKit.shared.createShareLink(path: filenamePath, account: metadata.account) { [self] account, share, data, error in
NCActivityIndicator.shared.stop()
if error == .success && share != nil {
- let home = utilityFileSystem.getHomeServer(urlBase: self.metadata.urlBase, userId: self.metadata.userId)
+ let home = self.utilityFileSystem.getHomeServer(session: self.session)
NCManageDatabase.shared.addShare(account: self.metadata.account, home:home, shares: [share!])
+ if !metadata.contentType.contains("directory") {
+ AnalyticsHelper.shared.trackEventWithMetadata(eventName: .EVENT__SHARE_FILE ,metadata: metadata)
+ }
} else if error != .success{
NCContentPresenter().showError(error: error)
}
@@ -175,6 +178,11 @@ class NCShareNetworking: NSObject {
delegate.transferReloadData(serverUrl: self.metadata.serverUrl, requestData: true, status: nil)
}
}
+ NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUpdateShare, userInfo: ["account": self.metadata.account, "serverUrl": self.metadata.serverUrl])
+
+ if !self.metadata.contentType.contains("directory") {
+ AnalyticsHelper.shared.trackEventWithMetadata(eventName: .EVENT__SHARE_FILE ,metadata: self.metadata)
+ }
} else {
NCContentPresenter().showError(error: error)
}
diff --git a/iOSClient/Share/NCShareUserCell.swift b/iOSClient/Share/NCShareUserCell.swift
index f0d9f4e168..8a9cc3a74a 100644
--- a/iOSClient/Share/NCShareUserCell.swift
+++ b/iOSClient/Share/NCShareUserCell.swift
@@ -161,7 +161,6 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol {
imageItem?.addGestureRecognizer(tapGesture)
buttonMenu.setImage(UIImage.init(named: "shareMenu")!.image(color: NCBrandColor.shared.customer, size: 24), for: .normal)
buttonMenu.contentMode = .scaleAspectFill
-// buttonMenu.setImage(NCImageCache.images.buttonMore.image(color: NCBrandColor.shared.customer, size: 24), for: .normal)
labelQuickStatus.textColor = NCBrandColor.shared.customer
imageDownArrow.image = UIImage(named: "downArrow")?.imageColor(NCBrandColor.shared.customer)
switchCanEdit.transform = CGAffineTransform(scaleX: 0.75, y: 0.75)
diff --git a/iOSClient/Utility/NCUtility.swift b/iOSClient/Utility/NCUtility.swift
index 8a7526f446..a0390fbfbb 100644
--- a/iOSClient/Utility/NCUtility.swift
+++ b/iOSClient/Utility/NCUtility.swift
@@ -14,6 +14,20 @@ final class NCUtility: NSObject, Sendable {
let utilityFileSystem = NCUtilityFileSystem()
let global = NCGlobal.shared
+ @objc func isSimulatorOrTestFlight() -> Bool {
+ guard let path = Bundle.main.appStoreReceiptURL?.path else {
+ return false
+ }
+ return path.contains("CoreSimulator") || path.contains("sandboxReceipt")
+ }
+
+ func isSimulator() -> Bool {
+ guard let path = Bundle.main.appStoreReceiptURL?.path else {
+ return false
+ }
+ return path.contains("CoreSimulator")
+ }
+
func isTypeFileRichDocument(_ metadata: tableMetadata) -> Bool {
let fileExtension = (metadata.fileNameView as NSString).pathExtension
guard let capabilities = NCNetworking.shared.capabilities[metadata.account],
@@ -88,11 +102,11 @@ final class NCUtility: NSObject, Sendable {
}
}
- func isQuickLookDisplayable(metadata: tableMetadata) -> Bool {
+ @objc func isQuickLookDisplayable(metadata: tableMetadata) -> Bool {
return true
}
- func ocIdToFileId(ocId: String?) -> String? {
+ @objc func ocIdToFileId(ocId: String?) -> String? {
guard let ocId = ocId else { return nil }
let items = ocId.components(separatedBy: "oc")
@@ -275,12 +289,20 @@ final class NCUtility: NSObject, Sendable {
return (usedmegabytes, totalmegabytes)
}
- func getHeightHeaderEmptyData(view: UIView, portraitOffset: CGFloat, landscapeOffset: CGFloat) -> CGFloat {
+// func removeForbiddenCharacters(_ fileName: String) -> String {
+// var fileName = fileName
+// for character in global.forbiddenCharacters {
+// fileName = fileName.replacingOccurrences(of: character, with: "")
+// }
+// return fileName
+// }
+
+ func getHeightHeaderEmptyData(view: UIView, portraitOffset: CGFloat, landscapeOffset: CGFloat, isHeaderMenuTransferViewEnabled: Bool = false) -> CGFloat {
var height: CGFloat = 0
if UIDevice.current.orientation.isPortrait {
height = (view.frame.height / 2) - (view.safeAreaInsets.top / 2) + portraitOffset
} else {
- height = (view.frame.height / 2) + landscapeOffset
+ height = (view.frame.height / 2) + landscapeOffset + CGFloat(isHeaderMenuTransferViewEnabled ? 35 : 0)
}
return height
}
From c2df0b962f847ccac32de9446158ee06f80bb6c7 Mon Sep 17 00:00:00 2001
From: harshada-15-tsys
Date: Mon, 6 Oct 2025 13:01:51 +0530
Subject: [PATCH 5/6] NMC 1997 - Sharing customisation changes and
new-sharing-design customisation changes
---
Nextcloud.xcodeproj/project.pbxproj | 34 +-
iOSClient/Activity/NCActivity.swift | 160 ++--
.../Extensions/DateFormatter+Extension.swift | 13 +-
.../Extensions/UIToolbar+Extension.swift | 2 +-
iOSClient/Extensions/UIView+Extension.swift | 50 +-
iOSClient/Menu/NCShare+Menu.swift | 99 +--
iOSClient/NCGlobal.swift | 292 +++++--
.../DownloadLimitViewModel.swift | 16 +
...hareDownloadLimitTableViewController.swift | 13 +-
.../NCShareDownloadLimitViewController.swift | 42 +-
.../Advanced/NCShareAdvancePermission.swift | 447 +++++++----
.../NCShareAdvancePermissionFooter.swift | 15 +-
.../NCShareAdvancePermissionHeader.xib | 22 +-
iOSClient/Share/Advanced/NCShareCells.swift | 158 ++--
.../Share/Advanced/NCShareDateCell.swift | 7 +-
.../Advanced/NCShareNewUserAddComment.swift | 61 +-
.../Share/Advanced/NCShareTextInputCell.swift | 117 +--
iOSClient/Share/CreateLinkFooterView.swift | 79 ++
iOSClient/Share/NCPermissions.swift | 103 +++
iOSClient/Share/NCSearchUserDropDownCell.xib | 8 +-
iOSClient/Share/NCShare+NCCellDelegate.swift | 18 +-
iOSClient/Share/NCShare.storyboard | 82 +-
iOSClient/Share/NCShare.swift | 724 +++++++++++++-----
iOSClient/Share/NCShareCommentsCell.swift | 3 +-
iOSClient/Share/NCShareCommon.swift | 21 +-
iOSClient/Share/NCShareEmailFieldCell.swift | 178 +++--
iOSClient/Share/NCShareEmailFieldCell.xib | 217 ++++--
.../Share/NCShareEmailLinkHeaderView.swift | 43 ++
iOSClient/Share/NCShareHeader.swift | 80 +-
iOSClient/Share/NCShareHeader.xib | 231 +++---
iOSClient/Share/NCShareLinkCell.swift | 123 +--
iOSClient/Share/NCShareLinkCell.xib | 233 +++---
iOSClient/Share/NCShareNetworking.swift | 256 ++++++-
iOSClient/Share/NCSharePaging.swift | 30 +-
iOSClient/Share/NCShareUserCell.swift | 181 +++--
iOSClient/Share/NoSharesFooterView.swift | 63 ++
.../Share/ShareDownloadLimitNetwork.swift | 20 +-
iOSClient/Share/Shareable.swift | 44 +-
iOSClient/Share/TransientShare.swift | 7 +-
iOSClient/Utility/NCUtility.swift | 142 +++-
40 files changed, 2980 insertions(+), 1454 deletions(-)
create mode 100644 iOSClient/Share/CreateLinkFooterView.swift
create mode 100644 iOSClient/Share/NCPermissions.swift
create mode 100644 iOSClient/Share/NCShareEmailLinkHeaderView.swift
create mode 100644 iOSClient/Share/NoSharesFooterView.swift
diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj
index af31c937a7..bc45aa6008 100644
--- a/Nextcloud.xcodeproj/project.pbxproj
+++ b/Nextcloud.xcodeproj/project.pbxproj
@@ -86,6 +86,15 @@
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 */; };
+ B5BEBD192E93A5260002C9E5 /* Shareable.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD182E93A5260002C9E5 /* Shareable.swift */; };
+ B5BEBD1E2E93A74C0002C9E5 /* CreateLinkFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD1A2E93A74C0002C9E5 /* CreateLinkFooterView.swift */; };
+ B5BEBD1F2E93A74C0002C9E5 /* NCPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD1B2E93A74C0002C9E5 /* NCPermissions.swift */; };
+ B5BEBD202E93A74C0002C9E5 /* NCShareEmailLinkHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD1C2E93A74C0002C9E5 /* NCShareEmailLinkHeaderView.swift */; };
+ B5BEBD212E93A74C0002C9E5 /* NoSharesFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD1D2E93A74C0002C9E5 /* NoSharesFooterView.swift */; };
+ B5BEBD222E93A74C0002C9E5 /* CreateLinkFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD1A2E93A74C0002C9E5 /* CreateLinkFooterView.swift */; };
+ B5BEBD232E93A74C0002C9E5 /* NCPermissions.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD1B2E93A74C0002C9E5 /* NCPermissions.swift */; };
+ B5BEBD242E93A74C0002C9E5 /* NCShareEmailLinkHeaderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD1C2E93A74C0002C9E5 /* NCShareEmailLinkHeaderView.swift */; };
+ B5BEBD252E93A74C0002C9E5 /* NoSharesFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5BEBD1D2E93A74C0002C9E5 /* NoSharesFooterView.swift */; };
B5E2E6D42DAE52B500AB2EDD /* SharingTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E2E6D32DAE52B500AB2EDD /* SharingTest.swift */; };
B5E2E6D72DAE571200AB2EDD /* PasswordInputField.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5E2E6D62DAE571200AB2EDD /* PasswordInputField.xib */; };
B5E2E6D82DAE571200AB2EDD /* PasswordInputField.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E2E6D52DAE571200AB2EDD /* PasswordInputField.swift */; };
@@ -101,7 +110,6 @@
B5E2E6ED2DAE66AF00AB2EDD /* NCShareEmailFieldCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = B5E2E6EC2DAE66AF00AB2EDD /* NCShareEmailFieldCell.xib */; };
B5E2E6EE2DAE66AF00AB2EDD /* NCShareEmailFieldCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E2E6EB2DAE66AF00AB2EDD /* NCShareEmailFieldCell.swift */; };
B5E2E6F02DAE6E3F00AB2EDD /* ShareDownloadLimitNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5E2E6EF2DAE6E3F00AB2EDD /* ShareDownloadLimitNetwork.swift */; };
- 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 */; };
@@ -1239,6 +1247,11 @@
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 /* NCShare+Helper.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "NCShare+Helper.swift"; sourceTree = ""; };
+ B5BEBD182E93A5260002C9E5 /* Shareable.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Shareable.swift; sourceTree = ""; };
+ B5BEBD1A2E93A74C0002C9E5 /* CreateLinkFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateLinkFooterView.swift; sourceTree = ""; };
+ B5BEBD1B2E93A74C0002C9E5 /* NCPermissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCPermissions.swift; sourceTree = ""; };
+ B5BEBD1C2E93A74C0002C9E5 /* NCShareEmailLinkHeaderView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCShareEmailLinkHeaderView.swift; sourceTree = ""; };
+ B5BEBD1D2E93A74C0002C9E5 /* NoSharesFooterView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NoSharesFooterView.swift; sourceTree = ""; };
B5E2E6D32DAE52B500AB2EDD /* SharingTest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SharingTest.swift; sourceTree = ""; };
B5E2E6D52DAE571200AB2EDD /* PasswordInputField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PasswordInputField.swift; sourceTree = ""; };
B5E2E6D62DAE571200AB2EDD /* PasswordInputField.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = PasswordInputField.xib; sourceTree = ""; };
@@ -2058,7 +2071,6 @@
children = (
AA52EB452D42AC5A0089C348 /* Placeholder.swift */,
B5E2E6D32DAE52B500AB2EDD /* SharingTest.swift */,
- AF8ED1FB2757821000B8DBC4 /* NextcloudUnitTests.swift */,
);
path = NextcloudUnitTests;
sourceTree = "";
@@ -2345,6 +2357,11 @@
F728CE741BF6322C00E69702 /* Share */ = {
isa = PBXGroup;
children = (
+ B5BEBD1A2E93A74C0002C9E5 /* CreateLinkFooterView.swift */,
+ B5BEBD1B2E93A74C0002C9E5 /* NCPermissions.swift */,
+ B5BEBD1C2E93A74C0002C9E5 /* NCShareEmailLinkHeaderView.swift */,
+ B5BEBD1D2E93A74C0002C9E5 /* NoSharesFooterView.swift */,
+ B5BEBD182E93A5260002C9E5 /* Shareable.swift */,
B5E2E6EF2DAE6E3F00AB2EDD /* ShareDownloadLimitNetwork.swift */,
B5E2E6EB2DAE66AF00AB2EDD /* NCShareEmailFieldCell.swift */,
B5E2E6EC2DAE66AF00AB2EDD /* NCShareEmailFieldCell.xib */,
@@ -2369,7 +2386,7 @@
AF2D7C7D2742559100ADF566 /* NCShareUserCell.swift */,
AF93471727E2361E002537EE /* NCShareHeader.xib */,
AF93471527E2361E002537EE /* NCShareHeader.swift */,
- AFCE353827E5DE0400FEA6C2 /* Shareable.swift */,
+ AFCE353827E5DE0400FEA6C2 /* NCShare+Helper.swift */,
AA8E03D92D2ED83300E7E89C /* TransientShare.swift */,
);
path = Share;
@@ -4329,6 +4346,10 @@
F76B3CCF1EAE01BD00921AC9 /* NCBrand.swift in Sources */,
F72944F32A84246400246839 /* NCEndToEndMetadataV20.swift in Sources */,
F7BAADCC1ED5A87C00B7EAD4 /* NCManageDatabase.swift in Sources */,
+ B5BEBD1E2E93A74C0002C9E5 /* CreateLinkFooterView.swift in Sources */,
+ B5BEBD1F2E93A74C0002C9E5 /* NCPermissions.swift in Sources */,
+ B5BEBD202E93A74C0002C9E5 /* NCShareEmailLinkHeaderView.swift in Sources */,
+ B5BEBD212E93A74C0002C9E5 /* NoSharesFooterView.swift in Sources */,
F7327E322B73A86700A462C7 /* NCNetworking+WebDAV.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
@@ -4492,6 +4513,7 @@
F76D3CF12428B40E005DFA87 /* NCViewerPDFSearch.swift in Sources */,
F7245924289BB50C00474787 /* ThreadSafeDictionary.swift in Sources */,
F73F537F1E929C8500F8678D /* NCMore.swift in Sources */,
+ B5BEBD192E93A5260002C9E5 /* Shareable.swift in Sources */,
F702F2CF25EE5B5C008F8E80 /* NCGlobal.swift in Sources */,
F794E13F2BBC0F70003693D7 /* SceneDelegate.swift in Sources */,
F714A1472ED84AF90050A43B /* HudBannerView.swift in Sources */,
@@ -4549,7 +4571,7 @@
F71916142E2901FB00E13E96 /* NCNetworking+Upload.swift in Sources */,
F704B5E92430C0B800632F5F /* NCCreateFormUploadConflictCell.swift in Sources */,
F72D404923D2082500A97FD0 /* NCViewerNextcloudText.swift in Sources */,
- AFCE353927E5DE0500FEA6C2 /* Shareable.swift in Sources */,
+ AFCE353927E5DE0500FEA6C2 /* NCShare+Helper.swift in Sources */,
F77BB746289984CA0090FC19 /* UIViewController+Extension.swift in Sources */,
F700510522DF6A89003A3356 /* NCShare.swift in Sources */,
F72D1007210B6882009C96B7 /* NCPushNotificationEncryption.m in Sources */,
@@ -4662,6 +4684,10 @@
F76B3CCE1EAE01BD00921AC9 /* NCBrand.swift in Sources */,
F7FA7FFC2C0F4EE40072FC60 /* NCViewerQuickLookView.swift in Sources */,
F3A0479B2BD2668800658E7B /* NCAssistant.swift in Sources */,
+ B5BEBD222E93A74C0002C9E5 /* CreateLinkFooterView.swift in Sources */,
+ B5BEBD232E93A74C0002C9E5 /* NCPermissions.swift in Sources */,
+ B5BEBD242E93A74C0002C9E5 /* NCShareEmailLinkHeaderView.swift in Sources */,
+ B5BEBD252E93A74C0002C9E5 /* NoSharesFooterView.swift in Sources */,
F359D8672A7D03420023F405 /* NCUtility+Exif.swift in Sources */,
F7A03E352D427312007AA677 /* NCMainNavigationController.swift in Sources */,
F769CA192966EA3C00039397 /* ComponentView.swift in Sources */,
diff --git a/iOSClient/Activity/NCActivity.swift b/iOSClient/Activity/NCActivity.swift
index f7b6d19b6c..d760ba0f8d 100644
--- a/iOSClient/Activity/NCActivity.swift
+++ b/iOSClient/Activity/NCActivity.swift
@@ -1,6 +1,26 @@
-// SPDX-FileCopyrightText: Nextcloud GmbH
-// SPDX-FileCopyrightText: 2019 Marino Faggiana
-// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// NCActivity.swift
+// Nextcloud
+//
+// Created by Marino Faggiana on 17/01/2019.
+// Copyright © 2019 Marino Faggiana. All rights reserved.
+//
+// Author Marino Faggiana
+// Author Henrik Storch
+//
+// 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 SwiftRichString
@@ -22,6 +42,7 @@ class NCActivity: UIViewController, NCSharePagingContent {
let database = NCManageDatabase.shared
var allItems: [DateCompareable] = []
var sectionDates: [Date] = []
+ var dataSourceTask: URLSessionTask?
var insets = UIEdgeInsets(top: 8, left: 0, bottom: 0, right: 0)
var didSelectItemEnable: Bool = true
@@ -30,14 +51,11 @@ class NCActivity: UIViewController, NCSharePagingContent {
var isFetchingActivity = false
var hasActivityToLoad = true {
- didSet {
- tableView.tableFooterView?.isHidden = hasActivityToLoad
- }
+ didSet { tableView.tableFooterView?.isHidden = hasActivityToLoad }
}
var dateAutomaticFetch: Date?
private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
- @MainActor
var session: NCSession.Session {
if account.isEmpty {
NCSession.shared.getSession(controller: tabBarController)
@@ -51,7 +69,7 @@ class NCActivity: UIViewController, NCSharePagingContent {
override func viewDidLoad() {
super.viewDidLoad()
- navigationController?.setNavigationBarAppearance()
+ self.navigationController?.navigationBar.prefersLargeTitles = true
view.backgroundColor = .systemBackground
self.title = NSLocalizedString("_activity_", comment: "")
@@ -72,14 +90,7 @@ class NCActivity: UIViewController, NCSharePagingContent {
commentView = Bundle.main.loadNibNamed("NCActivityCommentView", owner: self, options: nil)?.first as? NCActivityCommentView
commentView?.setup(account: metadata.account) { newComment in
guard let newComment = newComment, !newComment.isEmpty, let metadata = self.metadata else { return }
- NextcloudKit.shared.putComments(fileId: metadata.fileId, message: newComment, account: metadata.account) { task in
- Task {
- let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: metadata.account,
- path: metadata.fileId,
- name: "putComments")
- await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task)
- }
- } completion: { _, _, error in
+ NextcloudKit.shared.putComments(fileId: metadata.fileId, message: newComment, account: metadata.account) { _, _, error in
if error == .success {
self.commentView?.newCommentField.text?.removeAll()
self.loadComments()
@@ -105,12 +116,9 @@ class NCActivity: UIViewController, NCSharePagingContent {
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
- Task {
- await NCNetworking.shared.networkingTasks.cancel(identifier: "NCActivity")
- }
-
// Cancel Queue & Retrieves Properties
NCNetworking.shared.downloadThumbnailActivityQueue.cancelAll()
+ dataSourceTask?.cancel()
}
override func viewWillLayoutSubviews() {
@@ -229,8 +237,8 @@ extension NCActivity: UITableViewDataSource {
cell.fileAvatarImageView?.image = results.image
}
- if let tblAvatar = results.tblAvatar,
- !tblAvatar.loaded,
+ if let tableAvatar = results.tableAvatar,
+ !tableAvatar.loaded,
NCNetworking.shared.downloadAvatarQueue.operations.filter({ ($0 as? NCOperationDownloadAvatar)?.fileName == fileName }).isEmpty {
NCNetworking.shared.downloadAvatarQueue.addOperation(NCOperationDownloadAvatar(user: comment.actorId, fileName: fileName, account: account, view: tableView))
}
@@ -275,7 +283,7 @@ extension NCActivity: UITableViewDataSource {
if !activity.icon.isEmpty {
activity.icon = activity.icon.replacingOccurrences(of: ".png", with: ".svg")
let fileNameIcon = (activity.icon as NSString).lastPathComponent
- let fileNameLocalPath = utilityFileSystem.createServerUrl(serverUrl: utilityFileSystem.directoryUserData, fileName: fileNameIcon)
+ let fileNameLocalPath = utilityFileSystem.directoryUserData + "/" + fileNameIcon
if FileManager.default.fileExists(atPath: fileNameLocalPath) {
let image = fileNameIcon.contains(".svg") ? SVGKImage(contentsOfFile: fileNameLocalPath)?.uiImage : UIImage(contentsOfFile: fileNameLocalPath)
@@ -284,14 +292,7 @@ extension NCActivity: UITableViewDataSource {
cell.icon.image = image.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
}
} else {
- NextcloudKit.shared.downloadContent(serverUrl: activity.icon, account: activity.account) { task in
- Task {
- let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: self.account,
- path: activity.icon,
- name: "downloadContent")
- await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task)
- }
- } completion: { _, responseData, error in
+ NextcloudKit.shared.downloadContent(serverUrl: activity.icon, account: activity.account) { _, responseData, error in
if error == .success, let data = responseData?.data {
do {
try data.write(to: NSURL(fileURLWithPath: fileNameLocalPath) as URL, options: .atomic)
@@ -317,7 +318,7 @@ extension NCActivity: UITableViewDataSource {
cell.fileAvatarImageView?.image = results.image
}
- if !(results.tblAvatar?.loaded ?? false),
+ if !(results.tableAvatar?.loaded ?? false),
NCNetworking.shared.downloadAvatarQueue.operations.filter({ ($0 as? NCOperationDownloadAvatar)?.fileName == fileName }).isEmpty {
NCNetworking.shared.downloadAvatarQueue.addOperation(NCOperationDownloadAvatar(user: activity.user, fileName: fileName, account: session.account, view: tableView))
}
@@ -341,7 +342,7 @@ extension NCActivity: UITableViewDataSource {
for key in keys {
if let result = database.getActivitySubjectRich(account: session.account, idActivity: activity.idActivity, key: key) {
orderKeysId.append(result.id)
- subject = subject.replacingOccurrences(of: "{\(key)}", with: "" + result.name.escapedForMarkup + "")
+ subject = subject.replacingOccurrences(of: "{\(key)}", with: "" + result.name + "")
}
}
@@ -380,8 +381,12 @@ extension NCActivity {
func fetchAll(isInitial: Bool) {
guard !isFetchingActivity else { return }
self.isFetchingActivity = true
+ var bottom: CGFloat = 0
- NCActivityIndicator.shared.start(backgroundView: self.view, style: .medium)
+ if let mainTabBar = self.tabBarController?.tabBar as? NCMainTabBar {
+ bottom = -mainTabBar.getHeight()
+ }
+ NCActivityIndicator.shared.start(backgroundView: self.view, bottom: bottom - 35, style: .medium)
let dispatchGroup = DispatchGroup()
loadComments(disptachGroup: dispatchGroup)
@@ -428,14 +433,7 @@ extension NCActivity {
guard showComments, let metadata = metadata else { return }
disptachGroup?.enter()
- NextcloudKit.shared.getComments(fileId: metadata.fileId, account: metadata.account) { task in
- Task {
- let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: metadata.account,
- path: metadata.fileId,
- name: "getComments")
- await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task)
- }
- } completion: { _, comments, _, error in
+ NextcloudKit.shared.getComments(fileId: metadata.fileId, account: metadata.account) { _, comments, _, error in
if error == .success, let comments = comments {
self.database.addComments(comments, account: metadata.account, objectId: metadata.fileId)
} else if error.errorCode != NCGlobal.shared.errorResourceNotFound {
@@ -456,13 +454,6 @@ extension NCActivity {
/// Check if most recent activivities are loaded, if not trigger reload
func checkRecentActivity(disptachGroup: DispatchGroup) {
- Task {
- // If is already in-flight, do nothing
- if await NCNetworking.shared.networkingTasks.isReading(identifier: "NCActivity") {
- return
- }
- }
-
guard let result = database.getLatestActivityId(account: session.account), metadata == nil, hasActivityToLoad else {
return self.loadActivity(idActivity: 0, disptachGroup: disptachGroup)
}
@@ -470,15 +461,14 @@ extension NCActivity {
disptachGroup.enter()
- NextcloudKit.shared.getActivity(since: 0,
- limit: 1,
- objectId: nil,
- objectType: objectType,
- previews: true,
- account: session.account) { task in
- Task {
- await NCNetworking.shared.networkingTasks.track(identifier: "NCActivity", task: task)
- }
+ NextcloudKit.shared.getActivity(
+ since: 0,
+ limit: 1,
+ objectId: nil,
+ objectType: objectType,
+ previews: true,
+ account: session.account) { task in
+ self.dataSourceTask = task
} completion: { account, _, activityFirstKnown, activityLastGiven, _, error in
defer { disptachGroup.leave() }
@@ -496,21 +486,18 @@ extension NCActivity {
}
func loadActivity(idActivity: Int, limit: Int = 200, disptachGroup: DispatchGroup) {
- guard hasActivityToLoad else {
- return
- }
+ guard hasActivityToLoad else { return }
var resultActivityId = 0
disptachGroup.enter()
- NextcloudKit.shared.getActivity(since: idActivity,
- limit: min(limit, 200),
- objectId: metadata?.fileId,
- objectType: objectType,
- previews: true,
- account: session.account) { task in
- Task {
- await NCNetworking.shared.networkingTasks.track(identifier: "NCActivity", task: task)
- }
+ NextcloudKit.shared.getActivity(
+ since: idActivity,
+ limit: min(limit, 200),
+ objectId: metadata?.fileId,
+ objectType: objectType,
+ previews: true,
+ account: session.account) { task in
+ self.dataSourceTask = task
} completion: { account, activities, activityFirstKnown, activityLastGiven, _, error in
defer { disptachGroup.leave() }
guard error == .success,
@@ -539,26 +526,22 @@ extension NCActivity: NCShareCommentsCellDelegate {
guard let tableComment = tableComment else {
return
}
- self.showProfileMenu(userId: tableComment.actorId, session: session, sender: sender)
+ self.showProfileMenu(userId: tableComment.actorId, session: session)
}
func tapMenu(with tableComments: tableComments?, sender: Any) {
- toggleMenu(with: tableComments, sender: sender)
+ toggleMenu(with: tableComments)
}
- func toggleMenu(with tableComments: tableComments?, sender: Any) {
+ func toggleMenu(with tableComments: tableComments?) {
var actions = [NCMenuAction]()
actions.append(
NCMenuAction(
title: NSLocalizedString("_edit_comment_", comment: ""),
icon: utility.loadImage(named: "pencil", colors: [NCBrandColor.shared.iconImageColor]),
- sender: sender,
action: { _ in
- guard let metadata = self.metadata,
- let tableComments = tableComments else {
- return
- }
+ guard let metadata = self.metadata, let tableComments = tableComments else { return }
let alert = UIAlertController(title: NSLocalizedString("_edit_comment_", comment: ""), message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: nil))
@@ -570,14 +553,7 @@ extension NCActivity: NCShareCommentsCellDelegate {
alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in
guard let message = alert.textFields?.first?.text, !message.isEmpty else { return }
- NextcloudKit.shared.updateComments(fileId: metadata.fileId, messageId: tableComments.messageId, message: message, account: metadata.account) { task in
- Task {
- let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: metadata.account,
- path: metadata.fileId,
- name: "updateComments")
- await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task)
- }
- } completion: { _, _, error in
+ NextcloudKit.shared.updateComments(fileId: metadata.fileId, messageId: tableComments.messageId, message: message, account: metadata.account) { _, _, error in
if error == .success {
self.loadComments()
} else {
@@ -600,18 +576,10 @@ extension NCActivity: NCShareCommentsCellDelegate {
title: NSLocalizedString("_delete_comment_", comment: ""),
destructive: true,
icon: utility.loadImage(named: "trash", colors: [.red]),
- sender: sender,
action: { _ in
guard let metadata = self.metadata, let tableComments = tableComments else { return }
- NextcloudKit.shared.deleteComments(fileId: metadata.fileId, messageId: tableComments.messageId, account: metadata.account) { task in
- Task {
- let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: metadata.account,
- path: metadata.fileId,
- name: "deleteComments")
- await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task)
- }
- } completion: { _, _, error in
+ NextcloudKit.shared.deleteComments(fileId: metadata.fileId, messageId: tableComments.messageId, account: metadata.account) { _, _, error in
if error == .success {
self.loadComments()
} else {
@@ -626,6 +594,6 @@ extension NCActivity: NCShareCommentsCellDelegate {
)
)
- presentMenu(with: actions, sender: sender)
+ presentMenu(with: actions)
}
}
diff --git a/iOSClient/Extensions/DateFormatter+Extension.swift b/iOSClient/Extensions/DateFormatter+Extension.swift
index 5d6a004843..2344faac6c 100644
--- a/iOSClient/Extensions/DateFormatter+Extension.swift
+++ b/iOSClient/Extensions/DateFormatter+Extension.swift
@@ -28,6 +28,7 @@ extension DateFormatter {
static let shareExpDate: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.formatterBehavior = .behavior10_4
+// dateFormatter.locale = Locale.current
dateFormatter.dateStyle = .medium
dateFormatter.dateFormat = NCShareAdvancePermission.displayDateFormat
return dateFormatter
@@ -35,9 +36,13 @@ extension DateFormatter {
}
extension Date {
- static var tomorrow: Date { return Date().dayAfter }
- static var today: Date {return Date()}
- var dayAfter: Date {
+ static var tomorrow: Date { return Date().dayAfter }
+ static var today: Date {return Date()}
+ static var dayAfterYear: Date { return Date().dateAfterYear }
+ var dayAfter: Date {
return Calendar.current.date(byAdding: .day, value: 1, to: Date())!
- }
+ }
+ var dateAfterYear: Date {
+ return Calendar.current.date(byAdding: .year, value: 1, to: Date())!
+ }
}
diff --git a/iOSClient/Extensions/UIToolbar+Extension.swift b/iOSClient/Extensions/UIToolbar+Extension.swift
index c457f56493..ac403c9791 100644
--- a/iOSClient/Extensions/UIToolbar+Extension.swift
+++ b/iOSClient/Extensions/UIToolbar+Extension.swift
@@ -37,7 +37,7 @@ extension UIToolbar {
buttons.append(clearButton)
}
buttons.append(UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil))
- let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .plain) {
+ let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .done) {
onDone()
}
buttons.append(doneButton)
diff --git a/iOSClient/Extensions/UIView+Extension.swift b/iOSClient/Extensions/UIView+Extension.swift
index 71084ad547..4673ca902c 100644
--- a/iOSClient/Extensions/UIView+Extension.swift
+++ b/iOSClient/Extensions/UIView+Extension.swift
@@ -30,22 +30,50 @@ enum VerticalLocation: String {
}
extension UIView {
+
+ // Source
+ // https://stackoverflow.com/questions/18680028/prevent-screen-capture-in-an-ios-app/67054892#67054892
+ //
+ // private weak var scrollView: UIScrollView! (it's an outlet)
+ // self.view.preventScreenshot(for: self.scrollView)
+ //
+ func preventScreenshot(for view: UIView) {
+ let textField = UITextField()
+ textField.isSecureTextEntry = true
+ textField.isUserInteractionEnabled = false
+ guard let hiddenView = textField.layer.sublayers?.first?.delegate as? UIView else {
+ return
+ }
+ hiddenView.subviews.forEach { $0.removeFromSuperview() }
+ hiddenView.translatesAutoresizingMaskIntoConstraints = false
+ self.addSubview(hiddenView)
+ hiddenView.fillSuperview()
+ hiddenView.addSubview(view)
+ }
+
+ func addBlur(style: UIBlurEffect.Style) {
+ let blur = UIBlurEffect(style: style)
+ let blurredEffectView = UIVisualEffectView(effect: blur)
+ blurredEffectView.frame = self.bounds
+ blurredEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+ blurredEffectView.isUserInteractionEnabled = false
+ self.addSubview(blurredEffectView)
+ }
+
+ func insertBlur(style: UIBlurEffect.Style) {
+ let blur = UIBlurEffect(style: style)
+ let blurredEffectView = UIVisualEffectView(effect: blur)
+ blurredEffectView.frame = self.bounds
+ blurredEffectView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+ blurredEffectView.isUserInteractionEnabled = false
+ self.insertSubview(blurredEffectView, at: 0)
+ }
+
func makeCircularBackground(withColor backgroundColor: UIColor) {
self.backgroundColor = backgroundColor
self.layer.cornerRadius = self.frame.size.width / 2
self.layer.masksToBounds = true
}
-
- var parentTabBarController: UITabBarController? {
- var responder: UIResponder? = self
- while let nextResponder = responder?.next {
- if let tabBarController = nextResponder as? UITabBarController {
- return tabBarController
- }
- responder = nextResponder
- }
- return nil
- }
func addShadow(location: VerticalLocation, height: CGFloat = 2, color: UIColor = NCBrandColor.shared.customerDarkGrey, opacity: Float = 0.4, radius: CGFloat = 2) {
switch location {
diff --git a/iOSClient/Menu/NCShare+Menu.swift b/iOSClient/Menu/NCShare+Menu.swift
index 83ef4c5791..68c66ff5fc 100644
--- a/iOSClient/Menu/NCShare+Menu.swift
+++ b/iOSClient/Menu/NCShare+Menu.swift
@@ -33,18 +33,8 @@ extension NCShare {
if share.shareType == NKShare.ShareType.publicLink.rawValue, canReshare {
actions.append(
NCMenuAction(
- title: NSLocalizedString("_share_add_sharelink_", comment: ""),
- icon: utility.loadImage(named: "plus", colors: [NCBrandColor.shared.iconImageColor]),
- sender: sender,
-// func toggleShareMenu(for share: tableShare, sendMail: Bool, folder: Bool, sender: Any) {
-//
-// var actions = [NCMenuAction]()
-//
-// if !folder {
-// actions.append(
-// NCMenuAction(
-// title: NSLocalizedString("_open_in_", comment: ""),
-// icon: utility.loadImage(named: "viewInFolder").imageColor(NCBrandColor.shared.brandElement),
+ title: NSLocalizedString("_open_in_", comment: ""),
+ icon: utility.loadImage(named: "viewInFolder").imageColor(NCBrandColor.shared.brandElement),
action: { _ in
NCShareCommon().copyLink(link: share.url, viewController: self, sender: sender)
}
@@ -54,14 +44,11 @@ extension NCShare {
actions.append(
NCMenuAction(
- title: NSLocalizedString("_advance_permissions_", comment: ""),
- icon: utility.loadImage(named: "rename").imageColor(NCBrandColor.shared.brandElement),
- accessibilityIdentifier: "shareMenu/details",
- sender: sender,
// title: NSLocalizedString("_details_", comment: ""),
// icon: utility.loadImage(named: "pencil", colors: [NCBrandColor.shared.iconImageColor]),
// accessibilityIdentifier: "shareMenu/details",
-
+ title: NSLocalizedString("_advance_permissions_", comment: ""),
+ icon: utility.loadImage(named: "rename").imageColor(NCBrandColor.shared.brandElement),
action: { _ in
guard
let advancePermission = UIStoryboard(name: "NCShare", bundle: nil).instantiateViewController(withIdentifier: "NCShareAdvancePermission") as? NCShareAdvancePermission,
@@ -100,9 +87,7 @@ extension NCShare {
actions.append(
NCMenuAction(
title: NSLocalizedString("_share_unshare_", comment: ""),
- destructive: true,
icon: utility.loadImage(named: "trash").imageColor(NCBrandColor.shared.brandElement),
- sender: sender,
action: { _ in
Task {
if share.shareType != NKShare.ShareType.publicLink.rawValue, let metadata = self.metadata, metadata.e2eEncrypted && capabilities.e2EEApiVersion == NCGlobal.shared.e2eeVersionV20 {
@@ -110,7 +95,7 @@ extension NCShare {
let error = NKError(errorCode: NCGlobal.shared.errorE2EEUploadInProgress, errorDescription: NSLocalizedString("_e2e_in_upload_", comment: ""))
return NCContentPresenter().showInfo(error: error)
}
- let error = await NCNetworkingE2EE().uploadMetadata(serverUrl: metadata.serverUrlFileName, addUserId: nil, removeUserId: share.shareWith, account: metadata.account)
+ let error = await NCNetworkingE2EE().uploadMetadata(serverUrl: serverUrl, addUserId: nil, removeUserId: share.shareWith, account: metadata.account)
if error != .success {
return NCContentPresenter().showError(error: error)
}
@@ -121,58 +106,40 @@ extension NCShare {
)
)
- self.presentMenu(with: actions, sender: sender)
+ self.presentMenu(with: actions)
}
- func toggleQuickPermissionsMenu(isDirectory: Bool, share: tableShare, sender: Any?) {
+ func toggleUserPermissionMenu(isDirectory: Bool, tableShare: tableShare) {
var actions = [NCMenuAction]()
+ let permissions = NCPermissions()
- actions.append(contentsOf:
- [NCMenuAction(
+ actions.append(
+ NCMenuAction(
title: NSLocalizedString("_share_read_only_", comment: ""),
icon: utility.loadImage(named: "eye", colors: [NCBrandColor.shared.iconImageColor]),
selected: share.permissions == (NKShare.Permission.read.rawValue + NKShare.Permission.share.rawValue) || share.permissions == NKShare.Permission.read.rawValue,
on: false,
- sender: sender,
action: { _ in
- let permissions = NCSharePermissions.getPermissionValue(canCreate: false, canEdit: false, canDelete: false, canShare: false, isDirectory: isDirectory)
- self.updateSharePermissions(share: share, permissions: permissions)
+ let canShare = permissions.isPermissionToCanShare(tableShare.permissions)
+ let permissions = permissions.getPermission(canEdit: false, canCreate: false, canChange: false, canDelete: false, canShare: canShare, isDirectory: isDirectory)
+ self.updateSharePermissions(share: tableShare, permissions: permissions)
}
- ),
+ )
+ )
+
+ actions.append(
NCMenuAction(
-// title: NSLocalizedString("_share_editing_", comment: ""),
- title: isDirectory ? NSLocalizedString("_share_allow_upload_", comment: "") : NSLocalizedString("_share_editing_", comment: ""),
- icon: utility.loadImage(named: "pencil", colors: [NCBrandColor.shared.iconImageColor]),
- selected: hasUploadPermission(tableShare: share),
-// icon: UIImage(),
-// selected: hasUploadPermission(tableShare: tableShare),
+// title: isDirectory ? NSLocalizedString("_share_allow_upload_", comment: "") : NSLocalizedString("_share_editing_", comment: ""),
+ title: NSLocalizedString("_share_editing_", comment: ""),
+ icon: UIImage(),
+ selected: hasUploadPermission(tableShare: tableShare),
on: false,
- sender: sender,
action: { _ in
- let permissions = NCSharePermissions.getPermissionValue(canCreate: true, canEdit: true, canDelete: true, canShare: true, isDirectory: isDirectory)
- self.updateSharePermissions(share: share, permissions: permissions)
+ let canShare = permissions.isPermissionToCanShare(tableShare.permissions)
+ let permissions = permissions.getPermission(canEdit: true, canCreate: true, canChange: true, canDelete: true, canShare: canShare, isDirectory: isDirectory)
+ self.updateSharePermissions(share: tableShare, permissions: permissions)
}
- ),
- NCMenuAction(
- title: NSLocalizedString("_custom_permissions_", comment: ""),
- icon: utility.loadImage(named: "ellipsis", colors: [NCBrandColor.shared.iconImageColor]),
- sender: sender,
- action: { _ in
- guard
- let advancePermission = UIStoryboard(name: "NCShare", bundle: nil).instantiateViewController(withIdentifier: "NCShareAdvancePermission") as? NCShareAdvancePermission,
- let navigationController = self.navigationController, !share.isInvalidated else { return }
- advancePermission.networking = self.networking
- advancePermission.share = tableShare(value: share)
- advancePermission.oldTableShare = tableShare(value: share)
- advancePermission.metadata = self.metadata
-
- if let downloadLimit = try? self.database.getDownloadLimit(byAccount: self.metadata.account, shareToken: share.token) {
- advancePermission.downloadLimit = .limited(limit: downloadLimit.limit, count: downloadLimit.count)
- }
-
- navigationController.pushViewController(advancePermission, animated: true)
- }
- )]
+ )
)
if isDirectory && (share.shareType == NKShare.ShareType.publicLink.rawValue /* public link */ || share.shareType == NKShare.ShareType.email.rawValue) {
@@ -189,15 +156,16 @@ extension NCShare {
), at: 2)
}
- self.presentMenu(with: actions, sender: sender)
+ self.presentMenu(with: actions)
}
fileprivate func hasUploadPermission(tableShare: tableShare) -> Bool {
+ let permissions = NCPermissions()
let uploadPermissions = [
- NCSharePermissions.permissionMaxFileShare,
- NCSharePermissions.permissionMaxFolderShare,
- NCSharePermissions.permissionDefaultFileRemoteShareNoSupportShareOption,
- NCSharePermissions.permissionDefaultFolderRemoteShareNoSupportShareOption]
+ permissions.permissionMaxFileShare,
+ permissions.permissionMaxFolderShare,
+ permissions.permissionDefaultFileRemoteShareNoSupportShareOption,
+ permissions.permissionDefaultFolderRemoteShareNoSupportShareOption]
return uploadPermissions.contains(tableShare.permissions)
}
@@ -211,11 +179,8 @@ extension NCShare {
if let model = try database.getDownloadLimit(byAccount: metadata.account, shareToken: updatedShare.token) {
downloadLimit = .limited(limit: model.limit, count: model.count)
}
- if let model = try database.getDownloadLimit(byAccount: metadata.account, shareToken: updatedShare.token) {
- downloadLimit = .limited(limit: model.limit, count: model.count)
- }
} catch {
- nkLog(error: "Failed to get download limit from database!")
+ NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Failed to get download limit from database!")
return
}
diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift
index ffc823e651..dd5365d89a 100644
--- a/iOSClient/NCGlobal.swift
+++ b/iOSClient/NCGlobal.swift
@@ -4,18 +4,34 @@
import UIKit
-final class NCGlobal: Sendable {
- static let shared = NCGlobal()
-
- init() { }
+/// Used for read/write in Realm
+var isAppSuspending: Bool = false
+/// Used for know if the app in in Background mode
+var isAppInBackground: Bool = false
+class NCGlobal: NSObject, @unchecked Sendable {
+ @objc static let shared = NCGlobal()
+
+ override init() {
+ super.init()
+ NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { _ in
+ isAppSuspending = true
+ isAppInBackground = true
+ }
+
+ NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { _ in
+ isAppSuspending = false
+ isAppInBackground = false
+ }
+ }
+
// ENUM
//
public enum TypeFilterScanDocument: String {
case document = "document"
case original = "original"
}
-
+
// Directory on Group
//
let directoryProviderStorage = "File Provider Storage"
@@ -24,13 +40,13 @@ final class NCGlobal: Sendable {
let appDatabaseNextcloud = "Library/Application Support/Nextcloud"
let appScan = "Library/Application Support/Scan"
let appUserData = "Library/Application Support/UserData"
-
+
// Service
//
let metadataKeyedUnarchiver = "it.twsweb.nextcloud.metadata"
let refreshTask = "com.nextcloud.refreshTask"
let processingTask = "com.nextcloud.processingTask"
-
+
// App
//
let appName = "files"
@@ -39,9 +55,10 @@ final class NCGlobal: Sendable {
let spreedName = "spreed"
let twoFactorNotificatioName = "twofactor_nextcloud_notification"
let termsOfServiceName = "terms_of_service"
-
+
// Nextcloud version
//
+ let nextcloudVersion12: Int = 12
let nextcloudVersion18: Int = 18
let nextcloudVersion20: Int = 20
let nextcloudVersion23: Int = 23
@@ -52,21 +69,28 @@ final class NCGlobal: Sendable {
let nextcloudVersion28: Int = 28
let nextcloudVersion30: Int = 30
let nextcloudVersion31: Int = 31
-
+
// Nextcloud unsupported
//
let nextcloud_unsupported_version: Int = 20
+// let nextcloud_unsupported_version: Int = 17
+
// Intro selector
//
- let introLogin: Int = 0
- let introSignUpWithProvider: Int = 1
-
+ @objc let introLogin: Int = 0
+ let introSignup: Int = 1
+ // let introSignUpWithProvider: Int = 1
+
+ // Varie size GUI
+ //
+ @objc let heightCellSettings: CGFloat = 50
+
// Avatar
//
let avatarSize: Int = 128 * Int(UIScreen.main.scale)
let avatarSizeRounded: Int = 128
-
+
// Preview size
//
let size1024: CGSize = CGSize(width: 1024, height: 1024)
@@ -76,50 +100,50 @@ final class NCGlobal: Sendable {
let previewExt1024 = ".1024.preview.jpg"
let previewExt512 = ".512.preview.jpg"
let previewExt256 = ".256.preview.jpg"
-
+
func getSizeExtension(column: Int) -> String {
if column == 0 { return previewExt256 }
let width = UIScreen.main.bounds.width / CGFloat(column)
-
- switch (width * 4) {
- case 0...384:
- return previewExt256
- case 385...768:
- return previewExt512
- default:
- return previewExt1024
- }
+
+ switch (width * 4) {
+ case 0...384:
+ return previewExt256
+ case 385...768:
+ return previewExt512
+ default:
+ return previewExt1024
+ }
}
-
+
// E2EE
//
let e2eePassphraseTest = "more over television factory tendency independence international intellectual impress interest sentence pony"
- let e2eeVersions = ["1.1", "1.2", "2.0"]
+ @objc let e2eeVersions = ["1.1", "1.2", "2.0"]
let e2eeVersionV11 = "1.1"
let e2eeVersionV12 = "1.2"
let e2eeVersionV20 = "2.0"
-
+
// CHUNK
let chunkSizeMBCellular = 10000000
let chunkSizeMBEthernetOrWiFi = 100000000
-
+
// Video
//
let maxHTTPCache: Int64 = 10000000000 // 10 GB
let fileNameVideoEncoded: String = "video_encoded.mp4"
-
+
// NCViewerProviderContextMenu
//
let maxAutoDownload: UInt64 = 50000000 // 50MB
let maxAutoDownloadCellular: UInt64 = 10000000 // 10MB
-
+
// Layout
//
let layoutList = "typeLayoutList"
let layoutGrid = "typeLayoutGrid"
let layoutPhotoRatio = "typeLayoutPhotoRatio"
let layoutPhotoSquare = "typeLayoutPhotoSquare"
-
+
let layoutViewTrash = "LayoutTrash"
let layoutViewOffline = "LayoutOffline"
let layoutViewFavorite = "LayoutFavorite"
@@ -129,16 +153,47 @@ final class NCGlobal: Sendable {
let layoutViewShareExtension = "LayoutShareExtension"
let layoutViewGroupfolders = "LayoutGroupfolders"
let layoutViewMedia = "LayoutMedia"
+ let layoutViewMove = "LayoutMove"
+
// Button Type in Cell list/grid
//
let buttonMoreMore = "more"
let buttonMoreLock = "moreLock"
+ let buttonMoreStop = "stop"
+
+ // Standard height sections header/footer
+ //
+ let heightButtonsView: CGFloat = 50
+ let heightHeaderTransfer: CGFloat = 50
+ let heightSection: CGFloat = 30
+ let heightFooter: CGFloat = 1
+ let heightFooterButton: CGFloat = 30
+ let endHeightFooter: CGFloat = 85
+
+
+ // Text - OnlyOffice - Collabora - QuickLook
+ //
+ let editorText = "text"
+ let editorOnlyoffice = "onlyoffice"
+ let editorCollabora = "collabora"
+ let editorQuickLook = "quicklook"
+
+ let onlyofficeDocx = "onlyoffice_docx"
+ let onlyofficeXlsx = "onlyoffice_xlsx"
+ let onlyofficePptx = "onlyoffice_pptx"
+
+ // Template
+ //
+ let templateDocument = "document"
+ let templateSpreadsheet = "spreadsheet"
+ let templatePresentation = "presentation"
+
// Rich Workspace
//
let fileNameRichWorkspace = "Readme.md"
-
+
// ContentPresenter
//
let dismissAfterSecond: TimeInterval = 5
@@ -156,6 +211,7 @@ final class NCGlobal: Sendable {
let errorConflict: Int = 409
let errorPreconditionFailed: Int = 412
let errorUnsupportedMediaType: Int = 415
+ let errorWebDAVLocked: Int = 423
let errorInternalServerError: Int = 500
let errorMaintenance: Int = 503
let errorQuota: Int = 507
@@ -173,16 +229,12 @@ final class NCGlobal: Sendable {
let errorUnauthorizedFilesPasscode: Int = -99993
let errorDisableFilesApp: Int = -99992
let errorUnexpectedResponseFromDB: Int = -99991
- let errorIncorrectFileName: Int = -99990
- let errorVersionMismatch: Int = -99989
- let errorNCSessionNotFound: Int = -99988
-
// E2EE
let errorE2EENotEnabled: Int = -98000
let errorE2EEVersion: Int = -98001
let errorE2EEKeyChecksums: Int = -98002
let errorE2EEKeyEncodeMetadata: Int = -98003
- let errorE2EEKeyDecodeMetadataV12: Int = -98004
+ let errorE2EEKeyDecodeMetadata: Int = -98004
let errorE2EEKeyVerifySignature: Int = -98005
let errorE2EEKeyCiphertext: Int = -98006
let errorE2EEKeyFiledropCiphertext: Int = -98007
@@ -195,9 +247,7 @@ final class NCGlobal: Sendable {
let errorE2EEEncodedKey: Int = -98014
let errorE2EENoUserFound: Int = -98015
let errorE2EEUploadInProgress: Int = -98016
- let errorE2EEKeyDirectoryTop: Int = -98017
-
-
+
// Selector
//
let selectorReadFile = "readFile"
@@ -209,6 +259,7 @@ final class NCGlobal: Sendable {
let selectorDownloadFile = "downloadFile"
let selectorUploadAutoUpload = "uploadAutoUpload"
+ let selectorUploadAutoUploadAll = "uploadAutoUploadAll"
let selectorUploadFile = "uploadFile"
let selectorUploadFileNODelete = "UploadFileNODelete"
let selectorUploadFileShareExtension = "uploadFileShareExtension"
@@ -217,7 +268,9 @@ final class NCGlobal: Sendable {
let selectorSaveAsScan = "saveAsScan"
let selectorOpenDetail = "openDetail"
let selectorSynchronizationOffline = "synchronizationOffline"
-
+ let selectorPrint = "print"
+ let selectorDeleteFile = "deleteFile"
+
// Metadata : Status
//
// 0 normal
@@ -226,59 +279,107 @@ final class NCGlobal: Sendable {
// ± 3 error
//
let metadataStatusNormal: Int = 0
-
+
let metadataStatusWaitDownload: Int = -1
let metadataStatusDownloading: Int = -2
let metadataStatusDownloadError: Int = -3
-
+
let metadataStatusWaitUpload: Int = 1
let metadataStatusUploading: Int = 2
let metadataStatusUploadError: Int = 3
-
+
let metadataStatusWaitCreateFolder: Int = 10
let metadataStatusWaitDelete: Int = 11
let metadataStatusWaitRename: Int = 12
let metadataStatusWaitFavorite: Int = 13
let metadataStatusWaitCopy: Int = 14
let metadataStatusWaitMove: Int = 15
-
+
let metadataStatusUploadingAllMode = [1,2,3]
- let metadataStatusDownloadingAllMode = [-1, -2, -3]
- let metadataStatusForScreenAwake = [-1, -2, 1, 2]
+ let metadataStatusInTransfer = [-1, -2, 1, 2]
+ let metadataStatusFileDown = [-1, -2, -3]
let metadataStatusHideInView = [1, 2, 3, 11]
+ let metadataStatusHideInFileExtension = [1, 2, 3, 10, 11]
let metadataStatusWaitWebDav = [10, 11, 12, 13, 14, 15]
let metadataStatusTransfers = [-2, -3, 2, 3, 10, 11, 12, 13, 14, 15]
let metadatasStatusInWaiting = [-1, 1, 10, 11, 12, 13, 14, 15]
let metadatasStatusInProgress = [-2, 2]
+
+ let metadataStatusObserveNetworkingProcess = [-1, 1, 10, 11, 12, 13, 14, 15]
+ let metadataStatusObserveTrasfers = [-2, 2, 10, 11, 12, 13, 14, 15]
+ // Hidden files included in the read
+ //
+ let includeHiddenFiles: [String] = [".LivePhoto"]
+
// Auto upload subfolder granularity
//
- let subfolderGranularityDaily = 2
- let subfolderGranularityMonthly = 1
- let subfolderGranularityYearly = 0
-
+ @objc let subfolderGranularityDaily = 2
+ @objc let subfolderGranularityMonthly = 1
+ @objc let subfolderGranularityYearly = 0
+
// Notification Center
//
- let notificationCenterChangeUser = "changeUser" // userInfo: account, controller
- let notificationCenterChangeTheming = "changeTheming" // userInfo: account
+ @objc let notificationCenterChangeUser = "changeUser"
+ let notificationCenterChangeTheming = "changeTheming"
+ @objc let notificationCenterApplicationDidEnterBackground = "applicationDidEnterBackground"
+ @objc let notificationCenterApplicationDidBecomeActive = "applicationDidBecomeActive"
+ @objc let notificationCenterApplicationWillResignActive = "applicationWillResignActive"
+ @objc let notificationCenterApplicationWillEnterForeground = "applicationWillEnterForeground"
+
+
+ @objc let notificationCenterInitialize = "initialize"
let notificationCenterRichdocumentGrabFocus = "richdocumentGrabFocus"
let notificationCenterReloadDataNCShare = "reloadDataNCShare"
+ let notificationCenterDidCreateShareLink = "didCreateShareLink"
+
let notificationCenterCloseRichWorkspaceWebView = "closeRichWorkspaceWebView"
let notificationCenterReloadAvatar = "reloadAvatar"
+ let notificationCenterReloadHeader = "reloadHeader"
let notificationCenterClearCache = "clearCache"
+ let notificationCenterChangeLayout = "changeLayout" // userInfo: account, serverUrl, layoutForView
let notificationCenterCheckUserDelaultErrorDone = "checkUserDelaultErrorDone" // userInfo: account, controller
let notificationCenterServerDidUpdate = "serverDidUpdate" // userInfo: account
let notificationCenterNetworkReachability = "networkReachability"
+ let notificationCenterCreateMediaCacheEnded = "createMediaCacheEnded"
+ let notificationCenterUpdateNotification = "updateNotification"
+ let notificationCenterReloadDataSource = "reloadDataSource" // userInfo: serverUrl?, clearDataSource
+ let notificationCenterGetServerData = "getServerData" // userInfo: serverUrl?
+
+ let notificationCenterChangeStatusFolderE2EE = "changeStatusFolderE2EE" // userInfo: serverUrl
+
+ let notificationCenterDownloadStartFile = "downloadStartFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account
+ let notificationCenterDownloadedFile = "downloadedFile" // userInfo: ocId, ocIdTransfer, session, session, serverUrl, account, selector, error
+ let notificationCenterDownloadCancelFile = "downloadCancelFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account
+
+ let notificationCenterUploadStartFile = "uploadStartFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account, fileName, sessionSelector
+ let notificationCenterUploadedFile = "uploadedFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account, fileName, ocIdTransfer, error
+ let notificationCenterUploadedLivePhoto = "uploadedLivePhoto" // userInfo: ocId, ocIdTransfer, session, serverUrl, account, fileName, ocIdTransfer, error
+ let notificationCenterUploadCancelFile = "uploadCancelFile" // userInfo: ocId, ocIdTransfer, session, serverUrl, account
+
+ let notificationCenterProgressTask = "progressTask" // userInfo: account, ocId, ocIdTransfer, session, serverUrl, status, chunk, e2eEncrypted, progress, totalBytes, totalBytesExpected
+
+ let notificationCenterUpdateBadgeNumber = "updateBadgeNumber" // userInfo: counterDownload, counterUpload
+
+ let notificationCenterCreateFolder = "createFolder" // userInfo: ocId, serverUrl, account, withPush, sceneIdentifier
+ let notificationCenterDeleteFile = "deleteFile" // userInfo: [ocId], error
+ let notificationCenterCopyMoveFile = "copyMoveFile" // userInfo: [ocId] serverUrl, account, dragdrop, type (copy, move)
+ let notificationCenterMoveFile = "moveFile" // userInfo: [ocId], [indexPath], error
+ let notificationCenterCopyFile = "copyFile" // userInfo: [ocId], [indexPath], error
+ let notificationCenterRenameFile = "renameFile" // userInfo: serverUrl, account, error
+ let notificationCenterFavoriteFile = "favoriteFile" // userInfo: ocId, serverUrl
+ let notificationCenterFileExists = "fileExists" // userInfo: ocId, fileExists
+
let notificationCenterMenuSearchTextPDF = "menuSearchTextPDF"
let notificationCenterMenuGotToPageInPDF = "menuGotToPageInPDF"
-
+
let notificationCenterOpenMediaDetail = "openMediaDetail" // userInfo: ocId
-
+
let notificationCenterDismissScanDocument = "dismissScanDocument"
let notificationCenterDismissUploadAssets = "dismissUploadAssets"
-
+
let notificationCenterEnableSwipeGesture = "enableSwipeGesture"
let notificationCenterDisableSwipeGesture = "disableSwipeGesture"
@@ -289,10 +390,15 @@ final class NCGlobal: Sendable {
let notificationCenterStatusReadOnly = "statusReadOnly"
let notificationCenterStatusEditing = "statusEditing"
let notificationCenterStatusFileDrop = "statusFileDrop"
+
let notificationCenterPlayerIsPlaying = "playerIsPlaying"
let notificationCenterPlayerStoppedPlaying = "playerStoppedPlaying"
+
+ let notificationCenterUpdateShare = "updateShare"
+ let notificationCenterShareCountsUpdated = "shareCountsUpdated"
+ let notificationCenterUpdateIcons = "updateIcons"
// Networking Status
let networkingStatusCreateFolder = "statusCreateFolder"
@@ -317,8 +423,8 @@ final class NCGlobal: Sendable {
let tipAccountRequest = "tipAccountRequest"
let tipScanAddImage = "tipScanAddImage"
let tipMediaDetailView = "tipMediaDetailView"
- let tipAutoUploadButton = "tipAutoUploadButton"
-
+ let tipAutoUpload = "tipAutoUpload"
+
// ACTION
//
let actionNoAction = "no-action"
@@ -326,7 +432,7 @@ final class NCGlobal: Sendable {
let actionScanDocument = "add-scan-document"
let actionTextDocument = "create-text-document"
let actionVoiceMemo = "create-voice-memo"
-
+
// WIDGET ACTION
//
let widgetActionNoAction = "nextcloud://open-action?action=no-action"
@@ -334,24 +440,45 @@ final class NCGlobal: Sendable {
let widgetActionScanDocument = "nextcloud://open-action?action=add-scan-document"
let widgetActionTextDocument = "nextcloud://open-action?action=create-text-document"
let widgetActionVoiceMemo = "nextcloud://open-action?action=create-voice-memo"
-
+
// APPCONFIG
//
let configuration_brand = "brand"
-
+
let configuration_serverUrl = "serverUrl"
let configuration_username = "username"
let configuration_password = "password"
let configuration_apppassword = "apppassword"
-
+
let configuration_disable_intro = "disable_intro"
let configuration_disable_multiaccount = "disable_multiaccount"
let configuration_disable_crash_service = "disable_crash_service"
let configuration_disable_log = "disable_log"
+ let configuration_disable_manage_account = "disable_manage_account"
let configuration_disable_more_external_site = "disable_more_external_site"
let configuration_disable_openin_file = "disable_openin_file"
let configuration_enforce_passcode_lock = "enforce_passcode_lock"
-
+
+ // CAPABILITIES
+ //
+ var capabilityServerVersionMajor: Int = 0
+ @objc var capabilityServerVersion: String = ""
+ @objc var capabilityThemingName: String = ""
+ @objc var capabilityThemingSlogan: String = ""
+
+ @objc var capabilityE2EEEnabled: Bool = false
+ @objc var capabilityE2EEApiVersion: String = ""
+
+ var capabilityRichdocumentsEnabled: Bool = false
+ var capabilityRichdocumentsMimetypes: [String] = []
+ var capabilityActivity: [String] = []
+ var capabilityNotification: [String] = []
+
+ @objc var capabilityUserStatusEnabled: Bool = false
+ var isLivePhotoServerAvailable: Bool { // NC28
+ return capabilityServerVersionMajor >= nextcloudVersion28
+ }
+
// MORE NEXTCLOUD APPS
//
let talkSchemeUrl = "nextcloudtalk://"
@@ -359,42 +486,46 @@ final class NCGlobal: Sendable {
let talkAppStoreUrl = "https://apps.apple.com/in/app/nextcloud-talk/id1296825574"
let notesAppStoreUrl = "https://apps.apple.com/in/app/nextcloud-notes/id813973264"
let moreAppsUrl = "itms-apps://search.itunes.apple.com/WebObjects/MZSearch.woa/wa/search?media=software&term=nextcloud"
-
+
// SNAPSHOT PREVIEW
//
let defaultSnapshotConfiguration = "DefaultPreviewConfiguration"
-
+
+// // FORBIDDEN CHARACTERS
+// //
+// // TODO: Remove this
+// let forbiddenCharacters = ["/", "\\", ":", "\"", "|", "?", "*", "<", ">"]
+
// DIAGNOSTICS CLIENTS
//
let diagnosticIssueSyncConflicts = "sync_conflicts"
let diagnosticIssueProblems = "problems"
let diagnosticIssueVirusDetected = "virus_detected"
let diagnosticIssueE2eeErrors = "e2ee_errors"
-
+
let diagnosticProblemsForbidden = "CHARACTERS_FORBIDDEN"
let diagnosticProblemsBadResponse = "BAD_SERVER_RESPONSE"
let diagnosticProblemsUploadServerError = "UploadError.SERVER_ERROR"
-
+
// MEDIA LAYOUT
//
let mediaLayoutRatio = "mediaLayoutRatio"
let mediaLayoutSquare = "mediaLayoutSquare"
-
+
// DRAG & DROP
//
let metadataOcIdDataRepresentation = "text/com.nextcloud.ocId"
-
+
// GROUP AMIN
//
let groupAdmin = "admin"
-
- // TASK DESCRIPTION
+
+ // DATA TASK DESCRIPTION
//
let taskDescriptionRetrievesProperties = "retrievesProperties"
let taskDescriptionSynchronization = "synchronization"
-
- // LOG TAG
- //
+ let taskDescriptionDeleteFileOrFolder = "deleteFileOrFolder"
+
let logTagTask = "BGT"
let logTagLocation = "LOCATION"
let logTagBgSync = "BGSYNC"
@@ -407,10 +538,19 @@ final class NCGlobal: Sendable {
let logTagNetworkingTasks = "NETWORKING TASKS"
let logTagMetadataTransfers = "METADATA TRANSFERS"
- // USER DEFAULTS
+ // MoEngage App Version
//
- let udMigrationMultiDomains = "migrationMultiDomains"
- let udLastVersion = "lastVersion"
+ let moEngageAppVersion = 854
+
+ // Filename Mask and Type
+ //
+ let keyFileNameMask = "fileNameMask"
+ let keyFileNameType = "fileNameType"
+ let keyFileNameAutoUploadMask = "fileNameAutoUploadMask"
+ let keyFileNameAutoUploadType = "fileNameAutoUploadType"
+ let keyFileNameOriginal = "fileNameOriginal"
+ let keyFileNameOriginalAutoUpload = "fileNameOriginalAutoUpload"
+
}
/**
diff --git a/iOSClient/Share/Advanced/DownloadLimit/DownloadLimitViewModel.swift b/iOSClient/Share/Advanced/DownloadLimit/DownloadLimitViewModel.swift
index a949484cae..4d7b7d54f0 100644
--- a/iOSClient/Share/Advanced/DownloadLimit/DownloadLimitViewModel.swift
+++ b/iOSClient/Share/Advanced/DownloadLimit/DownloadLimitViewModel.swift
@@ -20,3 +20,19 @@ enum DownloadLimitViewModel {
///
case limited(limit: Int, count: Int)
}
+
+extension DownloadLimitViewModel {
+ var limit: Int? {
+ if case let .limited(limit, _) = self {
+ return limit
+ }
+ return nil
+ }
+
+ var count: Int? {
+ if case let .limited(_, count) = self {
+ return count
+ }
+ return nil
+ }
+}
diff --git a/iOSClient/Share/Advanced/DownloadLimit/NCShareDownloadLimitTableViewController.swift b/iOSClient/Share/Advanced/DownloadLimit/NCShareDownloadLimitTableViewController.swift
index 783e3096c2..c64c18015f 100644
--- a/iOSClient/Share/Advanced/DownloadLimit/NCShareDownloadLimitTableViewController.swift
+++ b/iOSClient/Share/Advanced/DownloadLimit/NCShareDownloadLimitTableViewController.swift
@@ -32,12 +32,9 @@ class NCShareDownloadLimitTableViewController: UITableViewController {
/// Default value for limits as possibly provided by the server capabilities.
///
var defaultLimit: Int {
- let capabilities = NCNetworking.shared.capabilities[metadata.account] ?? NKCapabilities.Capabilities()
- return capabilities.fileSharingDownloadLimitDefaultLimit
+ NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityFileSharingDownloadLimitDefaultLimit
}
- @IBOutlet var allowedDownloadsCell: UITableViewCell!
- @IBOutlet var limitDownloadCell: UITableViewCell!
@IBOutlet var limitSwitch: UISwitch!
@IBOutlet var limitTextField: UITextField!
@@ -50,14 +47,6 @@ class NCShareDownloadLimitTableViewController: UITableViewController {
} else {
limitSwitch.isOn = false
}
-
- var allowedDownloadsCellConfiguration = UIListContentConfiguration.cell()
- allowedDownloadsCellConfiguration.text = NSLocalizedString("_share_allowed_downloads_", comment: "")
- allowedDownloadsCell.contentConfiguration = allowedDownloadsCellConfiguration
-
- var limitDownloadCellConfiguration = UIListContentConfiguration.cell()
- limitDownloadCellConfiguration.text = NSLocalizedString("_share_limit_download_", comment: "")
- limitDownloadCell.contentConfiguration = limitDownloadCellConfiguration
}
@IBAction func switchDownloadLimit(_ sender: UISwitch) {
diff --git a/iOSClient/Share/Advanced/DownloadLimit/NCShareDownloadLimitViewController.swift b/iOSClient/Share/Advanced/DownloadLimit/NCShareDownloadLimitViewController.swift
index f21e12f356..e3d89e6fc5 100644
--- a/iOSClient/Share/Advanced/DownloadLimit/NCShareDownloadLimitViewController.swift
+++ b/iOSClient/Share/Advanced/DownloadLimit/NCShareDownloadLimitViewController.swift
@@ -16,14 +16,19 @@ class NCShareDownloadLimitViewController: UIViewController, NCShareNavigationTit
public var shareDownloadLimitTableViewControllerDelegate: NCShareDownloadLimitTableViewControllerDelegate?
@IBOutlet var headerContainerView: UIView!
+// private var headerView: NCShareAdvancePermissionHeader?
override func viewDidLoad() {
super.viewDidLoad()
self.setNavigationTitle()
+// NotificationCenter.default.addObserver(self, selector: #selector(handleShareCountsUpdate), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterShareCountsUpdated), object: nil)
+
// Set up header view.
+// setupHeaderView()
- guard let headerView = (Bundle.main.loadNibNamed("NCShareHeader", owner: self, options: nil)?.first as? NCShareHeader) else { return }
+ guard let headerView = (Bundle.main.loadNibNamed("NCShareAdvancePermissionHeader", owner: self, options: nil)?.first as? NCShareAdvancePermissionHeader) else { return }
+// guard let headerView = (Bundle.main.loadNibNamed("NCShareHeader", owner: self, options: nil)?.first as? NCShareHeader) else { return }
headerContainerView.addSubview(headerView)
headerView.frame = headerContainerView.frame
headerView.translatesAutoresizingMaskIntoConstraints = false
@@ -36,7 +41,7 @@ class NCShareDownloadLimitViewController: UIViewController, NCShareNavigationTit
// End editing of inputs when the user taps anywhere else.
- let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard(_:)))
+ let tapGesture = UITapGestureRecognizer(target: self, action: #selector(dismissKeyboard))
view.addGestureRecognizer(tapGesture)
}
@@ -51,7 +56,38 @@ class NCShareDownloadLimitViewController: UIViewController, NCShareNavigationTit
tableViewController.share = share
}
- @objc private func dismissKeyboard(_ sender: Any?) {
+ @objc private func dismissKeyboard() {
view.endEditing(true)
}
+
+// // MARK: - Header
+//
+// private func setupHeaderView() {
+// guard headerView == nil else { return } // Prevent multiple creations
+// guard let view = Bundle.main.loadNibNamed("NCShareAdvancePermissionHeader", owner: self, options: nil)?.first as? NCShareAdvancePermissionHeader else { return }
+//
+// headerView = view
+// headerContainerView.addSubview(view)
+//
+// // Auto Layout
+// view.translatesAutoresizingMaskIntoConstraints = false
+// NSLayoutConstraint.activate([
+// view.topAnchor.constraint(equalTo: headerContainerView.topAnchor),
+// view.bottomAnchor.constraint(equalTo: headerContainerView.bottomAnchor),
+// view.leadingAnchor.constraint(equalTo: headerContainerView.leadingAnchor),
+// view.trailingAnchor.constraint(equalTo: headerContainerView.trailingAnchor)
+// ])
+//
+// // Initial setup
+// headerView?.setupUI(with: metadata)
+// }
+//
+// @objc private func handleShareCountsUpdate(notification: Notification) {
+// guard let userInfo = notification.userInfo,
+// let links = userInfo["links"] as? Int,
+// let emails = userInfo["emails"] as? Int else { return }
+//
+// // Just update, don’t recreate
+// headerView?.setupUI(with: metadata, linkCount: links, emailCount: emails)
+// }
}
diff --git a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift
index 1609f92054..74527cef4c 100644
--- a/iOSClient/Share/Advanced/NCShareAdvancePermission.swift
+++ b/iOSClient/Share/Advanced/NCShareAdvancePermission.swift
@@ -27,9 +27,31 @@ import SVGKit
import CloudKit
import XLForm
-class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDelegate, NCShareNavigationTitleSetting {
-//class NCShareAdvancePermission: XLFormViewController, NCShareAdvanceFotterDelegate, NCShareDetail {
+class NCShareAdvancePermission: XLFormViewController, NCShareAdvanceFotterDelegate, NCShareNavigationTitleSetting {
func dismissShareAdvanceView(shouldSave: Bool) {
+
+ guard shouldSave else {
+ guard oldTableShare?.hasChanges(comparedTo: share) != false else {
+ navigationController?.popViewController(animated: true)
+ return
+ }
+
+ let alert = UIAlertController(
+ title: NSLocalizedString("_cancel_request_", comment: ""),
+ message: NSLocalizedString("_discard_changes_info_", comment: ""),
+ preferredStyle: .alert)
+
+ alert.addAction(UIAlertAction(
+ title: NSLocalizedString("_discard_changes_", comment: ""),
+ style: .destructive,
+ handler: { _ in self.navigationController?.popViewController(animated: true) }))
+
+ alert.addAction(UIAlertAction(title: NSLocalizedString("_continue_editing_", comment: ""), style: .default))
+ self.present(alert, animated: true)
+
+ return
+ }
+
if shouldSave {
self.oldTableShare?.permissions = self.permission ?? (self.oldTableShare?.permissions ?? 0)
self.share.permissions = self.permission ?? (self.oldTableShare?.permissions ?? 0)
@@ -44,23 +66,56 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
if let downloadSwitchCell = getDownloadLimitSwitchCell() {
let isDownloadLimitOn = downloadSwitchCell.switchControl.isOn
if !isDownloadLimitOn {
- setDownloadLimit(deleteLimit: true, limit: "")
+ setDownloadLimit(deleteLimit: true, limit: String(defaultLimit))
} else {
let downloadLimitInputCell = getDownloadLimitInputCell()
- let enteredDownloadLimit = downloadLimitInputCell?.cellTextField.text ?? ""
+// let enteredDownloadLimit = downloadLimitInputCell?.cellTextField.text ?? ""
+ let enteredDownloadLimit = downloadLimitInputCell?.cellTextField.text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
+
+// if enteredDownloadLimit.isEmpty {
+// showDownloadLimitError(message: NSLocalizedString("_share_download_limit_alert_empty_", comment: ""))
+// return
+// }
+// if let num = Int(enteredDownloadLimit), num < 1 {
+// showDownloadLimitError(message: NSLocalizedString("_share_download_limit_alert_zero_", comment: ""))
+// return
+// }
+//
+// self.downloadLimit = .limited(limit: Int(enteredDownloadLimit)!, count: downloadLimit.count ?? 0)
+
+ // Case 1: Empty input
if enteredDownloadLimit.isEmpty {
showDownloadLimitError(message: NSLocalizedString("_share_download_limit_alert_empty_", comment: ""))
return
}
- if let num = Int(enteredDownloadLimit), num < 1 {
+
+ // Case 2: Non-numeric or too large
+ guard let num = Int(enteredDownloadLimit) else {
+ // Input is either not a number or exceeds Int range
+ showDownloadLimitError(message: NSLocalizedString("_share_download_limit_alert_invalid_", comment: ""))
+ return
+ }
+
+ // Case 3: Zero or negative
+ if num < 1 {
showDownloadLimitError(message: NSLocalizedString("_share_download_limit_alert_zero_", comment: ""))
return
}
+
+ // ✅ Safe assignment
+ self.downloadLimit = .limited(limit: num, count: downloadLimit.count ?? 0)
setDownloadLimit(deleteLimit: false, limit: enteredDownloadLimit)
+ updateDownloadLimitUI()
}
}
- networking?.updateShare(option: share)
+ if let expiryDateSwitchCell = getExpiryDateSwitchCell() {
+ let isExpiryDateOn = expiryDateSwitchCell.switchControl.isOn
+ if !isExpiryDateOn {
+ share.expirationDate = nil
+ }
+ }
+ networking?.updateShare(share, downloadLimit: self.downloadLimit)
navigationController?.popViewController(animated: true)
}
} else {
@@ -102,43 +157,55 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
isNewShare ? share.shareType : oldTableShare?.shareType ?? NCShareCommon().SHARE_TYPE_USER
}()
static let displayDateFormat = "dd. MMM. yyyy"
- var downloadLimit: DownloadLimit?
var permission: Int?
+ ///
+ /// Default value for limits as possibly provided by the server capabilities.
+ ///
+ var defaultLimit: Int {
+ NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityFileSharingDownloadLimitDefaultLimit
+ }
+
override func viewDidLoad() {
super.viewDidLoad()
self.shareConfig = NCShareConfig(parentMetadata: metadata, share: share)
-
- // Only persisted shares have tokens which are provided by the server.
- // A download limit requires a token to exist.
- // Hence it can only be looked up if the share is already persisted at this point.
- if isNewShare == false {
- if let persistedShare = share as? tableShare {
- do {
- if let limit = try database.getDownloadLimit(byAccount: metadata.account, shareToken: persistedShare.token) {
- self.downloadLimit = .limited(limit: limit.limit, count: limit.count)
- }
- } catch {
- nkLog(error: "There was an error while fetching the download limit for share with token \(persistedShare.token)!")
- }
- }
- }
-
- tableView.estimatedRowHeight = tableView.rowHeight
- tableView.rowHeight = UITableView.automaticDimension
-
self.setNavigationTitle()
// disbale pull to dimiss
isModalInPresentation = true
self.tableView.separatorStyle = UITableViewCell.SeparatorStyle.none
self.permission = oldTableShare?.permissions
+ if !isNewShare {
+ Task {
+ await getDownloadLimit()
+ }
+ }
initializeForm()
changeTheming()
- getDownloadLimit()
+// getDownloadLimit()
+// Task {
+// await getDownloadLimit()
+// }
+
+// // Only persisted shares have tokens which are provided by the server.
+// // A download limit requires a token to exist.
+// // Hence it can only be looked up if the share is already persisted at this point.
+// if isNewShare == false {
+// if let persistedShare = share as? tableShare {
+// do {
+// if let limit = try database.getDownloadLimit(byAccount: metadata.account, shareToken: persistedShare.token) {
+// self.downloadLimit = .limited(limit: limit.limit, count: limit.count)
+// self.updateDownloadLimitUI()
+// }
+// } catch {
+// NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] There was an error while fetching the download limit for share with token \(persistedShare.token)!")
+// }
+// }
+// }
+
NotificationCenter.default.addObserver(self, selector: #selector(changeTheming), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterChangeTheming), object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(_:)), name: UIResponder.keyboardWillShowNotification, object: nil)
-
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(_:)), name: UIResponder.keyboardWillHideNotification, object: nil)
+// NotificationCenter.default.addObserver(self, selector: #selector(handleShareCountsUpdate), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterShareCountsUpdated), object: nil)
}
override func viewWillLayoutSubviews() {
@@ -148,6 +215,17 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
setupFooterView()
}
+// override func viewWillLayoutSubviews() {
+// super.viewWillLayoutSubviews()
+//
+// if tableView.tableHeaderView == nil {
+// setupHeaderView()
+// }
+// if tableView.tableFooterView == nil {
+// setupFooterView()
+// }
+// }
+
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
if (UIDevice.current.userInterfaceIdiom == .phone), UIDevice().hasNotch {
let isLandscape = UIDevice.current.orientation.isLandscape
@@ -156,16 +234,34 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
tableView.layoutIfNeeded()
}
}
-
- @objc func keyboardWillShow(_ notification:Notification) {
- if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue {
- tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardSize.height + 60, right: 0)
+
+ @objc func keyboardWillShow(_ notification: Notification) {
+ guard let userInfo = notification.userInfo else { return }
+
+ // Use the end frame for the keyboard
+ if let keyboardFrame = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
+
+ // Adjust the content inset of the table view
+ let keyboardHeight = keyboardFrame.height
+ let extraPadding: CGFloat = 60
+
+ // Animate the content inset change to match the keyboard's animation
+ UIView.animate(withDuration: 0.3, animations: {
+ self.tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: keyboardHeight + extraPadding, right: 0)
+ self.tableView.scrollIndicatorInsets = self.tableView.contentInset
+ })
}
}
-
- @objc func keyboardWillHide(_ notification:Notification) {
- if ((notification.userInfo?[UIResponder.keyboardFrameBeginUserInfoKey] as? NSValue)?.cgRectValue) != nil {
- tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: tableViewBottomInset, right: 0)
+
+ @objc func keyboardWillHide(_ notification: Notification) {
+ guard let userInfo = notification.userInfo else { return }
+
+ // Reset the content inset when the keyboard is hidden
+ if let _ = (userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue) {
+ UIView.animate(withDuration: 0.3, animations: {
+ self.tableView.contentInset = UIEdgeInsets(top: 0, left: 0, bottom: self.tableViewBottomInset, right: 0)
+ self.tableView.scrollIndicatorInsets = self.tableView.contentInset
+ })
}
}
@@ -203,39 +299,34 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
headerView.widthAnchor.constraint(equalTo: view.widthAnchor).isActive = true
}
- override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
- if section == 0 {
- return NSLocalizedString("_custom_permissions_", comment: "")
- } else if section == 1 {
- return NSLocalizedString("_advanced_", comment: "")
- } else { return nil }
- }
-
- override func numberOfSections(in tableView: UITableView) -> Int {
- return 2
- }
-
- override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- if section == 0 {
- // check reshare permission, if restricted add note
- let maxPermission = metadata.directory ? NCSharePermissions.permissionMaxFolderShare : NCSharePermissions.permissionMaxFileShare
- return shareConfig.sharePermission != maxPermission ? shareConfig.permissions.count + 1 : shareConfig.permissions.count
- } else if section == 1 {
- return shareConfig.advanced.count
- } else { return 0 }
- }
-
- override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
- guard let cell = shareConfig.cellFor(indexPath: indexPath) else {
- let noteCell = UITableViewCell(style: .subtitle, reuseIdentifier: "noteCell")
- noteCell.detailTextLabel?.text = NSLocalizedString("_share_reshare_restricted_", comment: "")
- noteCell.detailTextLabel?.isEnabled = false
- noteCell.isUserInteractionEnabled = false
- noteCell.detailTextLabel?.numberOfLines = 0
- return noteCell
- }
- }
-
+// @objc private func handleShareCountsUpdate(notification: Notification) {
+// guard let userInfo = notification.userInfo,
+// let links = userInfo["links"] as? Int,
+// let emails = userInfo["emails"] as? Int else {
+// return
+// }
+//
+// // Update existing header if possible
+// if let header = tableView.tableHeaderView as? NCShareAdvancePermissionHeader {
+// header.setupUI(with: metadata, linkCount: links, emailCount: emails)
+// } else {
+// // Fallback: re-create header if missing
+// setupHeaderView(linkCount: links, emailCount: emails)
+// }
+// }
+//
+// func setupHeaderView(linkCount: Int = 0, emailCount: Int = 0) {
+// guard let headerView = Bundle.main.loadNibNamed("NCShareAdvancePermissionHeader", owner: self, options: nil)?.first as? NCShareAdvancePermissionHeader else {
+// return
+// }
+//
+// headerView.setupUI(with: metadata, linkCount: linkCount, emailCount: emailCount)
+// headerView.ocId = metadata.ocId
+// headerView.frame = CGRect(x: 0, y: 0, width: view.frame.size.width, height: 190)
+//
+// tableView.tableHeaderView = headerView
+// }
+
func initializeForm() {
let form : XLFormDescriptor
var section : XLFormSectionDescriptor
@@ -285,8 +376,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
}
}
let enabled = NCShareCommon().isEditingEnabled(isDirectory: metadata.directory, fileExtension: metadata.fileExtension, shareType: shareType) || checkIsCollaboraFile()
- row.cellConfig["titleLabel.textColor"] = enabled ? NCBrandColor.shared.label : NCBrandColor.shared.systemGray
- row.disabled = !enabled
+ row.cellConfig["titleLabel.textColor"] = NCBrandColor.shared.label
section.addFormRow(row)
if !enabled {
@@ -314,6 +404,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
row = XLFormRowDescriptor(tag: "kNMCFilePermissionCellFiledropMessage", rowType: "kNMCFilePermissionCell", title: NSLocalizedString("_PERMISSIONS_", comment: ""))
row.cellConfig["titleLabel.text"] = NSLocalizedString("_file_drop_message_", comment: "")
row.cellConfig["titleLabel.textColor"] = NCBrandColor.shared.gray60
+// row.cellConfig["titleLabel.textColor"] = NCBrandColor.shared.label
row.cellConfig["imageCheck.image"] = UIImage()
row.height = 84
section.addFormRow(row)
@@ -394,6 +485,11 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
row.cellConfig["fileNameInputTextField.textColor"] = NCBrandColor.shared.label
row.cellConfig["backgroundColor"] = NCBrandColor.shared.secondarySystemGroupedBackground
row.height = 44
+
+// // Add validator for min 6 characters
+// guard let minLengthValidator = XLFormRegexValidator(msg: NSLocalizedString("_password_min_6_chars_", comment: "Password must be at least 6 characters"), andRegexString: "^.{6,}$") else { return <#default value#> }
+// row.addValidator(minLengthValidator)
+
let hasPassword = oldTableShare?.password != nil && !oldTableShare!.password.isEmpty
row.hidden = NSNumber.init(booleanLiteral: !hasPassword)
section.addFormRow(row)
@@ -426,6 +522,12 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
if let date = oldTableShare?.expirationDate {
row.cellConfig["cellTextField.text"] = DateFormatter.shareExpDate.string(from: date as Date)
}
+// else {
+// let nextYearTomorrow = Date.tomorrowNextYear
+// row.cellConfig["cellTextField.text"] = DateFormatter.shareExpDate.string(from: nextYearTomorrow)
+// share.expirationDate = nextYearTomorrow as NSDate
+// }
+
row.height = 44
let hasExpiry = oldTableShare?.expirationDate != nil
row.hidden = NSNumber.init(booleanLiteral: !hasExpiry)
@@ -450,10 +552,11 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
row.cellConfig["cellTextField.font"] = UIFont.systemFont(ofSize: 15.0)
row.cellConfig["cellTextField.textColor"] = NCBrandColor.shared.label
row.height = 44
- let downloadLimitSet = downloadLimit?.limit != nil
- row.hidden = NSNumber.init(booleanLiteral: !downloadLimitSet)
- if let value = downloadLimit?.limit {
- row.cellConfig["cellTextField.text"] = "\(value)"
+ if case let .limited(limit, _) = downloadLimit {
+ row.hidden = NSNumber(booleanLiteral: false)
+ row.cellConfig["cellTextField.text"] = "\(limit)"
+ } else {
+ row.hidden = NSNumber(booleanLiteral: true)
}
section.addFormRow(row)
@@ -461,12 +564,15 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
row = XLFormRowDescriptor(tag: "kNMCDownloadLimitCell", rowType: "kNMCFilePermissionCell", title: "")
row.cellClass = NCFilePermissionCell.self
row.height = 44
- if downloadLimit?.limit != nil {
- row.cellConfig["titleLabel.text"] = NSLocalizedString("_share_remaining_download_", comment: "") + " \(downloadLimit?.count ?? 0)"
+ switch downloadLimit {
+ case .limited(_, let count):
+ row.cellConfig["titleLabel.text"] = NSLocalizedString("_share_remaining_download_", comment: "") + " \(count)"
+ row.hidden = false
+ default:
+ row.hidden = true
}
- row.cellConfig["titleLabel.textColor"] = NCBrandColor.shared.systemGray
+ row.cellConfig["titleLabel.textColor"] = NCBrandColor.shared.systemGray
row.disabled = true
- row.hidden = NSNumber.init(booleanLiteral: !downloadLimitSet)
section.addFormRow(row)
}
@@ -481,7 +587,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
}
func updateDownloadLimitUI() {
- if let value = downloadLimit?.limit {
+ if let value = downloadLimit.limit {
if let downloadLimitSwitchField: XLFormRowDescriptor = self.form.formRow(withTag: "kNMCFilePermissionEditCellDownloadLimit") {
if let indexPath = self.form.indexPath(ofFormRow: downloadLimitSwitchField) {
let cell = tableView.cellForRow(at: indexPath) as? NCFilePermissionEditCell
@@ -500,7 +606,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
downloadLimitInputField.hidden = false
if let indexPath = self.form.indexPath(ofFormRow: downloadLimitInputField) {
let cell = tableView.cellForRow(at: indexPath) as? NCFilePermissionCell
- cell?.titleLabel.text = NSLocalizedString("_share_remaining_download_", comment: "") + " \(downloadLimit?.count ?? 0)"
+ cell?.titleLabel.text = NSLocalizedString("_share_remaining_download_", comment: "") + " \(downloadLimit.count ?? 0)"
}
}
}
@@ -527,6 +633,16 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
return nil
}
+ func getExpiryDateSwitchCell() -> NCFilePermissionEditCell? {
+ if let expiryRow : XLFormRowDescriptor = self.form.formRow(withTag: "kNMCFilePermissionEditCellExpiration") {
+ if let indexPath = self.form.indexPath(ofFormRow: expiryRow) {
+ let cell = tableView.cellForRow(at: indexPath) as? NCFilePermissionEditCell
+ return cell
+ }
+ }
+ return nil
+ }
+
// MARK: - Row Descriptor Value Changed
override func didSelectFormRow(_ formRow: XLFormRowDescriptor!) {
@@ -587,15 +703,6 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
}
}
- override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
- tableView.deselectRow(at: indexPath, animated: true)
- guard let cellConfig = shareConfig.config(for: indexPath) else { return }
- guard let cellConfig = cellConfig as? NCAdvancedPermission else {
- cellConfig.didSelect(for: share)
- tableView.reloadData()
- }
- }
-
func canReshareTheShare() -> Bool {
if let permissionValue = self.permission {
let canReshare = NCPermissions().isPermissionToCanShare(permissionValue)
@@ -668,7 +775,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
if let limitRow : XLFormRowDescriptor = self.form.formRow(withTag: "kNMCFilePermissionEditCellDownloadLimit") {
if let expiryIndexPath = self.form.indexPath(ofFormRow: limitRow), indexPath == expiryIndexPath {
let cell = cell as? NCFilePermissionEditCell
- cell?.switchControl.isOn = downloadLimit?.limit != nil
+ cell?.switchControl.isOn = downloadLimit.limit != nil
}
}
@@ -676,16 +783,16 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
if let downloadlimitFieldRow : XLFormRowDescriptor = self.form.formRow(withTag: "NCShareTextInputCellDownloadLimit") {
if let downloadlimitIndexPath = self.form.indexPath(ofFormRow: downloadlimitFieldRow), indexPath == downloadlimitIndexPath {
let cell = cell as? NCShareTextInputCell
- cell?.cellTextField.text = "\(downloadLimit?.limit ?? 0)"
+ cell?.cellTextField.text = "\(downloadLimit.limit ?? 0)"
}
}
//SetDownloadLimitSwitch
- if downloadLimit?.count != nil {
+ if downloadLimit.count != nil {
if let downloadlimitFieldRow : XLFormRowDescriptor = self.form.formRow(withTag: "kNMCDownloadLimitCell") {
if let downloadlimitIndexPath = self.form.indexPath(ofFormRow: downloadlimitFieldRow), indexPath == downloadlimitIndexPath {
let cell = cell as? NCFilePermissionCell
- cell?.titleLabel.text = NSLocalizedString("_share_remaining_download_", comment: "") + " \(downloadLimit?.count ?? 0)"
+ cell?.titleLabel.text = NSLocalizedString("_share_remaining_download_", comment: "") + " \(downloadLimit.count ?? 0)"
cell?.seperatorBelowFull.isHidden = true
cell?.seperatorBelow.isHidden = true
}
@@ -734,6 +841,36 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
self.form.delegate = self
}
+// case "SetPasswordInputField":
+// if let pwd = formRow.value as? String {
+// self.form.delegate = nil
+//
+// // Validate password length
+// if pwd.count < 6 {
+// share.password = ""
+//
+// // Show alert for invalid password
+// let alert = UIAlertController(
+// title: NSLocalizedString("_invalid_password_title_", comment: "Invalid Password"),
+// message: NSLocalizedString("_password_min_length_", comment: "Password must be at least 6 characters"),
+// preferredStyle: .alert
+// )
+// alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: "OK"), style: .default))
+// self.present(alert, animated: true)
+//
+// // Clear the text field in the cell
+// if let indexPath = self.form.indexPath(ofFormRow: formRow),
+// let cell = tableView.cellForRow(at: indexPath) as? PasswordInputField {
+// cell.fileNameInputTextField.text = ""
+// }
+// } else {
+// // Password is valid
+// share.password = pwd
+// }
+//
+// self.form.delegate = self
+// }
+
case "kNMCFilePermissionEditCellLinkLabel":
if let label = formRow.value as? String {
self.form.delegate = nil
@@ -741,22 +878,50 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
self.form.delegate = self
}
+// case "kNMCFilePermissionEditCellExpiration":
+// if let value = newValue as? Bool {
+// if let inputField : XLFormRowDescriptor = self.form.formRow(withTag: "NCShareTextInputCellExpiry") {
+// inputField.hidden = !value
+// }
+// }
+
case "kNMCFilePermissionEditCellExpiration":
if let value = newValue as? Bool {
- if let inputField : XLFormRowDescriptor = self.form.formRow(withTag: "NCShareTextInputCellExpiry") {
+ if let inputField: XLFormRowDescriptor = self.form.formRow(withTag: "NCShareTextInputCellExpiry") {
inputField.hidden = !value
+
+ // Only set expiration date if toggle is ON and there's no existing value
+ if value && share.expirationDate == nil {
+ let defaultExpiry = Date.dayNextYear
+ inputField.value = defaultExpiry
+ share.expirationDate = defaultExpiry as NSDate
+
+ // Reload the cell to update the UI
+ if let indexPath = self.form.indexPath(ofFormRow: inputField) {
+ // Reload row to ensure the text field is updated
+// self.tableView.reloadRows(at: [indexPath], with: .automatic)
+
+ // Manually update the cell's text field to display the expiration date
+ if let cell = self.tableView.cellForRow(at: indexPath) as? NCShareTextInputCell {
+ // Use DateFormatter to format the date
+ let formattedDate = DateFormatter.shareExpDate.string(from: defaultExpiry)
+ cell.cellTextField.text = formattedDate
+ }
+ }
+ }
}
}
case "kNMCFilePermissionEditCellDownloadLimit":
if let value = newValue as? Bool {
- self.downloadLimit = DownloadLimit()
- self.downloadLimit?.limit = value ? 0 : nil
+
+ self.downloadLimit = value ? .limited(limit: 0, count: 0) : .unlimited
+
if let inputField : XLFormRowDescriptor = self.form.formRow(withTag: "NCShareTextInputCellDownloadLimit") {
inputField.hidden = !value
if let indexPath = self.form.indexPath(ofFormRow: inputField) {
let cell = tableView.cellForRow(at: indexPath) as? NCShareTextInputCell
- cell?.cellTextField.text = ""
+ cell?.cellTextField.text = "\(downloadLimit.limit ?? 0)"
}
}
@@ -766,7 +931,7 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
let cell = tableView.cellForRow(at: indexPath) as? NCFilePermissionCell
cell?.seperatorBelowFull.isHidden = true
cell?.seperatorBelow.isHidden = true
- cell?.titleLabel.text = ""
+ cell?.titleLabel.text = "" //String(defaultLimit)
}
}
}
@@ -776,6 +941,11 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
self.form.delegate = nil
self.share.expirationDate = exp as NSDate
self.form.delegate = self
+ } else {
+ // Only clear if the row value was *explicitly* set to nil by the user
+ if formRow.value == nil {
+ self.share.expirationDate = nil
+ }
}
default:
@@ -856,31 +1026,6 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
self.permission = permissions.getPermission(canEdit: false, canCreate: false, canChange: false, canDelete: false, canShare: isOn, isDirectory: metadata.directory)
}
}
- let alertController = UIAlertController.password(titleKey: "_share_password_") { password in
- self.share.password = password ?? ""
- tableView.reloadData()
- }
- self.present(alertController, animated: true)
-// case .note:
-// let storyboard = UIStoryboard(name: "NCShare", bundle: nil)
-// guard let viewNewUserComment = storyboard.instantiateViewController(withIdentifier: "NCShareNewUserAddComment") as? NCShareNewUserAddComment else { return }
-// viewNewUserComment.metadata = self.metadata
-// viewNewUserComment.share = self.share
-// viewNewUserComment.onDismiss = tableView.reloadData
-// self.navigationController?.pushViewController(viewNewUserComment, animated: true)
-// case .label:
-// let alertController = UIAlertController.withTextField(titleKey: "_share_link_name_") { textField in
-// textField.placeholder = cellConfig.title
-// textField.text = self.share.label
-// } completion: { newValue in
-// self.share.label = newValue ?? ""
-// self.setNavigationTitle()
-// tableView.reloadData()
-// }
-// self.present(alertController, animated: true)
-// case .downloadAndSync:
-// share.downloadAndSync.toggle()
-// tableView.reloadData()
}
}
@@ -939,23 +1084,43 @@ class NCShareAdvancePermission: UITableViewController, NCShareAdvanceFotterDeleg
navigationController?.popViewController(animated: true)
}
- func getDownloadLimit() {
+ func getDownloadLimit() async {
NCActivityIndicator.shared.start(backgroundView: view)
- NMCCommunication.shared.getDownloadLimit(token: oldTableShare?.token ?? "") { [weak self] (downloadLimit: DownloadLimit?, error: String) in
- DispatchQueue.main.async {
- NCActivityIndicator.shared.stop()
- if let downloadLimit = downloadLimit {
- self?.downloadLimit = downloadLimit
+
+ do {
+ // First, try to fetch download limits from the server.
+ try await networking?.readDownloadLimits(account: metadata.account, tokens: [oldTableShare?.token ?? ""])
+ NCActivityIndicator.shared.stop() // Stop the activity indicator
+
+ if !isNewShare, let persistedShare = share as? tableShare {
+ // If not a new share and share exists, fetch the limit for that persisted share
+ do {
+ if let limit = try database.getDownloadLimit(byAccount: metadata.account, shareToken: persistedShare.token) {
+ DispatchQueue.main.async {
+ NCActivityIndicator.shared.stop() // Stop the activity indicator
+ self.downloadLimit = .limited(limit: limit.limit, count: limit.count)
+ self.updateDownloadLimitUI()
+ }
+ }
+ } catch {
+ // Handle the error for the persisted share token lookup
+ DispatchQueue.main.async {
+ NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Error fetching the download limit for share with token \(persistedShare.token).")
+ NCActivityIndicator.shared.stop() // Stop the activity indicator
+ }
}
- self?.updateDownloadLimitUI()
+ }
+ } catch {
+ // Handle error for fetching download limits from the server
+ DispatchQueue.main.async {
+ print("Error fetching download limit: \(error)")
+ NCActivityIndicator.shared.stop() // Stop the activity indicator
}
}
}
-
+
func setDownloadLimit(deleteLimit: Bool, limit: String) {
- NMCCommunication.shared.setDownloadLimit(deleteLimit: deleteLimit, limit: limit, token: oldTableShare?.token ?? "") { (success, errorMessage) in
- print(success)
- }
+ networking?.setShareDownloadLimit(Int(limit) ?? 0, token: oldTableShare?.token ?? "")
}
func showDownloadLimitError(message: String) {
@@ -973,3 +1138,15 @@ extension NCShareAdvancePermission: NCShareDownloadLimitTableViewControllerDeleg
self.downloadLimitChanged = true
}
}
+
+extension Date {
+ static var dayNextYear: Date {
+// let calendar = Calendar.current
+// let now = Date()
+// var components = DateComponents()
+// components.year = 1
+// components.day = 1
+// return calendar.date(byAdding: components, to: now)!
+ return Calendar.current.date(byAdding: .year, value: 1, to: Date())!
+ }
+}
diff --git a/iOSClient/Share/Advanced/NCShareAdvancePermissionFooter.swift b/iOSClient/Share/Advanced/NCShareAdvancePermissionFooter.swift
index 455b5da0c6..64d8f6d9eb 100644
--- a/iOSClient/Share/Advanced/NCShareAdvancePermissionFooter.swift
+++ b/iOSClient/Share/Advanced/NCShareAdvancePermissionFooter.swift
@@ -42,17 +42,6 @@ class NCShareAdvancePermissionFooter: UIView {
buttonCancel.layer.cornerRadius = 10
buttonCancel.layer.masksToBounds = true
buttonCancel.layer.borderWidth = 1
- buttonCancel.layer.borderColor = NCBrandColor.shared.textColor2.cgColor
- buttonCancel.backgroundColor = .secondarySystemBackground
- buttonCancel.addTarget(self, action: #selector(cancelClicked(_:)), for: .touchUpInside)
- buttonCancel.setTitleColor(NCBrandColor.shared.textColor2, for: .normal)
-
- buttonNext.setTitle(NSLocalizedString(delegate?.isNewShare == true ? "_share_" : "_save_", comment: ""), for: .normal)
- buttonNext.layer.cornerRadius = 25
- buttonNext.layer.masksToBounds = true
- buttonNext.backgroundColor = NCBrandColor.shared.getElement(account: account)
- buttonNext.addTarget(self, action: #selector(nextClicked(_:)), for: .touchUpInside)
-
addShadow(location: .top)
layer.cornerRadius = 10
layer.masksToBounds = true
@@ -66,11 +55,11 @@ class NCShareAdvancePermissionFooter: UIView {
buttonNext.layer.masksToBounds = true
}
- @objc func cancelClicked(_ sender: Any?) {
+ @objc func cancelClicked() {
delegate?.dismissShareAdvanceView(shouldSave: false)
}
- @objc func nextClicked(_ sender: Any?) {
+ @objc func nextClicked() {
delegate?.dismissShareAdvanceView(shouldSave: true)
}
}
diff --git a/iOSClient/Share/Advanced/NCShareAdvancePermissionHeader.xib b/iOSClient/Share/Advanced/NCShareAdvancePermissionHeader.xib
index 161dc96732..20cda3faac 100644
--- a/iOSClient/Share/Advanced/NCShareAdvancePermissionHeader.xib
+++ b/iOSClient/Share/Advanced/NCShareAdvancePermissionHeader.xib
@@ -1,34 +1,33 @@
-
+
-
-
+
-
+
-
+
-
+
-
+
@@ -39,19 +38,18 @@
-
+
-
+
-
@@ -62,7 +60,7 @@
-
+
@@ -75,7 +73,7 @@
-
+
diff --git a/iOSClient/Share/Advanced/NCShareCells.swift b/iOSClient/Share/Advanced/NCShareCells.swift
index 6915dd23c6..5205b361bd 100644
--- a/iOSClient/Share/Advanced/NCShareCells.swift
+++ b/iOSClient/Share/Advanced/NCShareCells.swift
@@ -22,8 +22,6 @@
//
import UIKit
-import OSLog
-import NextcloudKit
protocol NCShareCellConfig {
var title: String { get }
@@ -50,17 +48,18 @@ protocol NCPermission: NCToggleCellConfig {
static var forDirectory: [Self] { get }
static var forFile: [Self] { get }
static func forDirectoryE2EE(account: String) -> [NCPermission]
- func hasPermission(for parentPermission: Int) -> Bool
- func hasReadPermission() -> Bool
+ func hasResharePermission(for parentPermission: Int) -> Bool
+ func hasDownload() -> Bool
}
enum NCUserPermission: CaseIterable, NCPermission {
- func hasPermission(for parentPermission: Int) -> Bool {
+ func hasResharePermission(for parentPermission: Int) -> Bool {
+ if self == .download { return true }
return ((permissionBitFlag & parentPermission) != 0)
}
- func hasReadPermission() -> Bool {
- return self == .read
+ func hasDownload() -> Bool {
+ return self == .download
}
var permissionBitFlag: Int {
@@ -74,32 +73,39 @@ enum NCUserPermission: CaseIterable, NCPermission {
}
func didChange(_ share: Shareable, to newValue: Bool) {
- share.permissions ^= permissionBitFlag
+ if self == .download {
+ share.attributes = NCManageDatabase.shared.setAttibuteDownload(state: newValue)
+ } else {
+ share.permissions ^= permissionBitFlag
+ }
}
func isOn(for share: Shareable) -> Bool {
- return (share.permissions & permissionBitFlag) != 0
+ if self == .download {
+ return NCManageDatabase.shared.isAttributeDownloadEnabled(attributes: share.attributes)
+ } else {
+ return (share.permissions & permissionBitFlag) != 0
+ }
}
static func forDirectoryE2EE(account: String) -> [NCPermission] {
- let capabilities = NCNetworking.shared.capabilities[account] ?? NKCapabilities.Capabilities()
- if capabilities.e2EEApiVersion == NCGlobal.shared.e2eeVersionV20 {
+ if NCCapabilities.shared.getCapabilities(account: account).capabilityE2EEApiVersion == NCGlobal.shared.e2eeVersionV20 {
return NCUserPermission.allCases
}
return []
}
- case read, reshare, edit, create, delete
+ case reshare, edit, create, delete, download
static let forDirectory: [NCUserPermission] = NCUserPermission.allCases
- static let forFile: [NCUserPermission] = [.read, .reshare, .edit]
+ static let forFile: [NCUserPermission] = [.reshare, .edit]
var title: String {
switch self {
- case .read: return NSLocalizedString("_share_can_read_", comment: "")
case .reshare: return NSLocalizedString("_share_can_reshare_", comment: "")
case .edit: return NSLocalizedString("_share_can_change_", comment: "")
case .create: return NSLocalizedString("_share_can_create_", comment: "")
case .delete: return NSLocalizedString("_share_can_delete_", comment: "")
+ case .download: return NSLocalizedString("_share_can_download_", comment: "")
}
}
}
@@ -131,31 +137,90 @@ enum NCLinkEmailPermission: CaseIterable, NCPermission {
}
func didChange(_ share: Shareable, to newValue: Bool) {
- share.permissions ^= permissionBitFlag
+ guard self != .allowEdit || newValue else {
+ share.permissions = NCPermissions().permissionReadShare
+ return
+ }
+ share.permissions = permissionValue
+ }
+
+ func hasResharePermission(for parentPermission: Int) -> Bool {
+ permissionValue & parentPermission == permissionValue
+ }
+
+ func hasDownload() -> Bool {
+ return false
+ }
+
+ var permissionValue: Int {
+ switch self {
+ case .allowEdit:
+ return NCPermissions().getPermission(
+ canEdit: true,
+ canCreate: true,
+ canChange: true,
+ canDelete: true,
+ canShare: false,
+ isDirectory: false)
+ case .viewOnly:
+ return NCPermissions().getPermission(
+ canEdit: false,
+ canCreate: false,
+ canChange: false,
+ canDelete: false,
+ // not possible to create "read-only" shares without reshare option
+ // https://github.com/nextcloud/server/blame/f99876997a9119518fe5f7ad3a3a51d33459d4cc/apps/files_sharing/lib/Controller/ShareAPIController.php#L1104-L1107
+ canShare: true,
+ isDirectory: true)
+ case .uploadEdit:
+ return NCPermissions().getPermission(
+ canEdit: true,
+ canCreate: true,
+ canChange: true,
+ canDelete: true,
+ canShare: false,
+ isDirectory: true)
+ case .fileDrop:
+ return NCPermissions().permissionCreateShare
+ case .secureFileDrop:
+ return NCPermissions().permissionCreateShare
+ }
}
func isOn(for share: Shareable) -> Bool {
- return (share.permissions & permissionBitFlag) != 0
+ let permissions = NCPermissions()
+ switch self {
+ case .allowEdit: return permissions.isAnyPermissionToEdit(share.permissions)
+ case .viewOnly: return !permissions.isAnyPermissionToEdit(share.permissions) && share.permissions != permissions.permissionCreateShare
+ case .uploadEdit: return permissions.isAnyPermissionToEdit(share.permissions) && share.permissions != permissions.permissionCreateShare
+ case .fileDrop: return share.permissions == permissions.permissionCreateShare
+ case .secureFileDrop: return share.permissions == permissions.permissionCreateShare
+ }
+ }
+
+ static func forDirectoryE2EE(account: String) -> [NCPermission] {
+ return [NCLinkPermission.secureFileDrop]
}
var title: String {
switch self {
- case .read: return NSLocalizedString("_share_can_read_", comment: "")
- case .edit: return NSLocalizedString("_share_can_change_", comment: "")
- case .create: return NSLocalizedString("_share_can_create_", comment: "")
- case .delete: return NSLocalizedString("_share_can_delete_", comment: "")
+ case .allowEdit: return NSLocalizedString("_share_can_change_", comment: "")
+ case .viewOnly: return NSLocalizedString("_share_read_only_", comment: "")
+ case .uploadEdit: return NSLocalizedString("_share_allow_upload_", comment: "")
+ case .fileDrop: return NSLocalizedString("_share_file_drop_", comment: "")
+ case .secureFileDrop: return NSLocalizedString("_share_secure_file_drop_", comment: "")
}
}
- case edit, read, create, delete
- static let forDirectory: [NCLinkEmailPermission] = NCLinkEmailPermission.allCases
- static let forFile: [NCLinkEmailPermission] = [.read, .edit]
+ case allowEdit, viewOnly, uploadEdit, fileDrop, secureFileDrop
+ static let forDirectory: [NCLinkPermission] = [.viewOnly, .uploadEdit, .fileDrop]
+ static let forFile: [NCLinkPermission] = [.allowEdit]
}
///
/// Individual aspects of share.
///
-enum NCAdvancedPermission: CaseIterable, NCShareCellConfig {
+enum NCShareDetails: CaseIterable, NCShareCellConfig {
func didSelect(for share: Shareable) {
switch self {
case .hideDownload: share.hideDownload.toggle()
@@ -164,7 +229,6 @@ enum NCAdvancedPermission: CaseIterable, NCShareCellConfig {
case .password: return
case .note: return
case .label: return
- case .downloadAndSync: return
}
}
@@ -189,8 +253,6 @@ enum NCAdvancedPermission: CaseIterable, NCShareCellConfig {
let cell = UITableViewCell(style: .value1, reuseIdentifier: "shareLabel")
cell.detailTextLabel?.text = share.label
return cell
- case .downloadAndSync:
- return NCShareToggleCell(isOn: share.downloadAndSync)
}
}
@@ -202,23 +264,20 @@ enum NCAdvancedPermission: CaseIterable, NCShareCellConfig {
case .password: return NSLocalizedString("_share_password_protect_", comment: "")
case .note: return NSLocalizedString("_share_note_recipient_", comment: "")
case .label: return NSLocalizedString("_share_link_name_", comment: "")
- case .downloadAndSync: return NSLocalizedString("_share_can_download_", comment: "")
}
}
- case label, hideDownload, limitDownload, expirationDate, password, note, downloadAndSync
- static let forLink: [NCAdvancedPermission] = [.expirationDate, .hideDownload, .label, .limitDownload, .note, .password]
- static let forUser: [NCAdvancedPermission] = [.expirationDate, .note, .downloadAndSync]
+ case label, hideDownload, limitDownload, expirationDate, password, note
+ static let forLink: [NCShareDetails] = NCShareDetails.allCases
+ static let forUser: [NCShareDetails] = [.expirationDate, .note]
}
struct NCShareConfig {
let permissions: [NCPermission]
- let advanced: [NCAdvancedPermission]
- let shareable: Shareable
- let sharePermission: Int
- let isDirectory: Bool
+ let advanced: [NCShareDetails]
+ let share: Shareable
+ let resharePermission: Int
- /// There are many share types, but we only classify them as a link share (link type, email type) and a user share (every other share type).
init(parentMetadata: tableMetadata, share: Shareable) {
self.shareable = share
self.sharePermission = parentMetadata.sharePermissionsCollaborationServices
@@ -231,44 +290,29 @@ struct NCShareConfig {
let hasDownloadLimitCapability = capabilities.fileSharingDownloadLimit
if parentMetadata.isDirectory || hasDownloadLimitCapability == false {
- self.advanced = NCAdvancedPermission.forLink.filter { $0 != .limitDownload }
+ self.advanced = NCShareDetails.forLink.filter { $0 != .limitDownload }
} else {
- self.advanced = NCAdvancedPermission.forLink
+ self.advanced = NCShareDetails.forLink
}
} else {
- self.advanced = NCAdvancedPermission.forUser
+ self.advanced = NCShareDetails.forUser
}
}
func cellFor(indexPath: IndexPath) -> UITableViewCell? {
let cellConfig = config(for: indexPath)
- let cell = cellConfig?.getCell(for: shareable)
+ let cell = cellConfig?.getCell(for: share)
cell?.textLabel?.text = cellConfig?.title
- Logger().info("\(cellConfig?.title ?? "")")
-
- if let cellConfig = cellConfig as? NCPermission, !cellConfig.hasPermission(for: sharePermission) {
+ if let cellConfig = cellConfig as? NCPermission, !cellConfig.hasResharePermission(for: resharePermission), !cellConfig.hasDownload() {
cell?.isUserInteractionEnabled = false
cell?.textLabel?.isEnabled = false
}
-
- // For user permissions: Read permission is always enabled and we show it as a non-interactable permission for brevity.
- if let cellConfig = cellConfig as? NCUserPermission, cellConfig.hasReadPermission() {
- cell?.isUserInteractionEnabled = false
- cell?.textLabel?.isEnabled = false
- }
-
- // For link permissions: Read permission is always enabled and we show it as a non-interactable permission in files only for brevity.
- if let cellConfig = cellConfig as? NCLinkEmailPermission, cellConfig.hasReadPermission(), !isDirectory {
- cell?.isUserInteractionEnabled = false
- cell?.textLabel?.isEnabled = false
- }
-
return cell
}
func didSelectRow(at indexPath: IndexPath) {
let cellConfig = config(for: indexPath)
- cellConfig?.didSelect(for: shareable)
+ cellConfig?.didSelect(for: share)
}
func config(for indexPath: IndexPath) -> NCShareCellConfig? {
diff --git a/iOSClient/Share/Advanced/NCShareDateCell.swift b/iOSClient/Share/Advanced/NCShareDateCell.swift
index df1c4fe4af..a26dcf3918 100644
--- a/iOSClient/Share/Advanced/NCShareDateCell.swift
+++ b/iOSClient/Share/Advanced/NCShareDateCell.swift
@@ -2,8 +2,6 @@
// SPDX-FileCopyrightText: 2022 Henrik Storch
// SPDX-License-Identifier: GPL-3.0-or-later
-import NextcloudKit
-
///
/// Table view cell to manage the expiration date on a share in its details.
///
@@ -12,6 +10,7 @@ class NCShareDateCell: UITableViewCell {
let textField = UITextField()
var shareType: Int
var onReload: (() -> Void)?
+ let shareCommon = NCShareCommon()
init(share: Shareable) {
self.shareType = share.shareType
@@ -59,8 +58,6 @@ class NCShareDateCell: UITableViewCell {
}
private func isExpireDateEnforced(account: String) -> Bool {
- let capabilities = NCNetworking.shared.capabilities[account] ?? NKCapabilities.Capabilities()
-
switch self.shareType {
case NKShare.ShareType.publicLink.rawValue,
NKShare.ShareType.email.rawValue,
@@ -80,8 +77,6 @@ class NCShareDateCell: UITableViewCell {
}
private func defaultExpirationDays(account: String) -> Int {
- let capabilities = NCNetworking.shared.capabilities[account] ?? NKCapabilities.Capabilities()
-
switch self.shareType {
case NKShare.ShareType.publicLink.rawValue,
NKShare.ShareType.email.rawValue,
diff --git a/iOSClient/Share/Advanced/NCShareNewUserAddComment.swift b/iOSClient/Share/Advanced/NCShareNewUserAddComment.swift
index a7fe311e0c..c227d21c8a 100644
--- a/iOSClient/Share/Advanced/NCShareNewUserAddComment.swift
+++ b/iOSClient/Share/Advanced/NCShareNewUserAddComment.swift
@@ -35,17 +35,26 @@ class NCShareNewUserAddComment: UIViewController, NCShareNavigationTitleSetting
@IBOutlet weak var btnSendShare: UIButton!
@IBOutlet weak var buttonContainerView: UIView!
let contentInsets: CGFloat = 16
- public var share: NCTableShareable!
+ public var share: Shareable!
public var metadata: tableMetadata!
- var isNewShare: Bool { share is NCTableShareOptions }
+ var isNewShare: Bool { share is TransientShare }
var networking: NCShareNetworking?
+ ///
+ /// The possible download limit associated with this share.
+ ///
+ /// This can only be created after the share has been actually created due to its requirement of the share token provided by the server.
+ ///
+ var downloadLimit: DownloadLimitViewModel = .unlimited
+
override func viewDidLoad() {
super.viewDidLoad()
self.setNavigationTitle()
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(adjustForKeyboard), name: UIResponder.keyboardWillChangeFrameNotification, object: nil)
+// NotificationCenter.default.addObserver(self, selector: #selector(handleShareCountsUpdate), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterShareCountsUpdated), object: nil)
+
changeTheming()
setupHeader()
}
@@ -91,6 +100,50 @@ class NCShareNewUserAddComment: UIViewController, NCShareNavigationTitleSetting
headerView.rightAnchor.constraint(equalTo: headerContainerView.rightAnchor).isActive = true
headerView.setupUI(with: metadata)
}
+
+// @objc private func handleShareCountsUpdate(notification: Notification) {
+// guard let userInfo = notification.userInfo,
+// let links = userInfo["links"] as? Int,
+// let emails = userInfo["emails"] as? Int else {
+// return
+// }
+//
+// updateHeader(linkCount: links, emailCount: emails)
+// }
+//
+// private func updateHeader(linkCount: Int, emailCount: Int) {
+// // If header already exists, just update it
+// if let header = headerContainerView.subviews.first(where: { $0 is NCShareAdvancePermissionHeader }) as? NCShareAdvancePermissionHeader {
+// header.setupUI(with: metadata, linkCount: linkCount, emailCount: emailCount)
+// } else {
+// // Otherwise create and attach
+// setupHeader(linkCount: linkCount, emailCount: emailCount)
+// }
+// }
+//
+// private func setupHeader(linkCount: Int = 0, emailCount: Int = 0) {
+// // Clear old header if any
+// headerContainerView.subviews.forEach { $0.removeFromSuperview() }
+//
+// guard let headerView = Bundle.main.loadNibNamed("NCShareAdvancePermissionHeader", owner: self, options: nil)?
+// .first as? NCShareAdvancePermissionHeader else {
+// return
+// }
+//
+// headerView.ocId = metadata.ocId
+// headerContainerView.addSubview(headerView)
+//
+// headerView.translatesAutoresizingMaskIntoConstraints = false
+// NSLayoutConstraint.activate([
+// headerView.topAnchor.constraint(equalTo: headerContainerView.topAnchor),
+// headerView.bottomAnchor.constraint(equalTo: headerContainerView.bottomAnchor),
+// headerView.leadingAnchor.constraint(equalTo: headerContainerView.leadingAnchor),
+// headerView.trailingAnchor.constraint(equalTo: headerContainerView.trailingAnchor)
+// ])
+//
+// // Initial setup
+// headerView.setupUI(with: metadata, linkCount: linkCount, emailCount: emailCount)
+// }
@IBAction func cancelClicked(_ sender: Any) {
self.navigationController?.popToRootViewController(animated: true)
@@ -99,9 +152,9 @@ class NCShareNewUserAddComment: UIViewController, NCShareNavigationTitleSetting
@IBAction func sendShareClicked(_ sender: Any) {
share.note = commentTextView.text
if isNewShare {
- networking?.createShare(option: share)
+ networking?.createShare(share, downloadLimit: downloadLimit)
} else {
- networking?.updateShare(option: share)
+ networking?.updateShare(share, downloadLimit: downloadLimit)
}
self.navigationController?.popToRootViewController(animated: true)
}
diff --git a/iOSClient/Share/Advanced/NCShareTextInputCell.swift b/iOSClient/Share/Advanced/NCShareTextInputCell.swift
index 26da27ef03..a45ce889ce 100644
--- a/iOSClient/Share/Advanced/NCShareTextInputCell.swift
+++ b/iOSClient/Share/Advanced/NCShareTextInputCell.swift
@@ -14,128 +14,143 @@ class NCShareTextInputCell: XLFormBaseCell, UITextFieldDelegate {
@IBOutlet weak var seperatorBottom: UIView!
@IBOutlet weak var cellTextField: UITextField!
@IBOutlet weak var calendarImageView: UIImageView!
-
+
let datePicker = UIDatePicker()
var expirationDateText: String!
var expirationDate: NSDate!
-
+
override func awakeFromNib() {
super.awakeFromNib()
self.cellTextField.delegate = self
self.cellTextField.isEnabled = true
- calendarImageView.image = UIImage(named: "calender")?.imageColor(NCBrandColor.shared.brandElement)
+ calendarImageView.image = UIImage(named: "calender")?.imageColor(NCBrandColor.shared.brandElement)
self.selectionStyle = .none
self.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
- self.cellTextField.attributedPlaceholder = NSAttributedString(string: "",
- attributes: [NSAttributedString.Key.foregroundColor: NCBrandColor.shared.fileFolderName])
+ self.cellTextField.attributedPlaceholder = NSAttributedString(
+ string: "",
+ attributes: [NSAttributedString.Key.foregroundColor: NCBrandColor.shared.fileFolderName]
+ )
self.cellTextField.textColor = NCBrandColor.shared.singleTitleColorButton
}
-
+
override func configure() {
super.configure()
}
-
+
override func update() {
super.update()
+
calendarImageView.isHidden = rowDescriptor.tag != "NCShareTextInputCellExpiry"
+
if rowDescriptor.tag == "NCShareTextInputCellExpiry" {
seperator.isHidden = true
setDatePicker(sender: self.cellTextField)
} else if rowDescriptor.tag == "NCShareTextInputCellDownloadLimit" {
seperator.isHidden = true
cellTextField.keyboardType = .numberPad
- setDoneButton(sender: self.cellTextField)
+ setDownloadLimitDoneButton(sender: self.cellTextField)
}
}
-
+
+ // MARK: - TextField Delegate
+
func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
- if self.cellTextField == textField {
- if let rowDescriptor = rowDescriptor, let text = self.cellTextField.text {
-
- if (text + " ").isEmpty == false {
- rowDescriptor.value = self.cellTextField.text! + string
- } else {
- rowDescriptor.value = nil
- }
- }
+ if self.cellTextField == textField, let text = self.cellTextField.text {
+ rowDescriptor.value = (text + string).isEmpty ? nil : text + string
}
-
self.formViewController().textField(textField, shouldChangeCharactersIn: range, replacementString: string)
return true
}
-
+
func textFieldDidEndEditing(_ textField: UITextField) {
rowDescriptor.value = cellTextField.text
}
-
+
func textFieldShouldReturn(_ textField: UITextField) -> Bool {
self.formViewController()?.textFieldShouldReturn(textField)
return true
}
-
+
func textFieldShouldClear(_ textField: UITextField) -> Bool {
self.formViewController()?.textFieldShouldClear(textField)
return true
}
-
+
override class func formDescriptorCellHeight(for rowDescriptor: XLFormRowDescriptor!) -> CGFloat {
return 30
}
-
+
override func formDescriptorCellDidSelected(withForm controller: XLFormViewController!) {
self.selectionStyle = .none
}
-
+
+ // MARK: - Date Picker
+
func setDatePicker(sender: UITextField) {
- //Format Date
datePicker.datePickerMode = .date
datePicker.minimumDate = Date.tomorrow
if #available(iOS 13.4, *) {
datePicker.preferredDatePickerStyle = .wheels
datePicker.sizeToFit()
}
- //ToolBar
- let toolbar = UIToolbar();
+
+ let toolbar = UIToolbar()
toolbar.sizeToFit()
- let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .plain, target: self, action: #selector(doneDatePicker));
- let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
- let cancelButton = UIBarButtonItem(title: NSLocalizedString("_cancel_", comment: ""), style: .plain, target: self, action: #selector(cancelDatePicker));
- toolbar.setItems([cancelButton, spaceButton, doneButton], animated: false)
+ let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .plain, target: self, action: #selector(doneDatePicker))
+ let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
+ let clearButton = UIBarButtonItem(title: NSLocalizedString("_clear_", comment: ""), style: .plain, target: self, action: #selector(clearDatePicker))
+ toolbar.setItems([clearButton, spaceButton, doneButton], animated: false)
sender.inputAccessoryView = toolbar
sender.inputView = datePicker
}
-
+
@objc func doneDatePicker() {
- let dateFormatter = DateFormatter()
- dateFormatter.formatterBehavior = .behavior10_4
- dateFormatter.dateStyle = .medium
- dateFormatter.dateFormat = NCShareAdvancePermission.displayDateFormat
-
- var expiryDate = dateFormatter.string(from: datePicker.date)
- expiryDate = expiryDate.replacingOccurrences(of: "..", with: ".")
- self.expirationDateText = expiryDate
-
+// let dateFormatter = DateFormatter()
+// dateFormatter.dateFormat = NCShareAdvancePermission.displayDateFormat
+// var expiryDate = dateFormatter.string(from: datePicker.date)
+// expiryDate = expiryDate.replacingOccurrences(of: "..", with: ".")
+// self.expirationDateText = expiryDate
+// self.expirationDate = datePicker.date as NSDate
+
+ let expiryDateString = DateFormatter.shareExpDate.string(from: datePicker.date)
+ self.expirationDateText = expiryDateString
self.expirationDate = datePicker.date as NSDate
+
self.cellTextField.text = self.expirationDateText
self.rowDescriptor.value = self.expirationDate
self.cellTextField.endEditing(true)
}
- @objc func cancelDatePicker() {
+ @objc func clearDatePicker() {
+ self.expirationDate = nil
+ self.cellTextField.text = ""
+ self.rowDescriptor.value = nil
self.cellTextField.endEditing(true)
}
-
- func setDoneButton(sender: UITextField) {
- //ToolBar
- let toolbar = UIToolbar();
+
+ // MARK: - Download Limit
+
+ func setDownloadLimitDoneButton(sender: UITextField) {
+ let toolbar = UIToolbar()
toolbar.sizeToFit()
- let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .plain, target: self, action: #selector(cancelDatePicker));
- let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
+
+ let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .plain, target: self, action: #selector(doneDownloadLimit))
+ let spaceButton = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
toolbar.setItems([spaceButton, doneButton], animated: false)
+
sender.inputAccessoryView = toolbar
}
+
+ @objc func doneDownloadLimit() {
+ if let text = cellTextField.text, let limit = Int(text) {
+ rowDescriptor.value = limit
+ } else {
+ rowDescriptor.value = 0
+ }
+ cellTextField.endEditing(true)
+ }
}
class NCSeparatorCell: XLFormBaseCell {
@@ -143,9 +158,9 @@ class NCSeparatorCell: XLFormBaseCell {
super.awakeFromNib()
selectionStyle = .none
}
-
+
override func update() {
super.update()
- self.selectionStyle = .none
+ selectionStyle = .none
}
}
diff --git a/iOSClient/Share/CreateLinkFooterView.swift b/iOSClient/Share/CreateLinkFooterView.swift
new file mode 100644
index 0000000000..71e198fe64
--- /dev/null
+++ b/iOSClient/Share/CreateLinkFooterView.swift
@@ -0,0 +1,79 @@
+//
+// CreateLinkFooterView.swift
+// Nextcloud
+//
+// Created by A106551118 on 12/08/25.
+// Copyright © 2025 Marino Faggiana. All rights reserved.
+//
+
+
+import UIKit
+
+class CreateLinkFooterView: UITableViewHeaderFooterView {
+
+ static let reuseIdentifier = "CreateLinkFooterView"
+
+ private let createButton: UIButton = {
+ let button = UIButton(type: .system)
+ button.setTitle(NSLocalizedString("_create_new_link_", comment: ""), for: .normal)
+ button.setTitleColor(UIColor.label, for: .normal)
+// button.setTitleColor(NCBrandColor.shared.shareBlackColor, for: .normal)
+ button.titleLabel?.font = .systemFont(ofSize: 17, weight: .semibold)
+ button.layer.cornerRadius = 7
+ button.layer.borderWidth = 1
+ button.layer.borderColor = NCBrandColor.shared.label.cgColor
+ button.backgroundColor = .clear
+ button.translatesAutoresizingMaskIntoConstraints = false
+ return button
+ }()
+
+ private let separator: UIView = {
+ let view = UIView()
+ view.backgroundColor = .lightGray
+ view.translatesAutoresizingMaskIntoConstraints = false
+ return view
+ }()
+
+ var createButtonAction: (() -> Void)?
+
+ override init(reuseIdentifier: String?) {
+ super.init(reuseIdentifier: reuseIdentifier)
+ setupUI()
+ }
+
+ required init?(coder: NSCoder) {
+ super.init(coder: coder)
+ setupUI()
+ }
+
+ override func layoutSubviews() {
+ super.layoutSubviews()
+ createButton.layer.borderColor = UIColor.label.cgColor
+ }
+
+ private func setupUI() {
+ contentView.backgroundColor = .clear
+
+ contentView.addSubview(createButton)
+ contentView.addSubview(separator)
+
+ NSLayoutConstraint.activate([
+ createButton.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20),
+ createButton.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 15),
+ createButton.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -15),
+ createButton.heightAnchor.constraint(equalToConstant: 40),
+
+ separator.topAnchor.constraint(equalTo: createButton.bottomAnchor, constant: 20),
+ separator.leadingAnchor.constraint(equalTo: contentView.leadingAnchor),
+ separator.trailingAnchor.constraint(equalTo: contentView.trailingAnchor),
+ separator.heightAnchor.constraint(equalToConstant: 1),
+ separator.bottomAnchor.constraint(equalTo: contentView.bottomAnchor) // ensures correct height
+ ])
+
+ createButton.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
+ }
+
+ @objc private func buttonTapped() {
+ createButtonAction?()
+ }
+}
diff --git a/iOSClient/Share/NCPermissions.swift b/iOSClient/Share/NCPermissions.swift
new file mode 100644
index 0000000000..69e84c83e1
--- /dev/null
+++ b/iOSClient/Share/NCPermissions.swift
@@ -0,0 +1,103 @@
+//
+// NCPermissions.swift
+// Nextcloud
+//
+// Created by Marino Faggiana on 05/06/24.
+// Copyright © 2024 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 Foundation
+
+class NCPermissions: NSObject {
+ let permissionShared = "S"
+ let permissionCanShare = "R"
+ let permissionMounted = "M"
+ let permissionFileCanWrite = "W"
+ let permissionCanCreateFile = "C"
+ let permissionCanCreateFolder = "K"
+ let permissionCanDelete = "D"
+ let permissionCanRename = "N"
+ let permissionCanMove = "V"
+
+ // Share permission
+ // permissions - (int) 1 = read; 2 = update; 4 = create; 8 = delete; 16 = share; 31 = all
+ //
+ @objc let permissionReadShare: Int = 1
+ @objc let permissionUpdateShare: Int = 2
+ @objc let permissionCreateShare: Int = 4
+ @objc let permissionDeleteShare: Int = 8
+ @objc let permissionShareShare: Int = 16
+ //
+ let permissionMinFileShare: Int = 1
+ let permissionMaxFileShare: Int = 19
+ let permissionMinFolderShare: Int = 1
+ let permissionMaxFolderShare: Int = 31
+ let permissionDefaultFileRemoteShareNoSupportShareOption: Int = 3
+ let permissionDefaultFolderRemoteShareNoSupportShareOption: Int = 15
+ // ATTRIBUTES
+ let permissionDownloadShare: Int = 0
+
+ func isPermissionToRead(_ permission: Int) -> Bool {
+ return ((permission & permissionReadShare) > 0)
+ }
+ func isPermissionToCanDelete(_ permission: Int) -> Bool {
+ return ((permission & permissionDeleteShare) > 0)
+ }
+ func isPermissionToCanCreate(_ permission: Int) -> Bool {
+ return ((permission & permissionCreateShare) > 0)
+ }
+ func isPermissionToCanChange(_ permission: Int) -> Bool {
+ return ((permission & permissionUpdateShare) > 0)
+ }
+ func isPermissionToCanShare(_ permission: Int) -> Bool {
+ return ((permission & permissionShareShare) > 0)
+ }
+ func isAnyPermissionToEdit(_ permission: Int) -> Bool {
+ let canCreate = isPermissionToCanCreate(permission)
+ let canChange = isPermissionToCanChange(permission)
+ let canDelete = isPermissionToCanDelete(permission)
+ return canCreate || canChange || canDelete
+ }
+ func isPermissionToReadCreateUpdate(_ permission: Int) -> Bool {
+ let canRead = isPermissionToRead(permission)
+ let canCreate = isPermissionToCanCreate(permission)
+ let canChange = isPermissionToCanChange(permission)
+ return canCreate && canChange && canRead
+ }
+ func getPermission(canEdit: Bool, canCreate: Bool, canChange: Bool, canDelete: Bool, canShare: Bool, isDirectory: Bool) -> Int {
+ var permission = permissionReadShare
+
+ if canEdit && !isDirectory {
+ permission = permission + permissionUpdateShare
+ }
+ if canCreate && isDirectory {
+ permission = permission + permissionCreateShare
+ }
+ if canChange && isDirectory {
+ permission = permission + permissionUpdateShare
+ }
+ if canDelete && isDirectory {
+ permission = permission + permissionDeleteShare
+ }
+ if canShare {
+ permission = permission + permissionShareShare
+ }
+ return permission
+ }
+}
diff --git a/iOSClient/Share/NCSearchUserDropDownCell.xib b/iOSClient/Share/NCSearchUserDropDownCell.xib
index 6c2ffde821..f476cfafe9 100755
--- a/iOSClient/Share/NCSearchUserDropDownCell.xib
+++ b/iOSClient/Share/NCSearchUserDropDownCell.xib
@@ -1,9 +1,9 @@
-
+
-
+
@@ -73,12 +73,12 @@
-
+
-
+
diff --git a/iOSClient/Share/NCShare+NCCellDelegate.swift b/iOSClient/Share/NCShare+NCCellDelegate.swift
index 9e8be4757c..412510ed5b 100644
--- a/iOSClient/Share/NCShare+NCCellDelegate.swift
+++ b/iOSClient/Share/NCShare+NCCellDelegate.swift
@@ -29,10 +29,11 @@ extension NCShare: NCShareLinkCellDelegate, NCShareUserCellDelegate {
func copyInternalLink(sender: Any) {
guard let metadata = self.metadata else { return }
- NCNetworking.shared.readFile(serverUrlFileName: metadata.serverUrlFileName, account: metadata.account) { _, metadata, _, error in
+ let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName
+ NCNetworking.shared.readFile(serverUrlFileName: serverUrlFileName, account: metadata.account) { _, metadata, error in
if error == .success, let metadata = metadata {
let internalLink = metadata.urlBase + "/index.php/f/" + metadata.fileId
- NCShareCommon.copyLink(link: internalLink, viewController: self, sender: sender)
+ self.shareCommon.copyLink(link: internalLink, viewController: self, sender: sender)
} else {
NCContentPresenter().showError(error: error)
}
@@ -43,12 +44,11 @@ extension NCShare: NCShareLinkCellDelegate, NCShareUserCellDelegate {
guard let tableShare = tableShare else {
return copyInternalLink(sender: sender)
}
- NCShareCommon.copyLink(link: tableShare.url, viewController: self, sender: sender)
+ shareCommon.copyLink(link: tableShare.url, viewController: self, sender: sender)
}
func tapMenu(with tableShare: tableShare?, sender: Any) {
if let tableShare = tableShare {
-// self.toggleShareMenu(for: tableShare, sender: sender)
self.toggleShareMenu(for: tableShare, sendMail: (tableShare.shareType != NCShareCommon().SHARE_TYPE_LINK), folder: metadata?.directory ?? false, sender: sender)
} else {
self.makeNewLinkShare()
@@ -57,14 +57,12 @@ extension NCShare: NCShareLinkCellDelegate, NCShareUserCellDelegate {
func showProfile(with tableShare: tableShare?, sender: Any) {
guard let tableShare else { return }
- showProfileMenu(userId: tableShare.shareWith, session: session, sender: sender)
+ showProfileMenu(userId: tableShare.shareWith, session: session)
}
func quickStatus(with tableShare: tableShare?, sender: Any) {
- guard let tableShare, let metadata else { return }
- self.toggleQuickPermissionsMenu(isDirectory: metadata.directory, share: tableShare, sender: sender)
-// guard let tableShare = tableShare,
-// let metadata = metadata else { return }
-// self.toggleUserPermissionMenu(isDirectory: metadata.directory, tableShare: tableShare)
+ guard let tableShare = tableShare,
+ let metadata = metadata else { return }
+ self.toggleUserPermissionMenu(isDirectory: metadata.directory, tableShare: tableShare)
}
}
diff --git a/iOSClient/Share/NCShare.storyboard b/iOSClient/Share/NCShare.storyboard
index 85c52dc81f..0c8a27be32 100644
--- a/iOSClient/Share/NCShare.storyboard
+++ b/iOSClient/Share/NCShare.storyboard
@@ -1,10 +1,9 @@
-
+
-
-
+
@@ -238,81 +237,8 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift
index 30cdedb88d..01bca50932 100644
--- a/iOSClient/Share/NCShare.swift
+++ b/iOSClient/Share/NCShare.swift
@@ -30,7 +30,14 @@ import NextcloudKit
import MarqueeLabel
import ContactsUI
-class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent {
+enum ShareSection: Int, CaseIterable {
+ case header
+ case linkByEmail
+ case links
+ case emails
+}
+
+class NCShare: UIViewController, NCSharePagingContent {
var textField: UITextField? { self.view.viewWithTag(Tag.searchField) as? UITextField }
@@ -39,13 +46,13 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
weak var appDelegate = UIApplication.shared.delegate as? AppDelegate
public var metadata: tableMetadata!
+ public var sharingEnabled = true
public var height: CGFloat = 0
+ let shareCommon = NCShareCommon()
let utilityFileSystem = NCUtilityFileSystem()
let utility = NCUtility()
let database = NCManageDatabase.shared
- var shareLinksCount = 0
-
var canReshare: Bool {
return ((metadata.sharePermissionsCollaborationServices & NKShare.Permission.share.rawValue) != 0)
}
@@ -56,11 +63,27 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
var shares: (firstShareLink: tableShare?, share: [tableShare]?) = (nil, nil)
- var capabilities = NKCapabilities.Capabilities()
-
private var dropDown = DropDown()
var networking: NCShareNetworking?
+ var isCurrentUser: Bool {
+ if let currentUser = NCManageDatabase.shared.getActiveTableAccount(), currentUser.userId == metadata?.ownerId {
+ return true
+ }
+ return false
+ }
+ var shareLinks: [tableShare] = []
+ var shareEmails: [tableShare] = []
+ var shareOthers: [tableShare] = []
+ private var cachedHeader: NCShareAdvancePermissionHeader?
+ // Stores the next number per share
+// var nextLinkNumberByShare: [String: Int] = [:]
+//
+// // Stores assigned numbers for each link (per share)
+// var linkNumbersByShare: [String: [String: Int]] = [:]
+
+// var shareLinksCount = 0
+
// MARK: - View Life Cycle
override func viewDidLoad() {
@@ -76,6 +99,12 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
tableView.register(UINib(nibName: "NCShareLinkCell", bundle: nil), forCellReuseIdentifier: "cellLink")
tableView.register(UINib(nibName: "NCShareUserCell", bundle: nil), forCellReuseIdentifier: "cellUser")
tableView.register(UINib(nibName: "NCShareEmailFieldCell", bundle: nil), forCellReuseIdentifier: "NCShareEmailFieldCell")
+ tableView.register(NCShareEmailLinkHeaderView.self,
+ forHeaderFooterViewReuseIdentifier: NCShareEmailLinkHeaderView.reuseIdentifier)
+ tableView.register(CreateLinkFooterView.self, forHeaderFooterViewReuseIdentifier: CreateLinkFooterView.reuseIdentifier)
+ tableView.register(NoSharesFooterView.self, forHeaderFooterViewReuseIdentifier: NoSharesFooterView.reuseIdentifier)
+ tableView.register(UINib(nibName: "NCShareAdvancePermissionHeader", bundle: nil),
+ forHeaderFooterViewReuseIdentifier: NCShareAdvancePermissionHeader.reuseIdentifier)
NotificationCenter.default.addObserver(self, selector: #selector(reloadData), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataNCShare), object: nil)
@@ -95,7 +124,8 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
reloadData()
- networking = NCShareNetworking(metadata: metadata, view: self.view, delegate: self, session: session)
+ networking = NCShareNetworking(metadata: metadata, view: self.view, delegate: self, session: session)
+ if sharingEnabled {
let isVisible = (self.navigationController?.topViewController as? NCSharePaging)?.page == .sharing
networking?.readShare(showLoadingIndicator: isVisible)
@@ -105,6 +135,7 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
}
@objc func exitTapped() {
+ NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUpdateIcons)
self.dismiss(animated: true, completion: nil)
}
@@ -120,103 +151,53 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
}
}
- // Shared with you by ...
- func checkSharedWithYou() {
- guard !metadata.ownerId.isEmpty, metadata.ownerId != session.userId else { return }
-
- if !canReshare {
- searchField.isUserInteractionEnabled = false
- searchField.alpha = 0.5
- searchField.placeholder = NSLocalizedString("_share_reshare_disabled_", comment: "")
- btnContact.isEnabled = false
- }
-
- searchFieldTopConstraint.constant = 45
- sharedWithYouByView.isHidden = false
- sharedWithYouByLabel.text = NSLocalizedString("_shared_with_you_by_", comment: "") + " " + metadata.ownerDisplayName
- sharedWithYouByImage.image = utility.loadUserImage(for: metadata.ownerId, displayName: metadata.ownerDisplayName, urlBase: session.urlBase)
- sharedWithYouByLabel.accessibilityHint = NSLocalizedString("_show_profile_", comment: "")
-
- let shareAction = UITapGestureRecognizer(target: self, action: #selector(openShareProfile(_:)))
- sharedWithYouByImage.addGestureRecognizer(shareAction)
- let shareLabelAction = UITapGestureRecognizer(target: self, action: #selector(openShareProfile(_:)))
- sharedWithYouByLabel.addGestureRecognizer(shareLabelAction)
-
- let fileName = NCSession.shared.getFileName(urlBase: session.urlBase, user: metadata.ownerId)
- let results = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName)
-
- if results.image == nil {
- let etag = self.database.getTableAvatar(fileName: fileName)?.etag
- let fileNameLocalPath = utilityFileSystem.createServerUrl(serverUrl: utilityFileSystem.directoryUserData, fileName: fileName)
-
- NextcloudKit.shared.downloadAvatar(
- user: metadata.ownerId,
- fileNameLocalPath: fileNameLocalPath,
- sizeImage: NCGlobal.shared.avatarSize,
- avatarSizeRounded: NCGlobal.shared.avatarSizeRounded,
- etagResource: etag,
- account: metadata.account) { task in
- Task {
- let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: self.metadata.account,
- path: self.metadata.ownerId,
- name: "downloadAvatar")
- await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task)
- }
- } completion: { _, imageAvatar, _, etag, _, error in
- if error == .success, let etag = etag, let imageAvatar = imageAvatar {
- self.database.addAvatar(fileName: fileName, etag: etag)
- self.sharedWithYouByImage.image = imageAvatar
- self.reloadData()
- } else if error.errorCode == NCGlobal.shared.errorNotModified, let imageAvatar = self.database.setAvatarLoaded(fileName: fileName) {
- self.sharedWithYouByImage.image = imageAvatar
- }
- }
- }
-
- reloadData()
- }
-
// MARK: - Notification Center
- @objc func openShareProfile(_ sender: UITapGestureRecognizer) {
- self.showProfileMenu(userId: metadata.ownerId, session: session, sender: sender.view)
- }
-
@objc func openShareProfile() {
guard let metadata = metadata else { return }
self.showProfileMenu(userId: metadata.ownerId, session: session)
}
+ private func scrollToTopIfNeeded() {
+ if tableView.numberOfSections > 0 && tableView.numberOfRows(inSection: 0) > 0 {
+ self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
+ }
+ }
+
@objc func keyboardWillShow(notification: Notification) {
if UIDevice.current.userInterfaceIdiom == .phone {
- if (UIScreen.main.bounds.width < 374 || UIDevice.current.orientation.isLandscape) {
+ if UIScreen.main.bounds.width < 374 || UIDevice.current.orientation.isLandscape {
if let keyboardSize = (notification.userInfo?[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue)?.cgRectValue {
if view.frame.origin.y == 0 {
- self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
+ scrollToTopIfNeeded()
self.view.frame.origin.y -= keyboardSize.height
}
}
} else if UIScreen.main.bounds.height < 850 {
if view.frame.origin.y == 0 {
- self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
+ scrollToTopIfNeeded()
self.view.frame.origin.y -= 70
}
} else {
if view.frame.origin.y == 0 {
- self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
+ scrollToTopIfNeeded()
self.view.frame.origin.y -= 40
}
}
}
-
+
if UIDevice.current.userInterfaceIdiom == .pad, UIDevice.current.orientation.isLandscape {
if view.frame.origin.y == 0 {
- self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
+ if tableView.numberOfSections > 0 && tableView.numberOfRows(inSection: 0) > 0 {
+ self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
+ }
self.view.frame.origin.y -= 230
}
}
+
textField?.layer.borderColor = NCBrandColor.shared.brand.cgColor
}
+
@objc func keyboardWillHide(notification: Notification) {
if view.frame.origin.y != 0 {
@@ -228,22 +209,293 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
@objc func appWillEnterForeground(notification: Notification) {
reloadData()
}
+
+// @objc private func handleShareCountsUpdate(notification: Notification) {
+// guard let userInfo = notification.userInfo,
+// let links = userInfo["links"] as? Int,
+// let emails = userInfo["emails"] as? Int else { return }
+//
+// if let header = tableView.headerView(forSection: ShareSection.header.rawValue) as? NCShareAdvancePermissionHeader {
+// header.setupUI(with: metadata,
+// linkCount: links,
+// emailCount: emails)
+// } else {
+// let headerSection = IndexSet(integer: ShareSection.header.rawValue)
+// tableView.reloadSections(headerSection, with: .none)
+// }
+// }
+
// MARK: -
@objc func reloadData() {
+ guard let metadata = metadata else {
+ return
+ }
+// shares = (nil, nil) // reset
shares = self.database.getTableShares(metadata: metadata)
- shareLinksCount = 0
-// if let metadata = metadata {
-// shares = self.database.getTableShares(metadata: metadata)
-// }
+ updateShareArrays()
tableView.reloadData()
}
+
+ func updateShareArrays() {
+ shareLinks.removeAll()
+ shareEmails.removeAll()
+
+ guard var allShares = shares.share else { return }
+
+ if let firstLink = shares.firstShareLink {
+ // Remove if already exists to avoid duplication
+ allShares.removeAll { $0.idShare == firstLink.idShare }
+ allShares.insert(firstLink, at: 0)
+ }
+
+ shares.share = allShares
+
+ for item in allShares {
+ if item.shareType == shareCommon.SHARE_TYPE_LINK {
+ shareLinks.append(item)
+ } else {
+ shareEmails.append(item)
+ }
+ }
+ }
+
+
+// func updateShareArrays() {
+// shareLinks.removeAll()
+// shareEmails.removeAll()
+//
+// var allShares = shares.share ?? []
+//
+// if let firstLink = shares.firstShareLink {
+// if let idx = allShares.firstIndex(where: { $0.idShare == firstLink.idShare }) {
+// allShares.remove(at: idx) // only one removal
+// }
+// allShares.insert(firstLink, at: 0)
+// }
+//
+// shares.share = allShares
+//
+// for item in allShares {
+// if item.shareType == shareCommon.SHARE_TYPE_LINK {
+// shareLinks.append(item)
+// } else {
+// shareEmails.append(item)
+// }
+// }
+// }
+
+
+
+
+// func updateShareArrays() {
+// shareLinks.removeAll()
+// shareEmails.removeAll()
+//
+// if let shareLink = shares.firstShareLink {
+// shares.share?.insert(shareLink, at: 0)
+// }
+//
+// guard let allShares = shares.share else { return }
+//
+//// // Use current shareId as the scope
+//// let shareId = metadata?.ocId ?? "0"
+////
+//// // Ensure storage exists for this share
+//// if nextLinkNumberByShare[shareId] == nil {
+//// nextLinkNumberByShare[shareId] = 1
+//// linkNumbersByShare[shareId] = [:]
+//// }
+//
+// for item in allShares {
+// if item.shareType == shareCommon.SHARE_TYPE_LINK {
+// shareLinks.append(item)
+// } else {
+// shareEmails.append(item)
+// }
+// }
+//
+//// // Sort links by assigned number (per-share)
+//// shareLinks.sort { lhs, rhs in
+//// let lhsNum = linkNumbersByShare[shareId]?[String(lhs.idShare)] ?? 0
+//// let rhsNum = linkNumbersByShare[shareId]?[String(rhs.idShare)] ?? 0
+//// return lhsNum < rhsNum
+//// }
+////
+//// // ✅ If this share has no links, reset numbering for it
+//// if shareLinks.isEmpty {
+//// linkNumbersByShare[shareId] = [:]
+//// nextLinkNumberByShare[shareId] = 1
+//// saveLinkNumberData()
+//// }
+//
+//// NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare,
+//// userInfo: ["links": shareLinks.count,
+//// "emails": shareEmails.count])
+// }
+
+// // MARK: - Persistence
+// func saveLinkNumberData() {
+// // Save both maps as UserDefaults property lists
+// UserDefaults.standard.set(linkNumbersByShare, forKey: "linkNumbersByShare")
+// UserDefaults.standard.set(nextLinkNumberByShare, forKey: "nextLinkNumberByShare")
+// }
+//
+// func loadLinkNumberData() {
+// if let savedMap = UserDefaults.standard.dictionary(forKey: "linkNumbersByShare") as? [String: [String: Int]] {
+// linkNumbersByShare = savedMap
+// } else {
+// linkNumbersByShare = [:]
+// }
+//
+// if let savedNext = UserDefaults.standard.dictionary(forKey: "nextLinkNumberByShare") as? [String: Int] {
+// nextLinkNumberByShare = savedNext
+// } else {
+// nextLinkNumberByShare = [:]
+// }
+// }
+//
+// // MARK: - Number Assignment
+//
+// // Assign number to a link (or reuse existing)
+// func assignLinkNumber(forShare shareId: String, linkId: String) -> Int {
+// if nextLinkNumberByShare[shareId] == nil {
+// nextLinkNumberByShare[shareId] = 1
+// linkNumbersByShare[shareId] = [:]
+// }
+//
+// if let number = linkNumbersByShare[shareId]?[linkId] {
+// return number
+// }
+//
+// let nextNum = nextLinkNumberByShare[shareId]!
+// linkNumbersByShare[shareId]?[linkId] = nextNum
+// nextLinkNumberByShare[shareId]! += 1
+// return nextNum
+// }
+//
+// func removeLink(forShare shareId: String, linkId: String) {
+// linkNumbersByShare[shareId]?.removeValue(forKey: linkId)
+//
+// if linkNumbersByShare[shareId]?.isEmpty ?? true {
+// linkNumbersByShare[shareId] = [:]
+// nextLinkNumberByShare[shareId] = 1
+// }
+// }
+
+
+
+// func updateShareArrays() {
+// shareLinks.removeAll()
+// shareEmails.removeAll()
+//
+// if let shareLink = shares.firstShareLink {
+// shares.share?.insert(shareLink, at: 0)
+// }
+//
+// guard let allShares = shares.share else { return }
+//
+// // Use current shareId as the scope
+// let shareId = metadata?.ocId ?? "0"
+//
+// // Ensure storage exists for this share
+// if nextLinkNumberByShare[shareId] == nil {
+// nextLinkNumberByShare[shareId] = 1
+// linkNumbersByShare[shareId] = [:]
+// }
+//
+// for item in allShares {
+// if item.shareType == shareCommon.SHARE_TYPE_LINK {
+// let linkId = String(item.idShare)
+//
+// // Assign a number if missing
+// if linkNumbersByShare[shareId]?[linkId] == nil {
+// let nextNum = nextLinkNumberByShare[shareId] ?? 1
+// linkNumbersByShare[shareId]?[linkId] = nextNum
+// nextLinkNumberByShare[shareId] = nextNum + 1
+// saveLinkNumberData()
+// }
+//// if item.shareType == shareCommon.SHARE_TYPE_LINK { shareLinksCount += 1 }
+//
+// shareLinks.append(item)
+// } else {
+// shareEmails.append(item)
+// }
+// }
+//
+// // Sort links by assigned number (per-share)
+// shareLinks.sort { lhs, rhs in
+// let lhsNum = linkNumbersByShare[shareId]?[String(lhs.idShare)] ?? 0
+// let rhsNum = linkNumbersByShare[shareId]?[String(rhs.idShare)] ?? 0
+// return lhsNum < rhsNum
+// }
+//
+// // ✅ If this share has no links, reset numbering for it
+// if shareLinks.isEmpty {
+// linkNumbersByShare[shareId] = [:]
+// nextLinkNumberByShare[shareId] = 1
+// saveLinkNumberData()
+// }
+//
+//// NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare,
+//// userInfo: ["links": shareLinks.count,
+//// "emails": shareEmails.count])
+// }
+//
+// // MARK: - Persistence
+// func saveLinkNumberData() {
+// // Save both maps as UserDefaults property lists
+// UserDefaults.standard.set(linkNumbersByShare, forKey: "linkNumbersByShare")
+// UserDefaults.standard.set(nextLinkNumberByShare, forKey: "nextLinkNumberByShare")
+// }
+//
+// func loadLinkNumberData() {
+// if let savedMap = UserDefaults.standard.dictionary(forKey: "linkNumbersByShare") as? [String: [String: Int]] {
+// linkNumbersByShare = savedMap
+// } else {
+// linkNumbersByShare = [:]
+// }
+//
+// if let savedNext = UserDefaults.standard.dictionary(forKey: "nextLinkNumberByShare") as? [String: Int] {
+// nextLinkNumberByShare = savedNext
+// } else {
+// nextLinkNumberByShare = [:]
+// }
+// }
+//
+// // MARK: - Number Assignment
+//
+// // Assign number to a link (or reuse existing)
+// func assignLinkNumber(forShare shareId: String, linkId: String) -> Int {
+// if nextLinkNumberByShare[shareId] == nil {
+// nextLinkNumberByShare[shareId] = 1
+// linkNumbersByShare[shareId] = [:]
+// }
+//
+// if let number = linkNumbersByShare[shareId]?[linkId] {
+// return number
+// }
+//
+// let nextNum = nextLinkNumberByShare[shareId]!
+// linkNumbersByShare[shareId]?[linkId] = nextNum
+// nextLinkNumberByShare[shareId]! += 1
+// return nextNum
+// }
+//
+// func removeLink(forShare shareId: String, linkId: String) {
+// linkNumbersByShare[shareId]?.removeValue(forKey: linkId)
+//
+// if linkNumbersByShare[shareId]?.isEmpty ?? true {
+// linkNumbersByShare[shareId] = [:]
+// nextLinkNumberByShare[shareId] = 1
+// }
+// }
// MARK: - IBAction
@IBAction func searchFieldDidEndOnExit(textField: UITextField) {
guard let searchString = textField.text, !searchString.isEmpty else { return }
- if searchString.contains("@"), !utility.isValidEmail(searchString) { return }
+ if searchString.contains("@"), !utility.validateEmail(searchString) { return }
networking?.getSharees(searchString: searchString)
}
@@ -258,23 +510,24 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
}
}
- @objc private func searchSharees() {
- // https://stackoverflow.com/questions/25471114/how-to-validate-an-e-mail-address-in-swift
- func isValidEmail(_ email: String) -> Bool {
-
- let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
- let emailPred = NSPredicate(format: "SELF MATCHES %@", emailRegEx)
- return emailPred.evaluate(with: email)
- }
- guard let searchString = textField?.text, !searchString.isEmpty else { return }
- if searchString.contains("@"), !isValidEmail(searchString) { return }
- networking?.getSharees(searchString: searchString)
- }
+// @objc private func searchSharees() {
+// // https://stackoverflow.com/questions/25471114/how-to-validate-an-e-mail-address-in-swift
+// func isValidEmail(_ email: String) -> Bool {
+//
+// let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
+// let emailPred = NSPredicate(format: "SELF MATCHES %@", emailRegEx)
+// return emailPred.evaluate(with: email)
+// }
+// guard let searchString = textField?.text, !searchString.isEmpty else { return }
+// if searchString.contains("@"), !isValidEmail(searchString) { return }
+// networking?.getSharees(searchString: searchString)
+// }
- @IBAction func createLinkClicked(_ sender: Any) {
+ @IBAction func createLinkClicked(_ sender: Any?) {
appDelegate?.adjust.trackEvent(TriggerEvent(CreateLink.rawValue))
TealiumHelper.shared.trackEvent(title: "magentacloud-app.sharing.create", data: ["": ""])
- self.touchUpInsideButtonMenu(sender)
+// self.touchUpInsideButtonMenu(sender)
+ self.touchUpInsideButtonMenu(sender as Any)
}
@IBAction func touchUpInsideButtonMenu(_ sender: Any) {
@@ -304,6 +557,16 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
}
}
+
+ private func createShareAndReload(password: String) {
+ networking?.createShareLink(password: password)
+
+ // Delay to wait for DB update or async API completion
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
+ self.reloadData()
+ }
+ }
+
@IBAction func selectContactClicked(_ sender: Any) {
let cnPicker = CNContactPickerViewController()
@@ -322,15 +585,6 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
self.present(UIAlertController.password(titleKey: "_enforce_password_protection_", completion: completion), animated: true)
}
-
- @IBAction func selectContactClicked(_ sender: Any) {
- let cnPicker = CNContactPickerViewController()
- cnPicker.delegate = self
- cnPicker.displayedPropertyKeys = [CNContactEmailAddressesKey]
- cnPicker.predicateForEnablingContact = NSPredicate(format: "emailAddresses.@count > 0")
- cnPicker.predicateForSelectionOfProperty = NSPredicate(format: "emailAddresses.@count > 0")
- self.present(cnPicker, animated: true)
- }
}
// MARK: - NCShareNetworkingDelegate
@@ -338,32 +592,37 @@ class NCShare: UIViewController, NCShareNetworkingDelegate, NCSharePagingContent
extension NCShare: NCShareNetworkingDelegate {
func readShareCompleted() {
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare)
- reloadData()
+// self.reloadData()
}
func shareCompleted() {
- NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare)
- reloadData()
+// NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare)
+// self.reloadData()
+ // Allow DB async save to finish before reload
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
+ self.reloadData()
+ }
}
func unShareCompleted() {
-// reloadData()
-// NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataSource)
- NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare)
- self.reloadData()
+// NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare)
+ // Same buffer for consistency
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
+ self.reloadData()
+ }
}
+// func unShareCompleted() {
+// DispatchQueue.main.async {
+// self.reloadData()
+// }
+// }
func updateShareWithError(idShare: Int) {
- reloadData()
+ self.reloadData()
}
func getSharees(sharees: [NKSharee]?) {
- guard let sharees else {
- return
- }
-
- // close keyboard
- self.view.endEditing(true)
+ guard let sharees else { return }
dropDown = DropDown()
let appearance = DropDown.appearance()
@@ -377,18 +636,11 @@ extension NCShare: NCShareNetworkingDelegate {
appearance.textColor = .darkGray
appearance.setupMaskedCorners([.layerMaxXMaxYCorner, .layerMinXMaxYCorner])
- let account = NCManageDatabase.shared.getTableAccount(account: metadata.account)
- let existingShares = NCManageDatabase.shared.getTableShares(metadata: metadata)
-
for sharee in sharees {
- if sharee.shareWith == account?.user { continue } // do not show your own account
- if let shares = existingShares.share, shares.contains(where: {$0.shareWith == sharee.shareWith}) { continue } // do not show already existing sharees
- if metadata.ownerDisplayName == sharee.shareWith { continue } // do not show owner of the share
var label = sharee.label
if sharee.shareType == NKShare.ShareType.team.rawValue {
label += " (\(sharee.circleInfo), \(sharee.circleOwner))"
}
-
dropDown.dataSource.append(label)
}
@@ -456,9 +708,25 @@ extension NCShare: NCShareNetworkingDelegate {
extension NCShare: UITableViewDelegate {
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
-// return 60
- return indexPath.row == 0 ? UITableView.automaticDimension : 60
+ guard let sectionType = ShareSection(rawValue: indexPath.section) else { return 0 }
+
+ switch sectionType {
+ case .header:
+ return 210
+
+ case .linkByEmail:
+ let isPad = UIDevice.current.userInterfaceIdiom == .pad
+ if isCurrentUser {
+ return 130
+ } else {
+ return isPad ? (canReshare ? 200 : 220) : 220
+ }
+
+ case .links, .emails:
+ return 60
+ }
}
+
}
// MARK: - UITableViewDataSource
@@ -466,39 +734,61 @@ extension NCShare: UITableViewDelegate {
extension NCShare: UITableViewDataSource {
func numberOfSections(in tableView: UITableView) -> Int {
- return 1
+ ShareSection.allCases.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
- var numRows = shares.share?.count ?? 0
- if section == 0 {
- if metadata.e2eEncrypted, capabilities.e2EEApiVersion == NCGlobal.shared.e2eeVersionV12 {
- numRows = 1
- } else {
- // don't allow link creation if reshare is disabled
- numRows = shares.firstShareLink != nil || canReshare ? 2 : 1
- }
+ guard let sectionType = ShareSection(rawValue: section) else { return 0 }
+
+ switch sectionType {
+ case .header:
+ return 0
+ case .linkByEmail:
+ return 1
+ case .links:
+ return shareLinks.count
+ case .emails:
+ return shareEmails.count
}
- if let shareLink = shares.firstShareLink {
- shares.share?.insert(shareLink, at: 0)
- }
-
- if shares.share != nil {
- numOfRows = shares.share!.count
- }
- return canReshare ? (numOfRows + 1) : numOfRows
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
-
- if indexPath.row == 0 {
- guard let cell = tableView.dequeueReusableCell(withIdentifier: "NCShareEmailFieldCell", for: indexPath) as? NCShareEmailFieldCell else { return UITableViewCell() }
+ guard let sectionType = ShareSection(rawValue: indexPath.section) else { return UITableViewCell() }
+
+ switch sectionType {
+ case .header:
+ return UITableViewCell() // Empty row
+ case .linkByEmail:
+ guard let cell = tableView.dequeueReusableCell(withIdentifier: "NCShareEmailFieldCell", for: indexPath) as? NCShareEmailFieldCell else {
+ return UITableViewCell()
+ }
cell.searchField.addTarget(self, action: #selector(searchFieldDidEndOnExit(textField:)), for: .editingDidEndOnExit)
cell.searchField.addTarget(self, action: #selector(searchFieldDidChange(textField:)), for: .editingChanged)
- cell.btnCreateLink.addTarget(self, action: #selector(createLinkClicked(_:)), for: .touchUpInside)
cell.btnContact.addTarget(self, action: #selector(selectContactClicked(_:)), for: .touchUpInside)
- cell.labelNoShare.isHidden = (shares.share?.count ?? 0) > 0
- cell.heightLabelNoShare.constant = (shares.share?.count ?? 0) > 0 ? 0 : 25
+ cell.setupCell(with: metadata)
+ return cell
+
+ case .links:
+ let tableShare = shareLinks[indexPath.row]
+ guard let cell = tableView.dequeueReusableCell(withIdentifier: "cellLink", for: indexPath) as? NCShareLinkCell else {
+ return UITableViewCell()
+ }
+ cell.delegate = self
+ if indexPath.row == 0 {
+ cell.configure(with: tableShare, at: indexPath, isDirectory: metadata.directory, title: "")
+ } else {
+ let linkNumber = " \(indexPath.row + 1)"
+ cell.configure(with: tableShare, at: indexPath, isDirectory: metadata.directory, title: linkNumber)
+ }
+ return cell
+
+ case .emails:
+ let tableShare = shareEmails[indexPath.row]
+ guard let cell = tableView.dequeueReusableCell(withIdentifier: "cellUser", for: indexPath) as? NCShareUserCell else {
+ return UITableViewCell()
+ }
+ cell.delegate = self
+ cell.configure(with: tableShare, at: indexPath, isDirectory: metadata.directory, userId: session.userId)
return cell
}
@@ -574,55 +864,92 @@ extension NCShare: UITableViewDataSource {
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
- guard let headerView = Bundle.main.loadNibNamed("NCShareHeaderView", owner: self, options: nil)?.first as? NCShareHeaderView else {
- return UIView()
- }
- headerView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
- headerView.fileName.textColor = NCBrandColor.shared.label
- headerView.labelSharing.textColor = NCBrandColor.shared.label
- headerView.labelSharingInfo.textColor = NCBrandColor.shared.label
- headerView.info.textColor = NCBrandColor.shared.systemGray2
- headerView.ocId = metadata!.ocId
- headerView.updateCanReshareUI()
-
-
- if let image = NCUtility().getImage(ocId: metadata.ocId, etag: metadata.etag, ext: NCGlobal.shared.previewExt1024) {
- headerView.fullWidthImageView.image = image
-// headerView.fullWidthImageView.image = UIImage(contentsOfFile: utilityFileSystem.getDirectoryProviderStorageIconOcId(metadata?.ocId ?? "", etag: metadata?.etag ?? ""))
- headerView.fullWidthImageView.contentMode = .scaleAspectFill
- headerView.imageView.isHidden = true
- } else {
- if metadata?.directory ?? false {
- let image = (metadata?.e2eEncrypted ?? false) ? NCImageCache.shared.getFolderEncrypted() : NCImageCache.shared.getFolder()
- headerView.imageView.image = image
- } else if !(metadata?.iconName.isEmpty ?? false) {
- if let image = UIImage.init(named: metadata!.iconName) {
- headerView.imageView.image = metadata!.fileExtension == "odg" ? UIImage(named: "diagram") : image
- } else {
- headerView.imageView.image = metadata!.fileExtension == "odg" ? UIImage(named: "diagram") : NCUtility().loadImage(named: metadata.iconName, useTypeIconFile: true, account: metadata.account)
- }
- } else {
- headerView.imageView.image = NCImageCache.shared.getImageFile()
+ guard let sectionType = ShareSection(rawValue: section) else { return nil }
+
+ switch sectionType {
+ case .header:
+ let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: NCShareAdvancePermissionHeader.reuseIdentifier) as! NCShareAdvancePermissionHeader
+ headerView.ocId = metadata.ocId
+ headerView.setupUI(with: metadata, linkCount: shareLinks.count, emailCount: shareEmails.count)
+ return headerView
+
+ case .linkByEmail:
+ return nil
+
+ case .links:
+ if isCurrentUser || canReshare {
+ let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "NCShareEmailLinkHeaderView") as! NCShareEmailLinkHeaderView
+ headerView.configure(text: NSLocalizedString("_share_copy_link_", comment: ""))
+ return headerView
}
+ return nil
+
+ case .emails:
+ if (isCurrentUser || canReshare) && numberOfRows(in: section) > 0 {
+ let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "NCShareEmailLinkHeaderView") as! NCShareEmailLinkHeaderView
+ headerView.configure(text: NSLocalizedString("_share_shared_with_", comment: ""))
+ return headerView
+ }
+ return nil
}
-
- headerView.fileName.text = metadata?.fileNameView
- headerView.fileName.textColor = NCBrandColor.shared.label
- if metadata!.favorite {
- headerView.favorite.setImage(utility.loadImage(named: "star.fill", colors: [NCBrandColor.shared.yellowFavorite], size: 24), for: .normal)
- } else {
- headerView.favorite.setImage(utility.loadImage(named: "star.fill", colors: [NCBrandColor.shared.textInfo], size: 24), for: .normal)
+ }
+
+ func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
+ guard let sectionType = ShareSection(rawValue: section) else { return 0 }
+
+ switch sectionType {
+ case .header:
+ return 190
+ case .linkByEmail:
+ return 0
+ case .links:
+ return (isCurrentUser || canReshare) ? 44 : 0
+ case .emails:
+ return ((isCurrentUser || canReshare) && numberOfRows(in: section) > 0) ? 44 : 0
}
- headerView.info.text = utilityFileSystem.transformedSize(metadata!.size) + ", " + utility.dateDiff(metadata!.date as Date)
- return headerView
-
}
- func tableView(_ tableView: UITableView, estimatedHeightForHeaderInSection section: Int) -> CGFloat {
- return metadata?.ownerId != session?.userId ? canReshare ? 400 : 350 : 320
+
+ func tableView(_ tableView: UITableView, viewForFooterInSection section: Int) -> UIView? {
+ guard isCurrentUser || canReshare,
+ let sectionType = ShareSection(rawValue: section) else {
+ return nil
+ }
+
+ switch sectionType {
+ case .links:
+ let footer = tableView.dequeueReusableHeaderFooterView(withIdentifier: CreateLinkFooterView.reuseIdentifier) as! CreateLinkFooterView
+ footer.createButtonAction = { [weak self] in
+ self?.createLinkClicked(nil)
+ }
+ return footer
+
+ case .emails:
+ if numberOfRows(in: section) == 0 {
+ return tableView.dequeueReusableHeaderFooterView(withIdentifier: NoSharesFooterView.reuseIdentifier)
+ }
+ return nil
+ case .header, .linkByEmail:
+ return nil
+ }
}
- func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
- return metadata?.ownerId != session?.userId ? canReshare ? UITableView.automaticDimension : 350 : 320
+
+ func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
+ guard isCurrentUser || canReshare,
+ let sectionType = ShareSection(rawValue: section) else {
+ return 0.001
+ }
+
+ switch sectionType {
+ case .links:
+ return 80
+ case .emails:
+ return numberOfRows(in: section) == 0 ? 100 : 80
+ case .header, .linkByEmail:
+ return 0.001
+ }
}
+
+
}
//MARK: CNContactPickerDelegate
@@ -630,7 +957,7 @@ extension NCShare: UITableViewDataSource {
extension NCShare: CNContactPickerDelegate {
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
if contact.emailAddresses.count > 1 {
- showEmailList(arrEmail: contact.emailAddresses.map({$0.value as String}), sender: picker)
+ showEmailList(arrEmail: contact.emailAddresses.map({$0.value as String}))
} else if let email = contact.emailAddresses.first?.value as? String {
textField?.text = email
networking?.getSharees(searchString: email)
@@ -650,7 +977,6 @@ extension NCShare: CNContactPickerDelegate {
icon: utility.loadImage(named: "email").imageColor(NCBrandColor.shared.brandElement),
selected: false,
on: false,
- sender: sender,
action: { _ in
self.textField?.text = email
self.networking?.getSharees(searchString: email)
@@ -659,7 +985,7 @@ extension NCShare: CNContactPickerDelegate {
)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
- self.presentMenu(with: actions, sender: sender)
+ self.presentMenu(with: actions)
}
}
}
@@ -668,25 +994,27 @@ extension NCShare: CNContactPickerDelegate {
extension NCShare: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
- NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(searchSharees(_:)), object: nil)
+ NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(searchSharees), object: nil)
if searchText.isEmpty {
dropDown.hide()
} else {
- perform(#selector(searchSharees(_:)), with: nil, afterDelay: 1)
+ perform(#selector(searchSharees), with: nil, afterDelay: 0.5)
}
}
- @objc private func searchSharees(_ sender: Any?) {
- // https://stackoverflow.com/questions/25471114/how-to-validate-an-e-mail-address-in-swift
+ @objc private func searchSharees() {
+// // https://stackoverflow.com/questions/25471114/how-to-validate-an-e-mail-address-in-swift
func isValidEmail(_ email: String) -> Bool {
+// let emailRegEx = "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-\\u00a1-\\uffff]+\\.[A-Za-z\\u00a1-\\uffff]{2,64}$"
let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailPred = NSPredicate(format: "SELF MATCHES %@", emailRegEx)
return emailPred.evaluate(with: email)
}
- guard let searchString = searchField.text, !searchString.isEmpty else { return }
- if searchString.contains("@"), !isValidEmail(searchString) { return }
+ guard let searchString = textField?.text, !searchString.isEmpty else { return }
+ if searchString.contains("@"), !utility.validateEmail(searchString) { return }
networking?.getSharees(searchString: searchString)
}
+
}
diff --git a/iOSClient/Share/NCShareCommentsCell.swift b/iOSClient/Share/NCShareCommentsCell.swift
index 59cdf78c81..b537f6559d 100644
--- a/iOSClient/Share/NCShareCommentsCell.swift
+++ b/iOSClient/Share/NCShareCommentsCell.swift
@@ -54,8 +54,9 @@ class NCShareCommentsCell: UITableViewCell, NCCellProtocol {
override func awakeFromNib() {
super.awakeFromNib()
- let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapAvatarImage(_:)))
+ let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapAvatarImage))
imageItem?.addGestureRecognizer(tapGesture)
+ buttonMenu.setImage(UIImage(named: "shareMenu")!.image(color: .lightGray, size: 50), for: .normal)
}
@objc func tapAvatarImage(_ sender: UITapGestureRecognizer) {
diff --git a/iOSClient/Share/NCShareCommon.swift b/iOSClient/Share/NCShareCommon.swift
index 702ad9b592..4d99e3b93f 100644
--- a/iOSClient/Share/NCShareCommon.swift
+++ b/iOSClient/Share/NCShareCommon.swift
@@ -27,8 +27,25 @@ import NextcloudKit
enum NCShareCommon {
static let itemTypeFile = "file"
static let itemTypeFolder = "folder"
+}
+
+class NCShareCommon: NSObject {
+
+ // swiftlint:disable identifier_name
+ let SHARE_TYPE_USER = 0
+ let SHARE_TYPE_GROUP = 1
+ let SHARE_TYPE_LINK = 3
+ let SHARE_TYPE_EMAIL = 4
+ let SHARE_TYPE_CONTACT = 5
+ let SHARE_TYPE_REMOTE = 6
+ let SHARE_TYPE_CIRCLE = 7
+ let SHARE_TYPE_GUEST = 8
+ let SHARE_TYPE_REMOTE_GROUP = 9
+ let SHARE_TYPE_ROOM = 10
+ // swiftlint:enable identifier_name
+
+ func createLinkAvatar(imageName: String, colorCircle: UIColor) -> UIImage? {
- static func createLinkAvatar(imageName: String, colorCircle: UIColor) -> UIImage? {
let size: CGFloat = 200
let bottomImage = UIImage(named: "circle_fill")!.image(color: colorCircle, size: size / 2)
@@ -42,7 +59,7 @@ enum NCShareCommon {
return image
}
- static func copyLink(link: String, viewController: UIViewController, sender: Any) {
+ func copyLink(link: String, viewController: UIViewController, sender: Any) {
let objectsToShare = [link]
let activityViewController = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
diff --git a/iOSClient/Share/NCShareEmailFieldCell.swift b/iOSClient/Share/NCShareEmailFieldCell.swift
index c39be3b210..7b8643fe08 100644
--- a/iOSClient/Share/NCShareEmailFieldCell.swift
+++ b/iOSClient/Share/NCShareEmailFieldCell.swift
@@ -7,83 +7,169 @@
//
import UIKit
+import MarqueeLabel
+import NextcloudKit
enum Tag {
static let searchField = 999
}
class NCShareEmailFieldCell: UITableViewCell {
+
@IBOutlet weak var searchField: UITextField!
- @IBOutlet weak var btnCreateLink: UIButton!
- @IBOutlet weak var labelYourShare: UILabel!
- @IBOutlet weak var labelShareByMail: UILabel!
+ @IBOutlet weak var labelOrLink: UILabel!
@IBOutlet weak var btnContact: UIButton!
- @IBOutlet weak var labelNoShare: UILabel!
- @IBOutlet weak var heightLabelNoShare: NSLayoutConstraint!
-
+ @IBOutlet weak var labelSeparator1: UILabel!
+ @IBOutlet weak var labelSeparator2: UILabel!
+ @IBOutlet weak var labelSendLinkByMail: UILabel!
+ @IBOutlet weak var labelSharedWithBy: UILabel!
+ @IBOutlet weak var labelResharingAllowed: UILabel!
+ @IBOutlet weak var topConstraintResharingView: NSLayoutConstraint!
+ @IBOutlet weak var viewOrLinkSeparator: UIView!
+
+ var ocId = ""
+
override func awakeFromNib() {
super.awakeFromNib()
- // Initialization code
- setupCell()
}
-
+
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
-
- // Configure the view for the selected state
}
-
- func setupCell(){
- self.btnCreateLink.setTitle(NSLocalizedString("_create_link_", comment: ""), for: .normal)
- self.btnCreateLink.layer.cornerRadius = 7
- self.btnCreateLink.layer.masksToBounds = true
- self.btnCreateLink.layer.borderWidth = 1
- self.btnCreateLink.titleLabel?.font = UIFont.systemFont(ofSize: 17)
- self.btnCreateLink.titleLabel!.adjustsFontSizeToFitWidth = true
- self.btnCreateLink.titleLabel!.minimumScaleFactor = 0.5
- self.btnCreateLink.layer.borderColor = NCBrandColor.shared.label.cgColor
- self.btnCreateLink.setTitleColor(NCBrandColor.shared.label, for: .normal)
- self.btnCreateLink.backgroundColor = .clear
-
- self.labelShareByMail.text = NSLocalizedString("personal_share_by_mail", comment: "")
- self.labelShareByMail.textColor = NCBrandColor.shared.shareByEmailTextColor
-
- labelYourShare.text = NSLocalizedString("_your_shares_", comment: "")
+
+ func setupCell(with metadata: tableMetadata) {
+ contentView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+ ocId = metadata.ocId
+
+ configureSearchField()
+ configureContactButton()
+ configureLabels()
+ updateCanReshareUI()
+ setNeedsLayout()
+ layoutIfNeeded()
+ }
+
+ private func configureSearchField() {
searchField.layer.cornerRadius = 5
searchField.layer.masksToBounds = true
searchField.layer.borderWidth = 1
- self.searchField.text = ""
- searchField.attributedPlaceholder = NSAttributedString(string: NSLocalizedString("_shareLinksearch_placeholder_", comment: ""),
- attributes: [NSAttributedString.Key.foregroundColor: NCBrandColor.shared.gray60])
- searchField.textColor = NCBrandColor.shared.label
searchField.layer.borderColor = NCBrandColor.shared.label.cgColor
+ searchField.text = ""
+ searchField.textColor = NCBrandColor.shared.label
+ searchField.attributedPlaceholder = NSAttributedString(
+ string: NSLocalizedString("_shareLinksearch_placeholder_", comment: ""),
+ attributes: [.foregroundColor: NCBrandColor.shared.gray60]
+ )
searchField.tag = Tag.searchField
setDoneButton(sender: searchField)
-
+ }
+
+ private func configureContactButton() {
btnContact.layer.cornerRadius = 5
btnContact.layer.masksToBounds = true
btnContact.layer.borderWidth = 1
btnContact.layer.borderColor = NCBrandColor.shared.label.cgColor
btnContact.tintColor = NCBrandColor.shared.label
- btnContact.setImage(NCUtility().loadImage(named: "contact").image(color: NCBrandColor.shared.label, size: 24), for: .normal)
- labelNoShare.textColor = NCBrandColor.shared.textInfo
- labelNoShare.numberOfLines = 0
- labelNoShare.font = UIFont.systemFont(ofSize: 17)
- labelNoShare.text = NSLocalizedString("no_shares_created", comment: "")
+ let contactImage = NCUtility().loadImage(named: "contact").image(color: NCBrandColor.shared.label, size: 24)
+ btnContact.setImage(contactImage, for: .normal)
}
-
+
+ private func configureLabels() {
+ labelOrLink.text = NSLocalizedString("_share_or_", comment: "")
+ labelSendLinkByMail.text = NSLocalizedString("_share_send_link_by_mail_", comment: "")
+ labelSharedWithBy.text = NSLocalizedString("_share_received_shares_text_", comment: "")
+ labelResharingAllowed.text = NSLocalizedString("_share_reshare_allowed_", comment: "")
+
+ labelSendLinkByMail.textColor = NCBrandColor.shared.label
+ labelSharedWithBy.textColor = NCBrandColor.shared.label
+ labelResharingAllowed.textColor = NCBrandColor.shared.label
+ }
+
+ func updateCanReshareUI() {
+ guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return }
+
+ let isCurrentUser = NCShareCommon().isCurrentUserIsFileOwner(fileOwnerId: metadata.ownerId)
+ let canReshare = (metadata.sharePermissionsCollaborationServices & NCPermissions().permissionShareShare) != 0
+
+ labelSharedWithBy.isHidden = isCurrentUser
+ labelResharingAllowed.isHidden = isCurrentUser
+
+ if !canReshare {
+ searchField.isUserInteractionEnabled = false
+ searchField.alpha = 0.5
+ btnContact.isEnabled = false
+ btnContact.alpha = 0.5
+ }
+
+ if !isCurrentUser {
+ let ownerName = metadata.ownerDisplayName
+ let fullText = NSLocalizedString("_share_received_shares_text_", comment: "") + " " + ownerName
+ let attributed = NSMutableAttributedString(string: fullText)
+
+ if let range = fullText.range(of: ownerName) {
+ let nsRange = NSRange(range, in: fullText)
+ attributed.addAttribute(.font, value: UIFont.boldSystemFont(ofSize: 16), range: nsRange)
+ }
+
+ labelSharedWithBy.attributedText = attributed
+ labelSharedWithBy.numberOfLines = 0
+
+ labelResharingAllowed.text = canReshare
+ ? NSLocalizedString("_share_reshare_allowed_", comment: "")
+ : NSLocalizedString("_share_reshare_not_allowed_", comment: "")
+
+ topConstraintResharingView.constant = 15
+ } else {
+ topConstraintResharingView.constant = 0
+ }
+
+ viewOrLinkSeparator.isHidden = !canReshare
+ }
+
+ func updateShareUI(ocId: String, count: Int) {
+ guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return }
+
+ let isCurrentUser = NCShareCommon().isCurrentUserIsFileOwner(fileOwnerId: metadata.ownerId)
+ let canReshare = (metadata.sharePermissionsCollaborationServices & NCPermissions().permissionShareShare) != 0
+
+ if !isCurrentUser {
+ if canReshare {
+ labelOrLink.isHidden = true
+ labelSeparator1.isHidden = true
+ labelSeparator2.isHidden = true
+ }
+ }
+ }
+
@objc func cancelDatePicker() {
self.searchField.endEditing(true)
}
-
- func setDoneButton(sender: UITextField) {
- //ToolBar
- let toolbar = UIToolbar();
+
+ private func setDoneButton(sender: UITextField) {
+ let toolbar = UIToolbar()
toolbar.sizeToFit()
- let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .plain, target: self, action: #selector(cancelDatePicker));
- let spaceButton = UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil)
- toolbar.setItems([spaceButton, doneButton], animated: false)
+ let doneButton = UIBarButtonItem(
+ title: NSLocalizedString("_done_", comment: ""),
+ style: .plain,
+ target: self,
+ action: #selector(cancelDatePicker)
+ )
+ let space = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
+ toolbar.setItems([space, doneButton], animated: false)
sender.inputAccessoryView = toolbar
}
+
+ @IBAction func touchUpInsideFavorite(_ sender: UIButton) {
+ // Hook for favorite action if needed
+ }
+
+ @IBAction func touchUpInsideDetails(_ sender: UIButton) {
+ // Hook for toggling detail visibility if needed
+ }
+
+ @objc func longTap(_ sender: UIGestureRecognizer) {
+ let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_copied_path_")
+ NCContentPresenter().showInfo(error: error)
+ }
}
diff --git a/iOSClient/Share/NCShareEmailFieldCell.xib b/iOSClient/Share/NCShareEmailFieldCell.xib
index 72cbdfe2d3..cfeb42cc45 100644
--- a/iOSClient/Share/NCShareEmailFieldCell.xib
+++ b/iOSClient/Share/NCShareEmailFieldCell.xib
@@ -1,9 +1,9 @@
-
+
-
+
@@ -11,112 +11,161 @@
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
-
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
+
diff --git a/iOSClient/Share/NCShareEmailLinkHeaderView.swift b/iOSClient/Share/NCShareEmailLinkHeaderView.swift
new file mode 100644
index 0000000000..9502164891
--- /dev/null
+++ b/iOSClient/Share/NCShareEmailLinkHeaderView.swift
@@ -0,0 +1,43 @@
+//
+// NCShareEmailLinkHeaderView.swift
+// Nextcloud
+//
+// Created by A106551118 on 12/08/25.
+// Copyright © 2025 Marino Faggiana. All rights reserved.
+//
+
+import UIKit
+
+class NCShareEmailLinkHeaderView: UITableViewHeaderFooterView {
+ private let label = UILabel()
+ static let reuseIdentifier = "NCShareEmailLinkHeaderView"
+
+ override init(reuseIdentifier: String?) {
+ super.init(reuseIdentifier: reuseIdentifier)
+ setup()
+ }
+
+ required init?(coder: NSCoder) {
+ super.init(coder: coder)
+ setup()
+ }
+
+ private func setup() {
+ contentView.backgroundColor = .clear
+ label.translatesAutoresizingMaskIntoConstraints = false
+ label.font = .systemFont(ofSize: 17, weight: .semibold)
+ label.textColor = NCBrandColor.shared.textColor
+ contentView.addSubview(label)
+
+ NSLayoutConstraint.activate([
+ label.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20),
+ label.heightAnchor.constraint(equalToConstant: 30),
+ label.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 15),
+ label.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -15),
+ ])
+ }
+
+ func configure(text: String) {
+ label.text = text
+ }
+}
diff --git a/iOSClient/Share/NCShareHeader.swift b/iOSClient/Share/NCShareHeader.swift
index 4556a74516..905a05159c 100644
--- a/iOSClient/Share/NCShareHeader.swift
+++ b/iOSClient/Share/NCShareHeader.swift
@@ -23,12 +23,15 @@
import UIKit
-class NCShareAdvancePermissionHeader: UIView {
+class NCShareAdvancePermissionHeader: UITableViewHeaderFooterView {
@IBOutlet weak var imageView: UIImageView!
@IBOutlet weak var fileName: UILabel!
@IBOutlet weak var info: UILabel!
@IBOutlet weak var favorite: UIButton!
@IBOutlet weak var fullWidthImageView: UIImageView!
+
+ static let reuseIdentifier = "NCShareAdvancePermissionHeader"
+
var ocId = ""
let utility = NCUtility()
let utilityFileSystem = NCUtilityFileSystem()
@@ -40,25 +43,76 @@ class NCShareAdvancePermissionHeader: UIView {
fullWidthImageView.contentMode = .scaleAspectFill
imageView.isHidden = true
} else {
- if metadata.directory {
- imageView.image = metadata.e2eEncrypted ? NCImageCache.shared.getFolderEncrypted() : NCImageCache.shared.getFolder()
+ imageView.isHidden = false
+ if metadata.e2eEncrypted {
+ imageView.image = NCImageCache.shared.getFolderEncrypted()
+ } else if isShare {
+ imageView.image = NCImageCache.shared.getFolderSharedWithMe()
+ } else if !metadata.shareType.isEmpty {
+ imageView.image = metadata.shareType.contains(3)
+ ? NCImageCache.shared.getFolderPublic()
+ : NCImageCache.shared.getFolderSharedWithMe()
+ } else if metadata.directory {
+ imageView.image = NCImageCache.shared.getFolder()
} else if !metadata.iconName.isEmpty {
imageView.image = NCUtility().loadImage(named: metadata.iconName, useTypeIconFile: true, account: metadata.account)
} else {
imageView.image = NCImageCache.shared.getImageFile()
}
}
- favorite.setNeedsUpdateConstraints()
- favorite.layoutIfNeeded()
+
fileName.text = metadata.fileNameView
fileName.textColor = NCBrandColor.shared.fileFolderName
- if metadata.favorite {
- favorite.setImage(utility.loadImage(named: "star.fill", colors: [NCBrandColor.shared.yellowFavorite], size: 24), for: .normal)
+
+ updateFavoriteIcon(isFavorite: metadata.favorite)
+ info.text = utilityFileSystem.transformedSize(metadata.size) + ", " + utility.getRelativeDateTitle(metadata.date as Date)
+ }
+
+ func setupUI(with metadata: tableMetadata, linkCount: Int, emailCount: Int) {
+ contentView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+ fileName.textColor = NCBrandColor.shared.label
+ info.textColor = NCBrandColor.shared.textInfo
+
+// let isShare = metadata.permissions.contains(NCPermissions().permissionShared)
+ let hasShares = (linkCount > 0 || emailCount > 0)
+
+ if let image = NCUtility().getImage(ocId: metadata.ocId,
+ etag: metadata.etag,
+ ext: NCGlobal.shared.previewExt1024) {
+ fullWidthImageView.image = image
+ fullWidthImageView.contentMode = .scaleAspectFill
+ imageView.isHidden = true
} else {
- favorite.setImage(utility.loadImage(named: "star.fill", colors: [NCBrandColor.shared.textInfo], size: 24), for: .normal)
+ imageView.isHidden = false
+ if metadata.e2eEncrypted {
+ imageView.image = NCImageCache.shared.getFolderEncrypted()
+ } else if hasShares {
+ imageView.image = NCImageCache.shared.getFolderSharedWithMe()
+ } else if !metadata.shareType.isEmpty {
+ imageView.image = metadata.shareType.contains(3)
+ ? NCImageCache.shared.getFolderPublic()
+ : NCImageCache.shared.getFolderSharedWithMe()
+ } else if metadata.directory {
+ imageView.image = NCImageCache.shared.getFolder()
+ } else if !metadata.iconName.isEmpty {
+ imageView.image = NCUtility().loadImage(named: metadata.iconName,
+ useTypeIconFile: true,
+ account: metadata.account)
+ } else {
+ imageView.image = NCImageCache.shared.getImageFile()
+ }
}
- info.textColor = NCBrandColor.shared.optionItem
- info.text = utilityFileSystem.transformedSize(metadata.size) + ", " + utility.dateDiff(metadata.date as Date)
+
+ fileName.text = metadata.fileNameView
+ fileName.textColor = NCBrandColor.shared.fileFolderName
+
+ updateFavoriteIcon(isFavorite: metadata.favorite)
+ info.text = utilityFileSystem.transformedSize(metadata.size) + ", " + utility.getRelativeDateTitle(metadata.date as Date)
+ }
+
+ private func updateFavoriteIcon(isFavorite: Bool) {
+ let color = isFavorite ? NCBrandColor.shared.yellowFavorite : NCBrandColor.shared.textInfo
+ favorite.setImage(utility.loadImage(named: "star.fill", colors: [color], size: 24), for: .normal)
}
@IBAction func touchUpInsideFavorite(_ sender: UIButton) {
@@ -66,11 +120,7 @@ class NCShareAdvancePermissionHeader: UIView {
NCNetworking.shared.favoriteMetadata(metadata) { error in
if error == .success {
guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(metadata.ocId) else { return }
- if metadata.favorite {
- self.favorite.setImage(self.utility.loadImage(named: "star.fill", colors: [NCBrandColor.shared.yellowFavorite], size: 24), for: .normal)
- } else {
- self.favorite.setImage(self.utility.loadImage(named: "star.fill", colors: [NCBrandColor.shared.textInfo], size: 24), for: .normal)
- }
+ self.updateFavoriteIcon(isFavorite: metadata.favorite)
} else {
NCContentPresenter().showError(error: error)
}
diff --git a/iOSClient/Share/NCShareHeader.xib b/iOSClient/Share/NCShareHeader.xib
index 55ffce6cab..69ae9e03bd 100644
--- a/iOSClient/Share/NCShareHeader.xib
+++ b/iOSClient/Share/NCShareHeader.xib
@@ -1,131 +1,128 @@
-
-
+
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/iOSClient/Share/NCShareLinkCell.swift b/iOSClient/Share/NCShareLinkCell.swift
index 989d28ae47..058922bea1 100644
--- a/iOSClient/Share/NCShareLinkCell.swift
+++ b/iOSClient/Share/NCShareLinkCell.swift
@@ -24,32 +24,27 @@ import UIKit
import NextcloudKit
class NCShareLinkCell: UITableViewCell {
- @IBOutlet private weak var imageItem: UIImageView!
- @IBOutlet private weak var labelTitle: UILabel!
- @IBOutlet private weak var descriptionLabel: UILabel!
+ @IBOutlet weak var labelTitle: UILabel!
+ @IBOutlet weak var buttonDetail: UIButton!
+ @IBOutlet weak var buttonCopy: UIButton!
+ @IBOutlet weak var btnQuickStatus: UIButton!
+ @IBOutlet weak var imagePermissionType: UIImageView!
+ @IBOutlet weak var imageExpiredDateSet: UIImageView!
+ @IBOutlet weak var imagePasswordSet: UIImageView!
+ @IBOutlet weak var imageAllowedPermission: UIImageView!
+ @IBOutlet weak var imageRightArrow: UIImageView!
@IBOutlet weak var labelQuickStatus: UILabel!
- @IBOutlet weak var statusStackView: UIStackView!
- @IBOutlet private weak var menuButton: UIButton!
- @IBOutlet private weak var copyButton: UIButton!
- @IBOutlet weak var imageDownArrow: UIImageView!
-
-// @IBOutlet weak var imageItem: UIImageView!
-// @IBOutlet weak var labelTitle: UILabel!
-// @IBOutlet weak var buttonCopy: UIButton!
-// @IBOutlet weak var buttonMenu: UIButton!
-// @IBOutlet weak var status: UILabel!
-// @IBOutlet weak var btnQuickStatus: UIButton!
-// @IBOutlet weak var imageDownArrow: UIImageView!
-// @IBOutlet weak var labelQuickStatus: UILabel!
-
- private let iconShare: CGFloat = 200
- var tableShare: tableShare?
- var isDirectory = false
+ @IBOutlet weak var leadingContraintofImageRightArrow: NSLayoutConstraint!
+
+ private let iconShareSize: CGFloat = 200
+
weak var delegate: NCShareLinkCellDelegate?
+
+ var tableShare: tableShare?
var isInternalLink = false
+ var isDirectory = false
var indexPath = IndexPath()
- let utility = NCUtility()
override func prepareForReuse() {
super.prepareForReuse()
@@ -128,44 +123,84 @@ class NCShareLinkCell: UITableViewCell {
override func awakeFromNib() {
super.awakeFromNib()
- buttonMenu.contentMode = .scaleAspectFill
- imageItem.image = UIImage(named: "sharebylink")?.image(color: NCBrandColor.shared.label, size: 30)
- buttonCopy.setImage(UIImage.init(named: "shareCopy")!.image(color: NCBrandColor.shared.customer, size: 24), for: .normal)
- buttonMenu.setImage(UIImage.init(named: "shareMenu")!.image(color: NCBrandColor.shared.customer, size: 24), for: .normal)
- labelQuickStatus.textColor = NCBrandColor.shared.customer
+ setupCellAppearance()
}
- func setupCellUI() {
- let permissions = NCPermissions()
- guard let tableShare = tableShare else {
- return
+ override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
+ super.traitCollectionDidChange(previousTraitCollection)
+ if previousTraitCollection?.userInterfaceStyle != traitCollection.userInterfaceStyle {
+ setupCellAppearance()
}
+ }
+
+ func configure(with share: tableShare?, at indexPath: IndexPath, isDirectory: Bool, title: String) {
+ self.tableShare = share
+ self.indexPath = indexPath
+ self.isDirectory = isDirectory
+ setupCellAppearance(titleAppendString: title)
+
+// let shareLinksCountString = shareLinksCount > 0 ? String(shareLinksCount) : ""
+// setupCellAppearance(titleAppendString: shareLinksCountString)
+// setupCellAppearance(titleAppendString: String(shareLinksCount))
+ }
+
+ private func setupCellAppearance(titleAppendString: String? = nil) {
contentView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
labelTitle.textColor = NCBrandColor.shared.label
-
- if tableShare.permissions == permissions.permissionCreateShare {
- labelQuickStatus.text = NSLocalizedString("_share_file_drop_", comment: "")
- } else {
- // Read Only
- if permissions.isAnyPermissionToEdit(tableShare.permissions) {
- labelQuickStatus.text = NSLocalizedString("_share_editing_", comment: "")
+ labelQuickStatus.textColor = NCBrandColor.shared.shareBlueColor
+
+ buttonDetail.setTitleColor(NCBrandColor.shared.shareBlackColor, for: .normal)
+ buttonCopy.setImage(UIImage(named: "share")?.image(color: NCBrandColor.shared.brand, size: 24), for: .normal)
+
+ imageRightArrow.image = UIImage(named: "rightArrow")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ imageExpiredDateSet.image = UIImage(named: "calenderNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ imagePasswordSet.image = UIImage(named: "lockNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
+
+ buttonDetail.setTitle(NSLocalizedString("_share_details_", comment: ""), for: .normal)
+ labelTitle.text = NSLocalizedString("_share_link_", comment: "")
+
+ if let tableShare = tableShare, let titleAppendString {
+ if !tableShare.label.isEmpty {
+ labelTitle.text? += " (\(tableShare.label))"
} else {
- labelQuickStatus.text = NSLocalizedString("_share_read_only_", comment: "")
+ labelTitle.text?.append(" \(titleAppendString)")
}
}
+ updatePermissionUI()
}
-
+
+ private func updatePermissionUI() {
+ guard let tableShare = tableShare else { return }
+
+ let permissions = NCPermissions()
+
+ if tableShare.permissions == permissions.permissionCreateShare {
+ labelQuickStatus.text = NSLocalizedString("_share_quick_permission_everyone_can_just_upload_", comment: "")
+ imagePermissionType.image = UIImage(named: "upload")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ } else if permissions.isAnyPermissionToEdit(tableShare.permissions) {
+ labelQuickStatus.text = NSLocalizedString("_share_quick_permission_everyone_can_edit_", comment: "")
+ imagePermissionType.image = UIImage(named: "editNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ } else {
+ labelQuickStatus.text = NSLocalizedString("_share_quick_permission_everyone_can_only_view_", comment: "")
+ imagePermissionType.image = UIImage(named: "showPasswordNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ }
+
+ imagePasswordSet.isHidden = tableShare.password.isEmpty
+ imageExpiredDateSet.isHidden = (tableShare.expirationDate == nil)
+
+ leadingContraintofImageRightArrow.constant = (imagePasswordSet.isHidden && imageExpiredDateSet.isHidden) ? 0 : 5
+ }
+
+ // MARK: - Actions
+
@IBAction func touchUpInsideCopy(_ sender: Any) {
delegate?.tapCopy(with: tableShare, sender: sender)
}
-
- @IBAction func touchUpInsideMenu(_ sender: Any) {
+
+ @IBAction func touchUpInsideDetail(_ sender: Any) {
delegate?.tapMenu(with: tableShare, sender: sender)
}
- @objc func openQuickStatus(_ sender: UITapGestureRecognizer) {
- }
-
@IBAction func quickStatusClicked(_ sender: UIButton) {
delegate?.quickStatus(with: tableShare, sender: sender)
}
diff --git a/iOSClient/Share/NCShareLinkCell.xib b/iOSClient/Share/NCShareLinkCell.xib
index d5810a5294..9783995c5e 100755
--- a/iOSClient/Share/NCShareLinkCell.xib
+++ b/iOSClient/Share/NCShareLinkCell.xib
@@ -1,149 +1,152 @@
-
+
-
-
-
+
-
-
+
+
-
-
+
+
-
-
+
+
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/iOSClient/Share/NCShareNetworking.swift b/iOSClient/Share/NCShareNetworking.swift
index 19eee06f2b..1fde2ec34b 100644
--- a/iOSClient/Share/NCShareNetworking.swift
+++ b/iOSClient/Share/NCShareNetworking.swift
@@ -36,10 +36,245 @@ class NCShareNetworking: NSObject {
self.view = view
self.delegate = delegate
self.session = session
-
super.init()
}
+// private func readDownloadLimit(account: String, token: String) async throws -> NKDownloadLimit? {
+// return try await withCheckedThrowingContinuation { continuation in
+// NextcloudKit.shared.getDownloadLimit(account: account, token: token) { limit, error in
+// if error != .success {
+// continuation.resume(throwing: error.error)
+// return
+// } else {
+// continuation.resume(returning: limit)
+// }
+// }
+// }
+// }
+//
+// func readDownloadLimits(account: String, tokens: [String]) async throws {
+// for token in tokens {
+// self.database.deleteDownloadLimit(byAccount: account, shareToken: token)
+// if let downloadLimit = try await readDownloadLimit(account: account, token: token) {
+// self.database.createDownloadLimit(account: account, count: downloadLimit.count, limit: downloadLimit.limit, token: token)
+// }
+// }
+// }
+
+ // MARK: - Read
+ func readShare(showLoadingIndicator: Bool) {
+ if showLoadingIndicator {
+ NCActivityIndicator.shared.start(backgroundView: view)
+ }
+ let filenamePath = utilityFileSystem.getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, session: session)
+ let parameter = NKShareParameter(path: filenamePath)
+
+ NextcloudKit.shared.readShares(parameters: parameter, account: metadata.account) { account, shares, _, error in
+ if error == .success, let shares = shares {
+ self.database.deleteTableShare(account: account, path: "/" + filenamePath)
+ let home = self.utilityFileSystem.getHomeServer(session: self.session)
+ self.database.addShare(account: self.metadata.account, home: home, shares: shares)
+
+ NextcloudKit.shared.getGroupfolders(account: account) { account, results, _, error in
+ if showLoadingIndicator {
+ NCActivityIndicator.shared.stop()
+ }
+ if error == .success, let groupfolders = results {
+ self.database.addGroupfolders(account: account, groupfolders: groupfolders)
+ }
+
+ Task {
+ try await self.readDownloadLimits(account: account, tokens: shares.map(\.token))
+ self.delegate?.readShareCompleted()
+ }
+ }
+ } else {
+ if showLoadingIndicator {
+ NCActivityIndicator.shared.stop()
+ }
+ NCContentPresenter().showError(error: error)
+ self.delegate?.readShareCompleted()
+ }
+ }
+ }
+
+ // MARK: - Create Share Link
+ func createShareLink(password: String?) {
+ NCActivityIndicator.shared.start(backgroundView: view)
+ let filenamePath = utilityFileSystem.getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, session: session)
+
+ NextcloudKit.shared.createShareLink(path: filenamePath, account: metadata.account) { [weak self] account, share, _, error in
+ guard let self = self else { return }
+ NCActivityIndicator.shared.stop()
+
+ if error == .success, let share = share {
+ let home = self.utilityFileSystem.getHomeServer(session: self.session)
+ self.database.addShare(account: self.metadata.account, home: home, shares: [share])
+
+ if !self.metadata.contentType.contains("directory") {
+ AnalyticsHelper.shared.trackEventWithMetadata(eventName: .EVENT__SHARE_FILE, metadata: self.metadata)
+ }
+
+ NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDidCreateShareLink)
+ // 🔄 ensure we sync DB + UI with server
+ self.readShare(showLoadingIndicator: false)
+ } else {
+ NCContentPresenter().showError(error: error)
+ }
+
+ self.delegate?.shareCompleted()
+ }
+ }
+
+ // MARK: - Create Share (user/email/group)
+ func createShare(_ shareable: Shareable, downloadLimit: DownloadLimitViewModel) {
+ NCActivityIndicator.shared.start(backgroundView: view)
+ let filenamePath = utilityFileSystem.getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, session: session)
+
+ NextcloudKit.shared.createShare(
+ path: filenamePath,
+ shareType: shareable.shareType,
+ shareWith: shareable.shareWith,
+ password: shareable.password,
+ note: shareable.note,
+ permissions: shareable.permissions,
+ attributes: shareable.attributes,
+ account: metadata.account
+ ) { [weak self] _, share, _, error in
+ guard let self = self else { return }
+ NCActivityIndicator.shared.stop()
+
+ if error == .success, let share = share {
+ shareable.idShare = share.idShare
+ let home = self.utilityFileSystem.getHomeServer(session: self.session)
+ self.database.addShare(account: self.metadata.account, home: home, shares: [share])
+
+ let directory = self.metadata.directory
+
+ if shareable.hasChanges(comparedTo: share) {
+ self.updateShare(shareable, downloadLimit: downloadLimit)
+ // Download limit update should happen implicitly on share update.
+ } else {
+ if share.shareType == NCShareCommon().SHARE_TYPE_LINK && !directory {
+ if case let .limited(limit, _) = downloadLimit, NCCapabilities.shared.getCapabilities(account: self.metadata.account).capabilityFileSharingDownloadLimit {
+ self.setShareDownloadLimit(limit, token: share.token)
+ }
+ }
+ }
+
+ if !self.metadata.contentType.contains("directory") {
+ AnalyticsHelper.shared.trackEventWithMetadata(eventName: .EVENT__SHARE_FILE, metadata: self.metadata)
+ }
+
+ NotificationCenter.default.postOnMainThread(
+ name: NCGlobal.shared.notificationCenterUpdateShare,
+ userInfo: ["account": self.metadata.account, "serverUrl": self.metadata.serverUrl]
+ )
+ // 🔄 ensure consistency
+ self.readShare(showLoadingIndicator: false)
+ } else {
+ NCContentPresenter().showError(error: error)
+ }
+
+ self.delegate?.shareCompleted()
+ }
+ }
+
+ // MARK: - Unshare
+ func unShare(idShare: Int) {
+ NCActivityIndicator.shared.start(backgroundView: view)
+ NextcloudKit.shared.deleteShare(idShare: idShare, account: metadata.account) { [weak self] account, _, error in
+ guard let self = self else { return }
+ NCActivityIndicator.shared.stop()
+
+ if error == .success {
+ self.database.deleteTableShare(account: account, idShare: idShare)
+ self.delegate?.unShareCompleted()
+
+ NotificationCenter.default.postOnMainThread(
+ name: NCGlobal.shared.notificationCenterUpdateShare,
+ userInfo: ["account": self.metadata.account, "serverUrl": self.metadata.serverUrl]
+ )
+ // 🔄 reload to avoid missing/duplicate shares
+ self.readShare(showLoadingIndicator: false)
+ } else {
+ NCContentPresenter().showError(error: error)
+ }
+ }
+ }
+
+ // MARK: - Update Share
+ func updateShare(_ shareable: Shareable, downloadLimit: DownloadLimitViewModel) {
+ NCActivityIndicator.shared.start(backgroundView: view)
+ NextcloudKit.shared.updateShare(
+ idShare: shareable.idShare,
+ password: shareable.password,
+ expireDate: shareable.formattedDateString,
+ permissions: shareable.permissions,
+ note: shareable.note,
+ label: shareable.label,
+ hideDownload: shareable.hideDownload,
+ attributes: shareable.attributes,
+ account: metadata.account
+ ) { [weak self] _, share, _, error in
+ guard let self = self else { return }
+ NCActivityIndicator.shared.stop()
+
+ if error == .success, let share = share {
+ let home = self.utilityFileSystem.getHomeServer(session: self.session)
+ self.database.addShare(account: self.metadata.account, home: home, shares: [share])
+ self.delegate?.readShareCompleted()
+
+ let directory = self.metadata.directory
+
+// if capabilities.fileSharingDownloadLimit,
+// shareable.shareType == NCShareCommon.shareTypeLink,
+// shareable.itemType == NCShareCommon.itemTypeFile {
+ if share.shareType == NCShareCommon().SHARE_TYPE_LINK && !directory{
+ if NCCapabilities.shared.getCapabilities(account: self.metadata.account).capabilityFileSharingDownloadLimit {
+ if case let .limited(limit, _) = downloadLimit {
+ self.setShareDownloadLimit(limit, token: share.token)
+ } else {
+ self.removeShareDownloadLimit(token: share.token)
+ }
+ }
+ }
+
+ NotificationCenter.default.postOnMainThread(
+ name: NCGlobal.shared.notificationCenterUpdateShare,
+ userInfo: ["account": self.metadata.account, "serverUrl": self.metadata.serverUrl]
+ )
+ NotificationCenter.default.postOnMainThread(
+ name: NCGlobal.shared.notificationCenterReloadDataNCShare
+ )
+ // 🔄 refresh again from server
+ self.readShare(showLoadingIndicator: false)
+ } else {
+ NCContentPresenter().showError(error: error)
+ self.delegate?.updateShareWithError(idShare: shareable.idShare)
+ }
+ }
+ }
+
+ func getSharees(searchString: String) {
+ NCActivityIndicator.shared.start(backgroundView: view)
+ NextcloudKit.shared.searchSharees(search: searchString, account: metadata.account) { _, sharees, _, error in
+ NCActivityIndicator.shared.stop()
+
+ if error == .success {
+ self.delegate?.getSharees(sharees: sharees)
+ } else {
+ NCContentPresenter().showError(error: error)
+ self.delegate?.getSharees(sharees: nil)
+ }
+ }
+ }
+
+ // MARK: - Download Limit
+
+ ///
+ /// Remove the download limit on the share, if existent.
+ ///
private func readDownloadLimit(account: String, token: String) async throws -> NKDownloadLimit? {
return try await withCheckedThrowingContinuation { continuation in
NextcloudKit.shared.getDownloadLimit(account: account, token: token) { limit, error in
@@ -287,17 +522,12 @@ class NCShareNetworking: NSObject {
/// Remove the download limit on the share, if existent.
///
func removeShareDownloadLimit(token: String) {
- let capabilities = NCNetworking.shared.capabilities[self.metadata.account] ?? NKCapabilities.Capabilities()
-
- if !capabilities.fileSharingDownloadLimit || token.isEmpty {
+ if !NCCapabilities.shared.getCapabilities(account: self.metadata.account).capabilityFileSharingDownloadLimit || token.isEmpty {
return
}
-
NCActivityIndicator.shared.start(backgroundView: view)
-
NextcloudKit.shared.removeShareDownloadLimit(account: metadata.account, token: token) { error in
NCActivityIndicator.shared.stop()
-
if error == .success {
self.delegate?.downloadLimitRemoved(by: token)
} else {
@@ -306,23 +536,13 @@ class NCShareNetworking: NSObject {
}
}
- ///
- /// Set the download limit for the share.
- ///
- /// - Parameter limit: The new download limit to set.
- ///
func setShareDownloadLimit(_ limit: Int, token: String) {
- let capabilities = NCNetworking.shared.capabilities[self.metadata.account] ?? NKCapabilities.Capabilities()
-
- if !capabilities.fileSharingDownloadLimit || token.isEmpty {
+ if !NCCapabilities.shared.getCapabilities(account: self.metadata.account).capabilityFileSharingDownloadLimit || token.isEmpty {
return
}
-
NCActivityIndicator.shared.start(backgroundView: view)
-
NextcloudKit.shared.setShareDownloadLimit(account: metadata.account, token: token, limit: limit) { error in
NCActivityIndicator.shared.stop()
-
if error == .success {
self.delegate?.downloadLimitSet(to: limit, by: token)
} else {
diff --git a/iOSClient/Share/NCSharePaging.swift b/iOSClient/Share/NCSharePaging.swift
index 6fa56b56f6..6f5b91d89b 100644
--- a/iOSClient/Share/NCSharePaging.swift
+++ b/iOSClient/Share/NCSharePaging.swift
@@ -106,12 +106,7 @@ class NCSharePaging: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
-
- navigationController?.setNavigationBarAppearance()
-
- let capabilities = NCNetworking.shared.capabilities[metadata.account] ?? NKCapabilities.Capabilities()
-
- if !capabilities.fileSharingApiEnabled && !capabilities.filesComments && capabilities.activity.isEmpty {
+ if NCCapabilities.shared.disableSharesView(account: metadata.account) {
self.dismiss(animated: false, completion: nil)
}
@@ -166,7 +161,7 @@ class NCSharePaging: UIViewController {
view.frame.origin.y = 0
}
- @objc func exitTapped(_ sender: Any?) {
+ @objc func exitTapped() {
self.dismiss(animated: true, completion: nil)
}
@@ -178,6 +173,7 @@ class NCSharePaging: UIViewController {
// MARK: - PagingViewController Delegate
extension NCSharePaging: PagingViewControllerDelegate {
+
func pagingViewController(_ pagingViewController: PagingViewController, willScrollToItem pagingItem: PagingItem, startingViewController: UIViewController, destinationViewController: UIViewController) {
currentVC?.textField?.resignFirstResponder()
@@ -188,6 +184,7 @@ extension NCSharePaging: PagingViewControllerDelegate {
// MARK: - PagingViewController DataSource
extension NCSharePaging: PagingViewControllerDataSource {
+
func pagingViewController(_: PagingViewController, viewControllerAt index: Int) -> UIViewController {
let height: CGFloat = 50
@@ -233,9 +230,14 @@ extension NCSharePaging: PagingViewControllerDataSource {
// MARK: - Header
class NCShareHeaderViewController: PagingViewController {
+
public var image: UIImage?
public var metadata = tableMetadata()
+ public var activityEnabled = true
+ public var commentsEnabled = true
+ public var sharingEnabled = true
+
override func loadView() {
view = NCSharePagingView(
options: options,
@@ -264,6 +266,7 @@ class NCSharePagingView: PagingView {
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
+
}
class NCShareHeaderView: UIView {
@@ -285,8 +288,6 @@ class NCShareHeaderView: UIView {
override func awakeFromNib() {
super.awakeFromNib()
- let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(longTap(_:)))
- path.addGestureRecognizer(longGesture)
setupUI()
}
@@ -337,15 +338,4 @@ class NCShareHeaderView: UIView {
}
}
}
-
- @IBAction func touchUpInsideDetails(_ sender: UIButton) {
- creation.isHidden = !creation.isHidden
- upload.isHidden = !upload.isHidden
- }
-
- @objc func longTap(_ sender: UIGestureRecognizer) {
- UIPasteboard.general.string = path.text
- let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_copied_path_")
- NCContentPresenter().showInfo(error: error)
- }
}
diff --git a/iOSClient/Share/NCShareUserCell.swift b/iOSClient/Share/NCShareUserCell.swift
index 8a9cc3a74a..b5fed3c8fa 100644
--- a/iOSClient/Share/NCShareUserCell.swift
+++ b/iOSClient/Share/NCShareUserCell.swift
@@ -26,27 +26,29 @@ import NextcloudKit
class NCShareUserCell: UITableViewCell, NCCellProtocol {
- @IBOutlet weak var imageItem: UIImageView!
+ // MARK: - IBOutlets
@IBOutlet weak var labelTitle: UILabel!
@IBOutlet weak var buttonMenu: UIButton!
- @IBOutlet weak var imageStatus: UIImageView!
- @IBOutlet weak var status: UILabel!
@IBOutlet weak var btnQuickStatus: UIButton!
@IBOutlet weak var labelQuickStatus: UILabel!
- @IBOutlet weak var imageDownArrow: UIImageView!
- @IBOutlet weak var labelCanEdit: UILabel!
- @IBOutlet weak var switchCanEdit: UISwitch!
- private var index = IndexPath()
-
+ @IBOutlet weak var imagePermissionType: UIImageView!
+ @IBOutlet weak var imageRightArrow: UIImageView!
+ @IBOutlet weak var imageExpiredDateSet: UIImageView!
+ @IBOutlet weak var imagePasswordSet: UIImageView!
+ @IBOutlet weak var imageAllowedPermission: UIImageView!
+ @IBOutlet weak var leadingContraintofImageRightArrow: NSLayoutConstraint!
+
+ // MARK: - Properties
+ private var indexPathInternal = IndexPath()
var tableShare: tableShare?
- var isDirectory = false
- let utility = NCUtility()
+ var isDirectory: Bool = false
weak var delegate: NCShareUserCellDelegate?
var indexPath: IndexPath {
- get { return index }
- set { index = newValue }
+ get { indexPathInternal }
+ set { indexPathInternal = newValue }
}
+
var fileUser: String? {
get { return tableShare?.shareWith }
set {}
@@ -157,20 +159,93 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol {
override func awakeFromNib() {
super.awakeFromNib()
- let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapAvatarImage(_:)))
- imageItem?.addGestureRecognizer(tapGesture)
- buttonMenu.setImage(UIImage.init(named: "shareMenu")!.image(color: NCBrandColor.shared.customer, size: 24), for: .normal)
+ setupCellUIAppearance()
+ }
+
+ override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
+ super.traitCollectionDidChange(previousTraitCollection)
+ if previousTraitCollection?.userInterfaceStyle != traitCollection.userInterfaceStyle {
+ setupCellUIAppearance()
+ }
+ }
+
+ // MARK: - Configure
+ func configure(with share: tableShare?, at indexPath: IndexPath, isDirectory: Bool, userId: String) {
+ self.indexPath = indexPath
+ self.tableShare = share
+ self.isDirectory = isDirectory
+ setupCellUI(userId: userId)
+ }
+
+ // MARK: - UI Setup
+ private func setupCellUIAppearance() {
+ contentView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
buttonMenu.contentMode = .scaleAspectFill
- labelQuickStatus.textColor = NCBrandColor.shared.customer
- imageDownArrow.image = UIImage(named: "downArrow")?.imageColor(NCBrandColor.shared.customer)
- switchCanEdit.transform = CGAffineTransform(scaleX: 0.75, y: 0.75)
- switchCanEdit.onTintColor = NCBrandColor.shared.brandElement
+ buttonMenu.setImage(NCImageCache.images.buttonMore.image(color: NCBrandColor.shared.brand, size: 24), for: .normal)
+ labelQuickStatus.textColor = NCBrandColor.shared.shareBlueColor
+ labelTitle.textColor = NCBrandColor.shared.label
+ imageRightArrow.image = UIImage(named: "rightArrow")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ imageExpiredDateSet.image = UIImage(named: "calenderNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ imagePasswordSet.image = UIImage(named: "lockNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
+
+ imagePermissionType.image = imagePermissionType.image?.imageColor(NCBrandColor.shared.shareBlueColor)
+ updatePermissionUI()
}
- @objc func tapAvatarImage(_ sender: UITapGestureRecognizer) {
- delegate?.showProfile(with: tableShare, sender: sender)
+ private func updatePermissionUI() {
+ guard let tableShare = tableShare else { return }
+
+ let permissions = NCPermissions()
+
+ if tableShare.permissions == permissions.permissionCreateShare {
+ labelQuickStatus.text = NSLocalizedString("_share_quick_permission_everyone_can_just_upload_", comment: "")
+ imagePermissionType.image = UIImage(named: "upload")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ } else if permissions.isAnyPermissionToEdit(tableShare.permissions) {
+ labelQuickStatus.text = NSLocalizedString("_share_quick_permission_everyone_can_edit_", comment: "")
+ imagePermissionType.image = UIImage(named: "editNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ } else {
+ labelQuickStatus.text = NSLocalizedString("_share_quick_permission_everyone_can_only_view_", comment: "")
+ imagePermissionType.image = UIImage(named: "showPasswordNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ }
+
+ imagePasswordSet.isHidden = tableShare.password.isEmpty
+ imageExpiredDateSet.isHidden = (tableShare.expirationDate == nil)
+
+ leadingContraintofImageRightArrow.constant = (imagePasswordSet.isHidden && imageExpiredDateSet.isHidden) ? 0 : 5
}
+ private func setupCellUI(userId: String) {
+ guard let tableShare = tableShare else { return }
+
+ let permissions = NCPermissions()
+ labelTitle.text = tableShare.shareWithDisplayname
+
+ let isOwner = tableShare.uidOwner == userId || tableShare.uidFileOwner == userId
+ isUserInteractionEnabled = isOwner
+ buttonMenu.isHidden = !isOwner
+ buttonMenu.accessibilityLabel = NSLocalizedString("_more_", comment: "")
+
+ btnQuickStatus.setTitle("", for: .normal)
+ btnQuickStatus.isEnabled = true
+ btnQuickStatus.accessibilityHint = NSLocalizedString("_user_sharee_footer_", comment: "")
+ btnQuickStatus.contentHorizontalAlignment = .left
+
+ setupCellUIAppearance()
+// let permissionValue = tableShare.permissions
+//
+// if permissionValue == permissions.permissionCreateShare {
+// labelQuickStatus.text = NSLocalizedString("_share_quick_permission_everyone_can_just_upload_", comment: "")
+// imagePermissionType.image = UIImage(named: "upload")?.imageColor(NCBrandColor.shared.shareBlueColor)
+// } else if permissions.isAnyPermissionToEdit(permissionValue) {
+// labelQuickStatus.text = NSLocalizedString("_share_quick_permission_everyone_can_edit_", comment: "")
+// imagePermissionType.image = UIImage(named: "editNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
+// } else {
+// labelQuickStatus.text = NSLocalizedString("_share_quick_permission_everyone_can_only_view_", comment: "")
+// imagePermissionType.image = UIImage(named: "showPasswordNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
+// }
+ }
+
+ // MARK: - Actions
@IBAction func touchUpInsideMenu(_ sender: Any) {
delegate?.tapMenu(with: tableShare, sender: sender)
}
@@ -178,6 +253,10 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol {
@IBAction func quickStatusClicked(_ sender: Any) {
delegate?.quickStatus(with: tableShare, sender: sender)
}
+
+ @objc func tapAvatarImage(_ sender: UITapGestureRecognizer) {
+ delegate?.showProfile(with: tableShare, sender: sender)
+ }
}
protocol NCShareUserCellDelegate: AnyObject {
@@ -186,32 +265,35 @@ protocol NCShareUserCellDelegate: AnyObject {
func quickStatus(with tableShare: tableShare?, sender: Any)
}
-// MARK: - NCSearchUserDropDownCell
-
class NCSearchUserDropDownCell: DropDownCell, NCCellProtocol {
@IBOutlet weak var imageItem: UIImageView!
@IBOutlet weak var imageStatus: UIImageView!
- @IBOutlet weak var status: UILabel!
+ @IBOutlet weak var statusLabel: UILabel!
@IBOutlet weak var imageShareeType: UIImageView!
- @IBOutlet weak var centerTitle: NSLayoutConstraint!
+ @IBOutlet weak var centerTitleConstraint: NSLayoutConstraint!
+
+ private var userIdentifier: String = ""
+ private var currentIndexPath = IndexPath()
- private var user: String = ""
- private var index = IndexPath()
- private let utilityFileSystem = NCUtilityFileSystem()
+ // MARK: - NCCellProtocol
var indexPath: IndexPath {
- get { return index }
- set { index = newValue }
+ get { currentIndexPath }
+ set { currentIndexPath = newValue }
}
+
var fileAvatarImageView: UIImageView? {
- return imageItem
+ imageItem
}
+
var fileUser: String? {
- get { return user }
- set { user = newValue ?? "" }
+ get { userIdentifier }
+ set { userIdentifier = newValue ?? "" }
}
+ // MARK: - Setup
+
func setupCell(sharee: NKSharee, session: NCSession.Session) {
let utility = NCUtility()
imageItem.image = NCShareCommon.getImageShareType(shareType: sharee.shareType)
@@ -226,36 +308,7 @@ class NCSearchUserDropDownCell: DropDownCell, NCCellProtocol {
centerTitle.constant = 0
}
- imageItem.image = utility.loadUserImage(for: sharee.shareWith, displayName: nil, urlBase: session.urlBase)
-
- let fileName = NCSession.shared.getFileName(urlBase: session.urlBase, user: sharee.shareWith)
- let results = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName)
-
- if results.image == nil {
- let etag = NCManageDatabase.shared.getTableAvatar(fileName: fileName)?.etag
- let fileNameLocalPath = utilityFileSystem.createServerUrl(serverUrl: utilityFileSystem.directoryUserData, fileName: fileName)
-
- NextcloudKit.shared.downloadAvatar(
- user: sharee.shareWith,
- fileNameLocalPath: fileNameLocalPath,
- sizeImage: NCGlobal.shared.avatarSize,
- avatarSizeRounded: NCGlobal.shared.avatarSizeRounded,
- etagResource: etag,
- account: session.account) { task in
- Task {
- let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: session.account,
- path: sharee.shareWith,
- name: "downloadAvatar")
- await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task)
- }
- } completion: { _, imageAvatar, _, etag, _, error in
- if error == .success, let etag = etag, let imageAvatar = imageAvatar {
- NCManageDatabase.shared.addAvatar(fileName: fileName, etag: etag)
- self.imageItem.image = imageAvatar
- } else if error.errorCode == NCGlobal.shared.errorNotModified, let imageAvatar = NCManageDatabase.shared.setAvatarLoaded(fileName: fileName) {
- self.imageItem.image = imageAvatar
- }
- }
- }
+ statusLabel.text = userStatus.statusMessage
+ centerTitleConstraint.constant = (statusLabel.text?.isEmpty == false) ? -5 : 0
}
}
diff --git a/iOSClient/Share/NoSharesFooterView.swift b/iOSClient/Share/NoSharesFooterView.swift
new file mode 100644
index 0000000000..636b319a83
--- /dev/null
+++ b/iOSClient/Share/NoSharesFooterView.swift
@@ -0,0 +1,63 @@
+//
+// NoSharesFooterView.swift
+// Nextcloud
+//
+// Created by A106551118 on 12/08/25.
+// Copyright © 2025 Marino Faggiana. All rights reserved.
+//
+
+
+import UIKit
+
+class NoSharesFooterView: UITableViewHeaderFooterView {
+
+ static let reuseIdentifier = "NoSharesFooterView"
+
+ private let titleLabel: UILabel = {
+ let label = UILabel()
+ label.font = .systemFont(ofSize: 17, weight: .semibold)
+ label.textColor = NCBrandColor.shared.textColor
+ label.text = NSLocalizedString("_share_shared_with_", comment: "")
+ label.translatesAutoresizingMaskIntoConstraints = false
+ return label
+ }()
+
+ private let infoLabel: UILabel = {
+ let label = UILabel()
+ label.font = .systemFont(ofSize: 15, weight: .regular)
+ label.textColor = NCBrandColor.shared.textColor
+ label.text = NSLocalizedString("_share_no_shares_text_", comment: "")
+ label.numberOfLines = 0
+ label.lineBreakMode = .byWordWrapping
+ label.translatesAutoresizingMaskIntoConstraints = false
+ return label
+ }()
+
+ override init(reuseIdentifier: String?) {
+ super.init(reuseIdentifier: reuseIdentifier)
+ setupUI()
+ }
+
+ required init?(coder: NSCoder) {
+ super.init(coder: coder)
+ setupUI()
+ }
+
+ private func setupUI() {
+ contentView.backgroundColor = .clear
+ contentView.addSubview(titleLabel)
+ contentView.addSubview(infoLabel)
+
+ NSLayoutConstraint.activate([
+ titleLabel.topAnchor.constraint(equalTo: contentView.topAnchor, constant: 20),
+ titleLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 15),
+ titleLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -15),
+ titleLabel.heightAnchor.constraint(equalToConstant: 25),
+
+ infoLabel.topAnchor.constraint(equalTo: titleLabel.bottomAnchor, constant: 15),
+ infoLabel.leadingAnchor.constraint(equalTo: contentView.leadingAnchor, constant: 15),
+ infoLabel.trailingAnchor.constraint(equalTo: contentView.trailingAnchor, constant: -15),
+ infoLabel.bottomAnchor.constraint(equalTo: contentView.bottomAnchor)
+ ])
+ }
+}
diff --git a/iOSClient/Share/ShareDownloadLimitNetwork.swift b/iOSClient/Share/ShareDownloadLimitNetwork.swift
index 9fadc08515..118bd538d0 100644
--- a/iOSClient/Share/ShareDownloadLimitNetwork.swift
+++ b/iOSClient/Share/ShareDownloadLimitNetwork.swift
@@ -22,9 +22,13 @@ class NMCCommunication: NSObject, XMLParserDelegate {
var foundCharacters = "";
var downloadLimit = DownloadLimit()
private lazy var appDelegate = UIApplication.shared.delegate as? AppDelegate
+ var controller: NCMainTabBarController!
+ var session: NCSession.Session {
+ NCSession.shared.getSession(controller: controller)
+ }
func getDownloadLimit(token: String, completion: @escaping (_ downloadLimit: DownloadLimit?, _ errorDescription: String) -> Void) {
- let baseUrl = appDelegate?.urlBase ?? "" // NCBrandOptions.shared.loginBaseUrl
+ let baseUrl = session.urlBase // NCBrandOptions.shared.loginBaseUrl
let endPoint = "/ocs/v2.php/apps/files_downloadlimit/\(token)/limit"
let path = baseUrl+endPoint
do {
@@ -62,7 +66,7 @@ class NMCCommunication: NSObject, XMLParserDelegate {
}
func setDownloadLimit(deleteLimit: Bool, limit: String, token: String, completion: @escaping (_ success: Bool, _ errorDescription: String) -> Void) {
- let baseUrl = appDelegate?.urlBase ?? "" //NCBrandOptions.shared.loginBaseUrl
+ let baseUrl = session.urlBase //NCBrandOptions.shared.loginBaseUrl
let endPoint = "/ocs/v2.php/apps/files_downloadlimit/\(token)/limit"
let path = baseUrl+endPoint
do {
@@ -108,8 +112,8 @@ class NMCCommunication: NSObject, XMLParserDelegate {
}
public func authorizationToken() -> String {
- let accountDetails = NCManageDatabase.shared.getAllAccount().first
- let password = NCKeychain().getPassword(account: accountDetails?.account ?? "")
+ let accountDetails = NCManageDatabase.shared.getAllTableAccount().first
+ let password = NCKeychain().getPassword(account: accountDetails?.account ?? "")
let username = accountDetails?.user ?? ""
let credential = Data("\(username):\(password)".utf8).base64EncodedString()
return ("Basic \(credential)")
@@ -140,7 +144,7 @@ class NMCCommunication: NSObject, XMLParserDelegate {
}
}
-struct DownloadLimit: Codable {
- var limit: Int?
- var count: Int?
-}
+//struct DownloadLimit: Codable {
+// var limit: Int?
+// var count: Int?
+//}
diff --git a/iOSClient/Share/Shareable.swift b/iOSClient/Share/Shareable.swift
index 374eebabb1..4b1f413aeb 100644
--- a/iOSClient/Share/Shareable.swift
+++ b/iOSClient/Share/Shareable.swift
@@ -16,11 +16,9 @@ protocol Shareable: AnyObject {
var password: String { get set }
var label: String { get set }
var note: String { get set }
- var downloadAndSync: Bool { get set }
var expirationDate: NSDate? { get set }
var shareWithDisplayname: String { get set }
var attributes: String? { get set }
- var itemType: String { get set }
}
// MARK: - Default Implementations
@@ -31,7 +29,7 @@ extension Shareable {
///
var formattedDateString: String? {
guard let date = expirationDate else {
- return nil
+ return ""
}
let dateFormatter = DateFormatter()
@@ -56,44 +54,8 @@ extension Shareable {
// MARK: - tableShare Extension
-extension tableShare: Shareable {
- var downloadAndSync: Bool {
- get {
- NCManageDatabase.shared.isAttributeDownloadEnabled(attributes: attributes)
- }
- set {
- attributes = NCManageDatabase.shared.setAttibuteDownload(state: newValue)
- }
- }
-}
+extension tableShare: Shareable {}
// MARK: - NKShare Extension
-extension NKShare: Shareable {
- var downloadAndSync: Bool {
- get {
- NCManageDatabase.shared.isAttributeDownloadEnabled(attributes: attributes)
- }
- set {
- attributes = NCManageDatabase.shared.setAttibuteDownload(state: newValue)
- }
- }
-}
-
-private func isAttributeDownloadEnabled(attributes: String?) -> Bool {
- if let attributes = attributes, let data = attributes.data(using: .utf8) {
- do {
- if let json = try JSONSerialization.jsonObject(with: data) as? [Dictionary] {
- for sub in json {
- let key = sub["key"] as? String
- let enabled = sub["enabled"] as? Bool
- let scope = sub["scope"] as? String
- if key == "download", scope == "permissions", let enabled = enabled {
- return enabled
- }
- }
- }
- } catch let error as NSError { print(error) }
- }
- return true
-}
+extension NKShare: Shareable {}
diff --git a/iOSClient/Share/TransientShare.swift b/iOSClient/Share/TransientShare.swift
index 5276698339..88497103d6 100644
--- a/iOSClient/Share/TransientShare.swift
+++ b/iOSClient/Share/TransientShare.swift
@@ -22,8 +22,6 @@ class TransientShare: Shareable {
var note: String = ""
var expirationDate: NSDate?
var shareWithDisplayname: String = ""
- var downloadAndSync = false
- var itemType: String = ""
var attributes: String?
@@ -33,13 +31,11 @@ class TransientShare: Shareable {
if metadata.e2eEncrypted, capabilities.e2EEApiVersion == NCGlobal.shared.e2eeVersionV12 {
self.permissions = NKShare.Permission.create.rawValue
} else {
- self.permissions = capabilities.fileSharingDefaultPermission & metadata.sharePermissionsCollaborationServices
+ self.permissions = NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityFileSharingDefaultPermission & metadata.sharePermissionsCollaborationServices
}
self.shareType = shareType
- self.itemType = metadata.isDirectory ? NCShareCommon.itemTypeFolder : NCShareCommon.itemTypeFile
-
if let password = password {
self.password = password
}
@@ -48,6 +44,7 @@ class TransientShare: Shareable {
convenience init(sharee: NKSharee, metadata: tableMetadata, password: String?) {
self.init(shareType: sharee.shareType, metadata: metadata, password: password)
self.shareWith = sharee.shareWith
+ self.shareWithDisplayname = sharee.label
}
static func shareLink(metadata: tableMetadata, password: String?) -> TransientShare {
diff --git a/iOSClient/Utility/NCUtility.swift b/iOSClient/Utility/NCUtility.swift
index a0390fbfbb..8514a57702 100644
--- a/iOSClient/Utility/NCUtility.swift
+++ b/iOSClient/Utility/NCUtility.swift
@@ -9,6 +9,7 @@ import PDFKit
import Accelerate
import CoreMedia
import Photos
+import Alamofire
final class NCUtility: NSObject, Sendable {
let utilityFileSystem = NCUtilityFileSystem()
@@ -29,23 +30,19 @@ final class NCUtility: NSObject, Sendable {
}
func isTypeFileRichDocument(_ metadata: tableMetadata) -> Bool {
+ guard metadata.fileNameView != "." else { return false }
let fileExtension = (metadata.fileNameView as NSString).pathExtension
- guard let capabilities = NCNetworking.shared.capabilities[metadata.account],
- !fileExtension.isEmpty,
- let mimeType = UTType(tag: fileExtension.uppercased(), tagClass: .filenameExtension, conformingTo: nil)?.identifier else {
- return false
- }
-
+ guard !fileExtension.isEmpty else { return false }
+ guard let mimeType = UTType(tag: fileExtension.uppercased(), tagClass: .filenameExtension, conformingTo: nil)?.identifier else { return false }
/// contentype
- if !capabilities.richDocumentsMimetypes.filter({ $0.contains(metadata.contentType) || $0.contains("text/plain") }).isEmpty {
+ if !NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityRichDocumentsMimetypes.filter({ $0.contains(metadata.contentType) || $0.contains("text/plain") }).isEmpty {
return true
}
-
/// mimetype
- if !capabilities.richDocumentsMimetypes.isEmpty && mimeType.components(separatedBy: ".").count > 2 {
+ if !NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityRichDocumentsMimetypes.isEmpty && mimeType.components(separatedBy: ".").count > 2 {
let mimeTypeArray = mimeType.components(separatedBy: ".")
let mimeType = mimeTypeArray[mimeTypeArray.count - 2] + "." + mimeTypeArray[mimeTypeArray.count - 1]
- if !capabilities.richDocumentsMimetypes.filter({ $0.contains(mimeType) }).isEmpty {
+ if !NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityRichDocumentsMimetypes.filter({ $0.contains(mimeType) }).isEmpty {
return true
}
}
@@ -53,32 +50,39 @@ final class NCUtility: NSObject, Sendable {
}
func editorsDirectEditing(account: String, contentType: String) -> [String] {
- var names: [String] = []
- let capabilities = NCNetworking.shared.capabilities[account]
+ var editor: [String] = []
+ guard let results = NCManageDatabase.shared.getDirectEditingEditors(account: account) else { return editor }
- capabilities?.directEditingEditors.forEach { editor in
- editor.mimetypes.forEach { mimetype in
+ for result: tableDirectEditingEditors in results {
+ for mimetype in result.mimetypes {
if mimetype == contentType {
- names.append(editor.name)
+ editor.append(result.editor)
}
// HARDCODE
// https://github.com/nextcloud/text/issues/913
if mimetype == "text/markdown" && contentType == "text/x-markdown" {
- names.append(editor.name)
+ editor.append(result.editor)
}
if contentType == "text/html" {
- names.append(editor.name)
+ editor.append(result.editor)
}
}
-
- editor.optionalMimetypes.forEach { mimetype in
+ for mimetype in result.optionalMimetypes {
if mimetype == contentType {
- names.append(editor.name)
+ editor.append(result.editor)
}
}
}
+ return Array(Set(editor))
+ }
- return Array(Set(names))
+ func permissionsContainsString(_ metadataPermissions: String, permissions: String) -> Bool {
+ for char in permissions {
+ if metadataPermissions.contains(char) == false {
+ return false
+ }
+ }
+ return true
}
func getCustomUserAgentNCText() -> String {
@@ -153,6 +157,19 @@ final class NCUtility: NSObject, Sendable {
}
return ""
}
+
+ @objc func getVersionApp(withBuild: Bool = true) -> String {
+ if let dictionary = Bundle.main.infoDictionary {
+ if let version = dictionary["CFBundleShortVersionString"], let build = dictionary["CFBundleVersion"] {
+ if withBuild {
+ return "\(version).\(build)"
+ } else {
+ return "\(version)"
+ }
+ }
+ }
+ return ""
+ }
/*
Facebook's comparison algorithm:
@@ -289,14 +306,6 @@ final class NCUtility: NSObject, Sendable {
return (usedmegabytes, totalmegabytes)
}
-// func removeForbiddenCharacters(_ fileName: String) -> String {
-// var fileName = fileName
-// for character in global.forbiddenCharacters {
-// fileName = fileName.replacingOccurrences(of: character, with: "")
-// }
-// return fileName
-// }
-
func getHeightHeaderEmptyData(view: UIView, portraitOffset: CGFloat, landscapeOffset: CGFloat, isHeaderMenuTransferViewEnabled: Bool = false) -> CGFloat {
var height: CGFloat = 0
if UIDevice.current.orientation.isPortrait {
@@ -317,8 +326,77 @@ final class NCUtility: NSObject, Sendable {
func isValidEmail(_ email: String) -> Bool {
- let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
- let emailPred = NSPredicate(format:"SELF MATCHES %@", emailRegEx)
- return emailPred.evaluate(with: email)
+ // E-mail validations
+ // 1. Basic Email Validator (ASCII only)
+ func isValidEmail(_ email: String) -> Bool {
+ let emailRegex = "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}$"
+ let predicate = NSPredicate(format: "SELF MATCHES[c] %@", emailRegex)
+ return predicate.evaluate(with: email)
+ }
+
+ // 2. Manually Convert Unicode Domain to Punycode with German Char Support
+ func convertToPunycode(email: String) -> String? {
+ guard let atIndex = email.firstIndex(of: "@") else { return nil }
+
+ let localPart = String(email[.. String? {
+ // Mapping of common German characters to their corresponding Punycode equivalents
+ var punycodeDomain = domain.lowercased()
+
+ let germanCharToPunycode: [String: String] = [
+ "ü": "xn--u-1fa", // ü → xn--u-1fa
+ "ä": "xn--a-1fa", // ä → xn--a-1fa
+ "ö": "xn--o-1fa", // ö → xn--o-1fa
+ "ß": "xn--ss-1fa", // ß → xn--ss-1fa
+ "é": "xn--e-1fa", // é → xn--e-1fa
+ "è": "xn--e-1f", // è → xn--e-1f
+ "à": "xn--a-1f", // à → xn--a-1f
+ ]
+
+ // Replace each German character with the corresponding Punycode equivalent
+ for (char, punycode) in germanCharToPunycode {
+ punycodeDomain = punycodeDomain.replacingOccurrences(of: char, with: punycode)
+ }
+
+ // If no change occurred, return the domain as it is (i.e., no Punycode needed)
+ return punycodeDomain
+ }
+
+ // 4. IDN Email Validator (handles Unicode domain by converting to Punycode)
+ func isValidIDNEmail(_ email: String) -> Bool {
+ // Convert domain part to Punycode and validate using basic email regex
+ guard let punycodeEmail = convertToPunycode(email: email) else {
+ return false
+ }
+
+ return isValidEmail(punycodeEmail)
+ }
+
+ // 5. Unified Email Validation - Check for both basic and IDN emails
+ func validateEmail(_ email: String) -> Bool {
+ if isValidEmail(email) {
+ print("Valid ASCII email: \(email)")
+ return true
+ } else if isValidIDNEmail(email) {
+ print("Valid IDN email: \(email)")
+ return true
+ } else {
+ print("Invalid email: \(email)")
+ return false
+ }
}
}
From 70dd85b20231bf06f721293728b2f54731158f81 Mon Sep 17 00:00:00 2001
From: harshada-15-tsys
Date: Fri, 19 Dec 2025 15:13:38 +0530
Subject: [PATCH 6/6] NMC 1997 - Sharing customisation changes
---
Tests/NextcloudUnitTests/SharingTest.swift | 14 +-
iOSClient/Activity/NCActivity.swift | 171 +++--
.../Extensions/DateFormatter+Extension.swift | 72 ++-
iOSClient/Extensions/UIButton+Extension.swift | 23 +-
.../Extensions/UIToolbar+Extension.swift | 16 +-
iOSClient/Extensions/UIView+Extension.swift | 52 +-
iOSClient/Menu/NCShare+Menu.swift | 96 +--
iOSClient/NCGlobal.swift | 236 +++----
iOSClient/Networking/NCDownloadAction.swift | 358 +++++++---
.../Scan document/PasswordInputField.swift | 4 +-
...hareDownloadLimitTableViewController.swift | 13 +-
iOSClient/Share/CreateLinkFooterView.swift | 2 +-
iOSClient/Share/NCPermissions.swift | 11 +-
iOSClient/Share/NCShare+Helper.swift | 16 +-
iOSClient/Share/NCShare+NCCellDelegate.swift | 16 +-
iOSClient/Share/NCShare.storyboard | 258 +++++++-
iOSClient/Share/NCShare.swift | 611 +++++-------------
iOSClient/Share/NCShareCommentsCell.swift | 3 +-
iOSClient/Share/NCShareCommon.swift | 88 +--
iOSClient/Share/NCShareEmailFieldCell.swift | 29 +-
iOSClient/Share/NCShareEmailFieldCell.xib | 25 +-
iOSClient/Share/NCShareHeader.swift | 106 ++-
iOSClient/Share/NCShareHeader.xib | 232 +++----
iOSClient/Share/NCShareLinkCell.swift | 14 +-
iOSClient/Share/NCShareLinkCell.xib | 11 +-
.../Share/NCShareNavigationTitleSetting.swift | 4 +-
iOSClient/Share/NCShareNetworking.swift | 306 ++-------
iOSClient/Share/NCSharePaging.swift | 157 ++---
iOSClient/Share/NCSharePermissions.swift | 57 +-
iOSClient/Share/NCShareUserCell.swift | 142 +---
iOSClient/Share/NCShareUserCell.xib | 209 +++---
.../Share/ShareDownloadLimitNetwork.swift | 6 +
iOSClient/Share/Shareable.swift | 44 +-
iOSClient/Share/TransientShare.swift | 11 +-
iOSClient/Utility/NCUtility.swift | 150 ++---
35 files changed, 1747 insertions(+), 1816 deletions(-)
diff --git a/Tests/NextcloudUnitTests/SharingTest.swift b/Tests/NextcloudUnitTests/SharingTest.swift
index 66d94dbfbb..984a4c0ac3 100644
--- a/Tests/NextcloudUnitTests/SharingTest.swift
+++ b/Tests/NextcloudUnitTests/SharingTest.swift
@@ -201,32 +201,32 @@ final class SharingTest: XCTestCase {
}
func testGetImageShareType() {
- let sut = NCShareCommon() // Replace with the actual class containing the getImageShareType function
+ let sut = NCShareCommon // Replace with the actual class containing the getImageShareType function
// Test case 1: SHARE_TYPE_USER
- let shareType1 = sut.SHARE_TYPE_USER
+ let shareType1 = sut.shareTypeUser
let result1 = sut.getImageShareType(shareType: shareType1)
XCTAssertEqual(result1, UIImage(named: "shareTypeEmail")?.imageColor(NCBrandColor.shared.label))
// Test case 2: SHARE_TYPE_GROUP
- let shareType2 = sut.SHARE_TYPE_GROUP
+ let shareType2 = sut.shareTypeGroup
let result2 = sut.getImageShareType(shareType: shareType2)
XCTAssertEqual(result2, UIImage(named: "shareTypeGroup")?.imageColor(NCBrandColor.shared.label))
// Test case 3: SHARE_TYPE_LINK
- let shareType3 = sut.SHARE_TYPE_LINK
+ let shareType3 = sut.shareTypeLink
let result3 = sut.getImageShareType(shareType: shareType3)
XCTAssertEqual(result3, UIImage(named: "shareTypeLink")?.imageColor(NCBrandColor.shared.label))
// Test case 4: SHARE_TYPE_EMAIL (with isDropDown=false)
- let shareType4 = sut.SHARE_TYPE_EMAIL
+ let shareType4 = sut.shareTypeEmail
let result4 = sut.getImageShareType(shareType: shareType4)
XCTAssertEqual(result4, UIImage(named: "shareTypeUser")?.imageColor(NCBrandColor.shared.label))
// Test case 5: SHARE_TYPE_EMAIL (with isDropDown=true)
- let shareType5 = sut.SHARE_TYPE_EMAIL
+ let shareType5 = sut.shareTypeEmail
let isDropDown5 = true
- let result5 = sut.getImageShareType(shareType: shareType5, isDropDown: isDropDown5)
+ let result5 = sut.getImageShareType(shareType: shareType5)//, isDropDown: isDropDown5)
XCTAssertEqual(result5, UIImage(named: "email")?.imageColor(NCBrandColor.shared.label))
}
}
diff --git a/iOSClient/Activity/NCActivity.swift b/iOSClient/Activity/NCActivity.swift
index d760ba0f8d..70be71c3f5 100644
--- a/iOSClient/Activity/NCActivity.swift
+++ b/iOSClient/Activity/NCActivity.swift
@@ -1,26 +1,6 @@
-//
-// NCActivity.swift
-// Nextcloud
-//
-// Created by Marino Faggiana on 17/01/2019.
-// Copyright © 2019 Marino Faggiana. All rights reserved.
-//
-// Author Marino Faggiana
-// Author Henrik Storch
-//
-// 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 .
-//
+// SPDX-FileCopyrightText: Nextcloud GmbH
+// SPDX-FileCopyrightText: 2019 Marino Faggiana
+// SPDX-License-Identifier: GPL-3.0-or-later
import UIKit
import SwiftRichString
@@ -42,7 +22,6 @@ class NCActivity: UIViewController, NCSharePagingContent {
let database = NCManageDatabase.shared
var allItems: [DateCompareable] = []
var sectionDates: [Date] = []
- var dataSourceTask: URLSessionTask?
var insets = UIEdgeInsets(top: 8, left: 0, bottom: 0, right: 0)
var didSelectItemEnable: Bool = true
@@ -51,11 +30,13 @@ class NCActivity: UIViewController, NCSharePagingContent {
var isFetchingActivity = false
var hasActivityToLoad = true {
- didSet { tableView.tableFooterView?.isHidden = hasActivityToLoad }
+ didSet {
+ tableView.tableFooterView?.isHidden = hasActivityToLoad
+ }
}
var dateAutomaticFetch: Date?
- private let appDelegate = (UIApplication.shared.delegate as? AppDelegate)!
+ @MainActor
var session: NCSession.Session {
if account.isEmpty {
NCSession.shared.getSession(controller: tabBarController)
@@ -69,7 +50,7 @@ class NCActivity: UIViewController, NCSharePagingContent {
override func viewDidLoad() {
super.viewDidLoad()
- self.navigationController?.navigationBar.prefersLargeTitles = true
+ navigationController?.setNavigationBarAppearance()
view.backgroundColor = .systemBackground
self.title = NSLocalizedString("_activity_", comment: "")
@@ -90,7 +71,14 @@ class NCActivity: UIViewController, NCSharePagingContent {
commentView = Bundle.main.loadNibNamed("NCActivityCommentView", owner: self, options: nil)?.first as? NCActivityCommentView
commentView?.setup(account: metadata.account) { newComment in
guard let newComment = newComment, !newComment.isEmpty, let metadata = self.metadata else { return }
- NextcloudKit.shared.putComments(fileId: metadata.fileId, message: newComment, account: metadata.account) { _, _, error in
+ NextcloudKit.shared.putComments(fileId: metadata.fileId, message: newComment, account: metadata.account) { task in
+ Task {
+ let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: metadata.account,
+ path: metadata.fileId,
+ name: "putComments")
+ await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task)
+ }
+ } completion: { _, _, error in
if error == .success {
self.commentView?.newCommentField.text?.removeAll()
self.loadComments()
@@ -108,17 +96,18 @@ class NCActivity: UIViewController, NCSharePagingContent {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
- appDelegate.activeViewController = self
- navigationController?.setNavigationBarAppearance()
fetchAll(isInitial: true)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
+ Task {
+ await NCNetworking.shared.networkingTasks.cancel(identifier: "NCActivity")
+ }
+
// Cancel Queue & Retrieves Properties
NCNetworking.shared.downloadThumbnailActivityQueue.cancelAll()
- dataSourceTask?.cancel()
}
override func viewWillLayoutSubviews() {
@@ -137,10 +126,14 @@ class NCActivity: UIViewController, NCSharePagingContent {
let label = UILabel()
label.font = UIFont.systemFont(ofSize: 15)
- label.textColor = UIColor.systemGray
+ label.textColor = NCBrandColor.shared.textColor2
label.textAlignment = .center
label.text = NSLocalizedString("_no_activity_footer_", comment: "")
view.addSubview(label)
+ label.translatesAutoresizingMaskIntoConstraints = false
+ label.topAnchor.constraint(equalTo: view.topAnchor, constant: 20).isActive = true
+ label.leadingAnchor.constraint(equalTo: view.leadingAnchor).isActive = true
+ label.trailingAnchor.constraint(equalTo: view.trailingAnchor).isActive = true
return view
}
@@ -237,8 +230,8 @@ extension NCActivity: UITableViewDataSource {
cell.fileAvatarImageView?.image = results.image
}
- if let tableAvatar = results.tableAvatar,
- !tableAvatar.loaded,
+ if let tblAvatar = results.tblAvatar,
+ !tblAvatar.loaded,
NCNetworking.shared.downloadAvatarQueue.operations.filter({ ($0 as? NCOperationDownloadAvatar)?.fileName == fileName }).isEmpty {
NCNetworking.shared.downloadAvatarQueue.addOperation(NCOperationDownloadAvatar(user: comment.actorId, fileName: fileName, account: account, view: tableView))
}
@@ -283,7 +276,7 @@ extension NCActivity: UITableViewDataSource {
if !activity.icon.isEmpty {
activity.icon = activity.icon.replacingOccurrences(of: ".png", with: ".svg")
let fileNameIcon = (activity.icon as NSString).lastPathComponent
- let fileNameLocalPath = utilityFileSystem.directoryUserData + "/" + fileNameIcon
+ let fileNameLocalPath = utilityFileSystem.createServerUrl(serverUrl: utilityFileSystem.directoryUserData, fileName: fileNameIcon)
if FileManager.default.fileExists(atPath: fileNameLocalPath) {
let image = fileNameIcon.contains(".svg") ? SVGKImage(contentsOfFile: fileNameLocalPath)?.uiImage : UIImage(contentsOfFile: fileNameLocalPath)
@@ -292,7 +285,14 @@ extension NCActivity: UITableViewDataSource {
cell.icon.image = image.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
}
} else {
- NextcloudKit.shared.downloadContent(serverUrl: activity.icon, account: activity.account) { _, responseData, error in
+ NextcloudKit.shared.downloadContent(serverUrl: activity.icon, account: activity.account) { task in
+ Task {
+ let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: self.account,
+ path: activity.icon,
+ name: "downloadContent")
+ await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task)
+ }
+ } completion: { _, responseData, error in
if error == .success, let data = responseData?.data {
do {
try data.write(to: NSURL(fileURLWithPath: fileNameLocalPath) as URL, options: .atomic)
@@ -318,7 +318,7 @@ extension NCActivity: UITableViewDataSource {
cell.fileAvatarImageView?.image = results.image
}
- if !(results.tableAvatar?.loaded ?? false),
+ if !(results.tblAvatar?.loaded ?? false),
NCNetworking.shared.downloadAvatarQueue.operations.filter({ ($0 as? NCOperationDownloadAvatar)?.fileName == fileName }).isEmpty {
NCNetworking.shared.downloadAvatarQueue.addOperation(NCOperationDownloadAvatar(user: activity.user, fileName: fileName, account: session.account, view: tableView))
}
@@ -342,7 +342,7 @@ extension NCActivity: UITableViewDataSource {
for key in keys {
if let result = database.getActivitySubjectRich(account: session.account, idActivity: activity.idActivity, key: key) {
orderKeysId.append(result.id)
- subject = subject.replacingOccurrences(of: "{\(key)}", with: "" + result.name + "")
+ subject = subject.replacingOccurrences(of: "{\(key)}", with: "" + result.name.escapedForMarkup + "")
}
}
@@ -381,12 +381,8 @@ extension NCActivity {
func fetchAll(isInitial: Bool) {
guard !isFetchingActivity else { return }
self.isFetchingActivity = true
- var bottom: CGFloat = 0
- if let mainTabBar = self.tabBarController?.tabBar as? NCMainTabBar {
- bottom = -mainTabBar.getHeight()
- }
- NCActivityIndicator.shared.start(backgroundView: self.view, bottom: bottom - 35, style: .medium)
+ NCActivityIndicator.shared.start(backgroundView: self.view, style: .medium)
let dispatchGroup = DispatchGroup()
loadComments(disptachGroup: dispatchGroup)
@@ -433,7 +429,14 @@ extension NCActivity {
guard showComments, let metadata = metadata else { return }
disptachGroup?.enter()
- NextcloudKit.shared.getComments(fileId: metadata.fileId, account: metadata.account) { _, comments, _, error in
+ NextcloudKit.shared.getComments(fileId: metadata.fileId, account: metadata.account) { task in
+ Task {
+ let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: metadata.account,
+ path: metadata.fileId,
+ name: "getComments")
+ await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task)
+ }
+ } completion: { _, comments, _, error in
if error == .success, let comments = comments {
self.database.addComments(comments, account: metadata.account, objectId: metadata.fileId)
} else if error.errorCode != NCGlobal.shared.errorResourceNotFound {
@@ -454,6 +457,13 @@ extension NCActivity {
/// Check if most recent activivities are loaded, if not trigger reload
func checkRecentActivity(disptachGroup: DispatchGroup) {
+ Task {
+ // If is already in-flight, do nothing
+ if await NCNetworking.shared.networkingTasks.isReading(identifier: "NCActivity") {
+ return
+ }
+ }
+
guard let result = database.getLatestActivityId(account: session.account), metadata == nil, hasActivityToLoad else {
return self.loadActivity(idActivity: 0, disptachGroup: disptachGroup)
}
@@ -461,14 +471,15 @@ extension NCActivity {
disptachGroup.enter()
- NextcloudKit.shared.getActivity(
- since: 0,
- limit: 1,
- objectId: nil,
- objectType: objectType,
- previews: true,
- account: session.account) { task in
- self.dataSourceTask = task
+ NextcloudKit.shared.getActivity(since: 0,
+ limit: 1,
+ objectId: nil,
+ objectType: objectType,
+ previews: true,
+ account: session.account) { task in
+ Task {
+ await NCNetworking.shared.networkingTasks.track(identifier: "NCActivity", task: task)
+ }
} completion: { account, _, activityFirstKnown, activityLastGiven, _, error in
defer { disptachGroup.leave() }
@@ -486,18 +497,21 @@ extension NCActivity {
}
func loadActivity(idActivity: Int, limit: Int = 200, disptachGroup: DispatchGroup) {
- guard hasActivityToLoad else { return }
+ guard hasActivityToLoad else {
+ return
+ }
var resultActivityId = 0
disptachGroup.enter()
- NextcloudKit.shared.getActivity(
- since: idActivity,
- limit: min(limit, 200),
- objectId: metadata?.fileId,
- objectType: objectType,
- previews: true,
- account: session.account) { task in
- self.dataSourceTask = task
+ NextcloudKit.shared.getActivity(since: idActivity,
+ limit: min(limit, 200),
+ objectId: metadata?.fileId,
+ objectType: objectType,
+ previews: true,
+ account: session.account) { task in
+ Task {
+ await NCNetworking.shared.networkingTasks.track(identifier: "NCActivity", task: task)
+ }
} completion: { account, activities, activityFirstKnown, activityLastGiven, _, error in
defer { disptachGroup.leave() }
guard error == .success,
@@ -526,22 +540,26 @@ extension NCActivity: NCShareCommentsCellDelegate {
guard let tableComment = tableComment else {
return
}
- self.showProfileMenu(userId: tableComment.actorId, session: session)
+ self.showProfileMenu(userId: tableComment.actorId, session: session, sender: sender)
}
func tapMenu(with tableComments: tableComments?, sender: Any) {
- toggleMenu(with: tableComments)
+ toggleMenu(with: tableComments, sender: sender)
}
- func toggleMenu(with tableComments: tableComments?) {
+ func toggleMenu(with tableComments: tableComments?, sender: Any) {
var actions = [NCMenuAction]()
actions.append(
NCMenuAction(
title: NSLocalizedString("_edit_comment_", comment: ""),
icon: utility.loadImage(named: "pencil", colors: [NCBrandColor.shared.iconImageColor]),
+ sender: sender,
action: { _ in
- guard let metadata = self.metadata, let tableComments = tableComments else { return }
+ guard let metadata = self.metadata,
+ let tableComments = tableComments else {
+ return
+ }
let alert = UIAlertController(title: NSLocalizedString("_edit_comment_", comment: ""), message: nil, preferredStyle: .alert)
alert.addAction(UIAlertAction(title: NSLocalizedString("_cancel_", comment: ""), style: .cancel, handler: nil))
@@ -553,7 +571,14 @@ extension NCActivity: NCShareCommentsCellDelegate {
alert.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in
guard let message = alert.textFields?.first?.text, !message.isEmpty else { return }
- NextcloudKit.shared.updateComments(fileId: metadata.fileId, messageId: tableComments.messageId, message: message, account: metadata.account) { _, _, error in
+ NextcloudKit.shared.updateComments(fileId: metadata.fileId, messageId: tableComments.messageId, message: message, account: metadata.account) { task in
+ Task {
+ let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: metadata.account,
+ path: metadata.fileId,
+ name: "updateComments")
+ await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task)
+ }
+ } completion: { _, _, error in
if error == .success {
self.loadComments()
} else {
@@ -575,11 +600,19 @@ extension NCActivity: NCShareCommentsCellDelegate {
NCMenuAction(
title: NSLocalizedString("_delete_comment_", comment: ""),
destructive: true,
- icon: utility.loadImage(named: "trash", colors: [.red]),
+ icon: utility.loadImage(named: "trashIcon", colors: [.red]),
+ sender: sender,
action: { _ in
guard let metadata = self.metadata, let tableComments = tableComments else { return }
- NextcloudKit.shared.deleteComments(fileId: metadata.fileId, messageId: tableComments.messageId, account: metadata.account) { _, _, error in
+ NextcloudKit.shared.deleteComments(fileId: metadata.fileId, messageId: tableComments.messageId, account: metadata.account) { task in
+ Task {
+ let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: metadata.account,
+ path: metadata.fileId,
+ name: "deleteComments")
+ await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task)
+ }
+ } completion: { _, _, error in
if error == .success {
self.loadComments()
} else {
@@ -594,6 +627,6 @@ extension NCActivity: NCShareCommentsCellDelegate {
)
)
- presentMenu(with: actions)
+ presentMenu(with: actions, sender: sender)
}
}
diff --git a/iOSClient/Extensions/DateFormatter+Extension.swift b/iOSClient/Extensions/DateFormatter+Extension.swift
index 2344faac6c..8f14117050 100644
--- a/iOSClient/Extensions/DateFormatter+Extension.swift
+++ b/iOSClient/Extensions/DateFormatter+Extension.swift
@@ -28,21 +28,69 @@ extension DateFormatter {
static let shareExpDate: DateFormatter = {
let dateFormatter = DateFormatter()
dateFormatter.formatterBehavior = .behavior10_4
-// dateFormatter.locale = Locale.current
dateFormatter.dateStyle = .medium
- dateFormatter.dateFormat = NCShareAdvancePermission.displayDateFormat
return dateFormatter
}()
-}
-extension Date {
- static var tomorrow: Date { return Date().dayAfter }
- static var today: Date {return Date()}
- static var dayAfterYear: Date { return Date().dateAfterYear }
- var dayAfter: Date {
- return Calendar.current.date(byAdding: .day, value: 1, to: Date())!
- }
- var dateAfterYear: Date {
- return Calendar.current.date(byAdding: .year, value: 1, to: Date())!
+// static func formattedExpiryDate(_ date: Date) -> String {
+// // Get the app language
+// let appLanguage = Locale.preferredLanguages.first?.prefix(2) ?? "en"
+// let locale = Locale(identifier: "\(appLanguage)_\(appLanguage.uppercased())")
+//
+// // Extract components
+// let calendar = Calendar.current
+// let day = calendar.component(.day, from: date)
+//
+// // Get month name abbreviation in the correct locale
+// let monthFormatter = DateFormatter()
+// monthFormatter.locale = locale
+// monthFormatter.dateFormat = "MMM" // abbreviated month
+// var month = monthFormatter.string(from: date)
+//
+// // Capitalize first letter (German months are lowercase normally)
+// month = month.prefix(1).uppercased() + month.dropFirst()
+//
+// // Remove trailing period if present (common in German abbreviations)
+// month = month.replacingOccurrences(of: ".", with: "")
+//
+// // Get year
+// let year = calendar.component(.year, from: date)
+//
+// return String(format: "%02d.%@.%d", day, month, year)
+// }
+
+ /// Formats a given Date object into the specific string format "dd. MMM. yyyy"
+ /// required for the expiry date display (e.g., "01. Dez. 2026").
+ static func formattedExpiryDate(_ date: Date) -> String {
+
+ // 1. Determine the correct locale to use based on the app's preferences
+ let appLanguageCode = Locale.preferredLanguages.first?.prefix(2) ?? "en"
+ // Use a standard locale identifier for consistency across devices
+ let localeIdentifier = (appLanguageCode == "de" || appLanguageCode == "en") ? appLanguageCode : "en"
+ let locale = Locale(identifier: String(localeIdentifier))
+
+ let calendar = Calendar.current
+ let day = calendar.component(.day, from: date)
+ let year = calendar.component(.year, from: date)
+
+ // 2. Get the month abbreviation using the correct locale
+ let monthFormatter = DateFormatter()
+ monthFormatter.locale = locale
+ monthFormatter.dateFormat = "MMM" // e.g., "Dez." (German locale adds a period) or "Dec" (English locale adds no period)
+ var month = monthFormatter.string(from: date)
+
+ // 3. CRITICAL FIXES:
+ // A. Remove any trailing period the locale might have added
+ month = month.replacingOccurrences(of: ".", with: "")
+
+ // B. Capitalize the first letter (German defaults to lowercase 'dez')
+ month = month.prefix(1).uppercased() + month.dropFirst()
+
+ // 4. Use the String(format:) with correct spacing to guarantee the output structure
+ // This line guarantees a SINGLE period after the day and a SINGLE period after the month abbreviation.
+ let formattedDateString = String(format: "%02d. %@. %d", day, month, year)
+
+ return formattedDateString
}
+
}
diff --git a/iOSClient/Extensions/UIButton+Extension.swift b/iOSClient/Extensions/UIButton+Extension.swift
index 3f51b3e365..8050c15444 100644
--- a/iOSClient/Extensions/UIButton+Extension.swift
+++ b/iOSClient/Extensions/UIButton+Extension.swift
@@ -25,21 +25,12 @@ extension UIButton {
}
func hideSpinnerAndShowButton() {
- let spinnerTag = Int(bitPattern: Unmanaged.passUnretained(self).toOpaque())
- let spinner = self.superview?.subviews.first(where: { view -> Bool in
- return view.isKind(of: UIActivityIndicatorView.self) && view.tag == spinnerTag
- })
+ let spinnerTag = Int(bitPattern: Unmanaged.passUnretained(self).toOpaque())
+ let spinner = self.superview?.subviews.first(where: { view -> Bool in
+ return view.isKind(of: UIActivityIndicatorView.self) && view.tag == spinnerTag
+ })
- spinner?.removeFromSuperview()
- self.isHidden = false
- }
-
- func setBackgroundColor(_ color: UIColor, for forState: UIControl.State) {
- UIGraphicsBeginImageContext(CGSize(width: 1, height: 1))
- UIGraphicsGetCurrentContext()!.setFillColor(color.cgColor)
- UIGraphicsGetCurrentContext()!.fill(CGRect(x: 0, y: 0, width: 1, height: 1))
- let colorImage = UIGraphicsGetImageFromCurrentImageContext()
- UIGraphicsEndImageContext()
- self.setBackgroundImage(colorImage, for: forState)
- }
+ spinner?.removeFromSuperview()
+ self.isHidden = false
+ }
}
diff --git a/iOSClient/Extensions/UIToolbar+Extension.swift b/iOSClient/Extensions/UIToolbar+Extension.swift
index ac403c9791..1cf1f6f86b 100644
--- a/iOSClient/Extensions/UIToolbar+Extension.swift
+++ b/iOSClient/Extensions/UIToolbar+Extension.swift
@@ -37,7 +37,7 @@ extension UIToolbar {
buttons.append(clearButton)
}
buttons.append(UIBarButtonItem(barButtonSystemItem: UIBarButtonItem.SystemItem.flexibleSpace, target: nil, action: nil))
- let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .done) {
+ let doneButton = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .plain) {
onDone()
}
buttons.append(doneButton)
@@ -58,20 +58,6 @@ extension UIToolbar {
])
return view
}
-
- static func doneToolbar(completion: @escaping () -> Void) -> UIToolbar {
- let doneToolbar: UIToolbar = UIToolbar(frame: CGRect.init(x: 0, y: 0, width: UIScreen.main.bounds.width, height: 50))
- doneToolbar.barStyle = .default
-
- let flexSpace = UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil)
- let done: UIBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_done_", comment: ""), style: .done) {
- completion()
- }
- let items = [flexSpace, done]
- doneToolbar.items = items
- doneToolbar.sizeToFit()
- return doneToolbar
- }
}
// https://stackoverflow.com/a/67985180/9506784
diff --git a/iOSClient/Extensions/UIView+Extension.swift b/iOSClient/Extensions/UIView+Extension.swift
index 4673ca902c..ce28c998b5 100644
--- a/iOSClient/Extensions/UIView+Extension.swift
+++ b/iOSClient/Extensions/UIView+Extension.swift
@@ -24,11 +24,6 @@
import Foundation
import UIKit
-enum VerticalLocation: String {
- case bottom
- case top
-}
-
extension UIView {
// Source
@@ -74,21 +69,42 @@ extension UIView {
self.layer.cornerRadius = self.frame.size.width / 2
self.layer.masksToBounds = true
}
-
- func addShadow(location: VerticalLocation, height: CGFloat = 2, color: UIColor = NCBrandColor.shared.customerDarkGrey, opacity: Float = 0.4, radius: CGFloat = 2) {
- switch location {
- case .bottom:
- addShadow(offset: CGSize(width: 0, height: height), color: color, opacity: opacity, radius: radius)
- case .top:
- addShadow(offset: CGSize(width: 0, height: -height), color: color, opacity: opacity, radius: radius)
+
+ var parentTabBarController: UITabBarController? {
+ var responder: UIResponder? = self
+ while let nextResponder = responder?.next {
+ if let tabBarController = nextResponder as? UITabBarController {
+ return tabBarController
+ }
+ responder = nextResponder
}
+ return nil
}
- func addShadow(offset: CGSize, color: UIColor = .black, opacity: Float = 0.5, radius: CGFloat = 5.0) {
- self.layer.masksToBounds = false
- self.layer.shadowColor = color.cgColor
- self.layer.shadowOffset = offset
- self.layer.shadowOpacity = opacity
- self.layer.shadowRadius = radius
+ func addBlur(style: UIBlurEffect.Style, alpha: CGFloat = 1.0) {
+ let blurEffect = UIBlurEffect(style: style)
+ let blurView = UIVisualEffectView(effect: blurEffect)
+ blurView.frame = bounds
+ blurView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
+ blurView.alpha = alpha
+ blurView.layer.masksToBounds = true
+ insertSubview(blurView, at: 0)
+ }
+
+ func addBlurBackground(style: UIBlurEffect.Style, alpha: CGFloat = 1) {
+ let blur = UIBlurEffect(style: style)
+ let blurView = UIVisualEffectView(effect: blur)
+ blurView.isUserInteractionEnabled = false
+ blurView.alpha = alpha
+ blurView.layer.masksToBounds = true
+ blurView.translatesAutoresizingMaskIntoConstraints = false
+ insertSubview(blurView, at: 0)
+
+ NSLayoutConstraint.activate([
+ blurView.topAnchor.constraint(equalTo: topAnchor),
+ blurView.leadingAnchor.constraint(equalTo: leadingAnchor),
+ blurView.trailingAnchor.constraint(equalTo: trailingAnchor),
+ blurView.bottomAnchor.constraint(equalTo: bottomAnchor)
+ ])
}
}
diff --git a/iOSClient/Menu/NCShare+Menu.swift b/iOSClient/Menu/NCShare+Menu.swift
index 68c66ff5fc..fc3043036d 100644
--- a/iOSClient/Menu/NCShare+Menu.swift
+++ b/iOSClient/Menu/NCShare+Menu.swift
@@ -34,9 +34,10 @@ extension NCShare {
actions.append(
NCMenuAction(
title: NSLocalizedString("_open_in_", comment: ""),
- icon: utility.loadImage(named: "viewInFolder").imageColor(NCBrandColor.shared.brandElement),
+ icon: utility.loadImage(named: "open_file", colors: [NCBrandColor.shared.brandElement]),
+ sender: sender,
action: { _ in
- NCShareCommon().copyLink(link: share.url, viewController: self, sender: sender)
+ NCShareCommon.copyLink(link: share.url, viewController: self, sender: sender)
}
)
)
@@ -46,15 +47,16 @@ extension NCShare {
NCMenuAction(
// title: NSLocalizedString("_details_", comment: ""),
// icon: utility.loadImage(named: "pencil", colors: [NCBrandColor.shared.iconImageColor]),
-// accessibilityIdentifier: "shareMenu/details",
title: NSLocalizedString("_advance_permissions_", comment: ""),
- icon: utility.loadImage(named: "rename").imageColor(NCBrandColor.shared.brandElement),
+ icon: utility.loadImage(named: "rename", colors: [NCBrandColor.shared.brandElement]),
+ accessibilityIdentifier: "shareMenu/details",
+ sender: sender,
action: { _ in
guard
let advancePermission = UIStoryboard(name: "NCShare", bundle: nil).instantiateViewController(withIdentifier: "NCShareAdvancePermission") as? NCShareAdvancePermission,
let navigationController = self.navigationController, !share.isInvalidated else { return }
advancePermission.networking = self.networking
- advancePermission.share = share
+ advancePermission.share = tableShare(value: share)
advancePermission.oldTableShare = tableShare(value: share)
advancePermission.metadata = self.metadata
@@ -66,18 +68,19 @@ extension NCShare {
}
)
)
-
+
if sendMail {
actions.append(
NCMenuAction(
title: NSLocalizedString("_send_new_email_", comment: ""),
- icon: NCUtility().loadImage(named: "email").imageColor(NCBrandColor.shared.brandElement),
+ icon: utility.loadImage(named: "email", colors: [NCBrandColor.shared.brandElement]),
+ sender: sender,
action: { menuAction in
let storyboard = UIStoryboard(name: "NCShare", bundle: nil)
guard let viewNewUserComment = storyboard.instantiateViewController(withIdentifier: "NCShareNewUserAddComment") as? NCShareNewUserAddComment else { return }
viewNewUserComment.metadata = self.metadata
viewNewUserComment.share = tableShare(value: share)
- viewNewUserComment.networking = self.networking
+// viewNewUserComment.networking = self.networking
self.navigationController?.pushViewController(viewNewUserComment, animated: true)
}
)
@@ -87,7 +90,8 @@ extension NCShare {
actions.append(
NCMenuAction(
title: NSLocalizedString("_share_unshare_", comment: ""),
- icon: utility.loadImage(named: "trash").imageColor(NCBrandColor.shared.brandElement),
+ icon: utility.loadImage(named: "trashIcon", colors: [NCBrandColor.shared.brandElement]),
+ sender: sender,
action: { _ in
Task {
if share.shareType != NKShare.ShareType.publicLink.rawValue, let metadata = self.metadata, metadata.e2eEncrypted && capabilities.e2EEApiVersion == NCGlobal.shared.e2eeVersionV20 {
@@ -95,7 +99,7 @@ extension NCShare {
let error = NKError(errorCode: NCGlobal.shared.errorE2EEUploadInProgress, errorDescription: NSLocalizedString("_e2e_in_upload_", comment: ""))
return NCContentPresenter().showInfo(error: error)
}
- let error = await NCNetworkingE2EE().uploadMetadata(serverUrl: serverUrl, addUserId: nil, removeUserId: share.shareWith, account: metadata.account)
+ let error = await NCNetworkingE2EE().uploadMetadata(serverUrl: metadata.serverUrlFileName, addUserId: nil, removeUserId: share.shareWith, account: metadata.account)
if error != .success {
return NCContentPresenter().showError(error: error)
}
@@ -106,40 +110,56 @@ extension NCShare {
)
)
- self.presentMenu(with: actions)
+ self.presentMenu(with: actions, sender: sender)
}
- func toggleUserPermissionMenu(isDirectory: Bool, tableShare: tableShare) {
+ func toggleQuickPermissionsMenu(isDirectory: Bool, share: tableShare, sender: Any?) {
var actions = [NCMenuAction]()
- let permissions = NCPermissions()
- actions.append(
- NCMenuAction(
+ actions.append(contentsOf:
+ [NCMenuAction(
title: NSLocalizedString("_share_read_only_", comment: ""),
icon: utility.loadImage(named: "eye", colors: [NCBrandColor.shared.iconImageColor]),
selected: share.permissions == (NKShare.Permission.read.rawValue + NKShare.Permission.share.rawValue) || share.permissions == NKShare.Permission.read.rawValue,
on: false,
+ sender: sender,
action: { _ in
- let canShare = permissions.isPermissionToCanShare(tableShare.permissions)
- let permissions = permissions.getPermission(canEdit: false, canCreate: false, canChange: false, canDelete: false, canShare: canShare, isDirectory: isDirectory)
- self.updateSharePermissions(share: tableShare, permissions: permissions)
+ let permissions = NCSharePermissions.getPermissionValue(canCreate: false, canEdit: false, canDelete: false, canShare: false, isDirectory: isDirectory)
+ self.updateSharePermissions(share: share, permissions: permissions)
}
- )
- )
-
- actions.append(
+ ),
NCMenuAction(
-// title: isDirectory ? NSLocalizedString("_share_allow_upload_", comment: "") : NSLocalizedString("_share_editing_", comment: ""),
title: NSLocalizedString("_share_editing_", comment: ""),
- icon: UIImage(),
- selected: hasUploadPermission(tableShare: tableShare),
+ icon: utility.loadImage(named: "pencil", colors: [NCBrandColor.shared.iconImageColor]),
+ selected: hasUploadPermission(tableShare: share),
on: false,
+ sender: sender,
action: { _ in
- let canShare = permissions.isPermissionToCanShare(tableShare.permissions)
- let permissions = permissions.getPermission(canEdit: true, canCreate: true, canChange: true, canDelete: true, canShare: canShare, isDirectory: isDirectory)
- self.updateSharePermissions(share: tableShare, permissions: permissions)
+ let permissions = NCSharePermissions.getPermissionValue(canCreate: true, canEdit: true, canDelete: true, canShare: true, isDirectory: isDirectory)
+ self.updateSharePermissions(share: share, permissions: permissions)
}
- )
+ ),
+// NCMenuAction(
+// title: NSLocalizedString("_custom_permissions_", comment: ""),
+// icon: utility.loadImage(named: "ellipsis", colors: [NCBrandColor.shared.iconImageColor]),
+// sender: sender,
+// action: { _ in
+// guard
+// let advancePermission = UIStoryboard(name: "NCShare", bundle: nil).instantiateViewController(withIdentifier: "NCShareAdvancePermission") as? NCShareAdvancePermission,
+// let navigationController = self.navigationController, !share.isInvalidated else { return }
+// advancePermission.networking = self.networking
+// advancePermission.share = tableShare(value: share)
+// advancePermission.oldTableShare = tableShare(value: share)
+// advancePermission.metadata = self.metadata
+//
+// if let downloadLimit = try? self.database.getDownloadLimit(byAccount: self.metadata.account, shareToken: share.token) {
+// advancePermission.downloadLimit = .limited(limit: downloadLimit.limit, count: downloadLimit.count)
+// }
+//
+// navigationController.pushViewController(advancePermission, animated: true)
+// }
+// )
+ ]
)
if isDirectory && (share.shareType == NKShare.ShareType.publicLink.rawValue /* public link */ || share.shareType == NKShare.ShareType.email.rawValue) {
@@ -155,17 +175,16 @@ extension NCShare {
}
), at: 2)
}
-
- self.presentMenu(with: actions)
+
+ self.presentMenu(with: actions, sender: sender)
}
fileprivate func hasUploadPermission(tableShare: tableShare) -> Bool {
- let permissions = NCPermissions()
let uploadPermissions = [
- permissions.permissionMaxFileShare,
- permissions.permissionMaxFolderShare,
- permissions.permissionDefaultFileRemoteShareNoSupportShareOption,
- permissions.permissionDefaultFolderRemoteShareNoSupportShareOption]
+ NCSharePermissions.permissionMaxFileShare,
+ NCSharePermissions.permissionMaxFolderShare,
+ NCSharePermissions.permissionDefaultFileRemoteShareNoSupportShareOption,
+ NCSharePermissions.permissionDefaultFolderRemoteShareNoSupportShareOption]
return uploadPermissions.contains(tableShare.permissions)
}
@@ -179,8 +198,11 @@ extension NCShare {
if let model = try database.getDownloadLimit(byAccount: metadata.account, shareToken: updatedShare.token) {
downloadLimit = .limited(limit: model.limit, count: model.count)
}
+ if let model = try database.getDownloadLimit(byAccount: metadata.account, shareToken: updatedShare.token) {
+ downloadLimit = .limited(limit: model.limit, count: model.count)
+ }
} catch {
- NextcloudKit.shared.nkCommonInstance.writeLog("[ERROR] Failed to get download limit from database!")
+ nkLog(error: "Failed to get download limit from database!")
return
}
diff --git a/iOSClient/NCGlobal.swift b/iOSClient/NCGlobal.swift
index dd5365d89a..96ea74c54a 100644
--- a/iOSClient/NCGlobal.swift
+++ b/iOSClient/NCGlobal.swift
@@ -4,34 +4,18 @@
import UIKit
-/// Used for read/write in Realm
-var isAppSuspending: Bool = false
-/// Used for know if the app in in Background mode
-var isAppInBackground: Bool = false
+final class NCGlobal: Sendable {
+ static let shared = NCGlobal()
+
+ init() { }
-class NCGlobal: NSObject, @unchecked Sendable {
- @objc static let shared = NCGlobal()
-
- override init() {
- super.init()
- NotificationCenter.default.addObserver(forName: UIApplication.didEnterBackgroundNotification, object: nil, queue: .main) { _ in
- isAppSuspending = true
- isAppInBackground = true
- }
-
- NotificationCenter.default.addObserver(forName: UIApplication.willEnterForegroundNotification, object: nil, queue: .main) { _ in
- isAppSuspending = false
- isAppInBackground = false
- }
- }
-
// ENUM
//
public enum TypeFilterScanDocument: String {
case document = "document"
case original = "original"
}
-
+
// Directory on Group
//
let directoryProviderStorage = "File Provider Storage"
@@ -40,13 +24,13 @@ class NCGlobal: NSObject, @unchecked Sendable {
let appDatabaseNextcloud = "Library/Application Support/Nextcloud"
let appScan = "Library/Application Support/Scan"
let appUserData = "Library/Application Support/UserData"
-
+
// Service
//
let metadataKeyedUnarchiver = "it.twsweb.nextcloud.metadata"
let refreshTask = "com.nextcloud.refreshTask"
let processingTask = "com.nextcloud.processingTask"
-
+
// App
//
let appName = "files"
@@ -55,10 +39,9 @@ class NCGlobal: NSObject, @unchecked Sendable {
let spreedName = "spreed"
let twoFactorNotificatioName = "twofactor_nextcloud_notification"
let termsOfServiceName = "terms_of_service"
-
+
// Nextcloud version
//
- let nextcloudVersion12: Int = 12
let nextcloudVersion18: Int = 18
let nextcloudVersion20: Int = 20
let nextcloudVersion23: Int = 23
@@ -69,7 +52,7 @@ class NCGlobal: NSObject, @unchecked Sendable {
let nextcloudVersion28: Int = 28
let nextcloudVersion30: Int = 30
let nextcloudVersion31: Int = 31
-
+
// Nextcloud unsupported
//
let nextcloud_unsupported_version: Int = 20
@@ -78,14 +61,10 @@ class NCGlobal: NSObject, @unchecked Sendable {
// Intro selector
//
- @objc let introLogin: Int = 0
+ let introLogin: Int = 0
let introSignup: Int = 1
- // let introSignUpWithProvider: Int = 1
-
- // Varie size GUI
- //
- @objc let heightCellSettings: CGFloat = 50
-
+ let introSignUpWithProvider: Int = 1
+
// Avatar
//
let avatarSize: Int = 128 * Int(UIScreen.main.scale)
@@ -100,50 +79,50 @@ class NCGlobal: NSObject, @unchecked Sendable {
let previewExt1024 = ".1024.preview.jpg"
let previewExt512 = ".512.preview.jpg"
let previewExt256 = ".256.preview.jpg"
-
+
func getSizeExtension(column: Int) -> String {
if column == 0 { return previewExt256 }
let width = UIScreen.main.bounds.width / CGFloat(column)
-
- switch (width * 4) {
- case 0...384:
- return previewExt256
- case 385...768:
- return previewExt512
- default:
- return previewExt1024
- }
+
+ switch (width * 4) {
+ case 0...384:
+ return previewExt256
+ case 385...768:
+ return previewExt512
+ default:
+ return previewExt1024
+ }
}
-
+
// E2EE
//
let e2eePassphraseTest = "more over television factory tendency independence international intellectual impress interest sentence pony"
- @objc let e2eeVersions = ["1.1", "1.2", "2.0"]
+ let e2eeVersions = ["1.1", "1.2", "2.0"]
let e2eeVersionV11 = "1.1"
let e2eeVersionV12 = "1.2"
let e2eeVersionV20 = "2.0"
-
+
// CHUNK
let chunkSizeMBCellular = 10000000
let chunkSizeMBEthernetOrWiFi = 100000000
-
+
// Video
//
let maxHTTPCache: Int64 = 10000000000 // 10 GB
let fileNameVideoEncoded: String = "video_encoded.mp4"
-
+
// NCViewerProviderContextMenu
//
let maxAutoDownload: UInt64 = 50000000 // 50MB
let maxAutoDownloadCellular: UInt64 = 10000000 // 10MB
-
+
// Layout
//
let layoutList = "typeLayoutList"
let layoutGrid = "typeLayoutGrid"
let layoutPhotoRatio = "typeLayoutPhotoRatio"
let layoutPhotoSquare = "typeLayoutPhotoSquare"
-
+
let layoutViewTrash = "LayoutTrash"
let layoutViewOffline = "LayoutOffline"
let layoutViewFavorite = "LayoutFavorite"
@@ -153,16 +132,13 @@ class NCGlobal: NSObject, @unchecked Sendable {
let layoutViewShareExtension = "LayoutShareExtension"
let layoutViewGroupfolders = "LayoutGroupfolders"
let layoutViewMedia = "LayoutMedia"
- let layoutViewMove = "LayoutMove"
-
// Button Type in Cell list/grid
//
let buttonMoreMore = "more"
let buttonMoreLock = "moreLock"
let buttonMoreStop = "stop"
-
// Standard height sections header/footer
//
let heightButtonsView: CGFloat = 50
@@ -193,7 +169,7 @@ class NCGlobal: NSObject, @unchecked Sendable {
// Rich Workspace
//
let fileNameRichWorkspace = "Readme.md"
-
+
// ContentPresenter
//
let dismissAfterSecond: TimeInterval = 5
@@ -211,7 +187,6 @@ class NCGlobal: NSObject, @unchecked Sendable {
let errorConflict: Int = 409
let errorPreconditionFailed: Int = 412
let errorUnsupportedMediaType: Int = 415
- let errorWebDAVLocked: Int = 423
let errorInternalServerError: Int = 500
let errorMaintenance: Int = 503
let errorQuota: Int = 507
@@ -229,12 +204,16 @@ class NCGlobal: NSObject, @unchecked Sendable {
let errorUnauthorizedFilesPasscode: Int = -99993
let errorDisableFilesApp: Int = -99992
let errorUnexpectedResponseFromDB: Int = -99991
+ let errorIncorrectFileName: Int = -99990
+ let errorVersionMismatch: Int = -99989
+ let errorNCSessionNotFound: Int = -99988
+
// E2EE
let errorE2EENotEnabled: Int = -98000
let errorE2EEVersion: Int = -98001
let errorE2EEKeyChecksums: Int = -98002
let errorE2EEKeyEncodeMetadata: Int = -98003
- let errorE2EEKeyDecodeMetadata: Int = -98004
+ let errorE2EEKeyDecodeMetadataV12: Int = -98004
let errorE2EEKeyVerifySignature: Int = -98005
let errorE2EEKeyCiphertext: Int = -98006
let errorE2EEKeyFiledropCiphertext: Int = -98007
@@ -247,7 +226,9 @@ class NCGlobal: NSObject, @unchecked Sendable {
let errorE2EEEncodedKey: Int = -98014
let errorE2EENoUserFound: Int = -98015
let errorE2EEUploadInProgress: Int = -98016
-
+ let errorE2EEKeyDirectoryTop: Int = -98017
+
+
// Selector
//
let selectorReadFile = "readFile"
@@ -259,7 +240,6 @@ class NCGlobal: NSObject, @unchecked Sendable {
let selectorDownloadFile = "downloadFile"
let selectorUploadAutoUpload = "uploadAutoUpload"
- let selectorUploadAutoUploadAll = "uploadAutoUploadAll"
let selectorUploadFile = "uploadFile"
let selectorUploadFileNODelete = "UploadFileNODelete"
let selectorUploadFileShareExtension = "uploadFileShareExtension"
@@ -270,7 +250,7 @@ class NCGlobal: NSObject, @unchecked Sendable {
let selectorSynchronizationOffline = "synchronizationOffline"
let selectorPrint = "print"
let selectorDeleteFile = "deleteFile"
-
+
// Metadata : Status
//
// 0 normal
@@ -279,15 +259,15 @@ class NCGlobal: NSObject, @unchecked Sendable {
// ± 3 error
//
let metadataStatusNormal: Int = 0
-
+
let metadataStatusWaitDownload: Int = -1
let metadataStatusDownloading: Int = -2
let metadataStatusDownloadError: Int = -3
-
+
let metadataStatusWaitUpload: Int = 1
let metadataStatusUploading: Int = 2
let metadataStatusUploadError: Int = 3
-
+
let metadataStatusWaitCreateFolder: Int = 10
let metadataStatusWaitDelete: Int = 11
let metadataStatusWaitRename: Int = 12
@@ -309,36 +289,29 @@ class NCGlobal: NSObject, @unchecked Sendable {
let metadataStatusObserveNetworkingProcess = [-1, 1, 10, 11, 12, 13, 14, 15]
let metadataStatusObserveTrasfers = [-2, 2, 10, 11, 12, 13, 14, 15]
- // Hidden files included in the read
- //
- let includeHiddenFiles: [String] = [".LivePhoto"]
-
+ let metadataStatusUploadingAllMode = [1,2,3]
+ let metadataStatusDownloadingAllMode = [-1, -2, -3]
+ let metadataStatusForScreenAwake = [-1, -2, 1, 2]
+ let metadataStatusHideInView = [1, 2, 3, 11]
+ let metadataStatusWaitWebDav = [10, 11, 12, 13, 14, 15]
+
// Auto upload subfolder granularity
//
- @objc let subfolderGranularityDaily = 2
- @objc let subfolderGranularityMonthly = 1
- @objc let subfolderGranularityYearly = 0
-
+ let subfolderGranularityDaily = 2
+ let subfolderGranularityMonthly = 1
+ let subfolderGranularityYearly = 0
+
// Notification Center
//
- @objc let notificationCenterChangeUser = "changeUser"
- let notificationCenterChangeTheming = "changeTheming"
- @objc let notificationCenterApplicationDidEnterBackground = "applicationDidEnterBackground"
- @objc let notificationCenterApplicationDidBecomeActive = "applicationDidBecomeActive"
- @objc let notificationCenterApplicationWillResignActive = "applicationWillResignActive"
- @objc let notificationCenterApplicationWillEnterForeground = "applicationWillEnterForeground"
-
-
- @objc let notificationCenterInitialize = "initialize"
+ let notificationCenterChangeUser = "changeUser" // userInfo: account, controller
+ let notificationCenterChangeTheming = "changeTheming" // userInfo: account
let notificationCenterRichdocumentGrabFocus = "richdocumentGrabFocus"
let notificationCenterReloadDataNCShare = "reloadDataNCShare"
let notificationCenterDidCreateShareLink = "didCreateShareLink"
-
+
let notificationCenterCloseRichWorkspaceWebView = "closeRichWorkspaceWebView"
let notificationCenterReloadAvatar = "reloadAvatar"
- let notificationCenterReloadHeader = "reloadHeader"
let notificationCenterClearCache = "clearCache"
- let notificationCenterChangeLayout = "changeLayout" // userInfo: account, serverUrl, layoutForView
let notificationCenterCheckUserDelaultErrorDone = "checkUserDelaultErrorDone" // userInfo: account, controller
let notificationCenterServerDidUpdate = "serverDidUpdate" // userInfo: account
let notificationCenterNetworkReachability = "networkReachability"
@@ -374,31 +347,19 @@ class NCGlobal: NSObject, @unchecked Sendable {
let notificationCenterMenuSearchTextPDF = "menuSearchTextPDF"
let notificationCenterMenuGotToPageInPDF = "menuGotToPageInPDF"
-
+
let notificationCenterOpenMediaDetail = "openMediaDetail" // userInfo: ocId
-
+
let notificationCenterDismissScanDocument = "dismissScanDocument"
let notificationCenterDismissUploadAssets = "dismissUploadAssets"
-
+
let notificationCenterEnableSwipeGesture = "enableSwipeGesture"
let notificationCenterDisableSwipeGesture = "disableSwipeGesture"
-
- let notificationCenterShareViewIn = "ShareViewIn"
- let notificationCenterShareAdvancePermission = "ShareAdvancePermission"
- let notificationCenterShareSendEmail = "ShareSendEmail"
- let notificationCenterShareUnshare = "ShareUnshare"
- let notificationCenterStatusReadOnly = "statusReadOnly"
- let notificationCenterStatusEditing = "statusEditing"
- let notificationCenterStatusFileDrop = "statusFileDrop"
-
-
let notificationCenterPlayerIsPlaying = "playerIsPlaying"
let notificationCenterPlayerStoppedPlaying = "playerStoppedPlaying"
-
- let notificationCenterUpdateShare = "updateShare"
- let notificationCenterShareCountsUpdated = "shareCountsUpdated"
- let notificationCenterUpdateIcons = "updateIcons"
+
+ let notificationCenterFavoriteStatusChanged = "favoriteStatusChanged"
// Networking Status
let networkingStatusCreateFolder = "statusCreateFolder"
@@ -414,8 +375,9 @@ class NCGlobal: NSObject, @unchecked Sendable {
let networkingStatusUploading = "statusUploading"
let networkingStatusUploaded = "statusUploaded"
- let networkingStatusReloadAvatar = "statusReloadAvatar"
+ let networkingStatusReloadAvatar = "statusReloadAvatar"
+ let notificationCenterUpdateIcons = "updateIcons"
// TIP
//
@@ -423,8 +385,8 @@ class NCGlobal: NSObject, @unchecked Sendable {
let tipAccountRequest = "tipAccountRequest"
let tipScanAddImage = "tipScanAddImage"
let tipMediaDetailView = "tipMediaDetailView"
- let tipAutoUpload = "tipAutoUpload"
-
+ let tipAutoUploadButton = "tipAutoUploadButton"
+
// ACTION
//
let actionNoAction = "no-action"
@@ -432,7 +394,7 @@ class NCGlobal: NSObject, @unchecked Sendable {
let actionScanDocument = "add-scan-document"
let actionTextDocument = "create-text-document"
let actionVoiceMemo = "create-voice-memo"
-
+
// WIDGET ACTION
//
let widgetActionNoAction = "nextcloud://open-action?action=no-action"
@@ -440,45 +402,24 @@ class NCGlobal: NSObject, @unchecked Sendable {
let widgetActionScanDocument = "nextcloud://open-action?action=add-scan-document"
let widgetActionTextDocument = "nextcloud://open-action?action=create-text-document"
let widgetActionVoiceMemo = "nextcloud://open-action?action=create-voice-memo"
-
+
// APPCONFIG
//
let configuration_brand = "brand"
-
+
let configuration_serverUrl = "serverUrl"
let configuration_username = "username"
let configuration_password = "password"
let configuration_apppassword = "apppassword"
-
+
let configuration_disable_intro = "disable_intro"
let configuration_disable_multiaccount = "disable_multiaccount"
let configuration_disable_crash_service = "disable_crash_service"
let configuration_disable_log = "disable_log"
- let configuration_disable_manage_account = "disable_manage_account"
let configuration_disable_more_external_site = "disable_more_external_site"
let configuration_disable_openin_file = "disable_openin_file"
let configuration_enforce_passcode_lock = "enforce_passcode_lock"
-
- // CAPABILITIES
- //
- var capabilityServerVersionMajor: Int = 0
- @objc var capabilityServerVersion: String = ""
- @objc var capabilityThemingName: String = ""
- @objc var capabilityThemingSlogan: String = ""
-
- @objc var capabilityE2EEEnabled: Bool = false
- @objc var capabilityE2EEApiVersion: String = ""
-
- var capabilityRichdocumentsEnabled: Bool = false
- var capabilityRichdocumentsMimetypes: [String] = []
- var capabilityActivity: [String] = []
- var capabilityNotification: [String] = []
-
- @objc var capabilityUserStatusEnabled: Bool = false
- var isLivePhotoServerAvailable: Bool { // NC28
- return capabilityServerVersionMajor >= nextcloudVersion28
- }
-
+
// MORE NEXTCLOUD APPS
//
let talkSchemeUrl = "nextcloudtalk://"
@@ -486,41 +427,36 @@ class NCGlobal: NSObject, @unchecked Sendable {
let talkAppStoreUrl = "https://apps.apple.com/in/app/nextcloud-talk/id1296825574"
let notesAppStoreUrl = "https://apps.apple.com/in/app/nextcloud-notes/id813973264"
let moreAppsUrl = "itms-apps://search.itunes.apple.com/WebObjects/MZSearch.woa/wa/search?media=software&term=nextcloud"
-
+
// SNAPSHOT PREVIEW
//
let defaultSnapshotConfiguration = "DefaultPreviewConfiguration"
-
-// // FORBIDDEN CHARACTERS
-// //
-// // TODO: Remove this
-// let forbiddenCharacters = ["/", "\\", ":", "\"", "|", "?", "*", "<", ">"]
-
+
// DIAGNOSTICS CLIENTS
//
let diagnosticIssueSyncConflicts = "sync_conflicts"
let diagnosticIssueProblems = "problems"
let diagnosticIssueVirusDetected = "virus_detected"
let diagnosticIssueE2eeErrors = "e2ee_errors"
-
+
let diagnosticProblemsForbidden = "CHARACTERS_FORBIDDEN"
let diagnosticProblemsBadResponse = "BAD_SERVER_RESPONSE"
let diagnosticProblemsUploadServerError = "UploadError.SERVER_ERROR"
-
+
// MEDIA LAYOUT
//
let mediaLayoutRatio = "mediaLayoutRatio"
let mediaLayoutSquare = "mediaLayoutSquare"
-
+
// DRAG & DROP
//
let metadataOcIdDataRepresentation = "text/com.nextcloud.ocId"
-
+
// GROUP AMIN
//
let groupAdmin = "admin"
-
- // DATA TASK DESCRIPTION
+
+ // TASK DESCRIPTION
//
let taskDescriptionRetrievesProperties = "retrievesProperties"
let taskDescriptionSynchronization = "synchronization"
@@ -551,6 +487,24 @@ class NCGlobal: NSObject, @unchecked Sendable {
let keyFileNameOriginal = "fileNameOriginal"
let keyFileNameOriginalAutoUpload = "fileNameOriginalAutoUpload"
+ // LOG TAG
+ //
+ let logTagTask = "BGT"
+ let logTagLocation = "LOCATION"
+ let logTagBgSync = "BGSYNC"
+ let logTagE2EE = "E2EE"
+ let logTagPN = "PUSH NOTIFICATION"
+ let logTagSync = "SYNC"
+ let logTagServiceProficer = "SERVICE PROVIDER"
+ let logTagDatabase = "DB"
+ let logSpeedUpSyncMetadata = "SYNC METADATA"
+ let logNetworkingTasks = "NETWORKING TASKS"
+
+ // USER DEFAULTS
+ //
+ let udMigrationMultiDomains = "migrationMultiDomains"
+ let udLastVersion = "lastVersion"
+
}
/**
diff --git a/iOSClient/Networking/NCDownloadAction.swift b/iOSClient/Networking/NCDownloadAction.swift
index 3bb2c23f67..f2acb8aa99 100644
--- a/iOSClient/Networking/NCDownloadAction.swift
+++ b/iOSClient/Networking/NCDownloadAction.swift
@@ -16,7 +16,6 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
var documentController: UIDocumentInteractionController?
let utilityFileSystem = NCUtilityFileSystem()
let utility = NCUtility()
- let database = NCManageDatabase.shared
let global = NCGlobal.shared
var sceneIdentifier: String = ""
@@ -25,7 +24,9 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
func setup(sceneIdentifier: String) {
self.sceneIdentifier = sceneIdentifier
- NCNetworking.shared.addDelegate(self)
+ Task {
+ await NCNetworking.shared.transferDispatcher.addDelegate(self)
+ }
}
// MARK: - Download
@@ -68,7 +69,10 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
switch metadata.sessionSelector {
case NCGlobal.shared.selectorLoadFileQuickLook:
- let fileNamePath = self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
+ let fileNamePath = self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId,
+ fileName: metadata.fileNameView,
+ userId: metadata.userId,
+ urlBase: metadata.urlBase)
let fileNameTemp = NSTemporaryDirectory() + metadata.fileNameView
let viewerQuickLook = NCViewerQuickLook(with: URL(fileURLWithPath: fileNameTemp), isEditingEnabled: true, metadata: metadata)
if let image = UIImage(contentsOfFile: fileNamePath) {
@@ -99,8 +103,12 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
self.openActivityViewController(selectedMetadata: [metadata], controller: controller, sender: nil)
} else {
if let viewController = controller.currentViewController() {
- let image = self.utility.getImage(ocId: metadata.ocId, etag: metadata.etag, ext: NCGlobal.shared.previewExt1024)
- NCViewer().view(viewController: viewController, metadata: metadata, image: image)
+ let image = self.utility.getImage(ocId: metadata.ocId, etag: metadata.etag, ext: NCGlobal.shared.previewExt1024, userId: metadata.userId, urlBase: metadata.urlBase)
+ Task {
+ if let vc = await NCViewer().getViewerController(metadata: metadata, image: image, delegate: viewController) {
+ await viewController.navigationController?.pushViewController(vc, animated: true)
+ }
+ }
}
}
@@ -112,6 +120,14 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
self.openActivityViewController(selectedMetadata: [metadata], controller: controller, sender: nil)
+ case NCGlobal.shared.selectorPrint:
+ // waiting close menu
+ // https://github.com/nextcloud/ios/issues/2278
+// DispatchQueue.main.async {
+ DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
+ self.printDocument(metadata: metadata)
+ }
+
case NCGlobal.shared.selectorSaveAlbum:
self.saveAlbum(metadata: metadata, controller: controller)
@@ -134,29 +150,30 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
func setMetadataAvalableOffline(_ metadata: tableMetadata, isOffline: Bool) async {
if isOffline {
if metadata.directory {
- await self.database.setDirectoryAsync(serverUrl: metadata.serverUrlFileName, offline: false, metadata: metadata)
+ await NCManageDatabase.shared.setDirectoryAsync(serverUrl: metadata.serverUrlFileName, offline: false, metadata: metadata)
let predicate = NSPredicate(format: "account == %@ AND serverUrl BEGINSWITH %@ AND sessionSelector == %@ AND status == %d", metadata.account, metadata.serverUrlFileName, NCGlobal.shared.selectorSynchronizationOffline, NCGlobal.shared.metadataStatusWaitDownload)
- if let metadatas = await database.getMetadatasAsync(predicate: predicate) {
- await database.clearMetadatasSessionAsync(metadatas: metadatas)
+ if let metadatas = await NCManageDatabase.shared.getMetadatasAsync(predicate: predicate) {
+ await NCManageDatabase.shared.clearMetadatasSessionAsync(metadatas: metadatas)
}
} else {
- await database.setOffLocalFileAsync(ocId: metadata.ocId)
+ await NCManageDatabase.shared.setOffLocalFileAsync(ocId: metadata.ocId)
}
} else if metadata.directory {
- await database.setDirectoryAsync(serverUrl: metadata.serverUrlFileName, offline: true, metadata: metadata)
- await self.database.cleanTablesOcIds(account: metadata.account)
- await NCNetworking.shared.synchronization(account: metadata.account, serverUrl: metadata.serverUrlFileName, metadatasInDownload: nil)
+ await NCManageDatabase.shared.cleanTablesOcIds(account: metadata.account, userId: metadata.userId, urlBase: metadata.urlBase)
+ await NCManageDatabase.shared.setDirectoryAsync(serverUrl: metadata.serverUrlFileName, offline: true, metadata: metadata)
+ await NCNetworking.shared.synchronization(account: metadata.account, serverUrl: metadata.serverUrlFileName, userId: metadata.userId, urlBase: metadata.urlBase, metadatasInDownload: nil)
} else {
var metadatasSynchronizationOffline: [tableMetadata] = []
metadatasSynchronizationOffline.append(metadata)
- if let metadata = await database.getMetadataLivePhotoAsync(metadata: metadata) {
+ if let metadata = await NCManageDatabase.shared.getMetadataLivePhotoAsync(metadata: metadata) {
metadatasSynchronizationOffline.append(metadata)
}
- await database.addLocalFileAsync(metadata: metadata, offline: true)
+ await NCManageDatabase.shared.addLocalFileAsync(metadata: metadata, offline: true)
for metadata in metadatasSynchronizationOffline {
- await database.setMetadataSessionInWaitDownloadAsync(ocId: metadata.ocId,
- session: NCNetworking.shared.sessionDownloadBackground,
- selector: NCGlobal.shared.selectorSynchronizationOffline)
+ await NCManageDatabase.shared.setMetadataSessionInWaitDownloadAsync(ocId: metadata.ocId,
+ session: NCNetworking.shared.sessionDownloadBackground,
+ selector: NCGlobal.shared.selectorSynchronizationOffline)
+ AnalyticsHelper.shared.trackEventWithMetadata(eventName: .EVENT__OFFLINE_AVAILABLE, metadata: metadata)
}
}
}
@@ -168,12 +185,17 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
var downloadRequest: DownloadRequest?
let hud = NCHud(viewController.tabBarController?.view)
- if let metadata = await database.getMetadataFromFileIdAsync(fileId) {
+ if let metadata = await NCManageDatabase.shared.getMetadataFromFileIdAsync(fileId) {
do {
- let attr = try FileManager.default.attributesOfItem(atPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView))
+ let attr = try FileManager.default.attributesOfItem(atPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId,
+ fileName: metadata.fileNameView,
+ userId: metadata.userId,
+ urlBase: metadata.urlBase))
let fileSize = attr[FileAttributeKey.size] as? UInt64 ?? 0
if fileSize > 0 {
- NCViewer().view(viewController: viewController, metadata: metadata)
+ if let vc = await NCViewer().getViewerController(metadata: metadata, delegate: viewController) {
+ viewController.navigationController?.pushViewController(vc, animated: true)
+ }
return
}
} catch {
@@ -181,27 +203,38 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
}
}
- hud.initHudRing(tapToCancelDetailText: true) {
+ hud.ringProgress(tapToCancelDetailText: true) {
if let request = downloadRequest {
request.cancel()
}
}
- let resultsFile = await NextcloudKit.shared.getFileFromFileIdAsync(fileId: fileId, account: account)
+ let resultsFile = await NextcloudKit.shared.getFileFromFileIdAsync(fileId: fileId, account: account) { task in
+ Task {
+ let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: account,
+ path: fileId,
+ name: "getFileFromFileId")
+ await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task)
+ }
+ }
hud.dismiss()
guard resultsFile.error == .success, let file = resultsFile.file else {
NCContentPresenter().showError(error: resultsFile.error)
return
}
- let isDirectoryE2EE = await self.utilityFileSystem.isDirectoryE2EEAsync(file: file)
- let metadata = await self.database.convertFileToMetadataAsync(file, isDirectoryE2EE: isDirectoryE2EE)
- await self.database.addMetadataAsync(metadata)
+ let metadata = await NCManageDatabase.shared.convertFileToMetadataAsync(file)
+ await NCManageDatabase.shared.addMetadataAsync(metadata)
- let fileNameLocalPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
+ let fileNameLocalPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId,
+ fileName: metadata.fileNameView,
+ userId: metadata.userId,
+ urlBase: metadata.urlBase)
if metadata.isAudioOrVideo {
- NCViewer().view(viewController: viewController, metadata: metadata)
+ if let vc = await NCViewer().getViewerController(metadata: metadata, delegate: viewController) {
+ viewController.navigationController?.pushViewController(vc, animated: true)
+ }
return
}
@@ -210,25 +243,33 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
downloadRequest = request
} taskHandler: { task in
Task {
- await self.database.setMetadataSessionAsync(ocId: metadata.ocId,
- sessionTaskIdentifier: task.taskIdentifier,
- status: self.global.metadataStatusDownloading)
+ let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: metadata.account,
+ path: metadata.serverUrlFileName,
+ name: "download")
+ await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task)
+
+ let ocId = metadata.ocId
+ await NCManageDatabase.shared.setMetadataSessionAsync(ocId: ocId,
+ sessionTaskIdentifier: task.taskIdentifier,
+ status: self.global.metadataStatusDownloading)
}
} progressHandler: { progress in
hud.progress(progress.fractionCompleted)
}
hud.dismiss()
- await self.database.setMetadataSessionAsync(ocId: metadata.ocId,
- session: "",
- sessionTaskIdentifier: 0,
- sessionError: "",
- status: self.global.metadataStatusNormal,
- etag: download.etag)
+ await NCManageDatabase.shared.setMetadataSessionAsync(ocId: metadata.ocId,
+ session: "",
+ sessionTaskIdentifier: 0,
+ sessionError: "",
+ status: self.global.metadataStatusNormal,
+ etag: download.etag)
if download.nkError == .success {
- await self.database.addLocalFileAsync(metadata: metadata)
- NCViewer().view(viewController: viewController, metadata: metadata)
+ await NCManageDatabase.shared.addLocalFileAsync(metadata: metadata)
+ if let vc = await NCViewer().getViewerController(metadata: metadata, delegate: viewController) {
+ viewController.navigationController?.pushViewController(vc, animated: true)
+ }
}
}
@@ -236,35 +277,21 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
func openShare(viewController: UIViewController, metadata: tableMetadata, page: NCBrandOptions.NCInfoPagingTab) {
var page = page
- let capabilities = NKCapabilities.shared.getCapabilitiesBlocking(for: metadata.account)
+ let capabilities = NCNetworking.shared.capabilities[metadata.account] ?? NKCapabilities.Capabilities()
NCActivityIndicator.shared.start(backgroundView: viewController.view)
- NCNetworking.shared.readFile(serverUrlFileName: metadata.serverUrlFileName, account: metadata.account, queue: .main) { _, metadata, error in
- NCActivityIndicator.shared.stop()
-
- if let metadata = metadata, error == .success {
- let shareNavigationController = UIStoryboard(name: "NCShare", bundle: nil).instantiateInitialViewController() as? UINavigationController
- let shareViewController = shareNavigationController?.topViewController as? NCSharePaging
-
- for value in NCBrandOptions.NCInfoPagingTab.allCases {
- pages.append(value)
- }
-
- if capabilities.activity.isEmpty, let idx = pages.firstIndex(of: .activity) {
- pages.remove(at: idx)
- }
- if !metadata.isSharable(), let idx = pages.firstIndex(of: .sharing) {
- pages.remove(at: idx)
- }
-
- (pages, page) = NCApplicationHandle().filterPages(pages: pages, page: page, metadata: metadata)
-
- shareViewController?.pages = pages
-// let shareViewController = shareNavigationController?.topViewController as? NCShare
- shareViewController?.metadata = metadata
- shareNavigationController?.modalPresentationStyle = .formSheet
- if let shareNavigationController = shareNavigationController {
- viewController.present(shareNavigationController, animated: true, completion: nil)
+ NCNetworking.shared.readFile(serverUrlFileName: metadata.serverUrlFileName, account: metadata.account) { _, metadata, file, error in
+ Task { @MainActor in
+ NCActivityIndicator.shared.stop()
+
+ if let metadata = metadata, error == .success {
+ let shareNavigationController = UIStoryboard(name: "NCShare", bundle: nil).instantiateInitialViewController() as? UINavigationController
+ let shareViewController = shareNavigationController?.topViewController as? NCShare
+ shareViewController?.metadata = metadata
+ shareNavigationController?.modalPresentationStyle = .formSheet
+ if let shareNavigationController = shareNavigationController {
+ viewController.present(shareNavigationController, animated: true, completion: nil)
+ }
}
}
}
@@ -279,7 +306,10 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
var downloadMetadata: [(tableMetadata, URL)] = []
for metadata in metadatas {
- let fileURL = URL(fileURLWithPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView))
+ let fileURL = URL(fileURLWithPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId,
+ fileName: metadata.fileNameView,
+ userId: metadata.userId,
+ urlBase: metadata.urlBase))
if utilityFileSystem.fileProviderStorageExists(metadata) {
urls.append(fileURL)
} else {
@@ -291,20 +321,22 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
for (metadata, url) in downloadMetadata {
processor.execute { completion in
Task {
- guard let metadata = await self.database.setMetadataSessionInWaitDownloadAsync(ocId: metadata.ocId,
- session: NCNetworking.shared.sessionDownload,
- selector: "",
- sceneIdentifier: controller.sceneIdentifier) else {
+ guard let metadata = await NCManageDatabase.shared.setMetadataSessionInWaitDownloadAsync(ocId: metadata.ocId,
+ session: NCNetworking.shared.sessionDownload,
+ selector: "",
+ sceneIdentifier: controller.sceneIdentifier) else {
return completion()
}
- NCNetworking.shared.download(metadata: metadata) {
+ await NCNetworking.shared.downloadFile(metadata: metadata) { _ in
} progressHandler: { progress in
processor.hud.progress(progress.fractionCompleted)
- } completion: { _, _ in
- if self.utilityFileSystem.fileProviderStorageExists(metadata) { urls.append(url) }
- completion()
}
+
+ if self.utilityFileSystem.fileProviderStorageExists(metadata) {
+ urls.append(url)
+ }
+ completion()
}
}
}
@@ -335,9 +367,12 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
// MARK: - Save as scan
func saveAsScan(metadata: tableMetadata, controller: NCMainTabBarController?) {
- let fileNamePath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
+ let fileNamePath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId,
+ fileName: metadata.fileNameView,
+ userId: metadata.userId,
+ urlBase: metadata.urlBase)
let fileNameDestination = utilityFileSystem.createFileName("scan.png", fileDate: Date(), fileType: PHAssetMediaType.image, notUseMask: true)
- let fileNamePathDestination = utilityFileSystem.directoryScan + "/" + fileNameDestination
+ let fileNamePathDestination = utilityFileSystem.createServerUrl(serverUrl: utilityFileSystem.directoryScan, fileName: fileNameDestination)
utilityFileSystem.copyFile(atPath: fileNamePath, toPath: fileNamePathDestination)
@@ -353,7 +388,10 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
// MARK: - Save photo
func saveAlbum(metadata: tableMetadata, controller: NCMainTabBarController?) {
- let fileNamePath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId, fileNameView: metadata.fileNameView)
+ let fileNamePath = utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId,
+ fileName: metadata.fileNameView,
+ userId: metadata.userId,
+ urlBase: metadata.urlBase)
NCAskAuthorization().askAuthorizationPhotoLibrary(controller: controller) { hasPermission in
guard hasPermission else {
@@ -394,12 +432,66 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
// MARK: - Copy & Paste
- func pastePasteboard(serverUrl: String, account: String, controller: NCMainTabBarController?) {
+ func copyPasteboard(pasteboardOcIds: [String], controller: NCMainTabBarController?) {
+ var items = [[String: Any]]()
+ let hudView = controller
+
+ // getting file data can take some time and block the main queue
+ DispatchQueue.global(qos: .userInitiated).async {
+ var downloadMetadatas: [tableMetadata] = []
+ for ocid in pasteboardOcIds {
+ guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocid) else { continue }
+ if let pasteboardItem = metadata.toPasteBoardItem() {
+ items.append(pasteboardItem)
+ } else {
+ downloadMetadatas.append(metadata)
+ }
+ }
+
+ let processor = ParallelWorker(n: 5, titleKey: "_downloading_", totalTasks: downloadMetadatas.count, controller: controller)
+ for metadata in downloadMetadatas {
+ processor.execute { completion in
+ Task {
+ guard let metadata = await NCManageDatabase.shared.setMetadataSessionInWaitDownloadAsync(ocId: metadata.ocId,
+ session: NCNetworking.shared.sessionDownload,
+ selector: "",
+ sceneIdentifier: controller?.sceneIdentifier) else {
+ return completion()
+ }
+
+ await NCNetworking.shared.downloadFile(metadata: metadata) { _ in
+ } progressHandler: { progress in
+ processor.hud.progress(progress.fractionCompleted)
+ }
+
+ completion()
+ }
+ }
+ }
+
+ processor.completeWork {
+ items.append(contentsOf: downloadMetadatas.compactMap({ $0.toPasteBoardItem() }))
+ UIPasteboard.general.setItems(items, options: [:])
+ }
+ }
+ }
+
+ func pastePasteboard(serverUrl: String, account: String, controller: NCMainTabBarController?) async {
var fractionCompleted: Float = 0
let processor = ParallelWorker(n: 5, titleKey: "_status_uploading_", totalTasks: nil, controller: controller)
+ guard let tblAccount = await NCManageDatabase.shared.getTableAccountAsync(account: account) else {
+ return
+ }
func uploadPastePasteboard(fileName: String, serverUrlFileName: String, fileNameLocalPath: String, serverUrl: String, completion: @escaping () -> Void) {
NextcloudKit.shared.upload(serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, account: account) { _ in
+ } taskHandler: { task in
+ Task {
+ let identifier = await NCNetworking.shared.networkingTasks.createIdentifier(account: account,
+ path: serverUrlFileName,
+ name: "upload")
+ await NCNetworking.shared.networkingTasks.track(identifier: identifier, task: task)
+ }
} progressHandler: { progress in
if Float(progress.fractionCompleted) > fractionCompleted || fractionCompleted == 0 {
processor.hud.progress(progress.fractionCompleted)
@@ -407,11 +499,16 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
}
} completionHandler: { account, ocId, etag, _, _, _, error in
if error == .success && etag != nil && ocId != nil {
- let toPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(ocId!, fileNameView: fileName)
+ let toPath = self.utilityFileSystem.getDirectoryProviderStorageOcId(ocId!,
+ fileName: fileName,
+ userId: tblAccount.userId,
+ urlBase: tblAccount.urlBase)
self.utilityFileSystem.moveFile(atPath: fileNameLocalPath, toPath: toPath)
- self.database.addLocalFile(account: account, etag: etag!, ocId: ocId!, fileName: fileName)
- NCNetworking.shared.notifyAllDelegates { delegate in
- delegate.transferRequestData(serverUrl: serverUrl)
+ NCManageDatabase.shared.addLocalFile(account: account, etag: etag!, ocId: ocId!, fileName: fileName)
+ Task {
+ await NCNetworking.shared.transferDispatcher.notifyAllDelegates { delegate in
+ delegate.transferRequestData(serverUrl: serverUrl)
+ }
}
} else {
NCContentPresenter().showError(error: error)
@@ -423,14 +520,18 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
for (index, items) in UIPasteboard.general.items.enumerated() {
for item in items {
- let results = NKFilePropertyResolver().resolve(inUTI: item.key, account: account)
+ let capabilities = await NKCapabilities.shared.getCapabilities(for: account)
+ let results = NKFilePropertyResolver().resolve(inUTI: item.key, capabilities: capabilities)
guard let data = UIPasteboard.general.data(forPasteboardType: item.key, inItemSet: IndexSet([index]))?.first else {
continue
}
- let fileName = results.name + "_" + NCKeychain().incrementalNumber + "." + results.ext
- let serverUrlFileName = serverUrl + "/" + fileName
+ let fileName = results.name + "_" + NCPreferences().incrementalNumber + "." + results.ext
+ let serverUrlFileName = utilityFileSystem.createServerUrl(serverUrl: serverUrl, fileName: fileName)
let ocIdUpload = UUID().uuidString
- let fileNameLocalPath = utilityFileSystem.getDirectoryProviderStorageOcId(ocIdUpload, fileNameView: fileName)
+ let fileNameLocalPath = utilityFileSystem.getDirectoryProviderStorageOcId(ocIdUpload,
+ fileName: fileName,
+ userId: tblAccount.userId,
+ urlBase: tblAccount.urlBase)
do { try data.write(to: URL(fileURLWithPath: fileNameLocalPath)) } catch { continue }
processor.execute { completion in
uploadPastePasteboard(fileName: fileName, serverUrlFileName: serverUrlFileName, fileNameLocalPath: fileNameLocalPath, serverUrl: serverUrl, completion: completion)
@@ -464,8 +565,10 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
while serverUrlPush != serverUrl, !subDirs.isEmpty {
- guard let dir = subDirs.first else { return }
- serverUrlPush = serverUrlPush + "/" + dir
+ guard let dir = subDirs.first else {
+ return
+ }
+ serverUrlPush = self.utilityFileSystem.createServerUrl(serverUrl: serverUrlPush, fileName: String(dir))
if let viewController = controller.navigationCollectionViewCommon.first(where: { $0.navigationController == navigationController && $0.serverUrl == serverUrlPush})?.viewController as? NCFiles, viewController.isViewLoaded {
viewController.fileNameBlink = fileNameBlink
@@ -493,15 +596,15 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
// MARK: - NCSelect + Delegate
- func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool, session: NCSession.Session) {
- if let serverUrl, !items.isEmpty {
+ func dismissSelect(serverUrl: String?, metadata: tableMetadata?, type: String, items: [Any], overwrite: Bool, copy: Bool, move: Bool) {//, session: NCSession.Session) {
+ if let destination = serverUrl, !items.isEmpty {
if copy {
for case let metadata as tableMetadata in items {
if metadata.status != NCGlobal.shared.metadataStatusNormal, metadata.status != NCGlobal.shared.metadataStatusWaitCopy {
continue
}
- NCNetworking.shared.copyMetadata(metadata, serverUrlTo: serverUrl, overwrite: overwrite)
+ NCNetworking.shared.copyMetadata(metadata, destination: destination, overwrite: overwrite)
}
} else if move {
@@ -510,7 +613,7 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
continue
}
- NCNetworking.shared.moveMetadata(metadata, serverUrlTo: serverUrl, overwrite: overwrite)
+ NCNetworking.shared.moveMetadata(metadata, destination: destination, overwrite: overwrite)
}
}
}
@@ -522,7 +625,7 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
let topViewController = navigationController?.topViewController as? NCSelect
var listViewController = [NCSelect]()
var copyItems: [tableMetadata] = []
- let capabilities = NKCapabilities.shared.getCapabilitiesBlocking(for: controller?.account ?? "")
+ let capabilities = NCNetworking.shared.capabilities[controller?.account ?? ""] ?? NKCapabilities.Capabilities()
for item in items {
if let fileNameError = FileNameValidator.checkFileName(item.fileNameView, account: controller?.account, capabilities: capabilities) {
@@ -532,7 +635,7 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
copyItems.append(item)
}
- let homeUrl = utilityFileSystem.getHomeServer(session: session)
+ let home = utilityFileSystem.getHomeServer(session: session)
var serverUrl = copyItems[0].serverUrl
// Setup view controllers such that the current view is of the same directory the items to be copied are in
@@ -540,7 +643,7 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
// If not in the topmost directory, create a new view controller and set correct title.
// If in the topmost directory, use the default view controller as the base.
var viewController: NCSelect?
- if serverUrl != homeUrl {
+ if serverUrl != home {
viewController = UIStoryboard(name: "NCSelect", bundle: nil).instantiateViewController(withIdentifier: "NCSelect.storyboard") as? NCSelect
if viewController == nil {
return
@@ -560,9 +663,9 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
vc.navigationItem.backButtonTitle = vc.titleCurrentFolder
listViewController.insert(vc, at: 0)
- if serverUrl != homeUrl {
- if let path = utilityFileSystem.deleteLastPath(serverUrlPath: serverUrl) {
- serverUrl = path
+ if serverUrl != home {
+ if let serverDirectoryUp = utilityFileSystem.serverDirectoryUp(serverUrl: serverUrl, home: home) {
+ serverUrl = serverDirectoryUp
}
} else {
break
@@ -576,4 +679,63 @@ class NCDownloadAction: NSObject, UIDocumentInteractionControllerDelegate, NCSel
controller?.present(navigationController, animated: true, completion: nil)
}
}
+
+ // MARK: - Print
+
+ func printDocument(metadata: tableMetadata) {
+
+ let fileNameURL = URL(fileURLWithPath: utilityFileSystem.getDirectoryProviderStorageOcId(metadata.ocId,
+ fileName: metadata.fileNameView,
+ userId: metadata.userId,
+ urlBase: metadata.urlBase))
+ let printController = UIPrintInteractionController.shared
+ let printInfo = UIPrintInfo(dictionary: nil)
+
+ printInfo.jobName = fileNameURL.lastPathComponent
+ printInfo.outputType = metadata.isImage ? .photo : .general
+ printController.printInfo = printInfo
+ printController.showsNumberOfCopies = true
+
+ guard !UIPrintInteractionController.canPrint(fileNameURL) else {
+ printController.printingItem = fileNameURL
+ printController.present(animated: true)
+ return
+ }
+
+ // can't print without data
+ guard let data = try? Data(contentsOf: fileNameURL) else { return }
+
+ if let svg = SVGKImage(data: data) {
+ printController.printingItem = svg.uiImage
+ printController.present(animated: true)
+ return
+ }
+
+ guard let text = String(data: data, encoding: .utf8) else { return }
+ let formatter = UISimpleTextPrintFormatter(text: text)
+ formatter.perPageContentInsets.top = 72
+ formatter.perPageContentInsets.bottom = 72
+ formatter.perPageContentInsets.left = 72
+ formatter.perPageContentInsets.right = 72
+ printController.printFormatter = formatter
+ printController.present(animated: true)
+ }
+}
+
+fileprivate extension tableMetadata {
+ func toPasteBoardItem() -> [String: Any]? {
+ // Get Data
+ let fileUrl = URL(fileURLWithPath: NCUtilityFileSystem().getDirectoryProviderStorageOcId(ocId,
+ fileName: fileNameView,
+ userId: userId,
+ urlBase: urlBase))
+ guard NCUtilityFileSystem().fileProviderStorageExists(self),
+ let data = try? Data(contentsOf: fileUrl) else { return nil }
+
+ // Determine the UTI for the file
+ guard let fileUTI = UTType(filenameExtension: fileExtension)?.identifier else { return nil }
+
+ // Pasteboard item
+ return [fileUTI: data]
+ }
}
diff --git a/iOSClient/Scan document/PasswordInputField.swift b/iOSClient/Scan document/PasswordInputField.swift
index c2b893324b..43117f09f3 100644
--- a/iOSClient/Scan document/PasswordInputField.swift
+++ b/iOSClient/Scan document/PasswordInputField.swift
@@ -7,6 +7,7 @@
//
import Foundation
+import XLForm
class PasswordInputField: XLFormBaseCell,UITextFieldDelegate {
@@ -20,9 +21,6 @@ class PasswordInputField: XLFormBaseCell,UITextFieldDelegate {
fileNameInputTextField.delegate = self
separatorBottom.backgroundColor = NCBrandColor.shared.systemGray4
self.selectionStyle = .none
- fileNameInputTextField.inputAccessoryView = UIToolbar.doneToolbar {
- self.fileNameInputTextField.resignFirstResponder()
- }
}
override func setSelected(_ selected: Bool, animated: Bool) {
diff --git a/iOSClient/Share/Advanced/DownloadLimit/NCShareDownloadLimitTableViewController.swift b/iOSClient/Share/Advanced/DownloadLimit/NCShareDownloadLimitTableViewController.swift
index c64c18015f..783e3096c2 100644
--- a/iOSClient/Share/Advanced/DownloadLimit/NCShareDownloadLimitTableViewController.swift
+++ b/iOSClient/Share/Advanced/DownloadLimit/NCShareDownloadLimitTableViewController.swift
@@ -32,9 +32,12 @@ class NCShareDownloadLimitTableViewController: UITableViewController {
/// Default value for limits as possibly provided by the server capabilities.
///
var defaultLimit: Int {
- NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityFileSharingDownloadLimitDefaultLimit
+ let capabilities = NCNetworking.shared.capabilities[metadata.account] ?? NKCapabilities.Capabilities()
+ return capabilities.fileSharingDownloadLimitDefaultLimit
}
+ @IBOutlet var allowedDownloadsCell: UITableViewCell!
+ @IBOutlet var limitDownloadCell: UITableViewCell!
@IBOutlet var limitSwitch: UISwitch!
@IBOutlet var limitTextField: UITextField!
@@ -47,6 +50,14 @@ class NCShareDownloadLimitTableViewController: UITableViewController {
} else {
limitSwitch.isOn = false
}
+
+ var allowedDownloadsCellConfiguration = UIListContentConfiguration.cell()
+ allowedDownloadsCellConfiguration.text = NSLocalizedString("_share_allowed_downloads_", comment: "")
+ allowedDownloadsCell.contentConfiguration = allowedDownloadsCellConfiguration
+
+ var limitDownloadCellConfiguration = UIListContentConfiguration.cell()
+ limitDownloadCellConfiguration.text = NSLocalizedString("_share_limit_download_", comment: "")
+ limitDownloadCell.contentConfiguration = limitDownloadCellConfiguration
}
@IBAction func switchDownloadLimit(_ sender: UISwitch) {
diff --git a/iOSClient/Share/CreateLinkFooterView.swift b/iOSClient/Share/CreateLinkFooterView.swift
index 71e198fe64..fb07695cd0 100644
--- a/iOSClient/Share/CreateLinkFooterView.swift
+++ b/iOSClient/Share/CreateLinkFooterView.swift
@@ -48,7 +48,7 @@ class CreateLinkFooterView: UITableViewHeaderFooterView {
override func layoutSubviews() {
super.layoutSubviews()
- createButton.layer.borderColor = UIColor.label.cgColor
+ createButton.layer.borderColor = NCBrandColor.shared.label.cgColor
}
private func setupUI() {
diff --git a/iOSClient/Share/NCPermissions.swift b/iOSClient/Share/NCPermissions.swift
index 69e84c83e1..de40c00833 100644
--- a/iOSClient/Share/NCPermissions.swift
+++ b/iOSClient/Share/NCPermissions.swift
@@ -38,6 +38,11 @@ class NCPermissions: NSObject {
// Share permission
// permissions - (int) 1 = read; 2 = update; 4 = create; 8 = delete; 16 = share; 31 = all
//
+// let permissionReadShare: Int = 1
+// let permissionUpdateShare: Int = 2
+// let permissionCreateShare: Int = 4
+// let permissionDeleteShare: Int = 8
+// let permissionShareShare: Int = 16
@objc let permissionReadShare: Int = 1
@objc let permissionUpdateShare: Int = 2
@objc let permissionCreateShare: Int = 4
@@ -92,9 +97,9 @@ class NCPermissions: NSObject {
if canChange && isDirectory {
permission = permission + permissionUpdateShare
}
- if canDelete && isDirectory {
- permission = permission + permissionDeleteShare
- }
+// if canDelete && isDirectory {
+// permission = permission + permissionDeleteShare
+// }
if canShare {
permission = permission + permissionShareShare
}
diff --git a/iOSClient/Share/NCShare+Helper.swift b/iOSClient/Share/NCShare+Helper.swift
index 6f98012b78..48079eb097 100644
--- a/iOSClient/Share/NCShare+Helper.swift
+++ b/iOSClient/Share/NCShare+Helper.swift
@@ -77,11 +77,11 @@ class NCTableShareOptions: NCTableShareable {
var attributes: String?
- private init(shareType: Int, metadata: tableMetadata, password: String?) {
- if metadata.e2eEncrypted, NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityE2EEApiVersion == NCGlobal.shared.e2eeVersionV12 {
+ private init(shareType: Int, metadata: tableMetadata, password: String?) async {
+ if metadata.e2eEncrypted, await NKCapabilities.shared.getCapabilities(for: metadata.account).e2EEApiVersion == NCGlobal.shared.e2eeVersionV12 {
self.permissions = NCPermissions().permissionCreateShare
} else {
- self.permissions = NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityFileSharingDefaultPermission & metadata.sharePermissionsCollaborationServices
+ self.permissions = await NKCapabilities.shared.getCapabilities(for: metadata.account).fileSharingDefaultPermission & metadata.sharePermissionsCollaborationServices
}
self.shareType = shareType
if let password = password {
@@ -89,14 +89,14 @@ class NCTableShareOptions: NCTableShareable {
}
}
- convenience init(sharee: NKSharee, metadata: tableMetadata, password: String?) {
- self.init(shareType: sharee.shareType, metadata: metadata, password: password)
+ convenience init(sharee: NKSharee, metadata: tableMetadata, password: String?) async {
+ await self.init(shareType: sharee.shareType, metadata: metadata, password: password)
self.shareWith = sharee.shareWith
self.shareWithDisplayname = sharee.label
}
- static func shareLink(metadata: tableMetadata, password: String?) -> NCTableShareOptions {
- return NCTableShareOptions(shareType: NCShareCommon().SHARE_TYPE_LINK, metadata: metadata, password: password)
+ static func shareLink(metadata: tableMetadata, password: String?) async -> NCTableShareOptions {
+ return await NCTableShareOptions(shareType: NCShareCommon.shareTypeLink, metadata: metadata, password: password)
}
}
@@ -107,7 +107,7 @@ protocol NCShareDetail {
extension NCShareDetail where Self: UIViewController {
func setNavigationTitle() {
title = NSLocalizedString("_sharing_", comment: "")
- if share.shareType != NCShareCommon().SHARE_TYPE_LINK {
+ if share.shareType != NCShareCommon.shareTypeLink {
title! = share.shareWithDisplayname.isEmpty ? share.shareWith : share.shareWithDisplayname
}
}
diff --git a/iOSClient/Share/NCShare+NCCellDelegate.swift b/iOSClient/Share/NCShare+NCCellDelegate.swift
index 412510ed5b..0995bfc12f 100644
--- a/iOSClient/Share/NCShare+NCCellDelegate.swift
+++ b/iOSClient/Share/NCShare+NCCellDelegate.swift
@@ -29,11 +29,10 @@ extension NCShare: NCShareLinkCellDelegate, NCShareUserCellDelegate {
func copyInternalLink(sender: Any) {
guard let metadata = self.metadata else { return }
- let serverUrlFileName = metadata.serverUrl + "/" + metadata.fileName
- NCNetworking.shared.readFile(serverUrlFileName: serverUrlFileName, account: metadata.account) { _, metadata, error in
+ NCNetworking.shared.readFile(serverUrlFileName: metadata.serverUrlFileName, account: metadata.account) { _, metadata, _, error in
if error == .success, let metadata = metadata {
let internalLink = metadata.urlBase + "/index.php/f/" + metadata.fileId
- self.shareCommon.copyLink(link: internalLink, viewController: self, sender: sender)
+ NCShareCommon.copyLink(link: internalLink, viewController: self, sender: sender)
} else {
NCContentPresenter().showError(error: error)
}
@@ -44,12 +43,12 @@ extension NCShare: NCShareLinkCellDelegate, NCShareUserCellDelegate {
guard let tableShare = tableShare else {
return copyInternalLink(sender: sender)
}
- shareCommon.copyLink(link: tableShare.url, viewController: self, sender: sender)
+ NCShareCommon.copyLink(link: tableShare.url, viewController: self, sender: sender)
}
func tapMenu(with tableShare: tableShare?, sender: Any) {
if let tableShare = tableShare {
- self.toggleShareMenu(for: tableShare, sendMail: (tableShare.shareType != NCShareCommon().SHARE_TYPE_LINK), folder: metadata?.directory ?? false, sender: sender)
+ self.toggleShareMenu(for: tableShare, sendMail: (tableShare.shareType != NCShareCommon.shareTypeLink), folder: metadata?.directory ?? false, sender: sender)
} else {
self.makeNewLinkShare()
}
@@ -57,12 +56,11 @@ extension NCShare: NCShareLinkCellDelegate, NCShareUserCellDelegate {
func showProfile(with tableShare: tableShare?, sender: Any) {
guard let tableShare else { return }
- showProfileMenu(userId: tableShare.shareWith, session: session)
+ showProfileMenu(userId: tableShare.shareWith, session: session, sender: sender)
}
func quickStatus(with tableShare: tableShare?, sender: Any) {
- guard let tableShare = tableShare,
- let metadata = metadata else { return }
- self.toggleUserPermissionMenu(isDirectory: metadata.directory, tableShare: tableShare)
+ guard let tableShare, let metadata else { return }
+ self.toggleQuickPermissionsMenu(isDirectory: metadata.directory, share: tableShare, sender: sender)
}
}
diff --git a/iOSClient/Share/NCShare.storyboard b/iOSClient/Share/NCShare.storyboard
index 0c8a27be32..13289d1bd6 100644
--- a/iOSClient/Share/NCShare.storyboard
+++ b/iOSClient/Share/NCShare.storyboard
@@ -1,9 +1,8 @@
-
+
-
-
+
@@ -15,12 +14,12 @@
-
+
-
+
@@ -30,7 +29,7 @@
-
+
@@ -45,7 +44,7 @@
-
+
@@ -179,7 +178,6 @@
-
@@ -250,11 +248,255 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/iOSClient/Share/NCShare.swift b/iOSClient/Share/NCShare.swift
index 01bca50932..8ad37628d0 100644
--- a/iOSClient/Share/NCShare.swift
+++ b/iOSClient/Share/NCShare.swift
@@ -38,23 +38,32 @@ enum ShareSection: Int, CaseIterable {
}
class NCShare: UIViewController, NCSharePagingContent {
-
+// @IBOutlet weak var viewContainerConstraint: NSLayoutConstraint!
+// @IBOutlet weak var sharedWithYouByView: UIView!
+// @IBOutlet weak var sharedWithYouByImage: UIImageView!
+// @IBOutlet weak var sharedWithYouByLabel: UILabel!
+// @IBOutlet weak var searchFieldTopConstraint: NSLayoutConstraint!
+// @IBOutlet weak var searchField: UISearchBar!
+// var textField: UIView? { searchField }
var textField: UITextField? { self.view.viewWithTag(Tag.searchField) as? UITextField }
@IBOutlet weak var tableView: UITableView!
+// @IBOutlet weak var btnContact: UIButton!
weak var appDelegate = UIApplication.shared.delegate as? AppDelegate
public var metadata: tableMetadata!
- public var sharingEnabled = true
public var height: CGFloat = 0
- let shareCommon = NCShareCommon()
let utilityFileSystem = NCUtilityFileSystem()
let utility = NCUtility()
let database = NCManageDatabase.shared
+ var shareLinksCount = 0
+
var canReshare: Bool {
- return ((metadata.sharePermissionsCollaborationServices & NKShare.Permission.share.rawValue) != 0)
+ guard let metadata = metadata else { return true }
+ return ((metadata.sharePermissionsCollaborationServices & NCPermissions().permissionShareShare) != 0)
+// return ((metadata.sharePermissionsCollaborationServices & NCSharePermissions.permissionReshareShare) != 0)
}
var session: NCSession.Session {
@@ -63,6 +72,8 @@ class NCShare: UIViewController, NCSharePagingContent {
var shares: (firstShareLink: tableShare?, share: [tableShare]?) = (nil, nil)
+ var capabilities = NKCapabilities.Capabilities()
+
private var dropDown = DropDown()
var networking: NCShareNetworking?
@@ -76,25 +87,21 @@ class NCShare: UIViewController, NCSharePagingContent {
var shareEmails: [tableShare] = []
var shareOthers: [tableShare] = []
private var cachedHeader: NCShareAdvancePermissionHeader?
- // Stores the next number per share
-// var nextLinkNumberByShare: [String: Int] = [:]
-//
-// // Stores assigned numbers for each link (per share)
-// var linkNumbersByShare: [String: [String: Int]] = [:]
-
-// var shareLinksCount = 0
-
+
// MARK: - View Life Cycle
override func viewDidLoad() {
super.viewDidLoad()
- view.backgroundColor = .secondarySystemGroupedBackground
+ navigationController?.setNavigationBarAppearance()
+ view.backgroundColor = .systemBackground
+ title = NSLocalizedString("_details_", comment: "")
tableView.dataSource = self
tableView.delegate = self
tableView.allowsSelection = false
- tableView.backgroundColor = .secondarySystemGroupedBackground
+ tableView.backgroundColor = .systemBackground
+ tableView.contentInset = UIEdgeInsets(top: 8, left: 0, bottom: 10, right: 0)
tableView.register(UINib(nibName: "NCShareLinkCell", bundle: nil), forCellReuseIdentifier: "cellLink")
tableView.register(UINib(nibName: "NCShareUserCell", bundle: nil), forCellReuseIdentifier: "cellUser")
@@ -107,33 +114,38 @@ class NCShare: UIViewController, NCSharePagingContent {
forHeaderFooterViewReuseIdentifier: NCShareAdvancePermissionHeader.reuseIdentifier)
NotificationCenter.default.addObserver(self, selector: #selector(reloadData), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterReloadDataNCShare), object: nil)
+ NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow), name: UIResponder.keyboardWillShowNotification, object: nil)
+ NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide), name: UIResponder.keyboardWillHideNotification, object: nil)
+ NotificationCenter.default.addObserver(self, selector: #selector(appWillEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
+ NotificationCenter.default.addObserver(self, selector: #selector(reloadData), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterDidCreateShareLink), object: nil)
+// NotificationCenter.default.addObserver(self, selector: #selector(handleFavoriteStatusChanged), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterFavoriteStatusChanged), object: nil)
+ guard let metadata = metadata else { return }
+
+ reloadData()
+
Task {
self.capabilities = await NKCapabilities.shared.getCapabilities(for: metadata.account)
if metadata.e2eEncrypted {
let metadataDirectory = await self.database.getMetadataDirectoryAsync(serverUrl: metadata.serverUrl, account: metadata.account)
if capabilities.e2EEApiVersion == NCGlobal.shared.e2eeVersionV12 ||
(capabilities.e2EEApiVersion == NCGlobal.shared.e2eeVersionV20 && metadataDirectory?.e2eEncrypted ?? false) {
- searchFieldTopConstraint.constant = -50
- searchField.alpha = 0
- btnContact.alpha = 0
}
} else {
- checkSharedWithYou()
}
-
- reloadData()
-
- networking = NCShareNetworking(metadata: metadata, view: self.view, delegate: self, session: session)
- if sharingEnabled {
+
+ networking = NCShareNetworking(metadata: metadata, view: self.view, delegate: self, session: session)
let isVisible = (self.navigationController?.topViewController as? NCSharePaging)?.page == .sharing
networking?.readShare(showLoadingIndicator: isVisible)
-
- searchField.searchTextField.font = .systemFont(ofSize: 14)
- searchField.delegate = self
}
+
+ navigationItem.leftBarButtonItem = UIBarButtonItem(title: NSLocalizedString("_close_", comment: ""), style: .plain, target: self, action: #selector(exitTapped))
}
+ override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
+ super.traitCollectionDidChange(previousTraitCollection)
+ }
+
@objc func exitTapped() {
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUpdateIcons)
self.dismiss(animated: true, completion: nil)
@@ -143,7 +155,7 @@ class NCShare: UIViewController, NCSharePagingContent {
guard
let advancePermission = UIStoryboard(name: "NCShare", bundle: nil).instantiateViewController(withIdentifier: "NCShareAdvancePermission") as? NCShareAdvancePermission,
let navigationController = self.navigationController else { return }
- self.checkEnforcedPassword(shareType: NKShare.ShareType.publicLink.rawValue) { password in
+ self.checkEnforcedPassword(shareType: NCShareCommon.shareTypeLink) { password in
advancePermission.networking = self.networking
advancePermission.share = TransientShare.shareLink(metadata: self.metadata, password: password)
advancePermission.metadata = self.metadata
@@ -153,11 +165,10 @@ class NCShare: UIViewController, NCSharePagingContent {
// MARK: - Notification Center
- @objc func openShareProfile() {
- guard let metadata = metadata else { return }
- self.showProfileMenu(userId: metadata.ownerId, session: session)
+ @objc func openShareProfile(_ sender: UITapGestureRecognizer) {
+ self.showProfileMenu(userId: metadata.ownerId, session: session, sender: sender.view)
}
-
+
private func scrollToTopIfNeeded() {
if tableView.numberOfSections > 0 && tableView.numberOfRows(inSection: 0) > 0 {
self.tableView.scrollToRow(at: IndexPath(row: 0, section: 0), at: .top, animated: false)
@@ -210,28 +221,12 @@ class NCShare: UIViewController, NCSharePagingContent {
reloadData()
}
-// @objc private func handleShareCountsUpdate(notification: Notification) {
-// guard let userInfo = notification.userInfo,
-// let links = userInfo["links"] as? Int,
-// let emails = userInfo["emails"] as? Int else { return }
-//
-// if let header = tableView.headerView(forSection: ShareSection.header.rawValue) as? NCShareAdvancePermissionHeader {
-// header.setupUI(with: metadata,
-// linkCount: links,
-// emailCount: emails)
-// } else {
-// let headerSection = IndexSet(integer: ShareSection.header.rawValue)
-// tableView.reloadSections(headerSection, with: .none)
-// }
-// }
-
// MARK: -
-
+
@objc func reloadData() {
guard let metadata = metadata else {
return
}
-// shares = (nil, nil) // reset
shares = self.database.getTableShares(metadata: metadata)
updateShareArrays()
tableView.reloadData()
@@ -242,7 +237,7 @@ class NCShare: UIViewController, NCSharePagingContent {
shareEmails.removeAll()
guard var allShares = shares.share else { return }
-
+ allShares = allShares.sorted(by: { $0.date?.compare($1.date as Date? ?? Date()) == .orderedAscending })
if let firstLink = shares.firstShareLink {
// Remove if already exists to avoid duplication
allShares.removeAll { $0.idShare == firstLink.idShare }
@@ -252,249 +247,36 @@ class NCShare: UIViewController, NCSharePagingContent {
shares.share = allShares
for item in allShares {
- if item.shareType == shareCommon.SHARE_TYPE_LINK {
+ if item.shareType == NCShareCommon.shareTypeLink {
shareLinks.append(item)
} else {
shareEmails.append(item)
}
}
}
-
-// func updateShareArrays() {
-// shareLinks.removeAll()
-// shareEmails.removeAll()
-//
-// var allShares = shares.share ?? []
-//
-// if let firstLink = shares.firstShareLink {
-// if let idx = allShares.firstIndex(where: { $0.idShare == firstLink.idShare }) {
-// allShares.remove(at: idx) // only one removal
-// }
-// allShares.insert(firstLink, at: 0)
-// }
-//
-// shares.share = allShares
-//
-// for item in allShares {
-// if item.shareType == shareCommon.SHARE_TYPE_LINK {
-// shareLinks.append(item)
-// } else {
-// shareEmails.append(item)
-// }
-// }
-// }
-
-
-
-
-// func updateShareArrays() {
-// shareLinks.removeAll()
-// shareEmails.removeAll()
-//
-// if let shareLink = shares.firstShareLink {
-// shares.share?.insert(shareLink, at: 0)
-// }
-//
-// guard let allShares = shares.share else { return }
-//
-//// // Use current shareId as the scope
-//// let shareId = metadata?.ocId ?? "0"
-////
-//// // Ensure storage exists for this share
-//// if nextLinkNumberByShare[shareId] == nil {
-//// nextLinkNumberByShare[shareId] = 1
-//// linkNumbersByShare[shareId] = [:]
-//// }
-//
-// for item in allShares {
-// if item.shareType == shareCommon.SHARE_TYPE_LINK {
-// shareLinks.append(item)
-// } else {
-// shareEmails.append(item)
-// }
-// }
-//
-//// // Sort links by assigned number (per-share)
-//// shareLinks.sort { lhs, rhs in
-//// let lhsNum = linkNumbersByShare[shareId]?[String(lhs.idShare)] ?? 0
-//// let rhsNum = linkNumbersByShare[shareId]?[String(rhs.idShare)] ?? 0
-//// return lhsNum < rhsNum
-//// }
-////
-//// // ✅ If this share has no links, reset numbering for it
-//// if shareLinks.isEmpty {
-//// linkNumbersByShare[shareId] = [:]
-//// nextLinkNumberByShare[shareId] = 1
-//// saveLinkNumberData()
-//// }
-//
-//// NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare,
-//// userInfo: ["links": shareLinks.count,
-//// "emails": shareEmails.count])
-// }
-
-// // MARK: - Persistence
-// func saveLinkNumberData() {
-// // Save both maps as UserDefaults property lists
-// UserDefaults.standard.set(linkNumbersByShare, forKey: "linkNumbersByShare")
-// UserDefaults.standard.set(nextLinkNumberByShare, forKey: "nextLinkNumberByShare")
-// }
-//
-// func loadLinkNumberData() {
-// if let savedMap = UserDefaults.standard.dictionary(forKey: "linkNumbersByShare") as? [String: [String: Int]] {
-// linkNumbersByShare = savedMap
-// } else {
-// linkNumbersByShare = [:]
-// }
-//
-// if let savedNext = UserDefaults.standard.dictionary(forKey: "nextLinkNumberByShare") as? [String: Int] {
-// nextLinkNumberByShare = savedNext
-// } else {
-// nextLinkNumberByShare = [:]
-// }
-// }
-//
-// // MARK: - Number Assignment
-//
-// // Assign number to a link (or reuse existing)
-// func assignLinkNumber(forShare shareId: String, linkId: String) -> Int {
-// if nextLinkNumberByShare[shareId] == nil {
-// nextLinkNumberByShare[shareId] = 1
-// linkNumbersByShare[shareId] = [:]
-// }
-//
-// if let number = linkNumbersByShare[shareId]?[linkId] {
-// return number
-// }
-//
-// let nextNum = nextLinkNumberByShare[shareId]!
-// linkNumbersByShare[shareId]?[linkId] = nextNum
-// nextLinkNumberByShare[shareId]! += 1
-// return nextNum
-// }
-//
-// func removeLink(forShare shareId: String, linkId: String) {
-// linkNumbersByShare[shareId]?.removeValue(forKey: linkId)
-//
-// if linkNumbersByShare[shareId]?.isEmpty ?? true {
-// linkNumbersByShare[shareId] = [:]
-// nextLinkNumberByShare[shareId] = 1
-// }
-// }
-
-
-
-// func updateShareArrays() {
-// shareLinks.removeAll()
-// shareEmails.removeAll()
-//
-// if let shareLink = shares.firstShareLink {
-// shares.share?.insert(shareLink, at: 0)
-// }
-//
-// guard let allShares = shares.share else { return }
-//
-// // Use current shareId as the scope
-// let shareId = metadata?.ocId ?? "0"
-//
-// // Ensure storage exists for this share
-// if nextLinkNumberByShare[shareId] == nil {
-// nextLinkNumberByShare[shareId] = 1
-// linkNumbersByShare[shareId] = [:]
-// }
-//
-// for item in allShares {
-// if item.shareType == shareCommon.SHARE_TYPE_LINK {
-// let linkId = String(item.idShare)
-//
-// // Assign a number if missing
-// if linkNumbersByShare[shareId]?[linkId] == nil {
-// let nextNum = nextLinkNumberByShare[shareId] ?? 1
-// linkNumbersByShare[shareId]?[linkId] = nextNum
-// nextLinkNumberByShare[shareId] = nextNum + 1
-// saveLinkNumberData()
-// }
-//// if item.shareType == shareCommon.SHARE_TYPE_LINK { shareLinksCount += 1 }
-//
-// shareLinks.append(item)
-// } else {
-// shareEmails.append(item)
-// }
-// }
-//
-// // Sort links by assigned number (per-share)
-// shareLinks.sort { lhs, rhs in
-// let lhsNum = linkNumbersByShare[shareId]?[String(lhs.idShare)] ?? 0
-// let rhsNum = linkNumbersByShare[shareId]?[String(rhs.idShare)] ?? 0
-// return lhsNum < rhsNum
-// }
-//
-// // ✅ If this share has no links, reset numbering for it
-// if shareLinks.isEmpty {
-// linkNumbersByShare[shareId] = [:]
-// nextLinkNumberByShare[shareId] = 1
-// saveLinkNumberData()
-// }
-//
-//// NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare,
-//// userInfo: ["links": shareLinks.count,
-//// "emails": shareEmails.count])
-// }
-//
-// // MARK: - Persistence
-// func saveLinkNumberData() {
-// // Save both maps as UserDefaults property lists
-// UserDefaults.standard.set(linkNumbersByShare, forKey: "linkNumbersByShare")
-// UserDefaults.standard.set(nextLinkNumberByShare, forKey: "nextLinkNumberByShare")
-// }
-//
-// func loadLinkNumberData() {
-// if let savedMap = UserDefaults.standard.dictionary(forKey: "linkNumbersByShare") as? [String: [String: Int]] {
-// linkNumbersByShare = savedMap
-// } else {
-// linkNumbersByShare = [:]
-// }
-//
-// if let savedNext = UserDefaults.standard.dictionary(forKey: "nextLinkNumberByShare") as? [String: Int] {
-// nextLinkNumberByShare = savedNext
-// } else {
-// nextLinkNumberByShare = [:]
-// }
-// }
-//
-// // MARK: - Number Assignment
-//
-// // Assign number to a link (or reuse existing)
-// func assignLinkNumber(forShare shareId: String, linkId: String) -> Int {
-// if nextLinkNumberByShare[shareId] == nil {
-// nextLinkNumberByShare[shareId] = 1
-// linkNumbersByShare[shareId] = [:]
-// }
-//
-// if let number = linkNumbersByShare[shareId]?[linkId] {
-// return number
-// }
-//
-// let nextNum = nextLinkNumberByShare[shareId]!
-// linkNumbersByShare[shareId]?[linkId] = nextNum
-// nextLinkNumberByShare[shareId]! += 1
-// return nextNum
-// }
-//
-// func removeLink(forShare shareId: String, linkId: String) {
-// linkNumbersByShare[shareId]?.removeValue(forKey: linkId)
-//
-// if linkNumbersByShare[shareId]?.isEmpty ?? true {
-// linkNumbersByShare[shareId] = [:]
-// nextLinkNumberByShare[shareId] = 1
-// }
-// }
+ @objc func handleFavoriteStatusChanged(notification: Notification) {
+ // Retrieve the updated metadata from the notification object
+ if let updatedMetadata = notification.object as? tableMetadata {
+ // Update the table view header with the new metadata
+ if let headerView = tableView.tableHeaderView as? NCShareAdvancePermissionHeader {
+ headerView.setupUI(with: updatedMetadata, linkCount: shareLinks.count, emailCount: shareEmails.count) // Update header UI with new metadata
+ }
+ }
+ }
// MARK: - IBAction
@IBAction func searchFieldDidEndOnExit(textField: UITextField) {
+ // https://stackoverflow.com/questions/25471114/how-to-validate-an-e-mail-address-in-swift
+ func isValidEmail(_ email: String) -> Bool {
+
+ let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
+ let emailPred = NSPredicate(format: "SELF MATCHES %@", emailRegEx)
+ return emailPred.evaluate(with: email)
+ }
guard let searchString = textField.text, !searchString.isEmpty else { return }
+// if searchString.contains("@"), !isValidEmail(searchString) { return }
if searchString.contains("@"), !utility.validateEmail(searchString) { return }
networking?.getSharees(searchString: searchString)
}
@@ -505,23 +287,26 @@ class NCShare: UIViewController, NCSharePagingContent {
if searchString.count == 0 {
dropDown.hide()
} else {
-// networking?.getSharees(searchString: searchString)
perform(#selector(searchSharees), with: nil, afterDelay: 0.5)
}
}
-// @objc private func searchSharees() {
-// // https://stackoverflow.com/questions/25471114/how-to-validate-an-e-mail-address-in-swift
-// func isValidEmail(_ email: String) -> Bool {
-//
-// let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
-// let emailPred = NSPredicate(format: "SELF MATCHES %@", emailRegEx)
-// return emailPred.evaluate(with: email)
-// }
-// guard let searchString = textField?.text, !searchString.isEmpty else { return }
-// if searchString.contains("@"), !isValidEmail(searchString) { return }
-// networking?.getSharees(searchString: searchString)
-// }
+ func checkEnforcedPassword(shareType: Int, completion: @escaping (String?) -> Void) {
+ guard capabilities.fileSharingPubPasswdEnforced,
+ shareType == NCShareCommon.shareTypeLink || shareType == NCShareCommon.shareTypeEmail
+ else { return completion(nil) }
+
+ self.present(UIAlertController.password(titleKey: "_enforce_password_protection_", completion: completion), animated: true)
+ }
+
+ @IBAction func selectContactClicked(_ sender: Any) {
+ let cnPicker = CNContactPickerViewController()
+ cnPicker.delegate = self
+ cnPicker.displayedPropertyKeys = [CNContactEmailAddressesKey]
+ cnPicker.predicateForEnablingContact = NSPredicate(format: "emailAddresses.@count > 0")
+ cnPicker.predicateForSelectionOfProperty = NSPredicate(format: "emailAddresses.@count > 0")
+ self.present(cnPicker, animated: true)
+ }
@IBAction func createLinkClicked(_ sender: Any?) {
appDelegate?.adjust.trackEvent(TriggerEvent(CreateLink.rawValue))
@@ -533,7 +318,8 @@ class NCShare: UIViewController, NCSharePagingContent {
@IBAction func touchUpInsideButtonMenu(_ sender: Any) {
guard let metadata = metadata else { return }
- let isFilesSharingPublicPasswordEnforced = NCCapabilities.Capabilities().capabilityFileSharingPubPasswdEnforced
+ let capabilities = NCNetworking.shared.capabilities[metadata.account] ?? NKCapabilities.Capabilities()
+ let isFilesSharingPublicPasswordEnforced = capabilities.fileSharingPubPasswdEnforced
let shares = NCManageDatabase.shared.getTableShares(metadata: metadata)
if isFilesSharingPublicPasswordEnforced && shares.firstShareLink == nil {
@@ -552,108 +338,89 @@ class NCShare: UIViewController, NCSharePagingContent {
present(alertController, animated: true, completion:nil)
} else if shares.firstShareLink == nil {
networking?.createShareLink(password: "")
+
} else {
networking?.createShareLink(password: "")
}
}
- private func createShareAndReload(password: String) {
- networking?.createShareLink(password: password)
-
- // Delay to wait for DB update or async API completion
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.2) {
- self.reloadData()
- }
- }
-
-
- @IBAction func selectContactClicked(_ sender: Any) {
- let cnPicker = CNContactPickerViewController()
- cnPicker.delegate = self
- cnPicker.displayedPropertyKeys = [CNContactEmailAddressesKey]
- cnPicker.predicateForEnablingContact = NSPredicate(format: "emailAddresses.@count > 0")
- cnPicker.predicateForSelectionOfProperty = NSPredicate(format: "emailAddresses.@count > 0")
-
- self.present(cnPicker, animated: true)
- }
-
- func checkEnforcedPassword(shareType: Int, completion: @escaping (String?) -> Void) {
- guard capabilities.fileSharingPubPasswdEnforced,
- shareType == NKShare.ShareType.publicLink.rawValue || shareType == NKShare.ShareType.email.rawValue
- else { return completion(nil) }
-
- self.present(UIAlertController.password(titleKey: "_enforce_password_protection_", completion: completion), animated: true)
- }
}
- // MARK: - NCShareNetworkingDelegate
+// MARK: - NCShareNetworkingDelegate
extension NCShare: NCShareNetworkingDelegate {
func readShareCompleted() {
NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare)
-// self.reloadData()
+ reloadData()
}
func shareCompleted() {
-// NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare)
-// self.reloadData()
- // Allow DB async save to finish before reload
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
- self.reloadData()
- }
+ NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare)
+ reloadData()
}
func unShareCompleted() {
-// NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterReloadDataNCShare)
- // Same buffer for consistency
- DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
- self.reloadData()
- }
+ reloadData()
}
-// func unShareCompleted() {
-// DispatchQueue.main.async {
-// self.reloadData()
-// }
-// }
func updateShareWithError(idShare: Int) {
- self.reloadData()
+ reloadData()
}
func getSharees(sharees: [NKSharee]?) {
- guard let sharees else { return }
+ guard let sharees else {
+ return
+ }
+
+ // close keyboard
+// self.view.endEditing(true)
dropDown = DropDown()
let appearance = DropDown.appearance()
- appearance.backgroundColor = .secondarySystemGroupedBackground
+// // Setting up the blur effect
+// let blurEffect = UIBlurEffect(style: .light) // You can choose .dark, .extraLight, or .light
+// let blurEffectView = UIVisualEffectView(effect: blurEffect)
+// blurEffectView.frame = CGRect(x: 0, y: 0, width: 500, height: 20)
+
+ appearance.backgroundColor = .systemBackground
appearance.cornerRadius = 10
- appearance.shadowColor = UIColor(white: 0.5, alpha: 1)
- appearance.shadowOpacity = 0.9
- appearance.shadowRadius = 25
+ appearance.shadowColor = .black
+ appearance.shadowOpacity = 0.2
+ appearance.shadowRadius = 30
appearance.animationduration = 0.25
appearance.textColor = .darkGray
appearance.setupMaskedCorners([.layerMaxXMaxYCorner, .layerMinXMaxYCorner])
+ let account = NCManageDatabase.shared.getTableAccount(account: metadata.account)
+ let existingShares = NCManageDatabase.shared.getTableShares(metadata: metadata)
+
for sharee in sharees {
+ if sharee.shareWith == account?.user { continue } // do not show your own account
+ if let shares = existingShares.share, shares.contains(where: {$0.shareWith == sharee.shareWith}) { continue } // do not show already existing sharees
+ if metadata.ownerDisplayName == sharee.shareWith { continue } // do not show owner of the share
var label = sharee.label
- if sharee.shareType == NKShare.ShareType.team.rawValue {
+ if sharee.shareType == NCShareCommon.shareTypeTeam {
label += " (\(sharee.circleInfo), \(sharee.circleOwner))"
}
+
dropDown.dataSource.append(label)
}
dropDown.anchorView = textField
- dropDown.bottomOffset = CGPoint(x: 0, y: textField?.bounds.height ?? 0)
- dropDown.width = textField?.bounds.width ?? 0
- if (UIDevice.current.userInterfaceIdiom == .phone || UIDevice.current.orientation.isLandscape), UIScreen.main.bounds.width < 1111 {
- dropDown.topOffset = CGPoint(x: 0, y: -(textField?.bounds.height ?? 0))
- dropDown.direction = .top
- } else {
- dropDown.bottomOffset = CGPoint(x: 0, y: (textField?.bounds.height ?? 0) - 80)
- dropDown.direction = .any
- }
+ dropDown.bottomOffset = CGPoint(x: 10, y: textField?.bounds.height ?? 0)
+ dropDown.width = (textField?.bounds.width ?? 0) - 20
+ dropDown.direction = .bottom
+// dropDown.bottomOffset = CGPoint(x: 0, y: textField?.bounds.height ?? 0)
+// dropDown.width = textField?.bounds.width ?? 0
+// if (UIDevice.current.userInterfaceIdiom == .phone || UIDevice.current.orientation.isLandscape), UIScreen.main.bounds.width < 1111 {
+// dropDown.topOffset = CGPoint(x: 0, y: -(textField?.bounds.height ?? 0))
+// dropDown.direction = .top
+// } else {
+// dropDown.bottomOffset = CGPoint(x: 0, y: (textField?.bounds.height ?? 0) - 80)
+// dropDown.direction = .any
+// }
dropDown.cellNib = UINib(nibName: "NCSearchUserDropDownCell", bundle: nil)
dropDown.customCellConfiguration = { (index: Index, _, cell: DropDownCell) in
@@ -688,19 +455,6 @@ extension NCShare: NCShareNetworkingDelegate {
func downloadLimitSet(to limit: Int, by token: String) {
database.createDownloadLimit(account: metadata.account, count: 0, limit: limit, token: token)
}
-
- func checkIsCollaboraFile() -> Bool {
- guard let metadata = metadata else {
- return false
- }
-
- // EDITORS
- let editors = utility.editorsDirectEditing(account: metadata.account, contentType: metadata.contentType)
- let availableRichDocument = utility.isTypeFileRichDocument(metadata)
-
- // RichDocument: Collabora
- return (availableRichDocument && editors.count == 0)
- }
}
// MARK: - UITableViewDelegate
@@ -791,76 +545,10 @@ extension NCShare: UITableViewDataSource {
cell.configure(with: tableShare, at: indexPath, isDirectory: metadata.directory, userId: session.userId)
return cell
}
-
- // Setup default share cells
- guard indexPath.section != 0 else {
- guard let cell = tableView.dequeueReusableCell(withIdentifier: "cellLink", for: indexPath) as? NCShareLinkCell
- else { return UITableViewCell() }
- cell.delegate = self
- if metadata.e2eEncrypted, capabilities.e2EEApiVersion == NCGlobal.shared.e2eeVersionV12 {
- cell.tableShare = shares.firstShareLink
- } else {
- if indexPath.row == 0 {
- cell.isInternalLink = true
- } else if shares.firstShareLink?.isInvalidated != true {
- cell.tableShare = shares.firstShareLink
- }
- }
- cell.isDirectory = metadata.directory
- cell.setupCellUI()
- shareLinksCount += 1
- return cell
- }
+ }
- let orderedShares = shares.share?.sorted(by: { $0.date?.compare($1.date as Date? ?? Date()) == .orderedAscending })
- guard let tableShare = orderedShares?[indexPath.row] else { return UITableViewCell() }
-
- // LINK, EMAIL
- if tableShare.shareType == NKShare.ShareType.publicLink.rawValue || tableShare.shareType == NKShare.ShareType.email.rawValue {
- if let cell = tableView.dequeueReusableCell(withIdentifier: "cellLink", for: indexPath) as? NCShareLinkCell {
- cell.indexPath = indexPath
- cell.tableShare = tableShare
- cell.delegate = self
- cell.setupCellUI()
- if !tableShare.label.isEmpty {
- cell.labelTitle.text = String(format: NSLocalizedString("_share_linklabel_", comment: ""), tableShare.label)
- } else {
- cell.labelTitle.text = directory ? NSLocalizedString("_share_link_folder_", comment: "") : NSLocalizedString("_share_link_file_", comment: "")
- }
-// cell.setupCellUI(userId: session.userId)
- let isEditingAllowed = shareCommon.isEditingEnabled(isDirectory: directory, fileExtension: metadata?.fileExtension ?? "", shareType: tableShare.shareType)
- if isEditingAllowed || directory || checkIsCollaboraFile() {
- cell.btnQuickStatus.isEnabled = true
- cell.labelQuickStatus.textColor = NCBrandColor.shared.brand
- cell.imageDownArrow.image = UIImage(named: "downArrow")?.imageColor(NCBrandColor.shared.brand)
- } else {
- cell.btnQuickStatus.isEnabled = false
- cell.labelQuickStatus.textColor = NCBrandColor.shared.optionItem
- cell.imageDownArrow.image = UIImage(named: "downArrow")?.imageColor(NCBrandColor.shared.optionItem)
- }
-
- return cell
- } else {
- // USER / GROUP etc.
- if let cell = tableView.dequeueReusableCell(withIdentifier: "cellUser", for: indexPath) as? NCShareUserCell {
- cell.tableShare = tableShare
- cell.isDirectory = metadata.directory
- cell.delegate = self
- cell.setupCellUI(userId: session.userId, session: session, metadata: metadata)
- // cell.setupCellUI(userId: appDelegate.userId)
- let isEditingAllowed = shareCommon.isEditingEnabled(isDirectory: directory, fileExtension: metadata?.fileExtension ?? "", shareType: tableShare.shareType)
- if isEditingAllowed || checkIsCollaboraFile() {
- cell.btnQuickStatus.isEnabled = true
- } else {
- cell.btnQuickStatus.isEnabled = false
- cell.labelQuickStatus.textColor = NCBrandColor.shared.optionItem
- cell.imageDownArrow.image = UIImage(named: "downArrow")?.imageColor(NCBrandColor.shared.optionItem)
- }
- return cell
- }
- }
- }
- return UITableViewCell()
+ func numberOfRows(in section: Int) -> Int {
+ return tableView(tableView, numberOfRowsInSection: section)
}
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
@@ -868,9 +556,9 @@ extension NCShare: UITableViewDataSource {
switch sectionType {
case .header:
- let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: NCShareAdvancePermissionHeader.reuseIdentifier) as! NCShareAdvancePermissionHeader
- headerView.ocId = metadata.ocId
- headerView.setupUI(with: metadata, linkCount: shareLinks.count, emailCount: shareEmails.count)
+ let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: NCShareAdvancePermissionHeader.reuseIdentifier) as? NCShareAdvancePermissionHeader
+ headerView?.ocId = metadata.ocId
+ headerView?.setupUI(with: metadata, linkCount: shareLinks.count, emailCount: shareEmails.count)
return headerView
case .linkByEmail:
@@ -878,16 +566,16 @@ extension NCShare: UITableViewDataSource {
case .links:
if isCurrentUser || canReshare {
- let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "NCShareEmailLinkHeaderView") as! NCShareEmailLinkHeaderView
- headerView.configure(text: NSLocalizedString("_share_copy_link_", comment: ""))
+ let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "NCShareEmailLinkHeaderView") as? NCShareEmailLinkHeaderView
+ headerView?.configure(text: NSLocalizedString("_share_copy_link_", comment: "123"))
return headerView
}
return nil
case .emails:
if (isCurrentUser || canReshare) && numberOfRows(in: section) > 0 {
- let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "NCShareEmailLinkHeaderView") as! NCShareEmailLinkHeaderView
- headerView.configure(text: NSLocalizedString("_share_shared_with_", comment: ""))
+ let headerView = tableView.dequeueReusableHeaderFooterView(withIdentifier: "NCShareEmailLinkHeaderView") as? NCShareEmailLinkHeaderView
+ headerView?.configure(text: NSLocalizedString("_share_shared_with_", comment: ""))
return headerView
}
return nil
@@ -917,8 +605,8 @@ extension NCShare: UITableViewDataSource {
switch sectionType {
case .links:
- let footer = tableView.dequeueReusableHeaderFooterView(withIdentifier: CreateLinkFooterView.reuseIdentifier) as! CreateLinkFooterView
- footer.createButtonAction = { [weak self] in
+ let footer = tableView.dequeueReusableHeaderFooterView(withIdentifier: CreateLinkFooterView.reuseIdentifier) as? CreateLinkFooterView
+ footer?.createButtonAction = { [weak self] in
self?.createLinkClicked(nil)
}
return footer
@@ -949,34 +637,31 @@ extension NCShare: UITableViewDataSource {
}
}
-
}
-//MARK: CNContactPickerDelegate
+
+// MARK: - CNContactPickerDelegate
extension NCShare: CNContactPickerDelegate {
func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact) {
if contact.emailAddresses.count > 1 {
- showEmailList(arrEmail: contact.emailAddresses.map({$0.value as String}))
+ showEmailList(arrEmail: contact.emailAddresses.map({$0.value as String}), sender: picker)
} else if let email = contact.emailAddresses.first?.value as? String {
textField?.text = email
networking?.getSharees(searchString: email)
}
}
-
- func contactPickerDidCancel(_ picker: CNContactPickerViewController) {
- self.keyboardWillHide(notification: Notification(name: Notification.Name("dismiss")))
- }
-
- func showEmailList(arrEmail: [String]) {
+
+ func showEmailList(arrEmail: [String], sender: Any?) {
var actions = [NCMenuAction]()
for email in arrEmail {
actions.append(
NCMenuAction(
title: email,
- icon: utility.loadImage(named: "email").imageColor(NCBrandColor.shared.brandElement),
+ icon: utility.loadImage(named: "email", colors: [NCBrandColor.shared.iconImageColor]),
selected: false,
on: false,
+ sender: sender,
action: { _ in
self.textField?.text = email
self.networking?.getSharees(searchString: email)
@@ -985,7 +670,7 @@ extension NCShare: CNContactPickerDelegate {
)
}
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
- self.presentMenu(with: actions)
+ self.presentMenu(with: actions, sender: sender)
}
}
}
@@ -994,27 +679,25 @@ extension NCShare: CNContactPickerDelegate {
extension NCShare: UISearchBarDelegate {
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String) {
- NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(searchSharees), object: nil)
+ NSObject.cancelPreviousPerformRequests(withTarget: self, selector: #selector(searchSharees(_:)), object: nil)
if searchText.isEmpty {
dropDown.hide()
} else {
- perform(#selector(searchSharees), with: nil, afterDelay: 0.5)
+ perform(#selector(searchSharees(_:)), with: nil, afterDelay: 0.5)
}
}
- @objc private func searchSharees() {
-// // https://stackoverflow.com/questions/25471114/how-to-validate-an-e-mail-address-in-swift
+ @objc private func searchSharees(_ sender: Any?) {
+ // https://stackoverflow.com/questions/25471114/how-to-validate-an-e-mail-address-in-swift
func isValidEmail(_ email: String) -> Bool {
-// let emailRegEx = "^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-\\u00a1-\\uffff]+\\.[A-Za-z\\u00a1-\\uffff]{2,64}$"
let emailRegEx = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,64}"
let emailPred = NSPredicate(format: "SELF MATCHES %@", emailRegEx)
return emailPred.evaluate(with: email)
}
guard let searchString = textField?.text, !searchString.isEmpty else { return }
- if searchString.contains("@"), !utility.validateEmail(searchString) { return }
+ if searchString.contains("@"), !isValidEmail(searchString) { return }
networking?.getSharees(searchString: searchString)
}
-
}
diff --git a/iOSClient/Share/NCShareCommentsCell.swift b/iOSClient/Share/NCShareCommentsCell.swift
index b537f6559d..59cdf78c81 100644
--- a/iOSClient/Share/NCShareCommentsCell.swift
+++ b/iOSClient/Share/NCShareCommentsCell.swift
@@ -54,9 +54,8 @@ class NCShareCommentsCell: UITableViewCell, NCCellProtocol {
override func awakeFromNib() {
super.awakeFromNib()
- let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapAvatarImage))
+ let tapGesture = UITapGestureRecognizer(target: self, action: #selector(tapAvatarImage(_:)))
imageItem?.addGestureRecognizer(tapGesture)
- buttonMenu.setImage(UIImage(named: "shareMenu")!.image(color: .lightGray, size: 50), for: .normal)
}
@objc func tapAvatarImage(_ sender: UITapGestureRecognizer) {
diff --git a/iOSClient/Share/NCShareCommon.swift b/iOSClient/Share/NCShareCommon.swift
index 4d99e3b93f..f96b33f55a 100644
--- a/iOSClient/Share/NCShareCommon.swift
+++ b/iOSClient/Share/NCShareCommon.swift
@@ -22,34 +22,27 @@
import UIKit
import DropDown
-import NextcloudKit
enum NCShareCommon {
+ static let shareTypeUser = 0
+ static let shareTypeGroup = 1
+ static let shareTypeLink = 3
+ static let shareTypeEmail = 4
+ static let shareTypeContact = 5
+ static let shareTypeFederated = 6
+ static let shareTypeTeam = 7
+ static let shareTypeGuest = 8
+ static let shareTypeFederatedGroup = 9
+ static let shareTypeRoom = 10
+
static let itemTypeFile = "file"
static let itemTypeFolder = "folder"
-}
-
-class NCShareCommon: NSObject {
-
- // swiftlint:disable identifier_name
- let SHARE_TYPE_USER = 0
- let SHARE_TYPE_GROUP = 1
- let SHARE_TYPE_LINK = 3
- let SHARE_TYPE_EMAIL = 4
- let SHARE_TYPE_CONTACT = 5
- let SHARE_TYPE_REMOTE = 6
- let SHARE_TYPE_CIRCLE = 7
- let SHARE_TYPE_GUEST = 8
- let SHARE_TYPE_REMOTE_GROUP = 9
- let SHARE_TYPE_ROOM = 10
- // swiftlint:enable identifier_name
-
- func createLinkAvatar(imageName: String, colorCircle: UIColor) -> UIImage? {
+ static func createLinkAvatar(imageName: String, colorCircle: UIColor) -> UIImage? {
let size: CGFloat = 200
let bottomImage = UIImage(named: "circle_fill")!.image(color: colorCircle, size: size / 2)
- let topImage = UIImage(named: imageName)!.image(color: .white, size: size / 2)
+ let topImage = NCUtility().loadImage(named: imageName, colors: [NCBrandColor.shared.iconImageColor])
UIGraphicsBeginImageContextWithOptions(CGSize(width: size, height: size), false, UIScreen.main.scale)
bottomImage.draw(in: CGRect(origin: CGPoint.zero, size: CGSize(width: size, height: size)))
topImage.draw(in: CGRect(origin: CGPoint(x: size / 4, y: size / 4), size: CGSize(width: size / 2, height: size / 2)))
@@ -59,7 +52,7 @@ class NCShareCommon: NSObject {
return image
}
- func copyLink(link: String, viewController: UIViewController, sender: Any) {
+ static func copyLink(link: String, viewController: UIViewController, sender: Any) {
let objectsToShare = [link]
let activityViewController = UIActivityViewController(activityItems: objectsToShare, applicationActivities: nil)
@@ -75,40 +68,49 @@ class NCShareCommon: NSObject {
}
}
- static func getImageShareType(shareType: Int) -> UIImage? {
- typealias type = NKShare.ShareType
+ static func getImageShareType(shareType: Int, isDropDown:Bool = false) -> UIImage? {
switch shareType {
- case type.group.rawValue:
+ case NCShareCommon.shareTypeUser:
+ return UIImage(named: "shareTypeEmail")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
+ case NCShareCommon.shareTypeGroup:
return UIImage(named: "shareTypeGroup")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
- case type.publicLink.rawValue:
+ case NCShareCommon.shareTypeLink:
return UIImage(named: "shareTypeLink")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
- case type.email.rawValue:
- return UIImage(named: "shareTypeEmail")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
- case type.team.rawValue:
- return UIImage(named: "shareTypeTeam")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
- case type.federatedGroup.rawValue:
+ case NCShareCommon.shareTypeEmail:
+ return UIImage(named: isDropDown ? "email" : "shareTypeUser")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
+ case NCShareCommon.shareTypeContact:
+ return UIImage(named: "shareTypeUser")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
+ case NCShareCommon.shareTypeFederated:
+// return UIImage(named: "shareTypeUser")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
+ return UIImage(named: isDropDown ? "shareTypeUser" : "shareTypeEmail")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
+ case NCShareCommon.shareTypeTeam:
+// return UIImage(named: "shareTypeTeam")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
+ return UIImage(named: "shareTypeCircles")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
+ case NCShareCommon.shareTypeGuest:
+ return UIImage(named: "shareTypeUser")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
+ case NCShareCommon.shareTypeFederatedGroup:
return UIImage(named: "shareTypeGroup")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
- case type.talkConversation.rawValue:
+ case NCShareCommon.shareTypeRoom:
return UIImage(named: "shareTypeRoom")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
default:
- return UIImage(named: "shareTypeUser")?.imageColor(NCBrandColor.shared.label)
+ return UIImage(named: "shareTypeUser")?.withTintColor(NCBrandColor.shared.textColor, renderingMode: .alwaysOriginal)
}
}
- func isLinkShare(shareType: Int) -> Bool {
- return shareType == SHARE_TYPE_LINK
+ static func isLinkShare(shareType: Int) -> Bool {
+ return shareType == NCShareCommon.shareTypeLink
}
- func isExternalUserShare(shareType: Int) -> Bool {
- return shareType == SHARE_TYPE_EMAIL
+ static func isExternalUserShare(shareType: Int) -> Bool {
+ return shareType == NCShareCommon.shareTypeEmail
}
- func isInternalUser(shareType: Int) -> Bool {
- return shareType == SHARE_TYPE_USER
+ static func isInternalUser(shareType: Int) -> Bool {
+ return shareType == NCShareCommon.shareTypeUser
}
- func isFileTypeAllowedForEditing(fileExtension: String, shareType: Int) -> Bool {
+ static func isFileTypeAllowedForEditing(fileExtension: String, shareType: Int) -> Bool {
if fileExtension == "md" || fileExtension == "txt" {
return true
} else {
@@ -116,7 +118,7 @@ class NCShareCommon: NSObject {
}
}
- func isEditingEnabled(isDirectory: Bool, fileExtension: String, shareType: Int) -> Bool {
+ static func isEditingEnabled(isDirectory: Bool, fileExtension: String, shareType: Int) -> Bool {
if !isDirectory {//file
return isFileTypeAllowedForEditing(fileExtension: fileExtension, shareType: shareType)
} else {
@@ -124,18 +126,18 @@ class NCShareCommon: NSObject {
}
}
- func isFileDropOptionVisible(isDirectory: Bool, shareType: Int) -> Bool {
+ static func isFileDropOptionVisible(isDirectory: Bool, shareType: Int) -> Bool {
return (isDirectory && (isLinkShare(shareType: shareType) || isExternalUserShare(shareType: shareType)))
}
- func isCurrentUserIsFileOwner(fileOwnerId: String) -> Bool {
+ static func isCurrentUserIsFileOwner(fileOwnerId: String) -> Bool {
if let currentUser = NCManageDatabase.shared.getActiveTableAccount(), currentUser.userId == fileOwnerId {
return true
}
return false
}
- func canReshare(withPermission permission: String) -> Bool {
+ static func canReshare(withPermission permission: String) -> Bool {
return permission.contains(NCPermissions().permissionCanShare)
}
}
diff --git a/iOSClient/Share/NCShareEmailFieldCell.swift b/iOSClient/Share/NCShareEmailFieldCell.swift
index 7b8643fe08..48cdcb1774 100644
--- a/iOSClient/Share/NCShareEmailFieldCell.swift
+++ b/iOSClient/Share/NCShareEmailFieldCell.swift
@@ -37,19 +37,30 @@ class NCShareEmailFieldCell: UITableViewCell {
super.setSelected(selected, animated: animated)
}
+ override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
+ super.traitCollectionDidChange(previousTraitCollection)
+ if previousTraitCollection?.userInterfaceStyle != traitCollection.userInterfaceStyle {
+ setupCellAppearance()
+ }
+ }
+
func setupCell(with metadata: tableMetadata) {
- contentView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+// contentView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
ocId = metadata.ocId
- configureSearchField()
- configureContactButton()
- configureLabels()
+ setupCellAppearance()
updateCanReshareUI()
setNeedsLayout()
layoutIfNeeded()
}
+ func setupCellAppearance() {
+ configureSearchField()
+ configureContactButton()
+ configureLabels()
+ }
+
private func configureSearchField() {
searchField.layer.cornerRadius = 5
searchField.layer.masksToBounds = true
@@ -70,9 +81,11 @@ class NCShareEmailFieldCell: UITableViewCell {
btnContact.layer.masksToBounds = true
btnContact.layer.borderWidth = 1
btnContact.layer.borderColor = NCBrandColor.shared.label.cgColor
+ if let image = UIImage(named: "Contacts")?.withRenderingMode(.alwaysTemplate) {
+ btnContact.setImage(image, for: .normal)
+ }
btnContact.tintColor = NCBrandColor.shared.label
- let contactImage = NCUtility().loadImage(named: "contact").image(color: NCBrandColor.shared.label, size: 24)
- btnContact.setImage(contactImage, for: .normal)
+
}
private func configureLabels() {
@@ -89,7 +102,7 @@ class NCShareEmailFieldCell: UITableViewCell {
func updateCanReshareUI() {
guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return }
- let isCurrentUser = NCShareCommon().isCurrentUserIsFileOwner(fileOwnerId: metadata.ownerId)
+ let isCurrentUser = NCShareCommon.isCurrentUserIsFileOwner(fileOwnerId: metadata.ownerId)
let canReshare = (metadata.sharePermissionsCollaborationServices & NCPermissions().permissionShareShare) != 0
labelSharedWithBy.isHidden = isCurrentUser
@@ -130,7 +143,7 @@ class NCShareEmailFieldCell: UITableViewCell {
func updateShareUI(ocId: String, count: Int) {
guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return }
- let isCurrentUser = NCShareCommon().isCurrentUserIsFileOwner(fileOwnerId: metadata.ownerId)
+ let isCurrentUser = NCShareCommon.isCurrentUserIsFileOwner(fileOwnerId: metadata.ownerId)
let canReshare = (metadata.sharePermissionsCollaborationServices & NCPermissions().permissionShareShare) != 0
if !isCurrentUser {
diff --git a/iOSClient/Share/NCShareEmailFieldCell.xib b/iOSClient/Share/NCShareEmailFieldCell.xib
index cfeb42cc45..8384397621 100644
--- a/iOSClient/Share/NCShareEmailFieldCell.xib
+++ b/iOSClient/Share/NCShareEmailFieldCell.xib
@@ -1,9 +1,8 @@
-
+
-
-
+
@@ -23,6 +22,7 @@
+
@@ -35,6 +35,7 @@
+
@@ -49,17 +50,20 @@
+
+
+
@@ -68,14 +72,16 @@
+
-
+
-
+
+
@@ -95,6 +101,7 @@
+
@@ -145,6 +152,7 @@
+
@@ -153,6 +161,7 @@
+
@@ -169,9 +178,9 @@
-
-
-
+
+
+
diff --git a/iOSClient/Share/NCShareHeader.swift b/iOSClient/Share/NCShareHeader.swift
index 905a05159c..1dda12d002 100644
--- a/iOSClient/Share/NCShareHeader.swift
+++ b/iOSClient/Share/NCShareHeader.swift
@@ -1,5 +1,5 @@
//
-// NCShareAdvancePermissionHeader.swift
+// NCShareHeader.swift
// Nextcloud
//
// Created by T-systems on 10/08/21.
@@ -22,6 +22,55 @@
//
import UIKit
+import TagListView
+
+class NCShareHeader: UIView {
+ @IBOutlet weak var imageView: UIImageView!
+ @IBOutlet weak var fileName: UILabel!
+ @IBOutlet weak var info: UILabel!
+ @IBOutlet weak var fullWidthImageView: UIImageView!
+ @IBOutlet weak var fileNameTopConstraint: NSLayoutConstraint!
+ @IBOutlet weak var tagListView: TagListView!
+
+ private var heightConstraintWithImage: NSLayoutConstraint?
+ private var heightConstraintWithoutImage: NSLayoutConstraint?
+
+ func setupUI(with metadata: tableMetadata) {
+ let utilityFileSystem = NCUtilityFileSystem()
+ if let image = NCUtility().getImage(ocId: metadata.ocId, etag: metadata.etag, ext: NCGlobal.shared.previewExt1024, userId: metadata.userId, urlBase: metadata.urlBase) {
+ fullWidthImageView.image = image
+ fullWidthImageView.contentMode = .scaleAspectFill
+ imageView.image = fullWidthImageView.image
+ imageView.isHidden = true
+ } else {
+ if metadata.directory {
+ imageView.image = metadata.e2eEncrypted ? NCImageCache.shared.getFolderEncrypted(account: metadata.account) : NCImageCache.shared.getFolder(account: metadata.account)
+ } else if !metadata.iconName.isEmpty {
+ imageView.image = NCUtility().loadImage(named: metadata.iconName, useTypeIconFile: true, account: metadata.account)
+ } else {
+ imageView.image = NCImageCache.shared.getImageFile()
+ }
+
+ fileNameTopConstraint.constant -= 45
+ }
+
+ fileName.text = metadata.fileNameView
+ fileName.textColor = NCBrandColor.shared.textColor
+ info.textColor = NCBrandColor.shared.textColor2
+ info.text = utilityFileSystem.transformedSize(metadata.size) + ", " + NCUtility().getRelativeDateTitle(metadata.date as Date)
+
+ tagListView.addTags(Array(metadata.tags))
+
+ setNeedsLayout()
+ layoutIfNeeded()
+ }
+
+ override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?) {
+ if fullWidthImageView.image != nil {
+ imageView.isHidden = traitCollection.verticalSizeClass != .compact
+ }
+ }
+}
class NCShareAdvancePermissionHeader: UITableViewHeaderFooterView {
@IBOutlet weak var imageView: UIImageView!
@@ -37,7 +86,11 @@ class NCShareAdvancePermissionHeader: UITableViewHeaderFooterView {
let utilityFileSystem = NCUtilityFileSystem()
func setupUI(with metadata: tableMetadata) {
- let utilityFileSystem = NCUtilityFileSystem()
+ fileName.textColor = NCBrandColor.shared.label
+ info.textColor = NCBrandColor.shared.textInfo
+
+ let isShare = metadata.permissions.contains(NCPermissions().permissionShared)
+
if let image = NCUtility().getImage(ocId: metadata.ocId, etag: metadata.etag, ext: NCGlobal.shared.previewExt1024, userId: metadata.userId, urlBase: metadata.urlBase) {
fullWidthImageView.image = image
fullWidthImageView.contentMode = .scaleAspectFill
@@ -45,15 +98,17 @@ class NCShareAdvancePermissionHeader: UITableViewHeaderFooterView {
} else {
imageView.isHidden = false
if metadata.e2eEncrypted {
- imageView.image = NCImageCache.shared.getFolderEncrypted()
- } else if isShare {
- imageView.image = NCImageCache.shared.getFolderSharedWithMe()
+ imageView.image = NCImageCache.shared.getFolderEncrypted(account: metadata.account)
+ } else if isShare || !metadata.shareType.isEmpty {
+ imageView.image = NCImageCache.shared.getFolderPublic(account: metadata.account)
} else if !metadata.shareType.isEmpty {
imageView.image = metadata.shareType.contains(3)
- ? NCImageCache.shared.getFolderPublic()
- : NCImageCache.shared.getFolderSharedWithMe()
+ ? NCImageCache.shared.getFolderPublic(account: metadata.account)
+ : NCImageCache.shared.getFolderSharedWithMe(account: metadata.account)
+ } else if metadata.permissions.contains("S"), (metadata.permissions.range(of: "S") != nil) {
+ imageView.image = NCImageCache.shared.getImageSharedWithMe()
} else if metadata.directory {
- imageView.image = NCImageCache.shared.getFolder()
+ imageView.image = NCImageCache.shared.getFolder(account: metadata.account)
} else if !metadata.iconName.isEmpty {
imageView.image = NCUtility().loadImage(named: metadata.iconName, useTypeIconFile: true, account: metadata.account)
} else {
@@ -69,35 +124,28 @@ class NCShareAdvancePermissionHeader: UITableViewHeaderFooterView {
}
func setupUI(with metadata: tableMetadata, linkCount: Int, emailCount: Int) {
- contentView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
fileName.textColor = NCBrandColor.shared.label
info.textColor = NCBrandColor.shared.textInfo
-// let isShare = metadata.permissions.contains(NCPermissions().permissionShared)
+ let isShare = metadata.permissions.contains(NCPermissions().permissionShared)
let hasShares = (linkCount > 0 || emailCount > 0)
- if let image = NCUtility().getImage(ocId: metadata.ocId,
- etag: metadata.etag,
- ext: NCGlobal.shared.previewExt1024) {
+ if let image = NCUtility().getImage(ocId: metadata.ocId, etag: metadata.etag, ext: NCGlobal.shared.previewExt1024, userId: metadata.userId, urlBase: metadata.urlBase) {
fullWidthImageView.image = image
fullWidthImageView.contentMode = .scaleAspectFill
imageView.isHidden = true
} else {
imageView.isHidden = false
if metadata.e2eEncrypted {
- imageView.image = NCImageCache.shared.getFolderEncrypted()
- } else if hasShares {
- imageView.image = NCImageCache.shared.getFolderSharedWithMe()
- } else if !metadata.shareType.isEmpty {
- imageView.image = metadata.shareType.contains(3)
- ? NCImageCache.shared.getFolderPublic()
- : NCImageCache.shared.getFolderSharedWithMe()
+ imageView.image = NCImageCache.shared.getFolderEncrypted(account: metadata.account)
+ } else if metadata.permissions.contains("S"), (metadata.permissions.range(of: "S") != nil) {
+ imageView.image = NCImageCache.shared.getFolderSharedWithMe(account: metadata.account)
+ } else if isShare || !metadata.shareType.isEmpty {
+ imageView.image = NCImageCache.shared.getFolderPublic(account: metadata.account)
} else if metadata.directory {
- imageView.image = NCImageCache.shared.getFolder()
+ imageView.image = NCImageCache.shared.getFolder(account: metadata.account)
} else if !metadata.iconName.isEmpty {
- imageView.image = NCUtility().loadImage(named: metadata.iconName,
- useTypeIconFile: true,
- account: metadata.account)
+ imageView.image = NCUtility().loadImage(named: metadata.iconName, useTypeIconFile: true, account: metadata.account)
} else {
imageView.image = NCImageCache.shared.getImageFile()
}
@@ -111,16 +159,18 @@ class NCShareAdvancePermissionHeader: UITableViewHeaderFooterView {
}
private func updateFavoriteIcon(isFavorite: Bool) {
- let color = isFavorite ? NCBrandColor.shared.yellowFavorite : NCBrandColor.shared.textInfo
- favorite.setImage(utility.loadImage(named: "star.fill", colors: [color], size: 24), for: .normal)
+ favorite.setImage(NCUtility().loadImage(named: isFavorite ? "star" : "star.fill", colors: [NCBrandColor.shared.yellowFavorite], size: 24), for: .normal)
}
@IBAction func touchUpInsideFavorite(_ sender: UIButton) {
guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return }
NCNetworking.shared.favoriteMetadata(metadata) { error in
if error == .success {
- guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(metadata.ocId) else { return }
- self.updateFavoriteIcon(isFavorite: metadata.favorite)
+ Task {
+ guard let metadata = await NCManageDatabase.shared.getMetadataFromOcIdAsync(metadata.ocId) else { return }
+ self.updateFavoriteIcon(isFavorite: metadata.favorite)
+// NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterFavoriteStatusChanged, object: metadata)
+ }
} else {
NCContentPresenter().showError(error: error)
}
diff --git a/iOSClient/Share/NCShareHeader.xib b/iOSClient/Share/NCShareHeader.xib
index 69ae9e03bd..88f3d5ea08 100644
--- a/iOSClient/Share/NCShareHeader.xib
+++ b/iOSClient/Share/NCShareHeader.xib
@@ -1,128 +1,132 @@
-
+
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
+
+
-
-
-
+
+
+
+
+
+
+
+
+
+
diff --git a/iOSClient/Share/NCShareLinkCell.swift b/iOSClient/Share/NCShareLinkCell.swift
index 058922bea1..134b0afa3c 100644
--- a/iOSClient/Share/NCShareLinkCell.swift
+++ b/iOSClient/Share/NCShareLinkCell.swift
@@ -145,16 +145,16 @@ class NCShareLinkCell: UITableViewCell {
}
private func setupCellAppearance(titleAppendString: String? = nil) {
- contentView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+// contentView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
labelTitle.textColor = NCBrandColor.shared.label
labelQuickStatus.textColor = NCBrandColor.shared.shareBlueColor
buttonDetail.setTitleColor(NCBrandColor.shared.shareBlackColor, for: .normal)
buttonCopy.setImage(UIImage(named: "share")?.image(color: NCBrandColor.shared.brand, size: 24), for: .normal)
- imageRightArrow.image = UIImage(named: "rightArrow")?.imageColor(NCBrandColor.shared.shareBlueColor)
- imageExpiredDateSet.image = UIImage(named: "calenderNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
- imagePasswordSet.image = UIImage(named: "lockNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ imageRightArrow.image = UIImage(named: "rightArrow")?.image(color: NCBrandColor.shared.shareBlueColor)
+ imageExpiredDateSet.image = UIImage(named: "calenderNew")?.image(color: NCBrandColor.shared.shareBlueColor)
+ imagePasswordSet.image = UIImage(named: "lockNew")?.image(color: NCBrandColor.shared.shareBlueColor)
buttonDetail.setTitle(NSLocalizedString("_share_details_", comment: ""), for: .normal)
labelTitle.text = NSLocalizedString("_share_link_", comment: "")
@@ -176,13 +176,13 @@ class NCShareLinkCell: UITableViewCell {
if tableShare.permissions == permissions.permissionCreateShare {
labelQuickStatus.text = NSLocalizedString("_share_quick_permission_everyone_can_just_upload_", comment: "")
- imagePermissionType.image = UIImage(named: "upload")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ imagePermissionType.image = UIImage(named: "upload")?.image(color: NCBrandColor.shared.shareBlueColor)
} else if permissions.isAnyPermissionToEdit(tableShare.permissions) {
labelQuickStatus.text = NSLocalizedString("_share_quick_permission_everyone_can_edit_", comment: "")
- imagePermissionType.image = UIImage(named: "editNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ imagePermissionType.image = UIImage(named: "editNew")?.image(color: NCBrandColor.shared.shareBlueColor)
} else {
labelQuickStatus.text = NSLocalizedString("_share_quick_permission_everyone_can_only_view_", comment: "")
- imagePermissionType.image = UIImage(named: "showPasswordNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ imagePermissionType.image = UIImage(named: "showPasswordNew")?.image(color: NCBrandColor.shared.shareBlueColor)
}
imagePasswordSet.isHidden = tableShare.password.isEmpty
diff --git a/iOSClient/Share/NCShareLinkCell.xib b/iOSClient/Share/NCShareLinkCell.xib
index 9783995c5e..0f88db8ca6 100755
--- a/iOSClient/Share/NCShareLinkCell.xib
+++ b/iOSClient/Share/NCShareLinkCell.xib
@@ -2,7 +2,6 @@
-
@@ -18,6 +17,7 @@
+
@@ -33,6 +33,7 @@
+
@@ -40,6 +41,7 @@
+
@@ -64,9 +66,11 @@
+
+
@@ -74,6 +78,7 @@
+
@@ -88,6 +93,7 @@
+
@@ -99,12 +105,13 @@
+
-
+
diff --git a/iOSClient/Share/NCShareNavigationTitleSetting.swift b/iOSClient/Share/NCShareNavigationTitleSetting.swift
index 927f21b97f..9804dea108 100644
--- a/iOSClient/Share/NCShareNavigationTitleSetting.swift
+++ b/iOSClient/Share/NCShareNavigationTitleSetting.swift
@@ -2,8 +2,6 @@
// SPDX-FileCopyrightText: 2025 Iva Horn
// SPDX-License-Identifier: GPL-3.0-or-later
-import NextcloudKit
-
///
/// View controllers conforming to this gain the convenience method ``setNavigationTitle()`` to set the navigation title in a convenient and consistent way.
///
@@ -20,7 +18,7 @@ extension NCShareNavigationTitleSetting where Self: UIViewController {
func setNavigationTitle() {
title = NSLocalizedString("_share_", comment: "") + " – "
- if share.shareType == NKShare.ShareType.publicLink.rawValue {
+ if share.shareType == NCShareCommon.shareTypeLink {
title! += share.label.isEmpty ? NSLocalizedString("_share_link_", comment: "") : share.label
} else {
title! += share.shareWithDisplayname.isEmpty ? share.shareWith : share.shareWithDisplayname
diff --git a/iOSClient/Share/NCShareNetworking.swift b/iOSClient/Share/NCShareNetworking.swift
index 1fde2ec34b..7cd04ddc16 100644
--- a/iOSClient/Share/NCShareNetworking.swift
+++ b/iOSClient/Share/NCShareNetworking.swift
@@ -39,242 +39,6 @@ class NCShareNetworking: NSObject {
super.init()
}
-// private func readDownloadLimit(account: String, token: String) async throws -> NKDownloadLimit? {
-// return try await withCheckedThrowingContinuation { continuation in
-// NextcloudKit.shared.getDownloadLimit(account: account, token: token) { limit, error in
-// if error != .success {
-// continuation.resume(throwing: error.error)
-// return
-// } else {
-// continuation.resume(returning: limit)
-// }
-// }
-// }
-// }
-//
-// func readDownloadLimits(account: String, tokens: [String]) async throws {
-// for token in tokens {
-// self.database.deleteDownloadLimit(byAccount: account, shareToken: token)
-// if let downloadLimit = try await readDownloadLimit(account: account, token: token) {
-// self.database.createDownloadLimit(account: account, count: downloadLimit.count, limit: downloadLimit.limit, token: token)
-// }
-// }
-// }
-
- // MARK: - Read
- func readShare(showLoadingIndicator: Bool) {
- if showLoadingIndicator {
- NCActivityIndicator.shared.start(backgroundView: view)
- }
- let filenamePath = utilityFileSystem.getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, session: session)
- let parameter = NKShareParameter(path: filenamePath)
-
- NextcloudKit.shared.readShares(parameters: parameter, account: metadata.account) { account, shares, _, error in
- if error == .success, let shares = shares {
- self.database.deleteTableShare(account: account, path: "/" + filenamePath)
- let home = self.utilityFileSystem.getHomeServer(session: self.session)
- self.database.addShare(account: self.metadata.account, home: home, shares: shares)
-
- NextcloudKit.shared.getGroupfolders(account: account) { account, results, _, error in
- if showLoadingIndicator {
- NCActivityIndicator.shared.stop()
- }
- if error == .success, let groupfolders = results {
- self.database.addGroupfolders(account: account, groupfolders: groupfolders)
- }
-
- Task {
- try await self.readDownloadLimits(account: account, tokens: shares.map(\.token))
- self.delegate?.readShareCompleted()
- }
- }
- } else {
- if showLoadingIndicator {
- NCActivityIndicator.shared.stop()
- }
- NCContentPresenter().showError(error: error)
- self.delegate?.readShareCompleted()
- }
- }
- }
-
- // MARK: - Create Share Link
- func createShareLink(password: String?) {
- NCActivityIndicator.shared.start(backgroundView: view)
- let filenamePath = utilityFileSystem.getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, session: session)
-
- NextcloudKit.shared.createShareLink(path: filenamePath, account: metadata.account) { [weak self] account, share, _, error in
- guard let self = self else { return }
- NCActivityIndicator.shared.stop()
-
- if error == .success, let share = share {
- let home = self.utilityFileSystem.getHomeServer(session: self.session)
- self.database.addShare(account: self.metadata.account, home: home, shares: [share])
-
- if !self.metadata.contentType.contains("directory") {
- AnalyticsHelper.shared.trackEventWithMetadata(eventName: .EVENT__SHARE_FILE, metadata: self.metadata)
- }
-
- NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDidCreateShareLink)
- // 🔄 ensure we sync DB + UI with server
- self.readShare(showLoadingIndicator: false)
- } else {
- NCContentPresenter().showError(error: error)
- }
-
- self.delegate?.shareCompleted()
- }
- }
-
- // MARK: - Create Share (user/email/group)
- func createShare(_ shareable: Shareable, downloadLimit: DownloadLimitViewModel) {
- NCActivityIndicator.shared.start(backgroundView: view)
- let filenamePath = utilityFileSystem.getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, session: session)
-
- NextcloudKit.shared.createShare(
- path: filenamePath,
- shareType: shareable.shareType,
- shareWith: shareable.shareWith,
- password: shareable.password,
- note: shareable.note,
- permissions: shareable.permissions,
- attributes: shareable.attributes,
- account: metadata.account
- ) { [weak self] _, share, _, error in
- guard let self = self else { return }
- NCActivityIndicator.shared.stop()
-
- if error == .success, let share = share {
- shareable.idShare = share.idShare
- let home = self.utilityFileSystem.getHomeServer(session: self.session)
- self.database.addShare(account: self.metadata.account, home: home, shares: [share])
-
- let directory = self.metadata.directory
-
- if shareable.hasChanges(comparedTo: share) {
- self.updateShare(shareable, downloadLimit: downloadLimit)
- // Download limit update should happen implicitly on share update.
- } else {
- if share.shareType == NCShareCommon().SHARE_TYPE_LINK && !directory {
- if case let .limited(limit, _) = downloadLimit, NCCapabilities.shared.getCapabilities(account: self.metadata.account).capabilityFileSharingDownloadLimit {
- self.setShareDownloadLimit(limit, token: share.token)
- }
- }
- }
-
- if !self.metadata.contentType.contains("directory") {
- AnalyticsHelper.shared.trackEventWithMetadata(eventName: .EVENT__SHARE_FILE, metadata: self.metadata)
- }
-
- NotificationCenter.default.postOnMainThread(
- name: NCGlobal.shared.notificationCenterUpdateShare,
- userInfo: ["account": self.metadata.account, "serverUrl": self.metadata.serverUrl]
- )
- // 🔄 ensure consistency
- self.readShare(showLoadingIndicator: false)
- } else {
- NCContentPresenter().showError(error: error)
- }
-
- self.delegate?.shareCompleted()
- }
- }
-
- // MARK: - Unshare
- func unShare(idShare: Int) {
- NCActivityIndicator.shared.start(backgroundView: view)
- NextcloudKit.shared.deleteShare(idShare: idShare, account: metadata.account) { [weak self] account, _, error in
- guard let self = self else { return }
- NCActivityIndicator.shared.stop()
-
- if error == .success {
- self.database.deleteTableShare(account: account, idShare: idShare)
- self.delegate?.unShareCompleted()
-
- NotificationCenter.default.postOnMainThread(
- name: NCGlobal.shared.notificationCenterUpdateShare,
- userInfo: ["account": self.metadata.account, "serverUrl": self.metadata.serverUrl]
- )
- // 🔄 reload to avoid missing/duplicate shares
- self.readShare(showLoadingIndicator: false)
- } else {
- NCContentPresenter().showError(error: error)
- }
- }
- }
-
- // MARK: - Update Share
- func updateShare(_ shareable: Shareable, downloadLimit: DownloadLimitViewModel) {
- NCActivityIndicator.shared.start(backgroundView: view)
- NextcloudKit.shared.updateShare(
- idShare: shareable.idShare,
- password: shareable.password,
- expireDate: shareable.formattedDateString,
- permissions: shareable.permissions,
- note: shareable.note,
- label: shareable.label,
- hideDownload: shareable.hideDownload,
- attributes: shareable.attributes,
- account: metadata.account
- ) { [weak self] _, share, _, error in
- guard let self = self else { return }
- NCActivityIndicator.shared.stop()
-
- if error == .success, let share = share {
- let home = self.utilityFileSystem.getHomeServer(session: self.session)
- self.database.addShare(account: self.metadata.account, home: home, shares: [share])
- self.delegate?.readShareCompleted()
-
- let directory = self.metadata.directory
-
-// if capabilities.fileSharingDownloadLimit,
-// shareable.shareType == NCShareCommon.shareTypeLink,
-// shareable.itemType == NCShareCommon.itemTypeFile {
- if share.shareType == NCShareCommon().SHARE_TYPE_LINK && !directory{
- if NCCapabilities.shared.getCapabilities(account: self.metadata.account).capabilityFileSharingDownloadLimit {
- if case let .limited(limit, _) = downloadLimit {
- self.setShareDownloadLimit(limit, token: share.token)
- } else {
- self.removeShareDownloadLimit(token: share.token)
- }
- }
- }
-
- NotificationCenter.default.postOnMainThread(
- name: NCGlobal.shared.notificationCenterUpdateShare,
- userInfo: ["account": self.metadata.account, "serverUrl": self.metadata.serverUrl]
- )
- NotificationCenter.default.postOnMainThread(
- name: NCGlobal.shared.notificationCenterReloadDataNCShare
- )
- // 🔄 refresh again from server
- self.readShare(showLoadingIndicator: false)
- } else {
- NCContentPresenter().showError(error: error)
- self.delegate?.updateShareWithError(idShare: shareable.idShare)
- }
- }
- }
-
- func getSharees(searchString: String) {
- NCActivityIndicator.shared.start(backgroundView: view)
- NextcloudKit.shared.searchSharees(search: searchString, account: metadata.account) { _, sharees, _, error in
- NCActivityIndicator.shared.stop()
-
- if error == .success {
- self.delegate?.getSharees(sharees: sharees)
- } else {
- NCContentPresenter().showError(error: error)
- self.delegate?.getSharees(sharees: nil)
- }
- }
- }
-
- // MARK: - Download Limit
-
- ///
- /// Remove the download limit on the share, if existent.
- ///
private func readDownloadLimit(account: String, token: String) async throws -> NKDownloadLimit? {
return try await withCheckedThrowingContinuation { continuation in
NextcloudKit.shared.getDownloadLimit(account: account, token: token) { limit, error in
@@ -349,20 +113,33 @@ class NCShareNetworking: NSObject {
}
}
+ // MARK: - Create Share Link
func createShareLink(password: String?) {
NCActivityIndicator.shared.start(backgroundView: view)
let filenamePath = utilityFileSystem.getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, session: session)
- NextcloudKit.shared.createShareLink(path: filenamePath, account: metadata.account) { [self] account, share, data, error in
+
+ NextcloudKit.shared.createShare(path: filenamePath,
+ shareType: NCShareCommon.shareTypeLink,
+ shareWith: "",
+ account: metadata.account) { [weak self] account, share, _, error in
+ guard let self = self else { return }
NCActivityIndicator.shared.stop()
- if error == .success && share != nil {
+
+ if error == .success, let share = share {
let home = self.utilityFileSystem.getHomeServer(session: self.session)
- NCManageDatabase.shared.addShare(account: self.metadata.account, home:home, shares: [share!])
- if !metadata.contentType.contains("directory") {
- AnalyticsHelper.shared.trackEventWithMetadata(eventName: .EVENT__SHARE_FILE ,metadata: metadata)
+ self.database.addShare(account: self.metadata.account, home: home, shares: [share])
+
+ if !self.metadata.contentType.contains("directory") {
+ AnalyticsHelper.shared.trackEventWithMetadata(eventName: .EVENT__SHARE_FILE, metadata: self.metadata)
}
- } else if error != .success{
+
+ NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterDidCreateShareLink)
+ // 🔄 ensure we sync DB + UI with server
+ self.readShare(showLoadingIndicator: false)
+ } else {
NCContentPresenter().showError(error: error)
}
+
self.delegate?.shareCompleted()
}
}
@@ -397,27 +174,26 @@ class NCShareNetworking: NSObject {
self.database.addShare(account: self.metadata.account, home: home, shares: [share])
if shareable.hasChanges(comparedTo: share) {
- self.updateShare(shareable, downloadLimit: downloadLimit, changeDownloadLimit: true)
+ self.updateShare(shareable, downloadLimit: downloadLimit)
// Download limit update should happen implicitly on share update.
} else {
if case let .limited(limit, _) = downloadLimit,
capabilities.fileSharingDownloadLimit,
- shareable.shareType == NKShare.ShareType.publicLink.rawValue,
+ shareable.shareType == NCShareCommon.shareTypeLink,
shareable.itemType == NCShareCommon.itemTypeFile {
self.setShareDownloadLimit(limit, token: share.token)
}
}
+
+ if !self.metadata.contentType.contains("directory") {
+ AnalyticsHelper.shared.trackEventWithMetadata(eventName: .EVENT__SHARE_FILE, metadata: self.metadata)
+ }
Task {
await NCNetworking.shared.transferDispatcher.notifyAllDelegates { delegate in
- delegate.transferReloadData(serverUrl: self.metadata.serverUrl, requestData: true, status: nil)
+ delegate.transferRequestData(serverUrl: self.metadata.serverUrl)
}
}
- NotificationCenter.default.postOnMainThread(name: NCGlobal.shared.notificationCenterUpdateShare, userInfo: ["account": self.metadata.account, "serverUrl": self.metadata.serverUrl])
-
- if !self.metadata.contentType.contains("directory") {
- AnalyticsHelper.shared.trackEventWithMetadata(eventName: .EVENT__SHARE_FILE ,metadata: self.metadata)
- }
} else {
NCContentPresenter().showError(error: error)
}
@@ -444,7 +220,7 @@ class NCShareNetworking: NSObject {
Task {
await NCNetworking.shared.transferDispatcher.notifyAllDelegates { delegate in
- delegate.transferReloadData(serverUrl: self.metadata.serverUrl, requestData: true, status: nil)
+ delegate.transferRequestData(serverUrl: self.metadata.serverUrl)
}
}
} else {
@@ -453,7 +229,7 @@ class NCShareNetworking: NSObject {
}
}
- func updateShare(_ shareable: Shareable, downloadLimit: DownloadLimitViewModel, changeDownloadLimit: Bool = false) {
+ func updateShare(_ shareable: Shareable, downloadLimit: DownloadLimitViewModel) {
NCActivityIndicator.shared.start(backgroundView: view)
NextcloudKit.shared.updateShare(idShare: shareable.idShare, password: shareable.password, expireDate: shareable.formattedDateString, permissions: shareable.permissions, note: shareable.note, label: shareable.label, hideDownload: shareable.hideDownload, attributes: shareable.attributes, account: metadata.account) { task in
Task {
@@ -473,9 +249,8 @@ class NCShareNetworking: NSObject {
self.delegate?.readShareCompleted()
if capabilities.fileSharingDownloadLimit,
- shareable.shareType == NKShare.ShareType.publicLink.rawValue,
- shareable.itemType == NCShareCommon.itemTypeFile,
- changeDownloadLimit {
+ shareable.shareType == NCShareCommon.shareTypeLink,
+ shareable.itemType == NCShareCommon.itemTypeFile {
if case let .limited(limit, _) = downloadLimit {
self.setShareDownloadLimit(limit, token: share.token)
} else {
@@ -485,7 +260,7 @@ class NCShareNetworking: NSObject {
Task {
await NCNetworking.shared.transferDispatcher.notifyAllDelegates { delegate in
- delegate.transferReloadData(serverUrl: self.metadata.serverUrl, requestData: true, status: nil)
+ delegate.transferRequestData(serverUrl: self.metadata.serverUrl)
}
}
} else {
@@ -522,12 +297,17 @@ class NCShareNetworking: NSObject {
/// Remove the download limit on the share, if existent.
///
func removeShareDownloadLimit(token: String) {
- if !NCCapabilities.shared.getCapabilities(account: self.metadata.account).capabilityFileSharingDownloadLimit || token.isEmpty {
+ let capabilities = NCNetworking.shared.capabilities[self.metadata.account] ?? NKCapabilities.Capabilities()
+
+ if !capabilities.fileSharingDownloadLimit || token.isEmpty {
return
}
+
NCActivityIndicator.shared.start(backgroundView: view)
+
NextcloudKit.shared.removeShareDownloadLimit(account: metadata.account, token: token) { error in
NCActivityIndicator.shared.stop()
+
if error == .success {
self.delegate?.downloadLimitRemoved(by: token)
} else {
@@ -536,13 +316,23 @@ class NCShareNetworking: NSObject {
}
}
+ ///
+ /// Set the download limit for the share.
+ ///
+ /// - Parameter limit: The new download limit to set.
+ ///
func setShareDownloadLimit(_ limit: Int, token: String) {
- if !NCCapabilities.shared.getCapabilities(account: self.metadata.account).capabilityFileSharingDownloadLimit || token.isEmpty {
+ let capabilities = NCNetworking.shared.capabilities[self.metadata.account] ?? NKCapabilities.Capabilities()
+
+ if !capabilities.fileSharingDownloadLimit || token.isEmpty {
return
}
+
NCActivityIndicator.shared.start(backgroundView: view)
+
NextcloudKit.shared.setShareDownloadLimit(account: metadata.account, token: token, limit: limit) { error in
NCActivityIndicator.shared.stop()
+
if error == .success {
self.delegate?.downloadLimitSet(to: limit, by: token)
} else {
diff --git a/iOSClient/Share/NCSharePaging.swift b/iOSClient/Share/NCSharePaging.swift
index 6f5b91d89b..7ab1c37269 100644
--- a/iOSClient/Share/NCSharePaging.swift
+++ b/iOSClient/Share/NCSharePaging.swift
@@ -54,15 +54,16 @@ class NCSharePaging: UIViewController {
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillShow(notification:)), name: UIResponder.keyboardWillShowNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(keyboardWillHide(notification:)), name: UIResponder.keyboardWillHideNotification, object: nil)
- NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground(notification:)), name: NSNotification.Name(rawValue: NCGlobal.shared.notificationCenterApplicationDidEnterBackground), object: nil)
+ NotificationCenter.default.addObserver(self, selector: #selector(applicationDidEnterBackground(notification:)), name: UIApplication.didEnterBackgroundNotification, object: nil)
// *** MUST BE THE FIRST ONE ***
pagingViewController.metadata = metadata
pagingViewController.backgroundColor = .systemBackground
pagingViewController.menuBackgroundColor = .systemBackground
pagingViewController.selectedBackgroundColor = .systemBackground
- pagingViewController.textColor = .label
- pagingViewController.selectedTextColor = .label
+ pagingViewController.indicatorColor = NCBrandColor.shared.getElement(account: metadata.account)
+ pagingViewController.textColor = NCBrandColor.shared.textColor
+ pagingViewController.selectedTextColor = NCBrandColor.shared.getElement(account: metadata.account)
// Pagination
addChild(pagingViewController)
@@ -74,14 +75,16 @@ class NCSharePaging: UIViewController {
height: 1,
zIndex: Int.max,
spacing: .zero,
- insets: UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5)
+ insets: .zero
)
+ pagingViewController.borderOptions = .visible(height: 1, zIndex: Int.max, insets: .zero)
+
// Contrain the paging view to all edges.
pagingViewController.view.translatesAutoresizingMaskIntoConstraints = false
NSLayoutConstraint.activate([
pagingViewController.view.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor),
- pagingViewController.view.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor),
+ pagingViewController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
pagingViewController.view.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor),
pagingViewController.view.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor)
])
@@ -95,7 +98,6 @@ class NCSharePaging: UIViewController {
pagingViewController.select(index: 0)
}
- (pagingViewController.view as? NCSharePagingView)?.setupConstraints()
pagingViewController.reloadMenu()
}
@@ -106,20 +108,25 @@ class NCSharePaging: UIViewController {
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
- if NCCapabilities.shared.disableSharesView(account: metadata.account) {
+
+ navigationController?.setNavigationBarAppearance()
+
+ let capabilities = NCNetworking.shared.capabilities[metadata.account] ?? NKCapabilities.Capabilities()
+
+ if !capabilities.fileSharingApiEnabled && !capabilities.filesComments && capabilities.activity.isEmpty {
self.dismiss(animated: false, completion: nil)
}
- pagingViewController.menuItemSize = .fixed(
- width: self.view.bounds.width / CGFloat(self.pages.count),
- height: 40)
+// pagingViewController.menuItemSize = .fixed(
+// width: self.view.bounds.width / CGFloat(self.pages.count),
+// height: 40)
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(animated)
Task {
await NCNetworking.shared.transferDispatcher.notifyAllDelegates { delegate in
- delegate.transferReloadData(serverUrl: metadata.serverUrl, requestData: false, status: nil)
+ delegate.transferReloadData(serverUrl: metadata.serverUrl, status: nil)
}
}
}
@@ -127,17 +134,12 @@ class NCSharePaging: UIViewController {
deinit {
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardDidShowNotification, object: nil)
NotificationCenter.default.removeObserver(self, name: UIResponder.keyboardWillHideNotification, object: nil)
+ NotificationCenter.default.removeObserver(self, name: UIApplication.didEnterBackgroundNotification, object: nil)
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) {
super.viewWillTransition(to: size, with: coordinator)
-
- coordinator.animate(alongsideTransition: nil) { _ in
- self.pagingViewController.menuItemSize = .fixed(
- width: self.view.bounds.width / CGFloat(self.pages.count),
- height: 40)
- self.currentVC?.textField?.resignFirstResponder()
- }
+ self.currentVC?.textField?.resignFirstResponder()
}
// MARK: - NotificationCenter & Keyboard & TextField
@@ -161,7 +163,7 @@ class NCSharePaging: UIViewController {
view.frame.origin.y = 0
}
- @objc func exitTapped() {
+ @objc func exitTapped(_ sender: Any?) {
self.dismiss(animated: true, completion: nil)
}
@@ -173,7 +175,6 @@ class NCSharePaging: UIViewController {
// MARK: - PagingViewController Delegate
extension NCSharePaging: PagingViewControllerDelegate {
-
func pagingViewController(_ pagingViewController: PagingViewController, willScrollToItem pagingItem: PagingItem, startingViewController: UIViewController, destinationViewController: UIViewController) {
currentVC?.textField?.resignFirstResponder()
@@ -184,7 +185,6 @@ extension NCSharePaging: PagingViewControllerDelegate {
// MARK: - PagingViewController DataSource
extension NCSharePaging: PagingViewControllerDataSource {
-
func pagingViewController(_: PagingViewController, viewControllerAt index: Int) -> UIViewController {
let height: CGFloat = 50
@@ -230,14 +230,9 @@ extension NCSharePaging: PagingViewControllerDataSource {
// MARK: - Header
class NCShareHeaderViewController: PagingViewController {
-
public var image: UIImage?
public var metadata = tableMetadata()
- public var activityEnabled = true
- public var commentsEnabled = true
- public var sharingEnabled = true
-
override func loadView() {
view = NCSharePagingView(
options: options,
@@ -249,11 +244,11 @@ class NCShareHeaderViewController: PagingViewController {
}
class NCSharePagingView: PagingView {
-
- static let headerHeight: CGFloat = 90
- static var tagHeaderHeight: CGFloat = 0
var metadata = tableMetadata()
+ let utilityFileSystem = NCUtilityFileSystem()
+ let utility = NCUtility()
public var headerHeightConstraint: NSLayoutConstraint?
+ var header: NCShareHeader?
// MARK: - View Life Cycle
@@ -267,75 +262,81 @@ class NCSharePagingView: PagingView {
fatalError("init(coder:) has not been implemented")
}
+ override func setupConstraints() {
+ guard let headerView = Bundle.main.loadNibNamed("NCShareHeader", owner: self, options: nil)?.first as? NCShareHeader else { return }
+ header = headerView
+ headerView.backgroundColor = .systemBackground
+
+ let dateFormatter = DateFormatter()
+ dateFormatter.dateStyle = .short
+ dateFormatter.timeStyle = .short
+ dateFormatter.locale = Locale.current
+
+ headerView.setupUI(with: metadata)
+
+ addSubview(headerView)
+
+ collectionView.translatesAutoresizingMaskIntoConstraints = false
+ headerView.translatesAutoresizingMaskIntoConstraints = false
+ pageView.translatesAutoresizingMaskIntoConstraints = false
+
+ NSLayoutConstraint.activate([
+ collectionView.leadingAnchor.constraint(equalTo: leadingAnchor),
+ collectionView.trailingAnchor.constraint(equalTo: trailingAnchor),
+ collectionView.heightAnchor.constraint(equalToConstant: options.menuHeight),
+ collectionView.topAnchor.constraint(equalTo: headerView.bottomAnchor),
+
+ headerView.topAnchor.constraint(equalTo: safeAreaLayoutGuide.topAnchor),
+ headerView.leadingAnchor.constraint(equalTo: safeAreaLayoutGuide.leadingAnchor),
+ headerView.trailingAnchor.constraint(equalTo: safeAreaLayoutGuide.trailingAnchor),
+
+ pageView.leadingAnchor.constraint(equalTo: leadingAnchor),
+ pageView.trailingAnchor.constraint(equalTo: trailingAnchor),
+ pageView.bottomAnchor.constraint(equalTo: bottomAnchor),
+ pageView.topAnchor.constraint(equalTo: headerView.bottomAnchor)
+ ])
+ }
}
class NCShareHeaderView: UIView {
@IBOutlet weak var imageView: UIImageView!
- @IBOutlet weak var fileName: UILabel!
+ @IBOutlet weak var path: MarqueeLabel!
@IBOutlet weak var info: UILabel!
+ @IBOutlet weak var creation: UILabel!
+ @IBOutlet weak var upload: UILabel!
@IBOutlet weak var favorite: UIButton!
- @IBOutlet weak var labelSharing: UILabel!
- @IBOutlet weak var labelSharingInfo: UILabel!
- @IBOutlet weak var fullWidthImageView: UIImageView!
- @IBOutlet weak var canShareInfoView: UIView!
- @IBOutlet weak var sharedByLabel: UILabel!
- @IBOutlet weak var resharingAllowedLabel: UILabel!
- @IBOutlet weak var sharedByImageView: UIImageView!
- @IBOutlet weak var constraintTopSharingLabel: NSLayoutConstraint!
- let utility = NCUtility()
+ @IBOutlet weak var details: UIButton!
+ @IBOutlet weak var tagListView: TagListView!
+
var ocId = ""
override func awakeFromNib() {
super.awakeFromNib()
- setupUI()
+ let longGesture = UILongPressGestureRecognizer(target: self, action: #selector(longTap(_:)))
+ path.addGestureRecognizer(longGesture)
}
- func setupUI() {
- labelSharing.text = NSLocalizedString("_sharing_", comment: "")
- labelSharingInfo.text = NSLocalizedString("_sharing_message_", comment: "")
-
- if UIScreen.main.bounds.width < 376 {
- constraintTopSharingLabel.constant = 15
- }
- }
-
- func updateCanReshareUI() {
- let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId)
- var isCurrentUser = true
- if let ownerId = metadata?.ownerId, !ownerId.isEmpty {
- isCurrentUser = NCShareCommon().isCurrentUserIsFileOwner(fileOwnerId: ownerId)
- }
- var canReshare: Bool {
- guard let metadata = metadata else { return true }
- return ((metadata.sharePermissionsCollaborationServices & NCPermissions().permissionShareShare) != 0)
- }
- canShareInfoView.isHidden = isCurrentUser
- labelSharingInfo.isHidden = !isCurrentUser
-
- if !isCurrentUser {
- sharedByImageView.image = UIImage(named: "cloudUpload")?.image(color: .systemBlue, size: 26)
- let ownerName = metadata?.ownerDisplayName ?? ""
- sharedByLabel.text = NSLocalizedString("_shared_with_you_by_", comment: "") + " " + ownerName
- let resharingAllowedMessage = NSLocalizedString("_share_reshare_allowed_", comment: "") + " " + NSLocalizedString("_sharing_message_", comment: "")
- let resharingNotAllowedMessage = NSLocalizedString("_share_reshare_not_allowed_", comment: "")
- resharingAllowedLabel.text = canReshare ? resharingAllowedMessage : resharingNotAllowedMessage
- }
- }
-
@IBAction func touchUpInsideFavorite(_ sender: UIButton) {
guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(ocId) else { return }
- NCNetworking.shared.setStatusWaitFavorite(metadata) { error in
+ NCNetworking.shared.favoriteMetadata(metadata) { error in
if error == .success {
guard let metadata = NCManageDatabase.shared.getMetadataFromOcId(metadata.ocId) else { return }
- if metadata.favorite {
- self.favorite.setImage(self.utility.loadImage(named: "star.fill", colors: [NCBrandColor.shared.yellowFavorite], size: 24), for: .normal)
- } else {
- self.favorite.setImage(self.utility.loadImage(named: "star.fill", colors: [NCBrandColor.shared.textInfo], size: 24), for: .normal)
- }
+ self.favorite.setImage(NCUtility().loadImage(named: metadata.favorite ? "star" : "star.fill", colors: [NCBrandColor.shared.yellowFavorite], size: 20), for: .normal)
} else {
NCContentPresenter().showError(error: error)
}
}
}
+
+ @IBAction func touchUpInsideDetails(_ sender: UIButton) {
+ creation.isHidden = !creation.isHidden
+ upload.isHidden = !upload.isHidden
+ }
+
+ @objc func longTap(_ sender: UIGestureRecognizer) {
+ UIPasteboard.general.string = path.text
+ let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_copied_path_")
+ NCContentPresenter().showInfo(error: error)
+ }
}
diff --git a/iOSClient/Share/NCSharePermissions.swift b/iOSClient/Share/NCSharePermissions.swift
index de12f94a59..26f3479412 100644
--- a/iOSClient/Share/NCSharePermissions.swift
+++ b/iOSClient/Share/NCSharePermissions.swift
@@ -3,15 +3,36 @@
// Nextcloud
//
// Created by Marino Faggiana on 05/06/24.
-// SPDX-FileCopyrightText: Nextcloud GmbH
-// SPDX-FileCopyrightText: 2024 Marino Faggiana
-// SPDX-License-Identifier: GPL-3.0-or-later
+// Copyright © 2024 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 Foundation
-import NextcloudKit
enum NCSharePermissions {
+ // Share permission
+ // permissions - (int) 1 = read; 2 = update; 4 = create; 8 = delete; 16 = Reshare; 31 = all
+ //
+ static let permissionReadShare: Int = 1
+ static let permissionEditShare: Int = 2
+ static let permissionCreateShare: Int = 4
+ static let permissionDeleteShare: Int = 8
+ static let permissionReshareShare: Int = 16
static let permissionMinFileShare: Int = 1
static let permissionMaxFileShare: Int = 19
@@ -25,30 +46,30 @@ enum NCSharePermissions {
static let permissionDownloadShare: Int = 0
static func hasPermissionToRead(_ permission: Int) -> Bool {
- return ((permission & NKShare.Permission.read.rawValue) > 0)
+ return ((permission & permissionReadShare) > 0)
}
static func hasPermissionToDelete(_ permission: Int) -> Bool {
- return ((permission & NKShare.Permission.delete.rawValue) > 0)
+ return ((permission & permissionDeleteShare) > 0)
}
static func hasPermissionToCreate(_ permission: Int) -> Bool {
- return ((permission & NKShare.Permission.create.rawValue) > 0)
+ return ((permission & permissionCreateShare) > 0)
}
static func hasPermissionToEdit(_ permission: Int) -> Bool {
- return ((permission & NKShare.Permission.update.rawValue) > 0)
+ return ((permission & permissionEditShare) > 0)
}
static func hasPermissionToShare(_ permission: Int) -> Bool {
- return ((permission & NKShare.Permission.share.rawValue) > 0)
+ return ((permission & permissionReshareShare) > 0)
}
static func isAnyPermissionToEdit(_ permission: Int) -> Bool {
let canCreate = hasPermissionToCreate(permission)
let canEdit = hasPermissionToEdit(permission)
let canDelete = hasPermissionToDelete(permission)
- return canCreate || canEdit || canDelete
+ return canCreate || canEdit //|| canDelete
}
/// "Can edit" means it has can read, create, edit, and delete.
@@ -57,7 +78,7 @@ enum NCSharePermissions {
let canCreate = isDirectory ? hasPermissionToCreate(permission) : true
let canEdit = hasPermissionToEdit(permission)
let canDelete = isDirectory ? hasPermissionToDelete(permission) : true
- return canCreate && canEdit && canRead && canDelete
+ return canCreate && canEdit && canRead //&& canDelete
}
/// Read permission is always true for a share, hence why it's not here.
@@ -65,20 +86,20 @@ enum NCSharePermissions {
var permission = 0
if canRead {
- permission = permission + NKShare.Permission.read.rawValue
+ permission = permission + permissionReadShare
}
if canCreate && isDirectory {
- permission = permission + NKShare.Permission.create.rawValue
+ permission = permission + permissionCreateShare
}
if canEdit {
- permission = permission + NKShare.Permission.update.rawValue
- }
- if canDelete && isDirectory {
- permission = permission + NKShare.Permission.delete.rawValue
+ permission = permission + permissionEditShare
}
+// if canDelete && isDirectory {
+// permission = permission + permissionDeleteShare
+// }
if canShare {
- permission = permission + NKShare.Permission.share.rawValue
+ permission = permission + permissionReshareShare
}
return permission
diff --git a/iOSClient/Share/NCShareUserCell.swift b/iOSClient/Share/NCShareUserCell.swift
index b5fed3c8fa..7e31ba5d86 100644
--- a/iOSClient/Share/NCShareUserCell.swift
+++ b/iOSClient/Share/NCShareUserCell.swift
@@ -54,109 +54,7 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol {
set {}
}
- func setupCellUI(userId: String, session: NCSession.Session, metadata: tableMetadata) {
- guard let tableShare = tableShare else {
- return
- }
- self.accessibilityCustomActions = [UIAccessibilityCustomAction(
- name: NSLocalizedString("_show_profile_", comment: ""),
- target: self,
- selector: #selector(tapAvatarImage(_:)))]
- labelTitle.text = (tableShare.shareWithDisplayname.isEmpty ? tableShare.shareWith : tableShare.shareWithDisplayname)
-
- let type = getTypeString(tableShare)
- if !type.isEmpty {
- labelTitle.text?.append(" (\(type))")
- }
-
- labelTitle.lineBreakMode = .byTruncatingMiddle
- labelTitle.textColor = NCBrandColor.shared.textColor
- contentView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
- let permissions = NCPermissions()
- labelTitle.text = tableShare.shareWithDisplayname
- labelTitle.textColor = NCBrandColor.shared.label
- isUserInteractionEnabled = true
- switchCanEdit.isHidden = true
- labelCanEdit.isHidden = true
- buttonMenu.isHidden = false
- buttonMenu.accessibilityLabel = NSLocalizedString("_more_", comment: "")
- imageItem.image = NCShareCommon.getImageShareType(shareType: tableShare.shareType)
-
- let status = utility.getUserStatus(userIcon: tableShare.userIcon, userStatus: tableShare.userStatus, userMessage: tableShare.userMessage)
- imageStatus.image = status.statusImage
- self.status.text = status.statusMessage
-
- if permissions.isAnyPermissionToEdit(tableShare.permissions) {
- switchCanEdit.setOn(true, animated: false)
- } else {
- switchCanEdit.setOn(false, animated: false)
- }
-
- // If the initiator or the recipient is not the current user, show the list of sharees without any options to edit it.
- if tableShare.uidOwner != userId && tableShare.uidFileOwner != userId {
- isUserInteractionEnabled = false
- switchCanEdit.isHidden = true
- labelCanEdit.isHidden = true
- buttonMenu.isHidden = true
- }
-
- btnQuickStatus.accessibilityHint = NSLocalizedString("_user_sharee_footer_", comment: "")
- btnQuickStatus.setTitle("", for: .normal)
- btnQuickStatus.contentHorizontalAlignment = .left
- btnQuickStatus.isEnabled = true
- labelQuickStatus.textColor = NCBrandColor.shared.brand
- imageDownArrow.image = UIImage(named: "downArrow")?.imageColor(NCBrandColor.shared.brand)
-
- if NCSharePermissions.canEdit(tableShare.permissions, isDirectory: isDirectory) { // Can edit
- labelQuickStatus.text = NSLocalizedString("_share_editing_", comment: "")
- } else if tableShare.permissions == NKShare.Permission.read.rawValue { // Read only
- labelQuickStatus.text = NSLocalizedString("_share_read_only_", comment: "")
- } else { // Custom permissions
- labelQuickStatus.text = NSLocalizedString("_custom_permissions_", comment: "")
- }
-
- let fileName = NCSession.shared.getFileName(urlBase: session.urlBase, user: tableShare.shareWith)
- let results = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName)
-
- imageItem.contentMode = .scaleAspectFill
-
- if tableShare.shareType == NKShare.ShareType.team.rawValue {
- imageItem.image = utility.loadImage(named: "custom.person.3.circle.fill", colors: [NCBrandColor.shared.iconImageColor2])
- } else if results.image == nil {
- imageItem.image = utility.loadUserImage(for: tableShare.shareWith, displayName: tableShare.shareWithDisplayname, urlBase: metadata.urlBase)
- } else {
- imageItem.image = results.image
- }
-
- if !(results.tblAvatar?.loaded ?? false),
- NCNetworking.shared.downloadAvatarQueue.operations.filter({ ($0 as? NCOperationDownloadAvatar)?.fileName == fileName }).isEmpty {
- NCNetworking.shared.downloadAvatarQueue.addOperation(NCOperationDownloadAvatar(user: tableShare.shareWith, fileName: fileName, account: metadata.account, view: self))
- }
- }
-
- private func getTypeString(_ tableShare: tableShareV2) -> String {
- switch tableShare.shareType {
- case NKShare.ShareType.federatedCloud.rawValue:
- return NSLocalizedString("_remote_", comment: "")
- case NKShare.ShareType.federatedGroup.rawValue:
- return NSLocalizedString("_remote_group_", comment: "")
- case NKShare.ShareType.talkConversation.rawValue:
- return NSLocalizedString("_conversation_", comment: "")
- default:
- return ""
- }
- if tableShare.permissions == permissions.permissionCreateShare {
- labelQuickStatus.text = NSLocalizedString("_share_file_drop_", comment: "")
- } else {
- // Read Only
- if permissions.isAnyPermissionToEdit(tableShare.permissions) {
- labelQuickStatus.text = NSLocalizedString("_share_editing_", comment: "")
- } else {
- labelQuickStatus.text = NSLocalizedString("_share_read_only_", comment: "")
- }
- }
- }
-
+ // MARK: - Lifecycle
override func awakeFromNib() {
super.awakeFromNib()
setupCellUIAppearance()
@@ -179,16 +77,17 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol {
// MARK: - UI Setup
private func setupCellUIAppearance() {
- contentView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
+// contentView.backgroundColor = NCBrandColor.shared.secondarySystemGroupedBackground
buttonMenu.contentMode = .scaleAspectFill
- buttonMenu.setImage(NCImageCache.images.buttonMore.image(color: NCBrandColor.shared.brand, size: 24), for: .normal)
+// buttonMenu.setImage(NCImageCache.images.buttonMore.image(color: NCBrandColor.shared.brand, size: 24), for: .normal)
+ buttonMenu.setImage(NCImageCache.shared.getImageButtonMore().image(color: NCBrandColor.shared.brand, size: 24), for: .normal)
labelQuickStatus.textColor = NCBrandColor.shared.shareBlueColor
labelTitle.textColor = NCBrandColor.shared.label
- imageRightArrow.image = UIImage(named: "rightArrow")?.imageColor(NCBrandColor.shared.shareBlueColor)
- imageExpiredDateSet.image = UIImage(named: "calenderNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
- imagePasswordSet.image = UIImage(named: "lockNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ imageRightArrow.image = UIImage(named: "rightArrow")?.image(color: NCBrandColor.shared.shareBlueColor)
+ imageExpiredDateSet.image = UIImage(named: "calenderNew")?.image(color: NCBrandColor.shared.shareBlueColor)
+ imagePasswordSet.image = UIImage(named: "lockNew")?.image(color: NCBrandColor.shared.shareBlueColor)
- imagePermissionType.image = imagePermissionType.image?.imageColor(NCBrandColor.shared.shareBlueColor)
+ imagePermissionType.image = imagePermissionType.image?.image(color: NCBrandColor.shared.shareBlueColor)
updatePermissionUI()
}
@@ -199,13 +98,13 @@ class NCShareUserCell: UITableViewCell, NCCellProtocol {
if tableShare.permissions == permissions.permissionCreateShare {
labelQuickStatus.text = NSLocalizedString("_share_quick_permission_everyone_can_just_upload_", comment: "")
- imagePermissionType.image = UIImage(named: "upload")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ imagePermissionType.image = UIImage(named: "upload")?.image(color: NCBrandColor.shared.shareBlueColor)
} else if permissions.isAnyPermissionToEdit(tableShare.permissions) {
labelQuickStatus.text = NSLocalizedString("_share_quick_permission_everyone_can_edit_", comment: "")
- imagePermissionType.image = UIImage(named: "editNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ imagePermissionType.image = UIImage(named: "editNew")?.image(color: NCBrandColor.shared.shareBlueColor)
} else {
labelQuickStatus.text = NSLocalizedString("_share_quick_permission_everyone_can_only_view_", comment: "")
- imagePermissionType.image = UIImage(named: "showPasswordNew")?.imageColor(NCBrandColor.shared.shareBlueColor)
+ imagePermissionType.image = UIImage(named: "showPasswordNew")?.image(color: NCBrandColor.shared.shareBlueColor)
}
imagePasswordSet.isHidden = tableShare.password.isEmpty
@@ -296,16 +195,15 @@ class NCSearchUserDropDownCell: DropDownCell, NCCellProtocol {
func setupCell(sharee: NKSharee, session: NCSession.Session) {
let utility = NCUtility()
- imageItem.image = NCShareCommon.getImageShareType(shareType: sharee.shareType)
-// imageShareeType.image = NCShareCommon.getImageShareType(shareType: sharee.shareType)
- imageShareeType.image = NCShareCommon().getImageShareType(shareType: sharee.shareType, isDropDown: true)
- let status = utility.getUserStatus(userIcon: sharee.userIcon, userStatus: sharee.userStatus, userMessage: sharee.userMessage)
- imageStatus.image = status.statusImage
- self.status.text = status.statusMessage
- if self.status.text?.count ?? 0 > 0 {
- centerTitle.constant = -5
- } else {
- centerTitle.constant = 0
+ imageShareeType.image = NCShareCommon.getImageShareType(shareType: sharee.shareType, isDropDown: true)
+
+ let userStatus = utility.getUserStatus(userIcon: sharee.userIcon,
+ userStatus: sharee.userStatus,
+ userMessage: sharee.userMessage)
+
+ if let statusImage = userStatus.statusImage {
+ imageStatus.image = statusImage
+ imageStatus.makeCircularBackground(withColor: .systemBackground)
}
statusLabel.text = userStatus.statusMessage
diff --git a/iOSClient/Share/NCShareUserCell.xib b/iOSClient/Share/NCShareUserCell.xib
index afd9bad812..2a7e57bf77 100755
--- a/iOSClient/Share/NCShareUserCell.xib
+++ b/iOSClient/Share/NCShareUserCell.xib
@@ -1,157 +1,134 @@
-
+
-
-
-
+
-
-
+
+
-
-
+
+
-
-
+
+
+
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
diff --git a/iOSClient/Share/ShareDownloadLimitNetwork.swift b/iOSClient/Share/ShareDownloadLimitNetwork.swift
index 118bd538d0..06858464bf 100644
--- a/iOSClient/Share/ShareDownloadLimitNetwork.swift
+++ b/iOSClient/Share/ShareDownloadLimitNetwork.swift
@@ -27,6 +27,9 @@ class NMCCommunication: NSObject, XMLParserDelegate {
NCSession.shared.getSession(controller: controller)
}
+ func getDownloadLimit(token: String, completion: @escaping (_ downloadLimit: DownloadLimit?, _ errorDescription: String) -> Void) {
+ let baseUrl = session.urlBase // NCBrandOptions.shared.loginBaseUrl
+
func getDownloadLimit(token: String, completion: @escaping (_ downloadLimit: DownloadLimit?, _ errorDescription: String) -> Void) {
let baseUrl = session.urlBase // NCBrandOptions.shared.loginBaseUrl
let endPoint = "/ocs/v2.php/apps/files_downloadlimit/\(token)/limit"
@@ -67,6 +70,7 @@ class NMCCommunication: NSObject, XMLParserDelegate {
func setDownloadLimit(deleteLimit: Bool, limit: String, token: String, completion: @escaping (_ success: Bool, _ errorDescription: String) -> Void) {
let baseUrl = session.urlBase //NCBrandOptions.shared.loginBaseUrl
+ let baseUrl = appDelegate?.urlBase ?? "" //NCBrandOptions.shared.loginBaseUrl
let endPoint = "/ocs/v2.php/apps/files_downloadlimit/\(token)/limit"
let path = baseUrl+endPoint
do {
@@ -113,6 +117,8 @@ class NMCCommunication: NSObject, XMLParserDelegate {
public func authorizationToken() -> String {
let accountDetails = NCManageDatabase.shared.getAllTableAccount().first
+ let accountDetails = NCManageDatabase.shared.getAllAccount().first
+ let password = NCKeychain().getPassword(account: accountDetails?.account ?? "")
let password = NCKeychain().getPassword(account: accountDetails?.account ?? "")
let username = accountDetails?.user ?? ""
let credential = Data("\(username):\(password)".utf8).base64EncodedString()
diff --git a/iOSClient/Share/Shareable.swift b/iOSClient/Share/Shareable.swift
index 4b1f413aeb..374eebabb1 100644
--- a/iOSClient/Share/Shareable.swift
+++ b/iOSClient/Share/Shareable.swift
@@ -16,9 +16,11 @@ protocol Shareable: AnyObject {
var password: String { get set }
var label: String { get set }
var note: String { get set }
+ var downloadAndSync: Bool { get set }
var expirationDate: NSDate? { get set }
var shareWithDisplayname: String { get set }
var attributes: String? { get set }
+ var itemType: String { get set }
}
// MARK: - Default Implementations
@@ -29,7 +31,7 @@ extension Shareable {
///
var formattedDateString: String? {
guard let date = expirationDate else {
- return ""
+ return nil
}
let dateFormatter = DateFormatter()
@@ -54,8 +56,44 @@ extension Shareable {
// MARK: - tableShare Extension
-extension tableShare: Shareable {}
+extension tableShare: Shareable {
+ var downloadAndSync: Bool {
+ get {
+ NCManageDatabase.shared.isAttributeDownloadEnabled(attributes: attributes)
+ }
+ set {
+ attributes = NCManageDatabase.shared.setAttibuteDownload(state: newValue)
+ }
+ }
+}
// MARK: - NKShare Extension
-extension NKShare: Shareable {}
+extension NKShare: Shareable {
+ var downloadAndSync: Bool {
+ get {
+ NCManageDatabase.shared.isAttributeDownloadEnabled(attributes: attributes)
+ }
+ set {
+ attributes = NCManageDatabase.shared.setAttibuteDownload(state: newValue)
+ }
+ }
+}
+
+private func isAttributeDownloadEnabled(attributes: String?) -> Bool {
+ if let attributes = attributes, let data = attributes.data(using: .utf8) {
+ do {
+ if let json = try JSONSerialization.jsonObject(with: data) as? [Dictionary] {
+ for sub in json {
+ let key = sub["key"] as? String
+ let enabled = sub["enabled"] as? Bool
+ let scope = sub["scope"] as? String
+ if key == "download", scope == "permissions", let enabled = enabled {
+ return enabled
+ }
+ }
+ }
+ } catch let error as NSError { print(error) }
+ }
+ return true
+}
diff --git a/iOSClient/Share/TransientShare.swift b/iOSClient/Share/TransientShare.swift
index 88497103d6..666b91b66c 100644
--- a/iOSClient/Share/TransientShare.swift
+++ b/iOSClient/Share/TransientShare.swift
@@ -22,6 +22,8 @@ class TransientShare: Shareable {
var note: String = ""
var expirationDate: NSDate?
var shareWithDisplayname: String = ""
+ var downloadAndSync = false
+ var itemType: String = ""
var attributes: String?
@@ -29,13 +31,15 @@ class TransientShare: Shareable {
let capabilities = NCNetworking.shared.capabilities[metadata.account] ?? NKCapabilities.Capabilities()
if metadata.e2eEncrypted, capabilities.e2EEApiVersion == NCGlobal.shared.e2eeVersionV12 {
- self.permissions = NKShare.Permission.create.rawValue
+ self.permissions = NCSharePermissions.permissionCreateShare
} else {
- self.permissions = NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityFileSharingDefaultPermission & metadata.sharePermissionsCollaborationServices
+ self.permissions = capabilities.fileSharingDefaultPermission & metadata.sharePermissionsCollaborationServices
}
self.shareType = shareType
+ self.itemType = metadata.isDirectory ? NCShareCommon.itemTypeFolder : NCShareCommon.itemTypeFile
+
if let password = password {
self.password = password
}
@@ -44,10 +48,9 @@ class TransientShare: Shareable {
convenience init(sharee: NKSharee, metadata: tableMetadata, password: String?) {
self.init(shareType: sharee.shareType, metadata: metadata, password: password)
self.shareWith = sharee.shareWith
- self.shareWithDisplayname = sharee.label
}
static func shareLink(metadata: tableMetadata, password: String?) -> TransientShare {
- TransientShare(shareType: NKShare.ShareType.publicLink.rawValue, metadata: metadata, password: password)
+ TransientShare(shareType: NCShareCommon.shareTypeLink, metadata: metadata, password: password)
}
}
diff --git a/iOSClient/Utility/NCUtility.swift b/iOSClient/Utility/NCUtility.swift
index 8514a57702..eb35e7d03e 100644
--- a/iOSClient/Utility/NCUtility.swift
+++ b/iOSClient/Utility/NCUtility.swift
@@ -1,48 +1,55 @@
-// SPDX-FileCopyrightText: Nextcloud GmbH
-// SPDX-FileCopyrightText: 2018 Marino Faggiana
-// SPDX-License-Identifier: GPL-3.0-or-later
+//
+// NCUtility.swift
+// Nextcloud
+//
+// Created by Marino Faggiana on 25/06/18.
+// Copyright © 2018 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 Foundation
import UIKit
import NextcloudKit
import PDFKit
import Accelerate
import CoreMedia
import Photos
-import Alamofire
final class NCUtility: NSObject, Sendable {
let utilityFileSystem = NCUtilityFileSystem()
let global = NCGlobal.shared
- @objc func isSimulatorOrTestFlight() -> Bool {
- guard let path = Bundle.main.appStoreReceiptURL?.path else {
- return false
- }
- return path.contains("CoreSimulator") || path.contains("sandboxReceipt")
- }
-
- func isSimulator() -> Bool {
- guard let path = Bundle.main.appStoreReceiptURL?.path else {
+ func isTypeFileRichDocument(_ metadata: tableMetadata) -> Bool {
+ let fileExtension = (metadata.fileNameView as NSString).pathExtension
+ guard let capabilities = NCNetworking.shared.capabilities[metadata.account],
+ !fileExtension.isEmpty,
+ let mimeType = UTType(tag: fileExtension.uppercased(), tagClass: .filenameExtension, conformingTo: nil)?.identifier else {
return false
}
- return path.contains("CoreSimulator")
- }
- func isTypeFileRichDocument(_ metadata: tableMetadata) -> Bool {
- guard metadata.fileNameView != "." else { return false }
- let fileExtension = (metadata.fileNameView as NSString).pathExtension
- guard !fileExtension.isEmpty else { return false }
- guard let mimeType = UTType(tag: fileExtension.uppercased(), tagClass: .filenameExtension, conformingTo: nil)?.identifier else { return false }
/// contentype
- if !NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityRichDocumentsMimetypes.filter({ $0.contains(metadata.contentType) || $0.contains("text/plain") }).isEmpty {
+ if !capabilities.richDocumentsMimetypes.filter({ $0.contains(metadata.contentType) || $0.contains("text/plain") }).isEmpty {
return true
}
+
/// mimetype
- if !NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityRichDocumentsMimetypes.isEmpty && mimeType.components(separatedBy: ".").count > 2 {
+ if !capabilities.richDocumentsMimetypes.isEmpty && mimeType.components(separatedBy: ".").count > 2 {
let mimeTypeArray = mimeType.components(separatedBy: ".")
let mimeType = mimeTypeArray[mimeTypeArray.count - 2] + "." + mimeTypeArray[mimeTypeArray.count - 1]
- if !NCCapabilities.shared.getCapabilities(account: metadata.account).capabilityRichDocumentsMimetypes.filter({ $0.contains(mimeType) }).isEmpty {
+ if !capabilities.richDocumentsMimetypes.filter({ $0.contains(mimeType) }).isEmpty {
return true
}
}
@@ -50,39 +57,32 @@ final class NCUtility: NSObject, Sendable {
}
func editorsDirectEditing(account: String, contentType: String) -> [String] {
- var editor: [String] = []
- guard let results = NCManageDatabase.shared.getDirectEditingEditors(account: account) else { return editor }
+ var names: [String] = []
+ let capabilities = NCNetworking.shared.capabilities[account]
- for result: tableDirectEditingEditors in results {
- for mimetype in result.mimetypes {
+ capabilities?.directEditingEditors.forEach { editor in
+ editor.mimetypes.forEach { mimetype in
if mimetype == contentType {
- editor.append(result.editor)
+ names.append(editor.name)
}
// HARDCODE
// https://github.com/nextcloud/text/issues/913
if mimetype == "text/markdown" && contentType == "text/x-markdown" {
- editor.append(result.editor)
+ names.append(editor.name)
}
if contentType == "text/html" {
- editor.append(result.editor)
+ names.append(editor.name)
}
}
- for mimetype in result.optionalMimetypes {
+
+ editor.optionalMimetypes.forEach { mimetype in
if mimetype == contentType {
- editor.append(result.editor)
+ names.append(editor.name)
}
}
}
- return Array(Set(editor))
- }
- func permissionsContainsString(_ metadataPermissions: String, permissions: String) -> Bool {
- for char in permissions {
- if metadataPermissions.contains(char) == false {
- return false
- }
- }
- return true
+ return Array(Set(names))
}
func getCustomUserAgentNCText() -> String {
@@ -106,11 +106,11 @@ final class NCUtility: NSObject, Sendable {
}
}
- @objc func isQuickLookDisplayable(metadata: tableMetadata) -> Bool {
+ func isQuickLookDisplayable(metadata: tableMetadata) -> Bool {
return true
}
- @objc func ocIdToFileId(ocId: String?) -> String? {
+ func ocIdToFileId(ocId: String?) -> String? {
guard let ocId = ocId else { return nil }
let items = ocId.components(separatedBy: "oc")
@@ -119,27 +119,18 @@ final class NCUtility: NSObject, Sendable {
return String(intFileId)
}
- func splitOcId(_ ocId: String) -> (fileId: String?, instanceId: String?) {
- let parts = ocId.components(separatedBy: "oc")
- guard parts.count == 2 else {
- return (nil, nil)
- }
- return (parts[0], "oc" + parts[1])
- }
-
- /// Pads a numeric fileId with leading zeros to reach 8 characters.
- func paddedFileId(_ fileId: String) -> String {
- if fileId.count >= 8 { return fileId }
- let zeros = String(repeating: "0", count: 8 - fileId.count)
- return zeros + fileId
- }
-
- func getLivePhotoOcId(metadata: tableMetadata) -> String? {
- if let instanceId = splitOcId(metadata.ocId).instanceId {
- return paddedFileId(metadata.livePhotoFile) + instanceId
- }
- return nil
- }
+// func getVersionApp(withBuild: Bool = true) -> String {
+// if let dictionary = Bundle.main.infoDictionary {
+// if let version = dictionary["CFBundleShortVersionString"], let build = dictionary["CFBundleVersion"] {
+// if withBuild {
+// return "\(version).\(build)"
+// } else {
+// return "\(version)"
+// }
+// }
+// }
+// return ""
+// }
func getVersionBuild() -> String {
if let dictionary = Bundle.main.infoDictionary,
@@ -157,19 +148,6 @@ final class NCUtility: NSObject, Sendable {
}
return ""
}
-
- @objc func getVersionApp(withBuild: Bool = true) -> String {
- if let dictionary = Bundle.main.infoDictionary {
- if let version = dictionary["CFBundleShortVersionString"], let build = dictionary["CFBundleVersion"] {
- if withBuild {
- return "\(version).\(build)"
- } else {
- return "\(version)"
- }
- }
- }
- return ""
- }
/*
Facebook's comparison algorithm:
@@ -254,7 +232,6 @@ final class NCUtility: NSObject, Sendable {
return isEqual
}
- #if !EXTENSION_FILE_PROVIDER_EXTENSION
func getLocation(latitude: Double, longitude: Double, completion: @escaping (String?) -> Void) {
let geocoder = CLGeocoder()
let llocation = CLLocation(latitude: latitude, longitude: longitude)
@@ -275,7 +252,6 @@ final class NCUtility: NSObject, Sendable {
}
}
}
- #endif
// https://stackoverflow.com/questions/5887248/ios-app-maximum-memory-budget/19692719#19692719
// https://stackoverflow.com/questions/27556807/swift-pointer-problems-with-mach-task-basic-info/27559770#27559770
@@ -306,26 +282,16 @@ final class NCUtility: NSObject, Sendable {
return (usedmegabytes, totalmegabytes)
}
- func getHeightHeaderEmptyData(view: UIView, portraitOffset: CGFloat, landscapeOffset: CGFloat, isHeaderMenuTransferViewEnabled: Bool = false) -> CGFloat {
+ func getHeightHeaderEmptyData(view: UIView, portraitOffset: CGFloat, landscapeOffset: CGFloat) -> CGFloat {
var height: CGFloat = 0
if UIDevice.current.orientation.isPortrait {
height = (view.frame.height / 2) - (view.safeAreaInsets.top / 2) + portraitOffset
} else {
- height = (view.frame.height / 2) + landscapeOffset + CGFloat(isHeaderMenuTransferViewEnabled ? 35 : 0)
+ height = (view.frame.height / 2) + landscapeOffset
}
return height
}
-
- func formatBadgeCount(_ count: Int) -> String {
- if count <= 9999 {
- return "\(count)"
- } else {
- return count.formatted(.number.notation(.compactName).locale(Locale(identifier: "en_US")))
- }
- }
- func isValidEmail(_ email: String) -> Bool {
-
// E-mail validations
// 1. Basic Email Validator (ASCII only)
func isValidEmail(_ email: String) -> Bool {