From a033db21e83334296db4ad308e90fa620edfa2ea Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Wed, 11 Feb 2026 18:31:20 +0100 Subject: [PATCH 1/8] prj Signed-off-by: Marino Faggiana --- Nextcloud.xcodeproj/project.pbxproj | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/Nextcloud.xcodeproj/project.pbxproj b/Nextcloud.xcodeproj/project.pbxproj index 02831e8684..7821d41ee7 100644 --- a/Nextcloud.xcodeproj/project.pbxproj +++ b/Nextcloud.xcodeproj/project.pbxproj @@ -568,7 +568,6 @@ F78026102E9CFA3700B63436 /* NCTransfersView.swift in Sources */ = {isa = PBXBuildFile; fileRef = F780260F2E9CF9DE00B63436 /* NCTransfersView.swift */; }; F78026122E9CFA6300B63436 /* NCTransfersModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F78026112E9CFA6000B63436 /* NCTransfersModel.swift */; }; F7802B322BD5584F00D74270 /* NCMedia+DragDrop.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7802B312BD5584F00D74270 /* NCMedia+DragDrop.swift */; }; - F7814E962F3B5F170074DA3A /* NCSVGRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7814E952F3B5F170074DA3A /* NCSVGRenderer.swift */; }; F7814E972F3B5F170074DA3A /* NCSVGRenderer.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7814E952F3B5F170074DA3A /* NCSVGRenderer.swift */; }; F7816EF22C2C3E1F00A52517 /* NCPushNotification.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7816EF12C2C3E1F00A52517 /* NCPushNotification.swift */; }; F7817CF829801A3500FFBC65 /* Data+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = F7817CF729801A3500FFBC65 /* Data+Extension.swift */; }; @@ -4243,7 +4242,6 @@ F799DF832C4B7DCC003410B5 /* NCSectionFooter.swift in Sources */, AF22B218277D196700DAB0CC /* NCShareExtension+Files.swift in Sources */, F799DF862C4B7E56003410B5 /* NCSectionHeader.swift in Sources */, - F7814E962F3B5F170074DA3A /* NCSVGRenderer.swift in Sources */, F702F2D025EE5B5C008F8E80 /* NCGlobal.swift in Sources */, F72437802C10B92400C7C68D /* NCSharePermissions.swift in Sources */, F7EDE4DB262D7BA200414FE6 /* NCCellProtocol.swift in Sources */, @@ -5749,7 +5747,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; DEBUG_INFORMATION_FORMAT = dwarf; DEVELOPMENT_TEAM = NKUJUXUJ3B; ENABLE_STRICT_OBJC_MSGSEND = YES; @@ -5815,7 +5813,7 @@ CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 3; + CURRENT_PROJECT_VERSION = 4; DEVELOPMENT_TEAM = NKUJUXUJ3B; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; From d901dbd6555b9849346a4ad20ca6fe68726c2688 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 12 Feb 2026 09:59:27 +0100 Subject: [PATCH 2/8] layout list search Signed-off-by: Marino Faggiana --- .../NCCollectionViewCommon+Search.swift | 12 +++++++++--- .../Collection Common/NCCollectionViewCommon.swift | 14 ++++++++++++-- 2 files changed, 21 insertions(+), 5 deletions(-) diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon+Search.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon+Search.swift index 24ce38a348..10a8c63438 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon+Search.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon+Search.swift @@ -17,14 +17,20 @@ extension NCCollectionViewCommon { } let capabilities = await NKCapabilities.shared.getCapabilities(for: session.account) - self.networkSearchInProgress = true + // Force layoutList + let layoutForView = database.getLayoutForView(account: session.account, key: layoutKey, serverUrl: serverUrl) + layoutForViewLayoutStore = layoutForView.layout + layoutForView.layout = self.global.layoutList + changeLayout(layoutForView: layoutForView) + // STOP PREEMPTIVE SYNC METADATA await self.stopSyncMetadata() // Clear datasotce - self.dataSource.removeAll() - self.collectionView.reloadData() + dataSource.removeAll() + collectionView.reloadData() // Start spinner setSearchBarLoading(true) + networkSearchInProgress = true if capabilities.serverVersionMajor >= global.nextcloudVersion20 { await unifiedSearch(text: text) diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index 8a20c4d6d6..3ba5d41774 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -36,12 +36,14 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, var richWorkspaceText: String? var sectionFirstHeader: NCSectionFirstHeader? var sectionFirstHeaderEmptyData: NCSectionFirstHeaderEmptyData? - var networkSearchInProgress: Bool = false + // Layout var layoutForView: NCDBLayoutForView? + var layoutForViewLayoutStore: String? var listLayout = NCListLayout() var gridLayout = NCGridLayout() var mediaLayout = NCMediaLayout() var layoutType = NCGlobal.shared.layoutList + var tabBarSelect: NCCollectionViewCommonSelectTabBar? var attributesZoomIn: UIMenuElement.Attributes = [] var attributesZoomOut: UIMenuElement.Attributes = [] @@ -49,6 +51,7 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, var syncMetadatasTask: Task? // Search var isSearchingMode: Bool = false + var networkSearchInProgress: Bool = false var searchOperationHandle = NKOperationHandle() var searchTask: URLSessionTask? var searchResultText: String? @@ -532,7 +535,7 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, } func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { - // + // (+) mainNavigationController?.hiddenPlusButton(false) self.isSearchingMode = false @@ -544,6 +547,13 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, await searchOperationHandle.cancel() self.dataSource.removeAll() await self.reloadDataSource() + + // Restore Layout + if let layoutForViewLayoutStore { + let layoutForView = database.getLayoutForView(account: session.account, key: layoutKey, serverUrl: serverUrl) + layoutForView.layout = layoutForViewLayoutStore + changeLayout(layoutForView: layoutForView) + } } } From e8cd6d32ed3ff0802f5dffe61d3e62dd85bbe35a Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 12 Feb 2026 11:05:17 +0100 Subject: [PATCH 3/8] code Signed-off-by: Marino Faggiana --- .../NCCollectionViewCommon.swift | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index 3ba5d41774..420440c284 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -185,11 +185,7 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, searchBar?.autocapitalizationType = .none searchBar?.backgroundImage = UIImage() - let textField = searchController?.searchBar.searchTextField - textField?.backgroundColor = .systemGray.withAlphaComponent(0.30) - textField?.borderStyle = .none - textField?.layer.cornerRadius = 20 - textField?.clipsToBounds = true + updateSearchFieldAppearance() navigationItem.searchController = searchController navigationItem.hidesSearchBarWhenScrolling = false @@ -247,7 +243,6 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, registerForTraitChanges([UITraitUserInterfaceStyle.self]) { [weak self] (view: NCCollectionViewCommon, _) in guard let self else { return } - sectionFirstHeader?.setRichWorkspaceColor(style: view.traitCollection.userInterfaceStyle) } @@ -359,22 +354,12 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, removeImageCache(metadatas: self.dataSource.getMetadatas()) } - func presentationControllerDidDismiss( _ presentationController: UIPresentationController) { - let viewController = presentationController.presentedViewController - - if viewController is NCViewerRichWorkspaceWebView { - closeRichWorkspaceWebView() - } - } - override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) { super.viewWillTransition(to: size, with: coordinator) coordinator.animate(alongsideTransition: { _ in - let animator = UIViewPropertyAnimator(duration: 0.3, curve: .easeInOut) { - self.collectionView?.collectionViewLayout.invalidateLayout() - } - animator.startAnimation() + self.updateSearchFieldAppearance() + self.collectionView?.collectionViewLayout.invalidateLayout() }) self.dismissTip() @@ -384,6 +369,28 @@ class NCCollectionViewCommon: UIViewController, NCAccountSettingsModelDelegate, return true } + private func updateSearchFieldAppearance() { + let textField = searchController?.searchBar.searchTextField + + if traitCollection.horizontalSizeClass == .regular { + textField?.backgroundColor = nil + textField?.layer.cornerRadius = 0 + } else { + textField?.backgroundColor = UIColor.systemGray.withAlphaComponent(0.30) + textField?.borderStyle = .none + textField?.layer.cornerRadius = 20 + textField?.clipsToBounds = true + } + } + + func presentationControllerDidDismiss( _ presentationController: UIPresentationController) { + let viewController = presentationController.presentedViewController + + if viewController is NCViewerRichWorkspaceWebView { + closeRichWorkspaceWebView() + } + } + // MARK: - NotificationCenter @objc func applicationWillResignActive(_ notification: NSNotification) { From aa4045a51a59961927b3f1e577ebbf3ab9453064 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 12 Feb 2026 11:42:29 +0100 Subject: [PATCH 4/8] fix widget Signed-off-by: Marino Faggiana --- Widget/Dashboard/DashboardData.swift | 30 ++++++++++---------- Widget/Dashboard/DashboardWidgetView.swift | 6 ++-- Widget/Files/FilesWidgetView.swift | 2 +- Widget/Lockscreen/LockscreenWidgetView.swift | 11 +++---- Widget/Toolbar/ToolbarWidgetView.swift | 2 +- 5 files changed, 24 insertions(+), 27 deletions(-) diff --git a/Widget/Dashboard/DashboardData.swift b/Widget/Dashboard/DashboardData.swift index ccc9b5bf1e..4692042a49 100644 --- a/Widget/Dashboard/DashboardData.swift +++ b/Widget/Dashboard/DashboardData.swift @@ -28,21 +28,21 @@ struct DashboardData: Identifiable, Hashable { let subTitle: String let link: URL let icon: UIImage - let avatar: Bool + let circle: Bool let imageColor: UIColor? } let dashboardDatasTest: [DashboardData] = [ - .init(id: 0, title: "title0", subTitle: "subTitle-description0", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, avatar: false, imageColor: nil), - .init(id: 1, title: "title1", subTitle: "subTitle-description1", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, avatar: false, imageColor: nil), - .init(id: 2, title: "title2", subTitle: "subTitle-description2", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, avatar: false, imageColor: nil), - .init(id: 3, title: "title3", subTitle: "subTitle-description3", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, avatar: false, imageColor: nil), - .init(id: 4, title: "title4", subTitle: "subTitle-description4", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, avatar: false, imageColor: nil), - .init(id: 5, title: "title5", subTitle: "subTitle-description5", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, avatar: false, imageColor: nil), - .init(id: 6, title: "title6", subTitle: "subTitle-description6", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, avatar: false, imageColor: nil), - .init(id: 7, title: "title7", subTitle: "subTitle-description7", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, avatar: false, imageColor: nil), - .init(id: 8, title: "title8", subTitle: "subTitle-description8", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, avatar: false, imageColor: nil), - .init(id: 9, title: "title9", subTitle: "subTitle-description9", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, avatar: false, imageColor: nil) + .init(id: 0, title: "title0", subTitle: "subTitle-description0", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "document")!, circle: false, imageColor: nil), + .init(id: 1, title: "title1", subTitle: "subTitle-description1", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "document")!, circle: false, imageColor: nil), + .init(id: 2, title: "title2", subTitle: "subTitle-description2", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "document")!, circle: false, imageColor: nil), + .init(id: 3, title: "title3", subTitle: "subTitle-description3", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "document")!, circle: false, imageColor: nil), + .init(id: 4, title: "title4", subTitle: "subTitle-description4", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageColor: nil), + .init(id: 5, title: "title5", subTitle: "subTitle-description5", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageColor: nil), + .init(id: 6, title: "title6", subTitle: "subTitle-description6", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageColor: nil), + .init(id: 7, title: "title7", subTitle: "subTitle-description7", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageColor: nil), + .init(id: 8, title: "title8", subTitle: "subTitle-description8", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageColor: nil), + .init(id: 9, title: "title9", subTitle: "subTitle-description9", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageColor: nil) ] func getDashboardItems(displaySize: CGSize, withButton: Bool) -> Int { @@ -140,9 +140,9 @@ func getDashboardDataEntry(configuration: DashboardIntent?, isPreview: Bool, dis let url = URL(string: entryLink) { link = url } - var iconImage = UIImage(systemName: "circle.fill") ?? UIImage() + var iconImage = UIImage(systemName: "document") ?? UIImage() - var imageAvatar: Bool = false + var imageCircle: Bool = false var imageColorized: Bool = false var imageColor: UIColor? @@ -152,7 +152,7 @@ func getDashboardDataEntry(configuration: DashboardIntent?, isPreview: Bool, dis let pathComponents = path.components(separatedBy: "/") if pathComponents.contains("avatar") { - imageAvatar = true + imageCircle = true } else if pathComponents.contains("getCalendarDotSvg") { imageColorized = true } @@ -178,7 +178,7 @@ func getDashboardDataEntry(configuration: DashboardIntent?, isPreview: Bool, dis } } - let data = DashboardData(id: counter, title: title, subTitle: subtitle, link: link, icon: iconImage, avatar: imageAvatar, imageColor: imageColor) + let data = DashboardData(id: counter, title: title, subTitle: subtitle, link: link, icon: iconImage, circle: imageCircle, imageColor: imageColor) datas.append(data) if datas.count == dashboardItems { break } diff --git a/Widget/Dashboard/DashboardWidgetView.swift b/Widget/Dashboard/DashboardWidgetView.swift index 61eb4138be..63ff627db6 100644 --- a/Widget/Dashboard/DashboardWidgetView.swift +++ b/Widget/Dashboard/DashboardWidgetView.swift @@ -60,7 +60,7 @@ struct DashboardWidgetView: View { .frame(width: 20, height: 20) .foregroundColor(Color(color)) } else { - if entry.dashboard?.itemIconsRound ?? false || element.avatar { + if entry.dashboard?.itemIconsRound ?? false || element.circle { Image(uiImage: element.icon) .resizable() .scaledToFill() @@ -137,7 +137,7 @@ struct DashboardWidgetView: View { .foregroundColor(entry.isPlaceholder ? Color(.systemGray4) : Color(NCBrandColor.shared.getElement(account: entry.account))) } .padding(.horizontal, 15.0) - .frame(maxWidth: geo.size.width, maxHeight: geo.size.height - 2, alignment: .bottomTrailing) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom) } } .containerBackground(.background, for: .widget) @@ -149,7 +149,7 @@ struct DashboardWidget_Previews: PreviewProvider { let datas = Array(dashboardDatasTest[0...4]) let title = "Dashboard" let titleImage = UIImage(systemName: "circle.fill")! - let entry = DashboardDataEntry(date: Date(), datas: datas, dashboard: nil, buttons: nil, isPlaceholder: false, isEmpty: true, titleImage: titleImage, title: title, footerImage: "checkmark.icloud", footerText: NCBrandOptions.shared.brand + " widget", account: "") + let entry = DashboardDataEntry(date: Date(), datas: datas, dashboard: nil, buttons: nil, isPlaceholder: false, isEmpty: false, titleImage: titleImage, title: title, footerImage: "checkmark.icloud", footerText: NCBrandOptions.shared.brand + " widget", account: "") DashboardWidgetView(entry: entry).previewContext(WidgetPreviewContext(family: .systemLarge)) } } diff --git a/Widget/Files/FilesWidgetView.swift b/Widget/Files/FilesWidgetView.swift index 029624fde3..770d90766a 100644 --- a/Widget/Files/FilesWidgetView.swift +++ b/Widget/Files/FilesWidgetView.swift @@ -170,7 +170,7 @@ struct FilesWidgetView: View { .lineLimit(1) .foregroundColor(entry.isPlaceholder ? Color(.systemGray4) : Color(NCBrandColor.shared.getElement(account: entry.account))) } - .frame(maxWidth: geo.size.width, maxHeight: geo.size.height, alignment: .bottomTrailing) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom) } } .containerBackground(.background, for: .widget) diff --git a/Widget/Lockscreen/LockscreenWidgetView.swift b/Widget/Lockscreen/LockscreenWidgetView.swift index 661ef51487..a013844ab7 100644 --- a/Widget/Lockscreen/LockscreenWidgetView.swift +++ b/Widget/Lockscreen/LockscreenWidgetView.swift @@ -6,7 +6,6 @@ import SwiftUI import WidgetKit struct LockscreenWidgetView: View { - let entry: LockscreenData @Environment(\.widgetFamily) private var family @@ -23,7 +22,7 @@ struct LockscreenWidgetView: View { } ) .gaugeStyle(.accessoryCircularCapacity) - .widgetBackground(Color.clear) + .containerBackground(.clear, for: .widget) } else { Gauge( value: entry.quotaRelative, @@ -37,21 +36,19 @@ struct LockscreenWidgetView: View { ) .gaugeStyle(.accessoryCircular) .redacted(reason: entry.isPlaceholder ? .placeholder : []) - .widgetBackground(Color.clear) + .containerBackground(.clear, for: .widget) } case .accessoryRectangular: VStack(alignment: .leading, spacing: 1) { HStack(spacing: 1) { - Image("activity") + Image(systemName: "bolt.fill") .renderingMode(.template) .resizable() .scaledToFill() - .foregroundColor(Color(NCBrandColor.shared.textColor2)) .frame(width: 11, height: 11) Text(NSLocalizedString("_recent_activity_", comment: "")) .font(.system(size: 11)) .fontWeight(.heavy) - .foregroundColor(Color(NCBrandColor.shared.textColor2)) } if entry.error { VStack(spacing: 1) { @@ -66,7 +63,7 @@ struct LockscreenWidgetView: View { } .widgetURL(entry.link) .redacted(reason: entry.isPlaceholder ? .placeholder : []) - .widgetBackground(Color.clear) + .containerBackground(.clear, for: .widget) default: Text("Not implemented") } diff --git a/Widget/Toolbar/ToolbarWidgetView.swift b/Widget/Toolbar/ToolbarWidgetView.swift index a2d903e168..dd43fb0756 100644 --- a/Widget/Toolbar/ToolbarWidgetView.swift +++ b/Widget/Toolbar/ToolbarWidgetView.swift @@ -93,7 +93,7 @@ struct ToolbarWidgetView: View { .padding(.trailing, 13.0) .foregroundColor(entry.isPlaceholder ? Color(.systemGray4) : Color(NCBrandColor.shared.getElement(account: entry.account))) } - .frame(maxWidth: geo.size.width - 5, maxHeight: geo.size.height - 2, alignment: .bottomTrailing) + .frame(maxWidth: .infinity, maxHeight: .infinity, alignment: .bottom) } } } From a5fbde32ebc1ea0e91b2818c65ed0bc0be7b1232 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 12 Feb 2026 12:10:53 +0100 Subject: [PATCH 5/8] widget Signed-off-by: Marino Faggiana --- Widget/Dashboard/DashboardData.swift | 27 ++++++++++++---------- Widget/Dashboard/DashboardWidgetView.swift | 8 ++++++- 2 files changed, 22 insertions(+), 13 deletions(-) diff --git a/Widget/Dashboard/DashboardData.swift b/Widget/Dashboard/DashboardData.swift index 4692042a49..d5061fb403 100644 --- a/Widget/Dashboard/DashboardData.swift +++ b/Widget/Dashboard/DashboardData.swift @@ -29,20 +29,21 @@ struct DashboardData: Identifiable, Hashable { let link: URL let icon: UIImage let circle: Bool + let imageSystem: Bool let imageColor: UIColor? } let dashboardDatasTest: [DashboardData] = [ - .init(id: 0, title: "title0", subTitle: "subTitle-description0", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "document")!, circle: false, imageColor: nil), - .init(id: 1, title: "title1", subTitle: "subTitle-description1", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "document")!, circle: false, imageColor: nil), - .init(id: 2, title: "title2", subTitle: "subTitle-description2", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "document")!, circle: false, imageColor: nil), - .init(id: 3, title: "title3", subTitle: "subTitle-description3", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "document")!, circle: false, imageColor: nil), - .init(id: 4, title: "title4", subTitle: "subTitle-description4", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageColor: nil), - .init(id: 5, title: "title5", subTitle: "subTitle-description5", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageColor: nil), - .init(id: 6, title: "title6", subTitle: "subTitle-description6", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageColor: nil), - .init(id: 7, title: "title7", subTitle: "subTitle-description7", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageColor: nil), - .init(id: 8, title: "title8", subTitle: "subTitle-description8", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageColor: nil), - .init(id: 9, title: "title9", subTitle: "subTitle-description9", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageColor: nil) + .init(id: 0, title: "title0", subTitle: "subTitle-description0", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "document")!, circle: false, imageSystem: true, imageColor: nil), + .init(id: 1, title: "title1", subTitle: "subTitle-description1", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "document")!, circle: false, imageSystem: true, imageColor: nil), + .init(id: 2, title: "title2", subTitle: "subTitle-description2", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "document")!, circle: true, imageSystem: false, imageColor: nil), + .init(id: 3, title: "title3", subTitle: "subTitle-description3", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "document")!, circle: false, imageSystem: false, imageColor: nil), + .init(id: 4, title: "title4", subTitle: "subTitle-description4", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageSystem: false, imageColor: nil), + .init(id: 5, title: "title5", subTitle: "subTitle-description5", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageSystem: false, imageColor: nil), + .init(id: 6, title: "title6", subTitle: "subTitle-description6", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageSystem: false, imageColor: nil), + .init(id: 7, title: "title7", subTitle: "subTitle-description7", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageSystem: false, imageColor: nil), + .init(id: 8, title: "title8", subTitle: "subTitle-description8", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageSystem: false, imageColor: nil), + .init(id: 9, title: "title9", subTitle: "subTitle-description9", link: URL(string: "https://nextcloud.com/")!, icon: UIImage(systemName: "circle.fill")!, circle: false, imageSystem: false, imageColor: nil) ] func getDashboardItems(displaySize: CGSize, withButton: Bool) -> Int { @@ -141,9 +142,9 @@ func getDashboardDataEntry(configuration: DashboardIntent?, isPreview: Bool, dis link = url } var iconImage = UIImage(systemName: "document") ?? UIImage() - var imageCircle: Bool = false var imageColorized: Bool = false + var imageSystem: Bool = false var imageColor: UIColor? if let iconUrl = item.iconUrl, let url = URL(string: iconUrl) { @@ -168,6 +169,8 @@ func getDashboardDataEntry(configuration: DashboardIntent?, isPreview: Bool, dis let data = results.responseData?.data { if let image = UIImage(data: data) { iconImage = image + } else { + imageSystem = true } /* NO MEMORY else if let image = try? await NCSVGRenderer().renderSVGToUIImage(svgData: data) { @@ -178,7 +181,7 @@ func getDashboardDataEntry(configuration: DashboardIntent?, isPreview: Bool, dis } } - let data = DashboardData(id: counter, title: title, subTitle: subtitle, link: link, icon: iconImage, circle: imageCircle, imageColor: imageColor) + let data = DashboardData(id: counter, title: title, subTitle: subtitle, link: link, icon: iconImage, circle: imageCircle, imageSystem: imageSystem, imageColor: imageColor) datas.append(data) if datas.count == dashboardItems { break } diff --git a/Widget/Dashboard/DashboardWidgetView.swift b/Widget/Dashboard/DashboardWidgetView.swift index 63ff627db6..5268455592 100644 --- a/Widget/Dashboard/DashboardWidgetView.swift +++ b/Widget/Dashboard/DashboardWidgetView.swift @@ -57,8 +57,14 @@ struct DashboardWidgetView: View { Image(uiImage: element.icon) .renderingMode(.template) .resizable() - .frame(width: 20, height: 20) + .frame(width: 35, height: 35) .foregroundColor(Color(color)) + } else if element.imageSystem { + Image(uiImage: element.icon) + .resizable() + .scaledToFit() + .frame(width: 35, height: 35) + .scaleEffect(0.8) } else { if entry.dashboard?.itemIconsRound ?? false || element.circle { Image(uiImage: element.icon) From 90f37aa6b93c347bffea167d35fb6decf57efd16 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 12 Feb 2026 12:19:04 +0100 Subject: [PATCH 6/8] code Signed-off-by: Marino Faggiana --- Widget/Dashboard/DashboardData.swift | 1 + Widget/Dashboard/DashboardWidgetView.swift | 1 + 2 files changed, 2 insertions(+) diff --git a/Widget/Dashboard/DashboardData.swift b/Widget/Dashboard/DashboardData.swift index d5061fb403..b16f2d9953 100644 --- a/Widget/Dashboard/DashboardData.swift +++ b/Widget/Dashboard/DashboardData.swift @@ -163,6 +163,7 @@ func getDashboardDataEntry(configuration: DashboardIntent?, isPreview: Bool, dis let path = (urlComponents.path as NSString) let colorString = ((path.lastPathComponent) as NSString).deletingPathExtension imageColor = UIColor(hex: colorString) + iconImage = UIImage(systemName: "circle.fill") ?? UIImage() } else { let results = await NextcloudKit.shared.downloadPreviewAsync(url: url, account: activeTableAccount.account) if results.error == .success, diff --git a/Widget/Dashboard/DashboardWidgetView.swift b/Widget/Dashboard/DashboardWidgetView.swift index 5268455592..3ae749bdd9 100644 --- a/Widget/Dashboard/DashboardWidgetView.swift +++ b/Widget/Dashboard/DashboardWidgetView.swift @@ -59,6 +59,7 @@ struct DashboardWidgetView: View { .resizable() .frame(width: 35, height: 35) .foregroundColor(Color(color)) + .scaleEffect(0.8) } else if element.imageSystem { Image(uiImage: element.icon) .resizable() From 39c2ae443e999ca2cca61c916d07cd89d11f9f1c Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 12 Feb 2026 14:52:41 +0100 Subject: [PATCH 7/8] fix open-file Signed-off-by: Marino Faggiana --- Widget/Files/FilesData.swift | 3 +- iOSClient/Files/NCFiles.swift | 25 +++-- ...ionViewCommon+CollectionViewDelegate.swift | 97 +++++++++---------- .../NCCollectionViewCommon.swift | 4 +- iOSClient/Menu/NCViewerContextMenu.swift | 9 +- .../NCNetworking+TransferDelegate.swift | 67 +++++++------ iOSClient/SceneDelegate.swift | 44 ++++----- .../en.lproj/Localizable.strings | 2 +- 8 files changed, 124 insertions(+), 127 deletions(-) diff --git a/Widget/Files/FilesData.swift b/Widget/Files/FilesData.swift index 12a31755bb..78d8ecbaf4 100644 --- a/Widget/Files/FilesData.swift +++ b/Widget/Files/FilesData.swift @@ -186,9 +186,8 @@ func getFilesDataEntry(configuration: AccountIntent?, isPreview: Bool, displaySi // URL: nextcloud://open-file?path=Talk/IMG_0000123.jpg&user=marinofaggiana&link=https://cloud.nextcloud.com/f/123 guard var path = utilityFileSystem.getPath(path: file.path, user: file.user, fileName: file.fileName).urlEncoded else { continue } if path.first == "/" { path = String(path.dropFirst())} - guard let user = file.user.urlEncoded else { continue } let link = file.urlBase + "/f/" + file.fileId - let urlString = "nextcloud://open-file?path=\(path)&user=\(user)&link=\(link)" + let urlString = "nextcloud://open-file?path=\(path)&user=\(file.userId)&link=\(link)&account=\(file.account)" guard let url = URL(string: urlString) else { continue } // IMAGE diff --git a/iOSClient/Files/NCFiles.swift b/iOSClient/Files/NCFiles.swift index c712f876b6..4b9fc5b05d 100644 --- a/iOSClient/Files/NCFiles.swift +++ b/iOSClient/Files/NCFiles.swift @@ -9,7 +9,7 @@ import SwiftUI class NCFiles: NCCollectionViewCommon { internal var fileNameBlink: String? - internal var fileNameOpen: String? + internal var openMetadata: tableMetadata? internal var lastOffsetY: CGFloat = 0 internal var lastScrollTime: TimeInterval = 0 @@ -110,13 +110,13 @@ class NCFiles: NCCollectionViewCommon { super.viewDidAppear(animated) if !self.dataSource.isEmpty() { - self.blinkCell(fileName: self.fileNameBlink) - self.openFile(fileName: self.fileNameOpen) - self.fileNameBlink = nil - self.fileNameOpen = nil + blinkCell(fileName: self.fileNameBlink) + fileNameBlink = nil } Task { + // Automatically open + await open(metadata: self.openMetadata) // Plus Menu reload let capabilities = await database.getCapabilities(account: self.session.account) ?? NKCapabilities.Capabilities() await mainNavigationController?.createPlusMenu(session: self.session, capabilities: capabilities) @@ -140,7 +140,7 @@ class NCFiles: NCCollectionViewCommon { super.viewDidDisappear(animated) fileNameBlink = nil - fileNameOpen = nil + openMetadata = nil } // MARK: - DataSource @@ -380,15 +380,12 @@ class NCFiles: NCCollectionViewCommon { } } - func openFile(fileName: String?) { - if let fileName = fileName, let metadata = database.getMetadata(predicate: NSPredicate(format: "account == %@ AND serverUrl == %@ AND fileName == %@", session.account, self.serverUrl, fileName)) { - let indexPath = self.dataSource.getIndexPathMetadata(ocId: metadata.ocId) - if let indexPath = indexPath { - DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { - self.collectionView(self.collectionView, didSelectItemAt: indexPath) - } - } + func open(metadata: tableMetadata?) async { + guard let metadata else { + return } + await didSelectMetadata(metadata, withOcIds: false) + self.openMetadata = nil } // MARK: - NCAccountSettingsModelDelegate diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegate.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegate.swift index f2d6cd59cf..abb7b406ec 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegate.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon+CollectionViewDelegate.swift @@ -9,8 +9,9 @@ import Alamofire import LucidBanner extension NCCollectionViewCommon: UICollectionViewDelegate { - func didSelectMetadata(_ metadata: tableMetadata, withOcIds: Bool) { - let capabilities = NCNetworking.shared.capabilities[session.account] ?? NKCapabilities.Capabilities() + @MainActor + func didSelectMetadata(_ metadata: tableMetadata, withOcIds: Bool) async { + let capabilities = await NKCapabilities.shared.getCapabilities(for: session.account) if metadata.e2eEncrypted { if capabilities.e2EEEnabled { if !NCPreferences().isEndToEndEnabled(account: metadata.account) { @@ -20,9 +21,7 @@ extension NCCollectionViewCommon: UICollectionViewDelegate { return } } else { - Task { - await showInfoBanner(controller: self.controller, text: "_e2e_server_disabled_") - } + await showInfoBanner(controller: self.controller, text: "_e2e_server_disabled_") return } } @@ -72,55 +71,51 @@ extension NCCollectionViewCommon: UICollectionViewDelegate { if metadata.directory { pushMetadata(metadata) } else { - Task { @MainActor in - let image = utility.getImage(ocId: metadata.ocId, etag: metadata.etag, ext: self.global.previewExt1024, userId: metadata.userId, urlBase: metadata.urlBase) - let fileExists = utilityFileSystem.fileProviderStorageExists(metadata) - - // --- E2EE ------- - if metadata.isDirectoryE2EE { - if fileExists { - if let vc = await NCViewer().getViewerController(metadata: metadata, delegate: self) { - self.navigationController?.pushViewController(vc, animated: true) - } - } else { - await downloadFile() + let image = utility.getImage(ocId: metadata.ocId, etag: metadata.etag, ext: self.global.previewExt1024, userId: metadata.userId, urlBase: metadata.urlBase) + let fileExists = utilityFileSystem.fileProviderStorageExists(metadata) + + // --- E2EE ------- + if metadata.isDirectoryE2EE { + if fileExists { + if let vc = await NCViewer().getViewerController(metadata: metadata, delegate: self) { + self.navigationController?.pushViewController(vc, animated: true) } - return + } else { + await downloadFile() } - // --------------- + return + } + // --------------- - if metadata.isImage || metadata.isAudioOrVideo { - let metadatas = self.dataSource.getMetadatas() - let ocIds = metadatas.filter { $0.classFile == NKTypeClassFile.image.rawValue || - $0.classFile == NKTypeClassFile.video.rawValue || - $0.classFile == NKTypeClassFile.audio.rawValue }.map(\.ocId) + if metadata.isImage || metadata.isAudioOrVideo { + let metadatas = self.dataSource.getMetadatas() + let ocIds = metadatas.filter { $0.classFile == NKTypeClassFile.image.rawValue || + $0.classFile == NKTypeClassFile.video.rawValue || + $0.classFile == NKTypeClassFile.audio.rawValue }.map(\.ocId) - if let vc = await NCViewer().getViewerController(metadata: metadata, ocIds: withOcIds ? ocIds : nil, image: image, delegate: self) { - self.navigationController?.pushViewController(vc, animated: true) - } - } else if !metadata.isDirectoryE2EE, metadata.isAvailableEditorView || utilityFileSystem.fileProviderStorageExists(metadata) || metadata.name == self.global.talkName { - if let vc = await NCViewer().getViewerController(metadata: metadata, image: image, delegate: self) { - self.navigationController?.pushViewController(vc, animated: true) - } - } else if NextcloudKit.shared.isNetworkReachable() { - guard let metadata = await database.setMetadataSessionInWaitDownloadAsync(ocId: metadata.ocId, - session: self.networking.sessionDownload, - selector: global.selectorLoadFileView, - sceneIdentifier: self.controller?.sceneIdentifier) else { - return - } + if let vc = await NCViewer().getViewerController(metadata: metadata, ocIds: withOcIds ? ocIds : nil, image: image, delegate: self) { + self.navigationController?.pushViewController(vc, animated: true) + } + } else if !metadata.isDirectoryE2EE, metadata.isAvailableEditorView || utilityFileSystem.fileProviderStorageExists(metadata) || metadata.name == self.global.talkName { + if let vc = await NCViewer().getViewerController(metadata: metadata, image: image, delegate: self) { + self.navigationController?.pushViewController(vc, animated: true) + } + } else if NextcloudKit.shared.isNetworkReachable() { + guard let metadata = await database.setMetadataSessionInWaitDownloadAsync(ocId: metadata.ocId, + session: self.networking.sessionDownload, + selector: global.selectorLoadFileView, + sceneIdentifier: self.controller?.sceneIdentifier) else { + return + } - if metadata.name == "files" { - await downloadFile() - } else if !metadata.url.isEmpty, - let vc = await NCViewer().getViewerController(metadata: metadata, delegate: self) { - self.navigationController?.pushViewController(vc, animated: true) - } - } else { - Task { - await showErrorBanner(controller: controller, text: "_go_online_", errorCode: NCGlobal.shared.errorOffline) - } + if metadata.name == "files" { + await downloadFile() + } else if !metadata.url.isEmpty, + let vc = await NCViewer().getViewerController(metadata: metadata, delegate: self) { + self.navigationController?.pushViewController(vc, animated: true) } + } else { + await showErrorBanner(controller: controller, text: "_go_online_", errorCode: NCGlobal.shared.errorOffline) } } } @@ -138,13 +133,13 @@ extension NCCollectionViewCommon: UICollectionViewDelegate { } self.collectionView.reloadItems(at: [indexPath]) self.tabBarSelect?.update(fileSelect: self.fileSelect, metadatas: self.getSelectedMetadatas(), userId: metadata.userId) - // self.collectionView.reloadSections(IndexSet(integer: indexPath.section)) - self.collectionView.collectionViewLayout.invalidateLayout() return } - self.didSelectMetadata(metadata, withOcIds: true) + Task { + await didSelectMetadata(metadata, withOcIds: true) + } } func collectionView(_ collectionView: UICollectionView, contextMenuConfigurationForItemAt indexPath: IndexPath, point: CGPoint) -> UIContextMenuConfiguration? { diff --git a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift index 420440c284..51fdabae6f 100644 --- a/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift +++ b/iOSClient/Main/Collection Common/NCCollectionViewCommon.swift @@ -847,7 +847,9 @@ extension NCCollectionViewCommon: NCSectionFirstHeaderDelegate { } func tapRecommendations(with metadata: tableMetadata) { - didSelectMetadata(metadata, withOcIds: false) + Task { + await didSelectMetadata(metadata, withOcIds: false) + } } } diff --git a/iOSClient/Menu/NCViewerContextMenu.swift b/iOSClient/Menu/NCViewerContextMenu.swift index 05a089eaee..f21bb47a9b 100644 --- a/iOSClient/Menu/NCViewerContextMenu.swift +++ b/iOSClient/Menu/NCViewerContextMenu.swift @@ -90,10 +90,11 @@ class NCViewerContextMenu: NSObject { title: NSLocalizedString("_view_in_folder_", comment: ""), image: UIImage(systemName: "questionmark.folder") ) { _ in - NCNetworking.shared.openFileViewInFolder(serverUrl: metadata.serverUrl, - fileNameBlink: metadata.fileName, - fileNameOpen: nil, - sceneIdentifier: controller.sceneIdentifier) + Task { + await NCNetworking.shared.openFileViewInFolder(serverUrl: metadata.serverUrl, + fileNameBlink: metadata.fileName, + sceneIdentifier: controller.sceneIdentifier) + } } } diff --git a/iOSClient/Networking/NCNetworking+TransferDelegate.swift b/iOSClient/Networking/NCNetworking+TransferDelegate.swift index 16e7b07e30..bd9b845273 100644 --- a/iOSClient/Networking/NCNetworking+TransferDelegate.swift +++ b/iOSClient/Networking/NCNetworking+TransferDelegate.swift @@ -286,54 +286,57 @@ extension NCNetworking: NCTransferDelegate { // MARK: - - func openFileViewInFolder(serverUrl: String, fileNameBlink: String?, fileNameOpen: String?, sceneIdentifier: String) { + @MainActor + func openFileViewInFolder(serverUrl: String, + fileNameBlink: String? = nil, + metadata: tableMetadata? = nil, + sceneIdentifier: String) async { 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 { + navigationController.popToRootViewController(animated: false) + controller.selectedIndex = 0 + if serverUrlPush == serverUrl, + let viewController = navigationController.topViewController as? NCFiles { + Task { viewController.blinkCell(fileName: fileNameBlink) - viewController.openFile(fileName: fileNameOpen) - return + await viewController.open(metadata: metadata) } + return + } - let diffDirectory = serverUrl.replacingOccurrences(of: serverUrlPush, with: "") - var subDirs = diffDirectory.split(separator: "/") - - while serverUrlPush != serverUrl, !subDirs.isEmpty { + let diffDirectory = serverUrl.replacingOccurrences(of: serverUrlPush, with: "") + var subDirs = diffDirectory.split(separator: "/") - guard let dir = subDirs.first else { - return - } - serverUrlPush = self.utilityFileSystem.createServerUrl(serverUrl: serverUrlPush, fileName: String(dir)) + while serverUrlPush != serverUrl, !subDirs.isEmpty { + 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 - 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 + if let viewController = controller.navigationCollectionViewCommon.first(where: { $0.navigationController == navigationController && $0.serverUrl == serverUrlPush})?.viewController as? NCFiles, viewController.isViewLoaded { + viewController.fileNameBlink = fileNameBlink + viewController.openMetadata = metadata + 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)) + controller.navigationCollectionViewCommon.append(NavigationCollectionViewCommon(serverUrl: serverUrlPush, navigationController: navigationController, viewController: viewController)) - if serverUrlPush == serverUrl { - viewController.fileNameBlink = fileNameBlink - viewController.fileNameOpen = fileNameOpen - } - navigationController.pushViewController(viewController, animated: false) + if serverUrlPush == serverUrl { + viewController.fileNameBlink = fileNameBlink + viewController.openMetadata = metadata } + navigationController.pushViewController(viewController, animated: false) } - subDirs.remove(at: 0) } + subDirs.remove(at: 0) } } } diff --git a/iOSClient/SceneDelegate.swift b/iOSClient/SceneDelegate.swift index b39adbe162..90ffa1e782 100644 --- a/iOSClient/SceneDelegate.swift +++ b/iOSClient/SceneDelegate.swift @@ -304,12 +304,13 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { return } - func getMatchedAccount(userId: String, url: String) async -> tableAccount? { + func getMatchedAccount(user: String, url: String, account: String? = nil) async -> tableAccount? { let tblAccounts = await NCManageDatabase.shared.getAllTableAccountAsync() for tblAccount in tblAccounts { - let urlBase = URL(string: tblAccount.urlBase) - if url.contains(urlBase?.host ?? "") && userId == tblAccount.userId { + let host = URL(string: tblAccount.urlBase)?.host() ?? "" + + if (account == tblAccount.account) || (url.contains(host) && user == tblAccount.userId) { await NCAccount().changeAccount(tblAccount.account, userProfile: nil, controller: controller) // wait switch account try? await Task.sleep(for: .seconds(1)) @@ -333,7 +334,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } Task { - if await getMatchedAccount(userId: userScheme, url: urlScheme) == nil { + if await getMatchedAccount(user: userScheme, url: urlScheme) == nil { let message = NSLocalizedString("_the_account_", comment: "") + " " + userScheme + NSLocalizedString("_of_", comment: "") + " " + urlScheme + " " + NSLocalizedString("_does_not_exist_", comment: "") let alertController = UIAlertController(title: NSLocalizedString("_info_", comment: ""), message: message, preferredStyle: .alert) alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) @@ -386,36 +387,35 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { else if scheme == self.global.appScheme && action == "open-file" { if let urlComponents = URLComponents(url: url, resolvingAgainstBaseURL: false) { - var serverUrl: String = "" - var fileName: String = "" let queryItems = urlComponents.queryItems guard let userScheme = queryItems?.filter({ $0.name == "user" }).first?.value, - let pathScheme = queryItems?.filter({ $0.name == "path" }).first?.value, - let linkScheme = queryItems?.filter({ $0.name == "link" }).first?.value else { return} + // let pathScheme = queryItems?.filter({ $0.name == "path" }).first?.value, + let linkScheme = queryItems?.filter({ $0.name == "link" }).first?.value else { + return + } + let domain = URL(string: linkScheme)?.host ?? "" + let accountScheme = queryItems?.filter({ $0.name == "account" }).first?.value Task { - guard let tblAccount = await getMatchedAccount(userId: userScheme, url: linkScheme) else { - guard let domain = URL(string: linkScheme)?.host else { return } + guard let tblAccount = await getMatchedAccount(user: userScheme, url: linkScheme, account: accountScheme) else { - fileName = (pathScheme as NSString).lastPathComponent - let message = String(format: NSLocalizedString("_account_not_available_", comment: ""), userScheme, domain, fileName) + let message = String(format: NSLocalizedString("_account_not_available_", comment: ""), userScheme, domain) let alertController = UIAlertController(title: NSLocalizedString("_info_", comment: ""), message: message, preferredStyle: .alert) alertController.addAction(UIAlertAction(title: NSLocalizedString("_ok_", comment: ""), style: .default, handler: { _ in })) controller.present(alertController, animated: true) return } - let davFiles = "remote.php/dav/files/" + tblAccount.userId - if pathScheme.contains("/") { - fileName = (pathScheme as NSString).lastPathComponent - serverUrl = tblAccount.urlBase + "/" + davFiles + "/" + (pathScheme as NSString).deletingLastPathComponent - } else { - fileName = pathScheme - serverUrl = tblAccount.urlBase + "/" + davFiles + let results = await NextcloudKit.shared.getFileFromFileIdAsync(link: linkScheme, + account: tblAccount.account) + if results.error == .success, let file = results.file { + let metadata = await NCManageDatabaseCreateMetadata().convertFileToMetadataAsync(file) + await NCManageDatabase.shared.addMetadataAsync(metadata) + await NCNetworking.shared.openFileViewInFolder(serverUrl: metadata.serverUrl, + metadata: metadata, + sceneIdentifier: controller.sceneIdentifier) } - - NCNetworking.shared.openFileViewInFolder(serverUrl: serverUrl, fileNameBlink: nil, fileNameOpen: fileName, sceneIdentifier: controller.sceneIdentifier) } } @@ -434,7 +434,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { } Task { - _ = await getMatchedAccount(userId: userScheme, url: urlScheme) + _ = await getMatchedAccount(user: userScheme, url: urlScheme) } } else if let action { if DeepLink(rawValue: action) != nil { diff --git a/iOSClient/Supporting Files/en.lproj/Localizable.strings b/iOSClient/Supporting Files/en.lproj/Localizable.strings index 3aa17e8259..59cf1839df 100644 --- a/iOSClient/Supporting Files/en.lproj/Localizable.strings +++ b/iOSClient/Supporting Files/en.lproj/Localizable.strings @@ -74,7 +74,7 @@ "_denied_album_" = "This app does not have access to \"Photos\". You can enable access in Privacy Settings."; "_denied_camera_" = "This app does not have access to the \"Camera\". You can enable access in Privacy Settings."; "_force_start_" = "Force the start"; -"_account_not_available_" = "The account %@ of %@ does not exist, please add it to be able to read the file %@."; +"_account_not_available_" = "The account %@ of %@ does not exist, please add it."; "_the_account_" = "The account"; "_does_not_exist_" = "does not exist"; "_sharing_" = "Sharing"; From bbc4eb088ec79fe94e95af7a21d5a3902a6806d2 Mon Sep 17 00:00:00 2001 From: Marino Faggiana Date: Thu, 12 Feb 2026 15:36:26 +0100 Subject: [PATCH 8/8] code Signed-off-by: Marino Faggiana --- iOSClient/Files/NCFiles.swift | 6 ---- iOSClient/Menu/NCViewerContextMenu.swift | 6 ++-- .../NCNetworking+TransferDelegate.swift | 30 ++++++++++++------- iOSClient/SceneDelegate.swift | 13 ++++++-- 4 files changed, 33 insertions(+), 22 deletions(-) diff --git a/iOSClient/Files/NCFiles.swift b/iOSClient/Files/NCFiles.swift index 4b9fc5b05d..98bda6ebc5 100644 --- a/iOSClient/Files/NCFiles.swift +++ b/iOSClient/Files/NCFiles.swift @@ -9,8 +9,6 @@ import SwiftUI class NCFiles: NCCollectionViewCommon { internal var fileNameBlink: String? - internal var openMetadata: tableMetadata? - internal var lastOffsetY: CGFloat = 0 internal var lastScrollTime: TimeInterval = 0 internal var accumulatedScrollDown: CGFloat = 0 @@ -115,8 +113,6 @@ class NCFiles: NCCollectionViewCommon { } Task { - // Automatically open - await open(metadata: self.openMetadata) // Plus Menu reload let capabilities = await database.getCapabilities(account: self.session.account) ?? NKCapabilities.Capabilities() await mainNavigationController?.createPlusMenu(session: self.session, capabilities: capabilities) @@ -140,7 +136,6 @@ class NCFiles: NCCollectionViewCommon { super.viewDidDisappear(animated) fileNameBlink = nil - openMetadata = nil } // MARK: - DataSource @@ -385,7 +380,6 @@ class NCFiles: NCCollectionViewCommon { return } await didSelectMetadata(metadata, withOcIds: false) - self.openMetadata = nil } // MARK: - NCAccountSettingsModelDelegate diff --git a/iOSClient/Menu/NCViewerContextMenu.swift b/iOSClient/Menu/NCViewerContextMenu.swift index f21bb47a9b..7ce2dc9e6c 100644 --- a/iOSClient/Menu/NCViewerContextMenu.swift +++ b/iOSClient/Menu/NCViewerContextMenu.swift @@ -91,9 +91,9 @@ class NCViewerContextMenu: NSObject { image: UIImage(systemName: "questionmark.folder") ) { _ in Task { - await NCNetworking.shared.openFileViewInFolder(serverUrl: metadata.serverUrl, - fileNameBlink: metadata.fileName, - sceneIdentifier: controller.sceneIdentifier) + await NCNetworking.shared.blinkInFolder(serverUrl: metadata.serverUrl, + fileName: metadata.fileName, + sceneIdentifier: controller.sceneIdentifier) } } } diff --git a/iOSClient/Networking/NCNetworking+TransferDelegate.swift b/iOSClient/Networking/NCNetworking+TransferDelegate.swift index bd9b845273..e5fc79c672 100644 --- a/iOSClient/Networking/NCNetworking+TransferDelegate.swift +++ b/iOSClient/Networking/NCNetworking+TransferDelegate.swift @@ -287,10 +287,23 @@ extension NCNetworking: NCTransferDelegate { // MARK: - @MainActor - func openFileViewInFolder(serverUrl: String, - fileNameBlink: String? = nil, - metadata: tableMetadata? = nil, - sceneIdentifier: String) async { + func openFileView(serverUrl: String, + metadata: tableMetadata? = nil, + sceneIdentifier: String) async { + guard let controller = SceneManager.shared.getController(sceneIdentifier: sceneIdentifier), + let navigationController = controller.viewControllers?.first as? UINavigationController + else { return } + controller.selectedIndex = 0 + + if let viewController = navigationController.topViewController as? NCFiles { + await viewController.open(metadata: metadata) + } + } + + @MainActor + func blinkInFolder(serverUrl: String, + fileName: String, + sceneIdentifier: String) async { guard let controller = SceneManager.shared.getController(sceneIdentifier: sceneIdentifier), let navigationController = controller.viewControllers?.first as? UINavigationController else { return } @@ -302,8 +315,7 @@ extension NCNetworking: NCTransferDelegate { if serverUrlPush == serverUrl, let viewController = navigationController.topViewController as? NCFiles { Task { - viewController.blinkCell(fileName: fileNameBlink) - await viewController.open(metadata: metadata) + viewController.blinkCell(fileName: fileName) } return } @@ -318,8 +330,7 @@ extension NCNetworking: NCTransferDelegate { 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 - viewController.openMetadata = metadata + viewController.fileNameBlink = fileName navigationController.pushViewController(viewController, animated: false) } else { if let viewController: NCFiles = UIStoryboard(name: "NCFiles", bundle: nil).instantiateInitialViewController() as? NCFiles { @@ -330,8 +341,7 @@ extension NCNetworking: NCTransferDelegate { controller.navigationCollectionViewCommon.append(NavigationCollectionViewCommon(serverUrl: serverUrlPush, navigationController: navigationController, viewController: viewController)) if serverUrlPush == serverUrl { - viewController.fileNameBlink = fileNameBlink - viewController.openMetadata = metadata + viewController.fileNameBlink = fileName } navigationController.pushViewController(viewController, animated: false) } diff --git a/iOSClient/SceneDelegate.swift b/iOSClient/SceneDelegate.swift index 90ffa1e782..469b7df76b 100644 --- a/iOSClient/SceneDelegate.swift +++ b/iOSClient/SceneDelegate.swift @@ -412,9 +412,16 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { if results.error == .success, let file = results.file { let metadata = await NCManageDatabaseCreateMetadata().convertFileToMetadataAsync(file) await NCManageDatabase.shared.addMetadataAsync(metadata) - await NCNetworking.shared.openFileViewInFolder(serverUrl: metadata.serverUrl, - metadata: metadata, - sceneIdentifier: controller.sceneIdentifier) + if metadata.hasPreview { + let results = await NextcloudKit.shared.downloadPreviewAsync(fileId: metadata.fileId, etag: metadata.etag, account: metadata.account) + if results.error == .success, + let data = results.responseData?.data { + NCUtility().createImageFileFrom(data: data, metadata: metadata) + } + } + await NCNetworking.shared.openFileView(serverUrl: metadata.serverUrl, + metadata: metadata, + sceneIdentifier: controller.sceneIdentifier) } } }