Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
7a6262b
WIP
mpivchev Jan 19, 2026
2b07b93
WIP
mpivchev Jan 20, 2026
a385756
WIP
mpivchev Jan 21, 2026
5838d2a
Merge branch 'master' into assistant-improvements
mpivchev Jan 23, 2026
0e0c8e3
Send message
mpivchev Jan 23, 2026
39a6029
Merge branch 'master' of https://github.com/nextcloud/ios into assist…
mpivchev Jan 26, 2026
6728acb
WIP
mpivchev Jan 26, 2026
d3c21c2
WIP
mpivchev Jan 26, 2026
a17f15a
Refactor
mpivchev Jan 26, 2026
c1711eb
WIP
mpivchev Jan 27, 2026
5a26235
Merge branch 'master' into assistant-improvements
mpivchev Jan 28, 2026
7197086
WIP
mpivchev Jan 29, 2026
eac00d8
Merge branch 'master' of https://github.com/nextcloud/ios into assist…
mpivchev Jan 29, 2026
32022db
WIP
mpivchev Jan 30, 2026
bb62d62
WIP
mpivchev Jan 30, 2026
0afd898
WIP
mpivchev Feb 2, 2026
af3d1fc
Merge branch 'master' of https://github.com/nextcloud/ios into assist…
mpivchev Feb 2, 2026
8febeb7
WIP
mpivchev Feb 3, 2026
a0a8dd0
Merge branch 'master' into assistant-improvements
mpivchev Feb 4, 2026
e99ef9d
WIP
mpivchev Feb 5, 2026
6c36443
WIP
mpivchev Feb 5, 2026
8334485
WIP
mpivchev Feb 5, 2026
ae375a1
WIP
mpivchev Feb 6, 2026
1f70fb1
WIP
mpivchev Feb 6, 2026
53a5820
WIP
mpivchev Feb 6, 2026
a4d5786
WIP
mpivchev Feb 6, 2026
93bb21b
Merge branch 'master' of https://github.com/nextcloud/ios into assist…
mpivchev Feb 6, 2026
34cc2c7
WIP
mpivchev Feb 6, 2026
61b65ab
WIP
mpivchev Feb 6, 2026
9c3a973
WIP
mpivchev Feb 9, 2026
1de03b0
Merge branch 'master' of https://github.com/nextcloud/ios into assist…
mpivchev Feb 9, 2026
d958fc6
WIP
mpivchev Feb 9, 2026
896da87
WIP
mpivchev Feb 9, 2026
16da8f5
WIP
mpivchev Feb 9, 2026
3634a53
WIP
mpivchev Feb 9, 2026
2f96160
NCKit
mpivchev Feb 9, 2026
8c5d5a5
Merge branch 'master' into assistant-improvements
mpivchev Feb 12, 2026
f8ff12f
Refactor
mpivchev Feb 12, 2026
020bce8
Add error handling
mpivchev Feb 13, 2026
33b0979
Merge remote-tracking branch 'origin/master' into assistant-improvements
marinofaggiana Feb 15, 2026
558fad2
fix assistantButtonItem
marinofaggiana Feb 15, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 37 additions & 9 deletions Nextcloud.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,12 @@
F3BB46522A39EC4900461F6E /* NCMoreAppSuggestionsCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3BB46512A39EC4900461F6E /* NCMoreAppSuggestionsCell.swift */; };
F3BB46542A3A1E9D00461F6E /* CCCellMore.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3BB46532A3A1E9D00461F6E /* CCCellMore.swift */; };
F3C587AE2D47E4FE004532DB /* PHAssetCollectionThumbnailLoader.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3C587AD2D47E4FE004532DB /* PHAssetCollectionThumbnailLoader.swift */; };
F3C6F6F62F34CC0900C531B6 /* NCAssistantChatConversationsModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3C6F6F52F34CC0900C531B6 /* NCAssistantChatConversationsModel.swift */; };
F3CA337D2D0B2B6C00672333 /* AlbumModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3CA337C2D0B2B6A00672333 /* AlbumModel.swift */; };
F3DDFE0F2F15453900A784C8 /* NCAssistantChat.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3DDFE0E2F15453900A784C8 /* NCAssistantChat.swift */; };
F3DDFE1E2F1F8EC600A784C8 /* ChatInputField.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3DDFE1D2F1F8EC600A784C8 /* ChatInputField.swift */; };
F3DDFE212F1F953000A784C8 /* NCAssistantChatConversations.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3DDFE202F1F953000A784C8 /* NCAssistantChatConversations.swift */; };
F3DDFE232F1FB4C300A784C8 /* NCAssistantChatModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3DDFE222F1FB4C300A784C8 /* NCAssistantChatModel.swift */; };
F3E173B02C9AF637006D177A /* ScreenAwakeManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3E173AF2C9AF637006D177A /* ScreenAwakeManager.swift */; };
F3E173C02C9B1067006D177A /* AwakeMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3E173BF2C9B1067006D177A /* AwakeMode.swift */; };
F3E173C12C9B1067006D177A /* AwakeMode.swift in Sources */ = {isa = PBXBuildFile; fileRef = F3E173BF2C9B1067006D177A /* AwakeMode.swift */; };
Expand Down Expand Up @@ -1267,7 +1272,12 @@
F3BB46512A39EC4900461F6E /* NCMoreAppSuggestionsCell.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMoreAppSuggestionsCell.swift; sourceTree = "<group>"; };
F3BB46532A3A1E9D00461F6E /* CCCellMore.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CCCellMore.swift; sourceTree = "<group>"; };
F3C587AD2D47E4FE004532DB /* PHAssetCollectionThumbnailLoader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PHAssetCollectionThumbnailLoader.swift; sourceTree = "<group>"; };
F3C6F6F52F34CC0900C531B6 /* NCAssistantChatConversationsModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAssistantChatConversationsModel.swift; sourceTree = "<group>"; };
F3CA337C2D0B2B6A00672333 /* AlbumModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AlbumModel.swift; sourceTree = "<group>"; };
F3DDFE0E2F15453900A784C8 /* NCAssistantChat.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAssistantChat.swift; sourceTree = "<group>"; };
F3DDFE1D2F1F8EC600A784C8 /* ChatInputField.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChatInputField.swift; sourceTree = "<group>"; };
F3DDFE202F1F953000A784C8 /* NCAssistantChatConversations.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAssistantChatConversations.swift; sourceTree = "<group>"; };
F3DDFE222F1FB4C300A784C8 /* NCAssistantChatModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCAssistantChatModel.swift; sourceTree = "<group>"; };
F3E173AF2C9AF637006D177A /* ScreenAwakeManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ScreenAwakeManager.swift; sourceTree = "<group>"; };
F3E173BF2C9B1067006D177A /* AwakeMode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AwakeMode.swift; sourceTree = "<group>"; };
F3F442ED2DDE292600FD701F /* NCMetadataPermissions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NCMetadataPermissions.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -2107,6 +2117,7 @@
F3374A7F2D64AB40002A38F9 /* Components */ = {
isa = PBXGroup;
children = (
F3DDFE1D2F1F8EC600A784C8 /* ChatInputField.swift */,
F3374A832D64AC2C002A38F9 /* AssistantLabelStyle.swift */,
F3374A802D64AB9E002A38F9 /* StatusInfo.swift */,
F3A0478F2BD2668800658E7B /* NCAssistantEmptyView.swift */,
Expand Down Expand Up @@ -2138,10 +2149,12 @@
isa = PBXGroup;
children = (
F3A047962BD2668800658E7B /* NCAssistant.swift */,
F3A047932BD2668800658E7B /* NCAssistantModel.swift */,
F3DDFE0D2F15452F00A784C8 /* Chat */,
F3DDFE1F2F1F951000A784C8 /* Chat Sessions */,
F3A047902BD2668800658E7B /* Create Task */,
F3A047942BD2668800658E7B /* Task Detail */,
F3374A7F2D64AB40002A38F9 /* Components */,
F3A047922BD2668800658E7B /* Models */,
);
path = Assistant;
sourceTree = "<group>";
Expand All @@ -2154,14 +2167,6 @@
path = "Create Task";
sourceTree = "<group>";
};
F3A047922BD2668800658E7B /* Models */ = {
isa = PBXGroup;
children = (
F3A047932BD2668800658E7B /* NCAssistantModel.swift */,
);
path = Models;
sourceTree = "<group>";
};
F3A047942BD2668800658E7B /* Task Detail */ = {
isa = PBXGroup;
children = (
Expand All @@ -2181,6 +2186,24 @@
path = Cells;
sourceTree = "<group>";
};
F3DDFE0D2F15452F00A784C8 /* Chat */ = {
isa = PBXGroup;
children = (
F3DDFE0E2F15453900A784C8 /* NCAssistantChat.swift */,
F3DDFE222F1FB4C300A784C8 /* NCAssistantChatModel.swift */,
);
path = Chat;
sourceTree = "<group>";
};
F3DDFE1F2F1F951000A784C8 /* Chat Sessions */ = {
isa = PBXGroup;
children = (
F3DDFE202F1F953000A784C8 /* NCAssistantChatConversations.swift */,
F3C6F6F52F34CC0900C531B6 /* NCAssistantChatConversationsModel.swift */,
);
path = "Chat Sessions";
sourceTree = "<group>";
};
F3E173BE2C9B1057006D177A /* ScreenAwakeManager */ = {
isa = PBXGroup;
children = (
Expand Down Expand Up @@ -4412,6 +4435,7 @@
F7AE00F8230E81CB007ACF8A /* NCBrowserWeb.swift in Sources */,
F77DD6A82C5CC093009448FB /* NCSession.swift in Sources */,
F702F30825EE5D47008F8E80 /* NCPopupViewController.swift in Sources */,
F3C6F6F62F34CC0900C531B6 /* NCAssistantChatConversationsModel.swift in Sources */,
F76340FC2EBDF64D0056F538 /* NCManageDatabase+Tag.swift in Sources */,
F733598125C1C188002ABA72 /* NCAskAuthorization.swift in Sources */,
370D26AF248A3D7A00121797 /* NCCellMain.swift in Sources */,
Expand Down Expand Up @@ -4583,6 +4607,7 @@
F7816EF22C2C3E1F00A52517 /* NCPushNotification.swift in Sources */,
F76882342C0DD1E7001CF441 /* NCDisplayView.swift in Sources */,
F7C30DF6291BC0CA0017149B /* NCNetworkingE2EEUpload.swift in Sources */,
F3DDFE232F1FB4C300A784C8 /* NCAssistantChatModel.swift in Sources */,
F7501C332212E57500FB1415 /* NCMedia.swift in Sources */,
F7411C552D7B26D700F57358 /* NCNetworking+ServerError.swift in Sources */,
F72944F22A84246400246839 /* NCEndToEndMetadataV20.swift in Sources */,
Expand Down Expand Up @@ -4699,7 +4724,9 @@
F7A03E2F2D425A14007AA677 /* NCFavoriteNavigationController.swift in Sources */,
F343A4BB2A1E734600DDA874 /* Optional+Extension.swift in Sources */,
F76882232C0DD1E7001CF441 /* NCCapabilitiesModel.swift in Sources */,
F3DDFE212F1F953000A784C8 /* NCAssistantChatConversations.swift in Sources */,
F7E2B64F2DDCC5C30075B4D0 /* NCMedia+TransferDelegate.swift in Sources */,
F3DDFE0F2F15453900A784C8 /* NCAssistantChat.swift in Sources */,
F7D68FCC28CB9051009139F3 /* NCManageDatabase+DashboardWidget.swift in Sources */,
F76882292C0DD1E7001CF441 /* NCManageE2EEModel.swift in Sources */,
F799DF8B2C4B84EB003410B5 /* NCCollectionViewCommon+EndToEndInitialize.swift in Sources */,
Expand All @@ -4723,6 +4750,7 @@
F76882272C0DD1E7001CF441 /* NCManageE2EEView.swift in Sources */,
F7864ACC2A78FE73004870E0 /* NCManageDatabase+LocalFile.swift in Sources */,
F7327E302B73A86700A462C7 /* NCNetworking+WebDAV.swift in Sources */,
F3DDFE1E2F1F8EC600A784C8 /* ChatInputField.swift in Sources */,
F7D61EA82EBF1694007F865B /* NCManageDatabase+TableCapabilities.swift in Sources */,
F79FFB262A97C24A0055EEA4 /* NCNetworkingE2EEMarkFolder.swift in Sources */,
F70D8D8124A4A9BF000A5756 /* NCNetworkingProcess.swift in Sources */,
Expand Down
2 changes: 1 addition & 1 deletion Tests/NextcloudUITests/AssistantUITests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ final class AssistantUITests: BaseUIXCTestCase {
}

private func createTask(input: String) {
app.navigationBars["Assistant"].buttons["CreateButton"].tap()
app.navigationBars["Assistant"].buttons["ConversationsButton"].tap()

let inputTextEditor = app.textViews["InputTextEditor"]
inputTextEditor.await()
Expand Down
2 changes: 1 addition & 1 deletion iOSClient/Account/NCAccount.swift
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ class NCAccount: NSObject {
return
}

await showErrorBanner(controller: controller, text: "_account_unauthorized_", errorCode: NCGlobal.shared.errorUnauthorized401)
await showErrorBanner(controller: controller, text: String(format: NSLocalizedString("_account_unauthorized_", comment: ""), account), errorCode: NCGlobal.shared.errorUnauthorized401)

let resultsWipe = await NextcloudKit.shared.getRemoteWipeStatusAsync(serverUrl: tblAccount.urlBase, token: token, account: account) { task in
Task {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
// SPDX-FileCopyrightText: Nextcloud GmbH
// SPDX-FileCopyrightText: 2026 Milen Pivchev
// SPDX-License-Identifier: GPL-3.0-or-later

import Foundation
import SwiftUI
import NextcloudKit

struct NCAssistantChatConversations: View {
var conversationsModel: NCAssistantChatConversationsModel
var selectedConversation: AssistantConversation?
var onConversationSelected: (AssistantConversation?) -> Void

@Environment(\.dismiss) private var dismiss

var body: some View {
Group {
List(conversationsModel.conversations, id: \.id) { conversation in
Button {
onConversationSelected(conversation)
dismiss()
} label: {
HStack {
Text(conversation.validTitle)
Spacer()
if selectedConversation?.id == conversation.id {
Image(systemName: "checkmark")
.foregroundStyle(.blue)
}
}
.contentShape(Rectangle())
}
}
}
.navigationTitle(NSLocalizedString("_conversations_", comment: ""))
.toolbar {
ToolbarItem(placement: .topBarTrailing) {
Button("_new_conversation_", systemImage: "plus.message.fill") {
Task {
let session = await conversationsModel.createNewConversation()
onConversationSelected(session)
dismiss()
}
}
}
}
}
}

#Preview {
NCAssistantChatConversations(conversationsModel: NCAssistantChatConversationsModel(controller: nil), selectedConversation: nil, onConversationSelected: { _ in })
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-FileCopyrightText: Nextcloud GmbH
// SPDX-FileCopyrightText: 2026 Milen Pivchev
// SPDX-License-Identifier: GPL-3.0-or-later

import Foundation
import NextcloudKit

@Observable class NCAssistantChatConversationsModel {
var conversations: [AssistantConversation] = []
var isLoading: Bool = false
var hasError: Bool = false

private let ncSession: NCSession.Session

init(controller: NCMainTabBarController?) {
self.ncSession = NCSession.shared.getSession(controller: controller)
loadAllSessions()
}

func loadAllSessions() {
Task {
let result = await NextcloudKit.shared.getAssistantChatConversations(account: ncSession.account)
conversations = result.sessions ?? []
}
}

func createNewConversation(title: String? = nil) async -> AssistantConversation? {
let timestamp = Int(Date().timeIntervalSince1970)
let result = await NextcloudKit.shared.createAssistantChatConversation(title: title, timestamp: timestamp, account: ncSession.account)
if result.error == .success, let newConversation = result.conversation?.conversation {
conversations.insert(newConversation, at: 0)
return newConversation
} else {
hasError = true
return nil
}
}
}
Loading
Loading