mirror of
https://github.com/Novaloop-AG/element-x-ios.git
synced 2026-11-03 06:55:59 +00:00
SwiftUI NavigationController and UserNotificationControllers (#309)
* Fixes #286 - Adopted the new SwiftUI NavigationStack based NavigationController throughout the application * Fixes #315 - Implemented new user notification components on top of SwiftUI and the new navigation flows * Add home screen fade animation between skeletons and real rooms * Bump the danger-swift version used on the CI and swiftlint with it * Renamed Splash to Onboarding, Empty to Splash
This commit is contained in:
@@ -20,6 +20,8 @@ import SwiftUI
|
||||
struct HomeScreenCoordinatorParameters {
|
||||
let userSession: UserSessionProtocol
|
||||
let attributedStringBuilder: AttributedStringBuilderProtocol
|
||||
let bugReportService: BugReportServiceProtocol
|
||||
let navigationController: NavigationController
|
||||
}
|
||||
|
||||
enum HomeScreenCoordinatorAction {
|
||||
@@ -30,34 +32,20 @@ enum HomeScreenCoordinatorAction {
|
||||
case signOut
|
||||
}
|
||||
|
||||
final class HomeScreenCoordinator: Coordinator, Presentable {
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
|
||||
final class HomeScreenCoordinator: CoordinatorProtocol {
|
||||
private let parameters: HomeScreenCoordinatorParameters
|
||||
private let hostingController: UIViewController
|
||||
private var viewModel: HomeScreenViewModelProtocol
|
||||
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
|
||||
// MARK: Public
|
||||
|
||||
// Must be used only internally
|
||||
var childCoordinators: [Coordinator] = []
|
||||
var callback: ((HomeScreenCoordinatorAction) -> Void)?
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(parameters: HomeScreenCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
|
||||
viewModel = HomeScreenViewModel(userSession: parameters.userSession,
|
||||
attributedStringBuilder: parameters.attributedStringBuilder)
|
||||
|
||||
let view = HomeScreen(context: viewModel.context)
|
||||
hostingController = UIHostingController(rootView: view)
|
||||
|
||||
viewModel.callback = { [weak self] action in
|
||||
guard let self else { return }
|
||||
|
||||
@@ -74,13 +62,21 @@ final class HomeScreenCoordinator: Coordinator, Presentable {
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func start() { }
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
hostingController
|
||||
func start() {
|
||||
if parameters.bugReportService.crashedLastRun {
|
||||
viewModel.presentAlert(
|
||||
AlertInfo(id: UUID(),
|
||||
title: ElementL10n.sendBugReportAppCrashed,
|
||||
primaryButton: .init(title: ElementL10n.no, action: nil),
|
||||
secondaryButton: .init(title: ElementL10n.yes) { [weak self] in
|
||||
self?.callback?(.presentFeedbackScreen)
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
func toPresentable() -> AnyView {
|
||||
AnyView(HomeScreen(context: viewModel.context))
|
||||
}
|
||||
|
||||
func stop() { }
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
@@ -98,11 +94,6 @@ final class HomeScreenCoordinator: Coordinator, Presentable {
|
||||
}
|
||||
|
||||
private func presentInviteFriends() {
|
||||
guard let permalink = try? PermalinkBuilder.permalinkTo(userIdentifier: parameters.userSession.userID).absoluteString else {
|
||||
return
|
||||
}
|
||||
let shareText = ElementL10n.inviteFriendsText(ElementInfoPlist.cfBundleDisplayName, permalink)
|
||||
let vc = UIActivityViewController(activityItems: [shareText], applicationActivities: nil)
|
||||
hostingController.present(vc, animated: true)
|
||||
parameters.navigationController.presentSheet(InviteFriendsCoordinator(userId: parameters.userSession.userID))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ struct HomeScreenViewState: BindableState {
|
||||
|
||||
var rooms: [HomeScreenRoom] = []
|
||||
|
||||
var roomListMode: HomeScreenRoomListMode = .rooms
|
||||
var roomListMode: HomeScreenRoomListMode = .skeletons
|
||||
|
||||
var visibleRooms: [HomeScreenRoom] {
|
||||
if roomListMode == .skeletons {
|
||||
@@ -77,6 +77,8 @@ struct HomeScreenViewState: BindableState {
|
||||
|
||||
struct HomeScreenViewStateBindings {
|
||||
var searchQuery = ""
|
||||
|
||||
var alertInfo: AlertInfo<UUID>?
|
||||
}
|
||||
|
||||
struct HomeScreenRoom: Identifiable, Equatable {
|
||||
@@ -92,15 +94,12 @@ struct HomeScreenRoom: Identifiable, Equatable {
|
||||
|
||||
var avatar: UIImage?
|
||||
|
||||
var isPlaceholder = false
|
||||
|
||||
static func placeholder(id: String) -> HomeScreenRoom {
|
||||
HomeScreenRoom(id: id,
|
||||
name: "Placeholder room name",
|
||||
hasUnreads: false,
|
||||
timestamp: "Now",
|
||||
lastMessage: AttributedString("Last message"),
|
||||
avatar: UIImage(systemName: "photo"),
|
||||
isPlaceholder: true)
|
||||
avatar: UIImage(systemName: "photo"))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -111,6 +111,10 @@ class HomeScreenViewModel: HomeScreenViewModelType, HomeScreenViewModelProtocol
|
||||
}
|
||||
}
|
||||
|
||||
func presentAlert(_ alertInfo: AlertInfo<UUID>) {
|
||||
state.bindings.alertInfo = alertInfo
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func loadDataForRoomIdentifier(_ identifier: String) {
|
||||
|
||||
@@ -22,4 +22,6 @@ protocol HomeScreenViewModelProtocol {
|
||||
var callback: ((HomeScreenViewModelAction) -> Void)? { get set }
|
||||
|
||||
var context: HomeScreenViewModelType.Context { get }
|
||||
|
||||
func presentAlert(_ alert: AlertInfo<UUID>)
|
||||
}
|
||||
|
||||
@@ -28,23 +28,30 @@ struct HomeScreen: View {
|
||||
sessionVerificationBanner
|
||||
}
|
||||
|
||||
LazyVStack {
|
||||
ForEach(context.viewState.visibleRooms) { room in
|
||||
if room.isPlaceholder {
|
||||
if context.viewState.roomListMode == .skeletons {
|
||||
LazyVStack {
|
||||
ForEach(context.viewState.visibleRooms) { room in
|
||||
HomeScreenRoomCell(room: room, context: context)
|
||||
.redacted(reason: .placeholder)
|
||||
.disabled(true)
|
||||
} else {
|
||||
}
|
||||
}
|
||||
.padding(.horizontal)
|
||||
} else {
|
||||
LazyVStack {
|
||||
ForEach(context.viewState.visibleRooms) { room in
|
||||
HomeScreenRoomCell(room: room, context: context)
|
||||
}
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.searchable(text: $context.searchQuery)
|
||||
}
|
||||
.padding(.horizontal)
|
||||
.searchable(text: $context.searchQuery)
|
||||
}
|
||||
.disabled(context.viewState.roomListMode == .skeletons)
|
||||
.animation(.elementDefault, value: context.viewState.showSessionVerificationBanner)
|
||||
.animation(.elementDefault, value: context.viewState.roomListMode)
|
||||
.ignoresSafeArea(.all, edges: .bottom)
|
||||
.alert(item: $context.alertInfo) { $0.alert }
|
||||
.navigationTitle(ElementL10n.allChats)
|
||||
.toolbar {
|
||||
ToolbarItem(placement: .navigationBarLeading) {
|
||||
|
||||
Reference in New Issue
Block a user