Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

merge :: Base 세팅 #41

Merged
merged 26 commits into from
Oct 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,15 @@ public extension TargetDependency.Project.Features {
}

public extension TargetDependency.Project.Module {
static let KeychainModule = TargetDependency.module(name: "KeychainModule")
static let ErrorModule = TargetDependency.module(name: "ErrorModule")
static let FeatureThirdPartyLib = TargetDependency.module(name: "FeatureThirdPartyLib")
static let ThirdPartyLib = TargetDependency.module(name: "ThirdPartyLib")
static let Utility = TargetDependency.module(name: "Utility")
}

public extension TargetDependency.Project.Service {
static let DataMappingModule = TargetDependency.service(name: "DataMappingModule")
static let APIKit = TargetDependency.service(name: "APIKit")
static let Data = TargetDependency.service(name: "DataModule")
static let Domain = TargetDependency.service(name: "DomainModule")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ public extension TargetDependency.SPM {
static let Quick = TargetDependency.external(name: "Quick")
static let Nimble = TargetDependency.external(name: "Nimble")
static let Needle = TargetDependency.external(name: "NeedleFoundation")
static let Moya = TargetDependency.external(name: "Moya")
static let CombineMoya = TargetDependency.external(name: "CombineMoya")
}

public extension Package {
Expand Down

This file was deleted.

This file was deleted.

This file was deleted.

This file was deleted.

33 changes: 33 additions & 0 deletions Projects/Features/BaseFeature/Sources/BaseViewModel.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import Combine
import ErrorModule

open class BaseViewModel: ObservableObject {
@Published public var isErrorOcuured = false
@Published public var isLoading = false
@Published public var errorMessage = ""

public var bag = Set<AnyCancellable>()

public init() {}

public func addCancellable<T>(
_ publisher: AnyPublisher<T, Error>,
onReceiveValue: @escaping (T) -> Void,
onReceiveError: ((DmsError) -> Void)? = nil
) {
isLoading = true
publisher
.sink(receiveCompletion: { [weak self] completion in
if case let .failure(error) = completion {
if let onReceiveError {
onReceiveError(error.asDMSError)
}

self?.errorMessage = error.localizedDescription
self?.isErrorOcuured = true
}
self?.isLoading = false
}, receiveValue: onReceiveValue)
.store(in: &bag)
}
}
1 change: 0 additions & 1 deletion Projects/Features/BaseFeature/Sources/Feature.swift

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
7 changes: 7 additions & 0 deletions Projects/Modules/ErrorModule/Project.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import ProjectDescription
import ProjectDescriptionHelpers

let project = Project.makeModule(
name: "ErrorModule",
product: .staticFramework
)
24 changes: 24 additions & 0 deletions Projects/Modules/ErrorModule/Sources/DmsError.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Foundation

public enum DmsError: Error {
case unknown
case custom(message: String = "알 수 없는 오류가 발생하였습니다", code: Int = 500)
}

extension DmsError: LocalizedError {
public var errorDescription: String? {
switch self {
case .unknown:
return "알 수 없는 오류가 발생하였습니다"

case let .custom(message, _):
return message
}
}
}

public extension Error {
var asDMSError: DmsError {
self as? DmsError ?? .unknown
}
}
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>
7 changes: 7 additions & 0 deletions Projects/Modules/KeychainModule/Project.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import ProjectDescription
import ProjectDescriptionHelpers

let project = Project.makeModule(
name: "KeychainModule",
product: .staticFramework
)
11 changes: 11 additions & 0 deletions Projects/Modules/KeychainModule/Sources/Keychain.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
public enum KeychainType: String {
case accessToken = "ACCESS-TOKEN"
case refreshToken = "REFRESH-TOKEN"
case expiredAt = "EXPIRED-AT"
}

public protocol Keychain {
func save(type: KeychainType, value: String)
func load(type: KeychainType) -> String
func delete(type: KeychainType)
}
17 changes: 17 additions & 0 deletions Projects/Modules/KeychainModule/Sources/KeychainFake.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import Foundation

final class KeychainFake: Keychain {
var store: [String: String] = [:]

func save(type: KeychainType, value: String) {
store[type.rawValue] = value
}

func load(type: KeychainType) -> String {
store[type.rawValue] ?? ""
}

func delete(type: KeychainType) {
store[type.rawValue] = nil
}
}
44 changes: 44 additions & 0 deletions Projects/Modules/KeychainModule/Sources/KeychainImpl.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import Foundation

public struct KeychainImpl: Keychain {
public init() {}

private let service: String = Bundle.main.bundleIdentifier ?? ""

public func save(type: KeychainType, value: String) {
let query: NSDictionary = [
kSecClass: kSecClassGenericPassword,
kSecAttrService: service,
kSecAttrAccount: type.rawValue,
kSecValueData: value.data(using: .utf8, allowLossyConversion: false) ?? .init()
]
SecItemDelete(query)
SecItemAdd(query, nil)
}

public func load(type: KeychainType) -> String {
let query: NSDictionary = [
kSecClass: kSecClassGenericPassword,
kSecAttrService: service,
kSecAttrAccount: type.rawValue,
kSecReturnData: kCFBooleanTrue!,
kSecMatchLimit: kSecMatchLimitOne
]
var dataTypeRef: AnyObject?
let status = withUnsafeMutablePointer(to: &dataTypeRef) { SecItemCopyMatching(query, UnsafeMutablePointer($0)) }
if status == errSecSuccess {
guard let data = dataTypeRef as? Data else { return "" }
return String(data: data, encoding: .utf8) ?? ""
}
return ""
}

public func delete(type: KeychainType) {
let query: NSDictionary = [
kSecClass: kSecClassGenericPassword,
kSecAttrService: service,
kSecAttrAccount: type.rawValue
]
SecItemDelete(query)
}
}
Empty file.
17 changes: 17 additions & 0 deletions Projects/Modules/KeychainModule/Tests/TargetTest.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import XCTest

class TargetTests: XCTestCase {

override func setUpWithError() throws {
// Put setup code here. This method is called before the invocation of each test method in the class.
}

override func tearDownWithError() throws {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}

func testExample() throws {
XCTAssertEqual("A", "A")
}

}
3 changes: 2 additions & 1 deletion Projects/Modules/Utility/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ let project = Project.makeModule(
name: "Utility",
product: .staticFramework,
dependencies: [
.Project.Module.ThirdPartyLib
.Project.Module.ThirdPartyLib,
.Project.Module.ErrorModule
]
)
19 changes: 19 additions & 0 deletions Projects/Modules/Utility/Sources/DateUtil.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import Foundation

public extension String {
func toDMSDate() -> Date {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
formatter.timeZone = TimeZone(identifier: "UTC")
return formatter.date(from: self) ?? .init()
}
}

public extension Date {
func toDMSDateString() -> String {
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss"
formatter.timeZone = .init(identifier: "UTC")
return formatter.string(from: self)
}
}
1 change: 0 additions & 1 deletion Projects/Modules/Utility/Sources/Utility.swift

This file was deleted.

8 changes: 7 additions & 1 deletion Projects/Services/APIKit/Project.swift
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,12 @@ let project = Project.makeModule(
name: "APIKit",
product: .staticFramework,
dependencies: [
.Project.Module.ThirdPartyLib
.Project.Module.ThirdPartyLib,
.Project.Module.KeychainModule,
.Project.Module.ErrorModule,
.Project.Service.DataMappingModule,

.SPM.Moya,
.SPM.CombineMoya
]
)
1 change: 0 additions & 1 deletion Projects/Services/APIKit/Sources/API.swift

This file was deleted.

38 changes: 38 additions & 0 deletions Projects/Services/APIKit/Sources/DmsAPI.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import Foundation
import Moya
import ErrorModule

public protocol DmsAPI: TargetType, JwtAuthorizable {
var domain: DmsDomain { get }
var urlPath: String { get }
var errorMap: [Int: DmsError] { get }
}

public extension DmsAPI {
var baseURL: URL {
URL(string: "https://google.com")! // TODO: 서버의 배포가 완료되기 전에는 구글에게 몰래 요청을 날립니다
}

var path: String {
domain.asURLString + urlPath
}

var headers: [String: String]? {
["Content-Type": "application/json"]
}
}

public enum DmsDomain: String {
case auth
case users
case losts
case notices
case meal
case images
}

extension DmsDomain {
var asURLString: String {
"/\(self.rawValue)"
}
}
Loading