Add poll history service

This commit is contained in:
Alfonso Grillo 2023-01-12 17:59:23 +01:00
parent e4a930a64d
commit 84f27cc04c
9 changed files with 141 additions and 18 deletions

View file

@ -36,7 +36,8 @@ final class PollHistoryCoordinator: Coordinator, Presentable {
init(parameters: PollHistoryCoordinatorParameters) {
self.parameters = parameters
let viewModel = PollHistoryViewModel(mode: parameters.mode)
#warning("replace with the real service after that it's done")
let viewModel = PollHistoryViewModel(mode: parameters.mode, pollService: MockPollHistoryService())
let view = PollHistory(viewModel: viewModel.context)
pollHistoryViewModel = viewModel
pollHistoryHostingController = VectorHostingController(rootView: view)

View file

@ -42,7 +42,7 @@ enum MockPollHistoryScreenState: MockScreenState, CaseIterable {
pollHistoryMode = .past
}
let viewModel = PollHistoryViewModel(mode: pollHistoryMode)
let viewModel = PollHistoryViewModel(mode: pollHistoryMode, pollService: MockPollHistoryService())
// can simulate service and viewModel actions here if needs be.

View file

@ -37,8 +37,9 @@ struct PollHistoryViewState: BindableState {
}
var bindings: PollHistoryViewBindings
var polls: [PollListData] = []
}
enum PollHistoryViewAction {
#warning("e.g. show poll detail")
case viewAppeared
}

View file

@ -18,16 +18,43 @@ import SwiftUI
typealias PollHistoryViewModelType = StateStoreViewModel<PollHistoryViewState, PollHistoryViewAction>
class PollHistoryViewModel: PollHistoryViewModelType, PollHistoryViewModelProtocol {
final class PollHistoryViewModel: PollHistoryViewModelType, PollHistoryViewModelProtocol {
private let pollService: PollHistoryServiceProtocol
private var fetchingTask: Task<Void, Error>? {
didSet {
oldValue?.cancel()
}
}
var completion: ((PollHistoryViewModelResult) -> Void)?
init(mode: PollHistoryMode) {
init(mode: PollHistoryMode, pollService: PollHistoryServiceProtocol) {
self.pollService = pollService
super.init(initialViewState: PollHistoryViewState(mode: mode))
}
// MARK: - Public
override func process(viewAction: PollHistoryViewAction) {
switch viewAction {
case .viewAppeared:
fetchingTask = fetchPolls()
}
}
}
private extension PollHistoryViewModel {
func fetchPolls() -> Task<Void, Error> {
Task {
let polls = try await pollService.fetchHistory()
guard Task.isCancelled == false else {
return
}
await MainActor.run {
state.polls = polls
}
}
}
}

View file

@ -0,0 +1,24 @@
//
// Copyright 2023 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
import MatrixSDK
import Foundation
final class PollHistoryService: PollHistoryServiceProtocol {
func fetchHistory() async throws -> [PollListData] {
[]
}
}

View file

@ -0,0 +1,27 @@
//
// Copyright 2023 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
final class MockPollHistoryService: PollHistoryServiceProtocol {
func fetchHistory() async throws -> [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
}
}
}

View file

@ -0,0 +1,19 @@
//
// Copyright 2023 New Vector Ltd
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
protocol PollHistoryServiceProtocol {
func fetchHistory() async throws -> [PollListData]
}

View file

@ -39,8 +39,10 @@ struct PollHistory: View {
ScrollView {
LazyVStack(spacing: 32) {
ForEach(0..<10) { index in
PollListItem(data: .init(startDate: Date(), question: "Poll question number \(index)"))
let enumeratedPolls = Array(viewModel.viewState.polls.enumerated())
ForEach(enumeratedPolls, id: \.offset) { _, pollData in
PollListItem(pollData: pollData)
}
.frame(maxWidth: .infinity, alignment: .leading)
@ -60,10 +62,13 @@ struct PollHistory: View {
.background(theme.colors.background.ignoresSafeArea())
.accentColor(theme.colors.accent)
.navigationTitle(VectorL10n.pollHistoryTitle)
.onAppear {
viewModel.send(viewAction: .viewAppeared)
}
}
}
extension PollHistoryMode {
private extension PollHistoryMode {
var segmentTitle: String {
switch self {
case .active:

View file

@ -24,33 +24,52 @@ struct PollListData {
struct PollListItem: View {
@Environment(\.theme) private var theme
private let data: PollListData
private let pollData: PollListData
init(data: PollListData) {
self.data = data
init(pollData: PollListData) {
self.pollData = pollData
}
var body: some View {
VStack(alignment: .leading, spacing: 12) {
Text(data.startDate.description)
Text(pollData.formattedDate)
.foregroundColor(theme.colors.tertiaryContent)
.font(theme.fonts.caption1)
HStack(spacing: 8) {
HStack(alignment: .firstTextBaseline, spacing: 8) {
Image(uiImage: Asset.Images.pollHistory.image)
.resizable()
.frame(width: 16, height: 16)
Text(data.question)
Text(pollData.question)
.foregroundColor(theme.colors.primaryContent)
.font(theme.fonts.body)
.lineLimit(2)
}
}
}
}
struct PollListItem_Previews: PreviewProvider {
static var previews: some View {
PollListItem(data: .init(startDate: .init(), question: "Did you like this poll?"))
private extension PollListData {
var formattedDate: String {
DateFormatter.shortDateFormatter.string(from: startDate)
}
}
private extension DateFormatter {
static let shortDateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.timeStyle = .none
formatter.dateStyle = .short
formatter.timeZone = .init(identifier: "UTC")
return formatter
}()
}
// MARK: - Previews
struct PollListItem_Previews: PreviewProvider {
static var previews: some View {
PollListItem(pollData: .init(startDate: .init(), question: "Did you like this poll?"))
}
}