ios: choose user deletion mode (#1833)

* ios: choose user deletion mode

* update text

* refactor, disable button

* darker profile icon colors

* do not delete active user if changing user failed
This commit is contained in:
Evgeny Poberezkin
2023-01-24 19:00:30 +00:00
committed by GitHub
parent bc1d86e303
commit 93ab713748
6 changed files with 53 additions and 22 deletions
+9 -4
View File
@@ -945,17 +945,22 @@ func startChat() throws {
chatLastStartGroupDefault.set(Date.now)
}
func changeActiveUser(_ toUserId: Int64) {
func changeActiveUser(_ userId: Int64) {
let m = ChatModel.shared
do {
m.currentUser = try apiSetActiveUser(toUserId)
m.users = try listUsers()
try getUserChatData()
try changeActiveUser_(userId)
} catch let error {
logger.error("Unable to set active user: \(responseError(error))")
}
}
func changeActiveUser_(_ userId: Int64) throws {
let m = ChatModel.shared
m.currentUser = try apiSetActiveUser(userId)
m.users = try listUsers()
try getUserChatData()
}
func getUserChatData() throws {
let m = ChatModel.shared
m.userAddress = try apiGetUserAddress()
@@ -80,9 +80,8 @@ struct ChatListView: View {
}
} label: {
let user = chatModel.currentUser ?? User.sampleData
let color = Color(uiColor: .tertiarySystemGroupedBackground)
ZStack(alignment: .topTrailing) {
ProfileImage(imageStr: user.image, color: color)
ProfileImage(imageStr: user.image, color: Color(uiColor: .quaternaryLabel))
.frame(width: 32, height: 32)
.padding(.trailing, 4)
let allRead = chatModel.users
@@ -96,7 +96,7 @@ struct UserPicker: View {
}
}, label: {
HStack(spacing: 0) {
ProfileImage(imageStr: user.image)
ProfileImage(imageStr: user.image, color: Color(uiColor: .tertiarySystemFill))
.frame(width: 44, height: 44)
.padding(.trailing, 12)
Text(user.chatViewName)
@@ -394,7 +394,7 @@ func settingsRow<Content : View>(_ icon: String, color: Color = .secondary, cont
struct ProfilePreview: View {
var profileOf: NamedChat
var color = Color(uiColor: .tertiarySystemGroupedBackground)
var color = Color(uiColor: .tertiarySystemFill)
var body: some View {
HStack {
@@ -9,15 +9,17 @@ import SimpleXChat
struct UserProfilesView: View {
@EnvironmentObject private var m: ChatModel
@Environment(\.editMode) private var editMode
@State private var showDeleteConfirmation = false
@State private var userToDelete: Int?
@State private var alert: UserProfilesAlert?
private enum UserProfilesAlert: Identifiable {
case deleteUser(index: Int)
case deleteUser(index: Int, delSMPQueues: Bool)
case error(title: LocalizedStringKey, error: LocalizedStringKey = "")
var id: String {
switch self {
case let .deleteUser(index): return "deleteUser \(index)"
case let .deleteUser(index, delSMPQueues): return "deleteUser \(index) \(delSMPQueues)"
case let .error(title, _): return "error \(title)"
}
}
@@ -31,7 +33,8 @@ struct UserProfilesView: View {
}
.onDelete { indexSet in
if let i = indexSet.first {
alert = .deleteUser(index: i)
showDeleteConfirmation = true
userToDelete = i
}
}
@@ -47,14 +50,18 @@ struct UserProfilesView: View {
}
}
.toolbar { EditButton() }
.confirmationDialog("Delete chat profile?", isPresented: $showDeleteConfirmation, titleVisibility: .visible) {
deleteModeButton("Profile and server connections", true)
deleteModeButton("Local profile data only", false)
}
.alert(item: $alert) { alert in
switch alert {
case let .deleteUser(index):
case let .deleteUser(index, delSMPQueues):
return Alert(
title: Text("Delete user profile?"),
message: Text("All chats and messages will be deleted - this cannot be undone!"),
primaryButton: .destructive(Text("Delete")) {
removeUser(index: index)
removeUser(index, delSMPQueues)
},
secondaryButton: .cancel()
)
@@ -64,24 +71,43 @@ struct UserProfilesView: View {
}
}
private func removeUser(index: Int) {
private func deleteModeButton(_ title: LocalizedStringKey, _ delSMPQueues: Bool) -> some View {
Button(title, role: .destructive) {
if let i = userToDelete {
alert = .deleteUser(index: i, delSMPQueues: delSMPQueues)
}
}
}
private func removeUser(_ index: Int, _ delSMPQueues: Bool) {
if index >= m.users.count { return }
do {
try apiDeleteUser(m.users[index].user.userId, true)
m.users.remove(at: index)
let u = m.users[index].user
if u.activeUser {
if let newActive = m.users.first(where: { !$0.user.activeUser }) {
try changeActiveUser_(newActive.user.userId)
try deleteUser(u.userId)
}
} else {
try deleteUser(u.userId)
}
} catch let error {
let a = getErrorAlert(error, "Error deleting user profile")
alert = .error(title: a.title, error: a.message)
}
func deleteUser(_ userId: Int64) throws {
try apiDeleteUser(userId, delSMPQueues)
m.users.remove(at: index)
}
}
@ViewBuilder private func userView(_ user: User) -> some View {
Button {
if !user.activeUser {
changeActiveUser(user.userId)
}
changeActiveUser(user.userId)
} label: {
HStack {
ProfileImage(imageStr: user.image)
ProfileImage(imageStr: user.image, color: Color(uiColor: .tertiarySystemFill))
.frame(width: 44, height: 44)
.padding(.vertical, 4)
.padding(.trailing, 12)
@@ -91,8 +117,9 @@ struct UserProfilesView: View {
.foregroundColor(user.activeUser ? .primary : .clear)
}
}
.disabled(user.activeUser)
.foregroundColor(.primary)
.deleteDisabled(user.activeUser)
.deleteDisabled(m.users.count <= 1)
}
}
+1 -1
View File
@@ -102,7 +102,7 @@ public enum ChatCommand {
case let .createActiveUser(profile): return "/create user \(profile.displayName) \(profile.fullName)"
case .listUsers: return "/users"
case let .apiSetActiveUser(userId): return "/_user \(userId)"
case let .apiDeleteUser(userId, delSMPQueues): return "/_delete user \(userId) delSMPQueues=\(onOff(delSMPQueues))"
case let .apiDeleteUser(userId, delSMPQueues): return "/_delete user \(userId) del_smp=\(onOff(delSMPQueues))"
case let .startChat(subscribe, expire): return "/_start subscribe=\(onOff(subscribe)) expire=\(onOff(expire))"
case .apiStopChat: return "/_stop"
case .apiActivateChat: return "/_app activate"