fix contact
This commit is contained in:
parent
e44d56e71b
commit
e9b43e76fa
@ -25,6 +25,11 @@ struct ContactPayload: Decodable {
|
||||
let createdAt: Date
|
||||
}
|
||||
|
||||
struct ContactsListPayload: Decodable {
|
||||
let items: [ContactPayload]
|
||||
let hasMore: Bool
|
||||
}
|
||||
|
||||
final class ContactsService {
|
||||
private let client: NetworkClient
|
||||
private let decoder: JSONDecoder
|
||||
@ -36,16 +41,20 @@ final class ContactsService {
|
||||
self.decoder.dateDecodingStrategy = .custom(Self.decodeDate)
|
||||
}
|
||||
|
||||
func fetchContacts(completion: @escaping (Result<[ContactPayload], Error>) -> Void) {
|
||||
func fetchContacts(limit: Int, offset: Int, completion: @escaping (Result<ContactsListPayload, Error>) -> Void) {
|
||||
client.request(
|
||||
path: "/v1/user/contact/list",
|
||||
method: .get,
|
||||
query: [
|
||||
"limit": String(limit),
|
||||
"offset": String(offset)
|
||||
],
|
||||
requiresAuth: true
|
||||
) { [decoder] result in
|
||||
switch result {
|
||||
case .success(let response):
|
||||
do {
|
||||
let apiResponse = try decoder.decode(APIResponse<[ContactPayload]>.self, from: response.data)
|
||||
let apiResponse = try decoder.decode(APIResponse<ContactsListPayload>.self, from: response.data)
|
||||
guard apiResponse.status == "fine" else {
|
||||
let message = apiResponse.detail ?? NSLocalizedString("Не удалось загрузить контакты.", comment: "Contacts service unexpected status")
|
||||
completion(.failure(ContactsServiceError.unexpectedStatus(message)))
|
||||
@ -71,9 +80,9 @@ final class ContactsService {
|
||||
}
|
||||
}
|
||||
|
||||
func fetchContacts() async throws -> [ContactPayload] {
|
||||
func fetchContacts(limit: Int, offset: Int) async throws -> ContactsListPayload {
|
||||
try await withCheckedThrowingContinuation { continuation in
|
||||
fetchContacts { result in
|
||||
fetchContacts(limit: limit, offset: offset) { result in
|
||||
continuation.resume(with: result)
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,9 +5,13 @@ struct ContactsTab: View {
|
||||
@State private var contacts: [Contact] = []
|
||||
@State private var isLoading = false
|
||||
@State private var loadError: String?
|
||||
@State private var pagingError: String?
|
||||
@State private var activeAlert: ContactsAlert?
|
||||
@State private var hasMore = true
|
||||
@State private var offset = 0
|
||||
|
||||
private let contactsService = ContactsService()
|
||||
private let pageSize = 25
|
||||
|
||||
var body: some View {
|
||||
List {
|
||||
@ -20,7 +24,7 @@ struct ContactsTab: View {
|
||||
} else if contacts.isEmpty {
|
||||
emptyState
|
||||
} else {
|
||||
ForEach(contacts) { contact in
|
||||
ForEach(Array(contacts.enumerated()), id: \.element.id) { index, contact in
|
||||
Button {
|
||||
showContactPlaceholder(for: contact)
|
||||
} label: {
|
||||
@ -57,16 +61,29 @@ struct ContactsTab: View {
|
||||
}
|
||||
}
|
||||
.listRowInsets(EdgeInsets(top: 0, leading: 12, bottom: 0, trailing: 12))
|
||||
.onAppear {
|
||||
if index >= contacts.count - 5 {
|
||||
Task {
|
||||
await loadContacts(reset: false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if isLoading && !contacts.isEmpty {
|
||||
loadingState
|
||||
} else if let pagingError, !contacts.isEmpty {
|
||||
pagingErrorState(pagingError)
|
||||
}
|
||||
}
|
||||
}
|
||||
.background(Color(UIColor.systemBackground))
|
||||
.listStyle(.plain)
|
||||
.task {
|
||||
await loadContacts()
|
||||
await loadContacts(reset: false)
|
||||
}
|
||||
.refreshable {
|
||||
await loadContacts()
|
||||
await refreshContacts()
|
||||
}
|
||||
.alert(item: $activeAlert) { alert in
|
||||
switch alert {
|
||||
@ -106,7 +123,25 @@ struct ContactsTab: View {
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.orange)
|
||||
Spacer()
|
||||
Button(action: { Task { await loadContacts() } }) {
|
||||
Button(action: { Task { await refreshContacts() } }) {
|
||||
Text(NSLocalizedString("Обновить", comment: "Contacts retry button"))
|
||||
.font(.subheadline)
|
||||
}
|
||||
}
|
||||
.padding(.vertical, 10)
|
||||
.listRowInsets(EdgeInsets(top: 10, leading: 12, bottom: 10, trailing: 12))
|
||||
.listRowSeparator(.hidden)
|
||||
}
|
||||
|
||||
private func pagingErrorState(_ message: String) -> some View {
|
||||
HStack(alignment: .center, spacing: 8) {
|
||||
Image(systemName: "exclamationmark.triangle.fill")
|
||||
.foregroundColor(.orange)
|
||||
Text(message)
|
||||
.font(.subheadline)
|
||||
.foregroundColor(.orange)
|
||||
Spacer()
|
||||
Button(action: { Task { await loadContacts(reset: false) } }) {
|
||||
Text(NSLocalizedString("Обновить", comment: "Contacts retry button"))
|
||||
.font(.subheadline)
|
||||
}
|
||||
@ -136,20 +171,43 @@ struct ContactsTab: View {
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func loadContacts() async {
|
||||
if isLoading {
|
||||
return
|
||||
private func refreshContacts() async {
|
||||
hasMore = true
|
||||
offset = 0
|
||||
pagingError = nil
|
||||
loadError = nil
|
||||
contacts.removeAll()
|
||||
await loadContacts(reset: true)
|
||||
}
|
||||
|
||||
@MainActor
|
||||
private func loadContacts(reset: Bool) async {
|
||||
if isLoading { return }
|
||||
if !reset && !hasMore { return }
|
||||
|
||||
isLoading = true
|
||||
if offset == 0 {
|
||||
loadError = nil
|
||||
}
|
||||
pagingError = nil
|
||||
|
||||
do {
|
||||
let payloads = try await contactsService.fetchContacts()
|
||||
contacts = payloads.map(Contact.init)
|
||||
let payload = try await contactsService.fetchContacts(limit: pageSize, offset: offset)
|
||||
let newContacts = payload.items.map(Contact.init)
|
||||
if reset {
|
||||
contacts = newContacts
|
||||
} else {
|
||||
contacts.append(contentsOf: newContacts)
|
||||
}
|
||||
offset += newContacts.count
|
||||
hasMore = payload.hasMore
|
||||
} catch {
|
||||
loadError = error.localizedDescription
|
||||
// activeAlert = .error(message: error.localizedDescription)
|
||||
let message = error.localizedDescription
|
||||
if contacts.isEmpty {
|
||||
loadError = message
|
||||
} else {
|
||||
pagingError = message
|
||||
}
|
||||
if AppConfig.DEBUG { print("[ContactsTab] load contacts failed: \(error)") }
|
||||
}
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user