Improve PollListItem to support ended polls

This commit is contained in:
Alfonso Grillo
2023-01-17 16:44:56 +01:00
parent be2a6f15b1
commit a898d6fda8
6 changed files with 113 additions and 13 deletions
@@ -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)
@@ -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
}
@@ -20,6 +20,7 @@ typealias PollHistoryViewModelType = StateStoreViewModel<PollHistoryViewState, P
final class PollHistoryViewModel: PollHistoryViewModelType, PollHistoryViewModelProtocol {
private let pollService: PollHistoryServiceProtocol
private var polls: [PollListData] = []
private var fetchingTask: Task<Void, Error>? {
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
}
}
@@ -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
}
}
}
@@ -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 {
@@ -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()
}
}