Skip to content

Commit 9d9b5f8

Browse files
authored
Merge pull request #208 from Nexters/release/1.0.3
v1.0.3 Release -> Main
2 parents d321de7 + 77211d3 commit 9d9b5f8

File tree

40 files changed

+1021
-61
lines changed

40 files changed

+1021
-61
lines changed

Plugins/DependencyPlugin/ProjectDescriptionHelpers/Modules.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public extension ModulePath {
2727
// MARK: - FeatureModule
2828
public extension ModulePath {
2929
enum Feature: String, CaseIterable {
30+
case Guide
3031
case TabBar
3132
case Report
3233
case BottleArrival

Projects/App/Sources/AppDelegate.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ extension AppDelegate: UNUserNotificationCenterDelegate {
4444
Log.debug("fcm token: \(fcmToken ?? "NO TOKEN")")
4545
if let fcmToken {
4646
// TODO: user defaults 설정 방법 변경
47-
UserDefaults.standard.set(fcmToken, forKey: "fcmToken")
47+
store.send(.appDelegate(.didReceivedFcmToken(fcmToken: fcmToken)))
4848
}
4949
}
5050

Projects/Domain/Auth/Sources/AuthClient.swift

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
import Foundation
99

1010
import DomainAuthInterface
11+
import DomainUser
12+
1113
import CoreNetwork
1214
import CoreLoggerInterface
1315

@@ -19,12 +21,13 @@ extension AuthClient: DependencyKey {
1921
private static func live() -> AuthClient {
2022
@Dependency(\.network) var networkManager
2123
@Dependency(\.loginManager) var loginManager
22-
24+
@Dependency(\.userClient) var userClient
2325
return .init(
2426
signInWithKakao: {
2527
let signInResult = try await loginManager.signIn(loginType: .kakao)
2628
let accessToken = signInResult.accessToken
27-
guard let fcmToken = UserDefaults.standard.string(forKey: "fcmToken")
29+
let fcmToken = userClient.fetchFcmToken()
30+
guard let fcmToken = fcmToken
2831
else {
2932
Log.fault("no fcm token")
3033
fatalError()
@@ -40,8 +43,8 @@ extension AuthClient: DependencyKey {
4043
let signInResult = try await loginManager.signIn(loginType: .apple)
4144
let accessToken = signInResult.accessToken
4245
let userName = signInResult.userName
43-
44-
guard let fcmToken = UserDefaults.standard.string(forKey: "fcmToken")
46+
let fcmToken = userClient.fetchFcmToken()
47+
guard let fcmToken = fcmToken
4548
else {
4649
Log.fault("no fcm token")
4750
fatalError()
@@ -62,7 +65,8 @@ extension AuthClient: DependencyKey {
6265
try await networkManager.reqeust(api: .apiType(AuthAPI.withdraw))
6366
},
6467
logout: {
65-
guard let fcmToken = UserDefaults.standard.string(forKey: "fcmToken")
68+
let fcmToken = userClient.fetchFcmToken()
69+
guard let fcmToken = fcmToken
6670
else {
6771
Log.fault("no fcm token")
6872
return

Projects/Domain/User/Interface/Sources/UserClient.swift

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,25 @@ import Foundation
1010
public struct UserClient {
1111
private let _isLoggedIn: () -> Bool
1212
private let _isAppDeleted: () -> Bool
13+
private let _fetchFcmToken: () -> String?
1314
private let updateLoginState: (Bool) -> Void
1415
private let updateDeleteState: (Bool) -> Void
16+
private let updateFcmToken: (String) -> Void
1517

1618
public init(
1719
isLoggedIn: @escaping () -> Bool,
1820
isAppDeleted: @escaping () -> Bool,
21+
fetchFcmToken: @escaping () -> String?,
1922
updateLoginState: @escaping (Bool) -> Void,
20-
updateDeleteState: @escaping (Bool) -> Void
23+
updateDeleteState: @escaping (Bool) -> Void,
24+
updateFcmToken: @escaping (String) -> Void
2125
) {
2226
self._isLoggedIn = isLoggedIn
2327
self._isAppDeleted = isAppDeleted
28+
self._fetchFcmToken = fetchFcmToken
2429
self.updateLoginState = updateLoginState
2530
self.updateDeleteState = updateDeleteState
31+
self.updateFcmToken = updateFcmToken
2632
}
2733

2834
public func isLoggedIn() -> Bool {
@@ -33,11 +39,19 @@ public struct UserClient {
3339
_isAppDeleted()
3440
}
3541

42+
public func fetchFcmToken() -> String? {
43+
_fetchFcmToken()
44+
}
45+
3646
public func updateLoginState(isLoggedIn: Bool) {
3747
updateLoginState(isLoggedIn)
3848
}
3949

4050
public func updateDeleteState(isDelete: Bool) {
4151
updateDeleteState(isDelete)
4252
}
53+
54+
public func updateFcmToken(fcmToken: String) {
55+
updateFcmToken(fcmToken)
56+
}
4357
}

Projects/Domain/User/Sources/UserClient.swift

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,20 @@ extension UserClient: DependencyKey {
2626
return !UserDefaults.standard.bool(forKey: "deleteState")
2727
},
2828

29+
fetchFcmToken: {
30+
return UserDefaults.standard.string(forKey: "fcmToken")
31+
},
32+
2933
updateLoginState: { isLoggedIn in
3034
UserDefaults.standard.set(isLoggedIn, forKey: "loginState")
3135
},
3236

3337
updateDeleteState: { isDelete in
3438
UserDefaults.standard.set(!isDelete, forKey: "deleteState")
39+
},
40+
41+
updateFcmToken: { fcmToken in
42+
UserDefaults.standard.set(fcmToken, forKey: "fcmToken")
3543
}
3644
)
3745
}

Projects/Feature/BottleStorage/Example/Sources/AppView.swift

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,6 @@ struct AppView: App {
2121
initialState: BottleStorageFeature.State(),
2222
reducer: { BottleStorageFeature() }
2323
))
24-
.onAppear {
25-
AuthClient.liveValue.saveToken(token: .init(
26-
accessToken: "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzIzMTE3ODk1LCJleHAiOjE3MjMxNTM4OTV9.HjjnS1onaAUA6nJGOV-f6FE55eAihUGTFNYGmmyETQc",
27-
refershToken: "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwiaWF0IjoxNzIzMTE3ODk1LCJleHAiOjE3Mzc2MzMwOTV9.Af-L2h_5pBQWrZCc1OQI3tm1DGwowqCAId-rK5vAPaQ"
28-
))
29-
}
3024
}
3125
}
3226
}

Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/PingPongDetail/PingPongDetailFeature.swift

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ extension PingPongDetailFeature {
5454
return fetchPingPong(state: &state)
5555
case .popToRootDidRequired:
5656
return .send(.delegate(.popToRootDidRequired))
57+
case .refreshPingPong:
58+
return fetchPingPong(state: &state)
5759
}
5860

5961
case let .matching(.delegate(delegate)):

Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/Matching/MatchingView.swift

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import ComposableArchitecture
1313

1414
public struct MatchingView: View {
1515
@Perception.Bindable private var store: StoreOf<MatchingFeature>
16+
@Environment(\.openURL) var openURL
1617

1718
public init(store: StoreOf<MatchingFeature>) {
1819
self.store = store
@@ -175,7 +176,13 @@ private extension MatchingView {
175176
case .waiting:
176177
EmptyView()
177178
case .success:
178-
EmptyView()
179+
SolidButton(
180+
title: "카카오톡 바로가기",
181+
sizeType: .large,
182+
buttonType: .throttle,
183+
action: { openKakaoTalk() }
184+
)
185+
179186
case .failure:
180187
SolidButton(
181188
title: "다른 보틀 열어보기",
@@ -242,3 +249,12 @@ private extension MatchingView {
242249
.padding(.bottom, 32.0)
243250
}
244251
}
252+
253+
private extension MatchingView {
254+
// TODO: 추후 구조 변경 필요
255+
func openKakaoTalk() {
256+
let kakaoTalk = "kakaotalk://"
257+
guard let kakaoTalkURL = NSURL(string: kakaoTalk) as? URL else { return }
258+
openURL(kakaoTalkURL)
259+
}
260+
}

Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/QuestionAndAnswer/QuestionAndAnswerFeature.swift

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ extension QuestionAndAnswerFeature {
8282
}
8383
}
8484

85-
case .stopTalkButtonTapped:
85+
case .stopTalkButtonDidTapped:
8686
state.destination = .alert(.init(
8787
title: { TextState("중단하기") },
8888
actions: {
@@ -94,6 +94,9 @@ extension QuestionAndAnswerFeature {
9494
message: { TextState("중단 시 모든 핑퐁 내용이 사라져요. 정말 중단하시겠어요?") }
9595
))
9696
return .none
97+
98+
case .refreshDidPulled:
99+
return .send(.delegate(.refreshPingPong))
97100

98101
case let .destination(.presented(.alert(alert))):
99102
switch alert {

Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/QuestionAndAnswer/QuestionAndAnswerFeatureInterface.swift

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ public struct QuestionAndAnswerFeature {
204204
case finalSelectButtonDidTapped(willMatch: Bool)
205205
case refreshPingPongDidRequired
206206
case configureShowLoadingIndicatorRequired(isShow: Bool)
207-
case stopTalkButtonTapped
207+
case stopTalkButtonDidTapped
208+
case refreshDidPulled
208209

209210
// ETC.
210211
case binding(BindingAction<State>)
@@ -220,6 +221,7 @@ public struct QuestionAndAnswerFeature {
220221
public enum Delegate {
221222
case reloadPingPongRequired
222223
case popToRootDidRequired
224+
case refreshPingPong
223225
}
224226
}
225227

Projects/Feature/BottleStorage/Interface/Sources/PingPongDetail/View/SubViews/QuestionAndAnswer/QuestionAndAnswerView.swift

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ public struct QuestionAndAnswerView: View {
103103
color: .enableSecondary
104104
)
105105
.asThrottleButton {
106-
store.send(.stopTalkButtonTapped)
106+
store.send(.stopTalkButtonDidTapped)
107107
}
108108
.padding(.top, 12.0)
109109
.disabled(store.isStopped == true)
@@ -122,6 +122,10 @@ public struct QuestionAndAnswerView: View {
122122
isTextFieldFocused = textFieldState == .active || textFieldState == .enabled ? false : true
123123
}
124124
}
125+
.refreshable {
126+
try? await Task.sleep(nanoseconds: 300_000_000)
127+
await store.send(.refreshDidPulled).finish()
128+
}
125129
.scrollIndicators(.hidden)
126130
.overlay {
127131
if store.isShowLoadingIndicator {
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import SwiftUI
2+
3+
import FeatureGuideInterface
4+
5+
import ComposableArchitecture
6+
7+
@main
8+
struct AppView: App {
9+
let mainGuideStore = Store(
10+
initialState: MainGuideFeature.State(),
11+
reducer: { MainGuideFeature() })
12+
13+
let pingpongGuideStore = Store(
14+
initialState: PingPongGuideFeature.State(),
15+
reducer: { PingPongGuideFeature() })
16+
17+
let photoShareGuideStore = Store(
18+
initialState: PhotoShareGuideFeature.State(),
19+
reducer: { PhotoShareGuideFeature() })
20+
21+
let startGuideStore = Store(
22+
initialState: StartGuideFeature.State(),
23+
reducer: { StartGuideFeature() })
24+
25+
var body: some Scene {
26+
27+
WindowGroup {
28+
// MainGuideView(store: mainGuideStore)
29+
// PingPongGuideView(store: pingpongGuideStore)
30+
// PhotoShareGuideView(store: photoShareGuideStore)
31+
StartGuideView(store: startGuideStore)
32+
}
33+
}
34+
}
35+
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
//
2+
// MainGuideFeature.swift
3+
// FeatureGuideInterface
4+
//
5+
// Created by 임현규 on 8/22/24.
6+
//
7+
8+
import Foundation
9+
10+
import ComposableArchitecture
11+
12+
@Reducer
13+
public struct MainGuideFeature {
14+
private let reducer: Reduce<State, Action>
15+
16+
init(reducer: Reduce<State, Action>) {
17+
self.reducer = reducer
18+
}
19+
20+
public struct State: Equatable {
21+
public init() {}
22+
}
23+
24+
public enum Action {
25+
26+
// User Action
27+
case nextButtonDidTapped
28+
case backButtonDidTapped
29+
30+
// Delegate
31+
case delegate(Delegate)
32+
33+
public enum Delegate {
34+
case nextButtonDidTapped
35+
}
36+
}
37+
38+
public var body: some ReducerOf<Self> {
39+
reducer
40+
}
41+
}
42+
43+
extension MainGuideFeature {
44+
public init() {
45+
@Dependency(\.dismiss) var dismiss
46+
let reducer = Reduce<State, Action> { state, action in
47+
switch action {
48+
case .nextButtonDidTapped:
49+
return .send(.delegate(.nextButtonDidTapped))
50+
51+
case .backButtonDidTapped:
52+
return .run { send in
53+
await dismiss()
54+
}
55+
56+
default:
57+
return .none
58+
}
59+
}
60+
61+
self.init(reducer: reducer)
62+
}
63+
}

0 commit comments

Comments
 (0)