diff --git a/Brand/Database.swift b/Brand/Database.swift
index 4c94bbaea3..f083885915 100644
--- a/Brand/Database.swift
+++ b/Brand/Database.swift
@@ -8,4 +8,4 @@ import Foundation
//
let databaseName = "nextcloud.realm"
let tableAccountBackup = "tableAccountBackup.json"
-let databaseSchemaVersion: UInt64 = 408
+let databaseSchemaVersion: UInt64 = 409
diff --git a/Brand/NCBrand.swift b/Brand/NCBrand.swift
index c53e2e82a5..0fd9b5b6a7 100755
--- a/Brand/NCBrand.swift
+++ b/Brand/NCBrand.swift
@@ -326,12 +326,14 @@ final class NCBrandColor: @unchecked Sendable {
return false
}
+ /*
public func getTheming(account: String?) -> UIColor {
if let account, let color = self.themingColor[account] {
return color
}
return customer
}
+ */
public func getElement(account: String?) -> UIColor {
if let account, let color = self.themingColorElement[account] {
diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj
index ac069e22c1..72d1ca23e6 100644
--- a/Nextcloud.xcodeproj/project.pbxproj
+++ b/Nextcloud.xcodeproj/project.pbxproj
@@ -6129,7 +6129,7 @@
repositoryURL = "https://github.com/nextcloud/NextcloudKit";
requirement = {
kind = exactVersion;
- version = 7.2.8;
+ version = 7.2.9;
};
};
F788ECC5263AAAF900ADC67F /* XCRemoteSwiftPackageReference "MarkdownKit" */ = {
diff --git a/iOSClient/Data/NCManageDatabase+Trash.swift b/iOSClient/Data/NCManageDatabase+Trash.swift
index c17bfa8456..de1809b04e 100644
--- a/iOSClient/Data/NCManageDatabase+Trash.swift
+++ b/iOSClient/Data/NCManageDatabase+Trash.swift
@@ -7,25 +7,41 @@ import UIKit
import RealmSwift
import NextcloudKit
-class tableTrash: Object {
- @objc dynamic var account = ""
- @objc dynamic var classFile = ""
- @objc dynamic var contentType = ""
- @objc dynamic var date = NSDate()
- @objc dynamic var directory: Bool = false
- @objc dynamic var fileId = ""
- @objc dynamic var fileName = ""
- @objc dynamic var filePath = ""
- @objc dynamic var hasPreview: Bool = false
- @objc dynamic var iconName = ""
- @objc dynamic var size: Int64 = 0
- @objc dynamic var trashbinFileName = ""
- @objc dynamic var trashbinOriginalLocation = ""
- @objc dynamic var trashbinDeletionTime = NSDate()
-
- override static func primaryKey() -> String {
- return "fileId"
- }
+/// Represents a trash item stored in Realm.
+///
+/// Each object corresponds to a file or folder in the Nextcloud trashbin,
+/// associated with a specific account.
+///
+/// The `identifier` is used as primary key and is built from:
+/// `account + "|" + fileName`, where `fileName` includes the `.dXXXXX` suffix,
+/// making each item unique.
+///
+/// - `fileName`: name of the file in trash (includes `.dXXXXX`)
+/// - `trashbinFileName`: original file name before deletion
+/// - `trashbinOriginalLocation`: original path before deletion
+/// - `classFile`: type of file (e.g. "image", "video", "document")
+///
+/// This model replaces the legacy `tableTrash` schema.
+typealias tableTrash = tableTrashV2
+class tableTrashV2: Object {
+ // Primary key: unique per account + trash item
+ @Persisted(primaryKey: true) var identifier: String
+
+ @Persisted var account: String = ""
+ @Persisted var classFile: String = ""
+ @Persisted var contentType: String = ""
+ @Persisted var date: Date = Date()
+ @Persisted var directory: Bool = false
+ @Persisted var fileId: String = ""
+ @Persisted var fileName: String = ""
+ @Persisted var filePath: String = ""
+ @Persisted var hasPreview: Bool = false
+ @Persisted var iconName: String = ""
+ @Persisted var size: Int64 = 0
+ @Persisted var livePhoto: Bool = false
+ @Persisted var trashbinFileName: String = ""
+ @Persisted var trashbinOriginalLocation: String = ""
+ @Persisted var trashbinDeletionTime: Date = Date()
}
extension NCManageDatabase {
@@ -38,12 +54,22 @@ extension NCManageDatabase {
/// - account: The account string used to associate each trash item.
/// - items: An array of `NKTrash` items to be added to the database.
func addTrashAsync(items: [NKTrash], account: String) async {
+ let itemsFiltered = filterOutVideosMatchingImages(items)
+
await core.performRealmWriteAsync { realm in
- items.forEach { trash in
+
+ // Delete all existing trash items for this account.
+ let existingItems = realm.objects(tableTrash.self)
+ .where { $0.account == account }
+ realm.delete(existingItems)
+
+ itemsFiltered.forEach { trash in
let object = tableTrash()
+
+ object.identifier = "\(account)|\(trash.fileName)"
object.account = account
object.contentType = trash.contentType
- object.date = trash.date as NSDate
+ object.date = trash.date
object.directory = trash.directory
object.fileId = trash.fileId
object.fileName = trash.fileName
@@ -51,10 +77,12 @@ extension NCManageDatabase {
object.hasPreview = trash.hasPreview
object.iconName = trash.iconName
object.size = trash.size
- object.trashbinDeletionTime = trash.trashbinDeletionTime as NSDate
+ object.trashbinDeletionTime = trash.trashbinDeletionTime
object.trashbinFileName = trash.trashbinFileName
object.trashbinOriginalLocation = trash.trashbinOriginalLocation
object.classFile = trash.classFile
+ object.livePhoto = trash.livePhoto
+
realm.add(object, update: .all)
}
}
@@ -141,4 +169,84 @@ extension NCManageDatabase {
.map { tableTrash(value: $0) }
}
}
+
+ // MARK: - helpers
+
+ /// Filters out video items that have a matching image counterpart based on a shared trash suffix.
+ ///
+ /// This function is designed to handle Live Photo pairs in the trash, where both the image
+ /// (e.g. `.jpg`) and the video (e.g. `.mov`) share the same suffix (e.g. `.d123456`).
+ ///
+ /// The logic works as follows:
+ /// - Extract the suffix from each trash item file name.
+ /// - Detect which suffixes contain both an image and a video.
+ /// - Iterate through all items:
+ /// - If an item is a video and its suffix is shared with an image, the video is excluded.
+ /// - If an item is an image and its suffix is shared with a video, the image is kept and
+ /// marked with `isLivePhoto = true`.
+ /// - All other items are returned unchanged.
+ ///
+ /// - Parameter items: An array of `NKTrash` items to process.
+ /// - Returns: A filtered array where Live Photo videos are removed and matching images are marked as Live Photos.
+ func filterOutVideosMatchingImages(_ items: [NKTrash]) -> [NKTrash] {
+ var suffixMap: [String: (hasImage: Bool, hasVideo: Bool)] = [:]
+
+ for item in items {
+ guard let suffix = trashSuffix(from: item.fileName) else {
+ continue
+ }
+ var entry = suffixMap[suffix] ?? (false, false)
+
+ if item.classFile == "image" {
+ entry.hasImage = true
+ } else if item.classFile == "video" {
+ entry.hasVideo = true
+ }
+
+ suffixMap[suffix] = entry
+ }
+
+ return items.compactMap { item -> NKTrash? in
+ guard let suffix = trashSuffix(from: item.fileName) else {
+ return item
+ }
+ let entry = suffixMap[suffix]
+ let isLive = (entry?.hasImage == true && entry?.hasVideo == true)
+
+ if item.classFile == "video" && isLive {
+ return nil
+ }
+
+ if item.classFile == "image" && isLive {
+ var copy = item
+ copy.livePhoto = true
+ return copy
+ }
+
+ return item
+ }
+ }
+
+ /// Extracts the suffix component from a trash file name.
+ ///
+ /// The suffix is defined as the substring after the last dot (`.`) in the file name.
+ /// This is typically used to identify related files in the trash (e.g., Live Photo pairs),
+ /// where files share a common suffix such as `d123456`.
+ ///
+ /// Examples:
+ /// - `file.jpg.d123456` → `d123456`
+ /// - `video.mov.d987654` → `d987654`
+ ///
+ /// If the file name does not contain a dot or the suffix is empty, the function returns `nil`.
+ ///
+ /// - Parameter fileName: The full file name string.
+ /// - Returns: The extracted suffix, or `nil` if not available.
+ func trashSuffix(from fileName: String) -> String? {
+ guard let lastDot = fileName.lastIndex(of: ".") else {
+ return nil
+ }
+
+ let suffix = String(fileName[fileName.index(after: lastDot)...])
+ return suffix.isEmpty ? nil : suffix
+ }
}
diff --git a/iOSClient/Data/NCManageDatabase.swift b/iOSClient/Data/NCManageDatabase.swift
index 42f1eeb380..8e27653fc9 100644
--- a/iOSClient/Data/NCManageDatabase.swift
+++ b/iOSClient/Data/NCManageDatabase.swift
@@ -211,6 +211,7 @@ final class NCManageDatabase: @unchecked Sendable {
self.clearTable(tableMetadataTag.self)
self.clearTable(tableRecommendedFiles.self)
self.clearTable(tableShare.self)
+ self.clearTable(tableTrash.self)
}
func clearDatabase(account: String) {
diff --git a/iOSClient/GUI/ComponentView.swift b/iOSClient/GUI/ComponentView.swift
index 9a24acc557..628a642339 100644
--- a/iOSClient/GUI/ComponentView.swift
+++ b/iOSClient/GUI/ComponentView.swift
@@ -13,7 +13,7 @@ struct ButtonRounded: ButtonStyle {
.padding(.horizontal, 40)
.padding(.vertical, 10)
.background(disabled ? Color(UIColor.placeholderText) : Color(NCBrandColor.shared.getElement(account: account)))
- .foregroundColor(disabled ? Color(UIColor.placeholderText) : Color(NCBrandColor.shared.getText(account: account)))
+ .foregroundColor(disabled ? Color(UIColor.lightGray) : .white)
.clipShape(Capsule())
.opacity(configuration.isPressed ? 0.5 : 1.0)
}
diff --git a/iOSClient/Main/Collection Common/Cell/NCCellMain.swift b/iOSClient/Main/Collection Common/Cell/NCCellMain.swift
index 055b09a411..71b9ec76c6 100644
--- a/iOSClient/Main/Collection Common/Cell/NCCellMain.swift
+++ b/iOSClient/Main/Collection Common/Cell/NCCellMain.swift
@@ -13,6 +13,8 @@ protocol NCCellMainProtocol {
var localImg: UIImageView? { get set }
var statusImg: UIImageView? { get set }
var infoLbl: UILabel? { get set }
+
+ func selected(_ status: Bool, isEditMode: Bool, color: UIColor)
}
extension NCCellMainProtocol {
diff --git a/iOSClient/Main/Collection Common/Cell/NCGridCell.swift b/iOSClient/Main/Collection Common/Cell/NCGridCell.swift
index ee326110f5..57831aa19b 100644
--- a/iOSClient/Main/Collection Common/Cell/NCGridCell.swift
+++ b/iOSClient/Main/Collection Common/Cell/NCGridCell.swift
@@ -80,17 +80,23 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellMainP
imageItem.image = nil
imageItem.layer.cornerRadius = 6
imageItem.layer.masksToBounds = true
- imageSelect.isHidden = true
- imageSelect.image = NCImageCache.shared.getImageCheckedYes()
+
imageStatus.image = nil
imageFavorite.image = nil
imageLocal.image = nil
- labelTitle.text = ""
- labelExtension.text = ""
- labelExtension.isHidden = true
- labelInfo.text = ""
- labelSubinfo.text = ""
+ iconsStackView.addBlurBackground(style: .systemMaterial)
+ iconsStackView.layer.cornerRadius = 8
+ iconsStackView.clipsToBounds = true
+
+ imageVisualEffect.isHidden = false
+ imageVisualEffect.effect = nil
+ imageVisualEffect.alpha = 0
+ imageVisualEffect.isUserInteractionEnabled = false
+ imageVisualEffect.backgroundColor = UIColor.white.withAlphaComponent(0.2)
+
+ buttonMore.menu = nil
+ buttonMore.showsMenuAsPrimaryAction = true
// Dynamic Type Font Configuration
//
@@ -118,30 +124,22 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellMainP
// adjustsFontForContentSizeCategory:
// Enables live updates when accessibility settings change.
//
+ labelTitle.text = ""
labelTitle.font = .callout()
labelTitle.adjustsFontForContentSizeCategory = true
+ labelExtension.text = ""
+ labelExtension.isHidden = true
labelExtension.font = .callout()
labelExtension.adjustsFontForContentSizeCategory = true
+ labelInfo.text = ""
labelInfo.font = .footnote()
labelInfo.adjustsFontForContentSizeCategory = true
+ labelSubinfo.text = ""
labelSubinfo.font = .footnote()
labelSubinfo.adjustsFontForContentSizeCategory = true
-
- imageVisualEffect.layer.cornerRadius = 6
- imageVisualEffect.clipsToBounds = true
- imageVisualEffect.alpha = 0.5
-
- iconsStackView.addBlurBackground(style: .systemMaterial)
- iconsStackView.layer.cornerRadius = 8
- iconsStackView.clipsToBounds = true
-
- buttonMore.menu = nil
- buttonMore.showsMenuAsPrimaryAction = true
-
- contentView.bringSubviewToFront(buttonMore)
}
override func snapshotView(afterScreenUpdates afterUpdates: Bool) -> UIView? {
@@ -164,21 +162,17 @@ class NCGridCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellMainP
buttonMore.isHidden = status
}
- func selected(_ status: Bool, isEditMode: Bool) {
+ func selected(_ status: Bool, isEditMode: Bool, color: UIColor) {
if isEditMode {
buttonMore.isHidden = true
accessibilityCustomActions = nil
} else {
buttonMore.isHidden = false
}
- if status {
- imageSelect.isHidden = false
- imageSelect.image = NCImageCache.shared.getImageCheckedYes()
- imageVisualEffect.isHidden = false
- } else {
- imageSelect.isHidden = true
- imageVisualEffect.isHidden = true
- }
+
+ imageVisualEffect.alpha = status ? 1 : 0
+ imageSelect.alpha = status ? 1 : 0
+ imageSelect.image = NCImageCache.shared.getImageCheckedYes(color: color)
}
func writeInfoDateSize(date: NSDate, size: Int64) {
@@ -323,10 +317,10 @@ extension NCCollectionViewCommon {
// Edit mode
if fileSelect.contains(metadata.ocId) {
- cell.selected(true, isEditMode: isEditMode)
+ cell.selected(true, isEditMode: isEditMode, color: NCBrandColor.shared.getElement(account: session.account))
a11yValues.append(NSLocalizedString("_selected_", comment: ""))
} else {
- cell.selected(false, isEditMode: isEditMode)
+ cell.selected(false, isEditMode: isEditMode, color: NCBrandColor.shared.getElement(account: session.account))
}
// Accessibility
diff --git a/iOSClient/Main/Collection Common/Cell/NCGridCell.xib b/iOSClient/Main/Collection Common/Cell/NCGridCell.xib
index bed4152326..7cb8863c41 100644
--- a/iOSClient/Main/Collection Common/Cell/NCGridCell.xib
+++ b/iOSClient/Main/Collection Common/Cell/NCGridCell.xib
@@ -20,22 +20,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -67,16 +51,6 @@
-
@@ -103,6 +77,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -155,10 +154,10 @@
-
+
-
+
diff --git a/iOSClient/Main/Collection Common/Cell/NCListCell.swift b/iOSClient/Main/Collection Common/Cell/NCListCell.swift
index dc0deb49a5..d89a957dc7 100755
--- a/iOSClient/Main/Collection Common/Cell/NCListCell.swift
+++ b/iOSClient/Main/Collection Common/Cell/NCListCell.swift
@@ -104,16 +104,19 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellMainP
imageStatus.image = nil
imageFavorite.image = nil
imageLocal.image = nil
- imageSelect.image = nil
- labelTitle.text = ""
- labelExtension.text = ""
- labelExtension.isHidden = true
- labelInfo.text = ""
- labelSubinfo.text = ""
- tag1.text = ""
- tag2.text = ""
- tagMore.text = ""
+ buttonShared.setImage(nil, for: .normal)
+ buttonShared.imageEdgeInsets = .zero
+
+ buttonMore.setImage(nil, for: .normal)
+ buttonMore.menu = nil
+ buttonMore.showsMenuAsPrimaryAction = true
+
+ shareContainer.isHidden = false
+ moreContainer.isHidden = false
+
+ imageItemLeftConstraint.constant = 10
+ separatorHeightConstraint.constant = 0.5
// Dynamic Type Font Configuration
//
@@ -141,40 +144,38 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellMainP
// adjustsFontForContentSizeCategory:
// Enables live updates when accessibility settings change.
//
+ labelTitle.text = ""
labelTitle.font = .callout()
labelTitle.adjustsFontForContentSizeCategory = true
+ labelExtension.text = ""
+ labelExtension.isHidden = true
labelExtension.font = .callout()
labelExtension.adjustsFontForContentSizeCategory = true
+ labelInfo.text = ""
labelInfo.font = .footnote()
labelInfo.adjustsFontForContentSizeCategory = true
labelInfoSeparator.font = .footnote()
labelInfoSeparator.adjustsFontForContentSizeCategory = true
+ labelSubinfo.text = ""
labelSubinfo.font = .footnote()
labelSubinfo.adjustsFontForContentSizeCategory = true
+ tag1.text = ""
+ tag2.text = ""
+
tag1.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
tag2.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
+
tag1.setContentHuggingPriority(.defaultLow, for: .horizontal)
tag2.setContentHuggingPriority(.defaultLow, for: .horizontal)
+
+ tagMore.text = ""
tagMore.setContentCompressionResistancePriority(.required, for: .horizontal)
tagMore.setContentHuggingPriority(.required, for: .horizontal)
-
- buttonShared.setImage(nil, for: .normal)
- buttonShared.imageEdgeInsets = .zero
-
- buttonMore.setImage(nil, for: .normal)
- buttonMore.menu = nil
- buttonMore.showsMenuAsPrimaryAction = true
-
- shareContainer.isHidden = false
- moreContainer.isHidden = false
-
- imageItemLeftConstraint.constant = 10
- separatorHeightConstraint.constant = 0.5
}
func setSharedAvatarImage(_ image: UIImage) {
@@ -221,7 +222,7 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellMainP
moreContainer.isHidden = hidden
}
- func selected(_ status: Bool, isEditMode: Bool) {
+ func selected(_ status: Bool, isEditMode: Bool, color: UIColor) {
if isEditMode {
imageItemLeftConstraint.constant = 45
imageSelect.isHidden = false
@@ -245,11 +246,11 @@ class NCListCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellMainP
blurEffectView?.backgroundColor = .lightGray
blurEffectView?.frame = self.bounds
blurEffectView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
- imageSelect.image = NCImageCache.shared.getImageCheckedYes()
+ imageSelect.image = NCImageCache.shared.getImageCheckedYes(color: color)
backgroundView = blurEffectView
separator.isHidden = true
} else {
- imageSelect.image = NCImageCache.shared.getImageCheckedNo()
+ imageSelect.image = NCImageCache.shared.getImageCheckedNo(color: color)
backgroundView = nil
separator.isHidden = false
}
@@ -535,10 +536,10 @@ extension NCCollectionViewCommon {
// Edit mode
if fileSelect.contains(metadata.ocId) {
- cell.selected(true, isEditMode: isEditMode)
+ cell.selected(true, isEditMode: isEditMode, color: NCBrandColor.shared.getElement(account: session.account))
a11yValues.append(NSLocalizedString("_selected_", comment: ""))
} else {
- cell.selected(false, isEditMode: isEditMode)
+ cell.selected(false, isEditMode: isEditMode, color: NCBrandColor.shared.getElement(account: session.account))
}
// Accessibility
diff --git a/iOSClient/Main/Collection Common/Cell/NCPhotoCell.swift b/iOSClient/Main/Collection Common/Cell/NCPhotoCell.swift
index 5c67a1dddc..2e29d9690a 100644
--- a/iOSClient/Main/Collection Common/Cell/NCPhotoCell.swift
+++ b/iOSClient/Main/Collection Common/Cell/NCPhotoCell.swift
@@ -15,6 +15,12 @@ class NCPhotoCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellMain
set { imageItem = newValue }
}
+ override func awakeFromNib() {
+ super.awakeFromNib()
+
+ initCell()
+ }
+
override func prepareForReuse() {
super.prepareForReuse()
@@ -27,25 +33,22 @@ class NCPhotoCell: UICollectionViewCell, UIGestureRecognizerDelegate, NCCellMain
accessibilityValue = nil
imageItem.image = nil
- imageSelect.isHidden = true
- imageSelect.image = NCImageCache.shared.getImageCheckedYes()
- imageVisualEffect.clipsToBounds = true
- imageVisualEffect.alpha = 0.5
+
+ imageVisualEffect.isHidden = false
+ imageVisualEffect.effect = nil
+ imageVisualEffect.alpha = 0
+ imageVisualEffect.isUserInteractionEnabled = false
+ imageVisualEffect.backgroundColor = UIColor.white.withAlphaComponent(0.2)
}
override func snapshotView(afterScreenUpdates afterUpdates: Bool) -> UIView? {
return nil
}
- func selected(_ status: Bool, isEditMode: Bool) {
- if status {
- imageSelect.isHidden = false
- imageVisualEffect.isHidden = false
- imageSelect.image = NCImageCache.shared.getImageCheckedYes()
- } else {
- imageSelect.isHidden = true
- imageVisualEffect.isHidden = true
- }
+ func selected(_ status: Bool, isEditMode: Bool, color: UIColor) {
+ imageVisualEffect.alpha = status ? 1 : 0
+ imageSelect.alpha = status ? 1 : 0
+ imageSelect.image = NCImageCache.shared.getImageCheckedYes(color: color)
}
func setAccessibility(label: String, value: String) {
@@ -96,9 +99,9 @@ extension NCCollectionViewCommon {
// Edit mode
//
if fileSelect.contains(metadata.ocId) {
- cell.selected(true, isEditMode: isEditMode)
+ cell.selected(true, isEditMode: isEditMode, color: NCBrandColor.shared.getElement(account: session.account))
} else {
- cell.selected(false, isEditMode: isEditMode)
+ cell.selected(false, isEditMode: isEditMode, color: NCBrandColor.shared.getElement(account: session.account))
}
return cell
diff --git a/iOSClient/Main/Collection Common/Cell/NCPhotoCell.xib b/iOSClient/Main/Collection Common/Cell/NCPhotoCell.xib
index 40878baeef..b5ec6e142b 100644
--- a/iOSClient/Main/Collection Common/Cell/NCPhotoCell.xib
+++ b/iOSClient/Main/Collection Common/Cell/NCPhotoCell.xib
@@ -19,13 +19,12 @@
-
+
-
diff --git a/iOSClient/Main/Collection Common/Cell/NCRecommendationsCell.swift b/iOSClient/Main/Collection Common/Cell/NCRecommendationsCell.swift
index 507ab98287..21d27676f7 100644
--- a/iOSClient/Main/Collection Common/Cell/NCRecommendationsCell.swift
+++ b/iOSClient/Main/Collection Common/Cell/NCRecommendationsCell.swift
@@ -92,7 +92,6 @@ class NCRecommendationsCell: UICollectionViewCell, UIGestureRecognizerDelegate {
buttonMore.menu = nil
buttonMore.showsMenuAsPrimaryAction = true
- contentView.bringSubviewToFront(buttonMore)
}
@objc private func handleTapObserver(_ g: UITapGestureRecognizer) {
diff --git a/iOSClient/Main/Create/Upload Assets/NCUploadAssetsView.swift b/iOSClient/Main/Create/Upload Assets/NCUploadAssetsView.swift
index 49b0445973..b7edd425aa 100644
--- a/iOSClient/Main/Create/Upload Assets/NCUploadAssetsView.swift
+++ b/iOSClient/Main/Create/Upload Assets/NCUploadAssetsView.swift
@@ -22,7 +22,6 @@ struct NCUploadAssetsView: View {
@State private var renameIndex: Int = 0
@State private var index: Int = 0
- var metadata: tableMetadata?
let gridItems: [GridItem] = [GridItem()]
let fileNamePath = NSTemporaryDirectory() + "Photo.jpg"
let utilityFileSystem = NCUtilityFileSystem()
@@ -147,7 +146,7 @@ struct NCUploadAssetsView: View {
.onChange(of: model.useAutoUploadFolder) {
model.updateUseAutoUploadFolder()
}
- .toggleStyle(SwitchToggleStyle(tint: Color(NCBrandColor.shared.getElement(account: metadata?.account))))
+ .toggleStyle(SwitchToggleStyle(tint: Color(NCBrandColor.shared.getElement(account: model.session.account))))
if model.useAutoUploadFolder {
Toggle(isOn: $model.useAutoUploadSubFolder, label: {
@@ -158,7 +157,7 @@ struct NCUploadAssetsView: View {
.onChange(of: model.useAutoUploadSubFolder) {
model.updateUseAutoUploadSubFolder()
}
- .toggleStyle(SwitchToggleStyle(tint: Color(NCBrandColor.shared.getElement(account: metadata?.account))))
+ .toggleStyle(SwitchToggleStyle(tint: Color(NCBrandColor.shared.getElement(account: model.session.account))))
}
}
diff --git a/iOSClient/Media/Cell/NCMediaCell.swift b/iOSClient/Media/Cell/NCMediaCell.swift
index 1575f21f6d..dc9ea1f615 100644
--- a/iOSClient/Media/Cell/NCMediaCell.swift
+++ b/iOSClient/Media/Cell/NCMediaCell.swift
@@ -24,7 +24,6 @@
import UIKit
class NCMediaCell: UICollectionViewCell {
-
@IBOutlet weak var imageItem: UIImageView!
@IBOutlet weak var imageVisualEffect: UIVisualEffectView!
@IBOutlet weak var imageSelect: UIImageView!
@@ -46,17 +45,17 @@ class NCMediaCell: UICollectionViewCell {
func initCell() {
imageStatus.image = nil
imageItem.image = nil
- imageVisualEffect.alpha = 0.4
- imageSelect.image = NCImageCache.shared.getImageCheckedYes()
+
+ imageVisualEffect.isHidden = false
+ imageVisualEffect.effect = nil
+ imageVisualEffect.alpha = 0
+ imageVisualEffect.isUserInteractionEnabled = false
+ imageVisualEffect.backgroundColor = UIColor.white.withAlphaComponent(0.2)
}
- func selected(_ status: Bool) {
- if status {
- imageSelect.isHidden = false
- imageVisualEffect.isHidden = false
- } else {
- imageSelect.isHidden = true
- imageVisualEffect.isHidden = true
- }
+ func selected(_ status: Bool, color: UIColor) {
+ imageVisualEffect.alpha = status ? 1 : 0
+ imageSelect.alpha = status ? 1 : 0
+ imageSelect.image = NCImageCache.shared.getImageCheckedYes(color: color)
}
}
diff --git a/iOSClient/Media/Cell/NCMediaCell.xib b/iOSClient/Media/Cell/NCMediaCell.xib
index 56d8a386e5..55163a7052 100644
--- a/iOSClient/Media/Cell/NCMediaCell.xib
+++ b/iOSClient/Media/Cell/NCMediaCell.xib
@@ -1,9 +1,8 @@
-
+
-
-
+
@@ -27,16 +26,15 @@
-
+
-
-
+
@@ -73,7 +71,7 @@
-
+
diff --git a/iOSClient/Media/NCMedia+CollectionViewDataSource.swift b/iOSClient/Media/NCMedia+CollectionViewDataSource.swift
index c6d951dbe4..1a051bbde3 100644
--- a/iOSClient/Media/NCMedia+CollectionViewDataSource.swift
+++ b/iOSClient/Media/NCMedia+CollectionViewDataSource.swift
@@ -75,9 +75,9 @@ extension NCMedia: UICollectionViewDataSource {
}
if isEditMode, fileSelect.contains(metadata.ocId) {
- cell.selected(true)
+ cell.selected(true, color: NCBrandColor.shared.getElement(account: session.account))
} else {
- cell.selected(false)
+ cell.selected(false, color: NCBrandColor.shared.getElement(account: session.account))
}
if cell.imageItem.image == nil {
diff --git a/iOSClient/Media/NCMedia+CollectionViewDelegate.swift b/iOSClient/Media/NCMedia+CollectionViewDelegate.swift
index b827bf0a65..fde3168ff7 100644
--- a/iOSClient/Media/NCMedia+CollectionViewDelegate.swift
+++ b/iOSClient/Media/NCMedia+CollectionViewDelegate.swift
@@ -15,10 +15,10 @@ extension NCMedia: UICollectionViewDelegate {
if isEditMode {
if let index = fileSelect.firstIndex(of: metadata.ocId) {
fileSelect.remove(at: index)
- cell.selected(false)
+ cell.selected(false, color: NCBrandColor.shared.getElement(account: session.account))
} else {
fileSelect.append(metadata.ocId)
- cell.selected(true)
+ cell.selected(true, color: NCBrandColor.shared.getElement(account: session.account))
}
tabBarSelect.selectCount = fileSelect.count
} else if let metadata = await self.database.getMetadataFromOcIdAsync(metadata.ocId) {
diff --git a/iOSClient/Media/NCMedia+Command.swift b/iOSClient/Media/NCMedia+Command.swift
index 28e70f9136..acc6596ba1 100644
--- a/iOSClient/Media/NCMedia+Command.swift
+++ b/iOSClient/Media/NCMedia+Command.swift
@@ -20,7 +20,7 @@ extension NCMedia {
if let visibleCells = collectionView?.indexPathsForVisibleItems.compactMap({ collectionView?.cellForItem(at: $0) }) {
for case let cell as NCMediaCell in visibleCells {
- cell.selected(false)
+ cell.selected(false, color: NCBrandColor.shared.getElement(account: session.account))
}
}
diff --git a/iOSClient/NCImageCache.swift b/iOSClient/NCImageCache.swift
index ee3512e750..1d11ba7057 100644
--- a/iOSClient/NCImageCache.swift
+++ b/iOSClient/NCImageCache.swift
@@ -185,12 +185,16 @@ final class NCImageCache: @unchecked Sendable {
return utility.loadImage(named: "checkmark.circle.fill", colors: colors)
}
- func getImageCheckedYes(colors: [UIColor] = [NCBrandColor.shared.iconImageColor2]) -> UIImage {
- return utility.loadImage(named: "checkmark.circle.fill", colors: colors)
+ func getImageCheckedYes(color: UIColor) -> UIImage? {
+ let config = UIImage.SymbolConfiguration(paletteColors: [.white, color])
+ return UIImage(systemName: "checkmark.circle.fill", withConfiguration: config)
}
- func getImageCheckedNo(colors: [UIColor] = [NCBrandColor.shared.iconImageColor]) -> UIImage {
- return utility.loadImage(named: "circle", colors: colors)
+ func getImageCheckedNo(color: UIColor) -> UIImage? {
+ let weightConfig = UIImage.SymbolConfiguration(weight: .light)
+ let colorConfig = UIImage.SymbolConfiguration(paletteColors: [color])
+ let config = weightConfig.applying(colorConfig)
+ return UIImage(systemName: "circle", withConfiguration: config)
}
func getImageButtonMore(colors: [UIColor] = [NCBrandColor.shared.iconImageColor]) -> UIImage {
diff --git a/iOSClient/Networking/E2EE/NCEndToEndMetadataV2.swift b/iOSClient/Networking/E2EE/NCEndToEndMetadataV2.swift
index 9b6d02f35e..638b2277aa 100644
--- a/iOSClient/Networking/E2EE/NCEndToEndMetadataV2.swift
+++ b/iOSClient/Networking/E2EE/NCEndToEndMetadataV2.swift
@@ -282,7 +282,7 @@ extension NCEndToEndMetadata {
let metadataKey = tableUser.metadataKey?.base64EncodedString(),
let decryptedMetadataKey = tableUser.metadataKey else {
return NKError(errorCode: NCGlobal.shared.errorE2EENoUserFound,
- errorDescription: NSLocalizedString("_e2ee_no_user_found_", comment: ""))
+ errorDescription: NSLocalizedString("_e2ee_no_metadataKey_found_", comment: ""))
}
// SIGNATURE CHECK
diff --git a/iOSClient/Share/NCShareLinkCell.swift b/iOSClient/Share/NCShareLinkCell.swift
index 2ec69b2b50..b1cf0a3495 100644
--- a/iOSClient/Share/NCShareLinkCell.swift
+++ b/iOSClient/Share/NCShareLinkCell.swift
@@ -114,7 +114,6 @@ class NCShareLinkCell: UITableViewCell {
labelQuickStatus.textColor = NCBrandColor.shared.customer
imageDownArrow.image = utility.loadImage(named: "arrowtriangle.down.circle", colors: [NCBrandColor.shared.customer])
- contentView.bringSubviewToFront(menuButton)
menuButton.menu = nil
menuButton.showsMenuAsPrimaryAction = true
}
diff --git a/iOSClient/Share/NCShareUserCell.swift b/iOSClient/Share/NCShareUserCell.swift
index 87e692ce31..023eba0edc 100644
--- a/iOSClient/Share/NCShareUserCell.swift
+++ b/iOSClient/Share/NCShareUserCell.swift
@@ -102,7 +102,6 @@ class NCShareUserCell: UITableViewCell {
stackViewQuickStatus.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(openQuickStatus)))
- contentView.bringSubviewToFront(buttonMenu)
buttonMenu.menu = nil
buttonMenu.showsMenuAsPrimaryAction = true
diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings
index 2c64b7e141..90cbf1c2f3 100644
--- a/iOSClient/Supporting Files/en.lproj/Localizable.strings
+++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings
@@ -776,6 +776,7 @@ You can stop it at any time, adjust the settings, and enable it again.";
"_e2ee_no_dir_" = "End-to-end encryption error, cannot get directory";
"_e2ee_no_certificate_" = "End-to-end encryption error, cannot get certificate";
"_e2ee_no_generate_key_" = "End-to-end encryption error, cannot generate key";
+"_e2ee_no_metadataKey_found_" = "End-to-end encryption error, cannot decrypt metadata key";
"_e2ee_no_user_found_" = "End-to-end encryption error, user not found";
"_e2ee_no_signature_found_" = "End-to-end encryption error, no signature found";
"_e2ee_counter_check_" = "End-to-end encryption error, the counter is lower than the previous one";
diff --git a/iOSClient/Trash/Cell/NCTrashCellProtocol.swift b/iOSClient/Trash/Cell/NCTrashCellProtocol.swift
index 61f5e78321..aee200246b 100644
--- a/iOSClient/Trash/Cell/NCTrashCellProtocol.swift
+++ b/iOSClient/Trash/Cell/NCTrashCellProtocol.swift
@@ -10,9 +10,9 @@ protocol NCTrashCellProtocol {
var labelExtension: UILabel! { get set }
var labelInfo: UILabel! { get set }
var imageItem: UIImageView! { get set }
- var account: String { get set }
+ var statusImg: UIImageView? { get set }
- func selected(_ status: Bool, isEditMode: Bool, account: String)
+ func selected(_ status: Bool, isEditMode: Bool, color: UIColor)
}
extension NCTrashCellProtocol where Self: UICollectionViewCell {
@@ -25,6 +25,9 @@ extension NCTrashCellProtocol where Self: UICollectionViewCell {
self.labelExtension?.textColor = NCBrandColor.shared.textColor
if self is NCTrashListCell {
self.labelInfo?.text = NCUtility().getRelativeDateTitle(tableTrash.trashbinDeletionTime as Date)
+ if tableTrash.livePhoto {
+ statusImg?.image = NCUtility().loadImage(named: "livephoto", colors: [NCBrandColor.shared.iconImageColor])
+ }
} else {
let dateFormatter = DateFormatter()
dateFormatter.dateStyle = .short
@@ -50,5 +53,13 @@ extension NCTrashCellProtocol where Self: UICollectionViewCell {
labelTitle.lineBreakMode = .byTruncatingTail
}
}
+
+ self.setIconOutlines()
+ }
+
+ func setIconOutlines() {
+ statusImg?.makeCircularBackground(
+ withColor: statusImg?.image != nil ? .systemBackground : .clear
+ )
}
}
diff --git a/iOSClient/Trash/Cell/NCTrashGridCell.swift b/iOSClient/Trash/Cell/NCTrashGridCell.swift
index e64671dd9c..cd68b288dc 100644
--- a/iOSClient/Trash/Cell/NCTrashGridCell.swift
+++ b/iOSClient/Trash/Cell/NCTrashGridCell.swift
@@ -20,9 +20,11 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol {
weak var delegate: NCTrashGridCellDelegate?
var objectId = ""
- var indexPath = IndexPath()
- var account = ""
- var user = ""
+
+ var statusImg: UIImageView? {
+ get { return nil }
+ set { imageItem = newValue }
+ }
override func awakeFromNib() {
super.awakeFromNib()
@@ -43,23 +45,11 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol {
imageItem.layer.cornerRadius = 6
imageItem.layer.masksToBounds = true
- imageVisualEffect.layer.cornerRadius = 6
- imageVisualEffect.clipsToBounds = true
- imageVisualEffect.alpha = 0.5
-
- labelTitle.text = ""
- labelExtension.text = ""
- labelExtension.isHidden = true
- labelInfo.text = ""
- labelSubinfo.text = ""
-
- if labelExtension.isHidden {
- labelTitle.numberOfLines = 2
- labelTitle.lineBreakMode = .byWordWrapping
- } else {
- labelTitle.numberOfLines = 1
- labelTitle.lineBreakMode = .byTruncatingTail
- }
+ imageVisualEffect.isHidden = false
+ imageVisualEffect.effect = nil
+ imageVisualEffect.alpha = 0
+ imageVisualEffect.isUserInteractionEnabled = false
+ imageVisualEffect.backgroundColor = UIColor.white.withAlphaComponent(0.2)
// Dynamic Type Font Configuration
//
@@ -87,17 +77,30 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol {
// adjustsFontForContentSizeCategory:
// Enables live updates when accessibility settings change.
//
+ labelTitle.text = ""
labelTitle.font = .callout()
labelTitle.adjustsFontForContentSizeCategory = true
+ labelExtension.text = ""
+ labelExtension.isHidden = true
labelExtension.font = .callout()
labelExtension.adjustsFontForContentSizeCategory = true
+ labelInfo.text = ""
labelInfo.font = .footnote()
labelInfo.adjustsFontForContentSizeCategory = true
+ labelSubinfo.text = ""
labelSubinfo.font = .footnote()
labelSubinfo.adjustsFontForContentSizeCategory = true
+
+ if labelExtension.isHidden {
+ labelTitle.numberOfLines = 2
+ labelTitle.lineBreakMode = .byWordWrapping
+ } else {
+ labelTitle.numberOfLines = 1
+ labelTitle.lineBreakMode = .byTruncatingTail
+ }
}
override func snapshotView(afterScreenUpdates afterUpdates: Bool) -> UIView? {
@@ -122,7 +125,7 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol {
setA11yActions()
}
- func selected(_ status: Bool, isEditMode: Bool, account: String) {
+ func selected(_ status: Bool, isEditMode: Bool, color: UIColor) {
if isEditMode {
buttonMore.isHidden = true
accessibilityCustomActions = nil
@@ -130,14 +133,10 @@ class NCTrashGridCell: UICollectionViewCell, NCTrashCellProtocol {
buttonMore.isHidden = false
setA11yActions()
}
- if status {
- imageSelect.image = NCImageCache.shared.getImageCheckedYes()
- imageSelect.isHidden = false
- imageVisualEffect.isHidden = false
- } else {
- imageSelect.isHidden = true
- imageVisualEffect.isHidden = true
- }
+
+ imageVisualEffect.alpha = status ? 1 : 0
+ imageSelect.alpha = status ? 1 : 0
+ imageSelect.image = NCImageCache.shared.getImageCheckedYes(color: color)
}
func writeInfoDateSize(date: NSDate, size: Int64) {
diff --git a/iOSClient/Trash/Cell/NCTrashGridCell.xib b/iOSClient/Trash/Cell/NCTrashGridCell.xib
index 347fc06c12..065039029b 100644
--- a/iOSClient/Trash/Cell/NCTrashGridCell.xib
+++ b/iOSClient/Trash/Cell/NCTrashGridCell.xib
@@ -3,14 +3,13 @@
-
-
+
@@ -18,24 +17,7 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
@@ -69,13 +51,6 @@
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
-
+
-
+
-
+
-
+
-
-
+
-
-
-
-
-
-
-
-
-
@@ -143,15 +121,11 @@
-
-
-
-
diff --git a/iOSClient/Trash/Cell/NCTrashListCell.swift b/iOSClient/Trash/Cell/NCTrashListCell.swift
index 37b60ae724..69229e3672 100644
--- a/iOSClient/Trash/Cell/NCTrashListCell.swift
+++ b/iOSClient/Trash/Cell/NCTrashListCell.swift
@@ -11,6 +11,7 @@ protocol NCTrashListCellDelegate: AnyObject {
class NCTrashListCell: UICollectionViewCell, NCTrashCellProtocol {
@IBOutlet weak var imageItem: UIImageView!
+ @IBOutlet weak var imageStatus: UIImageView!
@IBOutlet weak var imageItemLeftConstraint: NSLayoutConstraint!
@IBOutlet weak var imageSelect: UIImageView!
@IBOutlet weak var labelTitle: UILabel!
@@ -25,7 +26,11 @@ class NCTrashListCell: UICollectionViewCell, NCTrashCellProtocol {
weak var delegate: NCTrashListCellDelegate?
var objectId = ""
- var account = ""
+
+ var statusImg: UIImageView? {
+ get { return imageStatus }
+ set { imageStatus = newValue }
+ }
override func awakeFromNib() {
super.awakeFromNib()
@@ -52,14 +57,13 @@ class NCTrashListCell: UICollectionViewCell, NCTrashCellProtocol {
]
- labelExtension.text = ""
- labelExtension.isHidden = true
-
imageRestore.image = NCUtility().loadImage(named: "arrow.counterclockwise", colors: [NCBrandColor.shared.iconImageColor])
imageMore.image = NCUtility().loadImage(named: "trash", colors: [.red])
imageItem.layer.cornerRadius = 6
imageItem.layer.masksToBounds = true
+ imageStatus.image = nil
+
// These labels use fonts generated by the custom UIFont helpers defined in
// the UIFont extension (e.g. `.callout()`, `.caption1()`).
//
@@ -84,12 +88,16 @@ class NCTrashListCell: UICollectionViewCell, NCTrashCellProtocol {
// adjustsFontForContentSizeCategory:
// Enables live updates when accessibility settings change.
//
+ labelTitle.text = ""
labelTitle.font = .callout()
labelTitle.adjustsFontForContentSizeCategory = true
+ labelExtension.text = ""
+ labelExtension.isHidden = true
labelExtension.font = .callout()
labelExtension.adjustsFontForContentSizeCategory = true
+ labelInfo.text = ""
labelInfo.font = .footnote()
labelInfo.adjustsFontForContentSizeCategory = true
@@ -105,7 +113,7 @@ class NCTrashListCell: UICollectionViewCell, NCTrashCellProtocol {
delegate?.tapRestoreListItem(with: objectId, image: imageItem.image, sender: sender)
}
- func selected(_ status: Bool, isEditMode: Bool, account: String) {
+ func selected(_ status: Bool, isEditMode: Bool, color: UIColor) {
if isEditMode {
imageItemLeftConstraint.constant = 45
imageSelect.isHidden = false
@@ -128,14 +136,13 @@ class NCTrashListCell: UICollectionViewCell, NCTrashCellProtocol {
blurEffectView?.backgroundColor = .lightGray
blurEffectView?.frame = self.bounds
blurEffectView?.autoresizingMask = [.flexibleWidth, .flexibleHeight]
- imageSelect.image = NCImageCache.shared.getImageCheckedYes()
+ imageSelect.image = NCImageCache.shared.getImageCheckedYes(color: color)
backgroundView = blurEffectView
separator.isHidden = true
} else {
- imageSelect.image = NCImageCache.shared.getImageCheckedNo()
+ imageSelect.image = NCImageCache.shared.getImageCheckedNo(color: color)
backgroundView = nil
separator.isHidden = false
}
-
}
}
diff --git a/iOSClient/Trash/Cell/NCTrashListCell.xib b/iOSClient/Trash/Cell/NCTrashListCell.xib
index 1ce0ec16b9..1d9cb437ac 100644
--- a/iOSClient/Trash/Cell/NCTrashListCell.xib
+++ b/iOSClient/Trash/Cell/NCTrashListCell.xib
@@ -22,27 +22,34 @@
+
+
+
+
+
+
+
-
+
-
+