mirror of
https://gitlab.opencode.de/bwi/bundesmessenger/clients/bundesmessenger-ios.git
synced 2026-04-26 19:34:25 +02:00
added view in timeline action, added tests
This commit is contained in:
@@ -20,7 +20,6 @@ import SwiftUI
|
||||
|
||||
struct PollHistoryCoordinatorParameters {
|
||||
let mode: PollHistoryMode
|
||||
let session: MXSession
|
||||
let room: MXRoom
|
||||
let navigationRouter: NavigationRouterType
|
||||
}
|
||||
@@ -33,7 +32,7 @@ final class PollHistoryCoordinator: NSObject, Coordinator, Presentable {
|
||||
|
||||
// Must be used only internally
|
||||
var childCoordinators: [Coordinator] = []
|
||||
var completion: (() -> Void)?
|
||||
var completion: ((MXEvent) -> Void)?
|
||||
|
||||
init(parameters: PollHistoryCoordinatorParameters) {
|
||||
self.parameters = parameters
|
||||
@@ -58,33 +57,35 @@ final class PollHistoryCoordinator: NSObject, Coordinator, Presentable {
|
||||
|
||||
func showPollDetail(_ poll: TimelinePollDetails) {
|
||||
|
||||
parameters.session.event(withEventId: poll.id, inRoom: parameters.room.roomId) { [weak self] response in
|
||||
guard let self else { return }
|
||||
if let event = response.value,
|
||||
let detailCoordinator: PollHistoryDetailCoordinator = try? .init(parameters: .init(pollHistoryDetails: MockPollHistoryDetailScreenState.openUndisclosed.poll, event: event, session: self.parameters.session, room: self.parameters.room)) {
|
||||
detailCoordinator.toPresentable().presentationController?.delegate = self
|
||||
detailCoordinator.completion = { [weak self, weak detailCoordinator] result in
|
||||
guard let self = self, let coordinator = detailCoordinator else { return }
|
||||
switch result {
|
||||
case .dismiss:
|
||||
self.toPresentable().dismiss(animated: true)
|
||||
self.remove(childCoordinator: coordinator)
|
||||
case .viewInTimeline:
|
||||
self.toPresentable().dismiss(animated: true)
|
||||
self.remove(childCoordinator: coordinator)
|
||||
// TODO: go back in timeline
|
||||
if let event = parameters.room.mxSession.store.event(withEventId: poll.id, inRoom: parameters.room.roomId),
|
||||
let detailCoordinator: PollHistoryDetailCoordinator = try? .init(parameters: .init(event: event, room: self.parameters.room)) {
|
||||
detailCoordinator.toPresentable().presentationController?.delegate = self
|
||||
detailCoordinator.completion = { [weak self, weak detailCoordinator] result in
|
||||
guard let self = self, let coordinator = detailCoordinator else { return }
|
||||
switch result {
|
||||
case .dismiss:
|
||||
self.toPresentable().dismiss(animated: true)
|
||||
self.remove(childCoordinator: coordinator)
|
||||
case .viewInTimeline:
|
||||
self.toPresentable().dismiss(animated: false)
|
||||
self.remove(childCoordinator: coordinator)
|
||||
var event = event
|
||||
if poll.closed {
|
||||
let room = self.parameters.room
|
||||
let relatedEvents = room.mxSession.store.relations(forEvent: event.eventId, inRoom: room.roomId, relationType: MXEventRelationTypeReference)
|
||||
let pollEndedEvent = relatedEvents.first(where: { $0.eventType == .pollEnd })
|
||||
event = pollEndedEvent ?? event
|
||||
}
|
||||
self.completion?(event)
|
||||
}
|
||||
|
||||
self.add(childCoordinator: detailCoordinator)
|
||||
detailCoordinator.start()
|
||||
self.toPresentable().present(detailCoordinator.toPresentable(), animated: true)
|
||||
} else {
|
||||
// TODO: manage error
|
||||
}
|
||||
|
||||
self.add(childCoordinator: detailCoordinator)
|
||||
detailCoordinator.start()
|
||||
self.toPresentable().present(detailCoordinator.toPresentable(), animated: true)
|
||||
} else {
|
||||
// TODO: #1040 manage error
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
func toPresentable() -> UIViewController {
|
||||
|
||||
+2
-5
@@ -20,9 +20,7 @@ import Combine
|
||||
import MatrixSDK
|
||||
|
||||
struct PollHistoryDetailCoordinatorParameters {
|
||||
let pollHistoryDetails: TimelinePollDetails
|
||||
let event: MXEvent
|
||||
let session: MXSession
|
||||
let room: MXRoom
|
||||
}
|
||||
|
||||
@@ -30,7 +28,6 @@ final class PollHistoryDetailCoordinator: Coordinator, Presentable {
|
||||
private let parameters: PollHistoryDetailCoordinatorParameters
|
||||
private let pollHistoryDetailHostingController: UIViewController
|
||||
private var pollHistoryDetailViewModel: PollHistoryDetailViewModelProtocol
|
||||
private var cancellables = Set<AnyCancellable>()
|
||||
private var indicatorPresenter: UserIndicatorTypePresenterProtocol
|
||||
private var loadingIndicator: UserIndicator?
|
||||
|
||||
@@ -40,9 +37,9 @@ final class PollHistoryDetailCoordinator: Coordinator, Presentable {
|
||||
|
||||
init(parameters: PollHistoryDetailCoordinatorParameters) throws {
|
||||
self.parameters = parameters
|
||||
let timelinePollCoordinator = try TimelinePollCoordinator(parameters: .init(session: parameters.session, room: parameters.room, pollEvent: parameters.event))
|
||||
let timelinePollCoordinator = try TimelinePollCoordinator(parameters: .init(session: parameters.room.mxSession, room: parameters.room, pollEvent: parameters.event))
|
||||
|
||||
let viewModel = PollHistoryDetailViewModel(pollHistoryDetails: parameters.pollHistoryDetails, timelineViewModel: timelinePollCoordinator.viewModel)
|
||||
let viewModel = PollHistoryDetailViewModel(timelineViewModel: timelinePollCoordinator.viewModel)
|
||||
let view = PollHistoryDetail(viewModel: viewModel.context)
|
||||
pollHistoryDetailViewModel = viewModel
|
||||
|
||||
|
||||
+3
-3
@@ -25,7 +25,7 @@ enum MockPollHistoryDetailScreenState: MockScreenState, CaseIterable {
|
||||
case closedPollEnded
|
||||
|
||||
var screenType: Any.Type {
|
||||
TimelinePollDetails.self
|
||||
PollHistoryDetail.self
|
||||
}
|
||||
|
||||
var poll: TimelinePollDetails {
|
||||
@@ -37,7 +37,7 @@ enum MockPollHistoryDetailScreenState: MockScreenState, CaseIterable {
|
||||
question: "Question",
|
||||
answerOptions: answerOptions,
|
||||
closed: self == .closedDisclosed || self == .closedUndisclosed ? true : false,
|
||||
startDate: .init(),
|
||||
startDate: .init(timeIntervalSinceReferenceDate: 0),
|
||||
totalAnswerCount: 20,
|
||||
type: self == .closedDisclosed || self == .openDisclosed ? .disclosed : .undisclosed,
|
||||
eventType: self == .closedPollEnded ? .ended : .started,
|
||||
@@ -49,7 +49,7 @@ enum MockPollHistoryDetailScreenState: MockScreenState, CaseIterable {
|
||||
|
||||
var screenView: ([Any], AnyView) {
|
||||
|
||||
let viewModel = PollHistoryDetailViewModel(pollHistoryDetails: poll, timelineViewModel: TimelinePollViewModel(timelinePollDetails: poll))
|
||||
let viewModel = PollHistoryDetailViewModel(timelineViewModel: TimelinePollViewModel(timelinePollDetails: poll))
|
||||
|
||||
return ([viewModel], AnyView(PollHistoryDetail(viewModel: viewModel.context)))
|
||||
}
|
||||
|
||||
+6
-1
@@ -32,8 +32,13 @@ enum PollHistoryDetailViewModelResult {
|
||||
// MARK: View
|
||||
|
||||
struct PollHistoryDetailViewState: BindableState {
|
||||
var poll: TimelinePollDetails
|
||||
var timelineViewModel: TimelinePollViewModelProtocol
|
||||
var pollStartDate: Date {
|
||||
timelineViewModel.context.viewState.poll.startDate
|
||||
}
|
||||
var isPollClosed: Bool {
|
||||
timelineViewModel.context.viewState.poll.closed
|
||||
}
|
||||
}
|
||||
|
||||
enum PollHistoryDetailViewAction {
|
||||
|
||||
+2
-2
@@ -29,8 +29,8 @@ class PollHistoryDetailViewModel: PollHistoryDetailViewModelType, PollHistoryDet
|
||||
|
||||
// MARK: - Setup
|
||||
|
||||
init(pollHistoryDetails: TimelinePollDetails, timelineViewModel: TimelinePollViewModelProtocol) {
|
||||
super.init(initialViewState: PollHistoryDetailViewState(poll: pollHistoryDetails, timelineViewModel: timelineViewModel))
|
||||
init(timelineViewModel: TimelinePollViewModelProtocol) {
|
||||
super.init(initialViewState: PollHistoryDetailViewState(timelineViewModel: timelineViewModel))
|
||||
}
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
+10
-14
@@ -18,21 +18,17 @@ import RiotSwiftUI
|
||||
import XCTest
|
||||
|
||||
class PollHistoryDetailUITests: MockScreenTestCase {
|
||||
func testPollHistoryDetailPromptRegular() {
|
||||
let promptType = PollHistoryDetailPromptType.regular
|
||||
app.goToScreenWithIdentifier(MockPollHistoryDetailScreenState.promptType(promptType).title)
|
||||
|
||||
let title = app.staticTexts["title"]
|
||||
XCTAssert(title.exists)
|
||||
XCTAssertEqual(title.label, promptType.title)
|
||||
func testPollHistoryDetailOpenPoll() {
|
||||
app.goToScreenWithIdentifier(MockPollHistoryDetailScreenState.openDisclosed.title)
|
||||
XCTAssert(app.staticTexts["Active polls"].exists)
|
||||
XCTAssert(app.staticTexts["1/1/01"].exists)
|
||||
XCTAssert(app.buttons["View poll in timeline"].exists)
|
||||
}
|
||||
|
||||
func testPollHistoryDetailPromptUpgrade() {
|
||||
let promptType = PollHistoryDetailPromptType.upgrade
|
||||
app.goToScreenWithIdentifier(MockPollHistoryDetailScreenState.promptType(promptType).title)
|
||||
|
||||
let title = app.staticTexts["title"]
|
||||
XCTAssert(title.exists)
|
||||
XCTAssertEqual(title.label, promptType.title)
|
||||
func testPollHistoryDetailClosedPoll() {
|
||||
app.goToScreenWithIdentifier(MockPollHistoryDetailScreenState.closedDisclosed.title)
|
||||
XCTAssert(app.staticTexts["Past polls"].exists)
|
||||
XCTAssert(app.staticTexts["1/1/01"].exists)
|
||||
XCTAssert(app.buttons["View poll in timeline"].exists)
|
||||
}
|
||||
}
|
||||
|
||||
+19
-13
@@ -27,22 +27,28 @@ class PollHistoryDetailViewModelTests: XCTestCase {
|
||||
var context: PollHistoryDetailViewModelType.Context!
|
||||
|
||||
override func setUpWithError() throws {
|
||||
viewModel = PollHistoryDetailViewModel(promptType: .regular, initialCount: Constants.counterInitialValue)
|
||||
|
||||
let answerOptions = [TimelinePollAnswerOption(id: "1", text: "1", count: 1, winner: false, selected: false),
|
||||
TimelinePollAnswerOption(id: "2", text: "2", count: 1, winner: false, selected: false),
|
||||
TimelinePollAnswerOption(id: "3", text: "3", count: 1, winner: false, selected: false)]
|
||||
|
||||
let timelinePoll = TimelinePollDetails(id: "poll-id",
|
||||
question: "Question",
|
||||
answerOptions: answerOptions,
|
||||
closed: false,
|
||||
startDate: .init(),
|
||||
totalAnswerCount: 3,
|
||||
type: .disclosed,
|
||||
eventType: .started,
|
||||
maxAllowedSelections: 1,
|
||||
hasBeenEdited: false,
|
||||
hasDecryptionError: false)
|
||||
|
||||
viewModel = PollHistoryDetailViewModel(timelineViewModel: TimelinePollViewModel(timelinePollDetails: timelinePoll))
|
||||
context = viewModel.context
|
||||
}
|
||||
|
||||
func testInitialState() {
|
||||
XCTAssertEqual(context.viewState.count, Constants.counterInitialValue)
|
||||
}
|
||||
|
||||
func testCounter() throws {
|
||||
context.send(viewAction: .incrementCount)
|
||||
XCTAssertEqual(context.viewState.count, 1)
|
||||
|
||||
context.send(viewAction: .incrementCount)
|
||||
XCTAssertEqual(context.viewState.count, 2)
|
||||
|
||||
context.send(viewAction: .decrementCount)
|
||||
XCTAssertEqual(context.viewState.count, 1)
|
||||
XCTAssertFalse(context.viewState.isPollClosed)
|
||||
}
|
||||
}
|
||||
|
||||
+29
-19
@@ -47,41 +47,51 @@ struct PollHistoryDetail: View {
|
||||
}
|
||||
private var content: some View {
|
||||
let timelineViewModel = viewModel.viewState.timelineViewModel
|
||||
return VStack {
|
||||
TimelinePollView(viewModel: timelineViewModel.context)
|
||||
.navigationTitle(navigationTitle)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationBarBackButtonHidden(true)
|
||||
.navigationBarItems(leading: btnBack)
|
||||
viewInTimeline
|
||||
return ScrollView {
|
||||
VStack(alignment: .leading) {
|
||||
Text(DateFormatter.pollShortDateFormatter.string(from: viewModel.viewState.pollStartDate))
|
||||
.foregroundColor(theme.colors.tertiaryContent)
|
||||
.font(theme.fonts.caption1)
|
||||
.padding([.top])
|
||||
TimelinePollView(viewModel: timelineViewModel.context)
|
||||
.navigationTitle(navigationTitle)
|
||||
.navigationBarTitleDisplayMode(.inline)
|
||||
.navigationBarBackButtonHidden(true)
|
||||
.navigationBarItems(leading: btnBack, trailing: btnDone)
|
||||
viewInTimeline
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var btnBack : some View {
|
||||
private var btnBack: some View {
|
||||
Button(action: {
|
||||
viewModel.send(viewAction: .dismiss)
|
||||
}) {
|
||||
Image(systemName: "xmark") //"chevron.left"
|
||||
Image(systemName: "chevron.left")
|
||||
.aspectRatio(contentMode: .fit)
|
||||
.foregroundColor(theme.colors.accent)
|
||||
}
|
||||
}
|
||||
private var btnDone: some View {
|
||||
Button {
|
||||
viewModel.send(viewAction: .dismiss)
|
||||
} label: {
|
||||
Text(VectorL10n.done)
|
||||
}
|
||||
.accentColor(theme.colors.accent)
|
||||
}
|
||||
|
||||
private var viewInTimeline: some View {
|
||||
HStack {
|
||||
Button {
|
||||
viewModel.send(viewAction: .viewInTimeline)
|
||||
} label: {
|
||||
Text(VectorL10n.pollHistoryDetailViewInTimeline)
|
||||
}
|
||||
.accentColor(theme.colors.accent)
|
||||
Spacer()
|
||||
Button {
|
||||
viewModel.send(viewAction: .viewInTimeline)
|
||||
} label: {
|
||||
Text(VectorL10n.pollHistoryDetailViewInTimeline)
|
||||
}
|
||||
.accentColor(theme.colors.accent)
|
||||
}
|
||||
|
||||
private var navigationTitle: String {
|
||||
let poll = viewModel.viewState.poll
|
||||
if poll.closed {
|
||||
if viewModel.viewState.isPollClosed {
|
||||
return VectorL10n.pollHistoryPastSegmentTitle
|
||||
} else {
|
||||
return VectorL10n.pollHistoryActiveSegmentTitle
|
||||
|
||||
@@ -28,7 +28,7 @@ struct PollListItem: View {
|
||||
|
||||
var body: some View {
|
||||
VStack(alignment: .leading, spacing: 12) {
|
||||
Text(DateFormatter.shortDateFormatter.string(from: pollData.startDate))
|
||||
Text(DateFormatter.pollShortDateFormatter.string(from: pollData.startDate))
|
||||
.foregroundColor(theme.colors.tertiaryContent)
|
||||
.font(theme.fonts.caption1)
|
||||
|
||||
@@ -68,8 +68,8 @@ struct PollListItem: View {
|
||||
}
|
||||
}
|
||||
|
||||
private extension DateFormatter {
|
||||
static let shortDateFormatter: DateFormatter = {
|
||||
extension DateFormatter {
|
||||
static let pollShortDateFormatter: DateFormatter = {
|
||||
let formatter = DateFormatter()
|
||||
formatter.timeStyle = .none
|
||||
formatter.dateStyle = .short
|
||||
|
||||
Reference in New Issue
Block a user