Skip to content

Commit

Permalink
Merge pull request #242 from Nexters/feature/#239-강제-업데이트-구현
Browse files Browse the repository at this point in the history
[Feature/#239] 강제 업데이트 구현
  • Loading branch information
JongHoooon authored Sep 12, 2024
2 parents c10ab8a + 6c94b00 commit f8f56f9
Show file tree
Hide file tree
Showing 16 changed files with 315 additions and 17 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ public extension ModulePath {

public extension ModulePath {
enum Domain: String, CaseIterable {
case Error
case User
case Report
case WebView
Expand Down
7 changes: 7 additions & 0 deletions Projects/Domain/Auth/Interface/Sources/API/AuthAPI.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ public enum AuthAPI {
case logout(_ logOutRequestDTO: LogOutRequestDTO)
case revoke
case profile(_ requestDTO: ProfileRequestDTO)
case updateVersion
}

extension AuthAPI: BaseTargetType {
Expand All @@ -35,6 +36,8 @@ extension AuthAPI: BaseTargetType {
return "api/v1/auth/apple/revoke"
case .profile:
return "api/v2/auth/profile"
case .updateVersion:
return "api/v1/auth/app-version"
}
}

Expand All @@ -52,6 +55,8 @@ extension AuthAPI: BaseTargetType {
return .get
case .profile:
return .post
case .updateVersion:
return .get
}
}

Expand All @@ -69,6 +74,8 @@ extension AuthAPI: BaseTargetType {
return .requestPlain
case .profile(let requestDTO):
return .requestJSONEncodable(requestDTO)
case .updateVersion:
return .requestPlain
}
}
}
9 changes: 8 additions & 1 deletion Projects/Domain/Auth/Interface/Sources/AuthClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ public struct AuthClient {
private let fetchAppleClientSecret: () async throws -> String
private let registerUserProfile: (String) async throws -> Void
private let _removeAllToken: () -> Void
private let checkUpdateVersion: () async throws -> Void

public init(
signInWithKakao: @escaping () async throws -> UserInfo,
Expand All @@ -31,7 +32,8 @@ public struct AuthClient {
revokeAppleLogin: @escaping () async throws -> Void,
fetchAppleClientSecret: @escaping () async throws -> String,
registerUserProfile: @escaping (String) async throws -> Void,
removeAllToken: @escaping () -> Void
removeAllToken: @escaping () -> Void,
checkUpdateVersion: @escaping () async throws -> Void
) {
self.signInWithKakao = signInWithKakao
self.signInWithApple = signInWithApple
Expand All @@ -44,6 +46,7 @@ public struct AuthClient {
self.fetchAppleClientSecret = fetchAppleClientSecret
self.registerUserProfile = registerUserProfile
self._removeAllToken = removeAllToken
self.checkUpdateVersion = checkUpdateVersion
}

public func signInWithKakao() async throws -> UserInfo {
Expand Down Expand Up @@ -88,5 +91,9 @@ public struct AuthClient {
public func removeAllToken() {
_removeAllToken()
}

public func checkUpdateVersion() async throws {
return try await checkUpdateVersion()
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// UpdateVersionResponseDTO.swift
// DomainAuthInterface
//
// Created by JongHoon on 9/10/24.
//

import Foundation

public struct UpdateVersionResponseDTO: Decodable {
public let minimumIosVersion: Int?
}
3 changes: 2 additions & 1 deletion Projects/Domain/Auth/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ let project = Project.makeModule(
implements: .Auth,
factory: .init(
dependencies: [
.domain(interface: .Auth)
.domain(interface: .Auth),
.domain(interface: .Error)
]
)
),
Expand Down
17 changes: 17 additions & 0 deletions Projects/Domain/Auth/Sources/AuthClient.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import Foundation

import DomainAuthInterface
import DomainErrorInterface
import DomainUser

import CoreNetwork
Expand Down Expand Up @@ -91,6 +92,22 @@ extension AuthClient: DependencyKey {
},
removeAllToken: {
LocalAuthDataSourceImpl.removeAllToken()
},
checkUpdateVersion: {
let minimumIosBuildNumber = try await networkManager.reqeust(api: .apiType(AuthAPI.updateVersion), dto: UpdateVersionResponseDTO.self).minimumIosVersion

guard let buildNumberString = Bundle.main.infoDictionary?["CFBundleVersion"] as? String,
let buildNumber = Int(buildNumberString)
else {
Log.assertion(message: "no build number")
throw DomainError.unknown("no build number")
}
let minimumBuildNumber = minimumIosBuildNumber ?? buildNumber

guard minimumBuildNumber <= buildNumber
else {
throw DomainError.AuthError.needUpdateAppVersion
}
}
)
}
Expand Down
16 changes: 16 additions & 0 deletions Projects/Domain/Error/Interface/Sources/DomainError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//
// DomainError.swift
// DomainError
//
// Created by JongHoon on 9/11/24.
//

import Foundation

public enum DomainError: Error {
public enum AuthError: Error {
case needUpdateAppVersion
}

case unknown(_ message: String? = nil)
}
22 changes: 22 additions & 0 deletions Projects/Domain/Error/Project.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import ProjectDescription
import ProjectDescriptionHelpers
import DependencyPlugin

let project = Project.makeModule(
name: ModulePath.Domain.name+ModulePath.Domain.Error.rawValue,
targets: [
.domain(
interface: .Error,
factory: .init()
),
.domain(
implements: .Error,
factory: .init(
dependencies: [
.domain(interface: .Error)
]
)
),

]
)
1 change: 1 addition & 0 deletions Projects/Domain/Error/Sources/Source.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
// This is for Tuist
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@
//

import Foundation
import UIKit

import SharedDesignSystem
import CoreLoggerInterface
import DomainProfile
import DomainBottle
import DomainAuth
import DomainErrorInterface

import CoreLoggerInterface

import SharedDesignSystem
import SharedUtilInterface

import ComposableArchitecture
Expand All @@ -30,33 +35,48 @@ public struct SandBeachFeature {
public var isLoading: Bool = false
public var isDisableIslandBottle: Bool = false

@Presents var destination: Destination.State?

public init() {}
}

public enum Action: Equatable {
public enum Action: BindableAction {
case onAppear
case userStateFetchCompleted(userState: UserStateType, isDisableButton: Bool)
case updateIsDisableBottle(isDisable: Bool)
case writeButtonDidTapped
case newBottleIslandDidTapped
case bottleStorageIslandDidTapped
case needUpdateAppVersionErrorOccured
case updateAppVersion

case delegate(Delegate)

public enum Delegate {
case writeButtonDidTapped
case newBottleIslandDidTapped
case bottleStorageIslandDidTapped
}

case alert(Alert)
public enum Alert: Equatable {
case needUpdateAppVersion
}

case destination(PresentationAction<Destination.Action>)
case binding(BindingAction<State>)
}

public var body: some ReducerOf<Self> {
reducer
.ifLet(\.$destination, action: \.destination)
}
}

// MARK: - init {
extension SandBeachFeature {
public init() {
@Dependency(\.authClient) var authClient
@Dependency(\.profileClient) var profileClient
@Dependency(\.bottleClient) var bottleClient

Expand All @@ -78,9 +98,10 @@ extension SandBeachFeature {
})

return .run { send in
let isExsit = try await profileClient.checkExistIntroduction()
async let _ = authClient.checkUpdateVersion()
async let isExsit = try await profileClient.checkExistIntroduction()
// 자기소개 없는 상태
if !isExsit {
if try await !isExsit {
await send(.userStateFetchCompleted(
userState: .noIntroduction,
isDisableButton: true))
Expand Down Expand Up @@ -118,6 +139,12 @@ extension SandBeachFeature {
} catch: { error, send in
// TODO: 에러 핸들링
Log.error(error)
if let authError = error as? DomainError.AuthError {
switch authError {
case .needUpdateAppVersion:
await send(.needUpdateAppVersionErrorOccured)
}
}
}

case let .userStateFetchCompleted(userState, isDisableButton):
Expand All @@ -137,10 +164,45 @@ extension SandBeachFeature {
Log.debug("newBottleIslandDidTapped")
return .send(.delegate(.newBottleIslandDidTapped))

case .needUpdateAppVersionErrorOccured:
state.destination = .alert(.init(
title: { TextState("업데이트 안내") },
actions: {
ButtonState(
action: .needUpdateAppVersion,
label: { TextState("업데이트 하기") }
)
},
message: { TextState("최적의 사용 환경을 위해\n최신 버전의 앱으로 업데이트 해주세요") }
))
return .none

case let .destination(.presented(.alert(alert))):
switch alert {
case .needUpdateAppVersion:
return .send(.updateAppVersion)
}

case .updateAppVersion:
let appStoreURL = URL(string: Bundle.main.infoDictionary?["APP_STORE_URL"] as? String ?? "")!
UIApplication.shared.open(appStoreURL)
return .run { _ in
// TODO: Custom Alert 만들면 확인 눌러도 dismiss 되지 않도록 수정
try await Task.sleep(nanoseconds: 3000_000_000)
exit(0)
}

default:
return .none
}
}
self.init(reducer: reducer)
}
}

extension SandBeachFeature {
@Reducer(state: .equatable)
public enum Destination {
case alert(AlertState<SandBeachFeature.Action.Alert>)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import SharedDesignSystem
import ComposableArchitecture

public struct SandBeachView: View {
private let store: StoreOf<SandBeachFeature>
@Perception.Bindable private var store: StoreOf<SandBeachFeature>

public init(store: StoreOf<SandBeachFeature>) {
self.store = store
Expand Down Expand Up @@ -64,6 +64,7 @@ public struct SandBeachView: View {
}
}
}
.alert($store.scope(state: \.destination?.alert, action: \.destination.alert))
.onAppear {
store.send(.onAppear)
}
Expand Down
Loading

0 comments on commit f8f56f9

Please sign in to comment.