mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-23 18:12:44 +02:00
Configured and applied SwiftFormat
This commit is contained in:
committed by
Stefan Ceriu
parent
ff2e6ddfa7
commit
43c28d23b7
+11
-13
@@ -18,7 +18,6 @@ import UIKit
|
||||
|
||||
@objcMembers
|
||||
final class TemplateRoomsCoordinator: Coordinator, Presentable {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -26,7 +25,7 @@ final class TemplateRoomsCoordinator: Coordinator, Presentable {
|
||||
private let parameters: TemplateRoomsCoordinatorParameters
|
||||
|
||||
private var navigationRouter: NavigationRouterType {
|
||||
return self.parameters.navigationRouter
|
||||
parameters.navigationRouter
|
||||
}
|
||||
|
||||
// MARK: Public
|
||||
@@ -40,37 +39,36 @@ final class TemplateRoomsCoordinator: Coordinator, Presentable {
|
||||
|
||||
init(parameters: TemplateRoomsCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
|
||||
func start() {
|
||||
MXLog.debug("[TemplateRoomsCoordinator] did start.")
|
||||
let rootCoordinator = self.createTemplateRoomListCoordinator()
|
||||
let rootCoordinator = createTemplateRoomListCoordinator()
|
||||
rootCoordinator.start()
|
||||
|
||||
self.add(childCoordinator: rootCoordinator)
|
||||
add(childCoordinator: rootCoordinator)
|
||||
|
||||
if self.navigationRouter.modules.isEmpty == false {
|
||||
self.navigationRouter.push(rootCoordinator, animated: true, popCompletion: { [weak self] in
|
||||
if navigationRouter.modules.isEmpty == false {
|
||||
navigationRouter.push(rootCoordinator, animated: true, popCompletion: { [weak self] in
|
||||
self?.remove(childCoordinator: rootCoordinator)
|
||||
})
|
||||
} else {
|
||||
self.navigationRouter.setRootModule(rootCoordinator) { [weak self] in
|
||||
navigationRouter.setRootModule(rootCoordinator) { [weak self] in
|
||||
self?.remove(childCoordinator: rootCoordinator)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
return self.navigationRouter.toPresentable()
|
||||
navigationRouter.toPresentable()
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
|
||||
private func createTemplateRoomListCoordinator() -> TemplateRoomListCoordinator {
|
||||
let coordinator: TemplateRoomListCoordinator = TemplateRoomListCoordinator(parameters: TemplateRoomListCoordinatorParameters(session: parameters.session))
|
||||
let coordinator = TemplateRoomListCoordinator(parameters: TemplateRoomListCoordinatorParameters(session: parameters.session))
|
||||
|
||||
coordinator.callback = { [weak self] result in
|
||||
MXLog.debug("[TemplateRoomsCoordinator] TemplateRoomListCoordinator did complete with result \(result).")
|
||||
@@ -86,7 +84,7 @@ final class TemplateRoomsCoordinator: Coordinator, Presentable {
|
||||
}
|
||||
|
||||
private func createTemplateRoomChatCoordinator(room: MXRoom) -> TemplateRoomChatCoordinator {
|
||||
let coordinator: TemplateRoomChatCoordinator = TemplateRoomChatCoordinator(parameters: TemplateRoomChatCoordinatorParameters(room: room))
|
||||
let coordinator = TemplateRoomChatCoordinator(parameters: TemplateRoomChatCoordinatorParameters(room: room))
|
||||
return coordinator
|
||||
}
|
||||
|
||||
@@ -99,7 +97,7 @@ final class TemplateRoomsCoordinator: Coordinator, Presentable {
|
||||
|
||||
add(childCoordinator: templateRoomChatCoordinator)
|
||||
|
||||
self.navigationRouter.push(templateRoomChatCoordinator, animated: true, popCompletion: { [weak self] in
|
||||
navigationRouter.push(templateRoomChatCoordinator, animated: true, popCompletion: { [weak self] in
|
||||
self?.remove(childCoordinator: templateRoomChatCoordinator)
|
||||
})
|
||||
|
||||
|
||||
-1
@@ -18,7 +18,6 @@ import Foundation
|
||||
|
||||
/// TemplateRoomsCoordinator input parameters
|
||||
struct TemplateRoomsCoordinatorParameters {
|
||||
|
||||
/// The Matrix session
|
||||
let session: MXSession
|
||||
|
||||
|
||||
+2
-3
@@ -21,7 +21,6 @@ struct TemplateRoomChatCoordinatorParameters {
|
||||
}
|
||||
|
||||
final class TemplateRoomChatCoordinator: Coordinator, Presentable {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -48,6 +47,7 @@ final class TemplateRoomChatCoordinator: Coordinator, Presentable {
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
func start() {
|
||||
MXLog.debug("[TemplateRoomChatCoordinator] did start.")
|
||||
templateRoomChatViewModel.callback = { [weak self] result in
|
||||
@@ -56,12 +56,11 @@ final class TemplateRoomChatCoordinator: Coordinator, Presentable {
|
||||
switch result {
|
||||
case .done:
|
||||
self.callback?()
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
return self.templateRoomChatHostingController
|
||||
templateRoomChatHostingController
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -56,7 +56,7 @@ enum MockTemplateRoomChatScreenState: MockScreenState, CaseIterable {
|
||||
return (
|
||||
[service, viewModel],
|
||||
AnyView(TemplateRoomChat(viewModel: viewModel.context)
|
||||
.addDependency(MockAvatarService.example))
|
||||
.addDependency(MockAvatarService.example))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+20
-21
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,11 +14,10 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
class TemplateRoomChatService: TemplateRoomChatServiceProtocol {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -29,22 +28,23 @@ class TemplateRoomChatService: TemplateRoomChatServiceProtocol {
|
||||
private var eventBatch: [MXEvent]
|
||||
private var roomListenerReference: Any?
|
||||
|
||||
|
||||
// MARK: Public
|
||||
|
||||
private(set) var chatMessagesSubject: CurrentValueSubject<[TemplateRoomChatMessage], Never>
|
||||
private(set) var roomInitializationStatus: CurrentValueSubject<TemplateRoomChatRoomInitializationStatus, Never>
|
||||
|
||||
var roomName: String? {
|
||||
self.room.summary.displayname
|
||||
room.summary.displayname
|
||||
}
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(room: MXRoom) {
|
||||
self.room = room
|
||||
self.eventFormatter = EventFormatter(matrixSession: room.mxSession)
|
||||
self.chatMessagesSubject = CurrentValueSubject([])
|
||||
self.roomInitializationStatus = CurrentValueSubject(.notInitialized)
|
||||
self.eventBatch = [MXEvent]()
|
||||
eventFormatter = EventFormatter(matrixSession: room.mxSession)
|
||||
chatMessagesSubject = CurrentValueSubject([])
|
||||
roomInitializationStatus = CurrentValueSubject(.notInitialized)
|
||||
eventBatch = [MXEvent]()
|
||||
initializeRoom()
|
||||
}
|
||||
|
||||
@@ -54,14 +54,15 @@ class TemplateRoomChatService: TemplateRoomChatServiceProtocol {
|
||||
}
|
||||
|
||||
// MARK: Public
|
||||
|
||||
func send(textMessage: String) {
|
||||
var localEcho: MXEvent? = nil
|
||||
var localEcho: MXEvent?
|
||||
room.sendTextMessage(textMessage, threadId: nil, localEcho: &localEcho, completion: { _ in })
|
||||
}
|
||||
|
||||
// MARK: Private
|
||||
|
||||
private func initializeRoom(){
|
||||
private func initializeRoom() {
|
||||
room.liveTimeline { [weak self] timeline in
|
||||
guard let self = self,
|
||||
let timeline = timeline
|
||||
@@ -70,21 +71,20 @@ class TemplateRoomChatService: TemplateRoomChatServiceProtocol {
|
||||
}
|
||||
self.timeline = timeline
|
||||
timeline.resetPagination()
|
||||
self.roomListenerReference = timeline.listenToEvents([.roomMessage], { [weak self] event, direction, roomState in
|
||||
self.roomListenerReference = timeline.listenToEvents([.roomMessage]) { [weak self] event, direction, _ in
|
||||
guard let self = self else { return }
|
||||
if direction == .backwards {
|
||||
self.eventBatch.append(event)
|
||||
} else {
|
||||
self.chatMessagesSubject.value += self.mapChatMessages(from: [event])
|
||||
}
|
||||
|
||||
})
|
||||
}
|
||||
timeline.paginate(200, direction: .backwards, onlyFromStore: false) { result in
|
||||
guard result.isSuccess else {
|
||||
self.roomInitializationStatus.value = .failedToInitialize
|
||||
return
|
||||
}
|
||||
let sortedBatch = self.eventBatch.sorted(by: { $0.originServerTs < $1.originServerTs})
|
||||
let sortedBatch = self.eventBatch.sorted(by: { $0.originServerTs < $1.originServerTs })
|
||||
self.chatMessagesSubject.value = self.mapChatMessages(from: sortedBatch)
|
||||
self.roomInitializationStatus.value = .initialized
|
||||
}
|
||||
@@ -92,15 +92,14 @@ class TemplateRoomChatService: TemplateRoomChatServiceProtocol {
|
||||
}
|
||||
|
||||
private func mapChatMessages(from events: [MXEvent]) -> [TemplateRoomChatMessage] {
|
||||
return events
|
||||
.filter({ event in
|
||||
events
|
||||
.filter { event in
|
||||
event.type == kMXEventTypeStringRoomMessage
|
||||
&& event.content[kMXMessageTypeKey] as? String == kMXMessageTypeText
|
||||
|
||||
// TODO: New to our SwiftUI Template? Why not implement another message type like image?
|
||||
|
||||
})
|
||||
.compactMap({ event -> TemplateRoomChatMessage? in
|
||||
}
|
||||
.compactMap { event -> TemplateRoomChatMessage? in
|
||||
guard let eventId = event.eventId,
|
||||
let body = event.content[kMXMessageBodyKey] as? String,
|
||||
let sender = senderForMessage(event: event)
|
||||
@@ -112,7 +111,7 @@ class TemplateRoomChatService: TemplateRoomChatServiceProtocol {
|
||||
sender: sender,
|
||||
timestamp: Date(timeIntervalSince1970: TimeInterval(event.originServerTs / 1000))
|
||||
)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private func senderForMessage(event: MXEvent) -> TemplateRoomChatMember? {
|
||||
|
||||
+9
-10
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,39 +14,38 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
class MockTemplateRoomChatService: TemplateRoomChatServiceProtocol {
|
||||
|
||||
let roomName: String? = "New Vector"
|
||||
|
||||
static let amadine = TemplateRoomChatMember(id: "@amadine:matrix.org", avatarUrl: "!aaabaa:matrix.org", displayName: "Amadine")
|
||||
static let mathew = TemplateRoomChatMember(id: "@mathew:matrix.org", avatarUrl: "!bbabb:matrix.org", displayName: "Mathew")
|
||||
static let mockMessages = [
|
||||
TemplateRoomChatMessage(id: "!0:matrix.org", content: .text(TemplateRoomChatMessageTextContent(body: "Shall I put it live?")) , sender: amadine, timestamp: Date(timeIntervalSinceNow: 60 * -3)),
|
||||
TemplateRoomChatMessage(id: "!0:matrix.org", content: .text(TemplateRoomChatMessageTextContent(body: "Shall I put it live?")), sender: amadine, timestamp: Date(timeIntervalSinceNow: 60 * -3)),
|
||||
TemplateRoomChatMessage(id: "!1:matrix.org", content: .text(TemplateRoomChatMessageTextContent(body: "Yea go for it! ...and then let's head to the pub")), sender: mathew, timestamp: Date(timeIntervalSinceNow: 60)),
|
||||
TemplateRoomChatMessage(id: "!2:matrix.org", content: .text(TemplateRoomChatMessageTextContent(body: "Deal.")), sender: amadine, timestamp: Date(timeIntervalSinceNow: 60 * -2)),
|
||||
TemplateRoomChatMessage(id: "!3:matrix.org", content: .text(TemplateRoomChatMessageTextContent(body: "Ok, Done. 🍻")), sender: amadine, timestamp: Date(timeIntervalSinceNow: 60 * -1)),
|
||||
TemplateRoomChatMessage(id: "!3:matrix.org", content: .text(TemplateRoomChatMessageTextContent(body: "Ok, Done. 🍻")), sender: amadine, timestamp: Date(timeIntervalSinceNow: 60 * -1))
|
||||
]
|
||||
var roomInitializationStatus: CurrentValueSubject<TemplateRoomChatRoomInitializationStatus, Never>
|
||||
var chatMessagesSubject: CurrentValueSubject<[TemplateRoomChatMessage], Never>
|
||||
|
||||
init(messages: [TemplateRoomChatMessage] = mockMessages) {
|
||||
self.roomInitializationStatus = CurrentValueSubject(.notInitialized)
|
||||
self.chatMessagesSubject = CurrentValueSubject(messages)
|
||||
roomInitializationStatus = CurrentValueSubject(.notInitialized)
|
||||
chatMessagesSubject = CurrentValueSubject(messages)
|
||||
}
|
||||
|
||||
func send(textMessage: String) {
|
||||
let newMessage = TemplateRoomChatMessage(id: "!\(chatMessagesSubject.value.count):matrix.org", content: .text(TemplateRoomChatMessageTextContent(body: textMessage)), sender: Self.amadine, timestamp: Date())
|
||||
self.chatMessagesSubject.value += [newMessage]
|
||||
chatMessagesSubject.value += [newMessage]
|
||||
}
|
||||
|
||||
func simulateUpdate(initializationStatus: TemplateRoomChatRoomInitializationStatus) {
|
||||
self.roomInitializationStatus.value = initializationStatus
|
||||
roomInitializationStatus.value = initializationStatus
|
||||
}
|
||||
|
||||
func simulateUpdate(messages: [TemplateRoomChatMessage]) {
|
||||
self.chatMessagesSubject.value = messages
|
||||
chatMessagesSubject.value = messages
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
protocol TemplateRoomChatServiceProtocol {
|
||||
var roomInitializationStatus: CurrentValueSubject<TemplateRoomChatRoomInitializationStatus, Never> { get }
|
||||
|
||||
+1
-2
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -88,7 +88,6 @@ enum TemplateRoomChatViewModelAction {
|
||||
case done
|
||||
}
|
||||
|
||||
|
||||
// MARK: - View
|
||||
|
||||
/// Actions send from the `View` to the `ViewModel`.
|
||||
|
||||
+9
-11
@@ -14,18 +14,18 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
typealias TemplateRoomChatViewModelType = StateStoreViewModel<TemplateRoomChatViewState,
|
||||
Never,
|
||||
TemplateRoomChatViewAction>
|
||||
Never,
|
||||
TemplateRoomChatViewAction>
|
||||
|
||||
class TemplateRoomChatViewModel: TemplateRoomChatViewModelType, TemplateRoomChatViewModelProtocol {
|
||||
|
||||
enum Constants {
|
||||
static let maxTimeBeforeNewBubble: TimeInterval = 5*60
|
||||
static let maxTimeBeforeNewBubble: TimeInterval = 5 * 60
|
||||
}
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -70,9 +70,8 @@ class TemplateRoomChatViewModel: TemplateRoomChatViewModelType, TemplateRoomChat
|
||||
}
|
||||
|
||||
private static func makeBubbles(messages: [TemplateRoomChatMessage]) -> [TemplateRoomChatBubble] {
|
||||
|
||||
var bubbleOrder = [String]()
|
||||
var bubbleMap = [String:TemplateRoomChatBubble]()
|
||||
var bubbleMap = [String: TemplateRoomChatBubble]()
|
||||
|
||||
messages.enumerated().forEach { i, message in
|
||||
// New message content
|
||||
@@ -85,9 +84,8 @@ class TemplateRoomChatViewModel: TemplateRoomChatViewModelType, TemplateRoomChat
|
||||
let lastBubbleId = bubbleOrder.last,
|
||||
var lastBubble = bubbleMap[lastBubbleId],
|
||||
lastBubble.sender.id == message.sender.id,
|
||||
let interveningTime = lastBubble.items.last?.timestamp.timeIntervalSince(message.timestamp),
|
||||
abs(interveningTime) < Constants.maxTimeBeforeNewBubble
|
||||
{
|
||||
let interveningTime = lastBubble.items.last?.timestamp.timeIntervalSince(message.timestamp),
|
||||
abs(interveningTime) < Constants.maxTimeBeforeNewBubble {
|
||||
// if the last bubble's last message was within
|
||||
// the last 5 minutes append
|
||||
let item = TemplateRoomChatBubbleItem(
|
||||
@@ -108,7 +106,7 @@ class TemplateRoomChatViewModel: TemplateRoomChatViewModelType, TemplateRoomChat
|
||||
bubbleMap[bubble.id] = bubble
|
||||
}
|
||||
}
|
||||
return bubbleOrder.compactMap({ bubbleMap[$0] })
|
||||
return bubbleOrder.compactMap { bubbleMap[$0] }
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
+4
-5
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import RiotSwiftUI
|
||||
import XCTest
|
||||
|
||||
class TemplateRoomChatUITests: MockScreenTestCase {
|
||||
func testInitializingRoom() {
|
||||
@@ -44,12 +44,11 @@ class TemplateRoomChatUITests: MockScreenTestCase {
|
||||
|
||||
// Verify bubble grouping with:
|
||||
// 3 bubbles
|
||||
let bubbleCount = app.images.matching(identifier:"bubbleImage").count
|
||||
let bubbleCount = app.images.matching(identifier: "bubbleImage").count
|
||||
XCTAssertEqual(bubbleCount, 3)
|
||||
|
||||
// and 4 text items
|
||||
let bubbleTextItemCount = app.staticTexts.matching(identifier:"bubbleTextContent").count
|
||||
let bubbleTextItemCount = app.staticTexts.matching(identifier: "bubbleTextContent").count
|
||||
XCTAssertEqual(bubbleTextItemCount, 4)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+4
-6
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,13 +14,12 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Combine
|
||||
import XCTest
|
||||
|
||||
@testable import RiotSwiftUI
|
||||
|
||||
class TemplateRoomChatViewModelTests: XCTestCase {
|
||||
|
||||
var service: MockTemplateRoomChatService!
|
||||
var viewModel: TemplateRoomChatViewModel!
|
||||
var context: TemplateRoomChatViewModel.Context!
|
||||
@@ -39,18 +38,17 @@ class TemplateRoomChatViewModelTests: XCTestCase {
|
||||
XCTAssertEqual(context.viewState.roomInitializationStatus, .initialized)
|
||||
}
|
||||
|
||||
|
||||
func testSendMessageUpdatesReceived() throws {
|
||||
let bubblesPublisher: AnyPublisher<[[TemplateRoomChatBubble]], Never> = context.$viewState.map(\.bubbles).removeDuplicates().collect(2).first().eraseToAnyPublisher()
|
||||
let awaitDeferred = xcAwaitDeferred(bubblesPublisher)
|
||||
let newMessage: String = "Let's Go"
|
||||
let newMessage = "Let's Go"
|
||||
service.send(textMessage: newMessage)
|
||||
|
||||
let result: [[TemplateRoomChatBubble]]? = try awaitDeferred()
|
||||
|
||||
// Test that the update to the messages in turn updates the view's
|
||||
// the last bubble by appending another text item, asserting the body.
|
||||
guard let item:TemplateRoomChatBubbleItem = result?.last?.last?.items.last,
|
||||
guard let item: TemplateRoomChatBubbleItem = result?.last?.last?.items.last,
|
||||
case TemplateRoomChatBubbleItemContent.message(let message) = item.content,
|
||||
case let TemplateRoomChatMessageContent.text(text) = message else {
|
||||
XCTFail()
|
||||
|
||||
+5
-7
@@ -14,11 +14,10 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
struct TemplateRoomChat: View {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -32,7 +31,7 @@ struct TemplateRoomChat: View {
|
||||
|
||||
var body: some View {
|
||||
VStack {
|
||||
VStack{
|
||||
VStack {
|
||||
roomContent
|
||||
}.frame(maxHeight: .infinity)
|
||||
|
||||
@@ -51,7 +50,6 @@ struct TemplateRoomChat: View {
|
||||
.animation(.easeOut(duration: 0.25))
|
||||
.transition(.move(edge: .trailing))
|
||||
.padding()
|
||||
|
||||
}
|
||||
.background(theme.colors.background)
|
||||
.navigationTitle(viewModel.viewState.roomName ?? "Chat")
|
||||
@@ -83,14 +81,14 @@ struct TemplateRoomChat: View {
|
||||
|
||||
private var bubbleList: some View {
|
||||
ScrollViewReader { reader in
|
||||
ScrollView{
|
||||
ScrollView {
|
||||
LazyVStack {
|
||||
ForEach(viewModel.viewState.bubbles) { bubble in
|
||||
TemplateRoomChatBubbleView(bubble: bubble)
|
||||
.id(bubble.id)
|
||||
}
|
||||
}
|
||||
.onAppear{
|
||||
.onAppear {
|
||||
guard let lastBubbleId = viewModel.viewState.bubbles.last?.id
|
||||
else { return }
|
||||
reader.scrollTo(lastBubbleId, anchor: .bottom)
|
||||
@@ -116,7 +114,7 @@ struct TemplateRoomChat: View {
|
||||
}
|
||||
|
||||
private var itemCount: Int {
|
||||
return viewModel.viewState
|
||||
viewModel.viewState
|
||||
.bubbles
|
||||
.map(\.items)
|
||||
.map(\.count)
|
||||
|
||||
-1
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct TemplateRoomChatBubbleContentView: View {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
|
||||
-1
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct TemplateRoomChatBubbleImage: View {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
|
||||
-1
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct TemplateRoomChatBubbleMessage: View {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
|
||||
+3
-4
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct TemplateRoomChatBubbleView: View {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -29,10 +28,10 @@ struct TemplateRoomChatBubbleView: View {
|
||||
let bubble: TemplateRoomChatBubble
|
||||
|
||||
var body: some View {
|
||||
HStack(alignment: .top){
|
||||
HStack(alignment: .top) {
|
||||
AvatarImage(avatarData: bubble.sender.avatarData, size: .xSmall)
|
||||
.accessibility(identifier: "bubbleImage")
|
||||
VStack(alignment: .leading){
|
||||
VStack(alignment: .leading) {
|
||||
Text(bubble.sender.displayName ?? "")
|
||||
.foregroundColor(theme.userColor(for: bubble.sender.id))
|
||||
.font(theme.fonts.bodySB)
|
||||
@@ -42,7 +41,7 @@ struct TemplateRoomChatBubbleView: View {
|
||||
}
|
||||
Spacer()
|
||||
}
|
||||
//add to a style
|
||||
// add to a style
|
||||
.padding(.horizontal)
|
||||
.padding(.vertical, 8)
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
+1
-3
@@ -21,7 +21,6 @@ struct TemplateRoomListCoordinatorParameters {
|
||||
}
|
||||
|
||||
final class TemplateRoomListCoordinator: Coordinator, Presentable {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -59,12 +58,11 @@ final class TemplateRoomListCoordinator: Coordinator, Presentable {
|
||||
self.callback?(.didSelectRoom(roomId))
|
||||
case .done:
|
||||
self.callback?(.done)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
return self.templateRoomListHostingController
|
||||
templateRoomListHostingController
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import Foundation
|
||||
import SwiftUI
|
||||
|
||||
|
||||
/// Using an enum for the screen allows you define the different state cases with
|
||||
/// the relevant associated data for each case.
|
||||
enum MockTemplateRoomListScreenState: MockScreenState, CaseIterable {
|
||||
|
||||
+6
-8
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,11 +14,10 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
class TemplateRoomListService: TemplateRoomListServiceProtocol {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -27,6 +26,7 @@ class TemplateRoomListService: TemplateRoomListServiceProtocol {
|
||||
private var listenerReference: Any?
|
||||
|
||||
// MARK: Public
|
||||
|
||||
private(set) var roomsSubject: CurrentValueSubject<[TemplateRoomListRoom], Never>
|
||||
|
||||
// MARK: - Setup
|
||||
@@ -35,15 +35,13 @@ class TemplateRoomListService: TemplateRoomListServiceProtocol {
|
||||
self.session = session
|
||||
|
||||
let unencryptedRooms = session.rooms
|
||||
.filter({ !$0.summary.isEncrypted })
|
||||
.filter { !$0.summary.isEncrypted }
|
||||
.map(TemplateRoomListRoom.init(mxRoom:))
|
||||
self.roomsSubject = CurrentValueSubject(unencryptedRooms)
|
||||
roomsSubject = CurrentValueSubject(unencryptedRooms)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
fileprivate extension TemplateRoomListRoom {
|
||||
|
||||
private extension TemplateRoomListRoom {
|
||||
init(mxRoom: MXRoom) {
|
||||
self.init(id: mxRoom.roomId, avatar: mxRoom.avatarData, displayName: mxRoom.summary.displayname)
|
||||
}
|
||||
|
||||
+3
-4
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,11 +14,10 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
class MockTemplateRoomListService: TemplateRoomListServiceProtocol {
|
||||
|
||||
static let mockRooms = [
|
||||
TemplateRoomListRoom(id: "!aaabaa:matrix.org", avatar: MockAvatarInput.example, displayName: "Matrix Discussion"),
|
||||
TemplateRoomListRoom(id: "!zzasds:matrix.org", avatar: MockAvatarInput.example, displayName: "Element Mobile"),
|
||||
@@ -31,6 +30,6 @@ class MockTemplateRoomListService: TemplateRoomListServiceProtocol {
|
||||
}
|
||||
|
||||
func simulateUpdate(rooms: [TemplateRoomListRoom]) {
|
||||
self.roomsSubject.send(rooms)
|
||||
roomsSubject.send(rooms)
|
||||
}
|
||||
}
|
||||
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import Combine
|
||||
import Foundation
|
||||
|
||||
protocol TemplateRoomListServiceProtocol {
|
||||
var roomsSubject: CurrentValueSubject<[TemplateRoomListRoom], Never> { get }
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
+5
-6
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,15 +14,14 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import SwiftUI
|
||||
import Combine
|
||||
import SwiftUI
|
||||
|
||||
typealias TemplateRoomListViewModelType = StateStoreViewModel<TemplateRoomListViewState,
|
||||
Never,
|
||||
TemplateRoomListViewAction>
|
||||
Never,
|
||||
TemplateRoomListViewAction>
|
||||
|
||||
class TemplateRoomListViewModel: TemplateRoomListViewModelType, TemplateRoomListViewModelProtocol {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -42,7 +41,7 @@ class TemplateRoomListViewModel: TemplateRoomListViewModelType, TemplateRoomList
|
||||
}
|
||||
|
||||
private static func defaultState(templateRoomListService: TemplateRoomListServiceProtocol) -> TemplateRoomListViewState {
|
||||
return TemplateRoomListViewState(rooms: templateRoomListService.roomsSubject.value)
|
||||
TemplateRoomListViewState(rooms: templateRoomListService.roomsSubject.value)
|
||||
}
|
||||
|
||||
private func startObservingRooms() {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
||||
+3
-4
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,8 +14,8 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import RiotSwiftUI
|
||||
import XCTest
|
||||
|
||||
class TemplateRoomListUITests: MockScreenTestCase {
|
||||
func testTemplateRoomListNoRooms() {
|
||||
@@ -29,8 +29,7 @@ class TemplateRoomListUITests: MockScreenTestCase {
|
||||
func testTemplateRoomListRooms() {
|
||||
app.goToScreenWithIdentifier(MockTemplateRoomListScreenState.rooms.title)
|
||||
|
||||
let displayNameCount = app.buttons.matching(identifier:"roomNameText").count
|
||||
let displayNameCount = app.buttons.matching(identifier: "roomNameText").count
|
||||
XCTAssertEqual(displayNameCount, 3)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -14,14 +14,14 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import XCTest
|
||||
import Combine
|
||||
import XCTest
|
||||
|
||||
@testable import RiotSwiftUI
|
||||
|
||||
class TemplateRoomListViewModelTests: XCTestCase {
|
||||
private enum Constants {
|
||||
}
|
||||
private enum Constants { }
|
||||
|
||||
var service: MockTemplateRoomListService!
|
||||
var viewModel: TemplateRoomListViewModel!
|
||||
var context: TemplateRoomListViewModel.Context!
|
||||
@@ -46,7 +46,7 @@ class TemplateRoomListViewModelTests: XCTestCase {
|
||||
let updatedRooms = Array(MockTemplateRoomListService.mockRooms.dropLast())
|
||||
let roomsPublisher = context.$viewState.map(\.rooms).removeDuplicates().collect(2).first()
|
||||
let awaitDeferred = xcAwaitDeferred(roomsPublisher)
|
||||
service.simulateUpdate(rooms: updatedRooms)
|
||||
service.simulateUpdate(rooms: updatedRooms)
|
||||
XCTAssertEqual(try awaitDeferred(), [MockTemplateRoomListService.mockRooms, updatedRooms])
|
||||
}
|
||||
}
|
||||
|
||||
+2
-4
@@ -1,4 +1,4 @@
|
||||
//
|
||||
//
|
||||
// Copyright 2021 New Vector Ltd
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct TemplateRoomList: View {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -47,7 +46,7 @@ struct TemplateRoomList: View {
|
||||
.foregroundColor(theme.colors.primaryContent)
|
||||
.accessibility(identifier: "errorMessage")
|
||||
} else {
|
||||
ScrollView{
|
||||
ScrollView {
|
||||
LazyVStack(spacing: 0) {
|
||||
ForEach(viewModel.viewState.rooms) { room in
|
||||
Button {
|
||||
@@ -66,7 +65,6 @@ struct TemplateRoomList: View {
|
||||
// MARK: - Previews
|
||||
|
||||
struct TemplateRoomList_Previews: PreviewProvider {
|
||||
|
||||
static let stateRenderer = MockTemplateRoomListScreenState.stateRenderer
|
||||
static var previews: some View {
|
||||
stateRenderer.screenGroup(addNavigation: true)
|
||||
|
||||
+3
-4
@@ -17,7 +17,6 @@
|
||||
import SwiftUI
|
||||
|
||||
struct TemplateRoomListRow: View {
|
||||
|
||||
// MARK: - Properties
|
||||
|
||||
// MARK: Private
|
||||
@@ -30,14 +29,14 @@ struct TemplateRoomListRow: View {
|
||||
let displayName: String?
|
||||
|
||||
var body: some View {
|
||||
HStack{
|
||||
HStack {
|
||||
AvatarImage(avatarData: avatar, size: .medium)
|
||||
Text(displayName ?? "")
|
||||
.foregroundColor(theme.colors.primaryContent)
|
||||
.accessibility(identifier: "roomNameText")
|
||||
.accessibility(identifier: "roomNameText")
|
||||
Spacer()
|
||||
}
|
||||
//add to a style
|
||||
// add to a style
|
||||
.padding(.horizontal)
|
||||
.padding(.vertical, 8)
|
||||
.frame(maxWidth: .infinity)
|
||||
|
||||
Reference in New Issue
Block a user