Skip to content

Commit

Permalink
Merge pull request #65 from Nexters/feat/webview(#25)
Browse files Browse the repository at this point in the history
[홈] 웹 뷰 기본 세팅
  • Loading branch information
enebin committed Aug 17, 2023
2 parents 647be99 + 6117294 commit 29a710d
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 48 deletions.
5 changes: 3 additions & 2 deletions Projects/Domain/Sources/Client/KeymeTestsClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,15 @@ extension KeymeTestsClient: DependencyKey {
public static var liveValue = KeymeTestsClient(
fetchOnboardingTests: {
let api = KeymeTestsAPI.onboarding
// var response = try await KeymeTestsAPIManager.shared.requestWithSampleData(api, object: KeymeTestsDTO.self)
// var response = try await KeymeTestsAPIManager.shared.requestWithSampleData(api, object: KeymeTestsDTO.self)
var response = try await KeymeTestsAPIManager.shared.request(api, object: KeymeTestsDTO.self)

return response.toIconModel()
}, fetchDailyTests: {
let api = KeymeTestsAPI.daily
// var response = try await KeymeTestsAPIManager.shared.requestWithSampleData(api, object: KeymeTestsDTO.self)
var response = try await KeymeTestsAPIManager.shared.request(api, object: KeymeTestsDTO.self)

return response.toIconModel()
}
)
Expand Down
5 changes: 4 additions & 1 deletion Projects/Domain/Sources/Model/KeymeTestsModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import Kingfisher

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

Expand All @@ -31,6 +32,8 @@ public extension KeymeTestsDTO {
IconModel(image: $0.category.iconUrl,
color: Color.hex($0.category.color))
}
return KeymeTestsModel(nickname: nickname ?? "키미키미", icons: icons)
return KeymeTestsModel(nickname: nickname ?? "키미키미",
testId: data.testId,
icons: icons)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// KeymeTestsFeature.swift
// Features
//
// Created by 김영인 on 2023/08/17.
// Copyright © 2023 team.humanwave. All rights reserved.
//

import ComposableArchitecture
import Foundation

public struct KeymeTestsFeature: Reducer {

public struct State: Equatable {
let url: String

public init(url: String) {
self.url = url
}
}

public enum Action {
case transition
}

public init() { }

public var body: some Reducer<State, Action> {
Reduce { state, action in
switch action {
case .transition:
return .none
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//
// KeymeTestsView.swift
// Features
//
// Created by 김영인 on 2023/08/17.
// Copyright © 2023 team.humanwave. All rights reserved.
//

import SwiftUI

import ComposableArchitecture

import DSKit

public struct KeymeTestsView: View {
let store: StoreOf<KeymeTestsFeature>

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

public var body: some View {
WithViewStore(store, observe: { $0 }) { viewStore in
ZStack {
KeymeWebView(url: viewStore.url)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,29 +6,29 @@
// Copyright © 2023 team.humanwave. All rights reserved.
//

import CoreFoundation
import ComposableArchitecture

import Domain

public struct KeymeTestsStartFeature: Reducer {

public struct State: Equatable {
public var keymeTests: KeymeTestsFeature.State?
public var isAnimating: Bool = false
public var isOnboarding: Bool
public var nickname: String?
public var testId: Int = 0
public var icon: IconModel = .EMPTY

public init(isOnboarding: Bool) {
self.isOnboarding = isOnboarding
}
public init() { }
}

public enum Action {
case viewWillAppear
case fetchOnboardingTests(TaskResult<KeymeTestsModel>)
case fetchDailyTests(TaskResult<KeymeTestsModel>)
case startTests
case setIcon(IconModel)
case startButtonDidTap
case keymeTests(KeymeTestsFeature.Action)
}

@Dependency(\.continuousClock) var clock
Expand All @@ -40,41 +40,37 @@ public struct KeymeTestsStartFeature: Reducer {
Reduce { state, action in
switch action {
case .viewWillAppear:
if state.isOnboarding {
return .run { send in
await send(.fetchOnboardingTests(
TaskResult { try await self.keymeTestsClient.fetchOnboardingTests() }
))
}
} else {
return .run { send in
await send(.fetchDailyTests(
TaskResult { try await self.keymeTestsClient.fetchDailyTests() }
))
}
return .run { send in
await send(.fetchDailyTests(
TaskResult { try await self.keymeTestsClient.fetchDailyTests() }
))
}
case let .fetchOnboardingTests(.success(tests)),
let .fetchDailyTests(.success(tests)):
case let .fetchDailyTests(.success(tests)):
state.nickname = tests.nickname
state.testId = tests.testId
state.isAnimating.toggle()
return .run { send in
repeat {
for icon in tests.icons {
await send(.setIcon(icon))
try await self.clock.sleep(for: .seconds(1.59))
try await self.clock.sleep(for: .seconds(1.595))
}
} while true
}
case .fetchOnboardingTests(.failure),
.fetchDailyTests(.failure):
case .fetchDailyTests(.failure):
state.nickname = nil
case .startTests:
// TODO: 웹뷰 구현
return .none
case let .setIcon(icon):
state.icon = icon
case .startButtonDidTap:
let url = "https://keyme-frontend.vercel.app/test/\(state.testId)"
state.keymeTests = KeymeTestsFeature.State(url: url)
case .keymeTests:
return .none
}
return .none
}
.ifLet(\.keymeTests, action: /Action.keymeTests) {
KeymeTestsFeature()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,33 @@ public struct KeymeTestsStartView: View {
public var body: some View {
WithViewStore(store, observe: { $0 }) { viewStore in
VStack {
Spacer()
.frame(height: 75)

welcomeText(viewStore)

Spacer()

startTestsButton(viewStore)

Spacer()
Spacer()
IfLetStore(
self.store.scope(
state: \.keymeTests,
action: KeymeTestsStartFeature.Action.keymeTests
),
then: { store in
KeymeTestsView(store: store)
.ignoresSafeArea(.all)
.transition(.scale.animation(.easeIn))
},
else: {
Spacer()
.frame(height: 75)

welcomeText(viewStore)

Spacer()

startTestsButton(viewStore)
.onTapGesture {
viewStore.send(.startButtonDidTap)
}

Spacer()
Spacer()
}
)
}
.frame(maxWidth: .infinity)
.onAppear {
Expand All @@ -58,19 +74,19 @@ public struct KeymeTestsStartView: View {
.strokeBorder(.white.opacity(0.3), lineWidth: 1)
.background(Circle().foregroundColor(.white.opacity(0.3)))
.frame(width: 280, height: 280)
.scaleEffect(viewStore.isAnimating ? 1 : 0.8)
.scaleEffect(viewStore.isAnimating ? 1.0 : 0.8)
.shadow(color: .white.opacity(0.3), radius: 30, x: 0, y: 10)
.animation(.spring(response: 0.85).repeatForever(), value: viewStore.isAnimating)

Circle()
.foregroundColor(viewStore.icon.color)
.frame(width: 110, height: 110)
.scaleEffect(viewStore.isAnimating ? 1 : 0)
.scaleEffect(viewStore.isAnimating ? 1.0 : 0.001)
.animation(.spring(response: 0.8).repeatForever(), value: viewStore.isAnimating)

KFImageManager.shared.toImage(url:viewStore.icon.image)
.frame(width: 24, height: 24)
.scaleEffect(viewStore.isAnimating ? 1 : 0)
.scaleEffect(viewStore.isAnimating ? 1.0 : 0.001)
.animation(.spring(response: 0.8).repeatForever(), value: viewStore.isAnimating)
}
}
Expand Down
45 changes: 45 additions & 0 deletions Projects/Features/Sources/KeymeTests/KeymeWeb/KeymeWebView.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//
// KeymeWebView.swift
// Features
//
// Created by 김영인 on 2023/08/17.
// Copyright © 2023 team.humanwave. All rights reserved.
//

import SwiftUI
import WebKit

public struct KeymeWebView: UIViewRepresentable {
public let url: String

init(url: String) {
self.url = url
}

public func makeUIView(context: Context) -> WKWebView {
let webView = WKWebView(frame: CGRect.zero, configuration: WKWebViewConfiguration())
webView.backgroundColor = .init(white: 1, alpha: 0.3)

if let url = URL(string: url) {
webView.load(URLRequest(url: url))
}

return webView
}

public func updateUIView(_ uiView: WKWebView, context: Context) {

}

public func makeCoordinator() -> Coordinator {
Coordinator(parent: self)
}

public class Coordinator: NSObject {
let parent: KeymeWebView

init(parent: KeymeWebView) {
self.parent = parent
}
}
}
5 changes: 3 additions & 2 deletions Projects/Network/Sources/DTO/KeymeTestsDTO.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,11 @@ public struct KeymeTestsDTO: Codable {
}

public struct DataDTO: Codable {
public let testResultId: Int?
public let owner: PresenterProfileDTO
public let questions: [QuestionDTO]
let solvedCount, testId: Int
let testResultId: Int
let solvedCount: Int
public let testId: Int
let title: String
}

Expand Down
6 changes: 3 additions & 3 deletions Projects/Network/Sources/Network/API/KeymeTestsAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ extension KeymeTestsAPI: BaseAPI {

public var headers: [String : String]? {
// TODO: token 받아서 넣기
return ["Authorization": "access-token"]
return ["Authorization": "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJhY2Nlc3NUb2tlbiIsImlhdCI6MTY5MTg0MjM1NiwiZXhwIjoxNjk0NDM0MzU2LCJtZW1iZXJJZCI6Miwicm9sZSI6IlJPTEVfVVNFUiJ9.bLUl_ObvXr2pkLGNBZYWbJgLZLo3P0xB2pawckRGYZM"]
}

public var sampleData: Data {
Expand All @@ -44,13 +44,13 @@ extension KeymeTestsAPI: BaseAPI {
"code": 200,
"message": "요청에 성공했습니다.",
"data": {
"testId": 5,
"testId": 4,
"testResultId": null,
"solvedCount": 0,
"title": "님은 돈관리를 잘한다",
"owner": {
"id": 2,
"nickname": null,
"nickname": "영인",
"profileThumbnail": "https://keyme-ec2-access-s3.s3.ap-northeast-2.amazonaws.com/keyme_default.png"
},
"questions": [
Expand Down

0 comments on commit 29a710d

Please sign in to comment.