add work button in contact
This commit is contained in:
parent
a66eb04489
commit
8ba51f026c
@ -276,9 +276,6 @@
|
||||
},
|
||||
"Биография" : {
|
||||
|
||||
},
|
||||
"Блокировка контакта \"%1$@\" появится позже." : {
|
||||
"comment" : "Contacts block placeholder message"
|
||||
},
|
||||
"Больше сообщений нет" : {
|
||||
"comment" : "Chat history top reached"
|
||||
@ -648,11 +645,14 @@
|
||||
|
||||
},
|
||||
"Заблокировать" : {
|
||||
"comment" : "Blocked users add confirm\nBlocked users add title\nMessage profile block title"
|
||||
"comment" : "Blocked users add confirm\nBlocked users add title\nContacts block confirm action\nMessage profile block title"
|
||||
},
|
||||
"Заблокировать контакт" : {
|
||||
"comment" : "Contacts context action block"
|
||||
},
|
||||
"Заблокировать контакт?" : {
|
||||
"comment" : "Contacts block confirmation title"
|
||||
},
|
||||
"Забыли пароль? Сбросить" : {
|
||||
|
||||
},
|
||||
@ -811,9 +811,6 @@
|
||||
"Избранные сообщения" : {
|
||||
"comment" : "Saved messages title"
|
||||
},
|
||||
"Изменение контакта \"%1$@\" появится позже." : {
|
||||
"comment" : "Contacts edit placeholder message"
|
||||
},
|
||||
"Изменение пароля" : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@ -957,7 +954,7 @@
|
||||
}
|
||||
},
|
||||
"Контакт \"%1$@\" будет удалён из списка." : {
|
||||
"comment" : "Contact delete confirmation message"
|
||||
"comment" : "Contact delete confirmation message\nContacts delete confirmation message"
|
||||
},
|
||||
"Контактов пока нет" : {
|
||||
"comment" : "Contacts empty state title"
|
||||
@ -2241,6 +2238,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Пользователь \"%1$@\" будет добавлен в чёрный список." : {
|
||||
"comment" : "Contacts block confirmation message"
|
||||
},
|
||||
"Пользователь \"%1$@\" будет удалён из списка заблокированных." : {
|
||||
"comment" : "Unblock confirmation message"
|
||||
},
|
||||
@ -2792,7 +2792,7 @@
|
||||
"comment" : "Кнопка копирования кода восстановления"
|
||||
},
|
||||
"Скоро" : {
|
||||
"comment" : "Contacts placeholder title\nЗаголовок заглушки"
|
||||
"comment" : "Заголовок заглушки"
|
||||
},
|
||||
"Скоро можно будет искать сообщения, ссылки и файлы в этом чате." : {
|
||||
"comment" : "Message profile search action description"
|
||||
@ -3056,9 +3056,6 @@
|
||||
"Удаление аватара пока недоступно." : {
|
||||
"comment" : "Avatar delete placeholder"
|
||||
},
|
||||
"Удаление контакта \"%1$@\" появится позже." : {
|
||||
"comment" : "Contacts delete placeholder message"
|
||||
},
|
||||
"Удаление контакта появится позже." : {
|
||||
"comment" : "Contact edit delete placeholder message",
|
||||
"extractionState" : "stale",
|
||||
@ -3072,7 +3069,7 @@
|
||||
}
|
||||
},
|
||||
"Удалить" : {
|
||||
"comment" : "Contact delete confirm action"
|
||||
"comment" : "Contact delete confirm action\nContacts delete confirm action"
|
||||
},
|
||||
"Удалить из заблокированных?" : {
|
||||
"comment" : "Unblock confirmation title"
|
||||
@ -3081,7 +3078,7 @@
|
||||
"comment" : "Contact edit delete action\nContacts context action delete"
|
||||
},
|
||||
"Удалить контакт?" : {
|
||||
"comment" : "Contact delete confirmation title"
|
||||
"comment" : "Contact delete confirmation title\nContacts delete confirmation title"
|
||||
},
|
||||
"Удалить фото" : {
|
||||
"comment" : "Avatar delete"
|
||||
|
||||
@ -16,10 +16,18 @@ struct ContactsTab: View {
|
||||
@State private var contactAvatars: [UUID: AvatarInfo] = [:]
|
||||
@State private var avatarLoadedIds: Set<UUID> = []
|
||||
@State private var avatarLoadingIds: Set<UUID> = []
|
||||
@State private var contactToEdit: Contact?
|
||||
@State private var contactPendingBlock: Contact?
|
||||
@State private var contactPendingDelete: Contact?
|
||||
@State private var showBlockConfirmation = false
|
||||
@State private var showDeleteConfirmation = false
|
||||
@State private var blockingContactIds: Set<UUID> = []
|
||||
@State private var deletingContactIds: Set<UUID> = []
|
||||
|
||||
private let contactsService = ContactsService()
|
||||
private let chatService = ChatService()
|
||||
private let profileService = ProfileService()
|
||||
private let blockedUsersService = BlockedUsersService()
|
||||
private let pageSize = 25
|
||||
|
||||
private var currentUserId: String? {
|
||||
@ -50,13 +58,12 @@ struct ContactsTab: View {
|
||||
contact: contact,
|
||||
avatarInfo: contactAvatars[contact.id],
|
||||
currentUserId: currentUserId,
|
||||
isLoading: creatingChatForContactId == contact.id
|
||||
isLoading: isRowBusy(contact)
|
||||
)
|
||||
.contentShape(Rectangle())
|
||||
}
|
||||
.buttonStyle(.plain)
|
||||
.disabled(creatingChatForContactId == contact.id)
|
||||
// .disabled(contact.isDeleted || creatingChatForContactId == contact.id)
|
||||
.disabled(isRowBusy(contact))
|
||||
.contextMenu {
|
||||
Button {
|
||||
handleContactAction(.edit, for: contact)
|
||||
@ -86,7 +93,6 @@ struct ContactsTab: View {
|
||||
systemImage: "trash"
|
||||
)
|
||||
}
|
||||
// .disabled(contact.isDeleted)
|
||||
}
|
||||
.listRowInsets(EdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 12))
|
||||
.onAppear {
|
||||
@ -128,6 +134,59 @@ struct ContactsTab: View {
|
||||
)
|
||||
}
|
||||
}
|
||||
.sheet(item: $contactToEdit) { contact in
|
||||
NavigationView {
|
||||
ContactEditView(
|
||||
contact: contactEditInfo(for: contact),
|
||||
onContactDeleted: {
|
||||
handleContactRemoved(contact.id)
|
||||
},
|
||||
onContactUpdated: { newName in
|
||||
handleContactRenamed(contact.id, newName: newName)
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
.confirmationDialog(
|
||||
NSLocalizedString("Заблокировать контакт?", comment: "Contacts block confirmation title"),
|
||||
isPresented: $showBlockConfirmation,
|
||||
presenting: contactPendingBlock
|
||||
) { contact in
|
||||
Button(NSLocalizedString("Заблокировать", comment: "Contacts block confirm action"), role: .destructive) {
|
||||
showBlockConfirmation = false
|
||||
contactPendingBlock = nil
|
||||
performBlockContact(contact)
|
||||
}
|
||||
Button(NSLocalizedString("Отмена", comment: "Common cancel"), role: .cancel) {
|
||||
showBlockConfirmation = false
|
||||
contactPendingBlock = nil
|
||||
}
|
||||
} message: { contact in
|
||||
Text(String(
|
||||
format: NSLocalizedString("Пользователь \"%1$@\" будет добавлен в чёрный список.", comment: "Contacts block confirmation message"),
|
||||
contact.displayName
|
||||
))
|
||||
}
|
||||
.confirmationDialog(
|
||||
NSLocalizedString("Удалить контакт?", comment: "Contacts delete confirmation title"),
|
||||
isPresented: $showDeleteConfirmation,
|
||||
presenting: contactPendingDelete
|
||||
) { contact in
|
||||
Button(NSLocalizedString("Удалить", comment: "Contacts delete confirm action"), role: .destructive) {
|
||||
showDeleteConfirmation = false
|
||||
contactPendingDelete = nil
|
||||
performDeleteContact(contact)
|
||||
}
|
||||
Button(NSLocalizedString("Отмена", comment: "Common cancel"), role: .cancel) {
|
||||
showDeleteConfirmation = false
|
||||
contactPendingDelete = nil
|
||||
}
|
||||
} message: { contact in
|
||||
Text(String(
|
||||
format: NSLocalizedString("Контакт \"%1$@\" будет удалён из списка.", comment: "Contacts delete confirmation message"),
|
||||
contact.displayName
|
||||
))
|
||||
}
|
||||
.overlay(pendingChatNavigationLink)
|
||||
}
|
||||
|
||||
@ -243,10 +302,17 @@ struct ContactsTab: View {
|
||||
}
|
||||
|
||||
private func handleContactAction(_ action: ContactAction, for contact: Contact) {
|
||||
activeAlert = .info(
|
||||
title: NSLocalizedString("Скоро", comment: "Contacts placeholder title"),
|
||||
message: action.placeholderMessage(for: contact)
|
||||
)
|
||||
guard !isRowBusy(contact) else { return }
|
||||
switch action {
|
||||
case .edit:
|
||||
contactToEdit = contact
|
||||
case .block:
|
||||
contactPendingBlock = contact
|
||||
showBlockConfirmation = true
|
||||
case .delete:
|
||||
contactPendingDelete = contact
|
||||
showDeleteConfirmation = true
|
||||
}
|
||||
}
|
||||
|
||||
private var pendingChatNavigationLink: some View {
|
||||
@ -381,6 +447,92 @@ struct ContactsTab: View {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func performBlockContact(_ contact: Contact) {
|
||||
let contactId = contact.id
|
||||
guard !blockingContactIds.contains(contactId) else { return }
|
||||
blockingContactIds.insert(contactId)
|
||||
|
||||
Task {
|
||||
do {
|
||||
_ = try await blockedUsersService.add(userId: contactId)
|
||||
await MainActor.run {
|
||||
blockingContactIds.remove(contactId)
|
||||
handleContactRemoved(contactId)
|
||||
}
|
||||
} catch {
|
||||
await MainActor.run {
|
||||
blockingContactIds.remove(contactId)
|
||||
activeAlert = .error(message: error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func performDeleteContact(_ contact: Contact) {
|
||||
let contactId = contact.id
|
||||
guard !deletingContactIds.contains(contactId) else { return }
|
||||
deletingContactIds.insert(contactId)
|
||||
|
||||
Task {
|
||||
do {
|
||||
try await contactsService.removeContact(userId: contactId)
|
||||
await MainActor.run {
|
||||
deletingContactIds.remove(contactId)
|
||||
handleContactRemoved(contactId)
|
||||
}
|
||||
} catch {
|
||||
await MainActor.run {
|
||||
deletingContactIds.remove(contactId)
|
||||
activeAlert = .error(message: error.localizedDescription)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func contactEditInfo(for contact: Contact) -> ContactEditInfo {
|
||||
ContactEditInfo(
|
||||
userId: contact.id,
|
||||
login: contact.login,
|
||||
fullName: contact.fullName,
|
||||
customName: contact.customName,
|
||||
avatarFileId: contactAvatars[contact.id]?.fileId
|
||||
)
|
||||
}
|
||||
|
||||
private func handleContactRenamed(_ contactId: UUID, newName: String) {
|
||||
guard let index = contacts.firstIndex(where: { $0.id == contactId }) else { return }
|
||||
contacts[index] = contacts[index].updatingCustomName(newName)
|
||||
}
|
||||
|
||||
private func handleContactRemoved(_ contactId: UUID) {
|
||||
contacts.removeAll { $0.id == contactId }
|
||||
contactAvatars.removeValue(forKey: contactId)
|
||||
avatarLoadedIds.remove(contactId)
|
||||
avatarLoadingIds.remove(contactId)
|
||||
if creatingChatForContactId == contactId {
|
||||
creatingChatForContactId = nil
|
||||
}
|
||||
blockingContactIds.remove(contactId)
|
||||
deletingContactIds.remove(contactId)
|
||||
if contactToEdit?.id == contactId {
|
||||
contactToEdit = nil
|
||||
}
|
||||
if contactPendingBlock?.id == contactId {
|
||||
contactPendingBlock = nil
|
||||
showBlockConfirmation = false
|
||||
}
|
||||
if contactPendingDelete?.id == contactId {
|
||||
contactPendingDelete = nil
|
||||
showDeleteConfirmation = false
|
||||
}
|
||||
}
|
||||
|
||||
private func isRowBusy(_ contact: Contact) -> Bool {
|
||||
creatingChatForContactId == contact.id
|
||||
|| blockingContactIds.contains(contact.id)
|
||||
|| deletingContactIds.contains(contact.id)
|
||||
}
|
||||
}
|
||||
|
||||
private struct ContactRow: View {
|
||||
@ -575,6 +727,20 @@ private struct Contact: Identifiable, Equatable {
|
||||
}
|
||||
}
|
||||
|
||||
func updatingCustomName(_ newName: String) -> Contact {
|
||||
let trimmed = newName.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
let updatedCustomName = trimmed.isEmpty ? nil : trimmed
|
||||
let payload = ContactPayload(
|
||||
userId: id,
|
||||
login: login,
|
||||
fullName: fullName,
|
||||
customName: updatedCustomName,
|
||||
friendCode: friendCode,
|
||||
createdAt: createdAt
|
||||
)
|
||||
return Contact(payload: payload)
|
||||
}
|
||||
|
||||
private static let relativeFormatter: RelativeDateTimeFormatter = {
|
||||
let formatter = RelativeDateTimeFormatter()
|
||||
formatter.unitsStyle = .short
|
||||
@ -598,24 +764,4 @@ private enum ContactAction {
|
||||
case edit
|
||||
case block
|
||||
case delete
|
||||
|
||||
func placeholderMessage(for contact: Contact) -> String {
|
||||
switch self {
|
||||
case .edit:
|
||||
return String(
|
||||
format: NSLocalizedString("Изменение контакта \"%1$@\" появится позже.", comment: "Contacts edit placeholder message"),
|
||||
contact.displayName
|
||||
)
|
||||
case .block:
|
||||
return String(
|
||||
format: NSLocalizedString("Блокировка контакта \"%1$@\" появится позже.", comment: "Contacts block placeholder message"),
|
||||
contact.displayName
|
||||
)
|
||||
case .delete:
|
||||
return String(
|
||||
format: NSLocalizedString("Удаление контакта \"%1$@\" появится позже.", comment: "Contacts delete placeholder message"),
|
||||
contact.displayName
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user