Files
Luma/Sources/Shared/UI/GroupInfoView.swift
T
2026-07-30 20:07:51 +07:00

122 lines
4.8 KiB
Swift

import Foundation
import SwiftUI
@MainActor
struct GroupInfoView: View {
@ObservedObject var model: AppModel
let conversation: Conversation
@Environment(\.dismiss) private var dismiss
@State private var nickname: String
@State private var invitees = ""
@State private var isJoining = false
@State private var isInviting = false
init(model: AppModel, conversation: Conversation) {
self.model = model
self.conversation = conversation
_nickname = State(initialValue: conversation.groupNickname ?? model.suggestedGroupNickname)
}
var body: some View {
NavigationStack {
Form {
Section("Групповой чат") {
LabeledContent("Комната", value: conversation.jid)
LabeledContent("Состояние", value: liveConversation.isGroupJoined ? "Подключено" : "Не подключено")
LabeledContent("Участников", value: "\(liveConversation.occupantCount)")
TextField("Ваш псевдоним", text: $nickname)
.disabled(liveConversation.isGroupJoined)
}
if !liveConversation.isGroupJoined {
Section {
Button {
join()
} label: {
Label(liveConversation.invitedBy == nil ? "Войти в комнату" : "Принять приглашение", systemImage: "person.2.fill")
}
.disabled(nickname.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty || isJoining)
} footer: {
if let inviter = liveConversation.invitedBy {
Text("Приглашение от \(inviter)")
}
}
} else {
Section("Пригласить участников") {
TextField("user@example.org, ещё@example.org", text: $invitees, axis: .vertical)
.lineLimit(2...4)
Button {
invite()
} label: {
if isInviting {
ProgressView()
} else {
Label("Отправить приглашения", systemImage: "person.badge.plus")
}
}
.disabled(parsedInvitees.isEmpty || isInviting)
}
Section {
Button(role: .destructive) {
model.leaveGroup(jid: conversation.jid)
dismiss()
} label: {
Label("Покинуть комнату", systemImage: "rectangle.portrait.and.arrow.right")
}
}
}
Section {
Label(
model.encryptionEnabled(for: conversation.jid)
? "Для комнаты включено OMEMO. Нужны неанонимный MUC и OMEMO-устройства у всех участников."
: "OMEMO для этой комнаты выключено: сообщения передаются открытым текстом внутри TLS.",
systemImage: model.encryptionEnabled(for: conversation.jid) ? "lock.fill" : "lock.open"
)
.font(.footnote)
.foregroundStyle(.secondary)
}
}
.navigationTitle(conversation.displayName)
.toolbar {
ToolbarItem(placement: .confirmationAction) {
Button("Готово") { dismiss() }
}
}
}
#if os(macOS)
.frame(minWidth: 480, minHeight: 500)
#endif
}
private var liveConversation: Conversation {
model.conversations.first(where: { $0.id == conversation.id }) ?? conversation
}
private var parsedInvitees: [String] {
invitees.components(separatedBy: CharacterSet(charactersIn: ",;\n \t"))
.filter { !$0.isEmpty }
}
private func join() {
isJoining = true
Task {
await model.joinGroup(jid: conversation.jid, nickname: nickname)
isJoining = false
}
}
private func invite() {
let outgoing = parsedInvitees
guard !outgoing.isEmpty else { return }
isInviting = true
Task {
await model.inviteMembers(outgoing, to: conversation.jid)
invitees = ""
isInviting = false
}
}
}