Skip to content

Commit

Permalink
Feature/auth (#81)
Browse files Browse the repository at this point in the history
* 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]>
  • Loading branch information
ibcylon and Minny27 authored Jun 13, 2024
1 parent e20fddd commit 856901b
Show file tree
Hide file tree
Showing 209 changed files with 11,130 additions and 1,031 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -80,4 +80,4 @@ fastlane/*.env
# App Packaging
*.ipa
*.dSYM.zip
*.dSYM
*.dSYM
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,36 @@ public let infoPlistExtension: [String: InfoPlist.Value] = [
"CFBundleVersion": "1",
"UILaunchStoryboardName": "LaunchScreen",
"CFBundleName": "THT",
"UIApplicationSceneManifest": [
"UIApplicationSupportsMultipleScenes": false,
"UISceneConfigurations": [
"UIWindowSceneSessionRoleApplication": [
[
"UISceneConfigurationName": "Default Configuration",
"UISceneDelegateClassName": "$(PRODUCT_MODULE_NAME).SceneDelegate"
],
]
]
],

// MARK: Privacy

"UIAppFonts": [
"Item 0": "Pretendard-Medium.otf",
"Item 1": "Pretendard-Regular.otf",
"Item 2": "Pretendard-SemiBold.otf",
"Item 3": "Pretendard-Bold.otf",
"Item 4": "Pretendard-ExtraBold.otf"
],
"UIUserInterfaceStyle": "Dark"
]

public func infoPlistExtension(name: String) -> [String: InfoPlist.Value] {
[
"CFBundleShortVersionString": "1.0",
"CFBundleVersion": "1",
"UILaunchStoryboardName": "LaunchScreen",
"CFBundleName": "\(name)",
"UIApplicationSceneManifest": [
"UIApplicationSupportsMultipleScenes": false,
"UISceneConfigurations": [
Expand All @@ -23,8 +53,15 @@ public let infoPlistExtension: [String: InfoPlist.Value] = [
]
]
],
"App Transport Security Settings": ["Allow Arbitrary Loads": true],
"Privacy - Photo Library Additions Usage Description": "프로필에 사용됨",
"NSAppTransportSecurity": ["NSAllowsArbitraryLoads": true],

// MARK: Privacy
"NSContactsUsageDescription": "연락처 사용",
"NSLocationWhenInUseUsageDescription": "위치 정보 사용",

// MARK: 수출 규청 알고리즘 통과
"ITSAppUsesNonExemptEncryption": false,

"UIAppFonts": [
"Item 0": "Pretendard-Medium.otf",
"Item 1": "Pretendard-Regular.otf",
Expand All @@ -33,35 +70,5 @@ public let infoPlistExtension: [String: InfoPlist.Value] = [
"Item 4": "Pretendard-ExtraBold.otf"
],
"UIUserInterfaceStyle": "Dark"
]

public func infoPlistExtension(name: String) -> [String: InfoPlist.Value] {
[
"CFBundleShortVersionString": "1.0",
"CFBundleVersion": "1",
"UILaunchStoryboardName": "LaunchScreen",
"CFBundleName": "\(name)",
"UIApplicationSceneManifest": [
"UIApplicationSupportsMultipleScenes": false,
"UISceneConfigurations": [
"UIWindowSceneSessionRoleApplication": [
[
"UISceneConfigurationName": "Default Configuration",
"UISceneDelegateClassName": "$(PRODUCT_MODULE_NAME).SceneDelegate"
],
]
]
],
"App Transport Security Settings": ["Allow Arbitrary Loads": true],
"Privacy - Photo Library Additions Usage Description": "프로필에 사용됨",
"UIAppFonts": [
"Item 0": "Pretendard-Medium.otf",
"Item 1": "Pretendard-Regular.otf",
"Item 2": "Pretendard-SemiBold.otf",
"Item 3": "Pretendard-Bold.otf",
"Item 4": "Pretendard-ExtraBold.otf"
],
"UIUserInterfaceStyle": "Dark",
"ITSAppUsesNonExemptEncryption": false // 수출 규정 누락 문제
]
}
25 changes: 21 additions & 4 deletions Projects/App/Src/SceneDelegate+Register.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,34 @@ import Data

import Feature
import Networks
import FallingInterface
import LikeInterface
import ChatInterface
import MyPageInterface

extension AppDelegate {
var container: DIContainer {
DIContainer.shared
}

func registerDependencies() {
let tokenStore = UserDefaultTokenStore()
let tokenProvider = DefaultTokenProvider()

container.register(
interface: UserInfoUseCaseInterface.self,
implement: { UserInfoUseCase(repository: UserDefaultUserInfoRepository()) })

container.register(
interface: AuthUseCaseInterface.self,
implement: { AuthUseCase(authRepository: AuthRepository(tokenStore: tokenStore, tokenProvider: tokenProvider),
tokenStore: tokenStore) })
container.register(
interface: SignUpUseCaseInterface.self,
implement: { SignUpUseCase(
repository: SignUpRepository(),
locationService: LocationService(),
kakaoAPIService: KakaoAPIService(),
contactService: ContactService(),
tokenStore: tokenStore)
})

container.register(
interface: FallingUseCaseInterface.self,
implement: {
Expand Down
8 changes: 2 additions & 6 deletions Projects/Core/Src/BaseCoordinator/LaunchCoordinator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import UIKit

public protocol LaunchCoordinating {
public protocol LaunchCoordinating: Coordinator {
func launch(window: UIWindow)
}

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

TFLogger.domain.debug("AppCoordinator 1초 async")
DispatchQueue.main.asyncAfter(deadline: .now() + 1) {
self.start()
}
self.start()
}
}

46 changes: 46 additions & 0 deletions Projects/Core/Src/BaseType/ViewControllable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,50 @@ public extension ViewControllable {
self.uiController.navigationController?.popViewController(animated: animated)
}
}

func present(_ viewControllable: ViewControllable, animated: Bool) {
if let nav = self.uiController as? UINavigationController {
nav.present(viewControllable.uiController, animated: animated)
} else {
self.uiController.navigationController?.present(viewControllable.uiController, animated: animated)
}
}

func dismiss() {
if let presented = self.uiController.presentedViewController {
presented.dismiss(animated: true)
} else {
self.uiController.dismiss(animated: true)
}
}

func presentBottomSheet(_ viewControllable: ViewControllable, animated: Bool) {
let navigation = NavigationViewControllable(rootViewControllable: viewControllable)
if let sheet = navigation.uiController.sheetPresentationController {
sheet.prefersGrabberVisible = false
sheet.preferredCornerRadius = 12
sheet.detents = [
.small()
]
}

if let nav = self.uiController as? UINavigationController {
nav.present(navigation.uiController, animated: animated)
} else {
self.uiController.navigationController?.present(navigation.uiController, animated: animated)
}
}
}

extension UISheetPresentationController.Detent {
static func small(
identifier: UISheetPresentationController.Detent.Identifier? = nil,
resolvedValue: CGFloat = 300
) -> UISheetPresentationController.Detent {
return .custom { context in
resolvedValue
}
}

// static let small = UISheetPresentationController.Detent.Identifier("small")
}
32 changes: 32 additions & 0 deletions Projects/Core/Src/Util/AppData.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
//
// AppData.swift
// Core
//
// Created by Kanghos on 2024/03/02.
//

import Foundation

public struct AppData {
private enum Key: String {
case accessToken
case phoneNumber
case accessTokenExpiredIn
}
public struct Auth {
@Storage<String>(key: Key.accessToken.rawValue, defaultValue: "")
public static var accessToken

@Storage<Int>(key: Key.accessTokenExpiredIn.rawValue, defaultValue: 0)
public static var accessTokenExpiredIn

public static var needAuth: Bool {
accessToken.isEmpty
}
}

public struct User {
@Storage<String>(key: Key.phoneNumber.rawValue, defaultValue: "")
public static var phoneNumber
}
}
37 changes: 36 additions & 1 deletion Projects/Core/Src/Util/DateFormatter+Util.swift
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,51 @@ extension DateFormatter {
// formatter.locale = Locale(identifier: "ko-KR")
return formatter
}

static var normalDateFormatter: DateFormatter {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy.MM.dd"
formatter.locale = Locale(identifier: "ko-KR")

return formatter
}
}

public extension String {
func toDate() -> Date {
DateFormatter.unixDateFormatter.date(from: self) ?? Date()
DateFormatter.normalDateFormatter.date(from: self) ?? Date()
}
}

public extension Date {
func toTimeString() -> String {
DateFormatter.timeFormatter.string(from: self)
}
func toDateString() -> String {
DateFormatter.unixDateFormatter.string(from: self)
}
func toYMDDotDateString() -> String {
DateFormatter.normalDateFormatter.string(from: self)
}

// From GPT
static func currentAdultDateOrNil() -> Date? {
// 성년이 되는 나이
let adulthoodAge = 21

// 현재 달력
var calendar = Calendar.current

// 지역을 한국으로 설정 (옵션)
calendar.locale = Locale(identifier: "ko_KR")

// 날짜 구성 요소를 추출
var dateComponents = calendar.dateComponents([.year, .month, .day], from: Date())

// 성년 나이를 더함
dateComponents.year = (dateComponents.year ?? 0) - adulthoodAge

// 새로운 날짜를 생성하여 반환
return calendar.date(from: dateComponents)
}
}
57 changes: 57 additions & 0 deletions Projects/Core/Src/Util/JSONStorage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//
// JSONStorage.swift
// Core
//
// Created by Kanghos on 5/14/24.
//

import Foundation

extension UserDefaults {

public func setCodableObject<Object>(
_ object: Object, forKey: String
) throws where Object: Encodable {

let data = try JSONEncoder().encode(object)
self.set(data, forKey: forKey)
}

public func getCodableObject<Object>(
forKey: String,
as type: Object.Type
) throws -> Object where Object: Decodable {

guard let data = self.data(forKey: forKey) else {
throw NSError(domain: "UserDefaults", code: 0, userInfo: nil)
}
return try JSONDecoder().decode(type, from: data)
}
}

@propertyWrapper
public struct CodableStorage<T: Codable> {
private let key: String
private let defaultValue: T?

public init(key: String, defaultValue: T? = nil) {
self.key = key
self.defaultValue = defaultValue
}

public var wrappedValue: T? {
get {
guard let object = try? UserDefaults.standard.getCodableObject(forKey: key, as: T.self) else {
return defaultValue
}
return object
}
set {
if newValue == nil {
UserDefaults.standard.removeObject(forKey: key)
}
try? UserDefaults.standard.setCodableObject(newValue, forKey: key)
}
}
}

28 changes: 28 additions & 0 deletions Projects/Core/Src/Util/Storage.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// Storage.swift
// Core
//
// Created by Kanghos on 2024/03/02.
//

import Foundation

@propertyWrapper
public struct Storage<T> {
private let key: String
private let defaultValue: T

public init(key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}

public var wrappedValue: T {
get {
return UserDefaults.standard.object(forKey: key) as? T ?? defaultValue
}
set {
UserDefaults.standard.setValue(newValue, forKey: key)
}
}
}
Loading

0 comments on commit 856901b

Please sign in to comment.