From 30164f648e90511daf829dae6bac6c141dfc9b7d Mon Sep 17 00:00:00 2001 From: Jan Stoyke <michael-jan.stoyke@tu-ilmenau.de> Date: Sat, 18 Nov 2023 04:18:04 +0100 Subject: [PATCH] WIP: Create group skeleton --- Monal/Classes/ContactList.swift | 83 +++++++++++++ Monal/Classes/ContactsViewController.m | 13 +- Monal/Classes/ContactsViewController.m.rej | 14 +++ Monal/Classes/CreateGroupMenu.swift | 116 ++++++++++++++++++ ...ownloadFiletransferSettingViewController.m | 2 +- Monal/Classes/MLMessageProcessor.m | 2 +- Monal/Classes/SwiftuiHelpers.swift | 4 + Monal/Monal.xcodeproj/project.pbxproj | 8 ++ 8 files changed, 239 insertions(+), 3 deletions(-) create mode 100644 Monal/Classes/ContactList.swift create mode 100644 Monal/Classes/ContactsViewController.m.rej create mode 100644 Monal/Classes/CreateGroupMenu.swift diff --git a/Monal/Classes/ContactList.swift b/Monal/Classes/ContactList.swift new file mode 100644 index 0000000000..e0c1792a83 --- /dev/null +++ b/Monal/Classes/ContactList.swift @@ -0,0 +1,83 @@ +// +// ContactList.swift +// Monal +// +// Created by Jan on 15.12.22. +// Copyright © 2022 monal-im.org. All rights reserved. +// + +import SwiftUI +import monalxmpp + +struct ContactEntry: View { + let contact : MLContact + + var body:some View { + ZStack(alignment: .topLeading) { + HStack(alignment: .center) { + Image(uiImage: contact.avatar) + .resizable() + .frame(width: 40, height: 40, alignment: .center) + VStack(alignment: .leading) { + Text(contact.contactDisplayName as String) + Text(contact.contactJid as String).font(.footnote).opacity(0.6) + } + } + } + } +} + +struct ContactList: View { + @State var contacts : [MLContact] + @State var selectedContact : MLContact? + @State var searchFieldInput = "" + + func matchesSearch(contact : MLContact) -> Bool { + // TODO better lookup + if searchFieldInput.isEmpty == true { + return true + } else { + return contact.contactDisplayName.lowercased().contains(searchFieldInput.lowercased()) || + contact.contactJid.contains(searchFieldInput.lowercased()) + } + } + + var body: some View { + if(contacts.isEmpty) { + Text("No contacts to show :(") + .navigationTitle("Contact Lists") + } else { + List { + Section { + TextField("Search contacts", text: $searchFieldInput) + } + ForEach(contacts, id: \.self) { contact in + if matchesSearch(contact: contact) { + ContactEntry(contact: contact) + } + } + .onDelete { + print(contacts.remove(atOffsets: $0)) + } + .onInsert(of: [""], perform: { _,_ in + }) + } + .listStyle(.inset) + .navigationBarTitle("Contact List", displayMode: .inline) + .toolbar { + EditButton() + } + } + } +} + +struct ContactList_Previews: PreviewProvider { + static var previews: some View { + ContactList(contacts: [ + MLContact.makeDummyContact(0), + MLContact.makeDummyContact(1), + MLContact.makeDummyContact(2), + MLContact.makeDummyContact(3)] + ) + } +} diff --git a/Monal/Classes/ContactsViewController.m b/Monal/Classes/ContactsViewController.m index a76551ba1a..dd71765da4 100644 --- a/Monal/Classes/ContactsViewController.m +++ b/Monal/Classes/ContactsViewController.m @@ -47,7 +47,13 @@ -(void) openAddContacts:(id)sender [self presentViewController:addContactMenuView animated:YES completion:^{}]; } --(void) openContactRequests:(id)sender +-(void) openCreateGroup:(id) sender +{ + UIViewController* createGroupView = [[SwiftuiInterface new] makeViewWithName:@"CreateGroup"]; + [self presentViewController:createGroupView animated:YES completion:^{}]; +} + +-(void) openContactRequests:(id) sender { UIViewController* contactRequestsView = [[SwiftuiInterface new] makeViewWithName:@"ContactRequests"]; [self presentViewController:contactRequestsView animated:YES completion:^{}]; @@ -100,6 +106,11 @@ -(void) viewDidLoad [addContact setAction:@selector(openAddContacts:)]; self.navigationItem.rightBarButtonItems = [[NSArray alloc] initWithObjects:addContact, [UIBarButtonItem new], nil]; + UIBarButtonItem* createGroup = [[UIBarButtonItem alloc] init]; + createGroup.image = [UIImage systemImageNamed:@"person.3.fill"]; + [createGroup setAction:@selector(openCreateGroup:)]; + + self.navigationItem.rightBarButtonItems = [[NSArray alloc] initWithObjects:addContact, [[UIBarButtonItem alloc] init], createGroup, nil]; [self configureContactRequestsImage]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleContactUpdate) name:kMonalContactRemoved object:nil]; diff --git a/Monal/Classes/ContactsViewController.m.rej b/Monal/Classes/ContactsViewController.m.rej new file mode 100644 index 0000000000..2bcb0d25b8 --- /dev/null +++ b/Monal/Classes/ContactsViewController.m.rej @@ -0,0 +1,14 @@ +diff a/Monal/Classes/ContactsViewController.m b/Monal/Classes/ContactsViewController.m (rejected hunks) +@@ -99,7 +105,11 @@ -(void) viewDidLoad + addContact.image = [UIImage systemImageNamed:@"person.fill.badge.plus"]; + [addContact setAction:@selector(openAddContacts:)]; + +- self.navigationItem.rightBarButtonItems = [[NSArray alloc] initWithObjects:addContact, [[UIBarButtonItem alloc] init], nil]; ++ UIBarButtonItem* createGroup = [[UIBarButtonItem alloc] init]; ++ createGroup.image = [UIImage systemImageNamed:@"person.3.fill"]; ++ [createGroup setAction:@selector(openCreateGroup:)]; ++ ++ self.navigationItem.rightBarButtonItems = [[NSArray alloc] initWithObjects:addContact, [[UIBarButtonItem alloc] init], createGroup, nil]; + [self configureContactRequestsImage]; + + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(handleContactUpdate) name:kMonalContactRemoved object:nil]; diff --git a/Monal/Classes/CreateGroupMenu.swift b/Monal/Classes/CreateGroupMenu.swift new file mode 100644 index 0000000000..f55f1f01a5 --- /dev/null +++ b/Monal/Classes/CreateGroupMenu.swift @@ -0,0 +1,116 @@ +// +// AddContactMenu.swift +// Monal +// +// Created by Jan on 27.10.22. +// Copyright © 2022 monal-im.org. All rights reserved. +// + +import MobileCoreServices +import UniformTypeIdentifiers +import SwiftUI +import monalxmpp + +struct CreateGroupMenu: View { + var delegate: SheetDismisserProtocol + + @State private var connectedAccounts: [xmpp] + @State private var selectedAccount: Int + @State private var groupName: String = "" + + @State private var showAlert = false + // note: dismissLabel is not accessed but defined at the .alert() section + @State private var alertPrompt = AlertPrompt(dismissLabel: Text("Close")) + + @ObservedObject private var overlay = LoadingOverlayState() + + @State private var showQRCodeScanner = false + @State private var success = false + + private let dismissWithNewGroup: (MLContact) -> () + + init(delegate: SheetDismisserProtocol, dismissWithNewGroup: @escaping (MLContact) -> (), prefillJid: String = "", preauthToken:String? = nil) { + // FIXME + self.delegate = delegate + self.dismissWithNewGroup = dismissWithNewGroup + self.groupName = prefillJid + // self.preauthToken = preauthToken + + let connectedAccounts = MLXMPPManager.sharedInstance().connectedXMPP as! [xmpp] + self.connectedAccounts = connectedAccounts + self.selectedAccount = connectedAccounts.first != nil ? 0 : -1; + } + + // FIXME duplicate code from WelcomeLogIn.swift, maybe move to SwiftuiHelpers + + private func errorAlert(title: Text, message: Text = Text("")) { + alertPrompt.title = title + alertPrompt.message = message + showAlert = true + } + + private func successAlert(title: Text, message: Text) { + alertPrompt.title = title + alertPrompt.message = message + self.success = true // < dismiss entire view on close + showAlert = true + } + + private var buttonColor: Color { + return Color(UIColor.systemBlue) + } + + var body: some View { + Form { + if(connectedAccounts.isEmpty) { + Text("Please make sure at least one account has connected before trying to create new group.") + .foregroundColor(.secondary) + } + else + { + Section() { + if(connectedAccounts.count > 1) { + Picker("Use account", selection: $selectedAccount) { + ForEach(Array(self.connectedAccounts.enumerated()), id: \.element) { idx, account in + Text(account.connectionProperties.identity.jid).tag(idx) + } + } + .pickerStyle(.menu) + } + TextField("Group Name (optional)", text: $groupName) + .autocorrectionDisabled() + .autocapitalization(.none) + .addClearButton(text:$groupName) + + NavigationLink(destination: LazyClosureView(ContactList(contacts: DataLayer.sharedInstance().contactList() as! [MLContact])), label: { + Text("Group Members") + }) + } + Section { + Button(action: {}, label: { + Text("Create new group") + }) + } + } + } + .alert(isPresented: $showAlert) { + Alert(title: alertPrompt.title, message: alertPrompt.message, dismissButton:.default(Text("Close"), action: { + showAlert = false + if self.success == true { + // TODO dismissWithNewGroup + } + })) + } + .addLoadingOverlay(overlay) + .navigationBarTitle("Create new group", displayMode: .inline) + .navigationViewStyle(.stack) + } +} + +struct CreateGroupMenu_Previews: PreviewProvider { + static var delegate = SheetDismisserProtocol() + static var previews: some View { + CreateGroupMenu(delegate: delegate, dismissWithNewGroup: { c in + }) + } +} diff --git a/Monal/Classes/MLAutoDownloadFiletransferSettingViewController.m b/Monal/Classes/MLAutoDownloadFiletransferSettingViewController.m index 124b2a6ae5..45729bc7d7 100644 --- a/Monal/Classes/MLAutoDownloadFiletransferSettingViewController.m +++ b/Monal/Classes/MLAutoDownloadFiletransferSettingViewController.m @@ -106,7 +106,7 @@ -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NS // byte -> mb float mb = sliderValue / 1024 / 1024; labelToUpdate.text = [NSString stringWithFormat:NSLocalizedString(@"Load over WiFi upto: %.fMB", @""), mb]; - + return mb; } withUpdateFunc:^(UILabel* labelToUpdate, float sliderValue) { float newValue = roundf(sliderValue); diff --git a/Monal/Classes/MLMessageProcessor.m b/Monal/Classes/MLMessageProcessor.m index 9ca0c08e02..5267e6f86c 100644 --- a/Monal/Classes/MLMessageProcessor.m +++ b/Monal/Classes/MLMessageProcessor.m @@ -774,7 +774,7 @@ +(MLMessage* _Nullable) processMessage:(XMPPMessage*) messageNode andOuterMessag } } } - + return message; } diff --git a/Monal/Classes/SwiftuiHelpers.swift b/Monal/Classes/SwiftuiHelpers.swift index 645e21dedf..bd9bc8390d 100644 --- a/Monal/Classes/SwiftuiHelpers.swift +++ b/Monal/Classes/SwiftuiHelpers.swift @@ -473,6 +473,10 @@ class SwiftuiInterface : NSObject { host.rootView = AnyView(UIKitWorkaround(WelcomeLogIn(delegate:delegate))) case "ContactRequests": host.rootView = AnyView(AddTopLevelNavigation(withDelegate: delegate, to: ContactRequestsMenu(delegate: delegate))) + case "CreateGroup": + host.rootView = AnyView(AddTopLevelNavigation(withDelegate: delegate, to: CreateGroupMenu(delegate: delegate, dismissWithNewGroup: { contact in + // FIXME + }))) case "ChatPlaceholder": host.rootView = AnyView(ChatPlaceholder()) default: diff --git a/Monal/Monal.xcodeproj/project.pbxproj b/Monal/Monal.xcodeproj/project.pbxproj index 0a46648240..0df43c2aa2 100644 --- a/Monal/Monal.xcodeproj/project.pbxproj +++ b/Monal/Monal.xcodeproj/project.pbxproj @@ -172,6 +172,8 @@ C1049189261301530054AC9E /* MonalXMPPUnitTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1049188261301530054AC9E /* MonalXMPPUnitTests.swift */; }; C104918B261301530054AC9E /* monalxmpp.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 26CC579223A0867400ABB92A /* monalxmpp.framework */; }; C1049199261301710054AC9E /* MLCryptoTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = C1049198261301710054AC9E /* MLCryptoTest.swift */; }; + C117F7E12B086390001F2BC6 /* CreateGroupMenu.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D88BB76295BB6DC00FB30BA /* CreateGroupMenu.swift */; }; + C117F7E22B0863B3001F2BC6 /* ContactList.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3D631822294BAB1D00026BE7 /* ContactList.swift */; }; C12436142434AB5D00B8F074 /* MLAttributedLabel.m in Sources */ = {isa = PBXBuildFile; fileRef = C12436132434AB5D00B8F074 /* MLAttributedLabel.m */; }; C13A0BCE26E78B7B00987E29 /* ContactDetailsHeader.swift in Sources */ = {isa = PBXBuildFile; fileRef = C19C919A26E26AF000F8CC57 /* ContactDetailsHeader.swift */; }; C13EBB8E24DC685C008AADDA /* MLPrivacySettingsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C13EBB8D24DC685C008AADDA /* MLPrivacySettingsViewController.m */; }; @@ -500,10 +502,12 @@ 3D27D955290B0BB60014748B /* AddContactMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AddContactMenu.swift; sourceTree = "<group>"; }; 3D27D957290B0BC80014748B /* ContactRequestsMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactRequestsMenu.swift; sourceTree = "<group>"; }; 3D5A91412842B4AE008CE57E /* MemberList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MemberList.swift; sourceTree = "<group>"; }; + 3D631822294BAB1D00026BE7 /* ContactList.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactList.swift; sourceTree = "<group>"; }; 3D65B78C27234B74005A30F4 /* ContactDetails.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContactDetails.swift; sourceTree = "<group>"; }; 3D65B790272350F0005A30F4 /* SwiftuiHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftuiHelpers.swift; sourceTree = "<group>"; }; 3D7D352228626CB80042C5E5 /* LoadingOverlay.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LoadingOverlay.swift; sourceTree = "<group>"; }; 3D85E586282AE523006F5B3A /* OmemoQrCodeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OmemoQrCodeView.swift; sourceTree = "<group>"; }; + 3D88BB76295BB6DC00FB30BA /* CreateGroupMenu.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CreateGroupMenu.swift; sourceTree = "<group>"; }; 3DC5035B2822F5220064C8A7 /* OmemoKeys.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = OmemoKeys.swift; sourceTree = "<group>"; }; 3EB7A7084FA9A8F68A3D251C /* Pods-MonalXMPPUnitTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-MonalXMPPUnitTests.debug.xcconfig"; path = "Target Support Files/Pods-MonalXMPPUnitTests/Pods-MonalXMPPUnitTests.debug.xcconfig"; sourceTree = "<group>"; }; 4049F81F60EA5B7A57A4E9C6 /* Pods-NotificationService.beta.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-NotificationService.beta.xcconfig"; path = "Target Support Files/Pods-NotificationService/Pods-NotificationService.beta.xcconfig"; sourceTree = "<group>"; }; @@ -1049,7 +1053,9 @@ 26A78ED623C2B59400C7CF40 /* MLPlaceholderViewController.h */, 26A78ED723C2B59400C7CF40 /* MLPlaceholderViewController.m */, 84FC375828981A5600634E3E /* PasswordMigration.swift */, + 3D631822294BAB1D00026BE7 /* ContactList.swift */, 3D27D955290B0BB60014748B /* AddContactMenu.swift */, + 3D88BB76295BB6DC00FB30BA /* CreateGroupMenu.swift */, 3D27D957290B0BC80014748B /* ContactRequestsMenu.swift */, 846DF27B2937FAA600AAB9C0 /* ChatPlaceholder.swift */, 841898AB2957DBAC00FEC77D /* RichAlert.swift */, @@ -2013,6 +2019,7 @@ 841B6F1A297B18720074F9B7 /* AccountPicker.swift in Sources */, 3D65B791272350F0005A30F4 /* SwiftuiHelpers.swift in Sources */, C1A80DA424D9552400B99E01 /* MLChatViewHelper.m in Sources */, + C117F7E22B0863B3001F2BC6 /* ContactList.swift in Sources */, 1D60589B0D05DD56006BFB54 /* main.m in Sources */, 1D3623260D0F684500981E51 /* MonalAppDelegate.m in Sources */, 26158AF21FFA6E4500E53BDC /* MLWebViewController.m in Sources */, @@ -2052,6 +2059,7 @@ C13A0BCE26E78B7B00987E29 /* ContactDetailsHeader.swift in Sources */, 3D85E587282AE523006F5B3A /* OmemoQrCodeView.swift in Sources */, 849A53E4287135B2007E941A /* MLVoIPProcessor.m in Sources */, + C117F7E12B086390001F2BC6 /* CreateGroupMenu.swift in Sources */, 26D59D9320714F32006F1DEE /* UIColor+Theme.m in Sources */, 3D7D352328626CB80042C5E5 /* LoadingOverlay.swift in Sources */, 26D7C05E23D6AFD800CA123C /* MLChatInputContainer.m in Sources */,