This commit is contained in:
Woit 2024-11-22 14:12:09 +01:00
parent ad7a2b4f59
commit d1e3bc54bf
6 changed files with 138 additions and 145 deletions

View file

@ -1411,7 +1411,7 @@
name = tools;
sourceTree = "<group>";
};
29B97314FDCFA39411CA2CEA = {
29B97314FDCFA39411CA2CEA /* CustomTemplate */ = {
isa = PBXGroup;
children = (
8414ADF92A7ABAC900EFFCCC /* Packages */,
@ -2064,7 +2064,7 @@
eu,
"es-AR",
);
mainGroup = 29B97314FDCFA39411CA2CEA;
mainGroup = 29B97314FDCFA39411CA2CEA /* CustomTemplate */;
packageReferences = (
C1F5C7AD2777638B0001F295 /* XCRemoteSwiftPackageReference "swift-collections" */,
841898A82957712000FEC77D /* XCRemoteSwiftPackageReference "ViewExtractor" */,

View file

@ -11,7 +11,7 @@ struct AddContactOrChannelScreen: View {
@FocusState private var focus: Field?
// @State private var ownerCredentials: Credentials?
@State private var ownerAccount: Account?
@State private var contactJID: String = ""
var body: some View {
@ -56,13 +56,13 @@ struct AddContactOrChannelScreen: View {
.frame(alignment: .leading)
Spacer()
}
// UniversalInputCollection.DropDownMenu(
// prompt: "Use account",
// elements: activeClientsCredentials,
// selected: $ownerCredentials,
// focus: $focus,
// fieldType: .account
// )
UniversalInputCollection.DropDownMenu(
prompt: "Use account",
elements: wrapper.accounts,
selected: $ownerAccount,
focus: $focus,
fieldType: .account
)
// Contact text input
HStack(spacing: 0) {
@ -72,18 +72,18 @@ struct AddContactOrChannelScreen: View {
.frame(alignment: .leading)
Spacer()
}
// UniversalInputCollection.TextField(
// prompt: "Contact or channel JID",
// text: $contactJID,
// focus: $focus,
// fieldType: .contact,
// contentType: .emailAddress,
// keyboardType: .emailAddress,
// submitLabel: .done,
// action: {
// focus = .account
// }
// )
UniversalInputCollection.TextField(
prompt: "Contact or channel JID",
text: $contactJID,
focus: $focus,
fieldType: .contact,
contentType: .emailAddress,
keyboardType: .emailAddress,
submitLabel: .done,
action: {
focus = .account
}
)
// Save button
Button {
@ -94,7 +94,7 @@ struct AddContactOrChannelScreen: View {
Text(L10n.Global.save)
}
.buttonStyle(PrimaryButtonStyle())
// .disabled(!inputValid)
.disabled(!inputValid)
.padding(.top)
Spacer()
}
@ -102,24 +102,18 @@ struct AddContactOrChannelScreen: View {
}
}
.onAppear {
// if let exists = activeClientsCredentials.first {
// ownerCredentials = exists
// }
if let exists = wrapper.accounts.first {
ownerAccount = exists
}
}
}
// private var activeClientsCredentials: [Credentials] {
// clientsStore.clients
// .filter { $0.state != .disabled }
// .map { $0.credentials }
// }
private var inputValid: Bool {
ownerAccount != nil && !contactJID.isEmpty && UniversalInputCollection.Validators.isEmail(contactJID)
}
// private var inputValid: Bool {
// ownerCredentials != nil && !contactJID.isEmpty && UniversalInputCollection.Validators.isEmail(contactJID)
// }
//
private func save() async {
// guard let ownerCredentials = ownerCredentials else { return }
guard let ownerAccount = ownerAccount else { return }
router.showModal {
LoadingScreen()

View file

@ -26,94 +26,68 @@ struct ContactsScreen: View {
)
// Contacts list
// if !clientsStore.actualRosters.isEmpty {
// List {
// ForEach(elements.indices, id: \.self) { index in
// let element = elements[index]
// if let roster = element as? Roster {
// ContactsScreenRow(
// roster: roster
// )
// } else if let bareJid = element as? String {
// SharedSectionTitle(text: bareJid)
// }
// }
// }
// .listStyle(.plain)
// .background(Color.Material.Background.light)
// } else {
// Spacer()
// }
if !wrapper.contacts.isEmpty {
List {
ForEach(wrapper.contacts) {
ContactsScreenRow(contact: $0)
}
}
.listStyle(.plain)
.background(Color.Material.Background.light)
} else {
Spacer()
}
}
}
}
private var elements: [Any] {
[]
// if clientsStore.clients.filter({ $0.credentials.isActive }).count == 1 {
// return clientsStore.actualRosters
// } else {
// var result: [Any] = []
// for roster in clientsStore.actualRosters {
// if result.isEmpty {
// result.append(roster.bareJid)
// } else if let last = result.last as? Roster, last.bareJid != roster.bareJid {
// result.append(roster.bareJid)
// }
// result.append(roster)
// }
// return result
// }
}
}
private struct ContactsScreenRow: View {
@EnvironmentObject var wrapper: MonalXmppWrapper
@Environment(\.router) var router
// var roster: Roster
var contact: Contact
var body: some View {
Text("nothing for now")
// SharedListRow(
// iconType: .charCircle(roster.name?.firstLetter ?? roster.contactBareJid.firstLetter),
// text: roster.contactBareJid,
// controlType: .none
// )
// .onTapGesture {
// startChat()
// }
// .swipeActions(edge: .trailing, allowsFullSwipe: false) {
// Button {
// router.showAlert(.confirmationDialog, title: L10n.Contacts.deleteContact, subtitle: L10n.Contacts.Delete.message) {
// deleteConfirmation
// }
// } label: {
// Label("", systemImage: "trash")
// }
// .tint(Color.red)
// }
// .contextMenu {
// Button(L10n.Contacts.sendMessage, systemImage: "message") {
// startChat()
// }
// Divider()
//
// Button(L10n.Contacts.editContact) {
// print("Edit contact")
// }
//
// Button(L10n.Contacts.selectContact) {
// print("Select contact")
// }
//
// Divider()
// Button(L10n.Contacts.deleteContact, systemImage: "trash", role: .destructive) {
// router.showAlert(.confirmationDialog, title: L10n.Contacts.deleteContact, subtitle: L10n.Contacts.Delete.message) {
// deleteConfirmation
// }
// }
// }
SharedListRow(
iconType: .charCircle(contact.name?.firstLetter ?? contact.contactJid.firstLetter),
text: contact.contactJid,
controlType: .none
)
.onTapGesture {
startChat()
}
.swipeActions(edge: .trailing, allowsFullSwipe: false) {
Button {
router.showAlert(.confirmationDialog, title: L10n.Contacts.deleteContact, subtitle: L10n.Contacts.Delete.message) {
deleteConfirmation
}
} label: {
Label("", systemImage: "trash")
}
.tint(Color.red)
}
.contextMenu {
Button(L10n.Contacts.sendMessage, systemImage: "message") {
startChat()
}
Divider()
Button(L10n.Contacts.editContact) {
print("Edit contact")
}
Button(L10n.Contacts.selectContact) {
print("Select contact")
}
Divider()
Button(L10n.Contacts.deleteContact, systemImage: "trash", role: .destructive) {
router.showAlert(.confirmationDialog, title: L10n.Contacts.deleteContact, subtitle: L10n.Contacts.Delete.message) {
deleteConfirmation
}
}
}
}
@ViewBuilder private var deleteConfirmation: some View {

View file

@ -27,8 +27,7 @@ struct MainTabScreen: View {
// ChatsListScreen()
case .contacts:
Text("contacts")
// ContactsScreen()
ContactsScreen()
case .settings:
Text("settings")

View file

@ -1,5 +1,8 @@
import Foundation
import monalxmpp
import SwiftUI
// MARK: - Account
enum AccountsAvailability {
case noAccounts
case allDisabled
@ -32,8 +35,22 @@ struct Account: Identifiable {
}
}
struct Contact: Identifiable {
let jid: String
var id: String { jid }
extension Account: UniversalInputSelectionElement {
var icon: Image? { nil }
var text: String? { jid }
}
// MARK: - Contact
struct Contact: Identifiable {
let ownerId: Int
let contactJid: String
let name: String?
var id: String { contactJid }
init?(_ obj: MLContact) {
ownerId = obj.accountID.intValue
contactJid = obj.contactJid
name = obj.nickName
}
}

View file

@ -10,7 +10,6 @@ final class MonalXmppWrapper: ObservableObject {
private let db: DataLayer
private var notificationObservers: [AnyObject] = []
private var isInitialized: Bool = false
init() {
// here is some inits (just for now)
@ -88,33 +87,43 @@ private final class LoginTry {
// MARK: - Handle notifications
private extension MonalXmppWrapper {
func subscribeToUpdates() {
// General
let generalRefresh = NotificationCenter.default.addObserver(forName: Notification.Name(kMonalRefresh), object: nil, queue: .main) { [weak self] _ in
// get accounts
let accounts = self?.db.accountList()
.compactMap { dict -> Account? in
guard let dict = dict as? NSDictionary else { return nil }
return Account(dict)
} ?? []
self?.accounts = accounts
// start connect if it initialization process
if !(self?.isInitialized ?? true) {
self?.xmpp.reconnectAll()
self?.isInitialized = true
}
// mark accounts availability
if accounts.isEmpty {
self?.accountsAvailability = .noAccounts
} else if !accounts.filter({ $0.isEnabled }).isEmpty {
self?.accountsAvailability = .allDisabled
} else {
self?.accountsAvailability = .someEnabled
}
// get contacts for active accounts
//
self?.refreshAccounts()
self?.refreshContacts()
}
notificationObservers.append(generalRefresh)
// For contacts
let contactRefresh = NotificationCenter.default.addObserver(forName: Notification.Name(kMonalContactRefresh), object: nil, queue: .main) { [weak self] _ in
self?.refreshContacts()
}
let contactRemove = NotificationCenter.default.addObserver(forName: Notification.Name(kMonalContactRemoved), object: nil, queue: .main) { [weak self] _ in
self?.refreshContacts()
}
notificationObservers.append(contentsOf: [contactRefresh, contactRemove])
}
func refreshAccounts() {
let accounts = db.accountList()
.compactMap { dict -> Account? in
guard let dict = dict as? NSDictionary else { return nil }
return Account(dict)
}
self.accounts = accounts
xmpp.connectIfNecessary()
// mark accounts availability
if accounts.isEmpty {
accountsAvailability = .noAccounts
} else if accounts.filter({ $0.isEnabled }).isEmpty {
accountsAvailability = .allDisabled
} else {
accountsAvailability = .someEnabled
}
}
func refreshContacts() {
contacts = db.contactList().compactMap { Contact($0) }
}
}