diff --git a/DependencyGraph/mohanyang_dev_graph.png b/DependencyGraph/mohanyang_dev_graph.png index 6925cd5..a6a9607 100644 Binary files a/DependencyGraph/mohanyang_dev_graph.png and b/DependencyGraph/mohanyang_dev_graph.png differ diff --git a/DependencyGraph/mohanyang_prod_graph.png b/DependencyGraph/mohanyang_prod_graph.png index f11940b..ba40e0a 100644 Binary files a/DependencyGraph/mohanyang_prod_graph.png and b/DependencyGraph/mohanyang_prod_graph.png differ diff --git a/Makefile b/Makefile index 01c3f48..ba34001 100644 --- a/Makefile +++ b/Makefile @@ -37,7 +37,7 @@ dev: .PHONY: prod prod: - make generate config=prod + make generate config=prod target=Mohanyang ### Script ### diff --git a/Plugins/DependencyPlugin/ProjectDescriptionHelpers/Module/Domain.swift b/Plugins/DependencyPlugin/ProjectDescriptionHelpers/Module/Domain.swift index 1decdde..f341b7c 100644 --- a/Plugins/DependencyPlugin/ProjectDescriptionHelpers/Module/Domain.swift +++ b/Plugins/DependencyPlugin/ProjectDescriptionHelpers/Module/Domain.swift @@ -10,4 +10,5 @@ import Foundation @_spi(Domain) public enum Domain: String, Modulable { case AppService + case PushService } diff --git a/Plugins/DependencyPlugin/ProjectDescriptionHelpers/Module/Feature.swift b/Plugins/DependencyPlugin/ProjectDescriptionHelpers/Module/Feature.swift index 57c5720..fc7a525 100644 --- a/Plugins/DependencyPlugin/ProjectDescriptionHelpers/Module/Feature.swift +++ b/Plugins/DependencyPlugin/ProjectDescriptionHelpers/Module/Feature.swift @@ -9,5 +9,6 @@ import Foundation @_spi(Feature) public enum Feature: String, Modulable { - case AppFeature + case HomeFeature + case OnboardingFeature } diff --git a/Projects/App/Sources/AppDelegate.swift b/Projects/App/Sources/AppDelegate.swift index 1a4186d..a93c652 100644 --- a/Projects/App/Sources/AppDelegate.swift +++ b/Projects/App/Sources/AppDelegate.swift @@ -9,56 +9,56 @@ import SwiftUI import UserNotifications -import AppFeature +import Feature import DesignSystem -//import FirebaseMessaging +import ComposableArchitecture -//final class AppDelegate: UIResponder, UIApplicationDelegate { -// let store = Store( -// initialState: AppCore.State() -// ) { -// AppCore() -// } -// -// func application( -// _ application: UIApplication, -// didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? -// ) -> Bool { -// self.store.send(.appDelegate(.didFinishLaunching)) -// return true -// } -// -// func application( -// _ application: UIApplication, -// didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data -// ) { -// self.store.send(.appDelegate(.didRegisterForRemoteNotifications(.success(deviceToken)))) -// } -// -// func application( -// _ application: UIApplication, -// didFailToRegisterForRemoteNotificationsWithError error: Error -// ) { -// self.store.send(.appDelegate(.didRegisterForRemoteNotifications(.failure(error)))) -// } -//} -// -//@main -//struct KimcaddieOwnerApp: App { -// @UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate -// @Environment(\.scenePhase) private var scenePhase -// -// init() { -// DesignSystemFontFamily.registerAllCustomFonts() -// } -// -// var body: some Scene { -// WindowGroup { -// AppView(store: self.appDelegate.store) -// } -// .onChange(of: self.scenePhase) { value in -// self.appDelegate.store.send(.didChangeScenePhase(value)) -// } -// } -//} +final class AppDelegate: UIResponder, UIApplicationDelegate { + let store = Store( + initialState: AppCore.State() + ) { + AppCore() + } + + func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? + ) -> Bool { + self.store.send(.appDelegate(.didFinishLaunching)) + return true + } + + func application( + _ application: UIApplication, + didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data + ) { + self.store.send(.appDelegate(.didRegisterForRemoteNotifications(.success(deviceToken)))) + } + + func application( + _ application: UIApplication, + didFailToRegisterForRemoteNotificationsWithError error: Error + ) { + self.store.send(.appDelegate(.didRegisterForRemoteNotifications(.failure(error)))) + } +} + +@main +struct MohanyangApp: App { + @UIApplicationDelegateAdaptor(AppDelegate.self) private var appDelegate + @Environment(\.scenePhase) private var scenePhase + + init() { + DesignSystemFontFamily.registerAllCustomFonts() + } + + var body: some Scene { + WindowGroup { + AppView(store: self.appDelegate.store) + } + .onChange(of: self.scenePhase) { oldValue, newValue in + self.appDelegate.store.send(.didChangeScenePhase(newValue)) + } + } +} diff --git a/Projects/Core/Core/Project.swift b/Projects/Core/Core/Project.swift index b97882b..6317c5a 100644 --- a/Projects/Core/Core/Project.swift +++ b/Projects/Core/Core/Project.swift @@ -7,5 +7,5 @@ import DependencyPlugin let project: Project = .makeRootProject( rootModule: Core.self, scripts: [], - product: .framework + product: .staticLibrary ) diff --git a/Projects/Domain/Domain/Project.swift b/Projects/Domain/Domain/Project.swift index e5275e6..11f801e 100644 --- a/Projects/Domain/Domain/Project.swift +++ b/Projects/Domain/Domain/Project.swift @@ -7,5 +7,5 @@ import DependencyPlugin let project: Project = .makeRootProject( rootModule: Domain.self, scripts: [], - product: .framework + product: .staticLibrary ) diff --git a/Projects/Domain/PushService/Example/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json b/Projects/Domain/PushService/Example/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..f1cb98f --- /dev/null +++ b/Projects/Domain/PushService/Example/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images" : [ + { + "filename" : "ICON_DEMO.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/Domain/PushService/Example/Resources/Assets.xcassets/contents.json b/Projects/Domain/PushService/Example/Resources/Assets.xcassets/contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Projects/Domain/PushService/Example/Resources/Assets.xcassets/contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/Domain/PushService/Example/Resources/Font/Pretendard-Bold.otf b/Projects/Domain/PushService/Example/Resources/Font/Pretendard-Bold.otf new file mode 100644 index 0000000..a52ef39 Binary files /dev/null and b/Projects/Domain/PushService/Example/Resources/Font/Pretendard-Bold.otf differ diff --git a/Projects/Domain/PushService/Example/Resources/Font/Pretendard-Medium.otf b/Projects/Domain/PushService/Example/Resources/Font/Pretendard-Medium.otf new file mode 100644 index 0000000..a2dc009 Binary files /dev/null and b/Projects/Domain/PushService/Example/Resources/Font/Pretendard-Medium.otf differ diff --git a/Projects/Domain/PushService/Example/Resources/Font/Pretendard-Regular.otf b/Projects/Domain/PushService/Example/Resources/Font/Pretendard-Regular.otf new file mode 100644 index 0000000..c940185 Binary files /dev/null and b/Projects/Domain/PushService/Example/Resources/Font/Pretendard-Regular.otf differ diff --git a/Projects/Domain/PushService/Example/Resources/Font/Pretendard-SemiBold.otf b/Projects/Domain/PushService/Example/Resources/Font/Pretendard-SemiBold.otf new file mode 100644 index 0000000..c375b54 Binary files /dev/null and b/Projects/Domain/PushService/Example/Resources/Font/Pretendard-SemiBold.otf differ diff --git a/Projects/Domain/PushService/Example/Resources/LaunchScreen.storyboard b/Projects/Domain/PushService/Example/Resources/LaunchScreen.storyboard new file mode 100644 index 0000000..8f1bfc8 --- /dev/null +++ b/Projects/Domain/PushService/Example/Resources/LaunchScreen.storyboard @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Projects/Domain/PushService/Example/Sources/AppDelegate.swift b/Projects/Domain/PushService/Example/Sources/AppDelegate.swift new file mode 100644 index 0000000..0d538be --- /dev/null +++ b/Projects/Domain/PushService/Example/Sources/AppDelegate.swift @@ -0,0 +1,11 @@ +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + return true + } +} diff --git a/Projects/Domain/PushService/Interface/Model/PushNotificationContent.swift b/Projects/Domain/PushService/Interface/Model/PushNotificationContent.swift new file mode 100644 index 0000000..dea9329 --- /dev/null +++ b/Projects/Domain/PushService/Interface/Model/PushNotificationContent.swift @@ -0,0 +1,13 @@ +// +// PushNotificationContent.swift +// PushService +// +// Created by devMinseok on 7/22/24. +// Copyright © 2024 PomoNyang. All rights reserved. +// + +import Foundation + +public enum PushNotificationContent: Decodable { + case test +} diff --git a/Projects/Feature/AppFeature/Interface/AppFeatureInterface.swift b/Projects/Domain/PushService/Interface/PushServiceInterface.swift similarity index 51% rename from Projects/Feature/AppFeature/Interface/AppFeatureInterface.swift rename to Projects/Domain/PushService/Interface/PushServiceInterface.swift index d8776f5..95ff123 100644 --- a/Projects/Feature/AppFeature/Interface/AppFeatureInterface.swift +++ b/Projects/Domain/PushService/Interface/PushServiceInterface.swift @@ -1,5 +1,5 @@ import Foundation -public struct AppFeatureInterface { +public struct PushServiceInterface { public init() {} } diff --git a/Projects/Domain/PushService/Project.swift b/Projects/Domain/PushService/Project.swift new file mode 100644 index 0000000..1e8d980 --- /dev/null +++ b/Projects/Domain/PushService/Project.swift @@ -0,0 +1,23 @@ +import ProjectDescription +import ProjectDescriptionHelpers + +@_spi(Domain) +@_spi(Core) +import DependencyPlugin + +let project: Project = .makeTMABasedProject( + module: Domain.PushService, + scripts: [], + targets: [ + .sources, + .interface, + .tests, + .testing, + .example + ], + dependencies: [ + .interface: [ + .dependency(rootModule: Core.self) + ] + ] +) diff --git a/Projects/Feature/AppFeature/Preview/Resources/dummy.txt b/Projects/Domain/PushService/Resources/dummy.txt similarity index 100% rename from Projects/Feature/AppFeature/Preview/Resources/dummy.txt rename to Projects/Domain/PushService/Resources/dummy.txt diff --git a/Projects/Feature/AppFeature/Preview/Sources/AppFeature.swift b/Projects/Domain/PushService/Sources/PushService.swift similarity index 58% rename from Projects/Feature/AppFeature/Preview/Sources/AppFeature.swift rename to Projects/Domain/PushService/Sources/PushService.swift index 6d6f60a..b9bd75e 100644 --- a/Projects/Feature/AppFeature/Preview/Sources/AppFeature.swift +++ b/Projects/Domain/PushService/Sources/PushService.swift @@ -1,5 +1,5 @@ import Foundation -public struct AppFeature { +public struct PushService { public init() {} } diff --git a/Projects/Feature/AppFeature/Testing/AppFeatureTesting.swift b/Projects/Domain/PushService/Testing/PushServiceTesting.swift similarity index 53% rename from Projects/Feature/AppFeature/Testing/AppFeatureTesting.swift rename to Projects/Domain/PushService/Testing/PushServiceTesting.swift index 82a04dd..988726a 100644 --- a/Projects/Feature/AppFeature/Testing/AppFeatureTesting.swift +++ b/Projects/Domain/PushService/Testing/PushServiceTesting.swift @@ -1,5 +1,5 @@ import Foundation -public struct AppFeatureTesting { +public struct PushServiceTesting { public init() {} } diff --git a/Projects/Feature/AppFeature/Tests/AppFeatureTests.swift b/Projects/Domain/PushService/Tests/PushServiceTests.swift similarity index 54% rename from Projects/Feature/AppFeature/Tests/AppFeatureTests.swift rename to Projects/Domain/PushService/Tests/PushServiceTests.swift index 8c7ac98..b127c16 100644 --- a/Projects/Feature/AppFeature/Tests/AppFeatureTests.swift +++ b/Projects/Domain/PushService/Tests/PushServiceTests.swift @@ -1,5 +1,5 @@ import Foundation -public struct AppFeatureTests { +public struct PushServiceTests { public init() {} } diff --git a/Projects/Feature/Feature/Project.swift b/Projects/Feature/Feature/Project.swift index 8267176..9e8761e 100644 --- a/Projects/Feature/Feature/Project.swift +++ b/Projects/Feature/Feature/Project.swift @@ -7,5 +7,5 @@ import DependencyPlugin let project: Project = .makeRootProject( rootModule: Feature.self, scripts: [], - product: .framework + product: .staticLibrary ) diff --git a/Projects/Feature/Feature/Sources/AppCore.swift b/Projects/Feature/Feature/Sources/AppCore.swift new file mode 100644 index 0000000..7b5182b --- /dev/null +++ b/Projects/Feature/Feature/Sources/AppCore.swift @@ -0,0 +1,93 @@ +// +// AppCore.swift +// AppServiceInterface +// +// Created by devMinseok on 7/22/24. +// Copyright © 2024 PomoNyang. All rights reserved. +// + +import SwiftUI + +import HomeFeature +import HomeFeatureInterface +import OnboardingFeature +import OnboardingFeatureInterface +import PushServiceInterface + +import ComposableArchitecture + +@Reducer +public struct AppCore { + @ObservableState + public struct State: Equatable { + public var appDelegate: AppDelegateCore.State = .init() + var home: HomeCore.State? + var onboarding: OnboardingCore.State? + + public init() {} + } + + public enum Action { + case onAppear + case appDelegate(AppDelegateCore.Action) + case didChangeScenePhase(ScenePhase) + case home(HomeCore.Action) + case onboarding(OnboardingCore.Action) + } + + public init() {} + + public var body: some ReducerOf { + Scope(state: \.appDelegate, action: \.appDelegate) { + AppDelegateCore() + } + Reduce(self.core) + .ifLet(\.home, action: \.home) { + HomeCore() + } + .ifLet(\.onboarding, action: \.onboarding) { + OnboardingCore() + } + } + + private func core(_ state: inout State, _ action: Action) -> EffectOf { + switch action { + case .onAppear: + let isLoggedIn = false + if isLoggedIn { // 로그인 판단 + state.home = HomeCore.State() + } else { + state.onboarding = OnboardingCore.State() + } + return .none + + case let .appDelegate(.userNotifications(.didReceiveResponse(response, completionHandler))): + let userInfo = response.notification.request.content.userInfo + guard let data = try? JSONSerialization.data(withJSONObject: userInfo), + let pushNotiContent = try? JSONDecoder().decode(PushNotificationContent.self, from: data) + else { + completionHandler() + return .none + } + return .run { send in + switch pushNotiContent { + case .test: + break + } + completionHandler() + } + + case .appDelegate: + return .none + + case .didChangeScenePhase: + return .none + + case .home: + return .none + + case .onboarding: + return .none + } + } +} diff --git a/Projects/Feature/Feature/Sources/AppDelegateCore.swift b/Projects/Feature/Feature/Sources/AppDelegateCore.swift new file mode 100644 index 0000000..c3801ca --- /dev/null +++ b/Projects/Feature/Feature/Sources/AppDelegateCore.swift @@ -0,0 +1,89 @@ +// +// AppDelegateCore.swift +// AppServiceInterface +// +// Created by devMinseok on 7/22/24. +// Copyright © 2024 PomoNyang. All rights reserved. +// + +import UIKit +import Foundation + +import UserNotificationClientInterface +import KeychainClientInterface + +import ComposableArchitecture +import FirebaseCore +import FirebaseMessaging + +@Reducer +public struct AppDelegateCore { + @ObservableState + public struct State: Equatable { + public init() {} + } + + public enum Action { + case didFinishLaunching + case didRegisterForRemoteNotifications(Result) + case userNotifications(UserNotificationClient.DelegateEvent) + } + + @Dependency(\.keychainClient) var keychainClient + @Dependency(\.userNotificationClient) var userNotificationClient + + public init() {} + + public var body: some ReducerOf { + Reduce(self.core) + } + + private func core(_ state: inout State, _ action: Action) -> EffectOf { + switch action { + case .didFinishLaunching: + UIApplication.shared.applicationIconBadgeNumber = 0 + FirebaseApp.configure() + keychainClient.checkSubsequentRun() + let userNotificationEventStream = userNotificationClient.delegate() + + return .run { send in + await withThrowingTaskGroup(of: Void.self) { group in + group.addTask { + for await event in userNotificationEventStream { + await send(.userNotifications(event)) + } + } + + group.addTask { + let settings = await userNotificationClient.getNotificationSettings() + switch settings.authorizationStatus { + case .authorized: + guard try await userNotificationClient.requestAuthorization([.badge, .alert, .sound]) + else { return } + case .notDetermined, .provisional: + guard try await userNotificationClient.requestAuthorization(.provisional) + else { return } + default: + return + } + await UIApplication.shared.registerForRemoteNotifications() + } + } + } + + case let .didRegisterForRemoteNotifications(.success(tokenData)): + Messaging.messaging().apnsToken = tokenData + return .none + + case .didRegisterForRemoteNotifications(.failure): + return .none + + case let .userNotifications(.willPresentNotification(_, completionHandler)): + completionHandler([.banner, .list, .sound]) + return .none + + case .userNotifications: + return .none + } + } +} diff --git a/Projects/Feature/Feature/Sources/AppView.swift b/Projects/Feature/Feature/Sources/AppView.swift new file mode 100644 index 0000000..b0e5e2d --- /dev/null +++ b/Projects/Feature/Feature/Sources/AppView.swift @@ -0,0 +1,39 @@ +// +// AppServcieView.swift +// AppServiceInterface +// +// Created by devMinseok on 7/22/24. +// Copyright © 2024 PomoNyang. All rights reserved. +// + +import SwiftUI + +import HomeFeature +import HomeFeatureInterface +import OnboardingFeature +import OnboardingFeatureInterface + +import ComposableArchitecture + +public struct AppView: View { + let store: StoreOf + + public init(store: StoreOf) { + self.store = store + } + + public var body: some View { + Group { + if let homeStore = store.scope(state: \.home, action: \.home) { + HomeView(store: homeStore) + } else if let onboardingStore = store.scope(state: \.onboarding, action: \.onboarding) { + OnboardingView(store: onboardingStore) + } else { + Color.red + } + } + .onAppear { + store.send(.onAppear) + } + } +} diff --git a/Projects/Feature/Feature/Sources/Exports.swift b/Projects/Feature/Feature/Sources/Exports.swift deleted file mode 100644 index 5aa4893..0000000 --- a/Projects/Feature/Feature/Sources/Exports.swift +++ /dev/null @@ -1,10 +0,0 @@ -// -// Exports.swift -// Shared -// -// Created by devMinseok on 7/20/24. -// Copyright © 2024 PomoNyang. All rights reserved. -// - -@_exported import AppFeature -@_exported import AppFeatureInterface diff --git a/Projects/Feature/HomeFeature/Example/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json b/Projects/Feature/HomeFeature/Example/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..f1cb98f --- /dev/null +++ b/Projects/Feature/HomeFeature/Example/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images" : [ + { + "filename" : "ICON_DEMO.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/Feature/HomeFeature/Example/Resources/Assets.xcassets/contents.json b/Projects/Feature/HomeFeature/Example/Resources/Assets.xcassets/contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Projects/Feature/HomeFeature/Example/Resources/Assets.xcassets/contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/Feature/HomeFeature/Example/Resources/Font/Pretendard-Bold.otf b/Projects/Feature/HomeFeature/Example/Resources/Font/Pretendard-Bold.otf new file mode 100644 index 0000000..a52ef39 Binary files /dev/null and b/Projects/Feature/HomeFeature/Example/Resources/Font/Pretendard-Bold.otf differ diff --git a/Projects/Feature/HomeFeature/Example/Resources/Font/Pretendard-Medium.otf b/Projects/Feature/HomeFeature/Example/Resources/Font/Pretendard-Medium.otf new file mode 100644 index 0000000..a2dc009 Binary files /dev/null and b/Projects/Feature/HomeFeature/Example/Resources/Font/Pretendard-Medium.otf differ diff --git a/Projects/Feature/HomeFeature/Example/Resources/Font/Pretendard-Regular.otf b/Projects/Feature/HomeFeature/Example/Resources/Font/Pretendard-Regular.otf new file mode 100644 index 0000000..c940185 Binary files /dev/null and b/Projects/Feature/HomeFeature/Example/Resources/Font/Pretendard-Regular.otf differ diff --git a/Projects/Feature/HomeFeature/Example/Resources/Font/Pretendard-SemiBold.otf b/Projects/Feature/HomeFeature/Example/Resources/Font/Pretendard-SemiBold.otf new file mode 100644 index 0000000..c375b54 Binary files /dev/null and b/Projects/Feature/HomeFeature/Example/Resources/Font/Pretendard-SemiBold.otf differ diff --git a/Projects/Feature/HomeFeature/Example/Resources/LaunchScreen.storyboard b/Projects/Feature/HomeFeature/Example/Resources/LaunchScreen.storyboard new file mode 100644 index 0000000..be85df4 --- /dev/null +++ b/Projects/Feature/HomeFeature/Example/Resources/LaunchScreen.storyboard @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Projects/Feature/HomeFeature/Example/Sources/AppDelegate.swift b/Projects/Feature/HomeFeature/Example/Sources/AppDelegate.swift new file mode 100644 index 0000000..0d538be --- /dev/null +++ b/Projects/Feature/HomeFeature/Example/Sources/AppDelegate.swift @@ -0,0 +1,11 @@ +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + return true + } +} diff --git a/Projects/Feature/HomeFeature/Interface/HomeCoreInterface.swift b/Projects/Feature/HomeFeature/Interface/HomeCoreInterface.swift new file mode 100644 index 0000000..87e4b48 --- /dev/null +++ b/Projects/Feature/HomeFeature/Interface/HomeCoreInterface.swift @@ -0,0 +1,33 @@ +// +// HomeCoreInterface.swift +// HomeFeature +// +// Created by devMinseok on 7/22/24. +// Copyright © 2024 PomoNyang. All rights reserved. +// + +import Foundation + +import ComposableArchitecture + +@Reducer +public struct HomeCore { + private let reducer: Reduce + + public init(reducer: Reduce) { + self.reducer = reducer + } + + @ObservableState + public struct State: Equatable { + public init() {} + } + + public enum Action { + case onAppear + } + + public var body: some ReducerOf { + reducer + } +} diff --git a/Projects/Feature/HomeFeature/Interface/HomeView.swift b/Projects/Feature/HomeFeature/Interface/HomeView.swift new file mode 100644 index 0000000..cc78b40 --- /dev/null +++ b/Projects/Feature/HomeFeature/Interface/HomeView.swift @@ -0,0 +1,28 @@ +// +// HomeView.swift +// HomeFeatureInterface +// +// Created by devMinseok on 7/22/24. +// Copyright © 2024 PomoNyang. All rights reserved. +// + +import SwiftUI + +import ComposableArchitecture + +public struct HomeView: View { + let store: StoreOf + + public init(store: StoreOf) { + self.store = store + } + + public var body: some View { + VStack { + Text("Home") + .foregroundStyle(Color.black) + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(Color.white) + } +} diff --git a/Projects/Feature/AppFeature/Project.swift b/Projects/Feature/HomeFeature/Project.swift similarity index 84% rename from Projects/Feature/AppFeature/Project.swift rename to Projects/Feature/HomeFeature/Project.swift index 52b2aa5..6f25a9e 100644 --- a/Projects/Feature/AppFeature/Project.swift +++ b/Projects/Feature/HomeFeature/Project.swift @@ -1,18 +1,19 @@ import ProjectDescription import ProjectDescriptionHelpers -@_spi(Domain) @_spi(Feature) +@_spi(Domain) import DependencyPlugin let project: Project = .makeTMABasedProject( - module: Feature.AppFeature, + module: Feature.HomeFeature, scripts: [], targets: [ .sources, .interface, .tests, - .testing + .testing, + .example ], dependencies: [ .interface: [ diff --git a/Projects/Feature/AppFeature/Resources/dummy.txt b/Projects/Feature/HomeFeature/Resources/dummy.txt similarity index 100% rename from Projects/Feature/AppFeature/Resources/dummy.txt rename to Projects/Feature/HomeFeature/Resources/dummy.txt diff --git a/Projects/Feature/HomeFeature/Sources/HomeCore.swift b/Projects/Feature/HomeFeature/Sources/HomeCore.swift new file mode 100644 index 0000000..2720af5 --- /dev/null +++ b/Projects/Feature/HomeFeature/Sources/HomeCore.swift @@ -0,0 +1,23 @@ +// +// HomeCore.swift +// HomeFeature +// +// Created by devMinseok on 7/22/24. +// Copyright © 2024 PomoNyang. All rights reserved. +// + +import HomeFeatureInterface + +import ComposableArchitecture + +extension HomeCore { + public init() { + let reducer = Reduce { state, action in + switch action { + case .onAppear: + return .none + } + } + self.init(reducer: reducer) + } +} diff --git a/Projects/Feature/HomeFeature/Testing/HomeFeatureTesting.swift b/Projects/Feature/HomeFeature/Testing/HomeFeatureTesting.swift new file mode 100644 index 0000000..ca81c97 --- /dev/null +++ b/Projects/Feature/HomeFeature/Testing/HomeFeatureTesting.swift @@ -0,0 +1,5 @@ +import Foundation + +public struct HomeFeatureTesting { + public init() {} +} diff --git a/Projects/Feature/AppFeature/Sources/AppFeature.swift b/Projects/Feature/HomeFeature/Tests/HomeFeatureTests.swift similarity index 54% rename from Projects/Feature/AppFeature/Sources/AppFeature.swift rename to Projects/Feature/HomeFeature/Tests/HomeFeatureTests.swift index 6d6f60a..c050739 100644 --- a/Projects/Feature/AppFeature/Sources/AppFeature.swift +++ b/Projects/Feature/HomeFeature/Tests/HomeFeatureTests.swift @@ -1,5 +1,5 @@ import Foundation -public struct AppFeature { +public struct HomeFeatureTests { public init() {} } diff --git a/Projects/Feature/OnboardingFeature/Example/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json b/Projects/Feature/OnboardingFeature/Example/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..f1cb98f --- /dev/null +++ b/Projects/Feature/OnboardingFeature/Example/Resources/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,14 @@ +{ + "images" : [ + { + "filename" : "ICON_DEMO.png", + "idiom" : "universal", + "platform" : "ios", + "size" : "1024x1024" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/Feature/OnboardingFeature/Example/Resources/Assets.xcassets/contents.json b/Projects/Feature/OnboardingFeature/Example/Resources/Assets.xcassets/contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Projects/Feature/OnboardingFeature/Example/Resources/Assets.xcassets/contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Projects/Feature/OnboardingFeature/Example/Resources/Font/Pretendard-Bold.otf b/Projects/Feature/OnboardingFeature/Example/Resources/Font/Pretendard-Bold.otf new file mode 100644 index 0000000..a52ef39 Binary files /dev/null and b/Projects/Feature/OnboardingFeature/Example/Resources/Font/Pretendard-Bold.otf differ diff --git a/Projects/Feature/OnboardingFeature/Example/Resources/Font/Pretendard-Medium.otf b/Projects/Feature/OnboardingFeature/Example/Resources/Font/Pretendard-Medium.otf new file mode 100644 index 0000000..a2dc009 Binary files /dev/null and b/Projects/Feature/OnboardingFeature/Example/Resources/Font/Pretendard-Medium.otf differ diff --git a/Projects/Feature/OnboardingFeature/Example/Resources/Font/Pretendard-Regular.otf b/Projects/Feature/OnboardingFeature/Example/Resources/Font/Pretendard-Regular.otf new file mode 100644 index 0000000..c940185 Binary files /dev/null and b/Projects/Feature/OnboardingFeature/Example/Resources/Font/Pretendard-Regular.otf differ diff --git a/Projects/Feature/OnboardingFeature/Example/Resources/Font/Pretendard-SemiBold.otf b/Projects/Feature/OnboardingFeature/Example/Resources/Font/Pretendard-SemiBold.otf new file mode 100644 index 0000000..c375b54 Binary files /dev/null and b/Projects/Feature/OnboardingFeature/Example/Resources/Font/Pretendard-SemiBold.otf differ diff --git a/Projects/Feature/OnboardingFeature/Example/Resources/LaunchScreen.storyboard b/Projects/Feature/OnboardingFeature/Example/Resources/LaunchScreen.storyboard new file mode 100644 index 0000000..a58716d --- /dev/null +++ b/Projects/Feature/OnboardingFeature/Example/Resources/LaunchScreen.storyboard @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Projects/Feature/OnboardingFeature/Example/Sources/AppDelegate.swift b/Projects/Feature/OnboardingFeature/Example/Sources/AppDelegate.swift new file mode 100644 index 0000000..0d538be --- /dev/null +++ b/Projects/Feature/OnboardingFeature/Example/Sources/AppDelegate.swift @@ -0,0 +1,11 @@ +import UIKit + +@main +class AppDelegate: UIResponder, UIApplicationDelegate { + func application( + _ application: UIApplication, + didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil + ) -> Bool { + return true + } +} diff --git a/Projects/Feature/OnboardingFeature/Interface/OnboardingCoreInterface.swift b/Projects/Feature/OnboardingFeature/Interface/OnboardingCoreInterface.swift new file mode 100644 index 0000000..72fd03e --- /dev/null +++ b/Projects/Feature/OnboardingFeature/Interface/OnboardingCoreInterface.swift @@ -0,0 +1,33 @@ +// +// OnboardingCoreInterface.swift +// OnboardingFeatureInterface +// +// Created by devMinseok on 7/22/24. +// Copyright © 2024 PomoNyang. All rights reserved. +// + +import Foundation + +import ComposableArchitecture + +@Reducer +public struct OnboardingCore { + private let reducer: Reduce + + public init(reducer: Reduce) { + self.reducer = reducer + } + + @ObservableState + public struct State: Equatable { + public init() {} + } + + public enum Action { + case onAppear + } + + public var body: some ReducerOf { + reducer + } +} diff --git a/Projects/Feature/OnboardingFeature/Interface/OnboardingView.swift b/Projects/Feature/OnboardingFeature/Interface/OnboardingView.swift new file mode 100644 index 0000000..6a32071 --- /dev/null +++ b/Projects/Feature/OnboardingFeature/Interface/OnboardingView.swift @@ -0,0 +1,28 @@ +// +// OnboardingView.swift +// OnboardingFeatureInterface +// +// Created by devMinseok on 7/22/24. +// Copyright © 2024 PomoNyang. All rights reserved. +// + +import SwiftUI + +import ComposableArchitecture + +public struct OnboardingView: View { + let store: StoreOf + + public init(store: StoreOf) { + self.store = store + } + + public var body: some View { + VStack { + Text("Onboarding") + .foregroundStyle(Color.black) + } + .frame(maxWidth: .infinity, maxHeight: .infinity) + .background(Color.white) + } +} diff --git a/Projects/Feature/OnboardingFeature/Project.swift b/Projects/Feature/OnboardingFeature/Project.swift new file mode 100644 index 0000000..8ab4340 --- /dev/null +++ b/Projects/Feature/OnboardingFeature/Project.swift @@ -0,0 +1,23 @@ +import ProjectDescription +import ProjectDescriptionHelpers + +@_spi(Feature) +@_spi(Domain) +import DependencyPlugin + +let project: Project = .makeTMABasedProject( + module: Feature.OnboardingFeature, + scripts: [], + targets: [ + .sources, + .interface, + .tests, + .testing, + .example + ], + dependencies: [ + .interface: [ + .dependency(rootModule: Domain.self) + ] + ] +) diff --git a/Projects/Shared/DesignSystem/Resources/dummy.txt b/Projects/Feature/OnboardingFeature/Resources/dummy.txt similarity index 100% rename from Projects/Shared/DesignSystem/Resources/dummy.txt rename to Projects/Feature/OnboardingFeature/Resources/dummy.txt diff --git a/Projects/Feature/OnboardingFeature/Sources/OnboardingCore.swift b/Projects/Feature/OnboardingFeature/Sources/OnboardingCore.swift new file mode 100644 index 0000000..50a3125 --- /dev/null +++ b/Projects/Feature/OnboardingFeature/Sources/OnboardingCore.swift @@ -0,0 +1,23 @@ +// +// OnboardingCore.swift +// OnboardingFeature +// +// Created by devMinseok on 7/22/24. +// Copyright © 2024 PomoNyang. All rights reserved. +// + +import OnboardingFeatureInterface + +import ComposableArchitecture + +extension OnboardingCore { + public init() { + let reducer = Reduce { state, action in + switch action { + case .onAppear: + return .none + } + } + self.init(reducer: reducer) + } +} diff --git a/Projects/Feature/OnboardingFeature/Testing/OnboardingFeatureTesting.swift b/Projects/Feature/OnboardingFeature/Testing/OnboardingFeatureTesting.swift new file mode 100644 index 0000000..b799b32 --- /dev/null +++ b/Projects/Feature/OnboardingFeature/Testing/OnboardingFeatureTesting.swift @@ -0,0 +1,5 @@ +import Foundation + +public struct OnboardingFeatureTesting { + public init() {} +} diff --git a/Projects/Feature/OnboardingFeature/Tests/OnboardingFeatureTests.swift b/Projects/Feature/OnboardingFeature/Tests/OnboardingFeatureTests.swift new file mode 100644 index 0000000..f80e247 --- /dev/null +++ b/Projects/Feature/OnboardingFeature/Tests/OnboardingFeatureTests.swift @@ -0,0 +1,5 @@ +import Foundation + +public struct OnboardingFeatureTests { + public init() {} +} diff --git a/Projects/Shared/DesignSystem/Project.swift b/Projects/Shared/DesignSystem/Project.swift index 21cd84d..aa62f73 100644 --- a/Projects/Shared/DesignSystem/Project.swift +++ b/Projects/Shared/DesignSystem/Project.swift @@ -6,6 +6,9 @@ import DependencyPlugin let project: Project = .makeTMABasedProject( module: Shared.DesignSystem, + options: .options( + disableSynthesizedResourceAccessors: false + ), includeResource: true, scripts: [], targets: [ @@ -14,5 +17,10 @@ let project: Project = .makeTMABasedProject( .tests, .testing ], - dependencies: [:] + dependencies: [:], + resourceSynthesizers: [ + .fonts(), // for font + .assets(), // for .xcassets, + .files(extensions: ["mp4", "gif"]) + ] ) diff --git a/Projects/Shared/DesignSystem/Resources/Font/Pretendard/Pretendard-Bold.otf b/Projects/Shared/DesignSystem/Resources/Font/Pretendard/Pretendard-Bold.otf new file mode 100644 index 0000000..a52ef39 Binary files /dev/null and b/Projects/Shared/DesignSystem/Resources/Font/Pretendard/Pretendard-Bold.otf differ diff --git a/Projects/Shared/DesignSystem/Resources/Font/Pretendard/Pretendard-Medium.otf b/Projects/Shared/DesignSystem/Resources/Font/Pretendard/Pretendard-Medium.otf new file mode 100644 index 0000000..a2dc009 Binary files /dev/null and b/Projects/Shared/DesignSystem/Resources/Font/Pretendard/Pretendard-Medium.otf differ diff --git a/Projects/Shared/DesignSystem/Resources/Font/Pretendard/Pretendard-Regular.otf b/Projects/Shared/DesignSystem/Resources/Font/Pretendard/Pretendard-Regular.otf new file mode 100644 index 0000000..c940185 Binary files /dev/null and b/Projects/Shared/DesignSystem/Resources/Font/Pretendard/Pretendard-Regular.otf differ diff --git a/Projects/Shared/DesignSystem/Resources/Font/Pretendard/Pretendard-SemiBold.otf b/Projects/Shared/DesignSystem/Resources/Font/Pretendard/Pretendard-SemiBold.otf new file mode 100644 index 0000000..c375b54 Binary files /dev/null and b/Projects/Shared/DesignSystem/Resources/Font/Pretendard/Pretendard-SemiBold.otf differ diff --git a/Projects/Shared/Shared/Project.swift b/Projects/Shared/Shared/Project.swift index 0f00bcd..fbc5383 100644 --- a/Projects/Shared/Shared/Project.swift +++ b/Projects/Shared/Shared/Project.swift @@ -7,5 +7,5 @@ import DependencyPlugin let project: Project = .makeRootProject( rootModule: Shared.self, scripts: [], - product: .framework + product: .staticLibrary ) diff --git a/Projects/Shared/Shared/Sources/Exports.swift b/Projects/Shared/Shared/Sources/Exports.swift index 8c5e2aa..49b3a1a 100644 --- a/Projects/Shared/Shared/Sources/Exports.swift +++ b/Projects/Shared/Shared/Sources/Exports.swift @@ -11,3 +11,7 @@ @_exported import DesignSystemInterface @_exported import Utils @_exported import UtilsInterface + +@_exported import ThirdParty_SPM +@_exported import ThirdParty_Firebase +@_exported import ThirdParty_Realm diff --git a/Tuist/ProjectDescriptionHelpers/Templates/Project+Extension.swift b/Tuist/ProjectDescriptionHelpers/Templates/Project+Extension.swift index 5118278..b7047bb 100644 --- a/Tuist/ProjectDescriptionHelpers/Templates/Project+Extension.swift +++ b/Tuist/ProjectDescriptionHelpers/Templates/Project+Extension.swift @@ -32,9 +32,9 @@ extension Project { switch targetType { case .sources: let product: Product = if includeResource { - currentConfig == .dev ? .framework : .staticFramework + .staticFramework // currentConfig == .dev ? .framework : .staticFramework } else { - currentConfig == .dev ? .framework : .staticLibrary + .staticLibrary // currentConfig == .dev ? .framework : .staticLibrary } let resources: ResourceFileElements? = includeResource ? ["Resources/**"] : nil let interfaceDependency: [TargetDependency] = targets.contains(.interface) ? [.target(name: "\(name)Interface")] : [] @@ -51,7 +51,7 @@ extension Project { projectTargets.append(target) case .interface: - let product: Product = currentConfig == .dev ? .framework : .staticLibrary + let product: Product = .staticLibrary //currentConfig == .dev ? .framework : .staticLibrary let target: Target = .target( name: targetName, product: product, @@ -79,11 +79,12 @@ extension Project { projectTargets.append(target) case .testing: + let product: Product = .staticFramework // currentConfig == .dev ? .framework : .staticFramework let interfaceDependency: [TargetDependency] = targets.contains(.interface) ? [.target(name: "\(name)Interface")] : [] let dependencies: [TargetDependency] = (interfaceDependency + currentDependencies).compactMap { $0 } let target: Target = .target( name: targetName, - product: .framework, + product: product, infoPlist: infoPlist, sources: ["Testing/**/*.swift"], resources: nil,