Skip to content

Commit 856901b

Browse files
ibcylonMinny27
andauthored
Feature/auth (#81)
* Add SignUpFlows * Feat: Signup Flow - 자기소개까지 * Mod: ResizableTextView * Add LocationField * Add: Like * Feat LocationInput * Feat: Auth * Add: Kakao Service * Feat: SignUp, Auth * Update: Dim 색상 값 변경 * [#74]Feat: 경고창 클래스 커스텀 - ReportAction enum 커스텀 - title, message, contentView, 왼쪽, 오른쪽, dim action 추가 함수 구현 - UIViewController에서 경고창 표시하는 함수 구현 - Color -> Image로 변환 함수 구현 => button에 State에 따른 색상을 넣기 위함 - addAction Custom -> button 혹은 view에서 동작 구현을 위함 * [#74]Update: 디자인 변경 사항 반영 * [#74]Feat: TimerActiveAction 추가 -> 멈추는 이벤트에 따라 케이스를 나눔 - 프로필 더블 클릭, 다른 화면으로 이동할 때는 pauseView를 표시해야하고 - report 버튼을 클릭할 때는 pauseView를 표시하지 않아야 해서 - TimerActiveAction 케이스를 기준으로 Timer를 재개, 멈춤 구현 - info button tap, report button tap 합성 -> infoView를 hidden 시키는 두 가지 액션 처리 * [#74]Feat: report 버튼 클릭 시, 타이머를 멈추고 info view를 hidden하고 alert를 표시 - 현재는 차단하기를 했을 떄, 데이터 또는 dataSource에서 item을 삭제하지 않고, 0.5초 후에 scroll하는 방식으로 구현 - dimview를 클릭하면 타이머가 다시 시작되도록 이벤트 전달 - reject 버튼 이벤트는 애니메이션 1초여서 1초후에 다음 유저로 넘어가도록 구현 * Fix: Add MyPageRepository * [#74]Feat: 신고하기 팝업 커스텀 - ContentView 자체를 커스텀해서 content view를 파라미터로 받아서 팝업에 표시하도록 구현 - left, right -> top, bottom으로 수정 - withSeprator 플래그를 만들어서 구분선 유뮤 구현 - bottom button(마지막 버튼)은 무조건 separator 있음 * [#74]Feat: Toast 메시지 구현 - Toast-Swift 참고 - 디폴트 값 설정 * Update: 컴포넌트의 접근 지정 연산자 수정 및 이름 수정 * Update: 테스트 이미지로 임시 변경 - 서버 연동 전까지는 해당 이미지로 테스트하고자 함 * [#74]Feat: 차단, 신고 시, .none 상태로 업데이트 후, 다음 셀로 스크롤 구현 - user info box 팝업에서 report(느낌표) 버튼 클릭 시, 멈춤 화면 디자인 반영 - 차단 or 신고 팝업 표시 시, 멈춤 화면에서 이미지, 텍스트 히든 - 중지했을 때의 동작을 enum으로 나눠서 처리할 필요 없는 거 같아서 bool로 변경 - 차단 or 신고 시, 멈춤 화면 없애고 dim view 표시 후, none 상태로 설정 * Update: 그레디언트 색상 추가 * [#79]Feat: 좋아요 버튼 클릭 시, 원형 timer, progress 그레디언트 적용 * [#74]Feat: 마지막 더미 유저 Footer View 추가 - footer와 section의 제약조건 설정 * [#74]Feat: 좋아요 버튼 액션 구현 - TimeState에 none 케이스 생성 - 좋아요, 싫어요, 신고, 차단 시, 타이머, 프로그래스를 초기화하기 위함 - 13초에서 15초로 디자인 반영 - vc에서는 scroll만 처리하고 나머지는 cell에서 처리할 수 있도록 구현 * Mod: self capturing in closure * Add: Fastlane (#78) * Add: Fastlane fastlane * [#74]Feat: 신고하기 팝업 커스텀 - ContentView 자체를 커스텀해서 content view를 파라미터로 받아서 팝업에 표시하도록 구현 - left, right -> top, bottom으로 수정 - withSeprator 플래그를 만들어서 구분선 유뮤 구현 - bottom button(마지막 버튼)은 무조건 separator 있음 * [#74]Feat: Toast 메시지 구현 - Toast-Swift 참고 - 디폴트 값 설정 * Update: 컴포넌트의 접근 지정 연산자 수정 및 이름 수정 * Update: 테스트 이미지로 임시 변경 - 서버 연동 전까지는 해당 이미지로 테스트하고자 함 * [#74]Feat: 차단, 신고 시, .none 상태로 업데이트 후, 다음 셀로 스크롤 구현 - user info box 팝업에서 report(느낌표) 버튼 클릭 시, 멈춤 화면 디자인 반영 - 차단 or 신고 팝업 표시 시, 멈춤 화면에서 이미지, 텍스트 히든 - 중지했을 때의 동작을 enum으로 나눠서 처리할 필요 없는 거 같아서 bool로 변경 - 차단 or 신고 시, 멈춤 화면 없애고 dim view 표시 후, none 상태로 설정 * Update: 그레디언트 색상 추가 * [#79]Feat: 좋아요 버튼 클릭 시, 원형 timer, progress 그레디언트 적용 * [#74]Feat: 마지막 더미 유저 Footer View 추가 - footer와 section의 제약조건 설정 * [#74]Feat: 좋아요 버튼 액션 구현 - TimeState에 none 케이스 생성 - 좋아요, 싫어요, 신고, 차단 시, 타이머, 프로그래스를 초기화하기 위함 - 13초에서 15초로 디자인 반영 - vc에서는 scroll만 처리하고 나머지는 cell에서 처리할 수 있도록 구현 * CI_CD: add pkg extension to .gitignore and fastlane 인증 순서 변경 * CICD: TestFlight 수출 규정 암호화 규정 스킵 info plist에 추가 ITSAppUsesNonExemptEncryption --------- Co-authored-by: LeeSeungmin <[email protected]> * Update: layoutSubview() 호출될 때 layer의 frame 설정 및 mask path 설정 - borderWidth 삭제 - cgcolor로 설정 * Refactor: 좋아요, 싫어요 중복 클릭 방지 - 최근 클릭 후, 5초 딜레이 - 필요없는 코드 삭제 * Add: Interceptor * Fix: AuthRepository Init --------- Co-authored-by: LeeSeungmin <[email protected]>
1 parent e20fddd commit 856901b

File tree

209 files changed

+11130
-1031
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

209 files changed

+11130
-1031
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,4 +80,4 @@ fastlane/*.env
8080
# App Packaging
8181
*.ipa
8282
*.dSYM.zip
83-
*.dSYM
83+
*.dSYM

Plugins/THTIOSHappyNewYear/ProjectDescriptionHelpers/InfoPlist.swift

Lines changed: 39 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,36 @@ public let infoPlistExtension: [String: InfoPlist.Value] = [
1212
"CFBundleVersion": "1",
1313
"UILaunchStoryboardName": "LaunchScreen",
1414
"CFBundleName": "THT",
15+
"UIApplicationSceneManifest": [
16+
"UIApplicationSupportsMultipleScenes": false,
17+
"UISceneConfigurations": [
18+
"UIWindowSceneSessionRoleApplication": [
19+
[
20+
"UISceneConfigurationName": "Default Configuration",
21+
"UISceneDelegateClassName": "$(PRODUCT_MODULE_NAME).SceneDelegate"
22+
],
23+
]
24+
]
25+
],
26+
27+
// MARK: Privacy
28+
29+
"UIAppFonts": [
30+
"Item 0": "Pretendard-Medium.otf",
31+
"Item 1": "Pretendard-Regular.otf",
32+
"Item 2": "Pretendard-SemiBold.otf",
33+
"Item 3": "Pretendard-Bold.otf",
34+
"Item 4": "Pretendard-ExtraBold.otf"
35+
],
36+
"UIUserInterfaceStyle": "Dark"
37+
]
38+
39+
public func infoPlistExtension(name: String) -> [String: InfoPlist.Value] {
40+
[
41+
"CFBundleShortVersionString": "1.0",
42+
"CFBundleVersion": "1",
43+
"UILaunchStoryboardName": "LaunchScreen",
44+
"CFBundleName": "\(name)",
1545
"UIApplicationSceneManifest": [
1646
"UIApplicationSupportsMultipleScenes": false,
1747
"UISceneConfigurations": [
@@ -23,8 +53,15 @@ public let infoPlistExtension: [String: InfoPlist.Value] = [
2353
]
2454
]
2555
],
26-
"App Transport Security Settings": ["Allow Arbitrary Loads": true],
27-
"Privacy - Photo Library Additions Usage Description": "프로필에 사용됨",
56+
"NSAppTransportSecurity": ["NSAllowsArbitraryLoads": true],
57+
58+
// MARK: Privacy
59+
"NSContactsUsageDescription": "연락처 사용",
60+
"NSLocationWhenInUseUsageDescription": "위치 정보 사용",
61+
62+
// MARK: 수출 규청 알고리즘 통과
63+
"ITSAppUsesNonExemptEncryption": false,
64+
2865
"UIAppFonts": [
2966
"Item 0": "Pretendard-Medium.otf",
3067
"Item 1": "Pretendard-Regular.otf",
@@ -33,35 +70,5 @@ public let infoPlistExtension: [String: InfoPlist.Value] = [
3370
"Item 4": "Pretendard-ExtraBold.otf"
3471
],
3572
"UIUserInterfaceStyle": "Dark"
36-
]
37-
38-
public func infoPlistExtension(name: String) -> [String: InfoPlist.Value] {
39-
[
40-
"CFBundleShortVersionString": "1.0",
41-
"CFBundleVersion": "1",
42-
"UILaunchStoryboardName": "LaunchScreen",
43-
"CFBundleName": "\(name)",
44-
"UIApplicationSceneManifest": [
45-
"UIApplicationSupportsMultipleScenes": false,
46-
"UISceneConfigurations": [
47-
"UIWindowSceneSessionRoleApplication": [
48-
[
49-
"UISceneConfigurationName": "Default Configuration",
50-
"UISceneDelegateClassName": "$(PRODUCT_MODULE_NAME).SceneDelegate"
51-
],
52-
]
53-
]
54-
],
55-
"App Transport Security Settings": ["Allow Arbitrary Loads": true],
56-
"Privacy - Photo Library Additions Usage Description": "프로필에 사용됨",
57-
"UIAppFonts": [
58-
"Item 0": "Pretendard-Medium.otf",
59-
"Item 1": "Pretendard-Regular.otf",
60-
"Item 2": "Pretendard-SemiBold.otf",
61-
"Item 3": "Pretendard-Bold.otf",
62-
"Item 4": "Pretendard-ExtraBold.otf"
63-
],
64-
"UIUserInterfaceStyle": "Dark",
65-
"ITSAppUsesNonExemptEncryption": false // 수출 규정 누락 문제
6673
]
6774
}

Projects/App/Src/SceneDelegate+Register.swift

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,34 @@ import Data
1212

1313
import Feature
1414
import Networks
15-
import FallingInterface
16-
import LikeInterface
17-
import ChatInterface
18-
import MyPageInterface
1915

2016
extension AppDelegate {
2117
var container: DIContainer {
2218
DIContainer.shared
2319
}
2420

2521
func registerDependencies() {
22+
let tokenStore = UserDefaultTokenStore()
23+
let tokenProvider = DefaultTokenProvider()
24+
25+
container.register(
26+
interface: UserInfoUseCaseInterface.self,
27+
implement: { UserInfoUseCase(repository: UserDefaultUserInfoRepository()) })
28+
29+
container.register(
30+
interface: AuthUseCaseInterface.self,
31+
implement: { AuthUseCase(authRepository: AuthRepository(tokenStore: tokenStore, tokenProvider: tokenProvider),
32+
tokenStore: tokenStore) })
33+
container.register(
34+
interface: SignUpUseCaseInterface.self,
35+
implement: { SignUpUseCase(
36+
repository: SignUpRepository(),
37+
locationService: LocationService(),
38+
kakaoAPIService: KakaoAPIService(),
39+
contactService: ContactService(),
40+
tokenStore: tokenStore)
41+
})
42+
2643
container.register(
2744
interface: FallingUseCaseInterface.self,
2845
implement: {

Projects/Core/Src/BaseCoordinator/LaunchCoordinator.swift

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
import UIKit
99

10-
public protocol LaunchCoordinating {
10+
public protocol LaunchCoordinating: Coordinator {
1111
func launch(window: UIWindow)
1212
}
1313

@@ -21,10 +21,6 @@ open class LaunchCoordinator: BaseCoordinator, LaunchCoordinating {
2121
window.rootViewController = self.viewControllable.uiController
2222
window.makeKeyAndVisible()
2323

24-
TFLogger.domain.debug("AppCoordinator 1초 async")
25-
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
26-
self.start()
27-
}
24+
self.start()
2825
}
2926
}
30-

Projects/Core/Src/BaseType/ViewControllable.swift

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,50 @@ public extension ViewControllable {
3939
self.uiController.navigationController?.popViewController(animated: animated)
4040
}
4141
}
42+
43+
func present(_ viewControllable: ViewControllable, animated: Bool) {
44+
if let nav = self.uiController as? UINavigationController {
45+
nav.present(viewControllable.uiController, animated: animated)
46+
} else {
47+
self.uiController.navigationController?.present(viewControllable.uiController, animated: animated)
48+
}
49+
}
50+
51+
func dismiss() {
52+
if let presented = self.uiController.presentedViewController {
53+
presented.dismiss(animated: true)
54+
} else {
55+
self.uiController.dismiss(animated: true)
56+
}
57+
}
58+
59+
func presentBottomSheet(_ viewControllable: ViewControllable, animated: Bool) {
60+
let navigation = NavigationViewControllable(rootViewControllable: viewControllable)
61+
if let sheet = navigation.uiController.sheetPresentationController {
62+
sheet.prefersGrabberVisible = false
63+
sheet.preferredCornerRadius = 12
64+
sheet.detents = [
65+
.small()
66+
]
67+
}
68+
69+
if let nav = self.uiController as? UINavigationController {
70+
nav.present(navigation.uiController, animated: animated)
71+
} else {
72+
self.uiController.navigationController?.present(navigation.uiController, animated: animated)
73+
}
74+
}
75+
}
76+
77+
extension UISheetPresentationController.Detent {
78+
static func small(
79+
identifier: UISheetPresentationController.Detent.Identifier? = nil,
80+
resolvedValue: CGFloat = 300
81+
) -> UISheetPresentationController.Detent {
82+
return .custom { context in
83+
resolvedValue
84+
}
85+
}
86+
87+
// static let small = UISheetPresentationController.Detent.Identifier("small")
4288
}

Projects/Core/Src/Util/AppData.swift

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
//
2+
// AppData.swift
3+
// Core
4+
//
5+
// Created by Kanghos on 2024/03/02.
6+
//
7+
8+
import Foundation
9+
10+
public struct AppData {
11+
private enum Key: String {
12+
case accessToken
13+
case phoneNumber
14+
case accessTokenExpiredIn
15+
}
16+
public struct Auth {
17+
@Storage<String>(key: Key.accessToken.rawValue, defaultValue: "")
18+
public static var accessToken
19+
20+
@Storage<Int>(key: Key.accessTokenExpiredIn.rawValue, defaultValue: 0)
21+
public static var accessTokenExpiredIn
22+
23+
public static var needAuth: Bool {
24+
accessToken.isEmpty
25+
}
26+
}
27+
28+
public struct User {
29+
@Storage<String>(key: Key.phoneNumber.rawValue, defaultValue: "")
30+
public static var phoneNumber
31+
}
32+
}

Projects/Core/Src/Util/DateFormatter+Util.swift

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,51 @@ extension DateFormatter {
2525
// formatter.locale = Locale(identifier: "ko-KR")
2626
return formatter
2727
}
28+
29+
static var normalDateFormatter: DateFormatter {
30+
let formatter = DateFormatter()
31+
formatter.dateFormat = "yyyy.MM.dd"
32+
formatter.locale = Locale(identifier: "ko-KR")
33+
34+
return formatter
35+
}
2836
}
2937

3038
public extension String {
3139
func toDate() -> Date {
32-
DateFormatter.unixDateFormatter.date(from: self) ?? Date()
40+
DateFormatter.normalDateFormatter.date(from: self) ?? Date()
3341
}
3442
}
3543

3644
public extension Date {
3745
func toTimeString() -> String {
3846
DateFormatter.timeFormatter.string(from: self)
3947
}
48+
func toDateString() -> String {
49+
DateFormatter.unixDateFormatter.string(from: self)
50+
}
51+
func toYMDDotDateString() -> String {
52+
DateFormatter.normalDateFormatter.string(from: self)
53+
}
54+
55+
// From GPT
56+
static func currentAdultDateOrNil() -> Date? {
57+
// 성년이 되는 나이
58+
let adulthoodAge = 21
59+
60+
// 현재 달력
61+
var calendar = Calendar.current
62+
63+
// 지역을 한국으로 설정 (옵션)
64+
calendar.locale = Locale(identifier: "ko_KR")
65+
66+
// 날짜 구성 요소를 추출
67+
var dateComponents = calendar.dateComponents([.year, .month, .day], from: Date())
68+
69+
// 성년 나이를 더함
70+
dateComponents.year = (dateComponents.year ?? 0) - adulthoodAge
71+
72+
// 새로운 날짜를 생성하여 반환
73+
return calendar.date(from: dateComponents)
74+
}
4075
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//
2+
// JSONStorage.swift
3+
// Core
4+
//
5+
// Created by Kanghos on 5/14/24.
6+
//
7+
8+
import Foundation
9+
10+
extension UserDefaults {
11+
12+
public func setCodableObject<Object>(
13+
_ object: Object, forKey: String
14+
) throws where Object: Encodable {
15+
16+
let data = try JSONEncoder().encode(object)
17+
self.set(data, forKey: forKey)
18+
}
19+
20+
public func getCodableObject<Object>(
21+
forKey: String,
22+
as type: Object.Type
23+
) throws -> Object where Object: Decodable {
24+
25+
guard let data = self.data(forKey: forKey) else {
26+
throw NSError(domain: "UserDefaults", code: 0, userInfo: nil)
27+
}
28+
return try JSONDecoder().decode(type, from: data)
29+
}
30+
}
31+
32+
@propertyWrapper
33+
public struct CodableStorage<T: Codable> {
34+
private let key: String
35+
private let defaultValue: T?
36+
37+
public init(key: String, defaultValue: T? = nil) {
38+
self.key = key
39+
self.defaultValue = defaultValue
40+
}
41+
42+
public var wrappedValue: T? {
43+
get {
44+
guard let object = try? UserDefaults.standard.getCodableObject(forKey: key, as: T.self) else {
45+
return defaultValue
46+
}
47+
return object
48+
}
49+
set {
50+
if newValue == nil {
51+
UserDefaults.standard.removeObject(forKey: key)
52+
}
53+
try? UserDefaults.standard.setCodableObject(newValue, forKey: key)
54+
}
55+
}
56+
}
57+

Projects/Core/Src/Util/Storage.swift

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
//
2+
// Storage.swift
3+
// Core
4+
//
5+
// Created by Kanghos on 2024/03/02.
6+
//
7+
8+
import Foundation
9+
10+
@propertyWrapper
11+
public struct Storage<T> {
12+
private let key: String
13+
private let defaultValue: T
14+
15+
public init(key: String, defaultValue: T) {
16+
self.key = key
17+
self.defaultValue = defaultValue
18+
}
19+
20+
public var wrappedValue: T {
21+
get {
22+
return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
23+
}
24+
set {
25+
UserDefaults.standard.setValue(newValue, forKey: key)
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)