Skip to content

Commit eda8749

Browse files
Client integration (#3762)
* Add menu Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * WIP Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * WIP Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * Replace sheet with native context menu Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * WIP Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * WIP Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * WIP Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * Refactor Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * Use relative file path Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * Refactor Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * API Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * Error handling Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * WIP Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * WIP Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * WIP Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * WIP Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * WIP Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * WIP Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * Sendable fix Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * Refactor Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * Refactor Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * Refactor Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * WIP Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * Bring back more button in list This reverts commit c3dee5a. Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * Revert more button in grid Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * WIP This reverts commit 22eae10. Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * WIP Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * WIP Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * WIP Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * Refactor Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * Recommendations menu Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * Photo cell fix Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * Resize icons Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * Refactor Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> * remove old code Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * remove old code Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * cleaning Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * added onMenuIntent Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * normalized Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * normalized Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * TransferDelegate Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * transferReloadData Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * test Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * incredible strategy Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * code Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * Media Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * License Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * add Helper Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * Improved code Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * fix Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * hide button more in photo cell Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * improved Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * 2026 Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * 2026 Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * cell protocol improvements Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * cleaning code Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * lint Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * cleaning (Lint) Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * lint Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * NCContextMenu Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * NCContextMenu Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * doc Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> * code Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> --------- Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com> Signed-off-by: Marino Faggiana <marino.faggiana@nextcloud.com> Co-authored-by: Marino Faggiana <marino.faggiana@nextcloud.com>
1 parent 62c6688 commit eda8749

75 files changed

Lines changed: 1649 additions & 1660 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

Brand/NCBrand.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ final class NCBrandOptions: @unchecked Sendable {
2525

2626
var brand: String = "Nextcloud"
2727
var brandUserAgent: String = ""
28-
var textCopyrightNextcloudiOS: String = "Nextcloud Matheria for iOS %@ © 2025"
28+
var textCopyrightNextcloudiOS: String = "Nextcloud Matheria for iOS %@ © 2026"
2929
var textCopyrightNextcloudServer: String = "Nextcloud Server %@"
3030
var loginBaseUrl: String = "https://cloud.nextcloud.com"
3131
var pushNotificationServerProxy: String = ""

File Provider Extension/FileProviderExtension+Actions.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,7 @@ extension FileProviderExtension {
207207
}
208208

209209
if (favorite == true && !metadata.favorite) || (!favorite && metadata.favorite) {
210-
let fileNamePath = NCUtilityFileSystem().getFileNamePath(metadata.fileName, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, userId: metadata.userId)
210+
let fileNamePath = NCUtilityFileSystem().getRelativeFilePath(metadata.fileName, serverUrl: metadata.serverUrl, urlBase: metadata.urlBase, userId: metadata.userId)
211211
let resultsFavorite = await NextcloudKit.shared.setFavoriteAsync(fileName: fileNamePath, favorite: favorite, account: metadata.account)
212212

213213
if resultsFavorite.error == .success {

Nextcloud.xcodeproj/project.pbxproj

Lines changed: 43 additions & 9 deletions
Large diffs are not rendered by default.

Share/NCShareExtension+DataSource.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -76,14 +76,12 @@ extension NCShareExtension: UICollectionViewDataSource {
7676
}
7777

7878
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
79-
let cell = (collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as? NCListCell)!
79+
var cell = (collectionView.dequeueReusableCell(withReuseIdentifier: "listCell", for: indexPath) as? NCListCell)!
8080
guard let metadata = self.dataSource.getMetadata(indexPath: indexPath) else {
8181
return cell
8282
}
8383

84-
cell.fileOcId = metadata.ocId
85-
cell.fileOcIdTransfer = metadata.ocIdTransfer
86-
cell.fileUser = metadata.ownerId
84+
cell.metadata = metadata
8785
cell.labelTitle.text = metadata.fileNameView
8886
cell.labelTitle.textColor = NCBrandColor.shared.textColor
8987
cell.imageSelect.image = nil

iOSClient/Activity/NCActivity.swift

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -84,9 +84,7 @@ class NCActivity: UIViewController, NCSharePagingContent {
8484
self.loadComments()
8585
} else {
8686
Task {@MainActor in
87-
await showErrorBanner(controller: self.tabBarController,
88-
errorDescription: error.errorDescription,
89-
errorCode: error.errorCode)
87+
await showErrorBanner(controller: self.tabBarController, errorDescription: error.errorDescription)
9088
}
9189
}
9290
}
@@ -225,9 +223,9 @@ extension NCActivity: UITableViewDataSource {
225223
let results = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName)
226224

227225
if results.image == nil {
228-
cell.fileAvatarImageView?.image = utility.loadUserImage(for: comment.actorId, displayName: comment.actorDisplayName, urlBase: NCSession.shared.getSession(account: account).urlBase)
226+
cell.avatarImageView?.image = utility.loadUserImage(for: comment.actorId, displayName: comment.actorDisplayName, urlBase: NCSession.shared.getSession(account: account).urlBase)
229227
} else {
230-
cell.fileAvatarImageView?.image = results.image
228+
cell.avatarImageView?.image = results.image
231229
}
232230

233231
if let tblAvatar = results.tblAvatar,
@@ -313,9 +311,9 @@ extension NCActivity: UITableViewDataSource {
313311
let results = NCManageDatabase.shared.getImageAvatarLoaded(fileName: fileName)
314312

315313
if results.image == nil {
316-
cell.fileAvatarImageView?.image = utility.loadUserImage(for: activity.user, displayName: nil, urlBase: session.urlBase)
314+
cell.avatarImageView?.image = utility.loadUserImage(for: activity.user, displayName: nil, urlBase: session.urlBase)
317315
} else {
318-
cell.fileAvatarImageView?.image = results.image
316+
cell.avatarImageView?.image = results.image
319317
}
320318

321319
if !(results.tblAvatar?.loaded ?? false),
@@ -441,9 +439,7 @@ extension NCActivity {
441439
self.database.addComments(comments, account: metadata.account, objectId: metadata.fileId)
442440
} else if error.errorCode != NCGlobal.shared.errorResourceNotFound {
443441
Task {@MainActor in
444-
await showErrorBanner(controller: self.tabBarController,
445-
errorDescription: error.errorDescription,
446-
errorCode: error.errorCode)
442+
await showErrorBanner(controller: self.tabBarController, errorDescription: error.errorDescription)
447443
}
448444
}
449445

@@ -583,9 +579,7 @@ extension NCActivity: NCShareCommentsCellDelegate {
583579
self.loadComments()
584580
} else {
585581
Task {@MainActor in
586-
await showErrorBanner(controller: self.tabBarController,
587-
errorDescription: error.errorDescription,
588-
errorCode: error.errorCode)
582+
await showErrorBanner(controller: self.tabBarController, errorDescription: error.errorDescription)
589583
}
590584
}
591585
}
@@ -617,9 +611,7 @@ extension NCActivity: NCShareCommentsCellDelegate {
617611
self.loadComments()
618612
} else {
619613
Task {@MainActor in
620-
await showErrorBanner(controller: self.tabBarController,
621-
errorDescription: error.errorDescription,
622-
errorCode: error.errorCode)
614+
await showErrorBanner(controller: self.tabBarController, errorDescription: error.errorDescription)
623615
}
624616
}
625617
}

iOSClient/Activity/NCActivityTableViewCell.swift

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ class NCActivityTableViewCell: UITableViewCell, NCCellProtocol {
3737
get { return index }
3838
set { index = newValue }
3939
}
40-
var fileAvatarImageView: UIImageView? {
40+
var avatarImageView: UIImageView? {
4141
return avatar
4242
}
4343
var fileUser: String? {
@@ -86,9 +86,7 @@ extension NCActivityTableViewCell: UICollectionViewDelegate {
8686
} else {
8787
let error = NKError(errorCode: NCGlobal.shared.errorInternalError, errorDescription: "_trash_file_not_found_")
8888
Task {@MainActor in
89-
await showErrorBanner(controller: viewController.controller,
90-
errorDescription: error.errorDescription,
91-
errorCode: error.errorCode)
89+
await showErrorBanner(controller: viewController.controller, errorDescription: error.errorDescription)
9290
}
9391
}
9492
}

iOSClient/AppDelegate.swift

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import EasyTipView
1414
import SwiftUI
1515
import RealmSwift
1616

17-
@UIApplicationMain
1817
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate {
1918
var backgroundSessionCompletionHandler: (() -> Void)?
2019
var isUiTestingEnabled: Bool {
@@ -408,7 +407,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterD
408407
Task {
409408
await NCNetworking.shared.transferDispatcher.notifyAllDelegatesAsync { delegate in
410409
try? await Task.sleep(nanoseconds: 500_000_000)
411-
delegate.transferReloadData(serverUrl: nil, requestData: true, status: nil)
410+
delegate.transferReloadDataSource(serverUrl: nil, requestData: true, status: nil)
412411
}
413412
}
414413
} else if let navigationController = UIStoryboard(name: "NCNotification", bundle: nil).instantiateInitialViewController() as? UINavigationController,
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
// SPDX-FileCopyrightText: Nextcloud GmbH
2+
// SPDX-FileCopyrightText: 2025 Milen Pivchev
3+
// SPDX-License-Identifier: GPL-3.0-or-later
4+
5+
import SwiftUI
6+
7+
struct ClientIntegrationUIViewer: View {
8+
@Environment(\.openURL) private var openURL
9+
10+
struct Row: Identifiable {
11+
let id = UUID()
12+
let element: String
13+
let title: String?
14+
let urlString: String
15+
}
16+
17+
// Configurable inputs
18+
let rows: [Row]
19+
let baseURL: String
20+
21+
var body: some View {
22+
ScrollView {
23+
LazyVStack(alignment: .leading, spacing: 12) {
24+
ForEach(rows) { row in
25+
VStack(alignment: .leading, spacing: 8) {
26+
HStack {
27+
Text(row.element)
28+
.font(.subheadline)
29+
.fontWeight(.semibold)
30+
.foregroundStyle(.secondary)
31+
Spacer()
32+
}
33+
34+
if let title = row.title {
35+
Text(title).font(.headline)
36+
}
37+
38+
let finalUrl = baseURL + row.urlString
39+
40+
Text(finalUrl)
41+
.font(.footnote)
42+
.foregroundStyle(.secondary)
43+
.textSelection(.enabled)
44+
45+
HStack(spacing: 12) {
46+
Button {
47+
openURL(URL(string: finalUrl)!)
48+
} label: {
49+
Label("Open", systemImage: "safari")
50+
}
51+
52+
Button {
53+
UIPasteboard.general.string = row.urlString
54+
} label: {
55+
Label("Copy", systemImage: "doc.on.doc")
56+
}
57+
}
58+
.buttonStyle(.borderedProminent)
59+
}
60+
.padding()
61+
.background(.thinMaterial, in: RoundedRectangle(cornerRadius: 12))
62+
}
63+
}
64+
.padding()
65+
}
66+
}
67+
68+
// private func resolvedURL(for row: Row) -> URL? {
69+
// // If the string is already an absolute URL with a scheme, use it.
70+
// if let absolute = URL(string: row.urlString), absolute.scheme != nil {
71+
// return absolute
72+
// }
73+
// // Otherwise, resolve relative to the provided base URL if available.
74+
// if let baseURL {
75+
// return URL(string: row.urlString, relativeTo: baseURL)?.absoluteURL
76+
// }
77+
// return nil
78+
// }
79+
}
80+
81+
#Preview {
82+
ClientIntegrationUIViewer(rows: [.init(element: "URL", title: "Test", urlString: "/test")], baseURL: "test.com")
83+
}

iOSClient/Data/NCManageDatabase+Metadata.swift

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,13 @@ class tableMetadata: Object {
125125
@objc dynamic var autoUploadServerUrlBase: String?
126126
@objc dynamic var typeIdentifier: String = ""
127127

128+
// =========================
129+
// UI / transient properties
130+
// =========================
131+
132+
/// Used only for UI state (not persisted, not observed by Realm)
133+
var isOffline: Bool = false
134+
128135
override static func primaryKey() -> String {
129136
return "ocId"
130137
}

iOSClient/DeepLink/NCDeepLinkHandler.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,7 @@ class NCDeepLinkHandler {
116116
DispatchQueue.main.asyncAfter(deadline: .now() + 4) {
117117
let serverUrl = controller.currentServerUrl()
118118
let session = NCSession.shared.getSession(controller: controller)
119-
let fileFolderPath = NCUtilityFileSystem().getFileNamePath("", serverUrl: serverUrl, session: session)
119+
let fileFolderPath = NCUtilityFileSystem().getRelativeFilePath("", serverUrl: serverUrl, session: session)
120120
let fileFolderName = (serverUrl as NSString).lastPathComponent
121121
let capabilities = NCNetworking.shared.capabilities[controller.account] ?? NKCapabilities.Capabilities()
122122

0 commit comments

Comments
 (0)