ios: add group members when group is created (#857)
* ios: add group members when group is created * refactor * more refactor
This commit is contained in:
committed by
GitHub
parent
4f4935256c
commit
1b8c55a0a3
@@ -73,9 +73,7 @@ struct ChatView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.onTapGesture {
|
||||
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
||||
}
|
||||
.onTapGesture { hideKeyboard() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,15 @@ struct AddGroupMembersView: View {
|
||||
@Environment(\.dismiss) var dismiss: DismissAction
|
||||
var chat: Chat
|
||||
var groupInfo: GroupInfo
|
||||
@State var membersToAdd: [Contact]
|
||||
var membersToAdd: [Contact]
|
||||
var showSkip: Bool = false
|
||||
var addedMembersCb: ((Set<Int64>) -> Void)? = nil
|
||||
@State private var selectedContacts = Set<Int64>()
|
||||
@State private var selectedRole: GroupMemberRole = .admin
|
||||
|
||||
var body: some View {
|
||||
NavigationView {
|
||||
List {
|
||||
let v = List {
|
||||
ChatInfoToolbar(chat: chat, imageSize: 48)
|
||||
.frame(maxWidth: .infinity, alignment: .center)
|
||||
.listRowBackground(Color.clear)
|
||||
@@ -58,7 +60,20 @@ struct AddGroupMembersView: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationBarHidden(true)
|
||||
|
||||
if (showSkip) {
|
||||
v.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
if showSkip {
|
||||
Button ("Skip") {
|
||||
if let cb = addedMembersCb { cb(selectedContacts) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
v.navigationBarHidden(true)
|
||||
}
|
||||
}
|
||||
.frame(maxHeight: .infinity, alignment: .top)
|
||||
}
|
||||
@@ -70,6 +85,7 @@ struct AddGroupMembersView: View {
|
||||
await addMember(groupId: chat.chatInfo.apiId, contactId: contactId, memberRole: selectedRole)
|
||||
}
|
||||
await MainActor.run { dismiss() }
|
||||
if let cb = addedMembersCb { cb(selectedContacts) }
|
||||
}
|
||||
} label: {
|
||||
HStack {
|
||||
|
||||
@@ -35,19 +35,6 @@ struct GroupChatInfoView: View {
|
||||
groupInfoHeader()
|
||||
.listRowBackground(Color.clear)
|
||||
|
||||
if groupInfo.canEdit {
|
||||
Section {
|
||||
Button {
|
||||
showGroupProfile = true
|
||||
} label: {
|
||||
Label("Edit group profile", systemImage: "pencil")
|
||||
}
|
||||
}
|
||||
.sheet(isPresented: $showGroupProfile) {
|
||||
GroupProfileView(groupId: groupInfo.apiId, groupProfile: groupInfo.groupProfile)
|
||||
}
|
||||
}
|
||||
|
||||
Section("\(members.count + 1) members") {
|
||||
if groupInfo.canAddMembers {
|
||||
addMembersButton()
|
||||
@@ -63,8 +50,14 @@ struct GroupChatInfoView: View {
|
||||
.sheet(item: $selectedMember) { member in
|
||||
GroupMemberInfoView(groupInfo: groupInfo, member: member)
|
||||
}
|
||||
.sheet(isPresented: $showGroupProfile) {
|
||||
GroupProfileView(groupId: groupInfo.apiId, groupProfile: groupInfo.groupProfile)
|
||||
}
|
||||
|
||||
Section {
|
||||
if groupInfo.canEdit {
|
||||
editGroupButton()
|
||||
}
|
||||
clearChatButton()
|
||||
if groupInfo.canDelete {
|
||||
deleteGroupButton()
|
||||
@@ -156,6 +149,14 @@ struct GroupChatInfoView: View {
|
||||
}
|
||||
}
|
||||
|
||||
func editGroupButton() -> some View {
|
||||
Button {
|
||||
showGroupProfile = true
|
||||
} label: {
|
||||
Label("Edit group profile", systemImage: "pencil")
|
||||
}
|
||||
}
|
||||
|
||||
func deleteGroupButton() -> some View {
|
||||
Button(role: .destructive) {
|
||||
alert = .deleteGroupAlert
|
||||
|
||||
@@ -24,7 +24,7 @@ struct GroupProfileView: View {
|
||||
|
||||
var body: some View {
|
||||
return VStack(alignment: .leading) {
|
||||
Text("Group profile is stored on members devices.\nSimpleX servers cannot see group profile.")
|
||||
Text("Group profile is stored on members' devices, not on the servers.")
|
||||
.padding(.bottom)
|
||||
|
||||
ZStack(alignment: .center) {
|
||||
@@ -59,7 +59,7 @@ struct GroupProfileView: View {
|
||||
profileNameTextEdit("Group full name (optional)", $groupProfile.fullName)
|
||||
HStack(spacing: 20) {
|
||||
Button("Cancel") { dismiss() }
|
||||
Button("Save") { saveProfile() }
|
||||
Button("Save group profile") { saveProfile() }
|
||||
.disabled(groupProfile.displayName == "" || !validDisplayName(groupProfile.displayName))
|
||||
}
|
||||
}
|
||||
@@ -105,6 +105,8 @@ struct GroupProfileView: View {
|
||||
message: Text("\(saveGroupError ?? "Unexpected error")")
|
||||
)
|
||||
}
|
||||
.contentShape(Rectangle())
|
||||
.onTapGesture { hideKeyboard() }
|
||||
}
|
||||
|
||||
func profileNameTextEdit(_ label: String, _ name: Binding<String>) -> some View {
|
||||
|
||||
@@ -73,8 +73,8 @@ struct ChatPreviewView: View {
|
||||
}
|
||||
|
||||
@ViewBuilder private func groupInactiveIcon() -> some View {
|
||||
Image(systemName: "minus.circle.fill")
|
||||
.foregroundColor(.red)
|
||||
Image(systemName: "multiply.circle.fill")
|
||||
.foregroundColor(.secondary)
|
||||
.background(Circle().foregroundColor(Color(uiColor: .systemBackground)))
|
||||
}
|
||||
|
||||
|
||||
@@ -10,8 +10,10 @@ import SwiftUI
|
||||
import SimpleXChat
|
||||
|
||||
struct AddGroupView: View {
|
||||
@Binding var openedSheet: NewChatAction?
|
||||
@EnvironmentObject var m: ChatModel
|
||||
@Environment(\.dismiss) var dismiss: DismissAction
|
||||
@State private var chat: Chat?
|
||||
@State private var groupInfo: GroupInfo?
|
||||
@State private var profile = GroupProfile(displayName: "", fullName: "")
|
||||
@FocusState private var focusDisplayName
|
||||
@FocusState private var focusFullName
|
||||
@@ -21,6 +23,22 @@ struct AddGroupView: View {
|
||||
@State private var chosenImage: UIImage? = nil
|
||||
|
||||
var body: some View {
|
||||
if let chat = chat, let groupInfo = groupInfo {
|
||||
AddGroupMembersView(chat: chat,
|
||||
groupInfo: groupInfo,
|
||||
membersToAdd: filterMembersToAdd([]),
|
||||
showSkip: true) { _ in
|
||||
dismiss()
|
||||
DispatchQueue.main.async {
|
||||
m.chatId = groupInfo.id
|
||||
}
|
||||
}
|
||||
} else {
|
||||
createGroupView()
|
||||
}
|
||||
}
|
||||
|
||||
func createGroupView() -> some View {
|
||||
VStack(alignment: .leading) {
|
||||
Text("Create secret group")
|
||||
.font(.largeTitle)
|
||||
@@ -129,14 +147,15 @@ struct AddGroupView: View {
|
||||
func createGroup() {
|
||||
hideKeyboard()
|
||||
do {
|
||||
let groupInfo = try apiNewGroup(profile)
|
||||
m.addChat(Chat(chatInfo: .group(groupInfo: groupInfo), chatItems: []))
|
||||
openedSheet = nil
|
||||
DispatchQueue.main.async {
|
||||
m.chatId = groupInfo.id
|
||||
let gInfo = try apiNewGroup(profile)
|
||||
let c = Chat(chatInfo: .group(groupInfo: gInfo), chatItems: [])
|
||||
m.addChat(c)
|
||||
withAnimation {
|
||||
groupInfo = gInfo
|
||||
chat = c
|
||||
}
|
||||
} catch {
|
||||
openedSheet = nil
|
||||
dismiss()
|
||||
AlertManager.shared.showAlert(
|
||||
Alert(
|
||||
title: Text("Error creating group"),
|
||||
@@ -146,18 +165,17 @@ struct AddGroupView: View {
|
||||
}
|
||||
}
|
||||
|
||||
func hideKeyboard() {
|
||||
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
||||
}
|
||||
|
||||
func canCreateProfile() -> Bool {
|
||||
profile.displayName != "" && validDisplayName(profile.displayName)
|
||||
}
|
||||
}
|
||||
|
||||
func hideKeyboard() {
|
||||
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
||||
}
|
||||
|
||||
struct AddGroupView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
@State var openedSheet: NewChatAction? = nil
|
||||
return AddGroupView(openedSheet: $openedSheet)
|
||||
AddGroupView()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,9 +39,9 @@ struct NewChatButton: View {
|
||||
.sheet(item: $actionSheet) { sheet in
|
||||
switch sheet {
|
||||
case .createLink: AddContactView(connReqInvitation: connReq)
|
||||
case .pasteLink: PasteToConnectView(openedSheet: $actionSheet)
|
||||
case .scanQRCode: ScanToConnectView(openedSheet: $actionSheet)
|
||||
case .createGroup: AddGroupView(openedSheet: $actionSheet)
|
||||
case .pasteLink: PasteToConnectView()
|
||||
case .scanQRCode: ScanToConnectView()
|
||||
case .createGroup: AddGroupView()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -64,12 +64,12 @@ enum ConnReqType: Equatable {
|
||||
case invitation
|
||||
}
|
||||
|
||||
func connectViaLink(_ connectionLink: String, _ openedSheet: Binding<NewChatAction?>? = nil) {
|
||||
func connectViaLink(_ connectionLink: String, _ dismiss: DismissAction? = nil) {
|
||||
Task {
|
||||
do {
|
||||
let res = try await apiConnect(connReq: connectionLink)
|
||||
DispatchQueue.main.async {
|
||||
openedSheet?.wrappedValue = nil
|
||||
dismiss?()
|
||||
if let connReqType = res {
|
||||
connectionReqSentAlert(connReqType)
|
||||
}
|
||||
@@ -77,7 +77,7 @@ func connectViaLink(_ connectionLink: String, _ openedSheet: Binding<NewChatActi
|
||||
} catch {
|
||||
logger.error("connectViaLink apiConnect error: \(responseError(error))")
|
||||
DispatchQueue.main.async {
|
||||
openedSheet?.wrappedValue = nil
|
||||
dismiss?()
|
||||
connectionErrorAlert(error)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
import SwiftUI
|
||||
|
||||
struct PasteToConnectView: View {
|
||||
@Binding var openedSheet: NewChatAction?
|
||||
@Environment(\.dismiss) var dismiss: DismissAction
|
||||
@State private var connectionLink: String = ""
|
||||
|
||||
var body: some View {
|
||||
@@ -62,13 +62,12 @@ struct PasteToConnectView: View {
|
||||
}
|
||||
|
||||
private func connect() {
|
||||
connectViaLink(connectionLink.trimmingCharacters(in: .whitespaces), $openedSheet)
|
||||
connectViaLink(connectionLink.trimmingCharacters(in: .whitespaces), dismiss)
|
||||
}
|
||||
}
|
||||
|
||||
struct PasteToConnectView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
@State var openedSheet: NewChatAction? = nil
|
||||
return PasteToConnectView(openedSheet: $openedSheet)
|
||||
PasteToConnectView()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import SwiftUI
|
||||
import CodeScanner
|
||||
|
||||
struct ScanToConnectView: View {
|
||||
@Binding var openedSheet: NewChatAction?
|
||||
@Environment(\.dismiss) var dismiss: DismissAction
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading) {
|
||||
@@ -35,17 +35,16 @@ struct ScanToConnectView: View {
|
||||
func processQRCode(_ resp: Result<ScanResult, ScanError>) {
|
||||
switch resp {
|
||||
case let .success(r):
|
||||
Task { connectViaLink(r.string, $openedSheet) }
|
||||
Task { connectViaLink(r.string, dismiss) }
|
||||
case let .failure(e):
|
||||
logger.error("ConnectContactView.processQRCode QR code error: \(e.localizedDescription)")
|
||||
openedSheet = nil
|
||||
dismiss()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ConnectContactView_Previews: PreviewProvider {
|
||||
static var previews: some View {
|
||||
@State var openedSheet: NewChatAction? = nil
|
||||
return ScanToConnectView(openedSheet: $openedSheet)
|
||||
ScanToConnectView()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,10 +103,6 @@ struct CreateProfile: View {
|
||||
}
|
||||
}
|
||||
|
||||
func hideKeyboard() {
|
||||
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
||||
}
|
||||
|
||||
func canCreateProfile() -> Bool {
|
||||
displayName != "" && validDisplayName(displayName)
|
||||
}
|
||||
|
||||
@@ -92,8 +92,8 @@ struct MakeConnection: View {
|
||||
.sheet(item: $actionSheet) { sheet in
|
||||
switch sheet {
|
||||
case .createLink: AddContactView(connReqInvitation: connReq)
|
||||
case .pasteLink: PasteToConnectView(openedSheet: $actionSheet)
|
||||
case .scanQRCode: ScanToConnectView(openedSheet: $actionSheet)
|
||||
case .pasteLink: PasteToConnectView()
|
||||
case .scanQRCode: ScanToConnectView()
|
||||
case .createGroup: EmptyView() // TODO refactor / show during onboarding?
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user