diff --git a/project/Projects/Data/Project.swift b/project/Projects/Data/Project.swift index 6ce92599..d7f62406 100644 --- a/project/Projects/Data/Project.swift +++ b/project/Projects/Data/Project.swift @@ -73,7 +73,6 @@ let project = Project( deploymentTargets: DeploymentSettings.deployment_version, sources: ["DataTests/**"], dependencies: [ - D.Data.Repository, D.Testing, ], settings: .settings( diff --git a/project/Projects/Domain/Project.swift b/project/Projects/Domain/Project.swift index 256d9e93..a1046d69 100644 --- a/project/Projects/Domain/Project.swift +++ b/project/Projects/Domain/Project.swift @@ -46,7 +46,6 @@ let project = Project( dependencies: [ // for test - D.Domain, D.Testing, ], settings: .settings( diff --git a/project/Projects/Presentation/Feature/NotificationPage/ExampleApp/Sources/AppDelegate.swift b/project/Projects/Presentation/Feature/NotificationPage/ExampleApp/Sources/AppDelegate.swift index 00267bb5..cd3c7a26 100644 --- a/project/Projects/Presentation/Feature/NotificationPage/ExampleApp/Sources/AppDelegate.swift +++ b/project/Projects/Presentation/Feature/NotificationPage/ExampleApp/Sources/AppDelegate.swift @@ -7,6 +7,9 @@ import UIKit +import Testing +import Core + @main class AppDelegate: UIResponder, UIApplicationDelegate { diff --git a/project/Projects/Presentation/Feature/NotificationPage/ExampleApp/Sources/SceneDelegate.swift b/project/Projects/Presentation/Feature/NotificationPage/ExampleApp/Sources/SceneDelegate.swift index eeded47a..4a819ba4 100644 --- a/project/Projects/Presentation/Feature/NotificationPage/ExampleApp/Sources/SceneDelegate.swift +++ b/project/Projects/Presentation/Feature/NotificationPage/ExampleApp/Sources/SceneDelegate.swift @@ -6,12 +6,15 @@ // import UIKit + import NotificationPageFeature +import BaseFeature import PresentationCore import Domain import Repository import Core +import Testing import Swinject import RxSwift @@ -20,13 +23,25 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? + var router: RouterProtocol? + + var coordinator: NotificationPageCoordinator? + func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = scene as? UIWindowScene else { return } + DependencyInjector.shared.assemble(MockAssemblies) + + self.router = DependencyInjector.shared.resolve(RouterProtocol.self) + + coordinator = .init() window = UIWindow(windowScene: windowScene) window?.makeKeyAndVisible() + + router?.setRootModuleTo(module: UIViewController(), popCompletion: nil) + coordinator?.start() } } diff --git a/project/Projects/Presentation/Feature/NotificationPage/ExampleApp/Sources/ViewController.swift b/project/Projects/Presentation/Feature/NotificationPage/ExampleApp/Sources/ViewController.swift index e439d432..69d31e59 100644 --- a/project/Projects/Presentation/Feature/NotificationPage/ExampleApp/Sources/ViewController.swift +++ b/project/Projects/Presentation/Feature/NotificationPage/ExampleApp/Sources/ViewController.swift @@ -6,6 +6,7 @@ // import UIKit +import BaseFeature class ViewController: UIViewController { diff --git a/project/Projects/Presentation/Feature/NotificationPage/Project.swift b/project/Projects/Presentation/Feature/NotificationPage/Project.swift index 20a2c811..281566ed 100644 --- a/project/Projects/Presentation/Feature/NotificationPage/Project.swift +++ b/project/Projects/Presentation/Feature/NotificationPage/Project.swift @@ -47,6 +47,7 @@ let project = Project( resources: ["ExampleApp/Resources/**"], dependencies: [ .target(name: "NotificationPageFeature"), + D.Testing, ], settings: .settings( configurations: IdleConfiguration.presentationConfigurations diff --git a/project/Projects/Presentation/Feature/NotificationPage/Sources/NotificationPageModule/NotificationPageVC.swift b/project/Projects/Presentation/Feature/NotificationPage/Sources/NotificationPageModule/NotificationPageVC.swift index 5495f4f8..db5c7ae8 100644 --- a/project/Projects/Presentation/Feature/NotificationPage/Sources/NotificationPageModule/NotificationPageVC.swift +++ b/project/Projects/Presentation/Feature/NotificationPage/Sources/NotificationPageModule/NotificationPageVC.swift @@ -62,6 +62,15 @@ class NotificationPageVC: BaseViewController { let bar: IdleNavigationBar = .init(titleText: "알림") return bar }() + + let emptyView: EmptyNotificationPageView = { + let view: EmptyNotificationPageView = .init( + titleText: "아직 받은 알림이 없어요.", + descriptionText: "최근 30 이내의 알림만 확인할 수 있어요." + ) + view.isHidden = true + return view + }() var tableViewDataSource: UITableViewDiffableDataSource! let tableView: UITableView = { @@ -124,8 +133,10 @@ class NotificationPageVC: BaseViewController { private func setLayout() { [ + // zindex순서 + tableView, + emptyView, navigationBar, - tableView ].forEach { $0.translatesAutoresizingMaskIntoConstraints = false view.addSubview($0) @@ -133,13 +144,18 @@ class NotificationPageVC: BaseViewController { NSLayoutConstraint.activate([ navigationBar.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), - navigationBar.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor), - navigationBar.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor), + navigationBar.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), + navigationBar.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), tableView.topAnchor.constraint(equalTo: navigationBar.bottomAnchor), - tableView.leftAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leftAnchor), - tableView.rightAnchor.constraint(equalTo: view.safeAreaLayoutGuide.rightAnchor), + tableView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), + tableView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), tableView.bottomAnchor.constraint(equalTo: view.bottomAnchor), + + emptyView.topAnchor.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor), + emptyView.leadingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor), + emptyView.trailingAnchor.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor), + emptyView.bottomAnchor.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor), ]) } @@ -167,6 +183,9 @@ class NotificationPageVC: BaseViewController { guard let self else { return } + // 전달된 알림이 없는 경우 + emptyView.isHidden = tableData.count != 0 + self.tableData = tableData var snapShot: NSDiffableDataSourceSnapshot = .init() diff --git a/project/Projects/Presentation/Feature/NotificationPage/Sources/NotificationPageModule/View/EmptyNotificationPageView.swift b/project/Projects/Presentation/Feature/NotificationPage/Sources/NotificationPageModule/View/EmptyNotificationPageView.swift new file mode 100644 index 00000000..c33f44fe --- /dev/null +++ b/project/Projects/Presentation/Feature/NotificationPage/Sources/NotificationPageModule/View/EmptyNotificationPageView.swift @@ -0,0 +1,74 @@ +// +// EmptyNotificationPageView.swift +// NotificationPageFeature +// +// Created by choijunios on 10/21/24. +// + +import UIKit + +import BaseFeature +import DSKit + + +import RxSwift + +class EmptyNotificationPageView: UIView { + + // Init + + // View + let titleLabel: IdleLabel = { + let view: IdleLabel = .init(typography: .Heading2) + return view + }() + let descriptionLabel: IdleLabel = { + let view: IdleLabel = .init(typography: .Body3) + view.attrTextColor = DSColor.gray300.color + return view + }() + + // Observable + private let disposeBag = DisposeBag() + + public init( + titleText: String, + descriptionText: String + ) { + super.init(frame: .zero) + + self.titleLabel.textString = titleText + self.descriptionLabel.textString = descriptionText + + setAppearance() + setLayout() + setObservable() + } + + public required init?(coder: NSCoder) { fatalError() } + + private func setAppearance() { + self.backgroundColor = DSColor.gray0.color + } + + private func setLayout() { + + let labelStack: DSKit.VStack = .init( + [titleLabel, descriptionLabel], + spacing: 8, + alignment: .center + ) + + self.addSubview(labelStack) + labelStack.translatesAutoresizingMaskIntoConstraints = false + + NSLayoutConstraint.activate([ + labelStack.centerXAnchor.constraint(equalTo: self.centerXAnchor), + labelStack.centerYAnchor.constraint(equalTo: self.centerYAnchor), + ]) + } + + private func setObservable() { + + } +} diff --git a/project/Projects/Testing/Project.swift b/project/Projects/Testing/Project.swift index a3640155..14011a90 100644 --- a/project/Projects/Testing/Project.swift +++ b/project/Projects/Testing/Project.swift @@ -25,9 +25,10 @@ let project = Project( deploymentTargets: DeploymentSettings.deployment_version, sources: ["Sources/**"], dependencies: [ - D.Domain, - D.Data.DataSource, + D.Data.Repository, + + D.Presentation.BaseFeature, ], settings: .settings( base: ["ENABLE_TESTABILITY": "YES"], diff --git a/project/Projects/Testing/Sources/Data/MockNotificationsRepository.swift b/project/Projects/Testing/Sources/Data/MockNotificationsRepository.swift new file mode 100644 index 00000000..dd7716b4 --- /dev/null +++ b/project/Projects/Testing/Sources/Data/MockNotificationsRepository.swift @@ -0,0 +1,26 @@ +// +// MockNotificationsRepository.swift +// Testing +// +// Created by choijunios on 10/21/24. +// + +import Foundation + +import Domain +import Core + +class MockNotificationsRepository: NotificationsRepository { + + func readNotification(id: String) -> Sult { + .just(.success(())) + } + + func unreadNotificationCount() -> Sult { + .just(.success(1)) + } + + func notifcationList() -> Sult<[Domain.NotificationVO], Domain.DomainError> { + .just(.success([])) + } +} diff --git a/project/Projects/Testing/Sources/MockAssemblies.swift b/project/Projects/Testing/Sources/MockAssemblies.swift index 11d1ef78..b4d1e8e1 100644 --- a/project/Projects/Testing/Sources/MockAssemblies.swift +++ b/project/Projects/Testing/Sources/MockAssemblies.swift @@ -6,15 +6,18 @@ // import Foundation -import Domain + +import BaseFeature import DataSource +import Domain import Swinject -let MockAssemblies: [Assembly] = [ +public let MockAssemblies: [Assembly] = [ MockDataAssembly(), MockDomainAssembly(), + ServiceAssembly() ] // MARK: Domain Assembly @@ -40,5 +43,21 @@ struct MockDataAssembly: Assembly { container.register(LocalStorageService.self) { _ in MockLocalStorageService() } + + container.register(NotificationsRepository.self) { _ in + MockNotificationsRepository() + } + } +} + +// MARK: Service Assembly + +struct ServiceAssembly: Assembly { + + func assemble(container: Container) { + container.register(RouterProtocol.self) { _ in + Router() + } + .inObjectScope(.container) } } diff --git a/project/graph.png b/project/graph.png index 1b154dfc..1727f8d7 100644 Binary files a/project/graph.png and b/project/graph.png differ