edit view contacts
This commit is contained in:
		
							parent
							
								
									aac0a25c4d
								
							
						
					
					
						commit
						374bd1713b
					
				@ -1240,6 +1240,7 @@
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "Обновить" : {
 | 
					    "Обновить" : {
 | 
				
			||||||
 | 
					      "comment" : "Contacts retry button",
 | 
				
			||||||
      "localizations" : {
 | 
					      "localizations" : {
 | 
				
			||||||
        "en" : {
 | 
					        "en" : {
 | 
				
			||||||
          "stringUnit" : {
 | 
					          "stringUnit" : {
 | 
				
			||||||
@ -1828,6 +1829,9 @@
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
 | 
					    "Просмотр \"%1$@\" появится позже." : {
 | 
				
			||||||
 | 
					      "comment" : "Contacts placeholder message"
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
    "Профиль" : {
 | 
					    "Профиль" : {
 | 
				
			||||||
      "localizations" : {
 | 
					      "localizations" : {
 | 
				
			||||||
        "en" : {
 | 
					        "en" : {
 | 
				
			||||||
@ -2055,7 +2059,7 @@
 | 
				
			|||||||
      "comment" : "Search placeholder copy"
 | 
					      "comment" : "Search placeholder copy"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "Скоро" : {
 | 
					    "Скоро" : {
 | 
				
			||||||
      "comment" : "Add blocked user placeholder title"
 | 
					      "comment" : "Add blocked user placeholder title\nContacts placeholder title"
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    "Скоро появится мини-игра, где можно заработать очки для кастомизации профиля. Следите за обновлениями!" : {
 | 
					    "Скоро появится мини-игра, где можно заработать очки для кастомизации профиля. Следите за обновлениями!" : {
 | 
				
			||||||
      "comment" : "Concept tab placeholder description"
 | 
					      "comment" : "Concept tab placeholder description"
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,5 @@
 | 
				
			|||||||
import SwiftUI
 | 
					import SwiftUI
 | 
				
			||||||
 | 
					import Foundation
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct ContactsTab: View {
 | 
					struct ContactsTab: View {
 | 
				
			||||||
    @State private var contacts: [Contact] = []
 | 
					    @State private var contacts: [Contact] = []
 | 
				
			||||||
@ -17,15 +18,23 @@ struct ContactsTab: View {
 | 
				
			|||||||
            } else if contacts.isEmpty {
 | 
					            } else if contacts.isEmpty {
 | 
				
			||||||
                emptyState
 | 
					                emptyState
 | 
				
			||||||
            } else {
 | 
					            } 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)
 | 
					                        ContactRow(contact: contact)
 | 
				
			||||||
 | 
					                            .contentShape(Rectangle())
 | 
				
			||||||
                    }
 | 
					                    }
 | 
				
			||||||
 | 
					                    .buttonStyle(.plain)
 | 
				
			||||||
 | 
					                    .listRowInsets(EdgeInsets(top: 8, leading: 16, bottom: 8, trailing: 16))
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        .listStyle(.insetGrouped)
 | 
					        .background(Color(UIColor.systemBackground))
 | 
				
			||||||
        .background(Color(.systemGroupedBackground))
 | 
					        .listStyle(.plain)
 | 
				
			||||||
        .task {
 | 
					        .task {
 | 
				
			||||||
            await loadContacts()
 | 
					            await loadContacts()
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -40,42 +49,63 @@ struct ContactsTab: View {
 | 
				
			|||||||
                    message: Text(message),
 | 
					                    message: Text(message),
 | 
				
			||||||
                    dismissButton: .default(Text(NSLocalizedString("OK", comment: "Common OK")))
 | 
					                    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 {
 | 
					    private var loadingState: some View {
 | 
				
			||||||
        Section {
 | 
					        HStack {
 | 
				
			||||||
 | 
					            Spacer()
 | 
				
			||||||
            ProgressView()
 | 
					            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 {
 | 
					    private func errorState(_ message: String) -> some View {
 | 
				
			||||||
        Section {
 | 
					        HStack(alignment: .center, spacing: 8) {
 | 
				
			||||||
 | 
					            Image(systemName: "exclamationmark.triangle.fill")
 | 
				
			||||||
 | 
					                .foregroundColor(.orange)
 | 
				
			||||||
            Text(message)
 | 
					            Text(message)
 | 
				
			||||||
                .foregroundColor(.red)
 | 
					                .font(.subheadline)
 | 
				
			||||||
                .frame(maxWidth: .infinity, alignment: .center)
 | 
					                .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 {
 | 
					    private var emptyState: some View {
 | 
				
			||||||
        Section {
 | 
					        VStack(spacing: 12) {
 | 
				
			||||||
            VStack(spacing: 12) {
 | 
					            Image(systemName: "person.crop.circle.badge.questionmark")
 | 
				
			||||||
                Image(systemName: "person.crop.circle.badge.questionmark")
 | 
					                .font(.system(size: 52))
 | 
				
			||||||
                    .font(.system(size: 48))
 | 
					                .foregroundColor(.secondary)
 | 
				
			||||||
                    .foregroundColor(.secondary)
 | 
					            Text(NSLocalizedString("Контактов пока нет", comment: "Contacts empty state title"))
 | 
				
			||||||
                Text(NSLocalizedString("Контактов пока нет", comment: "Contacts empty state title"))
 | 
					                .font(.headline)
 | 
				
			||||||
                    .font(.headline)
 | 
					                .multilineTextAlignment(.center)
 | 
				
			||||||
                    .multilineTextAlignment(.center)
 | 
					            Text(NSLocalizedString("Добавьте контакты, чтобы быстрее выходить на связь.", comment: "Contacts empty state subtitle"))
 | 
				
			||||||
                Text(NSLocalizedString("Добавьте контакты, чтобы быстрее выходить на связь.", comment: "Contacts empty state subtitle"))
 | 
					                .font(.subheadline)
 | 
				
			||||||
                    .font(.subheadline)
 | 
					                .foregroundColor(.secondary)
 | 
				
			||||||
                    .foregroundColor(.secondary)
 | 
					                .multilineTextAlignment(.center)
 | 
				
			||||||
                    .multilineTextAlignment(.center)
 | 
					 | 
				
			||||||
            }
 | 
					 | 
				
			||||||
            .frame(maxWidth: .infinity)
 | 
					 | 
				
			||||||
            .padding(.vertical, 24)
 | 
					 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					        .frame(maxWidth: .infinity)
 | 
				
			||||||
 | 
					        .padding(.vertical, 36)
 | 
				
			||||||
 | 
					        .listRowInsets(EdgeInsets(top: 24, leading: 16, bottom: 24, trailing: 16))
 | 
				
			||||||
 | 
					        .listRowSeparator(.hidden)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    @MainActor
 | 
					    @MainActor
 | 
				
			||||||
@ -104,38 +134,50 @@ private struct ContactRow: View {
 | 
				
			|||||||
    let contact: Contact
 | 
					    let contact: Contact
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var body: some View {
 | 
					    var body: some View {
 | 
				
			||||||
        HStack(spacing: 12) {
 | 
					        HStack(alignment: .top, spacing: 14) {
 | 
				
			||||||
            Circle()
 | 
					            Circle()
 | 
				
			||||||
                .fill(Color.accentColor.opacity(0.15))
 | 
					                .fill(Color.accentColor.opacity(0.15))
 | 
				
			||||||
                .frame(width: 44, height: 44)
 | 
					                .frame(width: 52, height: 52)
 | 
				
			||||||
                .overlay(
 | 
					                .overlay(
 | 
				
			||||||
                    Text(contact.initials)
 | 
					                    Text(contact.initials)
 | 
				
			||||||
                        .font(.headline)
 | 
					                        .font(.headline)
 | 
				
			||||||
                        .foregroundColor(.accentColor)
 | 
					                        .foregroundColor(.accentColor)
 | 
				
			||||||
                )
 | 
					                )
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            VStack(alignment: .leading, spacing: 4) {
 | 
					            VStack(alignment: .leading, spacing: 6) {
 | 
				
			||||||
                Text(contact.displayName)
 | 
					                HStack(alignment: .firstTextBaseline) {
 | 
				
			||||||
                    .font(.body)
 | 
					                    Text(contact.displayName)
 | 
				
			||||||
 | 
					                        .font(.headline)
 | 
				
			||||||
 | 
					                        .foregroundColor(.primary)
 | 
				
			||||||
 | 
					                    Spacer()
 | 
				
			||||||
 | 
					                    Text(contact.formattedCreatedAt)
 | 
				
			||||||
 | 
					                        .font(.caption)
 | 
				
			||||||
 | 
					                        .foregroundColor(.secondary)
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                if let handle = contact.handle {
 | 
					                if let handle = contact.handle {
 | 
				
			||||||
                    Text(handle)
 | 
					                    Text(handle)
 | 
				
			||||||
                        .font(.caption)
 | 
					                        .font(.caption)
 | 
				
			||||||
                        .foregroundColor(.secondary)
 | 
					                        .foregroundColor(.secondary)
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
                HStack(spacing: 8) {
 | 
					
 | 
				
			||||||
                    if contact.friendCode {
 | 
					                if contact.friendCode {
 | 
				
			||||||
                        Label(NSLocalizedString("Код дружбы", comment: "Friend code badge"), systemImage: "heart.circle")
 | 
					                    friendCodeBadge
 | 
				
			||||||
                            .font(.caption2)
 | 
					 | 
				
			||||||
                            .foregroundColor(.secondary)
 | 
					 | 
				
			||||||
                    }
 | 
					 | 
				
			||||||
                    Text(contact.formattedCreatedAt)
 | 
					 | 
				
			||||||
                        .font(.caption2)
 | 
					 | 
				
			||||||
                        .foregroundColor(.secondary)
 | 
					 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
            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 {
 | 
					private enum ContactsAlert: Identifiable {
 | 
				
			||||||
    case error(id: UUID = UUID(), message: String)
 | 
					    case error(id: UUID = UUID(), message: String)
 | 
				
			||||||
 | 
					    case info(id: UUID = UUID(), title: String, message: String)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    var id: String {
 | 
					    var id: String {
 | 
				
			||||||
        switch self {
 | 
					        switch self {
 | 
				
			||||||
        case .error(let id, _):
 | 
					        case .error(let id, _), .info(let id, _, _):
 | 
				
			||||||
            return id.uuidString
 | 
					            return id.uuidString
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user