diff --git a/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift b/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift index c00ccf528..65d393957 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/MockPollHistoryScreenState.swift @@ -45,10 +45,10 @@ enum MockPollHistoryScreenState: MockScreenState, CaseIterable { pollHistoryMode = .past case .activeEmpty: pollHistoryMode = .active - pollService.pollListData = [] + pollService.activePollsData = [] case .pastEmpty: pollHistoryMode = .past - pollService.pollListData = [] + pollService.pastPollsData = [] } let viewModel = PollHistoryViewModel(mode: pollHistoryMode, pollService: pollService) diff --git a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift index c8960add0..93ef30819 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryModels.swift @@ -33,7 +33,7 @@ struct PollHistoryViewBindings { struct PollHistoryViewState: BindableState { init(mode: PollHistoryMode) { - self.bindings = .init(mode: mode) + bindings = .init(mode: mode) } var bindings: PollHistoryViewBindings @@ -42,4 +42,5 @@ struct PollHistoryViewState: BindableState { enum PollHistoryViewAction { case viewAppeared + case segmentDidChange } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift index 0addb8ef9..4199251da 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/PollHistoryViewModel.swift @@ -20,6 +20,7 @@ typealias PollHistoryViewModelType = StateStoreViewModel? { didSet { oldValue?.cancel() @@ -39,6 +40,8 @@ final class PollHistoryViewModel: PollHistoryViewModelType, PollHistoryViewModel switch viewAction { case .viewAppeared: fetchingTask = fetchPolls() + case .segmentDidChange: + updatePolls() } } } @@ -53,8 +56,22 @@ private extension PollHistoryViewModel { } await MainActor.run { - state.polls = polls + self.polls = polls + updatePolls() } } } + + func updatePolls() { + let renderedPolls: [PollListData] + + switch context.mode { + case .active: + renderedPolls = polls.filter { $0.winningOption == nil } + case .past: + renderedPolls = polls.filter { $0.winningOption != nil } + } + + state.polls = renderedPolls + } } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/Service/Mock/MockPollHistoryService.swift b/RiotSwiftUI/Modules/Room/PollHistory/Service/Mock/MockPollHistoryService.swift index 67d312181..62796963d 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/Service/Mock/MockPollHistoryService.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/Service/Mock/MockPollHistoryService.swift @@ -15,15 +15,30 @@ // final class MockPollHistoryService: PollHistoryServiceProtocol { - var pollListData: [PollListData] = (1..<10) + var activePollsData: [PollListData] = (1..<10) .map { index in - PollListData(startDate: .init().addingTimeInterval(-CGFloat(index) * 3600), question: "Do you like the poll number \(index)?") - } - .sorted { poll1, poll2 in - poll1.startDate > poll2.startDate + PollListData( + startDate: .init().addingTimeInterval(-CGFloat(index) * 3600), + question: "Do you like the active poll number \(index)?", + numberOfVotes: 30, + winningOption: nil + ) } + var pastPollsData: [PollListData] = (1..<10) + .map { index in + PollListData( + startDate: .init().addingTimeInterval(-CGFloat(index) * 3600), + question: "Do you like the past poll number \(index)?", + numberOfVotes: 30, + winningOption: .init(id: "id", text: "Yes, of course!", count: 20, winner: true, selected: true) + ) + } + func fetchHistory() async throws -> [PollListData] { - pollListData + (activePollsData + pastPollsData) + .sorted { poll1, poll2 in + poll1.startDate > poll2.startDate + } } } diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift index b1208f547..cd9001a56 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollHistory.swift @@ -45,6 +45,9 @@ struct PollHistory: View { .onAppear { viewModel.send(viewAction: .viewAppeared) } + .onChange(of: viewModel.mode) { newValue in + viewModel.send(viewAction: .segmentDidChange) + } } private var pollListView: some View { diff --git a/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift index 373ea0202..98c5f06bd 100644 --- a/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift +++ b/RiotSwiftUI/Modules/Room/PollHistory/View/PollListItem.swift @@ -19,6 +19,8 @@ import SwiftUI struct PollListData { let startDate: Date let question: String + let numberOfVotes: UInt + let winningOption: TimelinePollAnswerOption? } struct PollListItem: View { @@ -36,18 +38,62 @@ struct PollListItem: View { Text(pollData.formattedDate) .foregroundColor(theme.colors.tertiaryContent) .font(theme.fonts.caption1) - + HStack(alignment: .firstTextBaseline, spacing: 8) { Image(uiImage: Asset.Images.pollHistory.image) .resizable() .frame(width: imageSize, height: imageSize) - + Text(pollData.question) .foregroundColor(theme.colors.primaryContent) .font(theme.fonts.body) .lineLimit(2) .accessibilityLabel("PollListItem.title") } + + if pollData.winningOption != nil { + optionView(winningOption: pollData.winningOption!) + } + } + } + + private var clipShape: some Shape { + RoundedRectangle(cornerRadius: 4.0) + } + + private func optionView(winningOption: TimelinePollAnswerOption) -> some View { + VStack(alignment: .leading, spacing: 12.0) { + HStack(alignment: .top, spacing: 8.0) { + Text(pollData.winningOption!.text) + .font(theme.fonts.body) + .foregroundColor(theme.colors.primaryContent) + + Spacer() + + votesText(winningOption: winningOption) + } + + ProgressView(value: Double(winningOption.count), + total: Double(pollData.numberOfVotes)) + .progressViewStyle(LinearProgressViewStyle()) + .scaleEffect(x: 1.0, y: 1.2, anchor: .center) + } + .frame(maxWidth: .infinity, alignment: .leading) + .padding(.horizontal, 8.0) + .padding(.top, 12.0) + .padding(.bottom, 12.0) + .clipShape(clipShape) + .overlay(clipShape.stroke(theme.colors.accent, lineWidth: 1.0)) + .accentColor(theme.colors.accent) + } + + private func votesText(winningOption: TimelinePollAnswerOption) -> some View { + Label { + Text(winningOption.count == 1 ? VectorL10n.pollTimelineOneVote : VectorL10n.pollTimelineVotesCount(Int(winningOption.count))) + .font(theme.fonts.footnote) + .foregroundColor(theme.colors.accent) + } icon: { + Image(uiImage: Asset.Images.pollWinnerIcon.image) } } } @@ -72,6 +118,24 @@ private extension DateFormatter { struct PollListItem_Previews: PreviewProvider { static var previews: some View { - PollListItem(pollData: .init(startDate: .init(), question: "Did you like this poll?")) + Group { + let pollData1 = PollListData( + startDate: .init(), + question: "Do you like polls?", + numberOfVotes: 30, + winningOption: .init(id: "id", text: "Yes, of course!", count: 18, winner: true, selected: true) + ) + + PollListItem(pollData: pollData1) + + let pollData2 = PollListData( + startDate: .init(), + question: "Do you like polls?", + numberOfVotes: 30, + winningOption: nil) + + PollListItem(pollData: pollData2) + } + .padding() } }