diff --git a/ConversationsClassic/AppData/Store/ConversationStore.swift b/ConversationsClassic/AppData/Store/ConversationStore.swift index f2fd796..3d79f2c 100644 --- a/ConversationsClassic/AppData/Store/ConversationStore.swift +++ b/ConversationsClassic/AppData/Store/ConversationStore.swift @@ -67,6 +67,40 @@ extension ConversationStore { func sendCaptured(_ data: Data, _ type: GalleryMediaType) async { print("captured!", data, type) + // + // + // + } + + func sendDocuments(_ data: [Data], _ extensions: [String]) async { + print("documents!", data, extensions) + // + // + // + } + + func sendContact(_ jidStr: String) async { + print("contact!", jidStr) + // + // + // + } +} + +extension ConversationStore { + var contacts: [Roster] { + get async { + do { + let rosters = try await Database.shared.dbQueue.read { db in + try Roster + .filter(Column("locallyDeleted") == false) + .fetchAll(db) + } + return rosters + } catch { + return [] + } + } } } diff --git a/ConversationsClassic/View/Main/Conversation/Attachments/AttachmentPickerScreen.swift b/ConversationsClassic/View/Main/Conversation/Attachments/AttachmentPickerScreen.swift index aa07b3b..eb27f0b 100644 --- a/ConversationsClassic/View/Main/Conversation/Attachments/AttachmentPickerScreen.swift +++ b/ConversationsClassic/View/Main/Conversation/Attachments/AttachmentPickerScreen.swift @@ -39,16 +39,14 @@ struct AttachmentPickerScreen: View { .environmentObject(attachmentsStore) case .files: - Color.blue - // SharingFilesPickerView() + FilesPickerView() case .location: Color.green // SharingLocationPickerView() case .contacts: - Color.yellow - // SharingContactsPickerView() + ContactsPickerView() } // Tab bar diff --git a/ConversationsClassic/View/Main/Conversation/Attachments/ContactsPicker/ContactsPickerView.swift b/ConversationsClassic/View/Main/Conversation/Attachments/ContactsPicker/ContactsPickerView.swift new file mode 100644 index 0000000..c0b4a06 --- /dev/null +++ b/ConversationsClassic/View/Main/Conversation/Attachments/ContactsPicker/ContactsPickerView.swift @@ -0,0 +1,71 @@ +import SwiftUI + +struct ContactsPickerView: View { + @Environment(\.router) var router + @EnvironmentObject var conversation: ConversationStore + + @State private var rosters: [Roster] = [] + @State private var selectedContact: Roster? + + var body: some View { + VStack(spacing: 0) { + // Contacts list + if !rosters.isEmpty { + List { + ForEach(rosters) { roster in + ContactRow(roster: roster, selectedContact: $selectedContact) + } + } + .listStyle(.plain) + .background(Color.Material.Background.light) + } else { + Spacer() + } + + // Send panel + Rectangle() + .foregroundColor(.Material.Shape.black) + .frame(maxWidth: .infinity) + .frame(height: selectedContact == nil ? 0 : 50) + .overlay { + HStack { + Text(L10n.Attachment.Send.contact) + .foregroundColor(.Material.Text.white) + .font(.body1) + Image(systemName: "arrow.up.circle") + .foregroundColor(.Material.Text.white) + .font(.body1) + .padding(.leading, 8) + } + .padding() + } + .clipped() + .onTapGesture { + if let selectedContact = selectedContact { + Task { + await conversation.sendContact(selectedContact.contactBareJid) + } + router.dismissEnvironment() + } + } + } + .task { + rosters = await conversation.contacts + } + } +} + +private struct ContactRow: View { + var roster: Roster + @Binding var selectedContact: Roster? + + var body: some View { + SharedListRow( + iconType: .charCircle(roster.name?.firstLetter ?? roster.contactBareJid.firstLetter), + text: roster.contactBareJid + ) + .onTapGesture { + selectedContact = roster + } + } +} diff --git a/ConversationsClassic/View/Main/Conversation/Attachments/FilesPicker/FilesPickerView.swift b/ConversationsClassic/View/Main/Conversation/Attachments/FilesPicker/FilesPickerView.swift new file mode 100644 index 0000000..d041667 --- /dev/null +++ b/ConversationsClassic/View/Main/Conversation/Attachments/FilesPicker/FilesPickerView.swift @@ -0,0 +1,67 @@ +import SwiftUI +import UIKit + +struct FilesPickerView: View { + @Environment(\.router) var router + @EnvironmentObject var conversation: ConversationStore + + var body: some View { + DocumentPicker( + completion: { dataArray, extensionsArray in + Task { + await conversation.sendDocuments(dataArray, extensionsArray) + } + router.dismissEnvironment() + }, + cancel: { + router.dismissEnvironment() + } + ) + } +} + +struct DocumentPicker: UIViewControllerRepresentable { + let completion: ([Data], [String]) -> Void + let cancel: () -> Void + + func makeUIViewController(context: UIViewControllerRepresentableContext) -> UIDocumentPickerViewController { + let picker: UIDocumentPickerViewController + picker = UIDocumentPickerViewController(forOpeningContentTypes: [.item], asCopy: true) + picker.delegate = context.coordinator + picker.allowsMultipleSelection = true + return picker + } + + func updateUIViewController(_: UIDocumentPickerViewController, context _: UIViewControllerRepresentableContext) {} + + func makeCoordinator() -> Coordinator { + Coordinator(self) + } + + class Coordinator: NSObject, UIDocumentPickerDelegate { + var parent: DocumentPicker + + init(_ parent: DocumentPicker) { + self.parent = parent + } + + func documentPicker(_: UIDocumentPickerViewController, didPickDocumentsAt: [URL]) { + var dataArray = [Data]() + var extensionArray = [String]() + for url in didPickDocumentsAt { + do { + let data = try Data(contentsOf: url) + dataArray.append(data) + extensionArray.append(url.pathExtension) + } catch { + print("Unable to load data from \(url): \(error)") + } + } + parent.completion(dataArray, extensionArray) + } + + func documentPickerWasCancelled(_: UIDocumentPickerViewController) { + parent.cancel() + } + } +}