Skip to content

Commit

Permalink
Merge pull request #94 from Nexters/feat/home-daily-tests(#93)
Browse files Browse the repository at this point in the history
[ํ™ˆ] ๋ฐ์ผ๋ฆฌ ๋ฌธ์ œ ๋ฆฌ์ŠคํŠธ ํ™”๋ฉด ๊ตฌํ˜„
  • Loading branch information
enebin authored Sep 14, 2023
2 parents efcaa6f + 5ef0033 commit f5d9653
Show file tree
Hide file tree
Showing 29 changed files with 716 additions and 198 deletions.
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

0 comments on commit f5d9653

Please sign in to comment.