Skip to content

Commit ce3de4f

Browse files
committed
WIP
Signed-off-by: Milen Pivchev <milen.pivchev@gmail.com>
1 parent a054696 commit ce3de4f

4 files changed

Lines changed: 147 additions & 64 deletions

File tree

Sources/NextcloudKit/Models/DeclarativeUI/NKDeclarativeUI.swift renamed to Sources/NextcloudKit/Models/DeclarativeUI/NKDeclarativeUICapabilities.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ import Alamofire
4040
// }
4141
//}
4242

43-
public struct DeclarativeUI: Codable {
43+
public struct NKDeclarativeUICapabilities: Codable {
4444
public let apps: [String: AppContext]
4545

4646
public init(from decoder: Decoder) throws {
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// NKDeclarativeUIResponse.swift
3+
// NextcloudKit
4+
//
5+
// Created by Milen Pivchev on 24.09.25.
6+
//
7+
8+
9+
public struct NKDeclarativeUIResponse: Codable {
10+
let version: Double
11+
let root: RootContainer
12+
}
13+
14+
public struct RootContainer: Codable {
15+
let orientation: String
16+
let rows: [Row]
17+
}
18+
19+
public struct Row: Codable {
20+
let children: [Child]
21+
}
22+
23+
public struct Child: Codable {
24+
let element: String
25+
let text: String?
26+
let url: String?
27+
}

Sources/NextcloudKit/NextcloudKit+Capabilities.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -127,7 +127,7 @@ public extension NextcloudKit {
127127
let assistant: Assistant?
128128
let recommendations: Recommendations?
129129
let termsOfService: TermsOfService?
130-
let declarativeUI: DeclarativeUI?
130+
let declarativeUI: NKDeclarativeUICapabilities?
131131

132132
enum CodingKeys: String, CodingKey {
133133
case downloadLimit = "downloadlimit"
@@ -518,7 +518,7 @@ final public class NKCapabilities: Sendable {
518518
public var termsOfService: Bool = false
519519
// public var declarativeUIEnabled: Bool = false
520520
// public var declarativeUIContextMenu: [ContextMenuItem] = []
521-
public var declarativeUI: DeclarativeUI? = nil
521+
public var declarativeUI: NKDeclarativeUICapabilities? = nil
522522
public var directEditingEditors: [NKEditorDetailsEditor] = []
523523
public var directEditingCreators: [NKEditorDetailsCreator] = []
524524
public var directEditingTemplates: [NKEditorTemplate] = []

Sources/NextcloudKit/NextcloudKit+DeclarativeUI.swift

Lines changed: 117 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -19,68 +19,73 @@ public extension NextcloudKit {
1919
/// - options: Optional request configuration (headers, queue, etc.).
2020
/// - taskHandler: Callback for observing the underlying URLSessionTask.
2121
/// - completion: Returns the token string (if any), raw response data, and NKError result.
22-
func sendRequest(account: String,
22+
internal func sendRequest(account: String,
2323
fileId: String,
2424
filePath: String,
2525
url: String,
2626
method: String,
2727
params: [String: String]? = nil,
2828
options: NKRequestOptions = NKRequestOptions(),
2929
taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in },
30-
completion: @escaping (_ token: String?, _ responseData: AFDataResponse<Data>?, _ error: NKError) -> Void) {
30+
completion: @escaping (_ token: String?, _ uiResponse: NKDeclarativeUIResponse?, _ responseData: AFDataResponse<Data>?, _ error: NKError) -> Void) {
3131

32-
guard let nkSession = nkCommonInstance.nksessions.session(forAccount: account),
33-
let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else {
34-
return completion(nil, nil, .urlError)
35-
}
36-
37-
let httpMethod = HTTPMethod(rawValue: method.uppercased())
38-
39-
var queryParams: [String: Any] = [:]
40-
typealias pEnum = DeclarativeUI.Params
41-
if let params = params {
42-
params.forEach { (key: String, value: String) in
43-
switch value {
44-
case pEnum.fileId.rawValue:
45-
queryParams[pEnum.fileId.rawValue] = fileId
46-
case pEnum.filePath.rawValue:
47-
queryParams[pEnum.filePath.rawValue] = filePath
48-
default:
49-
queryParams = [:]
50-
}
51-
}
52-
53-
guard let url = URL(string: nkSession.urlBase + url) else {
54-
return options.queue.async { completion(nil, nil, .urlError) }
55-
}
56-
57-
// var headers: HTTPHeaders = [.init(name: "OCS-APIRequest", value: "true")]
58-
// headers.update(.userAgent(nkSession.userAgent))
59-
60-
61-
let encoding: ParameterEncoding = (httpMethod == .get ? URLEncoding.default : JSONEncoding.default)
62-
63-
unauthorizedSession.request(url,
64-
method: httpMethod,
65-
parameters: queryParams,
66-
encoding: encoding,
67-
headers: headers)
68-
.validate(statusCode: 200..<300)
69-
.onURLSessionTaskCreation { task in
70-
task.taskDescription = options.taskDescription
71-
taskHandler(task)
72-
}
73-
.responseData(queue: self.nkCommonInstance.backgroundQueue) { response in
74-
switch response.result {
75-
case .failure(let error):
76-
let error = NKError(error: error, afResponse: response, responseData: response.data)
77-
options.queue.async { completion(nil, response, error) }
78-
case .success(let data):
79-
let apppassword = NKDataFileXML(nkCommonInstance: self.nkCommonInstance).convertDataAppPassword(data: data)
80-
options.queue.async { completion(apppassword, response, .success) }
81-
}
82-
}
83-
}
32+
// guard let nkSession = nkCommonInstance.nksessions.session(forAccount: account),
33+
// let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else {
34+
// return completion(nil, nil, .urlError)
35+
// }
36+
//
37+
// let httpMethod = HTTPMethod(rawValue: method.uppercased())
38+
//
39+
// // var queryParams: [String: Any] = [:]
40+
// typealias pEnum = NKDeclarativeUICapabilities.Params
41+
// // Build query params if provided
42+
// var queryParams: [String: Any]? = nil
43+
// if let params = params {
44+
// var qp: [String: Any] = [:]
45+
// for (key, value) in params {
46+
// switch key {
47+
// case NKDeclarativeUICapabilities.Params.fileId.rawValue:
48+
// qp[key] = fileId
49+
// case NKDeclarativeUICapabilities.Params.filePath.rawValue:
50+
// qp[key] = filePath
51+
// default:
52+
// qp[key] = value
53+
// }
54+
// }
55+
// queryParams = qp
56+
// }
57+
//
58+
//
59+
// guard let url = URL(string: nkSession.urlBase + url) else {
60+
// return options.queue.async { completion(nil, nil, .urlError) }
61+
// }
62+
//
63+
// // var headers: HTTPHeaders = [.init(name: "OCS-APIRequest", value: "true")]
64+
// // headers.update(.userAgent(nkSession.userAgent))
65+
//
66+
//
67+
//// let encoding: ParameterEncoding = (httpMethod == .get ? URLEncoding.default : JSONEncoding.default)
68+
//
69+
// unauthorizedSession.request(url,
70+
// method: httpMethod,
71+
// parameters: queryParams,
72+
// encoding: URLEncoding.queryString,
73+
// headers: headers)
74+
// .validate(statusCode: 200..<300)
75+
// .onURLSessionTaskCreation { task in
76+
// task.taskDescription = options.taskDescription
77+
// taskHandler(task)
78+
// }
79+
// .responseData(queue: self.nkCommonInstance.backgroundQueue) { response in
80+
// switch response.result {
81+
// case .failure(let error):
82+
// let error = NKError(error: error, afResponse: response, responseData: response.data)
83+
// options.queue.async { completion(nil, response, error) }
84+
// case .success(let data):
85+
// let apppassword = NKDataFileXML(nkCommonInstance: self.nkCommonInstance).convertDataAppPassword(data: data)
86+
// options.queue.async { completion(apppassword, response, .success) }
87+
// }
88+
// }
8489
}
8590

8691
/// Asynchronously fetches an app password for the provided user credentials.
@@ -100,17 +105,68 @@ public extension NextcloudKit {
100105
method: String,
101106
params: [String: String]? = nil,
102107
options: NKRequestOptions = NKRequestOptions(),
103-
taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in },
108+
taskHandler: @escaping (_ task: URLSessionTask) -> Void = { _ in }
104109
) async -> (
105-
token: String?,
106-
107-
responseData: AFDataResponse<Data>?,
110+
account: String,
111+
uiResponse: NKDeclarativeUIResponse?,
108112
error: NKError
109113
) {
110-
await withCheckedContinuation { continuation in
111-
sendRequest(account: account, fileId: fileId, filePath: filePath, url: url, method: method, params: params) { token, responseData, error in
112-
continuation.resume(returning: (token: token, responseData: responseData, error: error))
114+
guard let nkSession = nkCommonInstance.nksessions.session(forAccount: account),
115+
let headers = nkCommonInstance.getStandardHeaders(account: account, options: options) else {
116+
return (account, nil, NKError.urlError)
117+
}
118+
119+
let httpMethod = HTTPMethod(rawValue: method.uppercased())
120+
121+
var queryParams: [String: Any]? = nil
122+
if let params = params {
123+
var qp: [String: Any] = [:]
124+
for (key, value) in params {
125+
switch key {
126+
case NKDeclarativeUICapabilities.Params.fileId.rawValue:
127+
qp[key] = fileId
128+
case NKDeclarativeUICapabilities.Params.filePath.rawValue:
129+
qp[key] = filePath
130+
default:
131+
qp[key] = value
132+
}
133+
}
134+
queryParams = qp
135+
}
136+
137+
guard let fullURL = URL(string: nkSession.urlBase + url) else {
138+
return (account, nil, NKError.urlError)
139+
}
140+
141+
let taskDescription = options.taskDescription
142+
143+
let request = unauthorizedSession.request(fullURL,
144+
method: httpMethod,
145+
parameters: queryParams,
146+
encoding: URLEncoding.queryString,
147+
headers: headers)
148+
.validate(statusCode: 200..<300)
149+
.onURLSessionTaskCreation { [taskDescription] task in
150+
task.taskDescription = taskDescription
151+
taskHandler(task)
152+
}
153+
154+
let response = await request.serializingData().response
155+
156+
switch response.result {
157+
case .failure(let afError):
158+
let nkErr = NKError(error: afError, afResponse: response, responseData: response.data)
159+
return (account, nil, nkErr)
160+
case .success(let data):
161+
do {
162+
let decoder = JSONDecoder()
163+
let ui = try decoder.decode(NKDeclarativeUIResponse.self, from: data)
164+
return (account, ui, .success)
165+
} catch {
166+
nkLog(debug: "Declarative UI response decoding failed: \(error)")
167+
return (account, nil, .invalidData)
113168
}
114169
}
115170
}
116171
}
172+

0 commit comments

Comments
 (0)