Add Flow coordinator and hook up screens.

This commit is contained in:
David Langley
2021-09-17 10:46:40 +01:00
parent f603d7cf4c
commit 935a8ac9d9
14 changed files with 209 additions and 45 deletions
@@ -0,0 +1,113 @@
// File created from FlowTemplate
// $ createRootCoordinator.sh TemplateRoomsCoordinator TemplateRooms
/*
Copyright 2021 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import UIKit
@objcMembers
final class TemplateRoomsCoordinator: Coordinator {
// MARK: - Properties
// MARK: Private
private let parameters: TemplateRoomsCoordinatorParameters
private var navigationRouter: NavigationRouterType {
return self.parameters.navigationRouter
}
// MARK: Public
// Must be used only internally
var childCoordinators: [Coordinator] = []
var completion: (() -> Void)?
// MARK: - Setup
init(parameters: TemplateRoomsCoordinatorParameters) {
self.parameters = parameters
}
// MARK: - Public
func start() {
if #available(iOS 14.0, *) {
let rootCoordinator = self.createTemplateRoomListCoordinator()
rootCoordinator.start()
self.add(childCoordinator: rootCoordinator)
if self.navigationRouter.modules.isEmpty == false {
self.navigationRouter.push(rootCoordinator, animated: true, popCompletion: { [weak self] in
self?.remove(childCoordinator: rootCoordinator)
})
} else {
self.navigationRouter.setRootModule(rootCoordinator) { [weak self] in
self?.remove(childCoordinator: rootCoordinator)
}
}
}
}
func toPresentable() -> UIViewController {
return self.navigationRouter.toPresentable()
}
// MARK: - Private
@available(iOS 14.0, *)
private func createTemplateRoomListCoordinator() -> TemplateRoomListCoordinator {
let coordinator: TemplateRoomListCoordinator = TemplateRoomListCoordinator(parameters: TemplateRoomListCoordinatorParameters(session: parameters.session))
coordinator.completion = { [weak self] result in
guard let self = self else { return }
switch result {
case .didSelectRoom(let roomId):
self.showTemplateRoomChat(roomId: roomId)
case .done:
self.completion?()
}
}
return coordinator
}
@available(iOS 14.0, *)
private func createTemplateRoomChatCoordinator(room: MXRoom) -> TemplateRoomChatCoordinator {
let coordinator: TemplateRoomChatCoordinator = TemplateRoomChatCoordinator(parameters: TemplateRoomChatCoordinatorParameters(room: room))
return coordinator
}
@available(iOS 14.0, *)
func showTemplateRoomChat(roomId: String) {
guard let room = parameters.session.room(withRoomId: roomId) else {
MXLog.error("[TemplateRoomsCoordinator] Failed to find room by selected Id.")
return
}
let templateRoomChatCoordinator = createTemplateRoomChatCoordinator(room: room)
add(childCoordinator: templateRoomChatCoordinator)
self.navigationRouter.push(templateRoomChatCoordinator, animated: true, popCompletion: { [weak self] in
self?.remove(childCoordinator: templateRoomChatCoordinator)
})
templateRoomChatCoordinator.start()
}
}
@@ -0,0 +1,35 @@
// File created from FlowTemplate
// $ createRootCoordinator.sh TemplateRoomsCoordinator TemplateRooms
/*
Copyright 2021 New Vector Ltd
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
import Foundation
/// TemplateRoomsCoordinator input parameters
struct TemplateRoomsCoordinatorParameters {
/// The Matrix session
let session: MXSession
/// The navigation router that manage physical navigation
let navigationRouter: NavigationRouterType
init(session: MXSession,
navigationRouter: NavigationRouterType? = nil) {
self.session = session
self.navigationRouter = navigationRouter ?? NavigationRouter(navigationController: RiotNavigationController())
}
}
@@ -18,7 +18,7 @@ import Foundation
import UIKit
import SwiftUI
final class TemplateRoomChatCoordinator: Coordinator {
final class TemplateRoomChatCoordinator: Coordinator, Presentable {
// MARK: - Properties
@@ -51,7 +51,7 @@ final class TemplateRoomChatCoordinator: Coordinator {
templateRoomChatViewModel.completion = { [weak self] result in
guard let self = self else { return }
switch result {
case .cancel, .done:
case .done:
self.completion?()
break
}
@@ -18,6 +18,5 @@ import Foundation
enum TemplateRoomChatViewAction {
case sendMessage
case cancel
case done
}
@@ -17,6 +17,5 @@
import Foundation
enum TemplateRoomChatViewModelResult {
case cancel
case done
}
@@ -28,6 +28,7 @@ struct TemplateRoomChat: View {
// MARK: Public
@ObservedObject var viewModel: TemplateRoomChatViewModel.Context
var presentedModally = false
var body: some View {
VStack {
@@ -76,24 +77,27 @@ struct TemplateRoomChat: View {
// When displaying/hiding the send button slide it on/off from the right side
.animation(.easeOut(duration: 0.25))
.transition(.move(edge: .trailing))
.padding(.horizontal)
.padding()
}
.navigationTitle(viewModel.viewState.roomName ?? "Chat")
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button(VectorL10n.done) {
viewModel.send(viewAction: .cancel)
}
}
ToolbarItem(placement: .cancellationAction) {
Button(VectorL10n.cancel) {
viewModel.send(viewAction: .cancel)
}
trailingToolBarButton
}
}
}
@ViewBuilder
private var trailingToolBarButton: some View {
if presentedModally {
Button(VectorL10n.done) {
viewModel.send(viewAction: .done)
}
}
}
private var itemCount: Int {
return viewModel.viewState
.bubbles
@@ -107,8 +107,6 @@ class TemplateRoomChatViewModel: TemplateRoomChatViewModelType, TemplateRoomChat
override func process(viewAction: TemplateRoomChatViewAction) {
switch viewAction {
case .cancel:
cancel()
case .done:
done()
case .sendMessage:
@@ -132,8 +130,4 @@ class TemplateRoomChatViewModel: TemplateRoomChatViewModelType, TemplateRoomChat
private func done() {
completion?(.done)
}
private func cancel() {
completion?(.cancel)
}
}
@@ -18,7 +18,7 @@ import Foundation
import UIKit
import SwiftUI
final class TemplateRoomListCoordinator: Coordinator {
final class TemplateRoomListCoordinator: Coordinator, Presentable {
// MARK: - Properties
@@ -32,7 +32,7 @@ final class TemplateRoomListCoordinator: Coordinator {
// Must be used only internally
var childCoordinators: [Coordinator] = []
var completion: (() -> Void)?
var completion: ((TemplateRoomListCoordinatorResult) -> Void)?
// MARK: - Setup
@@ -52,8 +52,10 @@ final class TemplateRoomListCoordinator: Coordinator {
templateRoomListViewModel.completion = { [weak self] result in
guard let self = self else { return }
switch result {
case .cancel, .done:
self.completion?()
case .didSelectRoom(let roomId):
self.completion?(.didSelectRoom(roomId))
case .done:
self.completion?(.done)
break
}
}
@@ -0,0 +1,22 @@
//
// Copyright 2021 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import Foundation
enum TemplateRoomListCoordinatorResult {
case didSelectRoom(String)
case done
}
@@ -17,6 +17,6 @@
import Foundation
enum TemplateRoomListViewAction {
case cancel
case done
case didSelectRoom(String)
}
@@ -17,6 +17,6 @@
import Foundation
enum TemplateRoomListViewModelResult {
case cancel
case didSelectRoom(String)
case done
}
@@ -35,11 +35,6 @@ class TemplateRoomListService: TemplateRoomListServiceProtocol {
init(session: MXSession) {
self.session = session
self.roomsSubject = CurrentValueSubject(session.rooms.map(TemplateRoomListRoom.init(mxRoom:)))
// self.listenerReference = setupPresenceListener()
}
deinit {
// guard let reference = listenerReference else { return }
}
}
@@ -35,12 +35,7 @@ struct TemplateRoomList: View {
.toolbar {
ToolbarItem(placement: .primaryAction) {
Button(VectorL10n.done) {
viewModel.send(viewAction: .cancel)
}
}
ToolbarItem(placement: .cancellationAction) {
Button(VectorL10n.cancel) {
viewModel.send(viewAction: .cancel)
viewModel.send(viewAction: .done)
}
}
}
@@ -51,12 +46,18 @@ struct TemplateRoomList: View {
if viewModel.viewState.rooms.isEmpty {
Text("No Rooms")
} else {
LazyVStack(spacing: 0) {
ForEach(viewModel.viewState.rooms) { room in
TemplateRoomListRow(avatar: room.avatar, displayName: room.displayName)
ScrollView{
LazyVStack(spacing: 0) {
ForEach(viewModel.viewState.rooms) { room in
Button {
viewModel.send(viewAction: .didSelectRoom(room.id))
} label: {
TemplateRoomListRow(avatar: room.avatar, displayName: room.displayName)
}
}
}
.frame(maxHeight: .infinity, alignment: .top)
}
.frame(maxHeight: .infinity, alignment: .top)
}
}
}
@@ -67,7 +68,7 @@ struct TemplateRoomList: View {
struct TemplateRoomList_Previews: PreviewProvider {
static var previews: some View {
MockTemplateRoomListScreenState
.screenGroup(themeId: .dark, addNavigation: true)
.screenGroup(addNavigation: true)
}
}
@@ -58,8 +58,8 @@ class TemplateRoomListViewModel: TemplateRoomListViewModelType, TemplateRoomList
override func process(viewAction: TemplateRoomListViewAction) {
switch viewAction {
case .cancel:
cancel()
case .didSelectRoom(let roomId):
didSelect(by: roomId)
case .done:
done()
}
@@ -79,7 +79,7 @@ class TemplateRoomListViewModel: TemplateRoomListViewModelType, TemplateRoomList
completion?(.done)
}
private func cancel() {
completion?(.cancel)
private func didSelect(by roomId: String) {
completion?(.didSelectRoom(roomId))
}
}