Feature/4383 poll participants details

This commit is contained in:
Frank Rotermund
2023-05-31 14:31:07 +00:00
committed by Arnfried Griesert
parent 00286183f6
commit 9bd569dac0
22 changed files with 462 additions and 19 deletions
@@ -42,7 +42,7 @@ final class PollEditFormCoordinator: Coordinator, Presentable {
init(parameters: PollEditFormCoordinatorParameters) {
self.parameters = parameters
var viewModel: PollEditFormViewModel
if let startEvent = parameters.pollStartEvent,
let pollContent = MXEventContentPollStart(fromJSON: startEvent.content) {
@@ -29,9 +29,9 @@ enum MockPollHistoryDetailScreenState: MockScreenState, CaseIterable {
}
var poll: TimelinePollDetails {
let answerOptions = [TimelinePollAnswerOption(id: "1", text: "First", count: 10, winner: false, selected: false),
TimelinePollAnswerOption(id: "2", text: "Second", count: 5, winner: false, selected: true),
TimelinePollAnswerOption(id: "3", text: "Third", count: 15, winner: true, selected: false)]
let answerOptions = [TimelinePollAnswerOption(id: "1", text: "First", count: 10, winner: false, selected: false, voters:[]),
TimelinePollAnswerOption(id: "2", text: "Second", count: 5, winner: false, selected: true, voters:[]),
TimelinePollAnswerOption(id: "3", text: "Third", count: 15, winner: true, selected: false, voters:[])]
let poll = TimelinePollDetails(id: "id",
question: "Question",
@@ -70,7 +70,7 @@ private extension MockPollHistoryService {
.map { index in
TimelinePollDetails(id: "p\(index)",
question: "Do you like the active poll number \(index)?",
answerOptions: [.init(id: "id", text: "Yes, of course!", count: 20, winner: true, selected: true)],
answerOptions: [.init(id: "id", text: "Yes, of course!", count: 20, winner: true, selected: true, voters: [])],
closed: true,
startDate: .init().addingTimeInterval(TimeInterval(-index) * 3600 * 24),
totalAnswerCount: 30,
@@ -85,7 +85,7 @@ struct PollListItem_Previews: PreviewProvider {
Group {
let pollData1 = TimelinePollDetails(id: UUID().uuidString,
question: "Do you like polls?",
answerOptions: [.init(id: "id", text: "Yes, of course!", count: 18, winner: true, selected: true)],
answerOptions: [.init(id: "id", text: "Yes, of course!", count: 18, winner: true, selected: true, voters:[])],
closed: true,
startDate: .init(),
totalAnswerCount: 30,
@@ -98,7 +98,7 @@ struct PollListItem_Previews: PreviewProvider {
let pollData2 = TimelinePollDetails(id: UUID().uuidString,
question: "Do you like polls?",
answerOptions: [.init(id: "id", text: "Yes, of course!", count: 18, winner: true, selected: true)],
answerOptions: [.init(id: "id", text: "Yes, of course!", count: 18, winner: true, selected: true, voters:[])],
closed: false,
startDate: .init(),
totalAnswerCount: 30,
@@ -112,8 +112,8 @@ struct PollListItem_Previews: PreviewProvider {
let pollData3 = TimelinePollDetails(id: UUID().uuidString,
question: "Do you like polls?",
answerOptions: [
.init(id: "id1", text: "Yes, of course!", count: 15, winner: true, selected: true),
.init(id: "id2", text: "No, I don't :-(", count: 15, winner: true, selected: true)
.init(id: "id1", text: "Yes, of course!", count: 15, winner: true, selected: true, voters:[]),
.init(id: "id2", text: "No, I don't :-(", count: 15, winner: true, selected: true, voters:[])
],
closed: true,
startDate: .init(),
@@ -29,6 +29,7 @@ final class TimelinePollCoordinator: Coordinator, Presentable, PollAggregatorDel
// MARK: Private
private let navigationRouter: NavigationRouterType?
private let parameters: TimelinePollCoordinatorParameters
private let selectedAnswerIdentifiersSubject = PassthroughSubject<[String], Never>()
@@ -43,9 +44,12 @@ final class TimelinePollCoordinator: Coordinator, Presentable, PollAggregatorDel
// MARK: - Setup
init(parameters: TimelinePollCoordinatorParameters) throws {
// FRROT show participants needs a navigation router as it is a button click that creates a new View
init(parameters: TimelinePollCoordinatorParameters, navigationRouter: NavigationRouterType? = nil) throws {
self.parameters = parameters
self.navigationRouter = navigationRouter
try pollAggregator = PollAggregator(session: parameters.session, room: parameters.room, pollEvent: parameters.pollEvent)
pollAggregator.delegate = self
@@ -56,6 +60,9 @@ final class TimelinePollCoordinator: Coordinator, Presentable, PollAggregatorDel
switch result {
case .selectedAnswerOptionsWithIdentifiers(let identifiers):
self.selectedAnswerIdentifiersSubject.send(identifiers)
case .showParticipants:
self.showParticipantsView()
}
}
@@ -105,6 +112,23 @@ final class TimelinePollCoordinator: Coordinator, Presentable, PollAggregatorDel
}
}
func showParticipantsView() {
if let navigationRouter = navigationRouter {
let parameters = PollParticipantDetailsCoordinatorParameters(room: parameters.room, poll: pollAggregator.poll)
let coordinator = PollParticipantDetailsCoordinator(parameters: parameters)
add(childCoordinator: coordinator)
if navigationRouter.modules.isEmpty == false {
navigationRouter.push(coordinator, animated: true, popCompletion: nil)
} else {
navigationRouter.setRootModule(coordinator, popCompletion: nil)
}
coordinator.start()
}
}
// MARK: - PollAggregatorDelegate
func pollAggregatorDidUpdateData(_ aggregator: PollAggregator) {
@@ -134,7 +158,8 @@ extension TimelinePollDetails {
text: pollAnswerOption.text,
count: pollAnswerOption.count,
winner: pollAnswerOption.isWinner,
selected: pollAnswerOption.isCurrentUserSelection)
selected: pollAnswerOption.isCurrentUserSelection,
voters:pollAnswerOption.voters)
}
self.init(id: poll.id,
@@ -31,11 +31,15 @@ class TimelinePollProvider: NSObject {
}
}
}
var navigationRouter: NavigationRouterType? = nil
var coordinatorsForEventIdentifiers = [String: TimelinePollCoordinator]()
/// Create or retrieve the poll timeline coordinator for this event and return
/// a view to be displayed in the timeline
func buildTimelinePollVCForEvent(_ event: MXEvent) -> UIViewController? {
guard let session = session, let room = session.room(withRoomId: event.roomId) else {
return nil
}
@@ -45,7 +49,7 @@ class TimelinePollProvider: NSObject {
}
let parameters = TimelinePollCoordinatorParameters(session: session, room: room, pollEvent: event)
guard let coordinator = try? TimelinePollCoordinator(parameters: parameters) else {
guard let coordinator = try? TimelinePollCoordinator(parameters: parameters, navigationRouter: navigationRouter ) else {
return messageViewController(for: event)
}
@@ -26,6 +26,7 @@ enum TimelinePollViewAction {
enum TimelinePollViewModelResult {
case selectedAnswerOptionsWithIdentifiers([String])
case showParticipants
}
enum TimelinePollType {
@@ -44,13 +45,15 @@ struct TimelinePollAnswerOption: Identifiable {
var count: UInt
var winner: Bool
var selected: Bool
var voters: [MXEvent]
init(id: String, text: String, count: UInt, winner: Bool, selected: Bool) {
init(id: String, text: String, count: UInt, winner: Bool, selected: Bool, voters: [MXEvent]) {
self.id = id
self.text = text
self.count = count
self.winner = winner
self.selected = selected
self.voters = voters
}
}
@@ -29,9 +29,9 @@ enum MockTimelinePollScreenState: MockScreenState, CaseIterable {
}
var screenView: ([Any], AnyView) {
let answerOptions = [TimelinePollAnswerOption(id: "1", text: "First", count: 10, winner: false, selected: false),
TimelinePollAnswerOption(id: "2", text: "Second", count: 5, winner: false, selected: true),
TimelinePollAnswerOption(id: "3", text: "Third", count: 15, winner: true, selected: false)]
let answerOptions = [TimelinePollAnswerOption(id: "1", text: "First", count: 10, winner: false, selected: false, voters:[]),
TimelinePollAnswerOption(id: "2", text: "Second", count: 5, winner: false, selected: true, voters:[]),
TimelinePollAnswerOption(id: "3", text: "Third", count: 15, winner: true, selected: false, voters:[])]
let poll = TimelinePollDetails(id: "id",
question: "Question",
@@ -50,7 +50,7 @@ class TimelinePollViewModel: TimelinePollViewModelType, TimelinePollViewModelPro
updateMultiSelectPollLocalState(&state, selectedAnswerIdentifier: identifier, callback: completion)
}
case .showParticipants:
break
completion?(.showParticipants)
}
}
@@ -169,6 +169,6 @@ struct TimelinePollAnswerOptionButton_Previews: PreviewProvider {
}
static func buildAnswerOption(text: String = "Test", selected: Bool, winner: Bool = false) -> TimelinePollAnswerOption {
TimelinePollAnswerOption(id: "1", text: text, count: 5, winner: winner, selected: selected)
TimelinePollAnswerOption(id: "1", text: text, count: 5, winner: winner, selected: selected, voters:[])
}
}
@@ -58,6 +58,19 @@ struct TimelinePollView: View {
.lineLimit(2)
.font(theme.fonts.footnote)
.foregroundColor(theme.colors.tertiaryContent)
if poll.showParticipants && (poll.type == .undisclosed || poll.closed) {
Button(action: {
viewModel.send(viewAction:.showParticipants)
})
{
Text(BWIL10n.pollTimelineShowParticipantsButton)
.font(theme.fonts.body)
.bold()
.foregroundColor(theme.colors.accent)
}
}
}
.padding([.horizontal, .top], 2.0)
.padding([.bottom])