add block user from settings
This commit is contained in:
parent
7a7f2eec5e
commit
7dc4882f27
@ -135,6 +135,15 @@ final class BlockedUsersService {
|
||||
|
||||
func add(userId: UUID, completion: @escaping (Result<BlockedUserInfo, Error>) -> Void) {
|
||||
let request = BlockedUserCreateRequest(userId: userId, login: nil)
|
||||
add(request: request, completion: completion)
|
||||
}
|
||||
|
||||
func add(login: String, completion: @escaping (Result<BlockedUserInfo, Error>) -> Void) {
|
||||
let request = BlockedUserCreateRequest(userId: nil, login: login)
|
||||
add(request: request, completion: completion)
|
||||
}
|
||||
|
||||
private func add(request: BlockedUserCreateRequest, completion: @escaping (Result<BlockedUserInfo, Error>) -> Void) {
|
||||
let encoder = JSONEncoder()
|
||||
encoder.keyEncodingStrategy = .convertToSnakeCase
|
||||
|
||||
@ -187,6 +196,14 @@ final class BlockedUsersService {
|
||||
}
|
||||
}
|
||||
|
||||
func add(login: String) async throws -> BlockedUserInfo {
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
add(login: login) { result in
|
||||
continuation.resume(with: result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static func decodeDate(from decoder: Decoder) throws -> Date {
|
||||
let container = try decoder.singleValueContainer()
|
||||
let string = try container.decode(String.self)
|
||||
|
||||
@ -335,6 +335,9 @@
|
||||
"Введите пароль" : {
|
||||
"comment" : "Пароль\nПоле ввода пароля на приложение"
|
||||
},
|
||||
"Введите юзернейм человека, которого нужно заблокировать. Символ @ указывать не нужно." : {
|
||||
"comment" : "Blocked users add login footer"
|
||||
},
|
||||
"Веб" : {
|
||||
"comment" : "Тип сессии — веб"
|
||||
},
|
||||
@ -590,9 +593,6 @@
|
||||
"Добавить контакт" : {
|
||||
"comment" : "Message profile add contact alert title"
|
||||
},
|
||||
"Добавление новых блокировок появится позже." : {
|
||||
"comment" : "Add blocked user placeholder message"
|
||||
},
|
||||
"Добавьте контакты, чтобы быстрее выходить на связь." : {
|
||||
"comment" : "Contacts empty state subtitle"
|
||||
},
|
||||
@ -648,7 +648,7 @@
|
||||
|
||||
},
|
||||
"Заблокировать" : {
|
||||
"comment" : "Message profile block title"
|
||||
"comment" : "Blocked users add confirm\nBlocked users add title\nMessage profile block title"
|
||||
},
|
||||
"Заблокировать контакт" : {
|
||||
"comment" : "Contacts context action block"
|
||||
@ -1106,6 +1106,9 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"Логин пользователя" : {
|
||||
"comment" : "Blocked users add login header"
|
||||
},
|
||||
"Логин уже занят." : {
|
||||
"localizations" : {
|
||||
"en" : {
|
||||
@ -1256,6 +1259,9 @@
|
||||
"Напишите нам через форму обратной связи в разделе \"Поддержка\"." : {
|
||||
"comment" : "FAQ answer: support"
|
||||
},
|
||||
"Например, username" : {
|
||||
"comment" : "Blocked users add login placeholder"
|
||||
},
|
||||
"Например: заметил неточную информацию в статье..." : {
|
||||
"comment" : "feedback placeholder: content",
|
||||
"localizations" : {
|
||||
@ -2788,7 +2794,7 @@
|
||||
"comment" : "Кнопка копирования кода восстановления"
|
||||
},
|
||||
"Скоро" : {
|
||||
"comment" : "Add blocked user placeholder title\nContacts placeholder title\nЗаголовок заглушки"
|
||||
"comment" : "Contacts placeholder title\nЗаголовок заглушки"
|
||||
},
|
||||
"Скоро можно будет искать сообщения, ссылки и файлы в этом чате." : {
|
||||
"comment" : "Message profile search action description"
|
||||
|
||||
@ -11,6 +11,11 @@ struct BlockedUsersView: View {
|
||||
@State private var removingUserIds: Set<UUID> = []
|
||||
@State private var activeAlert: ActiveAlert?
|
||||
@State private var errorMessageDown: String?
|
||||
@State private var isAddUserSheetPresented = false
|
||||
@State private var newBlockedUserLogin = ""
|
||||
@State private var addBlockedUserError: String?
|
||||
@State private var isProcessingAddBlockedUser = false
|
||||
@FocusState private var isAddBlockedUserFieldFocused: Bool
|
||||
|
||||
private let blockedUsersService = BlockedUsersService()
|
||||
private let limit = 20
|
||||
@ -32,7 +37,7 @@ struct BlockedUsersView: View {
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarTrailing) {
|
||||
Button {
|
||||
activeAlert = .addPlaceholder
|
||||
isAddUserSheetPresented = true
|
||||
} label: {
|
||||
Image(systemName: "plus")
|
||||
}
|
||||
@ -41,14 +46,11 @@ struct BlockedUsersView: View {
|
||||
.task {
|
||||
await loadBlockedUsers()
|
||||
}
|
||||
.sheet(isPresented: $isAddUserSheetPresented, onDismiss: resetAddBlockedUserForm) {
|
||||
addBlockedUserSheet
|
||||
}
|
||||
.alert(item: $activeAlert) { alert in
|
||||
switch alert {
|
||||
case .addPlaceholder:
|
||||
return Alert(
|
||||
title: Text(NSLocalizedString("Скоро", comment: "Add blocked user placeholder title")),
|
||||
message: Text(NSLocalizedString("Добавление новых блокировок появится позже.", comment: "Add blocked user placeholder message")),
|
||||
dismissButton: .default(Text(NSLocalizedString("OK", comment: "Common OK")))
|
||||
)
|
||||
case .error(_, let message):
|
||||
return Alert(
|
||||
title: Text(NSLocalizedString("Ошибка", comment: "Common error title")),
|
||||
@ -78,6 +80,58 @@ struct BlockedUsersView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private var addBlockedUserSheet: some View {
|
||||
NavigationView {
|
||||
Form {
|
||||
Section(
|
||||
header: Text(NSLocalizedString("Логин пользователя", comment: "Blocked users add login header")),
|
||||
footer: Text(NSLocalizedString("Введите юзернейм человека, которого нужно заблокировать. Символ @ указывать не нужно.", comment: "Blocked users add login footer"))
|
||||
.font(.footnote)
|
||||
.foregroundColor(.secondary)
|
||||
) {
|
||||
TextField(NSLocalizedString("Например, username", comment: "Blocked users add login placeholder"), text: $newBlockedUserLogin)
|
||||
.textInputAutocapitalization(.never)
|
||||
.autocorrectionDisabled()
|
||||
.keyboardType(.asciiCapable)
|
||||
.focused($isAddBlockedUserFieldFocused)
|
||||
}
|
||||
|
||||
if let addBlockedUserError {
|
||||
Section {
|
||||
Text(addBlockedUserError)
|
||||
.font(.footnote)
|
||||
.foregroundColor(.red)
|
||||
.multilineTextAlignment(.leading)
|
||||
}
|
||||
}
|
||||
}
|
||||
.navigationTitle(NSLocalizedString("Заблокировать", comment: "Blocked users add title"))
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .cancellationAction) {
|
||||
Button(NSLocalizedString("Отмена", comment: "Common cancel")) {
|
||||
isAddUserSheetPresented = false
|
||||
}
|
||||
}
|
||||
ToolbarItem(placement: .confirmationAction) {
|
||||
if isProcessingAddBlockedUser {
|
||||
ProgressView()
|
||||
} else {
|
||||
Button(NSLocalizedString("Заблокировать", comment: "Blocked users add confirm")) {
|
||||
submitAddBlockedUser()
|
||||
}
|
||||
.disabled(!canSubmitNewBlockedUser)
|
||||
}
|
||||
}
|
||||
}
|
||||
.onAppear {
|
||||
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
|
||||
isAddBlockedUserFieldFocused = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var usersSection: some View {
|
||||
Section(header: Text(NSLocalizedString("Заблокированные", comment: ""))) {
|
||||
ForEach(Array(blockedUsers.enumerated()), id: \.element.id) { index, user in
|
||||
@ -99,6 +153,14 @@ struct BlockedUsersView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private var trimmedNewBlockedUserLogin: String {
|
||||
newBlockedUserLogin.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||
}
|
||||
|
||||
private var canSubmitNewBlockedUser: Bool {
|
||||
!trimmedNewBlockedUserLogin.isEmpty && !isProcessingAddBlockedUser
|
||||
}
|
||||
|
||||
private func userRow(_ user: BlockedUser, index: Int) -> some View {
|
||||
HStack(spacing: 12) {
|
||||
Circle()
|
||||
@ -185,6 +247,53 @@ struct BlockedUsersView: View {
|
||||
}
|
||||
}
|
||||
|
||||
private func submitAddBlockedUser() {
|
||||
guard canSubmitNewBlockedUser else { return }
|
||||
|
||||
let login = trimmedNewBlockedUserLogin
|
||||
isProcessingAddBlockedUser = true
|
||||
addBlockedUserError = nil
|
||||
|
||||
Task {
|
||||
await performAddBlockedUser(login: login)
|
||||
}
|
||||
}
|
||||
|
||||
private func resetAddBlockedUserForm() {
|
||||
newBlockedUserLogin = ""
|
||||
addBlockedUserError = nil
|
||||
isProcessingAddBlockedUser = false
|
||||
isAddBlockedUserFieldFocused = false
|
||||
}
|
||||
|
||||
private func performAddBlockedUser(login: String) async {
|
||||
do {
|
||||
let payload = try await blockedUsersService.add(login: login)
|
||||
let newUser = BlockedUser(payload: payload)
|
||||
|
||||
await MainActor.run {
|
||||
let existed = blockedUsers.contains(where: { $0.id == newUser.id })
|
||||
blockedUsers.removeAll { $0.id == newUser.id }
|
||||
blockedUsers.insert(newUser, at: 0)
|
||||
if !existed {
|
||||
offset += 1
|
||||
}
|
||||
isAddUserSheetPresented = false
|
||||
}
|
||||
} catch {
|
||||
if AppConfig.DEBUG {
|
||||
print("[BlockedUsersView] add blocked user failed: \(error)")
|
||||
}
|
||||
await MainActor.run {
|
||||
addBlockedUserError = error.localizedDescription
|
||||
}
|
||||
}
|
||||
|
||||
await MainActor.run {
|
||||
isProcessingAddBlockedUser = false
|
||||
}
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func loadBlockedUsers() async {
|
||||
errorMessageDown = nil
|
||||
@ -296,13 +405,10 @@ private struct BlockedUser: Identifiable, Equatable {
|
||||
}
|
||||
|
||||
private enum ActiveAlert: Identifiable {
|
||||
case addPlaceholder
|
||||
case error(id: UUID = UUID(), message: String)
|
||||
|
||||
var id: String {
|
||||
switch self {
|
||||
case .addPlaceholder:
|
||||
return "addPlaceholder"
|
||||
case .error(let id, _):
|
||||
return id.uuidString
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user