Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[홈] 데일리 문제 리스트 화면 구현 #94

Merged
merged 15 commits into from
Sep 14, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "profile.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "[email protected]",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "[email protected]",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"images" : [
{
"filename" : "Group 1000012460.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"filename" : "Group [email protected]",
"idiom" : "universal",
"scale" : "2x"
},
{
"filename" : "Group [email protected]",
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
43 changes: 43 additions & 0 deletions Projects/Domain/Sources/Model/DailyStatisticsModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// DailyStatisticsModel.swift
// Domain
//
// Created by 김영인 on 2023/09/06.
// Copyright © 2023 team.humanwave. All rights reserved.
//

import SwiftUI

import Network

public struct DailyStatisticsModel: Equatable {
public let solvedCount: Int
public let testsStatistics: [TestsStatisticsModel]
}

public struct TestsStatisticsModel: Hashable, Equatable {
public let keymeTests: KeymeTestsInfoModel
public let avarageScore: Double?
}

public extension StatisticsDTO {
func toDailyStatisticsModel() -> DailyStatisticsModel {
let testsStatistics = data.questionsStatistics.map {
TestsStatisticsModel(
keymeTests: KeymeTestsInfoModel(
keyword: $0.keyword,
icon: IconModel(
imageURL: $0.category.iconUrl,
color: Color.hex($0.category.color)
)
),
avarageScore: $0.avgScore
)
}

return DailyStatisticsModel(
solvedCount: data.solvedCount,
testsStatistics: testsStatistics
)
}
}
16 changes: 16 additions & 0 deletions Projects/Domain/Sources/Model/EmptyModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// EmptyModel.swift
// Domain
//
// Created by 김영인 on 2023/09/06.
// Copyright © 2023 team.humanwave. All rights reserved.
//

import Foundation

public extension DailyStatisticsModel {
static var EMPTY: Self = .init(
solvedCount: 0,
testsStatistics: []
)
}
23 changes: 18 additions & 5 deletions Projects/Domain/Sources/Model/KeymeTestsModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,14 @@ import Network
import Kingfisher

public struct KeymeTestsModel: Equatable {
public let nickname: String
public let testId: Int
public let icons: [IconModel]
public let tests: [KeymeTestsInfoModel]
}

public struct KeymeTestsInfoModel: Hashable, Equatable {
public let keyword: String
public let icon: IconModel
}

public struct IconModel: Equatable, Hashable {
Expand All @@ -26,11 +32,18 @@ public struct IconModel: Equatable, Hashable {

public extension KeymeTestsDTO {
func toKeymeTestsModel() -> KeymeTestsModel {
let icons = data.questions.map {
IconModel(imageURL: $0.category.iconUrl,
color: Color.hex($0.category.color))
let tests = data.questions.map {
KeymeTestsInfoModel(
keyword: $0.keyword,
icon: IconModel(
imageURL: $0.category.iconUrl,
color: Color.hex($0.category.color)
)
)
}

return KeymeTestsModel(testId: data.testId, icons: icons)
return KeymeTestsModel(nickname: data.owner.nickname,
testId: data.testId,
tests: tests)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
//
// DailyTestFeature.swift
// Features
//
// Created by 김영인 on 2023/09/06.
// Copyright © 2023 team.humanwave. All rights reserved.
//

import ComposableArchitecture

import Domain
import Network

public struct DailyTestListFeature: Reducer {
@Dependency(\.keymeAPIManager) private var network

public struct State: Equatable {
let testData: KeymeTestsModel
var dailyStatistics: DailyStatisticsModel = .EMPTY

init(testData: KeymeTestsModel) {
self.testData = testData
}
}

public enum Action {
case onAppear
case onDisappear
case fetchDailyStatistics
case saveDailyStatistics(DailyStatisticsModel)
case shareButtonDidTap
}

enum CancelID {
case dailyTestList
}

public var body: some Reducer<State, Action> {
Reduce { state, action in
switch action {
case .onAppear:
return .send(.fetchDailyStatistics)

case .onDisappear:
return .cancel(id: CancelID.dailyTestList)

case .fetchDailyStatistics:
return .run { [testId = state.testData.testId] send in
let dailyStatisticsData = try await network.request(.test(.statistics(testId)), object: StatisticsDTO.self)
// let dailyStatisticsData = try await network.requestWithSampleData(.test(.statistics(testId)), object: StatisticsDTO.self)
let dailyStatistics = dailyStatisticsData.toDailyStatisticsModel()
await send(.saveDailyStatistics(dailyStatistics))
}
.cancellable(id: CancelID.dailyTestList)

case let .saveDailyStatistics(dailyStatistics):
state.dailyStatistics = dailyStatistics

default:
return .none
}

return .none
}
}
}
116 changes: 116 additions & 0 deletions Projects/Features/Sources/Home/DailyTestList/DailyTestListView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//
// DailyTestListView.swift
// Features
//
// Created by 김영인 on 2023/09/06.
// Copyright © 2023 team.humanwave. All rights reserved.
//

import SwiftUI

import ComposableArchitecture

import Core
import DSKit
import Util

struct DailyTestListView: View {
var store: StoreOf<DailyTestListFeature>
typealias DailyTestStore = ViewStore<DailyTestListFeature.State,
DailyTestListFeature.Action>

init(store: StoreOf<DailyTestListFeature>) {
self.store = store
}

var body: some View {
WithViewStore(store, observe: { $0 }) { viewStore in
VStack(alignment: .leading) {
Spacer()
.frame(height: 75)

welcomeText(nickname: viewStore.testData.nickname)

Spacer()

HStack(spacing: 4) {
Image(uiImage: DSKitAsset.Image.person.image)
.resizable()
.frame(width: 16, height: 16)

Text.keyme(
"\(viewStore.dailyStatistics.solvedCount)명의 친구가 문제를 풀었어요",
font: .body4
)
.foregroundColor(.white)
}

dailyTestList(viewStore)

Spacer()
}
.onAppear {
viewStore.send(.onAppear)
}
.onDisappear {
viewStore.send(.onDisappear)
}
.fullFrame()
.padding([.leading, .trailing], 16)
}
}
}

extension DailyTestListView {
func welcomeText(nickname: String) -> some View {
Text.keyme(
"\(nickname)님 친구들의\n답변이 쌓이고 있어요!",
font: .heading1)
.foregroundColor(DSKitAsset.Color.keymeWhite.swiftUIColor)
.frame(maxWidth: .infinity, alignment: .leading)
}

func dailyTestList(_ viewStore: DailyTestStore) -> some View {
LazyVStack(spacing: 12) {
ForEach(viewStore.dailyStatistics.testsStatistics, id: \.self) { testStatistics in
ZStack(alignment: .leading) {
Rectangle()
.foregroundColor(.white.opacity(0.05))
.frame(height: 86)
.cornerRadius(14)

HStack(spacing: 12) {
Spacer()
.frame(width: 14)

ZStack {
Circle()
.foregroundColor(testStatistics.keymeTests.icon.color)

KFImageManager.shared.toImage(url: testStatistics.keymeTests.icon.imageURL)
.scaledToFit()
.frame(width: 20)
}
.frame(width: 40, height: 40)

VStack(alignment: .leading, spacing: 7) {
Text.keyme("\(viewStore.testData.nickname)님의 \(testStatistics.keymeTests.keyword)정도는?",
font: .body3Semibold)
.foregroundColor(.white)

statisticsScoreText(score: testStatistics.avarageScore)
}
}
}
}
}
}
}

extension DailyTestListView {
func statisticsScoreText(score: Double?) -> some View {
Text.keyme(score != nil ? "평균점수 | \(String(describing: score))점" : "아직 아무도 풀지 않았어요",
font: .body4)
.foregroundColor(.white.opacity(0.5))
}
}
Loading