mirror of
https://github.com/ProtonMail/ios-mail.git
synced 2026-05-15 09:50:39 +00:00
148 lines
5.0 KiB
Swift
148 lines
5.0 KiB
Swift
// Copyright (c) 2024 Proton Technologies AG
|
|
//
|
|
// This file is part of Proton Mail.
|
|
//
|
|
// Proton Mail is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// Proton Mail is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with Proton Mail. If not, see https://www.gnu.org/licenses/.
|
|
|
|
import InboxCore
|
|
import InboxCoreUI
|
|
import InboxDesignSystem
|
|
import SwiftUI
|
|
import proton_app_uniffi
|
|
|
|
public struct ContactsScreen: View {
|
|
@Environment(\.dismissTestable) var dismiss: Dismissable
|
|
|
|
@StateObject private var store: ContactsStateStore
|
|
private let contactViewFactory: ContactViewFactory
|
|
|
|
/// `state` parameter is exposed only for testing purposes to be able to rely on data source in synchronous manner.
|
|
public init(
|
|
apiConfig: ApiConfig,
|
|
state: ContactsScreenState = .initial,
|
|
mailUserSession: MailUserSession,
|
|
contactsProvider: GroupedContactsProvider,
|
|
contactsWatcher: ContactsWatcher,
|
|
draftPresenter: ContactsDraftPresenter
|
|
) {
|
|
UISearchBar.appearance().tintColor = UIColor(DS.Color.Text.accent)
|
|
_store = .init(
|
|
wrappedValue: .init(
|
|
apiConfig: apiConfig,
|
|
state: state,
|
|
mailUserSession: mailUserSession,
|
|
contactsWrappers: .productionInstance(
|
|
contactsProvider: contactsProvider,
|
|
contactsWatcher: contactsWatcher
|
|
)
|
|
)
|
|
)
|
|
self.contactViewFactory = .init(
|
|
apiConfig: apiConfig,
|
|
mailUserSession: mailUserSession,
|
|
draftPresenter: draftPresenter
|
|
)
|
|
}
|
|
|
|
public var body: some View {
|
|
NavigationStack(path: navigationPath(store: store)) {
|
|
ContactsControllerRepresentable(
|
|
contacts: store.state.displayItems,
|
|
onDeleteItem: { item in handle(action: .onDeleteItem(item)) },
|
|
onTapItem: { item in handle(action: .onTapItem(item)) }
|
|
)
|
|
.ignoresSafeArea()
|
|
.navigationTitle(L10n.Contacts.title.string)
|
|
.navigationDestination(for: ContactsRoute.self) { route in
|
|
contactViewFactory
|
|
.makeView(for: route)
|
|
.environmentObject(store.router)
|
|
.navigationBarBackButtonHidden()
|
|
.toolbar {
|
|
ToolbarItemFactory.back { handle(action: .goBack) }
|
|
}
|
|
}
|
|
.toolbar {
|
|
ToolbarItem(placement: .topBarLeading) {
|
|
ButtonFactory.close {
|
|
dismiss()
|
|
}
|
|
}
|
|
ToolbarItemFactory.trailing(Image(symbol: .plus)) {
|
|
handle(action: .createTapped)
|
|
}
|
|
}
|
|
}
|
|
.sheet(
|
|
isPresented: $store.state.displayCreateContactSheet,
|
|
content: {
|
|
PromptSheet(
|
|
model: .createInWeb(
|
|
onAction: { handle(action: .createSheetAction(.openSafari)) },
|
|
onDismiss: { handle(action: .createSheetAction(.dismiss)) }
|
|
)
|
|
)
|
|
}
|
|
)
|
|
.sheet(
|
|
item: $store.state.createContactURL,
|
|
onDismiss: { handle(action: .dismissCreateSheet) },
|
|
content: SafariView.init
|
|
)
|
|
.alert(model: deletionAlert)
|
|
.searchable(
|
|
text: $store.state.search.query,
|
|
isPresented: $store.state.search.isActive,
|
|
placement: .navigationBarDrawer(displayMode: .always)
|
|
)
|
|
.onLoad { handle(action: .onLoad) }
|
|
}
|
|
|
|
// MARK: - Private
|
|
|
|
private func navigationPath(store: ContactsStateStore) -> Binding<[ContactsRoute]> {
|
|
.init(
|
|
get: { store.router.stack },
|
|
set: { newStack in store.router.stack = newStack }
|
|
)
|
|
}
|
|
|
|
private var deletionAlert: Binding<AlertModel?> {
|
|
.readonly {
|
|
store.state.itemToDelete.map { itemType in
|
|
DeleteConfirmationAlertFactory.make(
|
|
for: itemType,
|
|
action: { action in handle(action: .onDeleteItemAlertAction(action)) }
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func handle(action: ContactsStateStore.Action) {
|
|
Task {
|
|
await store.handle(action: action)
|
|
}
|
|
}
|
|
}
|
|
|
|
#Preview {
|
|
ContactsScreen(
|
|
apiConfig: .debugPreview,
|
|
mailUserSession: .init(noPointer: .init()),
|
|
contactsProvider: .previewInstance(),
|
|
contactsWatcher: .previewInstance(),
|
|
draftPresenter: ContactsDraftPresenterDummy()
|
|
)
|
|
}
|