Repository navigation
Expand file tree
/
Copy pathContactsSceneViewModel.swift
More file actions
130 lines (113 loc) · 3.8 KB
/
Copy pathContactsSceneViewModel.swift
File metadata and controls
130 lines (113 loc) · 3.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
// Copyright (c). Gem Wallet. All rights reserved.
import Components
import Foundation
import func Gemstone.contactList
import struct Gemstone.GemContactAddressInput
import struct Gemstone.GemContactList
import struct Gemstone.GemContactRow
import protocol Gemstone.GemContactServiceProtocol
import struct Gemstone.GemRecipient
import GemstonePrimitives
import GemstoneServices
import Localization
import Primitives
import PrimitivesComponents
import Store
import Style
import SwiftUI
@Observable
@MainActor
public final class ContactsSceneViewModel {
public enum Mode: Sendable {
case list
case addAddress(GemRecipient, chain: Chain)
}
enum RowAction {
case navigate
case select
}
private let service: any GemContactServiceProtocol
private let contactEditor: @MainActor (ContactEditorSceneViewModel.Mode) -> ContactEditorSceneViewModel
private let mode: Mode
var isPresentingAlertMessage: AlertMessage?
public let query: ObservableQuery<ContactsQuery>
var contacts: [ContactData] {
query.value
}
var isPresentingAddContact = false
public init(
service: any GemContactServiceProtocol,
contactEditor: @escaping @MainActor (ContactEditorSceneViewModel.Mode) -> ContactEditorSceneViewModel,
mode: Mode = .list,
) {
self.service = service
self.contactEditor = contactEditor
self.mode = mode
query = ObservableQuery(ContactsQuery(), initialValue: [])
}
var title: String {
Localized.Contacts.title
}
var rowAction: RowAction {
switch mode {
case .list: .navigate
case .addAddress: .select
}
}
func contactEditorModel(mode: ContactEditorSceneViewModel.Mode) -> ContactEditorSceneViewModel {
contactEditor(mode)
}
var addContactMode: ContactEditorSceneViewModel.Mode {
switch mode {
case .list: .add()
case let .addAddress(recipient, chain): .add(recipient: recipient, chain: chain)
}
}
func onSelect(contact: ContactData, dismiss: DismissAction) {
guard case let .addAddress(recipient, chain) = mode else { return }
Task {
do {
let addresses = GemContactAddressInput(
contactId: contact.contact.id,
chain: chain.rawValue,
address: recipient.address,
memo: recipient.memo,
replacingId: nil,
).addAddress(addresses: contact.addresses.map { $0.toGem() })
try await service.updateContact(contact: contact.contact.toGem(), addresses: addresses)
dismiss()
} catch {
isPresentingAlertMessage = AlertMessage(error: error)
}
}
}
var list: GemContactList {
contactList(contacts: contacts.map { $0.contact.toGem() })
}
func items(_ list: GemContactList) -> [(contact: ContactData, listItem: ListItemModel)] {
zip(contacts, list.rows).map { contact, row in
(contact, listItemModel(row: row))
}
}
private func listItemModel(row: GemContactRow) -> ListItemModel {
ListItemModel(
title: row.title,
titleExtra: row.subtitle,
titleStyleExtra: .calloutSecondary,
titleExtraLineLimit: 1,
imageStyle: .asset(assetImage: row.avatar.assetImage),
)
}
func deleteContacts(at offsets: IndexSet) {
let selected = offsets.map { contacts[$0].contact }
Task {
do {
for contact in selected {
try await service.deleteContact(contact: contact.toGem())
}
} catch {
isPresentingAlertMessage = AlertMessage(error: error)
}
}
}
}