From 374bd1713bd9d0877528307d33d15dcf4ce327fd Mon Sep 17 00:00:00 2001 From: cheykrym Date: Thu, 23 Oct 2025 23:15:22 +0300 Subject: [PATCH] edit view contacts --- yobble/Resources/Localizable.xcstrings | 6 +- yobble/Views/Tab/ContactsTab.swift | 125 +++++++++++++++++-------- 2 files changed, 89 insertions(+), 42 deletions(-) diff --git a/yobble/Resources/Localizable.xcstrings b/yobble/Resources/Localizable.xcstrings index 468bdbb..74432c5 100644 --- a/yobble/Resources/Localizable.xcstrings +++ b/yobble/Resources/Localizable.xcstrings @@ -1240,6 +1240,7 @@ } }, "Обновить" : { + "comment" : "Contacts retry button", "localizations" : { "en" : { "stringUnit" : { @@ -1828,6 +1829,9 @@ } } }, + "Просмотр \"%1$@\" появится позже." : { + "comment" : "Contacts placeholder message" + }, "Профиль" : { "localizations" : { "en" : { @@ -2055,7 +2059,7 @@ "comment" : "Search placeholder copy" }, "Скоро" : { - "comment" : "Add blocked user placeholder title" + "comment" : "Add blocked user placeholder title\nContacts placeholder title" }, "Скоро появится мини-игра, где можно заработать очки для кастомизации профиля. Следите за обновлениями!" : { "comment" : "Concept tab placeholder description" diff --git a/yobble/Views/Tab/ContactsTab.swift b/yobble/Views/Tab/ContactsTab.swift index 99845e8..bb19600 100644 --- a/yobble/Views/Tab/ContactsTab.swift +++ b/yobble/Views/Tab/ContactsTab.swift @@ -1,4 +1,5 @@ import SwiftUI +import Foundation struct ContactsTab: View { @State private var contacts: [Contact] = [] @@ -17,15 +18,23 @@ struct ContactsTab: View { } else if contacts.isEmpty { emptyState } else { - Section(header: Text(NSLocalizedString("Контакты", comment: ""))) { - ForEach(contacts) { contact in + ForEach(contacts) { contact in + Button { + activeAlert = .info( + title: NSLocalizedString("Скоро", comment: "Contacts placeholder title"), + message: String(format: NSLocalizedString("Просмотр \"%1$@\" появится позже.", comment: "Contacts placeholder message"), contact.displayName) + ) + } label: { ContactRow(contact: contact) + .contentShape(Rectangle()) } + .buttonStyle(.plain) + .listRowInsets(EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16)) } } } - .listStyle(.insetGrouped) - .background(Color(.systemGroupedBackground)) + .background(Color(UIColor.systemBackground)) + .listStyle(.plain) .task { await loadContacts() } @@ -40,42 +49,63 @@ struct ContactsTab: View { message: Text(message), dismissButton: .default(Text(NSLocalizedString("OK", comment: "Common OK"))) ) + case .info(_, let title, let message): + return Alert( + title: Text(title), + message: Text(message), + dismissButton: .default(Text(NSLocalizedString("OK", comment: "Common OK"))) + ) } } } private var loadingState: some View { - Section { + HStack { + Spacer() ProgressView() - .frame(maxWidth: .infinity, alignment: .center) + .progressViewStyle(CircularProgressViewStyle()) + Spacer() } + .padding(.vertical, 24) + .listRowInsets(EdgeInsets(top: 24, leading: 16, bottom: 24, trailing: 16)) + .listRowSeparator(.hidden) } private func errorState(_ message: String) -> some View { - Section { + HStack(alignment: .center, spacing: 8) { + Image(systemName: "exclamationmark.triangle.fill") + .foregroundColor(.orange) Text(message) - .foregroundColor(.red) - .frame(maxWidth: .infinity, alignment: .center) + .font(.subheadline) + .foregroundColor(.orange) + Spacer() + Button(action: { Task { await loadContacts() } }) { + Text(NSLocalizedString("Обновить", comment: "Contacts retry button")) + .font(.subheadline) + } } + .padding(.vertical, 12) + .listRowInsets(EdgeInsets(top: 12, leading: 16, bottom: 12, trailing: 16)) + .listRowSeparator(.hidden) } private var emptyState: some View { - Section { - VStack(spacing: 12) { - Image(systemName: "person.crop.circle.badge.questionmark") - .font(.system(size: 48)) - .foregroundColor(.secondary) - Text(NSLocalizedString("Контактов пока нет", comment: "Contacts empty state title")) - .font(.headline) - .multilineTextAlignment(.center) - Text(NSLocalizedString("Добавьте контакты, чтобы быстрее выходить на связь.", comment: "Contacts empty state subtitle")) - .font(.subheadline) - .foregroundColor(.secondary) - .multilineTextAlignment(.center) - } - .frame(maxWidth: .infinity) - .padding(.vertical, 24) + VStack(spacing: 12) { + Image(systemName: "person.crop.circle.badge.questionmark") + .font(.system(size: 52)) + .foregroundColor(.secondary) + Text(NSLocalizedString("Контактов пока нет", comment: "Contacts empty state title")) + .font(.headline) + .multilineTextAlignment(.center) + Text(NSLocalizedString("Добавьте контакты, чтобы быстрее выходить на связь.", comment: "Contacts empty state subtitle")) + .font(.subheadline) + .foregroundColor(.secondary) + .multilineTextAlignment(.center) } + .frame(maxWidth: .infinity) + .padding(.vertical, 36) + .listRowInsets(EdgeInsets(top: 24, leading: 16, bottom: 24, trailing: 16)) + .listRowSeparator(.hidden) } @MainActor @@ -104,38 +134,50 @@ private struct ContactRow: View { let contact: Contact var body: some View { - HStack(spacing: 12) { + HStack(alignment: .top, spacing: 14) { Circle() .fill(Color.accentColor.opacity(0.15)) - .frame(width: 44, height: 44) + .frame(width: 52, height: 52) .overlay( Text(contact.initials) .font(.headline) .foregroundColor(.accentColor) ) - VStack(alignment: .leading, spacing: 4) { - Text(contact.displayName) - .font(.body) + VStack(alignment: .leading, spacing: 6) { + HStack(alignment: .firstTextBaseline) { + Text(contact.displayName) + .font(.headline) + .foregroundColor(.primary) + Spacer() + Text(contact.formattedCreatedAt) + .font(.caption) + .foregroundColor(.secondary) + } + if let handle = contact.handle { Text(handle) .font(.caption) .foregroundColor(.secondary) } - HStack(spacing: 8) { - if contact.friendCode { - Label(NSLocalizedString("Код дружбы", comment: "Friend code badge"), systemImage: "heart.circle") - .font(.caption2) - .foregroundColor(.secondary) - } - Text(contact.formattedCreatedAt) - .font(.caption2) - .foregroundColor(.secondary) + + if contact.friendCode { + friendCodeBadge } } - Spacer() + .frame(maxWidth: .infinity, alignment: .leading) } - .padding(.vertical, 4) + .padding(.vertical, 6) + } + + private var friendCodeBadge: some View { + Text(NSLocalizedString("Код дружбы", comment: "Friend code badge")) + .font(.caption2.weight(.semibold)) + .foregroundColor(Color.accentColor) + .padding(.horizontal, 8) + .padding(.vertical, 4) + .background(Color.accentColor.opacity(0.12)) + .clipShape(Capsule()) } } @@ -203,10 +245,11 @@ private struct Contact: Identifiable, Equatable { private enum ContactsAlert: Identifiable { case error(id: UUID = UUID(), message: String) + case info(id: UUID = UUID(), title: String, message: String) var id: String { switch self { - case .error(let id, _): + case .error(let id, _), .info(let id, _, _): return id.uuidString } }