add contact add view
This commit is contained in:
parent
f5009157ca
commit
c2177278e2
@ -581,6 +581,9 @@
|
|||||||
"Добавить контакт" : {
|
"Добавить контакт" : {
|
||||||
"comment" : "Message profile add contact alert title"
|
"comment" : "Message profile add contact alert title"
|
||||||
},
|
},
|
||||||
|
"Добавление контакта появится позже." : {
|
||||||
|
"comment" : "Contact add placeholder message"
|
||||||
|
},
|
||||||
"Добавление новых блокировок появится позже." : {
|
"Добавление новых блокировок появится позже." : {
|
||||||
"comment" : "Add blocked user placeholder message"
|
"comment" : "Add blocked user placeholder message"
|
||||||
},
|
},
|
||||||
@ -810,7 +813,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"Изменение фото недоступно" : {
|
"Изменение фото недоступно" : {
|
||||||
"comment" : "Contact edit avatar unavailable title",
|
"comment" : "Contact add avatar unavailable title\nContact edit avatar unavailable title",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@ -1171,7 +1174,7 @@
|
|||||||
"comment" : "Сообщение при недоступной отправке письма"
|
"comment" : "Сообщение при недоступной отправке письма"
|
||||||
},
|
},
|
||||||
"Мы пока не можем обновить фото контакта." : {
|
"Мы пока не можем обновить фото контакта." : {
|
||||||
"comment" : "Contact edit avatar unavailable message",
|
"comment" : "Contact add avatar unavailable message\nContact edit avatar unavailable message",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
@ -1661,6 +1664,9 @@
|
|||||||
"Новое сообщение" : {
|
"Новое сообщение" : {
|
||||||
"comment" : "Default banner subtitle"
|
"comment" : "Default banner subtitle"
|
||||||
},
|
},
|
||||||
|
"Новый контакт" : {
|
||||||
|
"comment" : "Contact add title"
|
||||||
|
},
|
||||||
"Новый пароль" : {
|
"Новый пароль" : {
|
||||||
"comment" : "Новый пароль",
|
"comment" : "Новый пароль",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
@ -2459,7 +2465,7 @@
|
|||||||
|
|
||||||
},
|
},
|
||||||
"Публичная информация" : {
|
"Публичная информация" : {
|
||||||
"comment" : "Profile info section title"
|
"comment" : "Contact add public info section title\nProfile info section title"
|
||||||
},
|
},
|
||||||
"Публичное имя" : {
|
"Публичное имя" : {
|
||||||
|
|
||||||
@ -2806,7 +2812,7 @@
|
|||||||
"comment" : "Сообщение после активации 2FA"
|
"comment" : "Сообщение после активации 2FA"
|
||||||
},
|
},
|
||||||
"Сохранить" : {
|
"Сохранить" : {
|
||||||
"comment" : "Contact edit save button",
|
"comment" : "Contact add save button\nContact edit save button",
|
||||||
"localizations" : {
|
"localizations" : {
|
||||||
"en" : {
|
"en" : {
|
||||||
"stringUnit" : {
|
"stringUnit" : {
|
||||||
|
|||||||
@ -287,12 +287,24 @@ struct MessageProfileView: View {
|
|||||||
|
|
||||||
if shouldShowRelationshipQuickActions {
|
if shouldShowRelationshipQuickActions {
|
||||||
rowDivider
|
rowDivider
|
||||||
|
if let profile = currentChatProfile {
|
||||||
|
NavigationLink {
|
||||||
|
ContactAddView(contact: ContactEditInfo(profile: profile))
|
||||||
|
} label: {
|
||||||
|
filledActionLabel(
|
||||||
|
title: NSLocalizedString("Добавить в контакты", comment: "Message profile add to contacts title"),
|
||||||
|
tint: Color.accentColor
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
} else {
|
||||||
filledActionButton(
|
filledActionButton(
|
||||||
title: NSLocalizedString("Добавить в контакты", comment: "Message profile add to contacts title"),
|
title: NSLocalizedString("Добавить в контакты", comment: "Message profile add to contacts title"),
|
||||||
tint: Color.accentColor
|
tint: Color.accentColor
|
||||||
) {
|
) {
|
||||||
handleAddContactTap()
|
handleAddContactTap()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
rowDivider
|
rowDivider
|
||||||
filledActionButton(
|
filledActionButton(
|
||||||
@ -501,6 +513,16 @@ struct MessageProfileView: View {
|
|||||||
action: @escaping () -> Void
|
action: @escaping () -> Void
|
||||||
) -> some View {
|
) -> some View {
|
||||||
Button(action: action) {
|
Button(action: action) {
|
||||||
|
filledActionLabel(title: title, subtitle: subtitle, tint: tint)
|
||||||
|
}
|
||||||
|
.buttonStyle(.plain)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func filledActionLabel(
|
||||||
|
title: String,
|
||||||
|
subtitle: String? = nil,
|
||||||
|
tint: Color
|
||||||
|
) -> some View {
|
||||||
VStack(alignment: .leading, spacing: 4) {
|
VStack(alignment: .leading, spacing: 4) {
|
||||||
Text(title)
|
Text(title)
|
||||||
.font(.body)
|
.font(.body)
|
||||||
@ -515,8 +537,6 @@ struct MessageProfileView: View {
|
|||||||
.frame(maxWidth: .infinity, alignment: .leading)
|
.frame(maxWidth: .infinity, alignment: .leading)
|
||||||
.padding(.vertical, 10)
|
.padding(.vertical, 10)
|
||||||
}
|
}
|
||||||
.buttonStyle(.plain)
|
|
||||||
}
|
|
||||||
|
|
||||||
private func iconBackground<Content: View>(color: Color, @ViewBuilder content: () -> Content) -> some View {
|
private func iconBackground<Content: View>(color: Color, @ViewBuilder content: () -> Content) -> some View {
|
||||||
RoundedRectangle(cornerRadius: 14, style: .continuous)
|
RoundedRectangle(cornerRadius: 14, style: .continuous)
|
||||||
|
|||||||
137
yobble/Views/Contacts/ContactAddView.swift
Normal file
137
yobble/Views/Contacts/ContactAddView.swift
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
import SwiftUI
|
||||||
|
|
||||||
|
struct ContactAddView: View {
|
||||||
|
let contact: ContactEditInfo
|
||||||
|
|
||||||
|
@State private var displayName: String
|
||||||
|
@State private var activeAlert: ContactAddAlert?
|
||||||
|
|
||||||
|
init(contact: ContactEditInfo) {
|
||||||
|
self.contact = contact
|
||||||
|
let initialName = contact.preferredName
|
||||||
|
_displayName = State(initialValue: initialName)
|
||||||
|
}
|
||||||
|
|
||||||
|
var body: some View {
|
||||||
|
Form {
|
||||||
|
avatarSection
|
||||||
|
|
||||||
|
Section(header: Text(NSLocalizedString("Публичная информация", comment: "Contact add public info section title"))) {
|
||||||
|
TextField(NSLocalizedString("Отображаемое имя", comment: "Display name field placeholder"), text: $displayName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.navigationTitle(NSLocalizedString("Новый контакт", comment: "Contact add title"))
|
||||||
|
.navigationBarTitleDisplayMode(.inline)
|
||||||
|
.toolbar {
|
||||||
|
ToolbarItem(placement: .confirmationAction) {
|
||||||
|
Button(NSLocalizedString("Сохранить", comment: "Contact add save button")) {
|
||||||
|
handleSaveTap()
|
||||||
|
}
|
||||||
|
.disabled(!hasChanges)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.alert(item: $activeAlert) { item in
|
||||||
|
Alert(
|
||||||
|
title: Text(item.title),
|
||||||
|
message: Text(item.message),
|
||||||
|
dismissButton: .default(Text(NSLocalizedString("Понятно", comment: "Placeholder alert dismiss")))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var avatarSection: some View {
|
||||||
|
Section {
|
||||||
|
HStack {
|
||||||
|
Spacer()
|
||||||
|
VStack(spacing: 8) {
|
||||||
|
avatarView
|
||||||
|
.frame(width: 120, height: 120)
|
||||||
|
.clipShape(Circle())
|
||||||
|
|
||||||
|
Button(NSLocalizedString("Изменить фото", comment: "Edit avatar button title")) {
|
||||||
|
showAvatarUnavailableAlert()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Spacer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.listRowBackground(Color(UIColor.systemGroupedBackground))
|
||||||
|
}
|
||||||
|
|
||||||
|
@ViewBuilder
|
||||||
|
private var avatarView: some View {
|
||||||
|
if let url = avatarURL,
|
||||||
|
let fileId = contact.avatarFileId {
|
||||||
|
CachedAvatarView(url: url, fileId: fileId, userId: contact.userId) {
|
||||||
|
avatarPlaceholder
|
||||||
|
}
|
||||||
|
.aspectRatio(contentMode: .fill)
|
||||||
|
} else {
|
||||||
|
avatarPlaceholder
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private var avatarPlaceholder: some View {
|
||||||
|
Circle()
|
||||||
|
.fill(Color.accentColor.opacity(0.15))
|
||||||
|
.overlay(
|
||||||
|
Text(avatarInitial)
|
||||||
|
.font(.system(size: 48, weight: .semibold))
|
||||||
|
.foregroundColor(.accentColor)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private var avatarInitial: String {
|
||||||
|
let trimmedName = displayName.trimmedNonEmpty ?? contact.preferredName
|
||||||
|
if let first = trimmedName.trimmingCharacters(in: .whitespacesAndNewlines).first {
|
||||||
|
return String(first).uppercased()
|
||||||
|
}
|
||||||
|
if let login = contact.login?.trimmingCharacters(in: .whitespacesAndNewlines), !login.isEmpty {
|
||||||
|
return String(login.prefix(1)).uppercased()
|
||||||
|
}
|
||||||
|
return "?"
|
||||||
|
}
|
||||||
|
|
||||||
|
private var avatarURL: URL? {
|
||||||
|
guard let fileId = contact.avatarFileId else { return nil }
|
||||||
|
return URL(string: "\(AppConfig.API_SERVER)/v1/storage/download/avatar/\(contact.userId)?file_id=\(fileId)")
|
||||||
|
}
|
||||||
|
|
||||||
|
private var hasChanges: Bool {
|
||||||
|
let trimmed = displayName.trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
|
guard !trimmed.isEmpty else { return false }
|
||||||
|
|
||||||
|
if let existing = contact.customName?.trimmedNonEmpty {
|
||||||
|
return trimmed != existing
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
private func showAvatarUnavailableAlert() {
|
||||||
|
activeAlert = ContactAddAlert(
|
||||||
|
title: NSLocalizedString("Изменение фото недоступно", comment: "Contact add avatar unavailable title"),
|
||||||
|
message: NSLocalizedString("Мы пока не можем обновить фото контакта.", comment: "Contact add avatar unavailable message")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private func handleSaveTap() {
|
||||||
|
activeAlert = ContactAddAlert(
|
||||||
|
title: NSLocalizedString("Скоро", comment: "Common soon title"),
|
||||||
|
message: NSLocalizedString("Добавление контакта появится позже.", comment: "Contact add placeholder message")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private struct ContactAddAlert: Identifiable {
|
||||||
|
let id = UUID()
|
||||||
|
let title: String
|
||||||
|
let message: String
|
||||||
|
}
|
||||||
|
|
||||||
|
private extension String {
|
||||||
|
var trimmedNonEmpty: String? {
|
||||||
|
let value = trimmingCharacters(in: .whitespacesAndNewlines)
|
||||||
|
return value.isEmpty ? nil : value
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user