diff --git a/MLS/Core/.DS_Store b/MLS/Core/.DS_Store deleted file mode 100644 index aba2f814..00000000 Binary files a/MLS/Core/.DS_Store and /dev/null differ diff --git a/MLS/Core/Core.xcodeproj/project.pbxproj b/MLS/Core/Core.xcodeproj/project.pbxproj deleted file mode 100644 index 9e05efaf..00000000 --- a/MLS/Core/Core.xcodeproj/project.pbxproj +++ /dev/null @@ -1,496 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 77; - objects = { - -/* Begin PBXContainerItemProxy section */ - 77BEB57B2DC268AA002FFCFC /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 084A257A2DB93DDB00C395C0 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 084A25822DB93DDB00C395C0; - remoteInfo = Core; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 084A25832DB93DDB00C395C0 /* Core.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Core.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77BEB5762DC268AA002FFCFC /* DIContainerTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = DIContainerTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFileSystemSynchronizedRootGroup section */ - 084A25852DB93DDB00C395C0 /* Core */ = { - isa = PBXFileSystemSynchronizedRootGroup; - path = Core; - sourceTree = ""; - }; - 77BEB5772DC268AA002FFCFC /* DIContainerTests */ = { - isa = PBXFileSystemSynchronizedRootGroup; - path = DIContainerTests; - sourceTree = ""; - }; -/* End PBXFileSystemSynchronizedRootGroup section */ - -/* Begin PBXFrameworksBuildPhase section */ - 084A25802DB93DDB00C395C0 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 77BEB5732DC268AA002FFCFC /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 084A25792DB93DDB00C395C0 = { - isa = PBXGroup; - children = ( - 084A25852DB93DDB00C395C0 /* Core */, - 77BEB5772DC268AA002FFCFC /* DIContainerTests */, - 084A25842DB93DDB00C395C0 /* Products */, - ); - sourceTree = ""; - }; - 084A25842DB93DDB00C395C0 /* Products */ = { - isa = PBXGroup; - children = ( - 084A25832DB93DDB00C395C0 /* Core.framework */, - 77BEB5762DC268AA002FFCFC /* DIContainerTests.xctest */, - ); - name = Products; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 084A257E2DB93DDB00C395C0 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 084A25822DB93DDB00C395C0 /* Core */ = { - isa = PBXNativeTarget; - buildConfigurationList = 084A25892DB93DDB00C395C0 /* Build configuration list for PBXNativeTarget "Core" */; - buildPhases = ( - 084A257E2DB93DDB00C395C0 /* Headers */, - 084A257F2DB93DDB00C395C0 /* Sources */, - 084A25802DB93DDB00C395C0 /* Frameworks */, - 084A25812DB93DDB00C395C0 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - fileSystemSynchronizedGroups = ( - 084A25852DB93DDB00C395C0 /* Core */, - ); - name = Core; - packageProductDependencies = ( - ); - productName = Core; - productReference = 084A25832DB93DDB00C395C0 /* Core.framework */; - productType = "com.apple.product-type.framework"; - }; - 77BEB5752DC268AA002FFCFC /* DIContainerTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 77BEB57D2DC268AA002FFCFC /* Build configuration list for PBXNativeTarget "DIContainerTests" */; - buildPhases = ( - 77BEB5722DC268AA002FFCFC /* Sources */, - 77BEB5732DC268AA002FFCFC /* Frameworks */, - 77BEB5742DC268AA002FFCFC /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 77BEB57C2DC268AA002FFCFC /* PBXTargetDependency */, - ); - fileSystemSynchronizedGroups = ( - 77BEB5772DC268AA002FFCFC /* DIContainerTests */, - ); - name = DIContainerTests; - packageProductDependencies = ( - ); - productName = DIContainerTests; - productReference = 77BEB5762DC268AA002FFCFC /* DIContainerTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 084A257A2DB93DDB00C395C0 /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1620; - LastUpgradeCheck = 1620; - TargetAttributes = { - 084A25822DB93DDB00C395C0 = { - CreatedOnToolsVersion = 16.2; - LastSwiftMigration = 1620; - }; - 77BEB5752DC268AA002FFCFC = { - CreatedOnToolsVersion = 16.2; - }; - }; - }; - buildConfigurationList = 084A257D2DB93DDB00C395C0 /* Build configuration list for PBXProject "Core" */; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 084A25792DB93DDB00C395C0; - minimizedProjectReferenceProxies = 1; - packageReferences = ( - ); - preferredProjectObjectVersion = 77; - productRefGroup = 084A25842DB93DDB00C395C0 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 084A25822DB93DDB00C395C0 /* Core */, - 77BEB5752DC268AA002FFCFC /* DIContainerTests */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 084A25812DB93DDB00C395C0 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 77BEB5742DC268AA002FFCFC /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 084A257F2DB93DDB00C395C0 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 77BEB5722DC268AA002FFCFC /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 77BEB57C2DC268AA002FFCFC /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - platformFilter = ios; - target = 084A25822DB93DDB00C395C0 /* Core */; - targetProxy = 77BEB57B2DC268AA002FFCFC /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 084A258A2DB93DDB00C395C0 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.Core; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 084A258B2DB93DDB00C395C0 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.Core; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; - 084A258C2DB93DDB00C395C0 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.2; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 084A258D2DB93DDB00C395C0 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.2; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 77BEB57E2DC268AA002FFCFC /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = pinocchio22.DIContainerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 77BEB57F2DC268AA002FFCFC /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - GENERATE_INFOPLIST_FILE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = pinocchio22.DIContainerTests; - PRODUCT_NAME = "$(TARGET_NAME)"; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 084A257D2DB93DDB00C395C0 /* Build configuration list for PBXProject "Core" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 084A258C2DB93DDB00C395C0 /* Debug */, - 084A258D2DB93DDB00C395C0 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 084A25892DB93DDB00C395C0 /* Build configuration list for PBXNativeTarget "Core" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 084A258A2DB93DDB00C395C0 /* Debug */, - 084A258B2DB93DDB00C395C0 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 77BEB57D2DC268AA002FFCFC /* Build configuration list for PBXNativeTarget "DIContainerTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 77BEB57E2DC268AA002FFCFC /* Debug */, - 77BEB57F2DC268AA002FFCFC /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - }; - rootObject = 084A257A2DB93DDB00C395C0 /* Project object */; -} diff --git a/MLS/Core/Core.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/MLS/Core/Core.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a6..00000000 --- a/MLS/Core/Core.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/MLS/Core/Core/DIContainer/DIContainer.swift b/MLS/Core/Core/DIContainer/DIContainer.swift deleted file mode 100644 index 58830dc9..00000000 --- a/MLS/Core/Core/DIContainer/DIContainer.swift +++ /dev/null @@ -1,66 +0,0 @@ -import Foundation - -/// 의존성 주입을 위한 컨테이너 -public final class DIContainer { - static let shared = DIContainer() - // 저장 타입식별자 : [이름 식별자 : 객체 클로저] 형태 - private var services: [ObjectIdentifier: [String: () -> Any]] = [:] - private var instances: [ObjectIdentifier: [String: Any]] = [:] - // 동시성 문제를 해결하기 위한 큐 생성 - private let serviceQueue = DispatchQueue(label: "com.dicontainer.serviceQueue") - - /// 구현체 등록을 위한 함수 - /// - Parameters: - /// - type: 등록하는 객체의 타입 - /// - name: 같은 인터페이스끼리의 식별을 위한 문자열 식별자 - /// - component: 저장할 객체 - public static func register(type: T.Type, name: String? = nil, object: @escaping () -> T) { - shared.register(type: type, name: name, object: object) - } - - /// 등록된 구현체를 가져오기 위한 함수 - /// - Parameters: - /// - type: 가져올 객체의 타입 - /// - name: 가져올 객체의 식별자 - /// - Returns: 저장되어있던 객체 - public static func resolve(type: T.Type, name: String? = nil) -> T { - shared.resolve(type: type, name: name) - } -} - -private extension DIContainer { - private func register(type: T.Type, name: String?, object: @escaping () -> T) { - serviceQueue.sync { - let key = ObjectIdentifier(type) - var namedServices = services[key] ?? [:] - // 같은 식별자로 이미 저장되어있는 객체가 있다면 fatalError - if namedServices[name ?? "default"] != nil { - fatalError("\(type)타입과 \(name ?? "default")이름이 이미 존재") - } - // 문자열 식별자를 입력하지 않으면 default로 간주하여 저장 - namedServices[name ?? "default"] = { object() } - services[key] = namedServices - } - } - - private func resolve(type: T.Type, name: String?) -> T { -// serviceQueue.sync { - let key = ObjectIdentifier(type) - let nameKey = name ?? "default" - - if let instance = instances[key]?[nameKey] as? T { - return instance - } - - guard let services = services[key]?[nameKey] else { - fatalError("\(type) 타입과 \(nameKey) 이름이 등록되어 있지 않습니다.") - } - - let newInstance = services() - var namedInstances = instances[key] ?? [:] - namedInstances[nameKey] = newInstance - instances[key] = namedInstances - return newInstance as! T -// } - } -} diff --git a/MLS/Core/Core/Logger/Loggable.swift b/MLS/Core/Core/Logger/Loggable.swift deleted file mode 100644 index 03b0f3ad..00000000 --- a/MLS/Core/Core/Logger/Loggable.swift +++ /dev/null @@ -1,56 +0,0 @@ -import OSLog - -public protocol Loggable {} - -public extension Loggable { - /// 모듈 이름을 자동으로 추출 - /// - Returns: 타입이 정의된 모듈 이름 (예: "AuthFeature", "BookmarkFeature") - static var subsystem: String { - let fullName = String(reflecting: Self.self) - // "AuthFeature.LoginViewModel" -> "AuthFeature" - return fullName.components(separatedBy: ".").first ?? "Unknown" - } - - /// 타입 이름을 카테고리로 사용 - /// - Returns: 타입 이름 (예: "LoginViewModel", "BookmarkManager") - static var category: String { - String(describing: Self.self) - } - - /// 타입별로 캐싱된 Logger 인스턴스 - private static var logger: Logger { - LoggerStorage.logger(subsystem: subsystem, category: category) - } - - /// 디버그 로그 (Debug 빌드에서만 출력) - /// - Parameter message: 로그 메시지 (.private로 보호되어 민감 정보도 안전하게 로깅) - func logDebug(_ message: String) { - #if DEBUG - Self.logger.debug("\(message, privacy: .private)") - #endif - } - - /// 정보성 로그 (Notice 레벨) - /// - Parameter message: 로그 메시지 - func logNotice(_ message: String) { - Self.logger.notice("\(message)") - } - - /// 경고 로그 (비정상적이지만 처리 가능한 상황) - /// - Parameter message: 로그 메시지 - func logWarning(_ message: String) { - Self.logger.warning("\(message)") - } - - /// 에러 로그 - /// - Parameter message: 로그 메시지 - func logError(_ message: String) { - Self.logger.error("\(message)") - } - - /// 치명적 에러 로그 (앱 크래시 직전 상황) - /// - Parameter message: 로그 메시지 - func logCritical(_ message: String) { - Self.logger.critical("\(message)") - } -} diff --git a/MLS/Core/Core/Logger/LoggerStorage.swift b/MLS/Core/Core/Logger/LoggerStorage.swift deleted file mode 100644 index 701a7b43..00000000 --- a/MLS/Core/Core/Logger/LoggerStorage.swift +++ /dev/null @@ -1,47 +0,0 @@ -import OSLog - -/// Logger를 NSCache에 저장하기 위한 Wrapper 클래스 -/// Logger는 struct이므로 class로 감싸야 NSCache에 저장 가능 -private final class LoggerBox { - let logger: Logger - - init(logger: Logger) { - self.logger = logger - } -} - -/// Logger 인스턴스를 캐싱하여 재사용하는 저장소 -/// NSCache를 사용하여 메모리 압박 시 자동으로 해제되며, Thread-safe하게 동작 -final class LoggerStorage { - static let shared = LoggerStorage() - - /// 캐싱된 Logger 인스턴스들 - /// NSCache는 메모리 부족 시 자동으로 오래된 항목을 제거 - private let cache = NSCache() - - private init() {} - - /// Logger 인스턴스를 가져오거나 생성 - /// - Parameters: - /// - subsystem: 모듈 이름 (예: "AuthFeature") - /// - category: 카테고리 이름 (예: "LoginViewModel") - /// - Returns: 캐싱되거나 새로 생성된 Logger 인스턴스 - static func logger(subsystem: String, category: String) -> Logger { - shared.getOrCreateLogger(subsystem: subsystem, category: category) - } - - private func getOrCreateLogger(subsystem: String, category: String) -> Logger { - let key = "\(subsystem).\(category)" as NSString - - // 캐시에서 확인 - if let box = cache.object(forKey: key) { - return box.logger - } - - // 없으면 새로 생성 (NSCache는 thread-safe) - let newLogger = Logger(subsystem: subsystem, category: category) - let box = LoggerBox(logger: newLogger) - cache.setObject(box, forKey: key) - return newLogger - } -} diff --git a/MLS/Core/DIContainerTests/DIContainerTests.swift b/MLS/Core/DIContainerTests/DIContainerTests.swift deleted file mode 100644 index d8988c2c..00000000 --- a/MLS/Core/DIContainerTests/DIContainerTests.swift +++ /dev/null @@ -1,113 +0,0 @@ -import XCTest - -@testable import Core - -class DIContainerTests: XCTestCase { - - /// 객체 등록 및 가져오기 테스트 - func testRegisterAndResolve() { - DIContainer.register(type: Service.self, name: "A") { ServiceA() } - DIContainer.register(type: Service.self, name: "B") { ServiceB() } - - let serviceA: Service? = DIContainer.resolve(type: Service.self, name: "A") - let serviceB: Service? = DIContainer.resolve(type: Service.self, name: "B") - - XCTAssertNotNil(serviceA) - XCTAssertNotNil(serviceB) - XCTAssertEqual(serviceA?.perform(), "ServiceA") - XCTAssertEqual(serviceB?.perform(), "ServiceB") - } - - /// 기본 이름 동작 테스트 - func testDefaultName() { - DIContainer.register(type: Service.self) { ServiceA() as Service } - - let service: Service? = DIContainer.resolve(type: Service.self) - - XCTAssertNotNil(service) - XCTAssertEqual(service?.perform(), "ServiceA") - } - - // 중복 등록 시 fatalError 테스트 - // fatalError 구문은 주석처리하고 테스트 진행 -// func testDuplicateRegistration() { -// DIContainer.register(type: Service.self, name: "A") { ServiceA() as Service } -// DIContainer.register(type: Service.self, name: "A") { ServiceB() as Service } -// -// let service: Service? = DIContainer.resolve(type: Service.self, name: "A") -// XCTAssertNotNil(service) -// XCTAssertEqual(service?.perform(), "ServiceB", "Expected ServiceB to override ServiceA for name 'A'") -// } - - /// 등록되지 않은 객체 불러오기 테스트 - func testResolveUnregistered() { - let service: Service? = DIContainer.resolve(type: Service.self, name: "Unknown") - - XCTAssertNil(service) - } - - /// 타입 안전성 테스트 - func testTypeSafety() { - DIContainer.register(type: Service.self, name: "A") { ServiceA() as Service } - - let anotherService: AnotherService? = DIContainer.resolve(type: AnotherService.self, name: "A") - - XCTAssertNil(anotherService) - } - - /// 동시성 테스트 (여러 스레드에서 register/resolve 호출) - func testConcurrency() { - let expectation = XCTestExpectation(description: "Concurrent register and resolve") - let queue = DispatchQueue(label: "test.concurrent.queue", attributes: .concurrent) - let group = DispatchGroup() - - // 동시에 등록 및 호출 - for index in 0..<100 { - group.enter() - queue.async { - let name = "Test\(index)" - DIContainer.register(type: Service.self, name: name) { - index % 2 == 0 ? ServiceA() as Service : ServiceB() as Service - } - let service: Service? = DIContainer.resolve(type: Service.self, name: name) - XCTAssertNotNil(service) - XCTAssertEqual(service?.perform(), index % 2 == 0 ? "ServiceA" : "ServiceB") - group.leave() - } - } - - group.notify(queue: .main) { - expectation.fulfill() - } - wait(for: [expectation], timeout: 5.0) - } -} - -/// 테스트를 위한 임시 객체 -extension DIContainerTests { - protocol Service { - func perform() -> String - } - - class ServiceA: Service { - func perform() -> String { - return "ServiceA" - } - } - - class ServiceB: Service { - func perform() -> String { - return "ServiceB" - } - } - - protocol AnotherService { - func execute() -> String - } - - class AnotherServiceX: AnotherService { - func execute() -> String { - return "AnotherServiceX" - } - } -} diff --git a/MLS/Core/DIContainerTests/LoggerTests.swift b/MLS/Core/DIContainerTests/LoggerTests.swift deleted file mode 100644 index 1201aeb1..00000000 --- a/MLS/Core/DIContainerTests/LoggerTests.swift +++ /dev/null @@ -1,119 +0,0 @@ -@testable import Core -import Testing - -struct TestViewModel: Loggable { - func testLogs() { - logDebug("Debug 로그 테스트") - logNotice("Notice 로그 테스트") - logWarning("Warning 로그 테스트") - logError("Error 로그 테스트") - logCritical("Critical 로그 테스트") - } -} - -class TestManager: Loggable { - func testLogs() { - logDebug("Debug 로그 (class)") - logNotice("Notice 로그 (class)") - logWarning("Warning 로그 (class)") - logError("Error 로그 (class)") - logCritical("Critical 로그 (class)") - } -} - -struct LoggerTests { - - @Test("Subsystem 자동 추출 검증 - Struct") - func testSubsystemExtractionStruct() async throws { - // subsystem은 타입이 정의된 모듈 이름이어야 함 - let subsystem = TestViewModel.subsystem - let category = TestViewModel.category - - // DIContainerTests 모듈에 정의되어 있으므로 - #expect(subsystem == "DIContainerTests") - #expect(category == "TestViewModel") - } - - @Test("Subsystem 자동 추출 검증 - Class") - func testSubsystemExtractionClass() async throws { - let subsystem = TestManager.subsystem - let category = TestManager.category - - #expect(subsystem == "DIContainerTests") - #expect(category == "TestManager") - } - - @Test("Struct에서 Loggable 사용 테스트") - func testLoggableWithStruct() async throws { - let viewModel = TestViewModel() - - // 로그 출력 (Console.app에서 확인 가능) - // subsystem: "DIContainerTests", category: "TestViewModel" - viewModel.testLogs() - - // 에러 없이 실행되면 성공 - #expect(true) - } - - @Test("Class에서 Loggable 사용 테스트") - func testLoggableWithClass() async throws { - let manager = TestManager() - - // 로그 출력 (Console.app에서 확인 가능) - // subsystem: "DIContainerTests", category: "TestManager" - manager.testLogs() - - // 에러 없이 실행되면 성공 - #expect(true) - } - - @Test("동시성 안전성 테스트 - 같은 Logger 동시 접근") - func testConcurrentLoggerAccess() async throws { - // 100개 스레드가 동시에 같은 Logger 사용 - await withTaskGroup(of: Void.self) { group in - for i in 0..<100 { - group.addTask { - let vm = TestViewModel() - vm.logNotice("동시 로그 \(i)") - } - } - } - - // 크래시 없이 완료되면 성공 - #expect(true) - } - - @Test("여러 타입에서 동시에 로깅") - func testMultipleTypesConcurrent() async throws { - let viewModel = TestViewModel() - let manager = TestManager() - - // 동시에 로그 출력 - await withTaskGroup(of: Void.self) { group in - group.addTask { - viewModel.testLogs() - } - group.addTask { - manager.testLogs() - } - } - - // 에러 없이 실행되면 성공 - #expect(true) - } - - @Test("NSCache 캐싱 검증 - 반복 접근 시 정상 동작") - func testLoggerCaching() async throws { - let vm1 = TestViewModel() - let vm2 = TestViewModel() - - // 같은 타입에서 여러 번 로깅 (NSCache에서 캐싱된 Logger 재사용) - vm1.logNotice("첫 번째 인스턴스") - vm2.logNotice("두 번째 인스턴스") - vm1.logNotice("다시 첫 번째") - vm2.logNotice("다시 두 번째") - - // 크래시 없이 정상 동작하면 성공 - #expect(true) - } -} diff --git a/MLS/Data/.DS_Store b/MLS/Data/.DS_Store deleted file mode 100644 index 6cc22ba6..00000000 Binary files a/MLS/Data/.DS_Store and /dev/null differ diff --git a/MLS/Data/Data.xcodeproj/project.pbxproj b/MLS/Data/Data.xcodeproj/project.pbxproj deleted file mode 100644 index d8c34ba4..00000000 --- a/MLS/Data/Data.xcodeproj/project.pbxproj +++ /dev/null @@ -1,652 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 77; - objects = { - -/* Begin PBXBuildFile section */ - 080175492DCD274B00D0919F /* DomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 080175482DCD274B00D0919F /* DomainInterface.framework */; }; - 084A25C82DB93E0500C395C0 /* Core.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 084A25C72DB93E0500C395C0 /* Core.framework */; }; - 08E425522DF17B5C00D6ACD3 /* DomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08E425512DF17B5C00D6ACD3 /* DomainInterface.framework */; }; - 08E425562DF17B6300D6ACD3 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 08E425552DF17B6300D6ACD3 /* RxSwift */; }; - 08ED49342DCFDF78002C21A2 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 08ED49332DCFDF78002C21A2 /* RxSwift */; }; - 775D78522E0DA93400DDAD2F /* Data.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0879294D2DB90F3A009C301F /* Data.framework */; }; - 77660F932DD259AA007A4EF3 /* KakaoSDKAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 77660F922DD259AA007A4EF3 /* KakaoSDKAuth */; }; - 77660F952DD259AA007A4EF3 /* KakaoSDKUser in Frameworks */ = {isa = PBXBuildFile; productRef = 77660F942DD259AA007A4EF3 /* KakaoSDKUser */; }; - 77F0E9522EA525CE007368F8 /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 77F0E9512EA525CE007368F8 /* RxCocoa */; }; - 77FEEF222EC5B2300023197A /* AuthFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77FEEF202EC5B2300023197A /* AuthFeatureInterface.framework */; }; - 77FEEF242EC5B2300023197A /* DictionaryFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77FEEF212EC5B2300023197A /* DictionaryFeatureInterface.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 775D78542E0DA93400DDAD2F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 087929442DB90F3A009C301F /* Project object */; - proxyType = 1; - remoteGlobalIDString = 0879294C2DB90F3A009C301F; - remoteInfo = Data; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 080175482DCD274B00D0919F /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 084A256E2DB93C1400C395C0 /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 084A25722DB93C1900C395C0 /* MLSCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MLSCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 084A25C72DB93E0500C395C0 /* Core.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Core.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 0879294D2DB90F3A009C301F /* Data.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Data.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 08E4253B2DF17B3700D6ACD3 /* DataMock.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DataMock.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 08E425512DF17B5C00D6ACD3 /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77FEEF202EC5B2300023197A /* AuthFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AuthFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77FEEF212EC5B2300023197A /* DictionaryFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DictionaryFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFileSystemSynchronizedRootGroup section */ - 0879294F2DB90F3A009C301F /* Data */ = { - isa = PBXFileSystemSynchronizedRootGroup; - path = Data; - sourceTree = ""; - }; - 08E4253C2DF17B3700D6ACD3 /* DataMock */ = { - isa = PBXFileSystemSynchronizedRootGroup; - path = DataMock; - sourceTree = ""; - }; -/* End PBXFileSystemSynchronizedRootGroup section */ - -/* Begin PBXFrameworksBuildPhase section */ - 0879294A2DB90F3A009C301F /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 08ED49342DCFDF78002C21A2 /* RxSwift in Frameworks */, - 080175492DCD274B00D0919F /* DomainInterface.framework in Frameworks */, - 084A25C82DB93E0500C395C0 /* Core.framework in Frameworks */, - 77660F952DD259AA007A4EF3 /* KakaoSDKUser in Frameworks */, - 77660F932DD259AA007A4EF3 /* KakaoSDKAuth in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 08E425382DF17B3700D6ACD3 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 775D78522E0DA93400DDAD2F /* Data.framework in Frameworks */, - 08E425562DF17B6300D6ACD3 /* RxSwift in Frameworks */, - 77F0E9522EA525CE007368F8 /* RxCocoa in Frameworks */, - 77FEEF242EC5B2300023197A /* DictionaryFeatureInterface.framework in Frameworks */, - 77FEEF222EC5B2300023197A /* AuthFeatureInterface.framework in Frameworks */, - 08E425522DF17B5C00D6ACD3 /* DomainInterface.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 084A256D2DB93C1400C395C0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 77FEEF202EC5B2300023197A /* AuthFeatureInterface.framework */, - 77FEEF212EC5B2300023197A /* DictionaryFeatureInterface.framework */, - 08E425512DF17B5C00D6ACD3 /* DomainInterface.framework */, - 080175482DCD274B00D0919F /* DomainInterface.framework */, - 084A25C72DB93E0500C395C0 /* Core.framework */, - 084A25722DB93C1900C395C0 /* MLSCore.framework */, - 084A256E2DB93C1400C395C0 /* DomainInterface.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 087929432DB90F3A009C301F = { - isa = PBXGroup; - children = ( - 0879294F2DB90F3A009C301F /* Data */, - 08E4253C2DF17B3700D6ACD3 /* DataMock */, - 084A256D2DB93C1400C395C0 /* Frameworks */, - 0879294E2DB90F3A009C301F /* Products */, - ); - sourceTree = ""; - }; - 0879294E2DB90F3A009C301F /* Products */ = { - isa = PBXGroup; - children = ( - 0879294D2DB90F3A009C301F /* Data.framework */, - 08E4253B2DF17B3700D6ACD3 /* DataMock.framework */, - ); - name = Products; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 087929482DB90F3A009C301F /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 08E425362DF17B3700D6ACD3 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 0879294C2DB90F3A009C301F /* Data */ = { - isa = PBXNativeTarget; - buildConfigurationList = 087929532DB90F3A009C301F /* Build configuration list for PBXNativeTarget "Data" */; - buildPhases = ( - 087929482DB90F3A009C301F /* Headers */, - 087929492DB90F3A009C301F /* Sources */, - 0879294A2DB90F3A009C301F /* Frameworks */, - 0879294B2DB90F3A009C301F /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - fileSystemSynchronizedGroups = ( - 0879294F2DB90F3A009C301F /* Data */, - ); - name = Data; - packageProductDependencies = ( - 08ED49332DCFDF78002C21A2 /* RxSwift */, - 77660F922DD259AA007A4EF3 /* KakaoSDKAuth */, - 77660F942DD259AA007A4EF3 /* KakaoSDKUser */, - ); - productName = Data; - productReference = 0879294D2DB90F3A009C301F /* Data.framework */; - productType = "com.apple.product-type.framework"; - }; - 08E4253A2DF17B3700D6ACD3 /* DataMock */ = { - isa = PBXNativeTarget; - buildConfigurationList = 08E4254B2DF17B3700D6ACD3 /* Build configuration list for PBXNativeTarget "DataMock" */; - buildPhases = ( - 08E425362DF17B3700D6ACD3 /* Headers */, - 08E425372DF17B3700D6ACD3 /* Sources */, - 08E425382DF17B3700D6ACD3 /* Frameworks */, - 08E425392DF17B3700D6ACD3 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 775D78552E0DA93400DDAD2F /* PBXTargetDependency */, - ); - fileSystemSynchronizedGroups = ( - 08E4253C2DF17B3700D6ACD3 /* DataMock */, - ); - name = DataMock; - packageProductDependencies = ( - 08E425552DF17B6300D6ACD3 /* RxSwift */, - 77F0E9512EA525CE007368F8 /* RxCocoa */, - ); - productName = DataMock; - productReference = 08E4253B2DF17B3700D6ACD3 /* DataMock.framework */; - productType = "com.apple.product-type.framework"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 087929442DB90F3A009C301F /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1620; - LastUpgradeCheck = 1620; - TargetAttributes = { - 0879294C2DB90F3A009C301F = { - CreatedOnToolsVersion = 16.2; - }; - 08E4253A2DF17B3700D6ACD3 = { - CreatedOnToolsVersion = 16.2; - LastSwiftMigration = 1620; - }; - }; - }; - buildConfigurationList = 087929472DB90F3A009C301F /* Build configuration list for PBXProject "Data" */; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 087929432DB90F3A009C301F; - minimizedProjectReferenceProxies = 1; - packageReferences = ( - 0858ABFE2DCFDC340060EBCA /* XCRemoteSwiftPackageReference "RxSwift" */, - 77660F912DD259AA007A4EF3 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */, - ); - preferredProjectObjectVersion = 77; - productRefGroup = 0879294E2DB90F3A009C301F /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 0879294C2DB90F3A009C301F /* Data */, - 08E4253A2DF17B3700D6ACD3 /* DataMock */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 0879294B2DB90F3A009C301F /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 08E425392DF17B3700D6ACD3 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 087929492DB90F3A009C301F /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 08E425372DF17B3700D6ACD3 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 775D78552E0DA93400DDAD2F /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 0879294C2DB90F3A009C301F /* Data */; - targetProxy = 775D78542E0DA93400DDAD2F /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 087929542DB90F3A009C301F /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.Data; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 087929552DB90F3A009C301F /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.Data; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; - 087929562DB90F3A009C301F /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.2; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 087929572DB90F3A009C301F /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.2; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 08E4254C2DF17B3700D6ACD3 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALLOW_TARGET_PLATFORM_SPECIALIZATION = NO; - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = ( - "@executable_path/../Frameworks", - "@loader_path/Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 15.2; - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.DataMock; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SDKROOT = auto; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - XROS_DEPLOYMENT_TARGET = 2.2; - }; - name = Debug; - }; - 08E4254D2DF17B3700D6ACD3 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALLOW_TARGET_PLATFORM_SPECIALIZATION = NO; - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = ( - "@executable_path/../Frameworks", - "@loader_path/Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 15.2; - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.DataMock; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SDKROOT = auto; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - XROS_DEPLOYMENT_TARGET = 2.2; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 087929472DB90F3A009C301F /* Build configuration list for PBXProject "Data" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 087929562DB90F3A009C301F /* Debug */, - 087929572DB90F3A009C301F /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 087929532DB90F3A009C301F /* Build configuration list for PBXNativeTarget "Data" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 087929542DB90F3A009C301F /* Debug */, - 087929552DB90F3A009C301F /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 08E4254B2DF17B3700D6ACD3 /* Build configuration list for PBXNativeTarget "DataMock" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 08E4254C2DF17B3700D6ACD3 /* Debug */, - 08E4254D2DF17B3700D6ACD3 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - 0858ABFE2DCFDC340060EBCA /* XCRemoteSwiftPackageReference "RxSwift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ReactiveX/RxSwift"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 6.9.0; - }; - }; - 77660F912DD259AA007A4EF3 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/kakao/kakao-ios-sdk"; - requirement = { - branch = master; - kind = branch; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 08E425552DF17B6300D6ACD3 /* RxSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 0858ABFE2DCFDC340060EBCA /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxSwift; - }; - 08ED49332DCFDF78002C21A2 /* RxSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 0858ABFE2DCFDC340060EBCA /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxSwift; - }; - 77660F922DD259AA007A4EF3 /* KakaoSDKAuth */ = { - isa = XCSwiftPackageProductDependency; - package = 77660F912DD259AA007A4EF3 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; - productName = KakaoSDKAuth; - }; - 77660F942DD259AA007A4EF3 /* KakaoSDKUser */ = { - isa = XCSwiftPackageProductDependency; - package = 77660F912DD259AA007A4EF3 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; - productName = KakaoSDKUser; - }; - 77F0E9512EA525CE007368F8 /* RxCocoa */ = { - isa = XCSwiftPackageProductDependency; - package = 0858ABFE2DCFDC340060EBCA /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxCocoa; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 087929442DB90F3A009C301F /* Project object */; -} diff --git a/MLS/Data/Data/.DS_Store b/MLS/Data/Data/.DS_Store deleted file mode 100644 index caa2177c..00000000 Binary files a/MLS/Data/Data/.DS_Store and /dev/null differ diff --git a/MLS/Data/Data/Errors/NetworkError.swift b/MLS/Data/Data/Errors/NetworkError.swift deleted file mode 100644 index 203220d5..00000000 --- a/MLS/Data/Data/Errors/NetworkError.swift +++ /dev/null @@ -1,39 +0,0 @@ -import Foundation - -/// 네트워크 레이어에서 사용하는 에러 -public enum NetworkError: Error, Equatable { - case providerDeallocated - case urlRequest(Error) - case network(Error) - case invalidResponse - case noData - case decodeError(Error) - case httpError - case retryError(Error) - case statusError(Int, String) - case retry - - public static func == (lhs: NetworkError, rhs: NetworkError) -> Bool { - switch (lhs, rhs) { - case (.providerDeallocated, .providerDeallocated), - (.invalidResponse, .invalidResponse), - (.noData, .noData), - (.httpError, .httpError), - (.retry, .retry): - return true - - case let (.statusError(code1, msg1), .statusError(code2, msg2)): - return code1 == code2 && msg1 == msg2 - - // 연관된 Error 타입은 Equatable이 아니므로 항상 false로 비교 (혹은 타입 이름 비교 정도만 가능) - case (.urlRequest, .urlRequest), - (.network, .network), - (.decodeError, .decodeError), - (.retryError, .retryError): - return false - - default: - return false - } - } -} diff --git a/MLS/Data/Data/Network/.DS_Store b/MLS/Data/Data/Network/.DS_Store deleted file mode 100644 index a57661e1..00000000 Binary files a/MLS/Data/Data/Network/.DS_Store and /dev/null differ diff --git a/MLS/Data/Data/Network/DTO/AlarmDTO/AlarmResponseDTO.swift b/MLS/Data/Data/Network/DTO/AlarmDTO/AlarmResponseDTO.swift deleted file mode 100644 index 519a8084..00000000 --- a/MLS/Data/Data/Network/DTO/AlarmDTO/AlarmResponseDTO.swift +++ /dev/null @@ -1,91 +0,0 @@ -import DomainInterface - -public struct AlarmResponseDTO: Decodable { - public let contents: [Content] - public let hasMore: Bool - - public enum Content: Decodable { - case normal(NormalContent) - case all(AllContent) - - public init(from decoder: Decoder) throws { - let container = try decoder.singleValueContainer() - - if let normal = try? container.decode(NormalContent.self) { - self = .normal(normal) - return - } - - if let all = try? container.decode(AllContent.self) { - self = .all(all) - return - } - - throw DecodingError.typeMismatch( - Content.self, - DecodingError.Context( - codingPath: decoder.codingPath, - debugDescription: "Content type not matched" - ) - ) - } - } - - public struct NormalContent: Decodable { - public let id: Int - public let type: String - public let title: String - public let link: String - public let date: String - } - - public struct AllContent: Decodable { - public let alrim: NormalContent - public let alreadyRead: Bool - } -} - -public extension AlarmResponseDTO { - func toAlarmDomain() -> PagedEntity { - let alarms = contents.compactMap { content -> AlarmResponse? in - switch content { - case .normal(let normal): - return AlarmResponse( - id: normal.id, - type: normal.type, - title: normal.title, - link: normal.link, - date: normal.date - ) - case .all(let all): - return AlarmResponse( - id: all.alrim.id, - type: all.alrim.type, - title: all.alrim.title, - link: all.alrim.link, - date: all.alrim.date - ) - } - } - return PagedEntity(items: alarms, hasMore: hasMore) - } - - func toAllAlarmDomain() -> PagedEntity { - let allAlarms = contents.compactMap { content -> AllAlarmResponse? in - switch content { - case .all(let all): - return AllAlarmResponse( - id: all.alrim.id, - type: all.alrim.type, - title: all.alrim.title, - link: all.alrim.link, - date: all.alrim.date, - alreadyRead: all.alreadyRead - ) - case .normal: - return nil - } - } - return PagedEntity(items: allAlarms, hasMore: hasMore) - } -} diff --git a/MLS/Data/Data/Network/DTO/AuthDTO/AuthResponseDTO.swift b/MLS/Data/Data/Network/DTO/AuthDTO/AuthResponseDTO.swift deleted file mode 100644 index c3b86950..00000000 --- a/MLS/Data/Data/Network/DTO/AuthDTO/AuthResponseDTO.swift +++ /dev/null @@ -1,24 +0,0 @@ -import DomainInterface - -public struct AuthResponseDTO: Decodable { - public let accessToken: String - public let refreshToken: String - public let member: MemberDTO? -} - -public extension AuthResponseDTO { - func toLoginDomain() -> LoginResponse { - return .init( - isRegister: member != nil, - accessToken: accessToken, - refreshToken: refreshToken - ) - } - - func toSignUpDomain() -> SignUpResponse { - return .init( - accessToken: accessToken, - refreshToken: refreshToken - ) - } -} diff --git a/MLS/Data/Data/Network/DTO/AuthDTO/JobsDTO.swift b/MLS/Data/Data/Network/DTO/AuthDTO/JobsDTO.swift deleted file mode 100644 index 3fa00f59..00000000 --- a/MLS/Data/Data/Network/DTO/AuthDTO/JobsDTO.swift +++ /dev/null @@ -1,23 +0,0 @@ -import DomainInterface - -public struct JobsDTO: Decodable { - public let jobId: Int - public let jobName: String - public let jobLevel: Int - public let parentJobId: Int? -} - -public extension JobsDTO { - func toDomain() -> Job { - return Job(name: jobName, id: jobId) - } -} - -public extension Array where Element == JobsDTO { - func toDomain() -> JobListResponse { - let jobs = self - .filter { $0.jobLevel == 0 } - .map { Job(name: $0.jobName, id: $0.jobId) } - return JobListResponse(jobList: jobs) - } -} diff --git a/MLS/Data/Data/Network/DTO/AuthDTO/MemberDTO.swift b/MLS/Data/Data/Network/DTO/AuthDTO/MemberDTO.swift deleted file mode 100644 index 5126bcd5..00000000 --- a/MLS/Data/Data/Network/DTO/AuthDTO/MemberDTO.swift +++ /dev/null @@ -1,30 +0,0 @@ -import DomainInterface - -public struct MemberDTO: Decodable { - public let id: String - public let provider: String - public let nickname: String - public let fcmToken: String? - public let marketingAgreement: Bool? - public let noticeAgreement: Bool? - public let patchNoteAgreement: Bool? - public let eventAgreement: Bool? - public let jobId: Int? - public let level: Int? - public let profileImageUrl: String - - func toMyPageDomain() -> MyPageResponse { - return .init( - nickname: nickname, - jobId: jobId, - jobName: "", - level: level, - profileUrl: profileImageUrl, - platform: provider == "APPLE" ? .apple : .kakao, - noticeAgreement: noticeAgreement, - patchNoteAgreement: patchNoteAgreement, - eventAgreement: eventAgreement - ) - } - -} diff --git a/MLS/Data/Data/Network/DTO/BookmarkDTO/BookmarkDTO.swift b/MLS/Data/Data/Network/DTO/BookmarkDTO/BookmarkDTO.swift deleted file mode 100644 index 277fc720..00000000 --- a/MLS/Data/Data/Network/DTO/BookmarkDTO/BookmarkDTO.swift +++ /dev/null @@ -1,30 +0,0 @@ -import DomainInterface - -public struct BookmarkDTO: Decodable { - public let bookmarkId: Int - public let originalId: Int - public let name: String - public let imageUrl: String - public let type: String - public let level: Int? - - public func toDomain() -> BookmarkResponse? { - guard let type = DictionaryItemType(rawValue: type) else { - return nil - } - return BookmarkResponse( - name: name, - bookmarkId: bookmarkId, - originalId: originalId, - imageUrl: imageUrl, - type: type, - level: level - ) - } -} - -extension Array where Element == BookmarkDTO { - func toDomain() -> [BookmarkResponse] { - return self.compactMap { $0.toDomain() } - } -} diff --git a/MLS/Data/Data/Network/DTO/BookmarkDTO/SetBookmarkDTO.swift b/MLS/Data/Data/Network/DTO/BookmarkDTO/SetBookmarkDTO.swift deleted file mode 100644 index bb287fbb..00000000 --- a/MLS/Data/Data/Network/DTO/BookmarkDTO/SetBookmarkDTO.swift +++ /dev/null @@ -1,11 +0,0 @@ -import DomainInterface - -public struct SetBookmarkDTO: Decodable { - public let bookmarkId: Int - public let bookmarkType: String - public let resourceId: Int - - public func toDomain() -> Int { - return self.bookmarkId - } -} diff --git a/MLS/Data/Data/Network/DTO/CollectionDTO/CollectionListResponseDTO.swift b/MLS/Data/Data/Network/DTO/CollectionDTO/CollectionListResponseDTO.swift deleted file mode 100644 index 24b01d40..00000000 --- a/MLS/Data/Data/Network/DTO/CollectionDTO/CollectionListResponseDTO.swift +++ /dev/null @@ -1,12 +0,0 @@ -import DomainInterface - -public struct CollectionListResponseDTO: Decodable { - public let collectionId: Int - public let name: String - public let createdAt: [Int] - public let recentBookmarks: [BookmarkDTO] - - public func toDomain() -> CollectionResponse { - return CollectionResponse(collectionId: collectionId, name: name, createdAt: createdAt, recentBookmarks: recentBookmarks.toDomain()) - } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryAllDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryAllDTO.swift deleted file mode 100644 index 074cd7fe..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryAllDTO.swift +++ /dev/null @@ -1,9 +0,0 @@ -public struct DictionaryAllDTO: DictionaryDTOProtocol { - public let originalId: Int - public let name: String - public let imageUrl: String? - public let level: Int? - public let type: String - public let bookmarkId: Int? - public var id: Int { originalId } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryDTOProtocol.swift b/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryDTOProtocol.swift deleted file mode 100644 index ff3457a2..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryDTOProtocol.swift +++ /dev/null @@ -1,28 +0,0 @@ -import DomainInterface - -public protocol DictionaryDTOProtocol: Decodable { - var id: Int { get } - var name: String { get } - var imageUrl: String? { get } - var level: Int? { get } - var type: String { get } - var bookmarkId: Int? { get } - - func toDomain() -> DictionaryMainItemResponse? -} - -extension DictionaryDTOProtocol { - public func toDomain() -> DictionaryMainItemResponse? { - if let type = DictionaryItemType(rawValue: type) { - return DictionaryMainItemResponse( - id: id, - name: name, - imageUrl: imageUrl, level: level, - type: type, - bookmarkId: bookmarkId - ) - } else { - return nil - } - } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryItemDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryItemDTO.swift deleted file mode 100644 index 9d5de1f3..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryItemDTO.swift +++ /dev/null @@ -1,9 +0,0 @@ -public struct DictionaryItemDTO: DictionaryDTOProtocol { - public let itemId: Int - public let name: String - public let imageUrl: String? - public let level: Int? - public let type: String - public let bookmarkId: Int? - public var id: Int { itemId } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryMapDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryMapDTO.swift deleted file mode 100644 index 00e44cd9..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryMapDTO.swift +++ /dev/null @@ -1,9 +0,0 @@ -public struct DictionaryMapDTO: DictionaryDTOProtocol { - public let mapId: Int - public let name: String - public let imageUrl: String? - public let level: Int? - public let type: String - public let bookmarkId: Int? - public var id: Int { mapId } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryMonsterDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryMonsterDTO.swift deleted file mode 100644 index 86e39644..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryMonsterDTO.swift +++ /dev/null @@ -1,9 +0,0 @@ -public struct DictionaryMonsterDTO: DictionaryDTOProtocol { - public let monsterId: Int - public let name: String - public let imageUrl: String? - public let level: Int? - public let type: String - public let bookmarkId: Int? - public var id: Int { monsterId } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryNPCDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryNPCDTO.swift deleted file mode 100644 index 9ce8ea14..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryNPCDTO.swift +++ /dev/null @@ -1,9 +0,0 @@ -public struct DictionaryNPCDTO: DictionaryDTOProtocol { - public let npcId: Int - public let name: String - public let imageUrl: String? - public let level: Int? - public let type: String - public let bookmarkId: Int? - public var id: Int { npcId } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryQuestDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryQuestDTO.swift deleted file mode 100644 index 7382ac99..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDTO/DictionaryQuestDTO.swift +++ /dev/null @@ -1,9 +0,0 @@ -public struct DictionaryQuestDTO: DictionaryDTOProtocol { - public let questId: Int - public let name: String - public let imageUrl: String? - public let level: Int? - public let type: String - public let bookmarkId: Int? - public var id: Int { questId } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Item/DictionaryDetailItemDropMonsterResponseDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Item/DictionaryDetailItemDropMonsterResponseDTO.swift deleted file mode 100644 index f92a5868..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Item/DictionaryDetailItemDropMonsterResponseDTO.swift +++ /dev/null @@ -1,13 +0,0 @@ -import DomainInterface - -public struct DictionaryDetailItemDropMonsterResponseDTO: Decodable { - public let monsterId: Int? - public let monsterName: String? - public let level: Int? - public let dropRate: Double? - public let imageUrl: String? - - public func toDomain() -> DictionaryDetailItemDropMonsterResponse { - return DictionaryDetailItemDropMonsterResponse(monsterId: monsterId, monsterName: monsterName, level: level, dropRate: dropRate, imageUrl: imageUrl) - } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Item/DictionaryDetailItemResponseDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Item/DictionaryDetailItemResponseDTO.swift deleted file mode 100644 index 2cf32564..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Item/DictionaryDetailItemResponseDTO.swift +++ /dev/null @@ -1,35 +0,0 @@ -import DomainInterface - -public struct DictionaryDetailItemResponseDTO: Decodable { - public let itemId: Int - public let nameKr: String? - public let nameEn: String? - public let descriptionText: String? - public let itemImageUrl: String? - public let npcPrice: Int? - public let itemType: String? - public let categoryHierachy: CategoryHierachy? - public let availableJobs: [Jobs]? - public let requiredStats: RequiredStats? // 요구 스탯 - public let equipmentStats: EquipmentStats? // 착용하면 올라가는 스탯 - public let scrollDetail: ScrollDetail? // 주문서 상세정보 - public let bookmarkId: Int? - - public func toDomain() -> DictionaryDetailItemResponse { - return DictionaryDetailItemResponse( - itemId: itemId, - nameKr: nameKr, - nameEn: nameEn, - descriptionText: descriptionText, - imgUrl: itemImageUrl, - npcPrice: npcPrice, - itemType: itemType, - categoryHierachy: categoryHierachy, - availableJobs: availableJobs, - requiredStats: requiredStats, - equipmentStats: equipmentStats, - scrollDetail: scrollDetail, - bookmarkId: bookmarkId - ) - } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Map/DictionaryDetailMapNpcResponseDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Map/DictionaryDetailMapNpcResponseDTO.swift deleted file mode 100644 index 0d3a5469..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Map/DictionaryDetailMapNpcResponseDTO.swift +++ /dev/null @@ -1,12 +0,0 @@ -import DomainInterface - -public struct DictionaryDetailMapNpcResponseDTO: Decodable { - public let npcId: Int? - public let npcName: String? - public let npcNameEn: String? - public let iconUrl: String? - - public func toDomain() -> DictionaryDetailMapNpcResponse { - return DictionaryDetailMapNpcResponse(npcId: npcId, npcName: npcName, npcNameEn: npcNameEn, iconUrl: iconUrl) - } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Map/DictionaryDetailMapResponseDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Map/DictionaryDetailMapResponseDTO.swift deleted file mode 100644 index 653158e9..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Map/DictionaryDetailMapResponseDTO.swift +++ /dev/null @@ -1,17 +0,0 @@ -import DomainInterface - -public struct DictionaryDetailMapResponseDTO: Decodable { - public let mapId: Int - public let nameKr: String? - public let nameEn: String? - public let regionName: String? - public let detailName: String? - public let topRegionName: String? - public let mapUrl: String? - public let iconUrl: String? - public let bookmarkId: Int? - - public func toDomain() -> DictionaryDetailMapResponse { - return DictionaryDetailMapResponse(mapId: mapId, nameKr: nameKr, nameEn: nameEn, regionName: regionName, detailName: detailName, topRegionName: topRegionName, mapUrl: mapUrl, iconUrl: iconUrl, bookmarkId: bookmarkId) - } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Map/DictionaryDetailMapSpawnMonsterResponseDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Map/DictionaryDetailMapSpawnMonsterResponseDTO.swift deleted file mode 100644 index a0b7c376..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Map/DictionaryDetailMapSpawnMonsterResponseDTO.swift +++ /dev/null @@ -1,13 +0,0 @@ -import DomainInterface - -public struct DictionaryDetailMapSpawnMonsterResponseDTO: Decodable { - public let monsterId: Int? - public let monsterName: String? - public let level: Int? - public let maxSpawnCount: Int? - public let imageUrl: String? - - public func toDomain() -> DictionaryDetailMapSpawnMonsterResponse { - return DictionaryDetailMapSpawnMonsterResponse(monsterId: monsterId, monsterName: monsterName, level: level, maxSpawnCount: maxSpawnCount, imageUrl: imageUrl) - } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Monster/DictionaryDetailMonsterDropItemResponseDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Monster/DictionaryDetailMonsterDropItemResponseDTO.swift deleted file mode 100644 index 13e85308..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Monster/DictionaryDetailMonsterDropItemResponseDTO.swift +++ /dev/null @@ -1,13 +0,0 @@ -import DomainInterface - -public struct DictionaryDetailMonsterDropItemResponseDTO: Decodable { - public let itemId: Int - public let itemName: String - public let dropRate: Double - public let imageUrl: String - public let itemLevel: Int - - public func toDomain() -> DictionaryDetailMonsterDropItemResponse { - DictionaryDetailMonsterDropItemResponse(itemId: itemId, itemName: itemName, dropRate: dropRate, imageUrl: imageUrl, itemLevel: itemLevel) - } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Monster/DictionaryDetailMonsterMapResponseDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Monster/DictionaryDetailMonsterMapResponseDTO.swift deleted file mode 100644 index e34e5920..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Monster/DictionaryDetailMonsterMapResponseDTO.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -public struct DictionaryDetailMonsterMapResponseDTO: Decodable { - public let mapId: Int - public let mapName: String - public let regionName: String - public let detailName: String - public let topRegionName: String - public let iconUrl: String - public let maxSpawnCount: Int? - - public func toDomain() -> DictionaryDetailMonsterMapResponse { - return DictionaryDetailMonsterMapResponse(mapId: mapId, mapName: mapName, regionName: regionName, detailName: detailName, topRegionName: topRegionName, iconUrl: iconUrl, maxSpawnCount: maxSpawnCount) - } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Monster/DictionaryDetailMonsterResponseDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Monster/DictionaryDetailMonsterResponseDTO.swift deleted file mode 100644 index b094b332..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Monster/DictionaryDetailMonsterResponseDTO.swift +++ /dev/null @@ -1,43 +0,0 @@ -import DomainInterface - -public struct DictionaryDetailMonsterResponseDTO: Decodable { - public let monsterId: Int - public let nameKr: String - public let nameEn: String - public let imageUrl: String - public let level: Int - public let exp: Int - public let hp: Int - public let mp: Int - public let physicalDefense: Int - public let magicDefense: Int - public let requiredAccuracy: Int - public let bonusAccuracyPerLevelLower: Double - public let evasionRate: Int - public let mesoDropAmount: Int? - public let mesoDropRate: Int? - public let typeEffectiveness: Effectiveness? - public let bookmarkId: Int? - - public func toDomain() -> DictionaryDetailMonsterResponse { - return DictionaryDetailMonsterResponse( - monsterId: monsterId, - nameKr: nameKr, - nameEn: nameEn, - imageUrl: imageUrl, - level: level, - exp: exp, - hp: hp, - mp: mp, - physicalDefense: physicalDefense, - magicDefense: magicDefense, - requiredAccuracy: requiredAccuracy, - bonusAccuracyPerLevelLower: bonusAccuracyPerLevelLower, - evasionRate: evasionRate, - mesoDropAmount: mesoDropAmount, - mesoDropRate: mesoDropRate, - typeEffectiveness: typeEffectiveness, - bookmarkId: bookmarkId - ) - } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Npc/DictionaryDetailNpcQuestResponseDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Npc/DictionaryDetailNpcQuestResponseDTO.swift deleted file mode 100644 index 582eb0e2..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Npc/DictionaryDetailNpcQuestResponseDTO.swift +++ /dev/null @@ -1,14 +0,0 @@ -import DomainInterface - -public struct DictionaryDetailNpcQuestResponseDTO: Decodable { - public let questId: Int - public let questNameKr: String - public let questNameEn: String - public let questIconUrl: String - public let minLevel: Int? - public let maxLevel: Int? - - public func toDomain() -> DictionaryDetailNpcQuestResponse { - return DictionaryDetailNpcQuestResponse(questId: questId, questNameKr: questNameKr, questNameEn: questNameEn, questIconUrl: questIconUrl, minLevel: minLevel, maxLevel: maxLevel) - } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Npc/DictionaryDetailNpcResponseDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Npc/DictionaryDetailNpcResponseDTO.swift deleted file mode 100644 index ad3b8027..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Npc/DictionaryDetailNpcResponseDTO.swift +++ /dev/null @@ -1,13 +0,0 @@ -import DomainInterface - -public struct DictionaryDetailNpcResponseDTO: Decodable { - public let npcId: Int - public let nameKr: String - public let nameEn: String - public let iconUrlDetail: String? - public let bookmarkId: Int? - - public func toDomain() -> DictionaryDetailNpcResponse { - return DictionaryDetailNpcResponse(npcId: npcId, nameKr: nameKr, nameEn: nameEn, iconUrlDetail: iconUrlDetail, bookmarkId: bookmarkId) - } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Quest/DictionaryDetailQuestLinkedQuestsResponseDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Quest/DictionaryDetailQuestLinkedQuestsResponseDTO.swift deleted file mode 100644 index b34302f7..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Quest/DictionaryDetailQuestLinkedQuestsResponseDTO.swift +++ /dev/null @@ -1,10 +0,0 @@ -import DomainInterface - -public struct DictionaryDetailQuestLinkedQuestsResponseDTO: Decodable { - public let previousQuests: [Quest]? - public let nextQuests: [Quest]? - - public func toDomain() -> DictionaryDetailQuestLinkedQuestsResponse { - return DictionaryDetailQuestLinkedQuestsResponse(previousQuests: previousQuests, nextQuests: nextQuests) - } -} diff --git a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Quest/DictionaryDetailQuestResponseDTO.swift b/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Quest/DictionaryDetailQuestResponseDTO.swift deleted file mode 100644 index e79a4294..00000000 --- a/MLS/Data/Data/Network/DTO/DictionaryDetailDTO/Quest/DictionaryDetailQuestResponseDTO.swift +++ /dev/null @@ -1,45 +0,0 @@ -import DomainInterface - -public struct DictionaryDetailQuestResponseDTO: Decodable { - public let questId: Int - public let titlePrefix: String? - public let nameKr: String? - public let nameEn: String? - public let iconUrl: String? - public let questType: String? - public let minLevel: Int? - public let maxLevel: Int? - public let requiredMesoStart: Int? - public let startNpcId: Int? - public let startNpcName: String? - public let endNpcId: Int? - public let endNpcName: String? - public let reward: Reward? - public let rewardItems: [RewardItem]? - public let requirements: [Requirements]? - public let allowedJobs: [AllowedJob]? - public let bookmarkId: Int? - - public func toDomain() -> DictionaryDetailQuestResponse { - return DictionaryDetailQuestResponse( - questId: questId, - titlePrefix: titlePrefix, - nameKr: nameKr, - nameEn: nameEn, - iconUrl: iconUrl, - questType: questType, - minLevel: minLevel, - maxLevel: maxLevel, - requiredMesoStart: requiredMesoStart, - startNpcId: startNpcId, - startNpcName: startNpcName, - endNpcId: endNpcId, - endNpcName: endNpcName, - reward: reward, - rewardItems: rewardItems, - requirements: requirements, - allowedJobs: allowedJobs, - bookmarkId: bookmarkId - ) - } -} diff --git a/MLS/Data/Data/Network/DTO/PagedListResponseDTO.swift b/MLS/Data/Data/Network/DTO/PagedListResponseDTO.swift deleted file mode 100644 index d16b2813..00000000 --- a/MLS/Data/Data/Network/DTO/PagedListResponseDTO.swift +++ /dev/null @@ -1,17 +0,0 @@ -import DomainInterface - -public struct PagedListResponseDTO: Decodable { - public let totalPages: Int - public let totalElements: Int - public let content: [Item] -} - -extension PagedListResponseDTO where Item: DictionaryDTOProtocol { - public func toDomain() -> DictionaryMainResponse { - DictionaryMainResponse( - totalPages: totalPages, - totalElements: totalElements, - contents: content.compactMap { $0.toDomain() } - ) - } -} diff --git a/MLS/Data/Data/Network/DTO/SearchCountDTO/SearchCountDTO.swift b/MLS/Data/Data/Network/DTO/SearchCountDTO/SearchCountDTO.swift deleted file mode 100644 index 885b5795..00000000 --- a/MLS/Data/Data/Network/DTO/SearchCountDTO/SearchCountDTO.swift +++ /dev/null @@ -1,9 +0,0 @@ -import DomainInterface - -public struct SearchCountDTO: Decodable { - public let counts: Int? - - public func toDomain() -> SearchCountResponse { - return SearchCountResponse(count: counts) - } -} diff --git a/MLS/Data/Data/Network/Endpoints/AlarmEndPoint.swift b/MLS/Data/Data/Network/Endpoints/AlarmEndPoint.swift deleted file mode 100644 index 3cf91795..00000000 --- a/MLS/Data/Data/Network/Endpoints/AlarmEndPoint.swift +++ /dev/null @@ -1,59 +0,0 @@ -import DomainInterface - -public enum AlarmEndPoint { - static let base = "https://mapleland.2megabytes.me" - - public static func fetchPatchNotes(query: Encodable) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v2/alrim/list/patch-notes", - method: .GET, - query: query - ) - } - - public static func fetchNotices(query: Encodable) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v2/alrim/list/notices", - method: .GET, - query: query - ) - } - - public static func fetchOutdatedEvents(query: Encodable) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v2/alrim/list/events/outdated", - method: .GET, - query: query - ) - } - - public static func fetchOngoingEvents(query: Encodable) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v2/alrim/list/events/ongoing", - method: .GET, - query: query - ) - } - - public static func fetchAll(query: Encodable) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v2/alrim/all", - method: .GET, - query: query - ) - } - - public static func setRead(query: Encodable) -> EndPoint { - .init( - baseURL: base, - path: "/api/v1/alrim/set-read", - method: .POST, - query: query - ) - } -} diff --git a/MLS/Data/Data/Network/Endpoints/AuthEndPoint.swift b/MLS/Data/Data/Network/Endpoints/AuthEndPoint.swift deleted file mode 100644 index b9167db3..00000000 --- a/MLS/Data/Data/Network/Endpoints/AuthEndPoint.swift +++ /dev/null @@ -1,142 +0,0 @@ -import DomainInterface - -public enum AuthEndPoint { - static let base = "https://mapleland.2megabytes.me" - - public static func fetchProfile() -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v1/auth/me", - method: .GET - ) - } - - public static func loginWithKakao(credential: Credential) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v1/auth/login/kakao", - method: .POST, - headers: ["access-token": credential.token] - ) - } - - public static func loginWithApple(credential: Credential) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v1/auth/login/apple", - method: .POST, - headers: ["id-token": credential.token] - ) - } - - public static func signupWithKakao(credential: String, body: Encodable) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v1/auth/signup/kakao", - method: .POST, - headers: ["access-token": credential], - body: body - ) - } - - public static func signupWithApple(credential: String, body: Encodable) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v1/auth/signup/apple", - method: .POST, - headers: ["id-token": credential], - body: body - ) - } - - public static func reIssueToken(refreshToken: String) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v1/auth/reissue", - method: .POST, - headers: [ - "accept": "*/*", - "refresh-token": refreshToken - ] - ) - } - - public static func fcmToken(body: Encodable) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v1/auth/member/fcm-token", - method: .PUT, - body: body - ) - } - - public static func withdraw() -> EndPoint { - .init( - baseURL: base, - path: "/api/v1/auth/member", - method: .DELETE - ) - } - - public static func updateMarketingAgreement(credential: String, body: Encodable) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v1/auth/member/marketing-agreement", - method: .PUT, - headers: ["Authorization": "Bearer \(credential)"], - body: body - ) - } - - public static func fetchJobs() -> ResponsableEndPoint<[JobsDTO]> { - .init( - baseURL: base, - path: "/api/v1/jobs", - method: .GET - ) - } - - public static func fetchJob(jobId: String) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v1/jobs/\(jobId)", - method: .GET - ) - } - - public static func updateCharacterInfo(body: Encodable) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v1/auth/member/profile", - method: .PUT, - body: body - ) - } - - public static func updateNotification(body: Encodable) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v1/auth/member/alert-agreement", - method: .PUT, - body: body - ) - } - - public static func updateNickName(body: Encodable) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v1/auth/member/nickname", - method: .PUT, - body: body - ) - } - - public static func updateProfileImage(body: Encodable) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v1/auth/member/profile-image", - method: .PUT, - body: body - ) - } -} diff --git a/MLS/Data/Data/Network/Endpoints/BookmarkEndPoint.swift b/MLS/Data/Data/Network/Endpoints/BookmarkEndPoint.swift deleted file mode 100644 index 41373970..00000000 --- a/MLS/Data/Data/Network/Endpoints/BookmarkEndPoint.swift +++ /dev/null @@ -1,76 +0,0 @@ -import DomainInterface - -public enum BookmarkEndPoint { - static let base = "https://mapleland.2megabytes.me" - - public static func setBookmark(body: Encodable) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v1/bookmarks", - method: .POST, - body: body - ) - } - - public static func deleteBookmark(bookmarkId: Int) -> ResponsableEndPoint { - .init( - baseURL: base, - path: "/api/v1/bookmarks/\(bookmarkId)", - method: .DELETE - ) - } - - public static func fetchBookmark(query: Encodable) -> ResponsableEndPoint<[BookmarkDTO]> { - .init( - baseURL: base, - path: "/api/v1/bookmarks", - method: .GET, - query: query - ) - } - - public static func fetchMonsterBookmark(query: Encodable) -> ResponsableEndPoint<[BookmarkDTO]> { - .init( - baseURL: base, - path: "/api/v1/bookmarks/monsters", - method: .GET, - query: query - ) - } - - public static func fetchNPCBookmark(query: Encodable) -> ResponsableEndPoint<[BookmarkDTO]> { - .init( - baseURL: base, - path: "/api/v1/bookmarks/npcs", - method: .GET, - query: query - ) - } - - public static func fetchQuestBookmark(query: Encodable) -> ResponsableEndPoint<[BookmarkDTO]> { - .init( - baseURL: base, - path: "/api/v1/bookmarks/quests", - method: .GET, - query: query - ) - } - - public static func fetchItemBookmark(query: Encodable) -> ResponsableEndPoint<[BookmarkDTO]> { - .init( - baseURL: base, - path: "/api/v1/bookmarks/items", - method: .GET, - query: query - ) - } - - public static func fetchMapBookmark(query: Encodable) -> ResponsableEndPoint<[BookmarkDTO]> { - .init( - baseURL: base, - path: "/api/v1/bookmarks/maps", - method: .GET, - query: query - ) - } -} diff --git a/MLS/Data/Data/Network/Endpoints/CollectionEndPoint.swift b/MLS/Data/Data/Network/Endpoints/CollectionEndPoint.swift deleted file mode 100644 index dcdf838c..00000000 --- a/MLS/Data/Data/Network/Endpoints/CollectionEndPoint.swift +++ /dev/null @@ -1,52 +0,0 @@ -import DomainInterface - -public enum CollectionEndPoint { - static let base = "https://mapleland.2megabytes.me" - - public static func fetchCollectionList(query: Encodable) -> ResponsableEndPoint<[CollectionListResponseDTO]> { - .init( - baseURL: base, - path: "/api/v1/collections", - method: .GET, - query: query - ) - } - - public static func createCollectionList(body: Encodable) -> EndPoint { - .init(baseURL: base, path: "/api/v1/collections", method: .POST, body: body) - } - - public static func fetchCollection(id: Int) -> ResponsableEndPoint<[BookmarkDTO]> { - .init( - baseURL: base, - path: "/api/v1/collections/\(id)/bookmarks", - method: .GET - ) - } - - public static func setCollectionName(id: Int, body: Encodable) -> EndPoint { - .init( - baseURL: base, - path: "/api/v1/collections/\(id)", - method: .PUT, - body: body - ) - } - - public static func deleteCollection(id: Int) -> EndPoint { - .init( - baseURL: base, - path: "/api/v1/collections/\(id)", - method: .DELETE - ) - } - - public static func addCollectionAndBookmark(body: Encodable) -> EndPoint { - .init( - baseURL: base, - path: "/api/v1/bookmark-collections", - method: .POST, - body: body - ) - } -} diff --git a/MLS/Data/Data/Network/Endpoints/DictionaryDetailEndPoint.swift b/MLS/Data/Data/Network/Endpoints/DictionaryDetailEndPoint.swift deleted file mode 100644 index d71fd9c4..00000000 --- a/MLS/Data/Data/Network/Endpoints/DictionaryDetailEndPoint.swift +++ /dev/null @@ -1,69 +0,0 @@ -import Foundation -import UIKit - -import DomainInterface - -public enum DictionaryDetailEndPoint { - static let base = "https://mapleland.2megabytes.me" - - // 몬스터 디테일 상세정보 - public static func fetchMonsterDetail(id: Int) -> ResponsableEndPoint { - return .init(baseURL: base, path: "/api/v1/monsters/\(id)", method: .GET) - } - - // 몬스터 디테일 드롭아이템 - public static func fetchMonsterDetailDropItem(id: Int, query: Encodable) -> ResponsableEndPoint<[DictionaryDetailMonsterDropItemResponseDTO]> { - return .init(baseURL: base, path: "/api/v1/monsters/\(id)/items", method: .GET, query: query) - } - - // 몬스터 디테일 출현맵 - public static func fetchMonsterDetailMap(id: Int) -> ResponsableEndPoint<[DictionaryDetailMonsterMapResponseDTO]> { - return .init(baseURL: base, path: "/api/v1/monsters/\(id)/maps", method: .GET) - } - - // Npc 디테일 상세정보 - public static func fetchNpcDetail(id: Int) -> ResponsableEndPoint { - return .init(baseURL: base, path: "/api/v1/npcs/\(id)", method: .GET) - } - // Npc 디테일 퀘스트 - public static func fetchNpcDetailQuest(id: Int, query: Encodable) -> ResponsableEndPoint<[DictionaryDetailNpcQuestResponseDTO]> { - return .init(baseURL: base, path: "/api/v1/npcs/\(id)/quests", method: .GET, query: query) - } - // NPC 디테일 맵 - public static func fetchNpcDetailMap(id: Int) -> ResponsableEndPoint<[DictionaryDetailMonsterMapResponseDTO]> { - return .init(baseURL: base, path: "/api/v1/npcs/\(id)/maps", method: .GET) - } - // Item 디테일 상세정보 - public static func fetchItemDetail(id: Int) -> ResponsableEndPoint { - return .init(baseURL: base, path: "/api/v1/items/\(id)", method: .GET) - } - // Item 디테일 드롭몬스터 상세정보 - public static func fetchItemDetailDropMonster(id: Int, query: Encodable) -> ResponsableEndPoint<[DictionaryDetailItemDropMonsterResponseDTO]> { - return .init(baseURL: base, path: "/api/v1/items/\(id)/monsters", method: .GET, query: query) - } - - // Quest 디테일 상세정보 - public static func fetchQuestDetail(id: Int) -> ResponsableEndPoint { - return .init(baseURL: base, path: "/api/v1/quests/\(id)", method: .GET) - } - - // Quest 디테일 연계퀘스트 - public static func fetchQuestDetailLinkedQuests(id: Int) -> ResponsableEndPoint { - return .init(baseURL: base, path: "/api/v1/quests/\(id)/chain", method: .GET) - } - - // Map 디테일 상세정보 - public static func fetchMapDetail(id: Int) -> ResponsableEndPoint { - return .init(baseURL: base, path: "/api/v1/maps/\(id)", method: .GET) - } - - // Map 디테일 출현 몬스터 - public static func fetchMapDetailSpawnMonster(id: Int, query: Encodable) -> ResponsableEndPoint<[DictionaryDetailMapSpawnMonsterResponseDTO]> { - return .init(baseURL: base, path: "/api/v1/maps/\(id)/monsters", method: .GET, query: query) - } - - // Map 디테일 출현 npc - public static func fetchMapDetailNpc(id: Int) -> ResponsableEndPoint<[DictionaryDetailMapNpcResponseDTO]> { - return .init(baseURL: base, path: "/api/v1/maps/\(id)/npcs", method: .GET) - } -} diff --git a/MLS/Data/Data/Network/Endpoints/DictionaryListEndPoint.swift b/MLS/Data/Data/Network/Endpoints/DictionaryListEndPoint.swift deleted file mode 100644 index 76002ae1..00000000 --- a/MLS/Data/Data/Network/Endpoints/DictionaryListEndPoint.swift +++ /dev/null @@ -1,59 +0,0 @@ -import Foundation -import UIKit - -import DomainInterface - -public enum DictionaryListEndPoint { - static let base = "https://mapleland.2megabytes.me" - // 검색 카운트 - public static func fetchListCount(type: String, keyword: String?) -> ResponsableEndPoint { - let query = ["keyword": keyword ?? ""] - return .init(baseURL: base, path: "/api/v1/\(type)/counts", method: .GET, query: query) - } - // 전체 리스트 - public static func fetchAllList(keyword: String?, page: Int? = nil, size: Int? = nil) -> ResponsableEndPoint> { - let query = DictionaryListQuery(keyword: keyword ?? "", page: page ?? 0, size: size ?? 20, sort: nil) - return .init(baseURL: base, path: "/api/v1/search", method: .GET, query: query) - } - // 몬스터 리스트 - public static func fetchMonsterList(keyword: String?, minLevel: Int?, maxLevel: Int?, page: Int, size: Int, sort: String?) -> ResponsableEndPoint> { - let query = DictionaryListQuery(keyword: keyword ?? "", page: page, size: size, sort: sort, minLevel: minLevel ?? 1, maxLevel: maxLevel ?? 200) - return .init(baseURL: base, path: "/api/v1/monsters", method: .GET, query: query - ) - } - // NPC 리스트 - public static func fetchNPCList(keyword: String?, page: Int, size: Int, sort: String?) -> ResponsableEndPoint> { - let query = DictionaryListQuery(keyword: keyword ?? "", page: page, size: size, sort: sort) - return .init(baseURL: base, path: "/api/v1/npcs", method: .GET, query: query - ) - } - // 퀘스트 리스트 - public static func fetchQuestList(keyword: String?, page: Int, size: Int, sort: String?) -> ResponsableEndPoint> { - let query = DictionaryListQuery(keyword: keyword ?? "", page: page, size: size, sort: sort) - return .init(baseURL: base, path: "/api/v1/quests", method: .GET, query: query - ) - } - // 아이템 리스트 - public static func fetchItemList( - keyword: String? = nil, - jobId: [Int]? = nil, - minLevel: Int? = nil, - maxLevel: Int? = nil, - categoryIds: [Int]? = nil, - page: Int? = nil, - size: Int? = nil, - sort: String? = nil - ) -> ResponsableEndPoint> { - let joinedCategoryIds = categoryIds?.map(String.init).joined(separator: ",") - let joinedJobIds = jobId?.map(String.init).joined(separator: ",") - - let query = DictionaryListQuery(keyword: keyword, page: page ?? 0, size: size ?? 20, sort: sort, minLevel: minLevel, maxLevel: maxLevel, jobIds: joinedJobIds, categoryIds: joinedCategoryIds) - return .init(baseURL: base, path: "/api/v1/items", method: .GET, query: query - ) - } - // 맵 리스트 - public static func fetchMapList(keyword: String?, page: Int, size: Int, sort: String?) -> ResponsableEndPoint> { - let query = DictionaryListQuery(keyword: keyword ?? "", page: page, size: size, sort: sort) - return .init(baseURL: base, path: "/api/v1/maps", method: .GET, query: query) - } -} diff --git a/MLS/Data/Data/Network/Endpoints/EndPoint.swift b/MLS/Data/Data/Network/Endpoints/EndPoint.swift deleted file mode 100644 index fd56584f..00000000 --- a/MLS/Data/Data/Network/Endpoints/EndPoint.swift +++ /dev/null @@ -1,29 +0,0 @@ -import Foundation - -import DomainInterface - -/// 응답값이 없는 엔드포인트 -public struct EndPoint: Requestable { - public var baseURL: String - public var path: String - public var method: HTTPMethod - public var query: Encodable? - public var headers: [String: String]? - public var body: Encodable? - - public init( - baseURL: String, - path: String, - method: HTTPMethod, - query: Encodable? = nil, - headers: [String: String]? = nil, - body: Encodable? = nil - ) { - self.baseURL = baseURL - self.path = path - self.method = method - self.query = query - self.headers = headers - self.body = body - } -} diff --git a/MLS/Data/Data/Network/Endpoints/ResponsableEndPoint.swift b/MLS/Data/Data/Network/Endpoints/ResponsableEndPoint.swift deleted file mode 100644 index 1a00736c..00000000 --- a/MLS/Data/Data/Network/Endpoints/ResponsableEndPoint.swift +++ /dev/null @@ -1,31 +0,0 @@ -import Foundation - -import DomainInterface - -/// 응답값이 있는 엔드포인트 -public struct ResponsableEndPoint: Requestable, Responsable { - public typealias Response = T - - public var baseURL: String - public var path: String - public var method: HTTPMethod - public var query: (any Encodable)? - public var headers: [String: String]? - public var body: (any Encodable)? - - public init( - baseURL: String, - path: String, - method: HTTPMethod, - query: (any Encodable)? = nil, - headers: [String: String]? = nil, - body: (any Encodable)? = nil - ) { - self.baseURL = baseURL - self.path = path - self.method = method - self.query = query - self.headers = headers - self.body = body - } -} diff --git a/MLS/Data/Data/Providers/Network/NetworkProviderImpl.swift b/MLS/Data/Data/Providers/Network/NetworkProviderImpl.swift deleted file mode 100644 index 20a25e4e..00000000 --- a/MLS/Data/Data/Providers/Network/NetworkProviderImpl.swift +++ /dev/null @@ -1,176 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public final class NetworkProviderImpl: NetworkProvider { - - private let session: URLSession - - private let retryAttempt: Int = 2 - - public init() { - let configuration = URLSessionConfiguration.default - configuration.timeoutIntervalForRequest = 30 - configuration.timeoutIntervalForResource = 60 - self.session = URLSession(configuration: configuration) - } - - public func requestData(endPoint: T, interceptor: Interceptor?) -> Observable { - return Observable.create { [weak self] observer in - print("🚀 requestData: 요청 시작 - \(endPoint)") - - self?.sendRequest(endPoint: endPoint, interceptor: interceptor, completion: { result in - - switch result { - case .success(let data): - print("✅ requestData: 응답 수신") - - if let data = data { - print("📦 requestData: 응답 데이터 있음 - \(String(data: data, encoding: .utf8) ?? "디코딩 실패")") - do { - let decoded = try JSONDecoder().decode(APIDefaultResponseDTO.self, from: data) - print("🎯 requestData: 디코딩 성공 - \(decoded)") - if let decodedData = decoded.data { - observer.onNext(decodedData) - } else { - if T.Response.self == EmptyResponseDTO.self { - observer.onNext(EmptyResponseDTO() as! T.Response) - } else { - observer.onError(NetworkError.invalidResponse) - } - } - observer.onCompleted() - } catch { - print("❌ requestData: 디코딩 실패 - \(error)") - observer.onError(NetworkError.decodeError(error)) - } - } else { - print("⚠️ requestData: 응답 데이터 없음") - observer.onError(NetworkError.noData) - } - - case .failure(let error): - print("🔥 requestData: 네트워크 실패 - \(error)") - observer.onError(error) - } - }) - - return Disposables.create() - } - .retry(when: { (errors: Observable) in - errors - .enumerated() - .flatMap { attempt, error -> Observable in - print("🔁 requestData: 재시도 \(attempt + 1)회 - 에러: \(error)") - if attempt < self.retryAttempt, let networkError = error as? NetworkError, networkError == .retry { - return Observable.just(()) - } else { - return Observable.error(error) - } - } - }) - } - - public func requestData(endPoint: Requestable, interceptor: Interceptor?) -> Completable { - return Completable.create { [weak self] completable in - self?.sendRequest(endPoint: endPoint, interceptor: interceptor, completion: { result in - switch result { - case .success(let data): - if data != nil { - completable(.completed) - } else { - completable(.error(NetworkError.noData)) - } - case .failure(let error): - completable(.error(error)) - } - }) - return Disposables.create() - } - .retry(when: { (errors: Observable) in - errors - .enumerated() - .flatMap { attempt, error -> Observable in - if attempt < self.retryAttempt, let networkError = error as? NetworkError, networkError == .retry { - return Observable.just(()) - } else { - return Observable.error(error) - } - } - }) - } -} - -private extension NetworkProviderImpl { - /// 엔드 포인트를 이용하여 요청을 보내기 위한 함수 - /// - Parameters: - /// - endPoint: 요청을 위한 엔드포인트 객체 - /// - completion: 응답 결과 - func sendRequest(endPoint: T, interceptor: Interceptor?, completion: @escaping (Result) -> Void) { - do { - var request = try endPoint.getUrlRequest() - if let interceptor = interceptor { request = interceptor.adapt(request) } - let task = session.dataTask(with: request) { [weak self] data, response, error in - guard let self else { - completion(.failure(.providerDeallocated)) - return - } - let taskResult = checkValidation(data: data, response: response, error: error, interceptor: interceptor) - switch taskResult { - case .success(let data): - completion(.success(data)) - case .failure(let error): - completion(.failure(error)) - print("API 통신에러 \(error)") - } - } - task.resume() - } catch { - completion(.failure(NetworkError.urlRequest(error))) - } - } - - /// 통신간의 유효성 검사를 위한 함수 - /// - Parameters: - /// - data: 통신 결과로 돌려받은 데이터 - /// - response: 상태코드를 포함한 통신 응답 - /// - error: 통신간에 발생한 에러 - /// - Returns: 유효성검사 결과에 따른 데이터와 에러 - func checkValidation( - data: Data?, - response: URLResponse?, - error: Error?, - interceptor: Interceptor? - ) -> Result { - - // 1️⃣ 네트워크 레벨 에러 먼저 체크 - if let error { - if let urlError = error as? URLError, urlError.code == .unsupportedURL { - return .failure(.urlRequest(error)) - } - return .failure(.network(error)) - } - - // 2️⃣ HTTP 응답 객체 확인 - guard let httpResponse = response as? HTTPURLResponse else { - return .failure(.httpError) - } - - // 3️⃣ 상태 코드 기반 검사 - guard (200 ... 299).contains(httpResponse.statusCode) else { - // ❗️여기서만 인터셉터 개입 - if let interceptor = interceptor, - interceptor.retry(data: data, response: response, error: error) { - return .failure(.retry) - } - - let errorMessage = data.flatMap { String(data: $0, encoding: .utf8) } ?? "Unknown" - return .failure(.statusError(httpResponse.statusCode, errorMessage)) - } - - // ✅ 성공 응답 - return .success(data) - } -} diff --git a/MLS/Data/Data/Providers/SocialLogin/AppleCredential.swift b/MLS/Data/Data/Providers/SocialLogin/AppleCredential.swift deleted file mode 100644 index 52b8e7cf..00000000 --- a/MLS/Data/Data/Providers/SocialLogin/AppleCredential.swift +++ /dev/null @@ -1,11 +0,0 @@ -import DomainInterface - -public struct AppleCredential: Credential { - public let token: String - public let providerID: String - - public init(token: String, providerID: String) { - self.token = token - self.providerID = providerID - } -} diff --git a/MLS/Data/Data/Providers/SocialLogin/AppleLoginProviderImpl.swift b/MLS/Data/Data/Providers/SocialLogin/AppleLoginProviderImpl.swift deleted file mode 100644 index 6763e3a5..00000000 --- a/MLS/Data/Data/Providers/SocialLogin/AppleLoginProviderImpl.swift +++ /dev/null @@ -1,61 +0,0 @@ -import AuthenticationServices -import Foundation - -import DomainInterface - -import RxSwift - -public final class AppleLoginProviderImpl: NSObject, SocialAuthenticatableProvider { - override public init() {} - - private var authServiceResponse = PublishSubject() - - public func getCredential() -> Observable { - let subject = PublishSubject() - authServiceResponse = subject - performRequest() - return subject - } - - private func performRequest() { - let provider = ASAuthorizationAppleIDProvider() - let request = provider.createRequest() - let controller = ASAuthorizationController(authorizationRequests: [request]) - controller.delegate = self - controller.presentationContextProvider = self - controller.performRequests() - } -} - -// MARK: - Delegate -extension AppleLoginProviderImpl: ASAuthorizationControllerPresentationContextProviding, ASAuthorizationControllerDelegate { - public func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor { - let scenes = UIApplication.shared.connectedScenes - let windowScene = scenes.first as? UIWindowScene - return windowScene?.windows.first ?? UIWindow() - } - - public func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) { - guard let appleIDCredential = authorization.credential as? ASAuthorizationAppleIDCredential else { - authServiceResponse.onError(AuthError.unknown(message: "Invalid Apple credential")) - return - } - - guard let idTokenData = appleIDCredential.identityToken, - let idToken = String(data: idTokenData, encoding: .utf8), - let codeData = appleIDCredential.authorizationCode, - let authCode = String(data: codeData, encoding: .utf8) - else { - authServiceResponse.onError(AuthError.unknown(message: "Failed to parse Apple token or code")) - return - } - - let credential = AppleCredential(token: idToken, providerID: authCode) - authServiceResponse.onNext(credential) - authServiceResponse.onCompleted() - } - - public func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) { - authServiceResponse.onError(error) - } -} diff --git a/MLS/Data/Data/Providers/SocialLogin/KakaoCredential.swift b/MLS/Data/Data/Providers/SocialLogin/KakaoCredential.swift deleted file mode 100644 index 7caeadbd..00000000 --- a/MLS/Data/Data/Providers/SocialLogin/KakaoCredential.swift +++ /dev/null @@ -1,11 +0,0 @@ -import DomainInterface - -public struct KakaoCredential: Credential { - public let token: String - public let providerID: String - - public init(token: String, providerID: String) { - self.token = token - self.providerID = providerID - } -} diff --git a/MLS/Data/Data/Providers/SocialLogin/KakaoLoginProviderImpl.swift b/MLS/Data/Data/Providers/SocialLogin/KakaoLoginProviderImpl.swift deleted file mode 100644 index 825059ae..00000000 --- a/MLS/Data/Data/Providers/SocialLogin/KakaoLoginProviderImpl.swift +++ /dev/null @@ -1,61 +0,0 @@ -import Foundation - -import DomainInterface - -import KakaoSDKAuth -import KakaoSDKUser -import RxSwift - -public final class KakaoLoginProviderImpl: SocialAuthenticatableProvider { - public init() {} - - public func getCredential() -> Observable { - return Observable.create { [weak self] observer in - let disposable = Disposables.create() - - let handleLogin: (OAuthToken?, Error?) -> Void = { oauthToken, error in - self?.fetchEmailAfterDelay(oauthToken: oauthToken, error: error, observer: observer) - } - - DispatchQueue.main.async { - if UserApi.isKakaoTalkLoginAvailable() { - // 카카오톡 앱 로그인 - UserApi.shared.loginWithKakaoTalk(completion: handleLogin) - } else { - // 웹 브라우저 로그인 - UserApi.shared.loginWithKakaoAccount(completion: handleLogin) - } - } - - return disposable - } - } - - /// accessToken 기반으로 사용자 정보를 가져오는 함수 (딜레이 포함) - private func fetchEmailAfterDelay(oauthToken: OAuthToken?, error: Error?, observer: AnyObserver) { - if let error = error { - observer.onError(error) - return - } - - guard let accessToken = oauthToken?.accessToken else { - observer.onError(AuthError.unknown(message: "토큰이 없어요")) - return - } - - // ✅ Kakao SDK 내부 토큰 저장 시간 보장 - DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { - UserApi.shared.me { user, error in - if let error = error { - observer.onError(error) - return - } - - let id = user?.id ?? 0 - let credential = KakaoCredential(token: accessToken, providerID: String(id)) - observer.onNext(credential) - observer.onCompleted() - } - } - } -} diff --git a/MLS/Data/Data/Repository/AlarmAPIRepositoryImpl.swift b/MLS/Data/Data/Repository/AlarmAPIRepositoryImpl.swift deleted file mode 100644 index ab98afde..00000000 --- a/MLS/Data/Data/Repository/AlarmAPIRepositoryImpl.swift +++ /dev/null @@ -1,62 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class AlarmAPIRepositoryImpl: AlarmAPIRepository { - private let provider: NetworkProvider - private let tokenInterceptor: Interceptor - - public init(provider: NetworkProvider, interceptor: Interceptor) { - self.provider = provider - self.tokenInterceptor = interceptor - } - - public func fetchPatchNotes(cursor: Int?, pageSize: Int) -> Observable> { - let endpoint = AlarmEndPoint.fetchPatchNotes(query: AlarmQuery(cursor: cursor, pageSize: pageSize)) - return provider.requestData(endPoint: endpoint, interceptor: tokenInterceptor) - .map { $0.toAlarmDomain() } - } - - public func fetchNotices(cursor: Int?, pageSize: Int) -> Observable> { - let endpoint = AlarmEndPoint.fetchNotices(query: AlarmQuery(cursor: cursor, pageSize: pageSize)) - return provider.requestData(endPoint: endpoint, interceptor: tokenInterceptor) - .map { $0.toAlarmDomain() } - } - - public func fetchOutdatedEvents(cursor: Int?, pageSize: Int) -> Observable> { - let endpoint = AlarmEndPoint.fetchOutdatedEvents(query: AlarmQuery(cursor: cursor, pageSize: pageSize)) - return provider.requestData(endPoint: endpoint, interceptor: tokenInterceptor) - .map { $0.toAlarmDomain() } - } - - public func fetchOngoingEvents(cursor: Int?, pageSize: Int) -> Observable> { - let endpoint = AlarmEndPoint.fetchOngoingEvents(query: AlarmQuery(cursor: cursor, pageSize: pageSize)) - return provider.requestData(endPoint: endpoint, interceptor: tokenInterceptor) - .map { $0.toAlarmDomain() } - } - - public func fetchAll(cursor: Int?, pageSize: Int) -> Observable> { - let endpoint = AlarmEndPoint.fetchAll(query: AlarmQuery(cursor: cursor, pageSize: pageSize)) - return provider.requestData(endPoint: endpoint, interceptor: tokenInterceptor) - .map { $0.toAllAlarmDomain() } - } - - public func setRead(alarmLink: String) -> Completable { - let endpoint = AlarmEndPoint.setRead(query: SetReadQuery(alrimLink: alarmLink)) - return provider.requestData(endPoint: endpoint, interceptor: tokenInterceptor) - } - -} - -private extension AlarmAPIRepositoryImpl { - struct AlarmQuery: Encodable { - let cursor: Int? - let pageSize: Int - } - - struct SetReadQuery: Encodable { - let alrimLink: String - } -} diff --git a/MLS/Data/Data/Repository/AuthAPIRepositoryImpl.swift b/MLS/Data/Data/Repository/AuthAPIRepositoryImpl.swift deleted file mode 100644 index d5bef287..00000000 --- a/MLS/Data/Data/Repository/AuthAPIRepositoryImpl.swift +++ /dev/null @@ -1,169 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class AuthAPIRepositoryImpl: AuthAPIRepository { - private let provider: NetworkProvider - private let tokenInterceptor: Interceptor - private let authInterceptor: Interceptor - - public init(provider: NetworkProvider, tokenInterceptor: Interceptor, authInterceptor: Interceptor) { - self.provider = provider - self.tokenInterceptor = tokenInterceptor - self.authInterceptor = authInterceptor - } - - public func fetchProfile() -> Observable { - let endpoint = AuthEndPoint.fetchProfile() - return provider.requestData(endPoint: endpoint, interceptor: tokenInterceptor) - .map { $0.toMyPageDomain() } - } - - public func loginWithKakao(credential: Credential) -> Observable { - let endpoint = AuthEndPoint.loginWithKakao(credential: credential) - return provider.requestData(endPoint: endpoint, interceptor: authInterceptor) - .map { $0.toLoginDomain() } - .catch { error in - if case NetworkError.statusError(let code, _) = error, code == 404 { - return Observable.error(AuthError.userNotFound(credential: credential)) - } else { - return Observable.error(error) - } - } - } - - public func loginWithApple(credential: Credential) -> Observable { - let endpoint = AuthEndPoint.loginWithApple(credential: credential) - return provider.requestData(endPoint: endpoint, interceptor: authInterceptor) - .map { $0.toLoginDomain() } - .catch { error in - if case NetworkError.statusError(let code, _) = error, code == 404 { - return Observable.error(AuthError.userNotFound(credential: credential)) - } else { - return Observable.error(error) - } - } - } - - public func signUpWithKakao(credential: Credential, isMarketingAgreement: Bool, fcmToken: String?) -> Observable { - let endpoint = AuthEndPoint.signupWithKakao( - credential: credential.token, - body: KakaoBody( - providerId: credential.providerID, - fcmToken: fcmToken, - marketingAgreement: isMarketingAgreement - ) - ) - return provider.requestData(endPoint: endpoint, interceptor: nil).map { $0.toSignUpDomain() } - } - - public func signUpWithApple(credential: Credential, isMarketingAgreement: Bool, fcmToken: String?) -> Observable { - let endpoint = AuthEndPoint.signupWithApple( - credential: credential.token, - body: AppleBody( - providerId: credential.providerID, - fcmToken: fcmToken, - marketingAgreement: isMarketingAgreement - ) - ) - return provider.requestData(endPoint: endpoint, interceptor: nil).map { $0.toSignUpDomain() } - } - - public func withdraw() -> Completable { - let endPoint = AuthEndPoint.withdraw() - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - } - - public func reissueToken(refreshToken: String) -> Observable { - let endPoint = AuthEndPoint.reIssueToken(refreshToken: refreshToken) - return provider.requestData(endPoint: endPoint, interceptor: nil).map { $0.toLoginDomain() } - } - - public func fcmToken(fcmToken: String?) -> Completable { - let endPoint = AuthEndPoint.fcmToken(body: FCMTokenBody(fcmToken: fcmToken)) - return provider.requestData(endPoint: endPoint, interceptor: authInterceptor) - } - - public func fetchJobList() -> Observable { - let endPoint = AuthEndPoint.fetchJobs() - return provider.requestData(endPoint: endPoint, interceptor: nil).map { $0.toDomain() } - } - - public func fetchJob(jobId: String) -> Observable { - let endPoint = AuthEndPoint.fetchJob(jobId: jobId) - return provider.requestData(endPoint: endPoint, interceptor: nil).map { $0.toDomain() } - } - - public func updateUserInfo(level: Int, selectedJobID: Int) -> Completable { - let endPoint = AuthEndPoint.updateCharacterInfo(body: UpdateInfoBody(level: level, jobId: selectedJobID)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - } - - public func updateMarketingAgreement(credential: String, isMarketingAgreement: Bool) -> Completable { - let endPoint = AuthEndPoint.updateMarketingAgreement(credential: credential, body: MarketingAgreementBody(marketingAgreement: isMarketingAgreement)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - } - - public func updateNotificationAgreement(noticeAgreement: Bool, patchNoteAgreement: Bool, eventAgreement: Bool) -> Completable { - let endPoint = AuthEndPoint.updateNotification(body: NotificationAgreementBody(noticeAgreement: noticeAgreement, patchNoteAgreement: patchNoteAgreement, eventAgreement: eventAgreement)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - } - - public func updateNickName(nickName: String) -> Observable { - let endPoint = AuthEndPoint.updateNickName(body: NickNameBody(nickname: nickName)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - .map { $0.toMyPageDomain() } - } - - public func updateProfileImage(url: String) -> Completable { - let endPoint = AuthEndPoint.updateProfileImage(body: UpdateProfileImageBody(profileImageUrl: url)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - } -} - -private extension AuthAPIRepositoryImpl { - struct KakaoBody: Encodable { - let provider = "KAKAO" - let providerId: String - let nickname: String? = nil - let fcmToken: String? - let marketingAgreement: Bool - } - - struct AppleBody: Encodable { - let provider = "APPLE" - let providerId: String - let nickname: String? = nil - let fcmToken: String? - let marketingAgreement: Bool - } - - struct FCMTokenBody: Encodable { - let fcmToken: String? - } - - struct MarketingAgreementBody: Encodable { - let marketingAgreement: Bool - } - - struct NotificationAgreementBody: Encodable { - let noticeAgreement: Bool - let patchNoteAgreement: Bool - let eventAgreement: Bool - } - - struct NickNameBody: Encodable { - let nickname: String - } - - struct UpdateInfoBody: Encodable { - let level: Int - let jobId: Int - } - - struct UpdateProfileImageBody: Encodable { - let profileImageUrl: String - } -} diff --git a/MLS/Data/Data/Repository/BookmarkRepositoryImpl.swift b/MLS/Data/Data/Repository/BookmarkRepositoryImpl.swift deleted file mode 100644 index 144b7b86..00000000 --- a/MLS/Data/Data/Repository/BookmarkRepositoryImpl.swift +++ /dev/null @@ -1,88 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class BookmarkRepositoryImpl: BookmarkRepository { - private let provider: NetworkProvider - private let tokenInterceptor: Interceptor - - public init(provider: NetworkProvider, interceptor: Interceptor) { - self.provider = provider - self.tokenInterceptor = interceptor - } - - public func setBookmark(bookmarkId: Int, type: DictionaryItemType) -> Observable { - let endPoint = BookmarkEndPoint.setBookmark(body: SetBookmarkQuery(bookmarkType: type.rawValue, resourceId: bookmarkId)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - .map { $0.toDomain() } - } - - public func deleteBookmark(bookmarkId: Int) -> Observable { - let endPoint = BookmarkEndPoint.deleteBookmark(bookmarkId: bookmarkId) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - .map { $0.toBookmarkDomain() } - } - - public func fetchBookmark(sort: String?) -> Observable<[BookmarkResponse]> { - let endPoint = BookmarkEndPoint.fetchBookmark(query: SortedQuery(sort: sort)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - .map { $0.toDomain() } - } - - public func fetchMonsterBookmark(minLevel: Int?, maxLevel: Int?, sort: String?) -> Observable<[BookmarkResponse]> { - let endPoint = BookmarkEndPoint.fetchMonsterBookmark(query: BookmarkMonsterQuery(minLevel: minLevel, maxLevel: maxLevel, sort: sort)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - .map { $0.toDomain() } - } - - public func fetchNPCBookmark(sort: String?) -> Observable<[BookmarkResponse]> { - let endPoint = BookmarkEndPoint.fetchNPCBookmark(query: SortedQuery(sort: sort)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - .map { $0.toDomain() } - } - - public func fetchQuestBookmark(sort: String?) -> Observable<[BookmarkResponse]> { - let endPoint = BookmarkEndPoint.fetchQuestBookmark(query: SortedQuery(sort: sort)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - .map { $0.toDomain() } - } - - public func fetchItemBookmark(jobId: Int?, minLevel: Int?, maxLevel: Int?, categoryIds: [Int]?, sort: String?) -> Observable<[BookmarkResponse]> { - let endPoint = BookmarkEndPoint.fetchItemBookmark(query: BookmarkItemQuery(jobId: jobId, minLevel: minLevel, maxLevel: maxLevel, categoryIds: categoryIds, sort: sort)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - .map { $0.toDomain() } - } - - public func fetchMapBookmark(sort: String?) -> Observable<[BookmarkResponse]> { - let endPoint = BookmarkEndPoint.fetchMapBookmark(query: SortedQuery(sort: sort)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - .map { $0.toDomain() } - } -} - -private extension BookmarkRepositoryImpl { - struct SortedQuery: Encodable { - let sort: String? - } - - struct SetBookmarkQuery: Encodable { - let bookmarkType: String - let resourceId: Int - } - - struct BookmarkMonsterQuery: Encodable { - let minLevel: Int? - let maxLevel: Int? - let sort: String? - } - - struct BookmarkItemQuery: Encodable { - let jobId: Int? - let minLevel: Int? - let maxLevel: Int? - let categoryIds: [Int]? - let sort: String? - } -} diff --git a/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift b/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift deleted file mode 100644 index e3f7ad2a..00000000 --- a/MLS/Data/Data/Repository/CollectionAPIRepositoryImpl.swift +++ /dev/null @@ -1,75 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class CollectionAPIRepositoryImpl: CollectionAPIRepository { - private let provider: NetworkProvider - private let tokenInterceptor: Interceptor - - public init(provider: NetworkProvider, tokenInterceptor: Interceptor) { - self.provider = provider - self.tokenInterceptor = tokenInterceptor - } - - public func fetchCollectionList(sort: String?) -> Observable<[CollectionResponse]> { - let endPoint = CollectionEndPoint.fetchCollectionList(query: FetchCollectionListQuery(sort: sort)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - .map { $0.map { $0.toDomain() } - } - } - - public func createCollectionList(name: String) -> Completable { - let endPoint = CollectionEndPoint.createCollectionList(body: CreateCollectionRequestDTO(name: name)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - } - - public func fetchCollectionUseCase(id: Int) -> Observable<[BookmarkResponse]> { - let endPoint = CollectionEndPoint.fetchCollection(id: id) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - .map { $0.toDomain() } - } - - public func updateCollectionName(collectionId: Int, name: String) -> Completable { - let endPoint = CollectionEndPoint.setCollectionName(id: collectionId, body: SetCollectionRequestBody(name: name)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - } - - public func deleteCollection(collectionId: Int) -> Completable { - let endPoint = CollectionEndPoint.deleteCollection(id: collectionId) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - } - - public func addCollectionAndBookmark(collectionIds: [Int], bookmarkIds: [Int]) -> Completable { - let endPoint = CollectionEndPoint.addCollectionAndBookmark(body: AddCollectionAndBookmarkBody(collectionIds: collectionIds, bookmarkIds: bookmarkIds)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - } -} - -private extension CollectionAPIRepositoryImpl { - struct FetchCollectionListQuery: Encodable { - let sort: String? - } - - struct CreateCollectionRequestDTO: Encodable { - let name: String - } - - struct AddBookmarkRequestBody: Encodable { - let bookmarkIds: [Int] - } - - struct AddCollectionRequestBody: Encodable { - let collectionIds: [Int] - } - - struct SetCollectionRequestBody: Encodable { - let name: String - } - - struct AddCollectionAndBookmarkBody: Encodable { - let collectionIds: [Int] - let bookmarkIds: [Int] - } -} diff --git a/MLS/Data/Data/Repository/DictionaryDetailAPIRepositoryImpl.swift b/MLS/Data/Data/Repository/DictionaryDetailAPIRepositoryImpl.swift deleted file mode 100644 index 83f4faf0..00000000 --- a/MLS/Data/Data/Repository/DictionaryDetailAPIRepositoryImpl.swift +++ /dev/null @@ -1,85 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class DictionaryDetailAPIRepositoryImpl: DictionaryDetailAPIRepository { - - private let provider: NetworkProvider - private let tokenInterceptor: Interceptor? - - public init(provider: NetworkProvider, tokenInterceptor: Interceptor?) { - self.provider = provider - self.tokenInterceptor = tokenInterceptor - } - - // MARK: - 몬스터 디테일 상세정보 - public func fetchMonsterDetail(id: Int) -> Observable { - let endPoint = DictionaryDetailEndPoint.fetchMonsterDetail(id: id) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map { $0.toDomain() } - } - - public func fetchMonsterDetailDropItem(id: Int, sort: String?) -> Observable<[DictionaryDetailMonsterDropItemResponse]> { - let endPoint = DictionaryDetailEndPoint.fetchMonsterDetailDropItem(id: id, query: SortQuery(sort: sort)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map {$0.map {$0.toDomain()}} - } - - public func fetchMonsterDetailMap(id: Int) -> Observable<[DictionaryDetailMonsterMapResponse]> { - let endPoint = DictionaryDetailEndPoint.fetchMonsterDetailMap(id: id) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map { $0.map {$0.toDomain() }} - } - // MARK: - Npc 디테일 상세정보 - public func fetchNpcDetail(id: Int) -> Observable { - let endPoint = DictionaryDetailEndPoint.fetchNpcDetail(id: id) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map { $0.toDomain() } - } - - public func fetchNpcDetailQuest(id: Int, sort: String?) -> Observable<[DictionaryDetailNpcQuestResponse]> { - let endPoint = DictionaryDetailEndPoint.fetchNpcDetailQuest(id: id, query: SortQuery(sort: sort)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map { $0.map {$0.toDomain()} } - - } - - public func fetchNpcDetailMap(id: Int) -> Observable<[DictionaryDetailMonsterMapResponse]> { - let endPoint = DictionaryDetailEndPoint.fetchNpcDetailMap(id: id) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map { $0.map {$0.toDomain()} } - } - - public func fetchItemDetail(id: Int) -> Observable { - let endPoint = DictionaryDetailEndPoint.fetchItemDetail(id: id) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map { $0.toDomain() } - } - - public func fetchItemDetailDropMonster(id: Int, sort: String?) -> Observable<[DictionaryDetailItemDropMonsterResponse]> { - let endPoint = DictionaryDetailEndPoint.fetchItemDetailDropMonster(id: id, query: SortQuery(sort: sort)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map { $0.map {$0.toDomain() } } - } - - public func fetchQuestDetail(id: Int) -> Observable { - let endPoint = DictionaryDetailEndPoint.fetchQuestDetail(id: id) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map { $0.toDomain() } - } - - public func fetchQuestDetailLinkedQuestsDetail(id: Int) -> Observable { - let endPoint = DictionaryDetailEndPoint.fetchQuestDetailLinkedQuests(id: id) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map { $0.toDomain() } - } - - public func fetchMapDetail(id: Int) -> Observable { - let endPoint = DictionaryDetailEndPoint.fetchMapDetail(id: id) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map { $0.toDomain() } - } - - public func fetchMapDetailSpawnMonster(id: Int, sort: String?) -> Observable<[DictionaryDetailMapSpawnMonsterResponse]> { - let endPoint = DictionaryDetailEndPoint.fetchMapDetailSpawnMonster(id: id, query: SortQuery(sort: sort)) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map { $0.map {$0.toDomain()} } - } - - public func fetchMapDetailNpc(id: Int) -> Observable<[DictionaryDetailMapNpcResponse]> { - let endPoint = DictionaryDetailEndPoint.fetchMapDetailNpc(id: id) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map {$0.map {$0.toDomain()}} - } -} - -struct SortQuery: Encodable { - let sort: String? -} diff --git a/MLS/Data/Data/Repository/DictionaryListAPIRepositoryImpl.swift b/MLS/Data/Data/Repository/DictionaryListAPIRepositoryImpl.swift deleted file mode 100644 index 15c454a9..00000000 --- a/MLS/Data/Data/Repository/DictionaryListAPIRepositoryImpl.swift +++ /dev/null @@ -1,58 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class DictionaryListAPIRepositoryImpl: DictionaryListAPIRepository { - private let provider: NetworkProvider - private let tokenInterceptor: Interceptor? - - public init(provider: NetworkProvider, tokenInterceptor: Interceptor? = nil) { - self.provider = provider - self.tokenInterceptor = tokenInterceptor - } - // MARK: - 검색 카운트 - public func fetchSearchListCount(type: String, keyword: String?) -> Observable { - let endPoint = DictionaryListEndPoint.fetchListCount(type: type, keyword: keyword) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map {$0.toDomain()} - } - // MARK: - 검색 리스트 - public func fetchSearchList(keyword: String?) -> Observable { - let endPoint = DictionaryListEndPoint.fetchAllList(keyword: keyword) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map {$0.toDomain()} - } - // MARK: - 전체 리스트 - public func fetchAllList(keyword: String?, page: Int?) -> Observable { - let endPoint = DictionaryListEndPoint.fetchAllList(keyword: keyword, page: page) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor).map {$0.toDomain()} - } - // MARK: - 몬스터 리스트 - public func fetchMonsterList(keyword: String?, minLevel: Int?, maxLevel: Int?, page: Int, size: Int, sort: String?) -> Observable { - let endPoint = DictionaryListEndPoint.fetchMonsterList(keyword: keyword, minLevel: minLevel, maxLevel: maxLevel, page: page, size: size, sort: sort ?? "ASC") - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - .map { $0.toDomain() } - } - // MARK: - NPC 리스트 - public func fetchNpcList(keyword: String, page: Int, size: Int, sort: String?) -> Observable { - let endPoint = DictionaryListEndPoint.fetchNPCList(keyword: keyword, page: page, size: 20, sort: sort ?? "ASC") - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - .map { $0.toDomain() } - } - // MARK: - Quest 리스트 - public func fetchQuestList(keyword: String, page: Int, size: Int, sort: String?) -> Observable { - let endPoint = DictionaryListEndPoint.fetchQuestList(keyword: keyword, page: page, size: 20, sort: sort ?? "ASC") - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - .map { $0.toDomain() } - } - // MARK: - Item 리스트 - public func fetchItemList(keyword: String?, jobId: [Int]?, minLevel: Int?, maxLevel: Int?, categoryIds: [Int]?, page: Int?, size: Int?, sort: String?) -> Observable { - let endPoint = DictionaryListEndPoint.fetchItemList(keyword: keyword, jobId: jobId, minLevel: minLevel, maxLevel: maxLevel, categoryIds: categoryIds, page: page, size: size, sort: sort) - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - .map { $0.toDomain() } - } - // MARK: - Map 리스트 - public func fetchMapList(keyword: String, page: Int, size: Int, sort: String?) -> Observable { - let endPoint = DictionaryListEndPoint.fetchMapList(keyword: keyword, page: page, size: 20, sort: sort ?? "ASC") - return provider.requestData(endPoint: endPoint, interceptor: tokenInterceptor) - .map { $0.toDomain() } - } -} diff --git a/MLS/Data/Data/Repository/UserDefaultsRepositoryImpl.swift b/MLS/Data/Data/Repository/UserDefaultsRepositoryImpl.swift deleted file mode 100644 index a0976d39..00000000 --- a/MLS/Data/Data/Repository/UserDefaultsRepositoryImpl.swift +++ /dev/null @@ -1,125 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public final class UserDefaultsRepositoryImpl: UserDefaultsRepository { - private let recentSearchkey = "recentSearch" - private let platformKey = "platformKey" - private let bookmarkkey = "bookmark" - private let dictionaryDetailkey = "dictionaryDetailkey" - - public init() {} - - public func fetchRecentSearch() -> Observable<[String]> { - return Observable.create { observer in - let current = UserDefaults.standard.stringArray(forKey: self.recentSearchkey) ?? [] - observer.onNext(current) - observer.onCompleted() - return Disposables.create() - } - } - - public func addRecentSearch(keyword: String) -> Completable { - let keyword = keyword.trimmingCharacters(in: .whitespacesAndNewlines) - - guard !keyword.isEmpty else { - return .empty() - } - - var current = UserDefaults.standard.stringArray(forKey: recentSearchkey) ?? [] - - current.removeAll(where: { $0 == keyword }) - current.insert(keyword, at: 0) - - UserDefaults.standard.set(current, forKey: recentSearchkey) - - return .empty() - } - - public func removeRecentSearch(keyword: String) -> Completable { - return Completable.create { completable in - var current = UserDefaults.standard.stringArray(forKey: self.recentSearchkey) ?? [] - - // 해당 키워드 제거 - current.removeAll { $0 == keyword } - - // 다시 저장 - UserDefaults.standard.set(current, forKey: self.recentSearchkey) - - completable(.completed) - return Disposables.create() - } - } - - public func removeAllSearch() -> Completable { - return Completable.create { completable in - var current = UserDefaults.standard.stringArray(forKey: self.recentSearchkey) ?? [] - - // 해당 키워드 제거 - current.removeAll() - - // 다시 저장 - UserDefaults.standard.set(current, forKey: self.recentSearchkey) - - completable(.completed) - return Disposables.create() - } - } - - public func fetchPlatform() -> Observable { - return Observable.create { observer in - if let rawValue = UserDefaults.standard.string(forKey: self.platformKey), - let platform = LoginPlatform(rawValue: rawValue) { - observer.onNext(platform) - } else { - observer.onNext(nil) - } - observer.onCompleted() - return Disposables.create() - } - } - - public func savePlatform(platform: LoginPlatform) -> Completable { - return Completable.create { completable in - UserDefaults.standard.set(platform.rawValue, forKey: self.platformKey) - completable(.completed) - return Disposables.create() - } - } - - public func fetchBookmark() -> Observable { - return Observable.create { observer in - let hasVisited = UserDefaults.standard.bool(forKey: self.bookmarkkey) - observer.onNext(hasVisited) - observer.onCompleted() - return Disposables.create() - } - } - - public func saveBookmark() -> Completable { - return Completable.create { completable in - UserDefaults.standard.set(true, forKey: self.bookmarkkey) - completable(.completed) - return Disposables.create() - } - } - - public func fetchDictionaryDetail() -> Observable { - return Observable.create { observer in - let hasVisited = UserDefaults.standard.bool(forKey: self.dictionaryDetailkey) - observer.onNext(hasVisited) - observer.onCompleted() - return Disposables.create() - } - } - - public func saveDictionaryDetail() -> Completable { - return Completable.create { completable in - UserDefaults.standard.set(true, forKey: self.dictionaryDetailkey) - completable(.completed) - return Disposables.create() - } - } -} diff --git a/MLS/Data/DataMock/Factory/DictionaryFactoryMock.swift b/MLS/Data/DataMock/Factory/DictionaryFactoryMock.swift deleted file mode 100644 index 85d6d104..00000000 --- a/MLS/Data/DataMock/Factory/DictionaryFactoryMock.swift +++ /dev/null @@ -1,13 +0,0 @@ -import BaseFeature -import DictionaryFeatureInterface -import DomainInterface - -public final class DictionaryFactoryMock: DictionaryMainViewFactory { - public init() {} - - public func make() -> BaseViewController { - let viewController = BaseViewController() - viewController.view.backgroundColor = .blue - return viewController - } -} diff --git a/MLS/Data/DataMock/Factory/LoginFactoryMock.swift b/MLS/Data/DataMock/Factory/LoginFactoryMock.swift deleted file mode 100644 index 1bb84a2d..00000000 --- a/MLS/Data/DataMock/Factory/LoginFactoryMock.swift +++ /dev/null @@ -1,19 +0,0 @@ -import AuthFeatureInterface -import BaseFeature -import DictionaryFeatureInterface -import DomainInterface - -public final class LoginFactoryMock: LoginFactory { - public init() {} - - public func make(exitRoute: LoginExitRoute) -> BaseViewController { - let viewController = BaseViewController() - viewController.view.backgroundColor = .blue - return viewController - } - - public func make(exitRoute: LoginExitRoute, onLoginCompleted: (() -> Void)?) -> BaseViewController { - return BaseViewController() - } - -} diff --git a/MLS/Data/DataMock/Provider/AppleLoginProviderMock.swift b/MLS/Data/DataMock/Provider/AppleLoginProviderMock.swift deleted file mode 100644 index c6e4cdf3..00000000 --- a/MLS/Data/DataMock/Provider/AppleLoginProviderMock.swift +++ /dev/null @@ -1,14 +0,0 @@ -import Foundation - -import Data -import DomainInterface - -import RxSwift - -public final class AppleLoginProviderMock: SocialAuthenticatableProvider { - public init() {} - - public func getCredential() -> Observable { - return Observable.just(AppleCredential(token: "token", providerID: "token")) - } -} diff --git a/MLS/Data/DataMock/Provider/KakaoLoginProviderMock.swift b/MLS/Data/DataMock/Provider/KakaoLoginProviderMock.swift deleted file mode 100644 index fba5e5ac..00000000 --- a/MLS/Data/DataMock/Provider/KakaoLoginProviderMock.swift +++ /dev/null @@ -1,14 +0,0 @@ -import Foundation - -import Data -import DomainInterface - -import RxSwift - -public final class KakaoLoginProviderMock: SocialAuthenticatableProvider { - public init() {} - - public func getCredential() -> Observable { - return Observable.just(KakaoCredential(token: "Token", providerID: "email")) - } -} diff --git a/MLS/Data/DataMock/Repository/AuthAPIRepositoryMock.swift b/MLS/Data/DataMock/Repository/AuthAPIRepositoryMock.swift deleted file mode 100644 index 2e524dbd..00000000 --- a/MLS/Data/DataMock/Repository/AuthAPIRepositoryMock.swift +++ /dev/null @@ -1,104 +0,0 @@ -import Foundation - -import Data -import DomainInterface - -import RxSwift - -public class AuthAPIRepositoryMock: AuthAPIRepository { - public func fetchProfile() -> Observable { - return .empty() - } - - public func fetchJob(jobId: String) -> Observable { - return .empty() - } - - public func updateProfileImage(url: String) -> Completable { - return .empty() - } - - public func fetchProfile() -> Observable { - return .empty() - } - - public func signUpWithKakao(credential: any DomainInterface.Credential, isMarketingAgreement: Bool, fcmToken: String?) -> RxSwift.Observable { - if tryCount == 0 { - tryCount += 1 - let error = NSError(domain: "Auth", code: 401, userInfo: [NSLocalizedDescriptionKey: "애플 로그인 실패"]) - return Observable.error(error) - } else { - return Observable.just(.init(accessToken: "testToken", refreshToken: "testToken")) - } - } - - public func signUpWithApple(credential: any DomainInterface.Credential, isMarketingAgreement: Bool, fcmToken: String?) -> RxSwift.Observable { - return Observable.just(.init(accessToken: "testToken", refreshToken: "testToken")) - } - - public func fcmToken(fcmToken: String?) -> Completable { - return .empty() - } - - private var tryCount: Int = 0 - - private let provider: NetworkProvider - - public init(provider: NetworkProvider) { - self.provider = provider - } - - public func loginWithKakao(credential: Credential) -> Observable { - return Observable.just(.init(isRegister: true, accessToken: "", refreshToken: "")) - } - - public func loginWithApple(credential: Credential) -> Observable { - return Observable.just(.init(isRegister: false, accessToken: "", refreshToken: "")) - } - - public func reissueToken(refreshToken: String) -> Observable { - return Observable.just(.init(isRegister: true, accessToken: "testToken", refreshToken: "testToken")) - } - - public func withdraw() -> Completable { - return .empty() - } - - public func fetchJobList() -> Observable { - tryCount += 1 - if tryCount == 1 { - let error = NSError(domain: "Auth", code: 401, userInfo: [NSLocalizedDescriptionKey: "직업 리스트 조회 실패"]) - return Observable.error(error) - } else { - return Observable.just(.init(jobList: [ - Job(name: "마법사", id: 1) - ])) - } - } - - public func updateUserInfo(level: Int, selectedJob: String) -> Completable { - tryCount += 1 - if tryCount % 2 == 0 { - let error = NSError(domain: "Auth", code: 401, userInfo: [NSLocalizedDescriptionKey: "유저 정보 수정 실패"]) - return .error(error) - } else { - return .empty() - } - } - - public func updateMarketingAgreement(credential: String, isMarketingAgreement: Bool) -> Completable { - return .empty() - } - - public func updateUserInfo(level: Int, selectedJobID: Int) -> Completable { - return .empty() - } - - public func updateNotificationAgreement(noticeAgreement: Bool, patchNoteAgreement: Bool, eventAgreement: Bool) -> Completable { - return .empty() - } - - public func updateNickName(nickName: String) -> Observable { - return .empty() - } -} diff --git a/MLS/Domain/.DS_Store b/MLS/Domain/.DS_Store deleted file mode 100644 index 4895ceec..00000000 Binary files a/MLS/Domain/.DS_Store and /dev/null differ diff --git a/MLS/Domain/Domain.xcodeproj/project.pbxproj b/MLS/Domain/Domain.xcodeproj/project.pbxproj deleted file mode 100644 index febd6192..00000000 --- a/MLS/Domain/Domain.xcodeproj/project.pbxproj +++ /dev/null @@ -1,606 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 77; - objects = { - -/* Begin PBXBuildFile section */ - 0801754B2DCD275300D0919F /* DomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0801752E2DCD26B300D0919F /* DomainInterface.framework */; }; - 084A25CD2DB93E1E00C395C0 /* Core.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 084A25CC2DB93E1E00C395C0 /* Core.framework */; }; - 08ED490D2DCFDD63002C21A2 /* Core.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08ED490C2DCFDD63002C21A2 /* Core.framework */; }; - 08ED49322DCFDEF6002C21A2 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 08ED49312DCFDEF6002C21A2 /* RxSwift */; }; - 08ED49362DCFDF8F002C21A2 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 08ED49352DCFDF8F002C21A2 /* RxSwift */; }; - 779FC89A2E1411D100FD1551 /* RxRelay in Frameworks */ = {isa = PBXBuildFile; productRef = 779FC8992E1411D100FD1551 /* RxRelay */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 0801754D2DCD275300D0919F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 0879291A2DB90F11009C301F /* Project object */; - proxyType = 1; - remoteGlobalIDString = 0801752D2DCD26B300D0919F; - remoteInfo = DomainInterface; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXFileReference section */ - 0801752E2DCD26B300D0919F /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 0801754F2DCD275900D0919F /* Core.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Core.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 084A25672DB93C0C00C395C0 /* MLSCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MLSCore.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 084A256A2DB93C0F00C395C0 /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 084A25CC2DB93E1E00C395C0 /* Core.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Core.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 087929232DB90F11009C301F /* Domain.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Domain.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 08ED490C2DCFDD63002C21A2 /* Core.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Core.framework; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFileSystemSynchronizedRootGroup section */ - 0801752F2DCD26B300D0919F /* DomainInterface */ = { - isa = PBXFileSystemSynchronizedRootGroup; - path = DomainInterface; - sourceTree = ""; - }; - 087929252DB90F11009C301F /* Domain */ = { - isa = PBXFileSystemSynchronizedRootGroup; - path = Domain; - sourceTree = ""; - }; -/* End PBXFileSystemSynchronizedRootGroup section */ - -/* Begin PBXFrameworksBuildPhase section */ - 0801752B2DCD26B300D0919F /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 779FC89A2E1411D100FD1551 /* RxRelay in Frameworks */, - 08ED49322DCFDEF6002C21A2 /* RxSwift in Frameworks */, - 08ED490D2DCFDD63002C21A2 /* Core.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 087929202DB90F11009C301F /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 08ED49362DCFDF8F002C21A2 /* RxSwift in Frameworks */, - 0801754B2DCD275300D0919F /* DomainInterface.framework in Frameworks */, - 084A25CD2DB93E1E00C395C0 /* Core.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 084A25662DB93C0C00C395C0 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 08ED490C2DCFDD63002C21A2 /* Core.framework */, - 0801754F2DCD275900D0919F /* Core.framework */, - 084A25CC2DB93E1E00C395C0 /* Core.framework */, - 084A256A2DB93C0F00C395C0 /* DomainInterface.framework */, - 084A25672DB93C0C00C395C0 /* MLSCore.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 087929192DB90F11009C301F = { - isa = PBXGroup; - children = ( - 087929252DB90F11009C301F /* Domain */, - 0801752F2DCD26B300D0919F /* DomainInterface */, - 084A25662DB93C0C00C395C0 /* Frameworks */, - 087929242DB90F11009C301F /* Products */, - ); - sourceTree = ""; - }; - 087929242DB90F11009C301F /* Products */ = { - isa = PBXGroup; - children = ( - 087929232DB90F11009C301F /* Domain.framework */, - 0801752E2DCD26B300D0919F /* DomainInterface.framework */, - ); - name = Products; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 080175292DCD26B300D0919F /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 0879291E2DB90F11009C301F /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 0801752D2DCD26B300D0919F /* DomainInterface */ = { - isa = PBXNativeTarget; - buildConfigurationList = 080175332DCD26B300D0919F /* Build configuration list for PBXNativeTarget "DomainInterface" */; - buildPhases = ( - 080175292DCD26B300D0919F /* Headers */, - 0801752A2DCD26B300D0919F /* Sources */, - 0801752B2DCD26B300D0919F /* Frameworks */, - 0801752C2DCD26B300D0919F /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - fileSystemSynchronizedGroups = ( - 0801752F2DCD26B300D0919F /* DomainInterface */, - ); - name = DomainInterface; - packageProductDependencies = ( - 08ED49312DCFDEF6002C21A2 /* RxSwift */, - 779FC8992E1411D100FD1551 /* RxRelay */, - ); - productName = DomainInterface; - productReference = 0801752E2DCD26B300D0919F /* DomainInterface.framework */; - productType = "com.apple.product-type.framework"; - }; - 087929222DB90F11009C301F /* Domain */ = { - isa = PBXNativeTarget; - buildConfigurationList = 087929292DB90F11009C301F /* Build configuration list for PBXNativeTarget "Domain" */; - buildPhases = ( - 0879291E2DB90F11009C301F /* Headers */, - 0879291F2DB90F11009C301F /* Sources */, - 087929202DB90F11009C301F /* Frameworks */, - 087929212DB90F11009C301F /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 0801754E2DCD275300D0919F /* PBXTargetDependency */, - ); - fileSystemSynchronizedGroups = ( - 087929252DB90F11009C301F /* Domain */, - ); - name = Domain; - packageProductDependencies = ( - 08ED49352DCFDF8F002C21A2 /* RxSwift */, - ); - productName = Domain; - productReference = 087929232DB90F11009C301F /* Domain.framework */; - productType = "com.apple.product-type.framework"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 0879291A2DB90F11009C301F /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastUpgradeCheck = 1620; - TargetAttributes = { - 0801752D2DCD26B300D0919F = { - CreatedOnToolsVersion = 16.2; - }; - 087929222DB90F11009C301F = { - CreatedOnToolsVersion = 16.2; - LastSwiftMigration = 1620; - }; - }; - }; - buildConfigurationList = 0879291D2DB90F11009C301F /* Build configuration list for PBXProject "Domain" */; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 087929192DB90F11009C301F; - minimizedProjectReferenceProxies = 1; - packageReferences = ( - 0858AC052DCFDC640060EBCA /* XCRemoteSwiftPackageReference "RxSwift" */, - ); - preferredProjectObjectVersion = 77; - productRefGroup = 087929242DB90F11009C301F /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 087929222DB90F11009C301F /* Domain */, - 0801752D2DCD26B300D0919F /* DomainInterface */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 0801752C2DCD26B300D0919F /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 087929212DB90F11009C301F /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 0801752A2DCD26B300D0919F /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 0879291F2DB90F11009C301F /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 0801754E2DCD275300D0919F /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 0801752D2DCD26B300D0919F /* DomainInterface */; - targetProxy = 0801754D2DCD275300D0919F /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 080175342DCD26B300D0919F /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.DomainInterface; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 080175352DCD26B300D0919F /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.DomainInterface; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; - 0879292A2DB90F11009C301F /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.Domain; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 0879292B2DB90F11009C301F /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.Domain; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; - 0879292C2DB90F11009C301F /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.2; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 0879292D2DB90F11009C301F /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.2; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 080175332DCD26B300D0919F /* Build configuration list for PBXNativeTarget "DomainInterface" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 080175342DCD26B300D0919F /* Debug */, - 080175352DCD26B300D0919F /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 0879291D2DB90F11009C301F /* Build configuration list for PBXProject "Domain" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 0879292C2DB90F11009C301F /* Debug */, - 0879292D2DB90F11009C301F /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 087929292DB90F11009C301F /* Build configuration list for PBXNativeTarget "Domain" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 0879292A2DB90F11009C301F /* Debug */, - 0879292B2DB90F11009C301F /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - 0858AC052DCFDC640060EBCA /* XCRemoteSwiftPackageReference "RxSwift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ReactiveX/RxSwift"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 6.9.0; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 08ED49312DCFDEF6002C21A2 /* RxSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 0858AC052DCFDC640060EBCA /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxSwift; - }; - 08ED49352DCFDF8F002C21A2 /* RxSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 0858AC052DCFDC640060EBCA /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxSwift; - }; - 779FC8992E1411D100FD1551 /* RxRelay */ = { - isa = XCSwiftPackageProductDependency; - package = 0858AC052DCFDC640060EBCA /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxRelay; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 0879291A2DB90F11009C301F /* Project object */; -} diff --git a/MLS/Domain/Domain.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/MLS/Domain/Domain.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 94b2795e..00000000 --- a/MLS/Domain/Domain.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/MLS/Domain/Domain/Interceptor/TokenInterceptor.swift b/MLS/Domain/Domain/Interceptor/TokenInterceptor.swift deleted file mode 100644 index 089a9c95..00000000 --- a/MLS/Domain/Domain/Interceptor/TokenInterceptor.swift +++ /dev/null @@ -1,29 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class TokenInterceptor: Interceptor { - private let fetchTokenUseCase: FetchTokenFromLocalUseCase - - public init(fetchTokenUseCase: FetchTokenFromLocalUseCase) { - self.fetchTokenUseCase = fetchTokenUseCase - } - - public func adapt(_ request: URLRequest) -> URLRequest { - let accessFetchResult = fetchTokenUseCase.execute(type: .accessToken) - switch accessFetchResult { - case .success(let token): - var adaptedRequest = request - adaptedRequest.setValue("Bearer \(token)", forHTTPHeaderField: "Authorization") - return adaptedRequest - case .failure: - return request - } - } - - public func retry(data: Data?, response: URLResponse?, error: Error?) -> Bool { - return false - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchAllAlarmUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchAllAlarmUseCaseImpl.swift deleted file mode 100644 index 9622cd52..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchAllAlarmUseCaseImpl.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class FetchAllAlarmUseCaseImpl: FetchAllAlarmUseCase { - private var repository: AlarmAPIRepository - - public init(repository: AlarmAPIRepository) { - self.repository = repository - } - - public func execute(id: Int?, pageSize: Int) -> Observable> { - return repository.fetchAll(cursor: id, pageSize: pageSize) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchNoticesUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchNoticesUseCaseImpl.swift deleted file mode 100644 index b464aeed..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchNoticesUseCaseImpl.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class FetchNoticesUseCaseImpl: FetchNoticesUseCase { - private var repository: AlarmAPIRepository - - public init(repository: AlarmAPIRepository) { - self.repository = repository - } - - public func execute(id: Int?, pageSize: Int) -> Observable> { - return repository.fetchNotices(cursor: id, pageSize: pageSize) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchOngoingEventsUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchOngoingEventsUseCaseImpl.swift deleted file mode 100644 index 2a1c961f..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchOngoingEventsUseCaseImpl.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class FetchOngoingEventsUseCaseImpl: FetchOngoingEventsUseCase { - private var repository: AlarmAPIRepository - - public init(repository: AlarmAPIRepository) { - self.repository = repository - } - - public func execute(id: Int?, pageSize: Int) -> Observable> { - return repository.fetchOngoingEvents(cursor: id, pageSize: pageSize) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchOutdatedEventsUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchOutdatedEventsUseCaseImpl.swift deleted file mode 100644 index ba778aa4..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchOutdatedEventsUseCaseImpl.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class FetchOutdatedEventsUseCaseImpl: FetchOutdatedEventsUseCase { - private var repository: AlarmAPIRepository - - public init(repository: AlarmAPIRepository) { - self.repository = repository - } - - public func execute(id: Int?, pageSize: Int) -> Observable> { - return repository.fetchOutdatedEvents(cursor: id, pageSize: pageSize) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchPatchNotesUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchPatchNotesUseCaseImpl.swift deleted file mode 100644 index 122fa2ec..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Alarm/FetchPatchNotesUseCaseImpl.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class FetchPatchNotesUseCaseImpl: FetchPatchNotesUseCase { - private var repository: AlarmAPIRepository - - public init(repository: AlarmAPIRepository) { - self.repository = repository - } - - public func execute(id: Int?, pageSize: Int) -> Observable> { - return repository.fetchPatchNotes(cursor: id, pageSize: pageSize) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Alarm/SetReadUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Alarm/SetReadUseCaseImpl.swift deleted file mode 100644 index 9ce49f4d..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Alarm/SetReadUseCaseImpl.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class SetReadUseCaseImpl: SetReadUseCase { - private var repository: AlarmAPIRepository - - public init(repository: AlarmAPIRepository) { - self.repository = repository - } - - public func execute(alarmLink: String) -> Completable { - return repository.setRead(alarmLink: alarmLink) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/CheckLoginUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/CheckLoginUseCaseImpl.swift deleted file mode 100644 index 5b285263..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/CheckLoginUseCaseImpl.swift +++ /dev/null @@ -1,45 +0,0 @@ -import DomainInterface - -import RxRelay -import RxSwift - -public final class CheckLoginUseCaseImpl: CheckLoginUseCase { - private let authRepository: AuthAPIRepository - private let tokenRepository: TokenRepository - - public init(authRepository: AuthAPIRepository, tokenRepository: TokenRepository) { - self.authRepository = authRepository - self.tokenRepository = tokenRepository - } - - public func execute() -> Observable { - switch tokenRepository.fetchToken(type: .refreshToken) { - case .success(let token): - guard !token.isEmpty else { return .just(false) } - - return authRepository.reissueToken(refreshToken: token) - .map { [weak self] response in - guard let self else { return false } - - let accessResult = self.tokenRepository.saveToken(type: .accessToken, value: response.accessToken) - let refreshResult = self.tokenRepository.saveToken(type: .refreshToken, value: response.refreshToken) - - switch (accessResult, refreshResult) { - case (.success, .success): - return true - case (.failure(let error), _), - (_, .failure(let error)): - print("Token 저장 실패:", error.localizedDescription) - return false - } - } - .catch { error in - print("reissueToken 실패:", error.localizedDescription) - return .just(false) - } - - case .failure: - return .just(false) - } - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/CheckNotificationPermissionUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/CheckNotificationPermissionUseCaseImpl.swift deleted file mode 100644 index 72deffc0..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/CheckNotificationPermissionUseCaseImpl.swift +++ /dev/null @@ -1,23 +0,0 @@ -import UserNotifications - -import DomainInterface - -import RxSwift - -public final class CheckNotificationPermissionUseCaseImpl: CheckNotificationPermissionUseCase { - public init() {} - - public func execute() -> Single { - return Single.create { single in - UNUserNotificationCenter.current().getNotificationSettings { settings in - switch settings.authorizationStatus { - case .authorized: - single(.success(true)) - default: - single(.success(false)) - } - } - return Disposables.create() - } - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/FetchJobListUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/FetchJobListUseCaseImpl.swift deleted file mode 100644 index 9521f325..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/FetchJobListUseCaseImpl.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class FetchJobListUseCaseImpl: FetchJobListUseCase { - private var repository: AuthAPIRepository - - public init(repository: AuthAPIRepository) { - self.repository = repository - } - - public func execute() -> Observable { - return repository.fetchJobList() - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/FetchPlatformUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/FetchPlatformUseCaseImpl.swift deleted file mode 100644 index 40e7100d..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/FetchPlatformUseCaseImpl.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class FetchPlatformUseCaseImpl: FetchPlatformUseCase { - private var repository: UserDefaultsRepository - - public init(repository: UserDefaultsRepository) { - self.repository = repository - } - - public func execute() -> Observable { - return repository.fetchPlatform() - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithAppleUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithAppleUseCaseImpl.swift deleted file mode 100644 index 1819bf20..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithAppleUseCaseImpl.swift +++ /dev/null @@ -1,50 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class LoginWithAppleUseCaseImpl: LoginWithAppleUseCase { - private var authRepository: AuthAPIRepository - private let tokenRepository: TokenRepository - private var userDefaultsRepository: UserDefaultsRepository - - public init(authRepository: AuthAPIRepository, tokenRepository: TokenRepository, userDefaultsRepository: UserDefaultsRepository) { - self.authRepository = authRepository - self.tokenRepository = tokenRepository - self.userDefaultsRepository = userDefaultsRepository - } - - // 로그인할때 토큰 저장 필요 - public func execute(credential: Credential) -> Observable { - return authRepository.loginWithApple(credential: credential) - .flatMap { response -> Observable in - let saveAccess = self.tokenRepository.saveToken(type: .accessToken, value: response.accessToken) - let saveRefresh = self.tokenRepository.saveToken(type: .refreshToken, value: response.refreshToken) - let savePlatform = self.userDefaultsRepository.savePlatform(platform: .apple) - - guard case (.success, .success) = (saveAccess, saveRefresh) else { - return Observable.error(TokenRepositoryError.dataConversionError(message: "Failed to save tokens")) - } - - var fcmToken: String? - if case .success(let token) = self.tokenRepository.fetchToken(type: .fcmToken) { - fcmToken = token - } - - let fcmUpdate = if let fcmToken { - self.authRepository.fcmToken(fcmToken: fcmToken) - .catch { error in - print("FCM token update failed: \(error)") - return .empty() - } - } else { - Completable.empty() - } - return fcmUpdate.andThen(savePlatform).andThen(Observable.just(response)) - } - .catch { error in - Observable.error(error) - } - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithKakaoUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithKakaoUseCaseImpl.swift deleted file mode 100644 index db4e8719..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LoginWithKakaoUseCaseImpl.swift +++ /dev/null @@ -1,49 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class LoginWithKakaoUseCaseImpl: LoginWithKakaoUseCase { - private var authRepository: AuthAPIRepository - private let tokenRepository: TokenRepository - private var userDefaultsRepository: UserDefaultsRepository - - public init(authRepository: AuthAPIRepository, tokenRepository: TokenRepository, userDefaultsRepository: UserDefaultsRepository) { - self.authRepository = authRepository - self.tokenRepository = tokenRepository - self.userDefaultsRepository = userDefaultsRepository - } - - public func execute(credential: Credential) -> Observable { - return authRepository.loginWithKakao(credential: credential) - .flatMap { response -> Observable in - let saveAccess = self.tokenRepository.saveToken(type: .accessToken, value: response.accessToken) - let saveRefresh = self.tokenRepository.saveToken(type: .refreshToken, value: response.refreshToken) - let savePlatform = self.userDefaultsRepository.savePlatform(platform: .kakao) - - guard case (.success, .success) = (saveAccess, saveRefresh) else { - return Observable.error(TokenRepositoryError.dataConversionError(message: "Failed to save tokens")) - } - - var fcmToken: String? - if case .success(let token) = self.tokenRepository.fetchToken(type: .fcmToken) { - fcmToken = token - } - - let fcmUpdate = if let fcmToken { - self.authRepository.fcmToken(fcmToken: fcmToken) - .catch { error in - print("FCM token update failed: \(error)") - return .empty() - } - } else { - Completable.empty() - } - return fcmUpdate.andThen(savePlatform).andThen(Observable.just(response)) - } - .catch { error in - Observable.error(error) - } - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LogoutUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LogoutUseCaseImpl.swift deleted file mode 100644 index 0ece074f..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/LogoutUseCaseImpl.swift +++ /dev/null @@ -1,42 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class LogoutUseCaseImpl: LogoutUseCase { - private var repository: TokenRepository - - public init(repository: TokenRepository) { - self.repository = repository - } - - public func execute() -> Completable { - return Completable.create { [weak self] completable in - guard let self = self else { - completable(.completed) - return Disposables.create() - } - - let deleteAccess = self.repository.deleteToken(type: .accessToken) - let deleteRefresh = self.repository.deleteToken(type: .refreshToken) - - guard case .success = deleteAccess, case .success = deleteRefresh else { - completable(.error(NSError(domain: "LogoutError", code: -1, userInfo: nil))) - return Disposables.create() - } - - var fcmToken: String? - if case .success(let token) = self.repository.fetchToken(type: .fcmToken) { - fcmToken = token - } - - if fcmToken != nil { - _ = self.repository.deleteToken(type: .fcmToken) - } - - completable(.completed) - return Disposables.create() - } - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/OpenNotificationSettingUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/OpenNotificationSettingUseCaseImpl.swift deleted file mode 100644 index cb716070..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/OpenNotificationSettingUseCaseImpl.swift +++ /dev/null @@ -1,14 +0,0 @@ -import UIKit - -import DomainInterface - -public final class OpenNotificationSettingUseCaseImpl: OpenNotificationSettingUseCase { - public init() {} - - public func execute() { - guard let url = URL(string: UIApplication.openSettingsURLString) else { return } - if UIApplication.shared.canOpenURL(url) { - UIApplication.shared.open(url, options: [:], completionHandler: nil) - } - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/PutFCMTokenUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/PutFCMTokenUseCaseImpl.swift deleted file mode 100644 index 8f08eba0..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/PutFCMTokenUseCaseImpl.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class PutFCMTokenUseCaseImpl: PutFCMTokenUseCase { - private var repository: AuthAPIRepository - - public init(repository: AuthAPIRepository) { - self.repository = repository - } - - public func execute(fcmToken: String?) -> Completable { - return repository.fcmToken(fcmToken: fcmToken) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/ReissueUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/ReissueUseCaseImpl.swift deleted file mode 100644 index 4f632e16..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/ReissueUseCaseImpl.swift +++ /dev/null @@ -1,37 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public final class ReissueUseCaseImpl: ReissueUseCase { - private let repository: AuthAPIRepository - private let tokenRepository: TokenRepository - - public init( - repository: AuthAPIRepository, - tokenRepository: TokenRepository - ) { - self.repository = repository - self.tokenRepository = tokenRepository - } - - public func execute(refreshToken: String) -> Observable { - return repository.reissueToken(refreshToken: refreshToken) - .flatMap { [weak self] response -> Observable in - guard let self = self else { return .empty() } - - let saveAccess = self.tokenRepository.saveToken(type: .accessToken, value: response.accessToken) - let saveRefresh = self.tokenRepository.saveToken(type: .refreshToken, value: response.refreshToken) - - switch (saveAccess, saveRefresh) { - case (.success, .success): - print("✅ 새 토큰 저장 완료") - return .just(response) - default: - print("❌ 토큰 저장 실패") - return .error(TokenRepositoryError.dataConversionError(message: "Failed to save new tokens")) - } - } - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithAppleUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithAppleUseCaseImpl.swift deleted file mode 100644 index 6a1ed88a..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithAppleUseCaseImpl.swift +++ /dev/null @@ -1,47 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public final class SignUpWithAppleUseCaseImpl: SignUpWithAppleUseCase { - private let authRepository: AuthAPIRepository - private let tokenRepository: TokenRepository - private let userDefaultsRepository: UserDefaultsRepository - - public init( - authRepository: AuthAPIRepository, - tokenRepository: TokenRepository, - userDefaultsRepository: UserDefaultsRepository - ) { - self.authRepository = authRepository - self.tokenRepository = tokenRepository - self.userDefaultsRepository = userDefaultsRepository - } - - public func execute( - credential: Credential, - isMarketingAgreement: Bool, - fcmToken: String? - ) -> Observable { - return authRepository - .signUpWithApple(credential: credential, isMarketingAgreement: isMarketingAgreement, fcmToken: fcmToken) - .flatMap { response -> Observable in - let saveAccess = self.tokenRepository.saveToken(type: .accessToken, value: response.accessToken) - let saveRefresh = self.tokenRepository.saveToken(type: .refreshToken, value: response.refreshToken) - let savePlatform = self.userDefaultsRepository.savePlatform(platform: .apple) - - switch (saveAccess, saveRefresh) { - case (.success, .success): - return savePlatform.andThen(Observable.just(response)) - default: - return Observable.error( - TokenRepositoryError.dataConversionError(message: "Failed to save tokens") - ) - } - } - .catch { error in - Observable.error(error) - } - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithKakaoUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithKakaoUseCaseImpl.swift deleted file mode 100644 index 7316776b..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/SignUpWithKakaoUseCaseImpl.swift +++ /dev/null @@ -1,45 +0,0 @@ -import DomainInterface -import Foundation -import RxSwift - -public final class SignUpWithKakaoUseCaseImpl: SignUpWithKakaoUseCase { - private let authRepository: AuthAPIRepository - private let tokenRepository: TokenRepository - private let userDefaultsRepository: UserDefaultsRepository - - public init( - authRepository: AuthAPIRepository, - tokenRepository: TokenRepository, - userDefaultsRepository: UserDefaultsRepository - ) { - self.authRepository = authRepository - self.tokenRepository = tokenRepository - self.userDefaultsRepository = userDefaultsRepository - } - - public func execute( - credential: Credential, - isMarketingAgreement: Bool, - fcmToken: String? - ) -> Observable { - return authRepository - .signUpWithKakao(credential: credential, isMarketingAgreement: isMarketingAgreement, fcmToken: fcmToken) - .flatMap { response -> Observable in - let saveAccess = self.tokenRepository.saveToken(type: .accessToken, value: response.accessToken) - let saveRefresh = self.tokenRepository.saveToken(type: .refreshToken, value: response.refreshToken) - let savePlatform = self.userDefaultsRepository.savePlatform(platform: .kakao) - - switch (saveAccess, saveRefresh) { - case (.success, .success): - return savePlatform.andThen(Observable.just(response)) - default: - return Observable.error( - TokenRepositoryError.dataConversionError(message: "Failed to save tokens") - ) - } - } - .catch { error in - Observable.error(error) - } - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/UpdateMarketingAgreementUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/UpdateMarketingAgreementUseCaseImpl.swift deleted file mode 100644 index c0a4d6f4..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/UpdateMarketingAgreementUseCaseImpl.swift +++ /dev/null @@ -1,25 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class UpdateMarketingAgreementUseCaseImpl: UpdateMarketingAgreementUseCase { - private let authRepository: AuthAPIRepository - private let tokenRepository: TokenRepository - - public init(authRepository: AuthAPIRepository, tokenRepository: TokenRepository) { - self.authRepository = authRepository - self.tokenRepository = tokenRepository - } - - public func execute(credential: String, isMarketingAgreement: Bool) -> Completable { - switch tokenRepository.fetchToken(type: .accessToken) { - case .success(let token): - return authRepository.updateMarketingAgreement(credential: token, isMarketingAgreement: isMarketingAgreement) - case .failure(let error): - return .error(error) - } - - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/UpdateNotificationAgreementUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/UpdateNotificationAgreementUseCaseImpl.swift deleted file mode 100644 index 2d95c3d7..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/UpdateNotificationAgreementUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public class UpdateNotificationAgreementUseCaseImpl: UpdateNotificationAgreementUseCase { - private let repository: AuthAPIRepository - - public init(authRepository: AuthAPIRepository) { - self.repository = authRepository - } - - public func execute(noticeAgreement: Bool, patchNoteAgreement: Bool, eventAgreement: Bool) -> Completable { - return repository.updateNotificationAgreement(noticeAgreement: noticeAgreement, patchNoteAgreement: patchNoteAgreement, eventAgreement: eventAgreement) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/UpdateUserInfoUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/UpdateUserInfoUseCaseImpl.swift deleted file mode 100644 index c0320dd6..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/UpdateUserInfoUseCaseImpl.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class UpdateUserInfoUseCaseImpl: UpdateUserInfoUseCase { - private var repository: AuthAPIRepository - - public init(repository: AuthAPIRepository) { - self.repository = repository - } - - public func execute(level: Int, selectedJobID: Int) -> Completable { - return repository.updateUserInfo(level: level, selectedJobID: selectedJobID) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/WithdrawUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/AuthAPI/WithdrawUseCaseImpl.swift deleted file mode 100644 index fc6b314d..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/AuthAPI/WithdrawUseCaseImpl.swift +++ /dev/null @@ -1,34 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class WithdrawUseCaseImpl: WithdrawUseCase { - private let authRepository: AuthAPIRepository - private let tokenRepository: TokenRepository - - public init(authRepository: AuthAPIRepository, tokenRepository: TokenRepository) { - self.authRepository = authRepository - self.tokenRepository = tokenRepository - } - - public func execute() -> Completable { - return authRepository.withdraw() - .andThen(Completable.deferred { [weak self] in - guard let self = self else { return .empty() } - - let results: [Result] = [ - self.tokenRepository.deleteToken(type: .accessToken), - self.tokenRepository.deleteToken(type: .refreshToken) - ] - - for result in results { - if case .failure(let error) = result { - return .error(error) - } - } - return .empty() - }) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchBookmarkUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchBookmarkUseCaseImpl.swift deleted file mode 100644 index 9ad0aca7..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchBookmarkUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchBookmarkUseCaseImpl: FetchBookmarkUseCase { - private let repository: BookmarkRepository - - public init(repository: BookmarkRepository) { - self.repository = repository - } - - public func execute(sort: SortType?) -> Observable<[BookmarkResponse]> { - return repository.fetchBookmark(sort: sort?.sortParameter) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchItemBookmarkUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchItemBookmarkUseCaseImpl.swift deleted file mode 100644 index 9ea2cf69..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchItemBookmarkUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchItemBookmarkUseCaseImpl: FetchItemBookmarkUseCase { - private let repository: BookmarkRepository - - public init(repository: BookmarkRepository) { - self.repository = repository - } - - public func execute(jobId: Int?, minLevel: Int?, maxLevel: Int?, categoryIds: [Int]?, sort: SortType?) -> Observable<[BookmarkResponse]> { - return repository.fetchItemBookmark(jobId: jobId, minLevel: minLevel, maxLevel: maxLevel, categoryIds: categoryIds, sort: sort?.sortParameter) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchMapBookmarkUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchMapBookmarkUseCaseImpl.swift deleted file mode 100644 index 820a6ebc..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchMapBookmarkUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchMapBookmarkUseCaseImpl: FetchMapBookmarkUseCase { - private let repository: BookmarkRepository - - public init(repository: BookmarkRepository) { - self.repository = repository - } - - public func execute(sort: SortType?) -> Observable<[BookmarkResponse]> { - return repository.fetchMapBookmark(sort: sort?.sortParameter) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchMonsterBookmarkUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchMonsterBookmarkUseCaseImpl.swift deleted file mode 100644 index 486c066a..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchMonsterBookmarkUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchMonsterBookmarkUseCaseImpl: FetchMonsterBookmarkUseCase { - private let repository: BookmarkRepository - - public init(repository: BookmarkRepository) { - self.repository = repository - } - - public func execute(minLevel: Int?, maxLevel: Int?, sort: SortType?) -> Observable<[BookmarkResponse]> { - return repository.fetchMonsterBookmark(minLevel: minLevel, maxLevel: maxLevel, sort: sort?.sortParameter) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchNPCBookmarkUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchNPCBookmarkUseCaseImpl.swift deleted file mode 100644 index ed56836c..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchNPCBookmarkUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchNPCBookmarkUseCaseImpl: FetchNPCBookmarkUseCase { - private let repository: BookmarkRepository - - public init(repository: BookmarkRepository) { - self.repository = repository - } - - public func execute(sort: SortType?) -> Observable<[BookmarkResponse]> { - return repository.fetchNPCBookmark(sort: sort?.sortParameter) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchQuestBookmarkUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchQuestBookmarkUseCaseImpl.swift deleted file mode 100644 index eca2d814..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchQuestBookmarkUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchQuestBookmarkUseCaseImpl: FetchQuestBookmarkUseCase { - private let repository: BookmarkRepository - - public init(repository: BookmarkRepository) { - self.repository = repository - } - - public func execute(sort: SortType?) -> Observable<[BookmarkResponse]> { - return repository.fetchQuestBookmark(sort: sort?.sortParameter) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchVisitBookmarkUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchVisitBookmarkUseCaseImpl.swift deleted file mode 100644 index 1424d1b5..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Bookmark/FetchVisitBookmarkUseCaseImpl.swift +++ /dev/null @@ -1,23 +0,0 @@ -import DomainInterface -import Foundation - -import RxSwift - -public class FetchVisitBookmarkUseCaseImpl: FetchVisitBookmarkUseCase { - var repository: UserDefaultsRepository - public init(repository: UserDefaultsRepository) { - self.repository = repository - } - - public func execute() -> Observable { - return repository.fetchBookmark() - .flatMap { hasVisited -> Observable in - if hasVisited { - return .just(true) - } else { - return self.repository.saveBookmark() - .andThen(.just(false)) - } - } - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Bookmark/SetBookmarkUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Bookmark/SetBookmarkUseCaseImpl.swift deleted file mode 100644 index 0a45e333..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Bookmark/SetBookmarkUseCaseImpl.swift +++ /dev/null @@ -1,22 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class SetBookmarkUseCaseImpl: SetBookmarkUseCase { - private let repository: BookmarkRepository - - public init(repository: BookmarkRepository) { - self.repository = repository - } - - public func execute(bookmarkId: Int, isBookmark: IsBookmark) -> Observable { - switch isBookmark { - case .set(let type): - return repository - .setBookmark(bookmarkId: bookmarkId, type: type) - .map { Optional($0) } - case .delete: - return repository.deleteBookmark(bookmarkId: bookmarkId) - } - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Collection/AddCollectionAndBookmarkUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Collection/AddCollectionAndBookmarkUseCaseImpl.swift deleted file mode 100644 index 55b640e6..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Collection/AddCollectionAndBookmarkUseCaseImpl.swift +++ /dev/null @@ -1,14 +0,0 @@ -import DomainInterface -import RxSwift - -public final class AddCollectionAndBookmarkUseCaseImpl: AddCollectionAndBookmarkUseCase { - private let repository: CollectionAPIRepository - - public init(repository: CollectionAPIRepository) { - self.repository = repository - } - - public func execute(collectionIds: [Int], bookmarkIds: [Int]) -> Completable { - return repository.addCollectionAndBookmark(collectionIds: collectionIds, bookmarkIds: bookmarkIds) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Collection/CreateCollectionListUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Collection/CreateCollectionListUseCaseImpl.swift deleted file mode 100644 index 5325ee16..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Collection/CreateCollectionListUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class CreateCollectionListUseCaseImpl: CreateCollectionListUseCase { - private let repository: CollectionAPIRepository - - public init(repository: CollectionAPIRepository) { - self.repository = repository - } - - public func execute(name: String) -> Completable { - return repository.createCollectionList(name: name) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Collection/DeleteCollectionUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Collection/DeleteCollectionUseCaseImpl.swift deleted file mode 100644 index 40b318f3..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Collection/DeleteCollectionUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class DeleteCollectionUseCaseImpl: DeleteCollectionUseCase { - private let repository: CollectionAPIRepository - - public init(repository: CollectionAPIRepository) { - self.repository = repository - } - - public func execute(collectionId: Int) -> Completable { - return repository.deleteCollection(collectionId: collectionId) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Collection/FetchCollectionListUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Collection/FetchCollectionListUseCaseImpl.swift deleted file mode 100644 index a1f88c48..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Collection/FetchCollectionListUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchCollectionListUseCaseImpl: FetchCollectionListUseCase { - private let repository: CollectionAPIRepository - - public init(repository: CollectionAPIRepository) { - self.repository = repository - } - - public func execute(sort: SortType?) -> Observable<[CollectionResponse]> { - return repository.fetchCollectionList(sort: sort?.sortParameter) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Collection/FetchCollectionUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Collection/FetchCollectionUseCaseImpl.swift deleted file mode 100644 index 94067888..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Collection/FetchCollectionUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchCollectionUseCaseImpl: FetchCollectionUseCase { - private let repository: CollectionAPIRepository - - public init(repository: CollectionAPIRepository) { - self.repository = repository - } - - public func execute(id: Int) -> Observable<[BookmarkResponse]> { - return repository.fetchCollectionUseCase(id: id) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Collection/UpdateCollectionUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Collection/UpdateCollectionUseCaseImpl.swift deleted file mode 100644 index f8dc3727..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Collection/UpdateCollectionUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class UpdateCollectionUseCaseImpl: UpdateCollectionUseCase { - private let repository: CollectionAPIRepository - - public init(repository: CollectionAPIRepository) { - self.repository = repository - } - - public func execute(collectionId: Int, name: String) -> Completable { - return repository.updateCollectionName(collectionId: collectionId, name: name) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailItemMonsterUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailItemMonsterUseCaseImpl.swift deleted file mode 100644 index 322f67d1..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailItemMonsterUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchDictionaryDetailItemDropMonsterUseCaseImpl: FetchDictionaryDetailItemDropMonsterUseCase { - private let repository: DictionaryDetailAPIRepository - - public init(repository: DictionaryDetailAPIRepository) { - self.repository = repository - } - - public func execute(id: Int, sort: String?) -> Observable<[DictionaryDetailItemDropMonsterResponse]> { - return repository.fetchItemDetailDropMonster(id: id, sort: sort) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailItemUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailItemUseCaseImpl.swift deleted file mode 100644 index f3fde890..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailItemUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchDictionaryDetailItemUseCaseImpl: FetchDictionaryDetailItemUseCase { - private let repository: DictionaryDetailAPIRepository - - public init(repository: DictionaryDetailAPIRepository) { - self.repository = repository - } - - public func execute(id: Int) -> Observable { - return repository.fetchItemDetail(id: id) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMapNpcUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMapNpcUseCaseImpl.swift deleted file mode 100644 index aa65dcef..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMapNpcUseCaseImpl.swift +++ /dev/null @@ -1,13 +0,0 @@ -import DomainInterface -import RxSwift - -public final class FetchDictionaryDetailMapNpcUseCaseImpl: FetchDictionaryDetailMapNpcUseCase { - private let repository: DictionaryDetailAPIRepository - public init(repository: DictionaryDetailAPIRepository) { - self.repository = repository - } - - public func execute(id: Int) -> Observable<[DictionaryDetailMapNpcResponse]> { - return repository.fetchMapDetailNpc(id: id) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMapSpawnMonsterUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMapSpawnMonsterUseCaseImpl.swift deleted file mode 100644 index 97ed90a1..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMapSpawnMonsterUseCaseImpl.swift +++ /dev/null @@ -1,13 +0,0 @@ -import DomainInterface -import RxSwift - -public final class FetchDictionaryDetailMapSpawnMonsterUseCaseImpl: FetchDictionaryDetailMapSpawnMonsterUseCase { - private let repository: DictionaryDetailAPIRepository - public init(repository: DictionaryDetailAPIRepository) { - self.repository = repository - } - - public func execute(id: Int, sort: String?) -> Observable<[DictionaryDetailMapSpawnMonsterResponse]> { - return repository.fetchMapDetailSpawnMonster(id: id, sort: sort) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMapUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMapUseCaseImpl.swift deleted file mode 100644 index 73569a93..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMapUseCaseImpl.swift +++ /dev/null @@ -1,14 +0,0 @@ -import DomainInterface -import RxSwift - -public final class FetchDictionaryDetailMapUseCaseImpl: FetchDictionaryDetailMapUseCase { - private let repository: DictionaryDetailAPIRepository - - public init(repository: DictionaryDetailAPIRepository) { - self.repository = repository - } - - public func execute(id: Int) -> Observable { - return repository.fetchMapDetail(id: id) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMonsterDropItemUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMonsterDropItemUseCaseImpl.swift deleted file mode 100644 index c55067ac..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMonsterDropItemUseCaseImpl.swift +++ /dev/null @@ -1,14 +0,0 @@ -import DomainInterface -import RxSwift - -public final class FetchDictionaryDetailMonsterDropItemUseCaseImpl: FetchDictionaryDetailMonsterItemsUseCase { - private let repository: DictionaryDetailAPIRepository - public init(repository: DictionaryDetailAPIRepository) { - self.repository = repository - } - - public func execute(id: Int, sort: String?) -> Observable<[DictionaryDetailMonsterDropItemResponse]> { - return repository.fetchMonsterDetailDropItem(id: id, sort: sort) - } - -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMonsterMapUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMonsterMapUseCaseImpl.swift deleted file mode 100644 index f617cd0e..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMonsterMapUseCaseImpl.swift +++ /dev/null @@ -1,12 +0,0 @@ -import DomainInterface -import RxSwift - -public final class FetchDictionaryDetailMonsterMapUseCaseImpl: FetchDictionaryDetailMonsterMapUseCase { - private let repository: DictionaryDetailAPIRepository - public init(repository: DictionaryDetailAPIRepository) { - self.repository = repository - } - public func execute(id: Int) -> Observable<[DictionaryDetailMonsterMapResponse]> { - return repository.fetchMonsterDetailMap(id: id) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMonsterUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMonsterUseCaseImpl.swift deleted file mode 100644 index 962dcca0..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailMonsterUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchDictionaryDetailMonsterUseCaseImpl: FetchDictionaryDetailMonsterUseCase { - private let repository: DictionaryDetailAPIRepository - - public init(repository: DictionaryDetailAPIRepository) { - self.repository = repository - } - - public func execute(id: Int) -> Observable { - return repository.fetchMonsterDetail(id: id) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailNpcMapUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailNpcMapUseCaseImpl.swift deleted file mode 100644 index 33dab664..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailNpcMapUseCaseImpl.swift +++ /dev/null @@ -1,12 +0,0 @@ -import DomainInterface -import RxSwift - -public final class FetchDictionaryDetailNpcMapUseCaseImpl: FetchDictionaryDetailNpcMapUseCase { - private let repository: DictionaryDetailAPIRepository - public init(repository: DictionaryDetailAPIRepository) { - self.repository = repository - } - public func execute(id: Int) -> Observable<[DictionaryDetailMonsterMapResponse]> { - return repository.fetchNpcDetailMap(id: id) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailNpcQuestUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailNpcQuestUseCaseImpl.swift deleted file mode 100644 index 5eee5646..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailNpcQuestUseCaseImpl.swift +++ /dev/null @@ -1,13 +0,0 @@ -import DomainInterface -import RxSwift - -public final class FetchDictionaryDetailNpcQuestUseCaseImpl: FetchDictionaryDetailNpcQuestUseCase { - private let repository: DictionaryDetailAPIRepository - public init(repository: DictionaryDetailAPIRepository) { - self.repository = repository - } - - public func execute(id: Int, sort: String?) -> Observable<[DictionaryDetailNpcQuestResponse]> { - return repository.fetchNpcDetailQuest(id: id, sort: sort) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailNpcUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailNpcUseCaseImpl.swift deleted file mode 100644 index 2f5da66b..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailNpcUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchDictionaryDetailNpcUseCaseImpl: FetchDictionaryDetailNpcUseCase { - private let repository: DictionaryDetailAPIRepository - - public init(repository: DictionaryDetailAPIRepository) { - self.repository = repository - } - - public func execute(id: Int) -> Observable { - return repository.fetchNpcDetail(id: id) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailQuestLinkedQuestsUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailQuestLinkedQuestsUseCaseImpl.swift deleted file mode 100644 index 1a601571..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailQuestLinkedQuestsUseCaseImpl.swift +++ /dev/null @@ -1,14 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchDictionaryDetailQuestLinkedQuestsUseCaseImpl: FetchDictionaryDetailQuestLinkedQuestsUseCase { - private let repository: DictionaryDetailAPIRepository - public init(repository: DictionaryDetailAPIRepository) { - self.repository = repository - } - - public func execute(id: Int) -> Observable { - return repository.fetchQuestDetailLinkedQuestsDetail(id: id) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailQuestUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailQuestUseCaseImpl.swift deleted file mode 100644 index ff339e51..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchDictionaryDetailQuestUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchDictionaryDetailQuestUseCaseImpl: FetchDictionaryDetailQuestUseCase { - private let repository: DictionaryDetailAPIRepository - - public init(repository: DictionaryDetailAPIRepository) { - self.repository = repository - } - - public func execute(id: Int) -> Observable { - return repository.fetchQuestDetail(id: id) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchVisitDictionaryDetailUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchVisitDictionaryDetailUseCaseImpl.swift deleted file mode 100644 index 72ec9a53..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryDetail/FetchVisitDictionaryDetailUseCaseImpl.swift +++ /dev/null @@ -1,23 +0,0 @@ -import DomainInterface -import Foundation - -import RxSwift - -public class FetchVisitDictionaryDetailUseCaseImpl: FetchVisitDictionaryDetailUseCase { - var repository: UserDefaultsRepository - public init(repository: UserDefaultsRepository) { - self.repository = repository - } - - public func execute() -> Observable { - return repository.fetchDictionaryDetail() - .flatMap { hasVisited -> Observable in - if hasVisited { - return .just(true) - } else { - return self.repository.saveDictionaryDetail() - .andThen(.just(false)) - } - } - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryAllListUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryAllListUseCaseImpl.swift deleted file mode 100644 index b146cee6..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryAllListUseCaseImpl.swift +++ /dev/null @@ -1,16 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchDictionaryAllListUseCaseImpl: FetchDictionaryAllListUseCase { - - private let repository: DictionaryListAPIRepository - - public init(repository: DictionaryListAPIRepository) { - self.repository = repository - } - - public func execute(keyword: String?, page: Int?) -> Observable { - return repository.fetchAllList(keyword: keyword, page: page) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryItemListUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryItemListUseCaseImpl.swift deleted file mode 100644 index c9395f7b..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryItemListUseCaseImpl.swift +++ /dev/null @@ -1,16 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchDictionaryItemListUseCaseImpl: FetchDictionaryItemListUseCase { - - private let repository: DictionaryListAPIRepository - - public init(repository: DictionaryListAPIRepository) { - self.repository = repository - } - - public func execute(keyword: String?, jobId: [Int]?, minLevel: Int?, maxLevel: Int?, categoryIds: [Int]?, page: Int?, size: Int?, sort: String?) -> Observable { - return repository.fetchItemList(keyword: keyword, jobId: jobId, minLevel: minLevel, maxLevel: maxLevel, categoryIds: categoryIds, page: page, size: size, sort: sort) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryMapListUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryMapListUseCaseImpl.swift deleted file mode 100644 index 9b04e6bc..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryMapListUseCaseImpl.swift +++ /dev/null @@ -1,16 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchDictionaryMapListUseCaseImpl: FetchDictionaryMapListUseCase { - - private let repository: DictionaryListAPIRepository - - public init(repository: DictionaryListAPIRepository) { - self.repository = repository - } - - public func execute(keyword: String, page: Int, size: Int, sort: String?) -> Observable { - return repository.fetchMapList(keyword: keyword, page: page, size: size, sort: sort) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryMonsterListUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryMonsterListUseCaseImpl.swift deleted file mode 100644 index f7edd9d6..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryMonsterListUseCaseImpl.swift +++ /dev/null @@ -1,16 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchDictionaryMonsterListUseCaseImpl: FetchDictionaryMonsterListUseCase { - - private let repository: DictionaryListAPIRepository - - public init(repository: DictionaryListAPIRepository) { - self.repository = repository - } - public func execute(type: DictionaryType, query: DictionaryListQuery) -> Observable { - return repository.fetchMonsterList(keyword: query.keyword, minLevel: query.minLevel, maxLevel: query.maxLevel, page: query.page, size: query.size, sort: query.sort) - - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryNpcListUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryNpcListUseCaseImpl.swift deleted file mode 100644 index 95ea2602..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryNpcListUseCaseImpl.swift +++ /dev/null @@ -1,16 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchDictionaryNpcListUseCaseImpl: FetchDictionaryNpcListUseCase { - - private let repository: DictionaryListAPIRepository - - public init(repository: DictionaryListAPIRepository) { - self.repository = repository - } - - public func execute(keyword: String, page: Int, size: Int, sort: String?) -> Observable { - return repository.fetchNpcList(keyword: keyword, page: page, size: size, sort: sort) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryQuestListUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryQuestListUseCaseImpl.swift deleted file mode 100644 index efac0f6b..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionaryQuestListUseCaseImpl.swift +++ /dev/null @@ -1,16 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchDictionaryQuestListUseCaseImpl: FetchDictionaryQuestListUseCase { - - private let repository: DictionaryListAPIRepository - - public init(repository: DictionaryListAPIRepository) { - self.repository = repository - } - - public func execute(keyword: String, page: Int, size: Int, sort: String?) -> Observable { - return repository.fetchQuestList(keyword: keyword, page: page, size: size, sort: sort) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionarySearchListUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionarySearchListUseCaseImpl.swift deleted file mode 100644 index 69e0fcb4..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/FetchDictionarySearchListUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchDictionarySearchListUseCaseImpl: FetchDictionarySearchListUseCase { - private let repository: DictionaryListAPIRepository - - public init(repository: DictionaryListAPIRepository) { - self.repository = repository - } - - public func execute(keyword: String) -> Observable { - return repository.fetchAllList(keyword: keyword, page: nil) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/ParseItemFilterResultUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryList/ParseItemFilterResultUseCaseImpl.swift deleted file mode 100644 index 8bb273d4..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/ParseItemFilterResultUseCaseImpl.swift +++ /dev/null @@ -1,59 +0,0 @@ -import DomainInterface - -public final class ParseItemFilterResultUseCaseImpl: ParseItemFilterResultUseCase { - - private let jobIdMap: [String: Int] = [ - "전사": 100, "마법사": 200, "도적": 400, "궁수": 300 - ] - private let categoryIdMap: [String: Int] = [ - "한손검": 7, "한손도끼": 8, "한손둔기": 9, "단검": 10, "완드": 12, - "스태프": 13, "두손검": 14, "두손도끼": 15, "두손둔기": 16, "창": 17, - "폴암": 18, "활": 19, "석궁": 20, "아대": 21, "모자": 24, "상의": 25, - "하의": 26, "전신갑옷": 27, "신발": 28, "장갑": 29, "방패": 31, "망토": 30, - "얼굴장식": 32, "눈장식": 33, "귀고리": 34, "반지": 35, "펜던트": 36, - "벨트": 37, "어깨장식": 38, "화살": 81, "표창": 83, - "한손검주문서": 50, "한손도끼주문서": 51, "한손둔기주문서": 52, - "단검주문서": 53, "완드주문서": 55, "스태프주문서": 56, "두손검주문서": 57, - "두손도끼주문서": 58, "두손둔기주문서": 59, "창주문서": 60, "폴암주문서": 61, - "활주문서": 62, "석궁주문서": 63, "아대주문서": 64, "투구주문서": 67, "상의주문서": 68, "하의주문서": 69, "전신갑옷주문서": 70, "신발주문서": 71, "장갑주문서": 72, "망토주문서": 73, "방패주문서": 74, - "귀장식주문서": 78, "펫장비주문서": 75, "연성서주문서": 76, "귀환주문서": 77, - "마스터리북": 42, "스킬북": 43, "소비": 44, "설치": 45, "이동수단": 46 - ] - - public init() {} - - public func execute(results: [(String, String)]) -> ItemFilterCriteria { - let initialCriteria = (jobIds: [Int](), startLevel: Int?(nil), endLevel: Int?(nil), categoryIds: [Int]()) - - let finalCriteria = results.reduce(into: initialCriteria) { criteria, result in - let (key, value) = result - switch key { - case "직업": - if let id = jobIdMap[value] { - criteria.jobIds.append(id) - } - case "레벨": - let levelText = value.replacingOccurrences(of: "레벨", with: "").trimmingCharacters(in: .whitespaces) - let parts = levelText.split(separator: "~") - .map { $0.trimmingCharacters(in: .whitespaces) } - .map { $0.filter { $0.isNumber } } - if let low = Int(parts.first ?? ""), let high = Int(parts.last ?? "") { - criteria.startLevel = low - criteria.endLevel = high - } - case "무기", "발사체", "방어구", "장신구", "기타아이템": - if let id = categoryIdMap[value] { - criteria.categoryIds.append(id) - } - case "무기주문서", "방어구주문서", "기타주문서": - if let id = categoryIdMap[value + "주문서"] { - criteria.categoryIds.append(id) - } - default: - break - } - } - - return ItemFilterCriteria(jobIds: finalCriteria.jobIds, startLevel: finalCriteria.startLevel, endLevel: finalCriteria.endLevel, categoryIds: finalCriteria.categoryIds) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/ToggleBookmarkUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryList/ToggleBookmarkUseCaseImpl.swift deleted file mode 100644 index 2b89ed51..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryList/ToggleBookmarkUseCaseImpl.swift +++ /dev/null @@ -1,16 +0,0 @@ -// import DomainInterface -// import RxSwift -// -// public final class ToggleBookmarkUseCaseImpl: ToggleBookmarkUseCase { -// private let repository: DictionaryListRepository -// -// public init(repository: DictionaryListRepository) { -// self.repository = repository -// } -// -// public func execute(id: String, type: DictionaryType) -> Observable<[DictionaryItem]> { -// return repository.toggleBookmark(id: id) -// .withLatestFrom(repository.observeItems(type: type)) -// .take(1) -// } -// } diff --git a/MLS/Domain/Domain/UseCaseImpl/DictionaryListCount/FetchDictionaryListCountUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/DictionaryListCount/FetchDictionaryListCountUseCaseImpl.swift deleted file mode 100644 index eb58efa8..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/DictionaryListCount/FetchDictionaryListCountUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class FetchDictionaryListCountUseCaseImpl: FetchDictionaryListCountUseCase { - private let repository: DictionaryListAPIRepository - - public init(repository: DictionaryListAPIRepository) { - self.repository = repository - } - - public func execute(type: String, keyword: String?) -> Observable { - return repository.fetchSearchListCount(type: type, keyword: keyword) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/LocalToken/DeleteTokenFromLocalUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/LocalToken/DeleteTokenFromLocalUseCaseImpl.swift deleted file mode 100644 index ad6a4a04..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/LocalToken/DeleteTokenFromLocalUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Foundation - -import DomainInterface - -public class DeleteTokenFromLocalUseCaseImpl: DeleteTokenFromLocalUseCase { - var repository: TokenRepository - - public init(repository: TokenRepository) { - self.repository = repository - } - - public func execute(type: TokenType) -> Result { - return repository.deleteToken(type: type) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/LocalToken/FetchTokenFromLocalUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/LocalToken/FetchTokenFromLocalUseCaseImpl.swift deleted file mode 100644 index 175257ce..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/LocalToken/FetchTokenFromLocalUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Foundation - -import DomainInterface - -public class FetchTokenFromLocalUseCaseImpl: FetchTokenFromLocalUseCase { - var repository: TokenRepository - - public init(repository: TokenRepository) { - self.repository = repository - } - - public func execute(type: TokenType) -> Result { - return repository.fetchToken(type: type) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/LocalToken/SaveTokenToLocalUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/LocalToken/SaveTokenToLocalUseCaseImpl.swift deleted file mode 100644 index 069d3188..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/LocalToken/SaveTokenToLocalUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import Foundation - -import DomainInterface - -public class SaveTokenToLocalUseCaseImpl: SaveTokenToLocalUseCase { - var repository: TokenRepository - - public init(repository: TokenRepository) { - self.repository = repository - } - - public func execute(type: TokenType, value: String) -> Result { - return repository.saveToken(type: type, value: value) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/MyPage/FetchJobUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/MyPage/FetchJobUseCaseImpl.swift deleted file mode 100644 index 3e6f714b..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/MyPage/FetchJobUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public class FetchJobUseCaseImpl: FetchJobUseCase { - private var repository: AuthAPIRepository - - public init(repository: AuthAPIRepository) { - self.repository = repository - } - - public func execute(jobId: String) -> Observable { - repository.fetchJob(jobId: jobId) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/MyPage/FetchProfileUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/MyPage/FetchProfileUseCaseImpl.swift deleted file mode 100644 index 6353a869..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/MyPage/FetchProfileUseCaseImpl.swift +++ /dev/null @@ -1,29 +0,0 @@ -import DomainInterface - -import RxSwift - -public class FetchProfileUseCaseImpl: FetchProfileUseCase { - private var repository: AuthAPIRepository - private let fetchJobUseCase: FetchJobUseCase - - public init(repository: AuthAPIRepository, fetchJobUseCase: FetchJobUseCase) { - self.repository = repository - self.fetchJobUseCase = fetchJobUseCase - } - - public func execute() -> Observable { - return repository.fetchProfile() - .flatMap { [weak self] profile -> Observable in - guard let self = self, let jobId = profile?.jobId else { - return .just(profile) - } - - return self.fetchJobUseCase.execute(jobId: String(jobId)) - .map { job in - var new = profile - new?.jobName = job.name - return new - } - } - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/MyPage/UpdateNickNameUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/MyPage/UpdateNickNameUseCaseImpl.swift deleted file mode 100644 index 64fabd1e..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/MyPage/UpdateNickNameUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public class UpdateNickNameUseCaseImpl: UpdateNickNameUseCase { - private var repository: AuthAPIRepository - - public init(repository: AuthAPIRepository) { - self.repository = repository - } - - public func execute(nickName: String) -> Observable { - return repository.updateNickName(nickName: nickName) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/MyPage/UpdateProfileImageUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/MyPage/UpdateProfileImageUseCaseImpl.swift deleted file mode 100644 index 188a6d9b..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/MyPage/UpdateProfileImageUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public class UpdateProfileImageUseCaseImpl: UpdateProfileImageUseCase { - private var repository: AuthAPIRepository - - public init(repository: AuthAPIRepository) { - self.repository = repository - } - - public func execute(url: String) -> Completable { - return repository.updateProfileImage(url: url) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchAddUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchAddUseCaseImpl.swift deleted file mode 100644 index 929ec5f6..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchAddUseCaseImpl.swift +++ /dev/null @@ -1,17 +0,0 @@ -import DomainInterface -import Foundation - -import RxSwift - -public class RecentSearchAddUseCaseImpl: RecentSearchAddUseCase { - var repository: UserDefaultsRepository - - public init(repository: UserDefaultsRepository) { - self.repository = repository - } - - public func add(keyword: String) -> Completable { - guard !keyword.isEmpty else { return .empty() } - return repository.addRecentSearch(keyword: keyword) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchFetchUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchFetchUseCaseImpl.swift deleted file mode 100644 index e4e440d7..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchFetchUseCaseImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import DomainInterface - -import RxSwift - -public final class RecentSearchFetchUseCaseImpl: RecentSearchFetchUseCase { - private let repository: UserDefaultsRepository - - public init(repository: UserDefaultsRepository) { - self.repository = repository - } - - public func fetch() -> Observable<[String]> { - return repository.fetchRecentSearch() - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchRemoveUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchRemoveUseCaseImpl.swift deleted file mode 100644 index f130bd25..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/RecentSearch/RecentSearchRemoveUseCaseImpl.swift +++ /dev/null @@ -1,20 +0,0 @@ -import DomainInterface -import Foundation - -import RxSwift - -public class RecentSearchRemoveUseCaseImpl: RecentSearchRemoveUseCase { - var repository: UserDefaultsRepository - - public init(repository: UserDefaultsRepository) { - self.repository = repository - } - - public func remove(keyword: String) -> Completable { - return repository.removeRecentSearch(keyword: keyword) - } - - public func removeAll() -> Completable { - return repository.removeAllSearch() - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Shared/CheckEmptyLevelAndRoleUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Shared/CheckEmptyLevelAndRoleUseCaseImpl.swift deleted file mode 100644 index db4e50a3..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Shared/CheckEmptyLevelAndRoleUseCaseImpl.swift +++ /dev/null @@ -1,13 +0,0 @@ -import DomainInterface - -import RxSwift - -public class CheckEmptyLevelAndRoleUseCaseImpl: CheckEmptyLevelAndRoleUseCase { - public init() {} - - public func execute(level: Int?, job: String?) -> Observable { - let isValidLevel = level.map { (1 ... 200).contains($0) } ?? false - let isValidRole = job != nil && job != "" - return .just(isValidLevel && isValidRole) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Shared/CheckNickNameUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Shared/CheckNickNameUseCaseImpl.swift deleted file mode 100644 index 921d295f..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Shared/CheckNickNameUseCaseImpl.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class CheckNickNameUseCaseImpl: CheckNickNameUseCase { - public init() {} - - public func execute(nickName: String) -> Observable { - let pattern = "^[가-힣ㄱ-ㅎㅏ-ㅣ]{2,15}$" - - let trimmed = nickName.trimmingCharacters(in: .whitespacesAndNewlines) - let isValid = NSPredicate(format: "SELF MATCHES %@", pattern) - .evaluate(with: trimmed) - - return .just(isValid) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Shared/CheckValidLevelUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Shared/CheckValidLevelUseCaseImpl.swift deleted file mode 100644 index ad38bda5..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Shared/CheckValidLevelUseCaseImpl.swift +++ /dev/null @@ -1,14 +0,0 @@ -import DomainInterface - -import RxSwift - -public class CheckValidLevelUseCaseImpl: CheckValidLevelUseCase { - public init() {} - - public func execute(level: Int?) -> Observable { - guard let level = level else { - return .just(nil) - } - return .just((1 ... 200).contains(level)) - } -} diff --git a/MLS/Domain/Domain/UseCaseImpl/Shared/SocialLoginUseCaseImpl.swift b/MLS/Domain/Domain/UseCaseImpl/Shared/SocialLoginUseCaseImpl.swift deleted file mode 100644 index 9d59f9f3..00000000 --- a/MLS/Domain/Domain/UseCaseImpl/Shared/SocialLoginUseCaseImpl.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation - -import DomainInterface - -import RxSwift - -public class SocialLoginUseCaseImpl: FetchSocialCredentialUseCase { - public var provider: any SocialAuthenticatableProvider - - public init(provider: any SocialAuthenticatableProvider) { - self.provider = provider - } - - public func execute() -> Observable { - return provider.getCredential() - } -} diff --git a/MLS/Domain/DomainInterface/Entity/Alarm/AlarmResponse.swift b/MLS/Domain/DomainInterface/Entity/Alarm/AlarmResponse.swift deleted file mode 100644 index 0f486c35..00000000 --- a/MLS/Domain/DomainInterface/Entity/Alarm/AlarmResponse.swift +++ /dev/null @@ -1,45 +0,0 @@ -import Foundation - -public struct AlarmResponse: Equatable { - public let id: Int - public let type: String - public let title: String - public let link: String - public let date: String - - public init(id: Int, type: String, title: String, link: String, date: String) { - self.id = id - self.type = type - self.title = title - self.link = link - self.date = date - } -} - -public struct AllAlarmResponse: Equatable { - public let id: Int - public let type: String - public let title: String - public let link: String - public let date: String - public var alreadyRead: Bool - - public init(id: Int, type: String, title: String, link: String, date: String, alreadyRead: Bool) { - self.id = id - self.type = type - self.title = title - self.link = link - self.date = date - self.alreadyRead = alreadyRead - } -} - -public struct PagedEntity { - public let items: [T] - public let hasMore: Bool - - public init(items: [T], hasMore: Bool) { - self.items = items - self.hasMore = hasMore - } -} diff --git a/MLS/Domain/DomainInterface/Entity/AuthAPI/Credential.swift b/MLS/Domain/DomainInterface/Entity/AuthAPI/Credential.swift deleted file mode 100644 index 7abf603a..00000000 --- a/MLS/Domain/DomainInterface/Entity/AuthAPI/Credential.swift +++ /dev/null @@ -1,4 +0,0 @@ -public protocol Credential: Encodable { - var token: String { get } - var providerID: String { get } -} diff --git a/MLS/Domain/DomainInterface/Entity/AuthAPI/JobListResponse.swift b/MLS/Domain/DomainInterface/Entity/AuthAPI/JobListResponse.swift deleted file mode 100644 index 44e49789..00000000 --- a/MLS/Domain/DomainInterface/Entity/AuthAPI/JobListResponse.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Foundation - -public struct JobListResponse { - public var jobList: [Job] - - public init(jobList: [Job]) { - self.jobList = jobList - } -} - -public struct Job: Equatable { - public let name: String - public let id: Int - - public init(name: String, id: Int) { - self.name = name - self.id = id - } -} diff --git a/MLS/Domain/DomainInterface/Entity/AuthAPI/LoginResponse.swift b/MLS/Domain/DomainInterface/Entity/AuthAPI/LoginResponse.swift deleted file mode 100644 index 2d2e0105..00000000 --- a/MLS/Domain/DomainInterface/Entity/AuthAPI/LoginResponse.swift +++ /dev/null @@ -1,13 +0,0 @@ -import Foundation - -public struct LoginResponse { - public var isRegister: Bool - public var accessToken: String - public var refreshToken: String - - public init(isRegister: Bool, accessToken: String, refreshToken: String) { - self.isRegister = isRegister - self.accessToken = accessToken - self.refreshToken = refreshToken - } -} diff --git a/MLS/Domain/DomainInterface/Entity/AuthAPI/SignUpResponse.swift b/MLS/Domain/DomainInterface/Entity/AuthAPI/SignUpResponse.swift deleted file mode 100644 index 1f4091e4..00000000 --- a/MLS/Domain/DomainInterface/Entity/AuthAPI/SignUpResponse.swift +++ /dev/null @@ -1,11 +0,0 @@ -import Foundation - -public struct SignUpResponse { - public var accessToken: String - public var refreshToken: String - - public init(accessToken: String, refreshToken: String) { - self.accessToken = accessToken - self.refreshToken = refreshToken - } -} diff --git a/MLS/Domain/DomainInterface/Entity/Bookmark/BookmarkResponse.swift b/MLS/Domain/DomainInterface/Entity/Bookmark/BookmarkResponse.swift deleted file mode 100644 index e9934cd5..00000000 --- a/MLS/Domain/DomainInterface/Entity/Bookmark/BookmarkResponse.swift +++ /dev/null @@ -1,17 +0,0 @@ -public struct BookmarkResponse: Equatable { - public let name: String - public let bookmarkId: Int - public let originalId: Int - public let imageUrl: String? - public let type: DictionaryItemType - public let level: Int? - - public init(name: String, bookmarkId: Int, originalId: Int, imageUrl: String?, type: DictionaryItemType, level: Int?) { - self.name = name - self.bookmarkId = bookmarkId - self.originalId = originalId - self.imageUrl = imageUrl - self.type = type - self.level = level - } -} diff --git a/MLS/Domain/DomainInterface/Entity/Collection/CollectionResponse.swift b/MLS/Domain/DomainInterface/Entity/Collection/CollectionResponse.swift deleted file mode 100644 index a69ddd5c..00000000 --- a/MLS/Domain/DomainInterface/Entity/Collection/CollectionResponse.swift +++ /dev/null @@ -1,13 +0,0 @@ -public struct CollectionResponse: Equatable { - public let collectionId: Int - public var name: String - public let createdAt: [Int] - public var recentBookmarks: [BookmarkResponse] - - public init(collectionId: Int, name: String, createdAt: [Int], recentBookmarks: [BookmarkResponse]) { - self.collectionId = collectionId - self.name = name - self.createdAt = createdAt - self.recentBookmarks = recentBookmarks - } -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailItemDropMonsterResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailItemDropMonsterResponse.swift deleted file mode 100644 index 43096c9e..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailItemDropMonsterResponse.swift +++ /dev/null @@ -1,15 +0,0 @@ -public struct DictionaryDetailItemDropMonsterResponse: Equatable { - public let monsterId: Int? - public let monsterName: String? - public let level: Int? - public let dropRate: Double? - public let imageUrl: String? - - public init(monsterId: Int?, monsterName: String?, level: Int?, dropRate: Double?, imageUrl: String?) { - self.monsterId = monsterId - self.monsterName = monsterName - self.level = level - self.dropRate = dropRate - self.imageUrl = imageUrl - } -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailItemResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailItemResponse.swift deleted file mode 100644 index bc1f2064..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailItemResponse.swift +++ /dev/null @@ -1,118 +0,0 @@ -public struct DictionaryDetailItemResponse: Equatable { - public let itemId: Int - public let nameKr: String? - public let nameEn: String? - public let descriptionText: String? - public let imgUrl: String? - public let npcPrice: Int? - public let itemType: String? - public let categoryHierachy: CategoryHierachy? - public let availableJobs: [Jobs]? - public let requiredStats: RequiredStats? // 요구 스탯 - public let equipmentStats: EquipmentStats? // 착용하면 올라가는 스탯 - public let scrollDetail: ScrollDetail? // 주문서 상세정보 - public var bookmarkId: Int? - - public init( - itemId: Int, - nameKr: String?, - nameEn: String?, - descriptionText: String?, - imgUrl: String?, - npcPrice: Int?, - itemType: String?, - categoryHierachy: CategoryHierachy?, - availableJobs: [Jobs]?, - requiredStats: RequiredStats?, - equipmentStats: EquipmentStats?, - scrollDetail: ScrollDetail?, - bookmarkId: Int? - ) { - self.itemId = itemId - self.nameKr = nameKr - self.nameEn = nameEn - self.descriptionText = descriptionText - self.imgUrl = imgUrl - self.npcPrice = npcPrice - self.itemType = itemType - self.categoryHierachy = categoryHierachy - self.availableJobs = availableJobs - self.requiredStats = requiredStats - self.equipmentStats = equipmentStats - self.scrollDetail = scrollDetail - self.bookmarkId = bookmarkId - } - -} - -public struct CategoryHierachy: Decodable, Equatable { - public let rootCategory: Category? - public let leafCategory: Category? -} - -public struct Category: Decodable, Equatable { - public let categoryId: Int? - public let name: String? - public let categoryLevel: Int? - public let description: String? -} - -public struct Jobs: Decodable, Equatable { - public let jobId: Int? - public let jobName: String? - public let jobLevel: Int? - public let parentJobId: Int? -} - -public struct RequiredStats: Decodable, Equatable { - public let level: Int? - public let str: Int? - public let dex: Int? - public let intelligence: Int? - public let luk: Int? - public let pop: Int? -} - -public struct EquipmentStats: Decodable, Equatable { - public let str: Stats? - public let dex: Stats? - public let intelligence: Stats? - public let luk: Stats? - public let hp: Stats? - public let mp: Stats? - public let weaponAttack: Stats? - public let magicAttack: Stats? - public let physicalDefense: Stats? - public let magicDefense: Stats? - public let accuracy: Stats? - public let evasion: Stats? - public let speed: Stats? - public let jump: Stats? - public let attackSpeed: Int? - public let attackSpeedDetails: String? -} - -public struct Stats: Decodable, Equatable { - public let base: Int? - public let min: Int? - public let max: Int? -} - -public struct ScrollDetail: Decodable, Equatable { - public let successRatePercent: Int? - public let targetItemTypeText: String? - public let strChange: Int? - public let dexChange: Int? - public let intelligenceChange: Int? - public let lukChange: Int? - public let hpChange: Int? - public let mpChange: Int? - public let weaponAttackChange: Int? - public let magicAttackChange: Int? - public let physicalDefenseChange: Int? - public let magicDefenseChange: Int? - public let accuracyChange: Int? - public let evasionChange: Int? - public let speedChange: Int? - public let jumpChange: Int? -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMapNpcResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMapNpcResponse.swift deleted file mode 100644 index 74d3afb0..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMapNpcResponse.swift +++ /dev/null @@ -1,13 +0,0 @@ -public struct DictionaryDetailMapNpcResponse: Equatable { - public let npcId: Int? - public let npcName: String? - public let npcNameEn: String? - public let iconUrl: String? - - public init(npcId: Int?, npcName: String?, npcNameEn: String?, iconUrl: String?) { - self.npcId = npcId - self.npcName = npcName - self.npcNameEn = npcNameEn - self.iconUrl = iconUrl - } -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMapResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMapResponse.swift deleted file mode 100644 index 71881911..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMapResponse.swift +++ /dev/null @@ -1,23 +0,0 @@ -public struct DictionaryDetailMapResponse: Equatable { - public let mapId: Int - public let nameKr: String? - public let nameEn: String? - public let regionName: String? - public let detailName: String? - public let topRegionName: String? - public let mapUrl: String? - public let iconUrl: String? - public var bookmarkId: Int? - - public init(mapId: Int, nameKr: String?, nameEn: String?, regionName: String?, detailName: String?, topRegionName: String?, mapUrl: String?, iconUrl: String?, bookmarkId: Int?) { - self.mapId = mapId - self.nameKr = nameKr - self.nameEn = nameEn - self.regionName = regionName - self.detailName = detailName - self.topRegionName = topRegionName - self.mapUrl = mapUrl - self.iconUrl = iconUrl - self.bookmarkId = bookmarkId - } -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMapSpawnMonsterResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMapSpawnMonsterResponse.swift deleted file mode 100644 index 404ce346..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMapSpawnMonsterResponse.swift +++ /dev/null @@ -1,15 +0,0 @@ -public struct DictionaryDetailMapSpawnMonsterResponse: Equatable { - public let monsterId: Int? - public let monsterName: String? - public let level: Int? - public let maxSpawnCount: Int? - public let imageUrl: String? - - public init(monsterId: Int?, monsterName: String?, level: Int?, maxSpawnCount: Int?, imageUrl: String?) { - self.monsterId = monsterId - self.monsterName = monsterName - self.level = level - self.maxSpawnCount = maxSpawnCount - self.imageUrl = imageUrl - } -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMonsterDropItemResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMonsterDropItemResponse.swift deleted file mode 100644 index c5214a28..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMonsterDropItemResponse.swift +++ /dev/null @@ -1,15 +0,0 @@ -public struct DictionaryDetailMonsterDropItemResponse: Equatable { - public let itemId: Int - public let itemName: String - public let dropRate: Double - public let imageUrl: String - public let itemLevel: Int - - public init(itemId: Int, itemName: String, dropRate: Double, imageUrl: String, itemLevel: Int) { - self.itemId = itemId - self.itemName = itemName - self.dropRate = dropRate - self.imageUrl = imageUrl - self.itemLevel = itemLevel - } -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMonsterMapResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMonsterMapResponse.swift deleted file mode 100644 index 6daa29f5..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMonsterMapResponse.swift +++ /dev/null @@ -1,19 +0,0 @@ -public struct DictionaryDetailMonsterMapResponse: Equatable { - public let mapId: Int - public let mapName: String - public let regionName: String - public let detailName: String - public let topRegionName: String - public let iconUrl: String - public let maxSpawnCount: Int? - - public init(mapId: Int, mapName: String, regionName: String, detailName: String, topRegionName: String, iconUrl: String, maxSpawnCount: Int?) { - self.mapId = mapId - self.mapName = mapName - self.regionName = regionName - self.detailName = detailName - self.topRegionName = topRegionName - self.iconUrl = iconUrl - self.maxSpawnCount = maxSpawnCount - } -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMonsterResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMonsterResponse.swift deleted file mode 100644 index 90ced802..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailMonsterResponse.swift +++ /dev/null @@ -1,111 +0,0 @@ -import Foundation -import UIKit - -public struct DictionaryDetailMonsterResponse: Equatable { - - public let monsterId: Int - public let nameKr: String - public let nameEn: String - public let imageUrl: String - public let level: Int - public let exp: Int - public let hp: Int - public let mp: Int - public let physicalDefense: Int - public let magicDefense: Int - public let requiredAccuracy: Int - public let bonusAccuracyPerLevelLower: Double - public let evasionRate: Int - public let mesoDropAmount: Int? - public let mesoDropRate: Int? - public let typeEffectiveness: Effectiveness? - public var bookmarkId: Int? - - public init( - monsterId: Int, - nameKr: String, - nameEn: String, - imageUrl: String, - level: Int, - exp: Int, - hp: Int, - mp: Int, - physicalDefense: Int, - magicDefense: Int, - requiredAccuracy: Int, - bonusAccuracyPerLevelLower: Double, - evasionRate: Int, - mesoDropAmount: Int?, - mesoDropRate: Int?, - typeEffectiveness: Effectiveness?, - bookmarkId: Int? - ) { - self.monsterId = monsterId - self.nameKr = nameKr - self.nameEn = nameEn - self.imageUrl = imageUrl - self.level = level - self.exp = exp - self.hp = hp - self.mp = mp - self.physicalDefense = physicalDefense - self.magicDefense = magicDefense - self.requiredAccuracy = requiredAccuracy - self.bonusAccuracyPerLevelLower = bonusAccuracyPerLevelLower - self.evasionRate = evasionRate - self.mesoDropAmount = mesoDropAmount - self.mesoDropRate = mesoDropRate - self.typeEffectiveness = typeEffectiveness - self.bookmarkId = bookmarkId - } -} - -public struct Effectiveness: Decodable, Equatable { - public let fire: String? - public let lightning: String? - public let poison: String? - public let holy: String? - public let ice: String? - public let physical: String? - - public init(fire: String?, lightning: String?, poison: String?, holy: String?, ice: String?, physical: String?) { - self.fire = fire - self.lightning = lightning - self.poison = poison - self.holy = holy - self.ice = ice - self.physical = physical - } - // 순회하기 위해서 - public func nonNilElements() -> [(element: ElementType, value: String)] { - var result: [(ElementType, String)] = [] - - if let fire = fire { result.append((.fire, toKoreanEffect(data: fire))) } - if let lightning = lightning { result.append((.lightning, toKoreanEffect(data: lightning))) } - if let poison = poison { result.append((.poison, toKoreanEffect(data: poison))) } - if let holy = holy { result.append((.holy, toKoreanEffect(data: holy))) } - if let ice = ice { result.append((.ice, toKoreanEffect(data: ice))) } - if let physical = physical { result.append((.physical, toKoreanEffect(data: physical))) } - - return result - } - // 몬스터 약점 태그를 위한 변환 - private func toKoreanEffect(data: String) -> String { - switch data { - case "RESIST": return "저항" - case "WEAK": return "약점" - case "IMMUNE": return "면역" - default: - return "" - } - } -} - -public enum ElementType: String { - case fire = "불" - case lightning = "번개" - case poison = "독" - case holy = "빛" - case ice = "얼음" - case physical = "물리" -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailNpcQuestResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailNpcQuestResponse.swift deleted file mode 100644 index 93caad5f..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailNpcQuestResponse.swift +++ /dev/null @@ -1,17 +0,0 @@ -public struct DictionaryDetailNpcQuestResponse: Equatable { - public let questId: Int - public let questNameKr: String - public let questNameEn: String - public let questIconUrl: String - public let minLevel: Int? - public let maxLevel: Int? - - public init(questId: Int, questNameKr: String, questNameEn: String, questIconUrl: String, minLevel: Int?, maxLevel: Int?) { - self.questId = questId - self.questNameKr = questNameKr - self.questNameEn = questNameEn - self.questIconUrl = questIconUrl - self.minLevel = minLevel - self.maxLevel = maxLevel - } -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailNpcResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailNpcResponse.swift deleted file mode 100644 index 02962f19..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailNpcResponse.swift +++ /dev/null @@ -1,15 +0,0 @@ -public struct DictionaryDetailNpcResponse: Equatable { - public let npcId: Int - public let nameKr: String - public let nameEn: String - public let iconUrlDetail: String? - public var bookmarkId: Int? - - public init(npcId: Int, nameKr: String, nameEn: String, iconUrlDetail: String?, bookmarkId: Int?) { - self.npcId = npcId - self.nameKr = nameKr - self.nameEn = nameEn - self.iconUrlDetail = iconUrlDetail - self.bookmarkId = bookmarkId - } -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailQuestLinkedQuestsResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailQuestLinkedQuestsResponse.swift deleted file mode 100644 index 1f7c1aea..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailQuestLinkedQuestsResponse.swift +++ /dev/null @@ -1,25 +0,0 @@ -public struct DictionaryDetailQuestLinkedQuestsResponse: Equatable { - public let previousQuests: [Quest]? - public let nextQuests: [Quest]? - - public init(previousQuests: [Quest]?, nextQuests: [Quest]?) { - self.previousQuests = previousQuests - self.nextQuests = nextQuests - } -} - -public struct Quest: Decodable, Equatable { - public let questId: Int? - public let name: String? - public let minLevel: Int? - public let maxLevel: Int? - public let iconUrl: String? - - public init(questId: Int?, name: String?, minLevel: Int?, maxLevel: Int?, iconUrl: String?) { - self.questId = questId - self.name = name - self.minLevel = minLevel - self.maxLevel = maxLevel - self.iconUrl = iconUrl - } -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailQuestResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailQuestResponse.swift deleted file mode 100644 index 6c065792..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailQuestResponse.swift +++ /dev/null @@ -1,86 +0,0 @@ -public struct DictionaryDetailQuestResponse: Equatable { - public let questId: Int - public let titlePrefix: String? - public let nameKr: String? - public let nameEn: String? - public let iconUrl: String? - public let questType: String? - public let minLevel: Int? - public let maxLevel: Int? - public let requiredMesoStart: Int? - public let startNpcId: Int? - public let startNpcName: String? - public let endNpcId: Int? - public let endNpcName: String? - public let reward: Reward? - public let rewardItems: [RewardItem]? - public let requirements: [Requirements]? - public let allowedJobs: [AllowedJob]? - public var bookmarkId: Int? - - public init( - questId: Int, - titlePrefix: String?, - nameKr: String?, - nameEn: String?, - iconUrl: String?, - questType: String?, - minLevel: Int?, - maxLevel: Int?, - requiredMesoStart: Int?, - startNpcId: Int?, - startNpcName: String?, - endNpcId: Int?, - endNpcName: String?, - reward: Reward?, - rewardItems: [RewardItem]?, - requirements: [Requirements]?, - allowedJobs: [AllowedJob]?, - bookmarkId: Int? - ) { - self.questId = questId - self.titlePrefix = titlePrefix - self.nameKr = nameKr - self.nameEn = nameEn - self.iconUrl = iconUrl - self.questType = questType - self.minLevel = minLevel - self.maxLevel = maxLevel - self.requiredMesoStart = requiredMesoStart - self.startNpcId = startNpcId - self.startNpcName = startNpcName - self.endNpcId = endNpcId - self.endNpcName = endNpcName - self.reward = reward - self.rewardItems = rewardItems - self.requirements = requirements - self.allowedJobs = allowedJobs - self.bookmarkId = bookmarkId - } -} - -public struct Reward: Decodable, Equatable { - public let exp: Int? - public let meso: Int? - public let popularity: Int? -} - -public struct RewardItem: Decodable, Equatable { - public let itemId: Int? - public let itemName: String? - public let quantity: Int? -} - -public struct Requirements: Decodable, Equatable { - public let requirementType: String? - public let itemId: Int? - public let itemName: String? - public let monsterId: Int? - public let monsterName: String? - public let quantity: Int? -} - -public struct AllowedJob: Decodable, Equatable { - public let jobId: Int? - public let jobName: String? -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailText.swift b/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailText.swift deleted file mode 100644 index e1e62dfe..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryDetail/DictionaryDetailText.swift +++ /dev/null @@ -1,10 +0,0 @@ -public enum DictionaryDetailText { - public static let minLevel = "시작 최소 레벨" - public static let maxLevel = "시작 최대 레벨" - public static let startNpc = "시작 NPC" - public static let endNpc = "종료 NPC" - public static let job = "직업" - public static let meso = "메소" - public static let exp = "경험치" - public static let pop = "인기도" -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionaryItem.swift b/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionaryItem.swift deleted file mode 100644 index 109d8340..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionaryItem.swift +++ /dev/null @@ -1,28 +0,0 @@ -import UIKit - -public struct DictionaryItem: Equatable { - public let id: Int - public let type: DictionaryItemType - public let mainText: String - public let subText: String - public let image: UIImage - public var isBookmarked: Bool - - public static func == (lhs: DictionaryItem, rhs: DictionaryItem) -> Bool { - return lhs.id == rhs.id && - lhs.type == rhs.type && - lhs.mainText == rhs.mainText && - lhs.subText == rhs.subText && - lhs.image == rhs.image && - lhs.isBookmarked == rhs.isBookmarked - } - - public init(id: Int, type: DictionaryItemType, mainText: String, subText: String, image: UIImage, isBookmarked: Bool) { - self.id = id - self.type = type - self.mainText = mainText - self.subText = subText - self.image = image - self.isBookmarked = isBookmarked - } -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionaryListQuery.swift b/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionaryListQuery.swift deleted file mode 100644 index 26d19bfd..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionaryListQuery.swift +++ /dev/null @@ -1,25 +0,0 @@ -public struct DictionaryListQuery: Encodable { - public var keyword: String? - public var page: Int - public var size: Int - public var sort: String? - - // monster일 경우 - public var minLevel: Int? - public var maxLevel: Int? - - // item일 경우 - public var jobIds: String? - public var categoryIds: String? - - public init(keyword: String? = nil, page: Int, size: Int, sort: String?, minLevel: Int? = nil, maxLevel: Int? = nil, jobIds: String? = nil, categoryIds: String? = nil) { - self.keyword = keyword - self.page = page - self.size = size - self.sort = sort ?? "ASC" - self.minLevel = minLevel - self.maxLevel = maxLevel - self.jobIds = jobIds - self.categoryIds = categoryIds - } -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionaryMainResponse.swift b/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionaryMainResponse.swift deleted file mode 100644 index a6e74562..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionaryMainResponse.swift +++ /dev/null @@ -1,29 +0,0 @@ -public struct DictionaryMainResponse { - public let totalPages: Int - public let totalElements: Int - public var contents: [DictionaryMainItemResponse] - - public init(totalPages: Int, totalElements: Int, contents: [DictionaryMainItemResponse]) { - self.totalPages = totalPages - self.totalElements = totalElements - self.contents = contents - } -} - -public struct DictionaryMainItemResponse: Equatable { - public let id: Int - public let name: String - public let imageUrl: String? - public let level: Int? - public let type: DictionaryItemType - public var bookmarkId: Int? - - public init(id: Int, name: String, imageUrl: String?, level: Int?, type: DictionaryItemType, bookmarkId: Int?) { - self.id = id - self.name = name - self.imageUrl = imageUrl - self.level = level - self.type = type - self.bookmarkId = bookmarkId - } -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionaryMainViewType.swift b/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionaryMainViewType.swift deleted file mode 100644 index 9ad16018..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionaryMainViewType.swift +++ /dev/null @@ -1,16 +0,0 @@ -public enum DictionaryMainViewType { - case main - case search - case bookmark - - public var pageTabList: [DictionaryType] { - switch self { - case .main: - return [.total, .monster, .item, .map, .npc, .quest] - case .search: - return [.total, .monster, .item, .map, .npc, .quest] - case .bookmark: - return [.total, .collection, .monster, .item, .map, .npc, .quest] - } - } -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionaryType.swift b/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionaryType.swift deleted file mode 100644 index cb164b00..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionaryType.swift +++ /dev/null @@ -1,129 +0,0 @@ -public enum DictionaryType: String, CaseIterable { - case total - case collection - case item - case monster - case map - case npc - case quest - - public var title: String { - switch self { - case .total: - return "전체" - case .collection: - return "컬렉션" - case .monster: - return "몬스터" - case .item: - return "아이템" - case .map: - return "맵" - case .npc: - return "NPC" - case .quest: - return "퀘스트" - } - } - - public var sortedFilter: [SortType] { - switch self { - case .item: - return [ - .korean, .levelDESC, .levelASC - ] - case .monster: - return [ - .korean, .levelDESC, .levelASC, .expDESC, .expASC - ] - default: - return [] - } - } - - public var detailTypes: [DetailType] { - switch self { - case .item: - return [ - .dropMonsterWithText - ] - case .monster: - return [ - .appearMapWithText, .dropItemWithText - ] - case .map: - return [ - .appearMonsterWithText, .appearNPC - ] - case .npc: - return [ - .quest - ] - default: - return [] - } - } - - public var isSortHidden: Bool { - return sortedFilter.count == 0 - } - - public var bookmarkSortedFilter: [SortType] { - switch self { - case .total: - return [ - .latest, .korean - ] - case .item: - return [ - .korean, .levelDESC, .levelASC - ] - case .monster: - return [ - .korean, .levelDESC, .levelASC, .expDESC, .expASC - ] - default: - return [] - } - } - - public var isBookmarkSortHidden: Bool { - return bookmarkSortedFilter.count == 0 - } - - public var toItemType: DictionaryItemType? { - switch self { - case .item: - return .item - case .monster: - return .monster - case .map: - return .map - case .npc: - return .npc - case .quest: - return .quest - default: - return nil - } - } - - public var tabIndex: Int { - switch self { - case .total: - 0 - case .collection: - 0 - case .item: - 1 - case .monster: - 2 - case .map: - 3 - case .npc: - 4 - case .quest: - 5 - } - } -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionnaryItemType.swift b/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionnaryItemType.swift deleted file mode 100644 index 3ea6cc2e..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryList/DictionnaryItemType.swift +++ /dev/null @@ -1,103 +0,0 @@ -import UIKit - -public enum DictionaryItemType: String { - case item - case monster - case map - case npc - case quest - - public var detailTypes: [DetailType] { - switch self { - case .item: - [.normal, .dropMonsterWithText] - case .monster: - [.normal, .appearMapWithText, .dropItemWithText] - case .map: - [.mapInfo, .appearMonsterWithText, .appearNPC] - case .npc: - [.appearMap, .quest] - case .quest: - [.normal, .linkedQuest] - } - } - - public var detailTitle: String { - switch self { - case .item: - "아이템 상세 정보" - case .monster: - "몬스터 상세 정보" - case .map: - "맵 상세 정보" - case .npc: - "NPC 상세 정보" - case .quest: - "퀘스트 상세 정보" - } - } - - public var toDictionaryType: DictionaryType? { - switch self { - case .item: - return .item - case .monster: - return .monster - case .map: - return .map - case .npc: - return .npc - case .quest: - return .quest - } - } -} - -public enum DetailType { - case normal - case mapInfo - case appearMap - case appearNPC - case linkedQuest - case quest - case dropItemWithText - case appearMapWithText - case appearMonsterWithText - case dropMonsterWithText - - public var description: String { - switch self { - case .normal: - return "상세 정보" - case .mapInfo: - return "맵 정보" - case .appearNPC: - return "출현 NPC" - case .linkedQuest: - return "연계 퀘스트" - case .quest: - return "퀘스트" - case .appearMap, .appearMapWithText: - return "출현 맵" - case .dropItemWithText: - return "드롭 아이템" - case .appearMonsterWithText: - return "출현 몬스터" - case .dropMonsterWithText: - return "드롭 몬스터" - } - } - - public var sortFilter: [SortType] { - switch self { - case .appearMonsterWithText, .appearMapWithText: - [.mostAppear] - case .dropItemWithText, .dropMonsterWithText: - [.mostDrop, .levelASC, .levelDESC] - case .quest: - [.levelLowest, .levelHighest] - default: - [] - } - } -} diff --git a/MLS/Domain/DomainInterface/Entity/DictionaryList/ItemFilterCriteria.swift b/MLS/Domain/DomainInterface/Entity/DictionaryList/ItemFilterCriteria.swift deleted file mode 100644 index 8fe61cd6..00000000 --- a/MLS/Domain/DomainInterface/Entity/DictionaryList/ItemFilterCriteria.swift +++ /dev/null @@ -1,13 +0,0 @@ -public struct ItemFilterCriteria { - public let jobIds: [Int] - public let startLevel: Int? - public let endLevel: Int? - public let categoryIds: [Int] - - public init(jobIds: [Int], startLevel: Int?, endLevel: Int?, categoryIds: [Int]) { - self.jobIds = jobIds - self.startLevel = startLevel - self.endLevel = endLevel - self.categoryIds = categoryIds - } -} diff --git a/MLS/Domain/DomainInterface/Entity/Filter/FilterType.swift b/MLS/Domain/DomainInterface/Entity/Filter/FilterType.swift deleted file mode 100644 index 2546f395..00000000 --- a/MLS/Domain/DomainInterface/Entity/Filter/FilterType.swift +++ /dev/null @@ -1,4 +0,0 @@ -enum FilterType { - case monster - case item -} diff --git a/MLS/Domain/DomainInterface/Entity/Filter/SortType.swift b/MLS/Domain/DomainInterface/Entity/Filter/SortType.swift deleted file mode 100644 index 0adf976c..00000000 --- a/MLS/Domain/DomainInterface/Entity/Filter/SortType.swift +++ /dev/null @@ -1,51 +0,0 @@ -public enum SortType: String { - // 도감 메인 정렬 - case korean = "가나다 순" - case levelDESC = "레벨 높은 순" - case levelASC = "레벨 낮은 순" - case expDESC = "획득 경험치 높은 순" - case expASC = "획득 경험치 낮은 순" - case latest = "최신순" - - // 도감 상세 정렬 - case mostAppear = "출현 많은 순" - case levelLowest = "수락 레벨 낮은 순" - case levelHighest = "수락 레벨 높은 순" - case mostDrop = "드롭률 높은 순" - - // 정렬 키 - 이름, 레벨, 경험치 - public var sortKey: String { - switch self { - case .latest: - return "createdAt" - case .korean: - return "name" - case .levelASC, .levelDESC: - return "level" - case .expASC, .expDESC: - return "exp" - case .mostAppear: - return "maxSpawnCount" - case .mostDrop: - return "dropRate" - default: - return "" - } - } - // 정렬 방향 - 오름차순, 내림차순 - public var direction: String { - switch self { - case .expASC, .levelASC, .korean: - return "asc" - case .expDESC, .levelDESC, .mostDrop, .mostAppear, .latest: - return "desc" - default: - return "" - } - } - - // 정렬 파라미터 - public var sortParameter: String { - return "\(sortKey),\(direction)" - } -} diff --git a/MLS/Domain/DomainInterface/Entity/MyPage/CustomerSupportType.swift b/MLS/Domain/DomainInterface/Entity/MyPage/CustomerSupportType.swift deleted file mode 100644 index 449977de..00000000 --- a/MLS/Domain/DomainInterface/Entity/MyPage/CustomerSupportType.swift +++ /dev/null @@ -1,19 +0,0 @@ -public enum CustomerSupportType { - case event - case announcement - case patchNote - case terms - - public var detailTitle: String { - switch self { - case .event: - "이벤트" - case .announcement: - "공지사항" - case .patchNote: - "패치노트" - case .terms: - "약관 및 정책" - } - } -} diff --git a/MLS/Domain/DomainInterface/Entity/MyPage/MyPageResponse.swift b/MLS/Domain/DomainInterface/Entity/MyPage/MyPageResponse.swift deleted file mode 100644 index 05fed33d..00000000 --- a/MLS/Domain/DomainInterface/Entity/MyPage/MyPageResponse.swift +++ /dev/null @@ -1,23 +0,0 @@ -public struct MyPageResponse: Equatable { - public var nickname: String - public let jobId: Int? - public var jobName: String - public let level: Int? - public let profileUrl: String - public let platform: LoginPlatform - public let noticeAgreement: Bool - public let patchNoteAgreement: Bool - public let eventAgreement: Bool - - public init(nickname: String, jobId: Int?, jobName: String, level: Int?, profileUrl: String, platform: LoginPlatform, noticeAgreement: Bool?, patchNoteAgreement: Bool?, eventAgreement: Bool?) { - self.nickname = nickname - self.jobId = jobId - self.jobName = jobName - self.level = level - self.profileUrl = profileUrl - self.platform = platform - self.noticeAgreement = noticeAgreement ?? false - self.patchNoteAgreement = patchNoteAgreement ?? false - self.eventAgreement = eventAgreement ?? false - } -} diff --git a/MLS/Domain/DomainInterface/Entity/SearchCount/SearchCountResponse.swift b/MLS/Domain/DomainInterface/Entity/SearchCount/SearchCountResponse.swift deleted file mode 100644 index ef99985a..00000000 --- a/MLS/Domain/DomainInterface/Entity/SearchCount/SearchCountResponse.swift +++ /dev/null @@ -1,7 +0,0 @@ -public struct SearchCountResponse: Decodable { - public let count: Int? - - public init(count: Int?) { - self.count = count - } -} diff --git a/MLS/Domain/DomainInterface/Entity/Shared/LoginPlatform.swift b/MLS/Domain/DomainInterface/Entity/Shared/LoginPlatform.swift deleted file mode 100644 index 35c4f7ff..00000000 --- a/MLS/Domain/DomainInterface/Entity/Shared/LoginPlatform.swift +++ /dev/null @@ -1,6 +0,0 @@ -import Foundation - -public enum LoginPlatform: String { - case kakao - case apple -} diff --git a/MLS/Domain/DomainInterface/Error/AuthError.swift b/MLS/Domain/DomainInterface/Error/AuthError.swift deleted file mode 100644 index abc34978..00000000 --- a/MLS/Domain/DomainInterface/Error/AuthError.swift +++ /dev/null @@ -1,5 +0,0 @@ -public enum AuthError: Error { - case unknown(message: String) - case userNotFound(credential: Credential) - case tokenExpired -} diff --git a/MLS/Domain/DomainInterface/Interface/.DS_Store b/MLS/Domain/DomainInterface/Interface/.DS_Store deleted file mode 100644 index 6237231b..00000000 Binary files a/MLS/Domain/DomainInterface/Interface/.DS_Store and /dev/null differ diff --git a/MLS/Domain/DomainInterface/Interface/Network/HTTPMethod.swift b/MLS/Domain/DomainInterface/Interface/Network/HTTPMethod.swift deleted file mode 100644 index 818b9aff..00000000 --- a/MLS/Domain/DomainInterface/Interface/Network/HTTPMethod.swift +++ /dev/null @@ -1,5 +0,0 @@ -import Foundation - -public enum HTTPMethod: String { - case GET, POST, DELETE, PUT -} diff --git a/MLS/Domain/DomainInterface/Interface/Network/Interceptor.swift b/MLS/Domain/DomainInterface/Interface/Network/Interceptor.swift deleted file mode 100644 index 400e935e..00000000 --- a/MLS/Domain/DomainInterface/Interface/Network/Interceptor.swift +++ /dev/null @@ -1,18 +0,0 @@ -import Foundation - -import RxSwift - -public protocol Interceptor { - /// Request에 요소를 추가하기 위한 함수 - /// - Parameter request: 엔드포인트로 부터 만들어진 Request - /// - Returns: 요소가 추가된 Request - func adapt(_ request: URLRequest) -> URLRequest - - /// 필요에 따라 재요청을 하기 위한 함수 - /// - Parameters: - /// - request: 엔드포인트로 부터 만들어진 Request - /// - response: 돌려받은 응답 - /// - error: 통신간에 발생한 에러 - /// - Returns: 재요청이 필요하면 true, 필요없으면 false - func retry(data: Data?, response: URLResponse?, error: Error?) -> Bool -} diff --git a/MLS/Domain/DomainInterface/Interface/Network/Requestable.swift b/MLS/Domain/DomainInterface/Interface/Network/Requestable.swift deleted file mode 100644 index 53da0f3d..00000000 --- a/MLS/Domain/DomainInterface/Interface/Network/Requestable.swift +++ /dev/null @@ -1,51 +0,0 @@ -import Foundation - -public protocol Requestable { - var baseURL: String { get set } - var path: String { get set } - var method: HTTPMethod { get set } - var query: Encodable? { get set } - var headers: [String: String]? { get set } - var body: Encodable? { get set } -} - -extension Requestable { - /// 엔드포인트 객체의 속성들을 이용하여 Request를 만드는 함수 - /// - Returns: API 통신에 필요한 요청 -> Request - public func getUrlRequest() throws -> URLRequest { - guard var base = URL(string: baseURL) else { - throw URLError(.badURL) - } - - base.appendPathComponent(path) - - guard var components = URLComponents(url: base, resolvingAgainstBaseURL: false) else { - throw URLError(.badURL) - } - - if let query = query { - let queryData = try JSONEncoder().encode(query) - let dictionary = try JSONSerialization.jsonObject(with: queryData, options: []) as? [String: Any] - components.queryItems = dictionary?.map { - URLQueryItem(name: $0.key, value: "\($0.value)") - } - } - - guard let url = components.url else { - throw URLError(.badURL) - } - - var request = URLRequest(url: url) - request.httpMethod = method.rawValue - - headers?.forEach { key, value in - request.setValue(value, forHTTPHeaderField: key) - } - - if let body = body { - request.httpBody = try JSONEncoder().encode(body) - request.setValue("application/json", forHTTPHeaderField: "Content-Type") - } - return request - } -} diff --git a/MLS/Domain/DomainInterface/Interface/Network/Responsable.swift b/MLS/Domain/DomainInterface/Interface/Network/Responsable.swift deleted file mode 100644 index d185fd71..00000000 --- a/MLS/Domain/DomainInterface/Interface/Network/Responsable.swift +++ /dev/null @@ -1,5 +0,0 @@ -import Foundation - -public protocol Responsable { - associatedtype Response: Decodable -} diff --git a/MLS/Domain/DomainInterface/Providers/NetworkProvider.swift b/MLS/Domain/DomainInterface/Providers/NetworkProvider.swift deleted file mode 100644 index 1adb9ac2..00000000 --- a/MLS/Domain/DomainInterface/Providers/NetworkProvider.swift +++ /dev/null @@ -1,19 +0,0 @@ -import Foundation - -import RxSwift - -public protocol NetworkProvider { - /// 엔드포인트를 이용하여 응답이 있는 통신을 위한 함수 - /// - Parameters: - /// - endPoint: 목적지에 대한 정보를 담고있는 엔드포인트 객체 - /// - interceptor: Request에 필요한 인터셉터 - /// - Returns: 응답값을 포함한 Response - func requestData(endPoint: T, interceptor: Interceptor?) -> Observable - - /// 엔드포인트를 이용하여 응답이 없는 통신을 위한 함수 - /// - Parameters: - /// - endPoint: 목적지에 대한 정보를 담고있는 엔드포인트 객체 - /// - interceptor: Request에 필요한 인터셉터 - /// - Returns: 통신이 완료되었는지만 확인 가능 - func requestData(endPoint: Requestable, interceptor: Interceptor?) -> Completable -} diff --git a/MLS/Domain/DomainInterface/Providers/SocialAuthenticatableProvider.swift b/MLS/Domain/DomainInterface/Providers/SocialAuthenticatableProvider.swift deleted file mode 100644 index 090ccb67..00000000 --- a/MLS/Domain/DomainInterface/Providers/SocialAuthenticatableProvider.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation - -import RxSwift - -public protocol SocialAuthenticatableProvider { - func getCredential() -> Observable -} diff --git a/MLS/Domain/DomainInterface/Repository/AlarmAPIRepository.swift b/MLS/Domain/DomainInterface/Repository/AlarmAPIRepository.swift deleted file mode 100644 index e5c975b0..00000000 --- a/MLS/Domain/DomainInterface/Repository/AlarmAPIRepository.swift +++ /dev/null @@ -1,17 +0,0 @@ -import Foundation - -import RxSwift - -public protocol AlarmAPIRepository { - func fetchPatchNotes(cursor: Int?, pageSize: Int) -> Observable> - - func fetchNotices(cursor: Int?, pageSize: Int) -> Observable> - - func fetchOutdatedEvents(cursor: Int?, pageSize: Int) -> Observable> - - func fetchOngoingEvents(cursor: Int?, pageSize: Int) -> Observable> - - func fetchAll(cursor: Int?, pageSize: Int) -> Observable> - - func setRead(alarmLink: String) -> Completable -} diff --git a/MLS/Domain/DomainInterface/Repository/AuthAPIRepository.swift b/MLS/Domain/DomainInterface/Repository/AuthAPIRepository.swift deleted file mode 100644 index 2e8b1224..00000000 --- a/MLS/Domain/DomainInterface/Repository/AuthAPIRepository.swift +++ /dev/null @@ -1,68 +0,0 @@ -import Foundation - -import RxSwift - -/// 사용자 인증 및 회원 관련 API 호출을 담당하는 레포지토리 프로토콜 -public protocol AuthAPIRepository { - - /// 카카오 로그인 API 호출 - /// - /// - Parameter credential: 카카오 로그인에 필요한 자격 증명 (예: access token 등) - /// - Returns: 로그인 응답을 담은 Observable - func loginWithKakao(credential: Credential) -> Observable - - /// 애플 로그인 API 호출 - /// - /// - Parameter credential: 애플 로그인에 필요한 자격 증명 (예: identity token 등) - /// - Returns: 로그인 응답을 담은 Observable - func loginWithApple(credential: Credential) -> Observable - - /// 카카오 회원가입 API 호출 - /// - /// - Parameters: - /// - credential: 회원가입에 필요한 사용자 정보 - /// - isMarketingAgreement: 마케팅 수신 동의 여부 - /// - Returns: 회원가입 응답을 담은 Observable - func signUpWithKakao(credential: Credential, isMarketingAgreement: Bool, fcmToken: String?) -> Observable - - /// 애플 회원가입 API 호출 - /// - /// - Parameters: - /// - credential: 회원가입에 필요한 사용자 정보 - /// - isMarketingAgreement: 마케팅 수신 동의 여부 - /// - Returns: 회원가입 응답을 담은 Observable - func signUpWithApple(credential: Credential, isMarketingAgreement: Bool, fcmToken: String?) -> Observable - - func withdraw() -> Completable - - /// 직업 목록 조회 API 호출 - /// - /// - Returns: 직업 목록 응답을 담은 Observable - func fetchJobList() -> Observable - - func fetchJob(jobId: String) -> Observable - - /// 사용자 정보 수정 API 호출 - /// - /// - Note: 레벨과 직업을 업데이트 - /// - Returns: 작업 완료 여부를 나타내는 Completable - func updateUserInfo(level: Int, selectedJobID: Int) -> Completable - - /// 토큰 재발행 API 호출 - /// - /// - Parameter credential: refreshToken - /// - Returns: 토큰 갱신 응답을 담은 Observable - func reissueToken(refreshToken: String) -> Observable - - func fcmToken(fcmToken: String?) -> Completable - - func updateMarketingAgreement(credential: String, isMarketingAgreement: Bool) -> Completable - - func updateNotificationAgreement(noticeAgreement: Bool, patchNoteAgreement: Bool, eventAgreement: Bool) -> Completable - - func updateNickName(nickName: String) -> Observable - - func updateProfileImage(url: String) -> Completable - - func fetchProfile() -> Observable -} diff --git a/MLS/Domain/DomainInterface/Repository/BookmarkRepository.swift b/MLS/Domain/DomainInterface/Repository/BookmarkRepository.swift deleted file mode 100644 index 7730602d..00000000 --- a/MLS/Domain/DomainInterface/Repository/BookmarkRepository.swift +++ /dev/null @@ -1,21 +0,0 @@ -import Foundation - -import RxSwift - -public protocol BookmarkRepository { - func setBookmark(bookmarkId: Int, type: DictionaryItemType) -> Observable - - func deleteBookmark(bookmarkId: Int) -> Observable - - func fetchBookmark(sort: String?) -> Observable<[BookmarkResponse]> - - func fetchMonsterBookmark(minLevel: Int?, maxLevel: Int?, sort: String?) -> Observable<[BookmarkResponse]> - - func fetchNPCBookmark(sort: String?) -> Observable<[BookmarkResponse]> - - func fetchQuestBookmark(sort: String?) -> Observable<[BookmarkResponse]> - - func fetchItemBookmark(jobId: Int?, minLevel: Int?, maxLevel: Int?, categoryIds: [Int]?, sort: String?) -> Observable<[BookmarkResponse]> - - func fetchMapBookmark(sort: String?) -> Observable<[BookmarkResponse]> -} diff --git a/MLS/Domain/DomainInterface/Repository/CollectionAPIRepository.swift b/MLS/Domain/DomainInterface/Repository/CollectionAPIRepository.swift deleted file mode 100644 index a6033351..00000000 --- a/MLS/Domain/DomainInterface/Repository/CollectionAPIRepository.swift +++ /dev/null @@ -1,18 +0,0 @@ -import Foundation - -import RxSwift - -public protocol CollectionAPIRepository { - // 컬렉션 목록 조회 - func fetchCollectionList(sort: String?) -> Observable<[CollectionResponse]> - // 컬렉션 목록 추가 - func createCollectionList(name: String) -> Completable - // 컬렉션 상세 조회 - func fetchCollectionUseCase(id: Int) -> Observable<[BookmarkResponse]> - - func updateCollectionName(collectionId: Int, name: String) -> Completable - - func deleteCollection(collectionId: Int) -> Completable - - func addCollectionAndBookmark(collectionIds: [Int], bookmarkIds: [Int]) -> Completable -} diff --git a/MLS/Domain/DomainInterface/Repository/DictionaryDetailAPIRepository.swift b/MLS/Domain/DomainInterface/Repository/DictionaryDetailAPIRepository.swift deleted file mode 100644 index 4f593334..00000000 --- a/MLS/Domain/DomainInterface/Repository/DictionaryDetailAPIRepository.swift +++ /dev/null @@ -1,32 +0,0 @@ -import RxSwift - -public protocol DictionaryDetailAPIRepository { - // 몬스터 디테일 상세정보 - func fetchMonsterDetail(id: Int) -> Observable - // 몬스터 디테일 드롭 아이템 - func fetchMonsterDetailDropItem(id: Int, sort: String?) -> Observable<[DictionaryDetailMonsterDropItemResponse]> - // 몬스터 디테일 출현맵 - func fetchMonsterDetailMap(id: Int) -> Observable<[DictionaryDetailMonsterMapResponse]> - - // Npc 디테일 상세정보 - func fetchNpcDetail(id: Int) -> Observable - - // NPC 디테일 퀘스트 - func fetchNpcDetailQuest(id: Int, sort: String?) -> Observable<[DictionaryDetailNpcQuestResponse]> - // NPC 디테일 맵 - func fetchNpcDetailMap(id: Int) -> Observable<[DictionaryDetailMonsterMapResponse]> - // Item 디테일 상세정보 - func fetchItemDetail(id: Int) -> Observable - // Item 디테일 드롭 몬스터 - func fetchItemDetailDropMonster(id: Int, sort: String?) -> Observable<[DictionaryDetailItemDropMonsterResponse]> - // Quest 디테일 상세정보 - func fetchQuestDetail(id: Int) -> Observable - // Quest 연계 퀘스트 상세정보 - func fetchQuestDetailLinkedQuestsDetail(id: Int) -> Observable - // Map 디테일 상세정보 - func fetchMapDetail(id: Int) -> Observable - // Map 디테일 출현 몬스터 정보 - func fetchMapDetailSpawnMonster(id: Int, sort: String?) -> Observable<[DictionaryDetailMapSpawnMonsterResponse]> - // Map 디테일 출현 Npc 정보 - func fetchMapDetailNpc(id: Int) -> Observable<[DictionaryDetailMapNpcResponse]> -} diff --git a/MLS/Domain/DomainInterface/Repository/DictionaryListAPIRepository.swift b/MLS/Domain/DomainInterface/Repository/DictionaryListAPIRepository.swift deleted file mode 100644 index 5ea6acdb..00000000 --- a/MLS/Domain/DomainInterface/Repository/DictionaryListAPIRepository.swift +++ /dev/null @@ -1,20 +0,0 @@ -import RxSwift - -public protocol DictionaryListAPIRepository { - // 전체 - func fetchAllList(keyword: String?, page: Int?) -> Observable - // 몬스터 - func fetchMonsterList(keyword: String?, minLevel: Int?, maxLevel: Int?, page: Int, size: Int, sort: String?) -> Observable - // Npc - func fetchNpcList(keyword: String, page: Int, size: Int, sort: String?) -> Observable - // Quest - func fetchQuestList(keyword: String, page: Int, size: Int, sort: String?) -> Observable - // Item - func fetchItemList(keyword: String?, jobId: [Int]?, minLevel: Int?, maxLevel: Int?, categoryIds: [Int]?, page: Int?, size: Int?, sort: String?) -> Observable - // Map - func fetchMapList(keyword: String, page: Int, size: Int, sort: String?) -> Observable - // 검색 - func fetchSearchList(keyword: String?) -> Observable - // 검색 카운트 - func fetchSearchListCount(type: String, keyword: String?) -> Observable -} diff --git a/MLS/Domain/DomainInterface/Repository/TokenRepository.swift b/MLS/Domain/DomainInterface/Repository/TokenRepository.swift deleted file mode 100644 index d9043fe2..00000000 --- a/MLS/Domain/DomainInterface/Repository/TokenRepository.swift +++ /dev/null @@ -1,34 +0,0 @@ -import Foundation -import Security - -import RxSwift - -public enum TokenRepositoryError: Error { - case noValueFound(message: String) // 해당 키에 대해 값을 찾을 수 없을 때 발생 - case unhandledError(status: OSStatus) // 예상치 못한 OSStatus 오류가 발생했을 때 발생 - case dataConversionError(message: String) // 데이터 변환 중 오류가 발생했을 때 발생 -} - -public enum TokenType: String { - case accessToken // 액세스 토큰 - case refreshToken // 리프레시 토큰 - case fcmToken // fcm토큰 -} - -public protocol TokenRepository { - /// 토큰을 가져오는 메서드 - /// - Parameter type: 가져오려는 토큰의 타입 (`accessToken` 또는 `refreshToken`) - /// - Returns: 가져온 토큰을 담은 `Single` - func fetchToken(type: TokenType) -> Result - - /// 토큰을 저장하는 메서드 - /// - Parameter type: 저장하려는 토큰의 타입 (`accessToken` 또는 `refreshToken`) - /// - Parameter value: 저장할 토큰의 값 - /// - Returns: 완료 시 `Completable` - func saveToken(type: TokenType, value: String) -> Result - - /// 토큰을 삭제하는 메서드 - /// - Parameter type: 삭제하려는 토큰의 타입 (`accessToken` 또는 `refreshToken`) - /// - Returns: 완료 시 `Completable` - func deleteToken(type: TokenType) -> Result -} diff --git a/MLS/Domain/DomainInterface/Repository/UserDefaultsRepository.swift b/MLS/Domain/DomainInterface/Repository/UserDefaultsRepository.swift deleted file mode 100644 index f837248e..00000000 --- a/MLS/Domain/DomainInterface/Repository/UserDefaultsRepository.swift +++ /dev/null @@ -1,17 +0,0 @@ -import RxSwift - -public protocol UserDefaultsRepository { - func fetchRecentSearch() -> Observable<[String]> - func addRecentSearch(keyword: String) -> Completable - func removeRecentSearch(keyword: String) -> Completable - func removeAllSearch() -> Completable - - func fetchPlatform() -> Observable - func savePlatform(platform: LoginPlatform) -> Completable - - func fetchBookmark() -> Observable - func saveBookmark() -> Completable - - func fetchDictionaryDetail() -> Observable - func saveDictionaryDetail() -> Completable -} diff --git a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchAllAlarmUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Alarm/FetchAllAlarmUseCase.swift deleted file mode 100644 index b4dcccab..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchAllAlarmUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchAllAlarmUseCase { - func execute(id: Int?, pageSize: Int) -> Observable> -} diff --git a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchNoticesUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Alarm/FetchNoticesUseCase.swift deleted file mode 100644 index 3f2e85fb..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchNoticesUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchNoticesUseCase { - func execute(id: Int?, pageSize: Int) -> Observable> -} diff --git a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchOngoingEventsUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Alarm/FetchOngoingEventsUseCase.swift deleted file mode 100644 index d1ca0894..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchOngoingEventsUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchOngoingEventsUseCase { - func execute(id: Int?, pageSize: Int) -> Observable> -} diff --git a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchOutdatedEventsUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Alarm/FetchOutdatedEventsUseCase.swift deleted file mode 100644 index e322d2af..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchOutdatedEventsUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchOutdatedEventsUseCase { - func execute(id: Int?, pageSize: Int) -> Observable> -} diff --git a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchPatchNotesUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Alarm/FetchPatchNotesUseCase.swift deleted file mode 100644 index 2439fb39..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Alarm/FetchPatchNotesUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchPatchNotesUseCase { - func execute(id: Int?, pageSize: Int) -> Observable> -} diff --git a/MLS/Domain/DomainInterface/UseCase/Alarm/SetReadUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Alarm/SetReadUseCase.swift deleted file mode 100644 index f953f489..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Alarm/SetReadUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol SetReadUseCase { - func execute(alarmLink: String) -> Completable -} diff --git a/MLS/Domain/DomainInterface/UseCase/AuthAPI/CheckLoginUseCase.swift b/MLS/Domain/DomainInterface/UseCase/AuthAPI/CheckLoginUseCase.swift deleted file mode 100644 index fc8d8347..00000000 --- a/MLS/Domain/DomainInterface/UseCase/AuthAPI/CheckLoginUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol CheckLoginUseCase { - func execute() -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/AuthAPI/CheckNotificationPermissionUseCase.swift b/MLS/Domain/DomainInterface/UseCase/AuthAPI/CheckNotificationPermissionUseCase.swift deleted file mode 100644 index 04ae921c..00000000 --- a/MLS/Domain/DomainInterface/UseCase/AuthAPI/CheckNotificationPermissionUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol CheckNotificationPermissionUseCase { - func execute() -> Single -} diff --git a/MLS/Domain/DomainInterface/UseCase/AuthAPI/FetchJobListUseCase.swift b/MLS/Domain/DomainInterface/UseCase/AuthAPI/FetchJobListUseCase.swift deleted file mode 100644 index 12ab91bb..00000000 --- a/MLS/Domain/DomainInterface/UseCase/AuthAPI/FetchJobListUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchJobListUseCase { - func execute() -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/AuthAPI/FetchPlatformUseCase.swift b/MLS/Domain/DomainInterface/UseCase/AuthAPI/FetchPlatformUseCase.swift deleted file mode 100644 index ce1113f9..00000000 --- a/MLS/Domain/DomainInterface/UseCase/AuthAPI/FetchPlatformUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchPlatformUseCase { - func execute() -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/AuthAPI/LoginWithAppleUseCase.swift b/MLS/Domain/DomainInterface/UseCase/AuthAPI/LoginWithAppleUseCase.swift deleted file mode 100644 index d938224b..00000000 --- a/MLS/Domain/DomainInterface/UseCase/AuthAPI/LoginWithAppleUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol LoginWithAppleUseCase { - func execute(credential: Credential) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/AuthAPI/LoginWithKakaoUseCase.swift b/MLS/Domain/DomainInterface/UseCase/AuthAPI/LoginWithKakaoUseCase.swift deleted file mode 100644 index 8f856400..00000000 --- a/MLS/Domain/DomainInterface/UseCase/AuthAPI/LoginWithKakaoUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol LoginWithKakaoUseCase { - func execute(credential: Credential) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/AuthAPI/LogoutUseCase.swift b/MLS/Domain/DomainInterface/UseCase/AuthAPI/LogoutUseCase.swift deleted file mode 100644 index 10cf0abc..00000000 --- a/MLS/Domain/DomainInterface/UseCase/AuthAPI/LogoutUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol LogoutUseCase { - func execute() -> Completable -} diff --git a/MLS/Domain/DomainInterface/UseCase/AuthAPI/OpenNotificationSettingUseCase.swift b/MLS/Domain/DomainInterface/UseCase/AuthAPI/OpenNotificationSettingUseCase.swift deleted file mode 100644 index b2f485ca..00000000 --- a/MLS/Domain/DomainInterface/UseCase/AuthAPI/OpenNotificationSettingUseCase.swift +++ /dev/null @@ -1,3 +0,0 @@ -public protocol OpenNotificationSettingUseCase { - func execute() -} diff --git a/MLS/Domain/DomainInterface/UseCase/AuthAPI/PutFCMTokenUseCase.swift b/MLS/Domain/DomainInterface/UseCase/AuthAPI/PutFCMTokenUseCase.swift deleted file mode 100644 index 283f676c..00000000 --- a/MLS/Domain/DomainInterface/UseCase/AuthAPI/PutFCMTokenUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol PutFCMTokenUseCase { - func execute(fcmToken: String?) -> Completable -} diff --git a/MLS/Domain/DomainInterface/UseCase/AuthAPI/ReissueUseCase.swift b/MLS/Domain/DomainInterface/UseCase/AuthAPI/ReissueUseCase.swift deleted file mode 100644 index 4ab43bb7..00000000 --- a/MLS/Domain/DomainInterface/UseCase/AuthAPI/ReissueUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol ReissueUseCase { - func execute(refreshToken: String) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/AuthAPI/SignUpWithAppleUseCase.swift b/MLS/Domain/DomainInterface/UseCase/AuthAPI/SignUpWithAppleUseCase.swift deleted file mode 100644 index 77c0033c..00000000 --- a/MLS/Domain/DomainInterface/UseCase/AuthAPI/SignUpWithAppleUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol SignUpWithAppleUseCase { - func execute(credential: Credential, isMarketingAgreement: Bool, fcmToken: String?) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/AuthAPI/SignUpWithKakaoUseCase.swift b/MLS/Domain/DomainInterface/UseCase/AuthAPI/SignUpWithKakaoUseCase.swift deleted file mode 100644 index 480bc0d9..00000000 --- a/MLS/Domain/DomainInterface/UseCase/AuthAPI/SignUpWithKakaoUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol SignUpWithKakaoUseCase { - func execute(credential: Credential, isMarketingAgreement: Bool, fcmToken: String?) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/AuthAPI/UpdateMarketingAgreementUseCase.swift b/MLS/Domain/DomainInterface/UseCase/AuthAPI/UpdateMarketingAgreementUseCase.swift deleted file mode 100644 index 5311731f..00000000 --- a/MLS/Domain/DomainInterface/UseCase/AuthAPI/UpdateMarketingAgreementUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol UpdateMarketingAgreementUseCase { - func execute(credential: String, isMarketingAgreement: Bool) -> Completable -} diff --git a/MLS/Domain/DomainInterface/UseCase/AuthAPI/UpdateNotificationAgreementUseCase.swift b/MLS/Domain/DomainInterface/UseCase/AuthAPI/UpdateNotificationAgreementUseCase.swift deleted file mode 100644 index f7d052be..00000000 --- a/MLS/Domain/DomainInterface/UseCase/AuthAPI/UpdateNotificationAgreementUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol UpdateNotificationAgreementUseCase { - func execute(noticeAgreement: Bool, patchNoteAgreement: Bool, eventAgreement: Bool) -> Completable -} diff --git a/MLS/Domain/DomainInterface/UseCase/AuthAPI/UpdateUserInfoUseCase.swift b/MLS/Domain/DomainInterface/UseCase/AuthAPI/UpdateUserInfoUseCase.swift deleted file mode 100644 index 8e4e8cb9..00000000 --- a/MLS/Domain/DomainInterface/UseCase/AuthAPI/UpdateUserInfoUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol UpdateUserInfoUseCase { - func execute(level: Int, selectedJobID: Int) -> Completable -} diff --git a/MLS/Domain/DomainInterface/UseCase/AuthAPI/WithdrawUseCase.swift b/MLS/Domain/DomainInterface/UseCase/AuthAPI/WithdrawUseCase.swift deleted file mode 100644 index 0f8869db..00000000 --- a/MLS/Domain/DomainInterface/UseCase/AuthAPI/WithdrawUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol WithdrawUseCase { - func execute() -> Completable -} diff --git a/MLS/Domain/DomainInterface/UseCase/Bookmark/DeleteBookmarkUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Bookmark/DeleteBookmarkUseCase.swift deleted file mode 100644 index 09f11d50..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Bookmark/DeleteBookmarkUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol DeleteBookmarkUseCase { - func execute(bookmarkId: Int) -> Completable -} diff --git a/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchBookmarkUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchBookmarkUseCase.swift deleted file mode 100644 index 149d541c..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchBookmarkUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchBookmarkUseCase { - func execute(sort: SortType?) -> Observable<[BookmarkResponse]> -} diff --git a/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchItemBookmarkUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchItemBookmarkUseCase.swift deleted file mode 100644 index af6533ba..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchItemBookmarkUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchItemBookmarkUseCase { - func execute(jobId: Int?, minLevel: Int?, maxLevel: Int?, categoryIds: [Int]?, sort: SortType?) -> Observable<[BookmarkResponse]> -} diff --git a/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchMapBookmarkUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchMapBookmarkUseCase.swift deleted file mode 100644 index 1888ad12..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchMapBookmarkUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchMapBookmarkUseCase { - func execute(sort: SortType?) -> Observable<[BookmarkResponse]> -} diff --git a/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchMonsterBookmarkUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchMonsterBookmarkUseCase.swift deleted file mode 100644 index 3b5d9298..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchMonsterBookmarkUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchMonsterBookmarkUseCase { - func execute(minLevel: Int?, maxLevel: Int?, sort: SortType?) -> Observable<[BookmarkResponse]> -} diff --git a/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchNPCBookmarkUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchNPCBookmarkUseCase.swift deleted file mode 100644 index 6511d45c..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchNPCBookmarkUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchNPCBookmarkUseCase { - func execute(sort: SortType?) -> Observable<[BookmarkResponse]> -} diff --git a/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchQuestBookmarkUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchQuestBookmarkUseCase.swift deleted file mode 100644 index c62018b0..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchQuestBookmarkUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchQuestBookmarkUseCase { - func execute(sort: SortType?) -> Observable<[BookmarkResponse]> -} diff --git a/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchVisitBookmarkUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchVisitBookmarkUseCase.swift deleted file mode 100644 index 7df67704..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Bookmark/FetchVisitBookmarkUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchVisitBookmarkUseCase { - func execute() -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/Bookmark/SetBookmarkUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Bookmark/SetBookmarkUseCase.swift deleted file mode 100644 index 94117213..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Bookmark/SetBookmarkUseCase.swift +++ /dev/null @@ -1,10 +0,0 @@ -import RxSwift - -public protocol SetBookmarkUseCase { - func execute(bookmarkId: Int, isBookmark: IsBookmark) -> Observable -} - -public enum IsBookmark { - case set(DictionaryItemType) - case delete -} diff --git a/MLS/Domain/DomainInterface/UseCase/Collection/AddBookmarksToCollectionUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Collection/AddBookmarksToCollectionUseCase.swift deleted file mode 100644 index 50cc8f34..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Collection/AddBookmarksToCollectionUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -// import RxSwift -// -// public protocol AddBookmarksToCollectionUseCase { -// func execute(collectionId: Int, bookmarkIds: [Int]) -> Completable -// } diff --git a/MLS/Domain/DomainInterface/UseCase/Collection/AddCollectionAndBookmarkUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Collection/AddCollectionAndBookmarkUseCase.swift deleted file mode 100644 index b8f641d4..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Collection/AddCollectionAndBookmarkUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol AddCollectionAndBookmarkUseCase { - func execute(collectionIds: [Int], bookmarkIds: [Int]) -> Completable -} diff --git a/MLS/Domain/DomainInterface/UseCase/Collection/AddCollectionsToBookmarkUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Collection/AddCollectionsToBookmarkUseCase.swift deleted file mode 100644 index 0fe0a91d..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Collection/AddCollectionsToBookmarkUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -// import RxSwift -// -// public protocol AddCollectionsToBookmarkUseCase { -// func execute(bookmarkId: Int, collectionIds: [Int]) -> Completable -// } diff --git a/MLS/Domain/DomainInterface/UseCase/Collection/CreateCollectionListUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Collection/CreateCollectionListUseCase.swift deleted file mode 100644 index 1e2adbf8..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Collection/CreateCollectionListUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol CreateCollectionListUseCase { - func execute(name: String) -> Completable -} diff --git a/MLS/Domain/DomainInterface/UseCase/Collection/DeleteCollectionUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Collection/DeleteCollectionUseCase.swift deleted file mode 100644 index 738ccbb9..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Collection/DeleteCollectionUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol DeleteCollectionUseCase { - func execute(collectionId: Int) -> Completable -} diff --git a/MLS/Domain/DomainInterface/UseCase/Collection/FetchCollectionListUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Collection/FetchCollectionListUseCase.swift deleted file mode 100644 index 96513970..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Collection/FetchCollectionListUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchCollectionListUseCase { - func execute(sort: SortType?) -> Observable<[CollectionResponse]> -} diff --git a/MLS/Domain/DomainInterface/UseCase/Collection/FetchCollectionUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Collection/FetchCollectionUseCase.swift deleted file mode 100644 index 29d8226d..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Collection/FetchCollectionUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchCollectionUseCase { - func execute(id: Int) -> Observable<[BookmarkResponse]> -} diff --git a/MLS/Domain/DomainInterface/UseCase/Collection/UpdateCollectionUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Collection/UpdateCollectionUseCase.swift deleted file mode 100644 index efeb3308..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Collection/UpdateCollectionUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol UpdateCollectionUseCase { - func execute(collectionId: Int, name: String) -> Completable -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailItemDropMonsterUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailItemDropMonsterUseCase.swift deleted file mode 100644 index 4846a970..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailItemDropMonsterUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryDetailItemDropMonsterUseCase { - func execute(id: Int, sort: String?) -> Observable<[DictionaryDetailItemDropMonsterResponse]> -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailItemUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailItemUseCase.swift deleted file mode 100644 index ec2f31e8..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailItemUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryDetailItemUseCase { - func execute(id: Int) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMapNpcUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMapNpcUseCase.swift deleted file mode 100644 index 3ed6927d..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMapNpcUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryDetailMapNpcUseCase { - func execute(id: Int) -> Observable<[DictionaryDetailMapNpcResponse]> -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMapSpawnMonsterUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMapSpawnMonsterUseCase.swift deleted file mode 100644 index 11e6816c..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMapSpawnMonsterUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryDetailMapSpawnMonsterUseCase { - func execute(id: Int, sort: String?) -> Observable<[DictionaryDetailMapSpawnMonsterResponse]> -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMapUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMapUseCase.swift deleted file mode 100644 index 81dc05d6..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMapUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryDetailMapUseCase { - func execute(id: Int) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMonsterItemsUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMonsterItemsUseCase.swift deleted file mode 100644 index 85b3e261..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMonsterItemsUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryDetailMonsterItemsUseCase { - func execute(id: Int, sort: String?) -> Observable<[DictionaryDetailMonsterDropItemResponse]> -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMonsterMapUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMonsterMapUseCase.swift deleted file mode 100644 index 4e683ddd..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMonsterMapUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryDetailMonsterMapUseCase { - func execute(id: Int) -> Observable<[DictionaryDetailMonsterMapResponse]> -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMonsterUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMonsterUseCase.swift deleted file mode 100644 index 969a146c..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailMonsterUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryDetailMonsterUseCase { - func execute(id: Int) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailNpcMapUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailNpcMapUseCase.swift deleted file mode 100644 index 1069e032..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailNpcMapUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryDetailNpcMapUseCase { - func execute(id: Int) -> Observable<[DictionaryDetailMonsterMapResponse]> -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailNpcQuestUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailNpcQuestUseCase.swift deleted file mode 100644 index cad5aa6a..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailNpcQuestUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryDetailNpcQuestUseCase { - func execute(id: Int, sort: String?) -> Observable<[DictionaryDetailNpcQuestResponse]> -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailNpcUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailNpcUseCase.swift deleted file mode 100644 index 29a55429..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailNpcUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryDetailNpcUseCase { - func execute(id: Int) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailQuestLinkedQuestsUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailQuestLinkedQuestsUseCase.swift deleted file mode 100644 index 605d360e..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailQuestLinkedQuestsUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryDetailQuestLinkedQuestsUseCase { - func execute(id: Int) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailQuestUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailQuestUseCase.swift deleted file mode 100644 index b5cb19c4..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchDictionaryDetailQuestUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryDetailQuestUseCase { - func execute(id: Int) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchVisitDictionaryDetailUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchVisitDictionaryDetailUseCase.swift deleted file mode 100644 index 810c4969..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryDetail/FetchVisitDictionaryDetailUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchVisitDictionaryDetailUseCase { - func execute() -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryAllListUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryAllListUseCase.swift deleted file mode 100644 index 47923622..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryAllListUseCase.swift +++ /dev/null @@ -1,6 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryAllListUseCase { - // 쿼리없이 keyword, page만 전달 - func execute(keyword: String?, page: Int?) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryItemListUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryItemListUseCase.swift deleted file mode 100644 index 16ecffba..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryItemListUseCase.swift +++ /dev/null @@ -1,6 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryItemListUseCase { - /// 어떤 타입인지에 따라서 쿼리가 결정됨 -> 타입 마다 쿼리가 댜름. - func execute(keyword: String?, jobId: [Int]?, minLevel: Int?, maxLevel: Int?, categoryIds: [Int]?, page: Int?, size: Int?, sort: String?) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryMapListUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryMapListUseCase.swift deleted file mode 100644 index 4b8ceb53..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryMapListUseCase.swift +++ /dev/null @@ -1,6 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryMapListUseCase { - /// 어떤 타입인지에 따라서 쿼리가 결정됨 -> 타입 마다 쿼리가 댜름. - func execute(keyword: String, page: Int, size: Int, sort: String?) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryMonsterListUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryMonsterListUseCase.swift deleted file mode 100644 index 3f21d6ea..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryMonsterListUseCase.swift +++ /dev/null @@ -1,6 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryMonsterListUseCase { - /// 어떤 타입인지에 따라서 쿼리가 결정됨 -> 타입 마다 쿼리가 댜름. - func execute(type: DictionaryType, query: DictionaryListQuery) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryNpcListUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryNpcListUseCase.swift deleted file mode 100644 index 94dd500f..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryNpcListUseCase.swift +++ /dev/null @@ -1,6 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryNpcListUseCase { - /// 어떤 타입인지에 따라서 쿼리가 결정됨 -> 타입 마다 쿼리가 댜름. - func execute(keyword: String, page: Int, size: Int, sort: String?) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryQuestListUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryQuestListUseCase.swift deleted file mode 100644 index 65d08d20..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionaryQuestListUseCase.swift +++ /dev/null @@ -1,6 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryQuestListUseCase { - /// 어떤 타입인지에 따라서 쿼리가 결정됨 -> 타입 마다 쿼리가 댜름. - func execute(keyword: String, page: Int, size: Int, sort: String?) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionarySearchListUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionarySearchListUseCase.swift deleted file mode 100644 index d7b537c3..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryList/FetchDictionarySearchListUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchDictionarySearchListUseCase { - func execute(keyword: String) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryList/ParseItemFilterUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryList/ParseItemFilterUseCase.swift deleted file mode 100644 index 13a68723..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryList/ParseItemFilterUseCase.swift +++ /dev/null @@ -1,3 +0,0 @@ -public protocol ParseItemFilterResultUseCase { - func execute(results: [(String, String)]) -> ItemFilterCriteria -} diff --git a/MLS/Domain/DomainInterface/UseCase/DictionaryListCount/FetchDictionaryListCountUseCase.swift b/MLS/Domain/DomainInterface/UseCase/DictionaryListCount/FetchDictionaryListCountUseCase.swift deleted file mode 100644 index 4874676a..00000000 --- a/MLS/Domain/DomainInterface/UseCase/DictionaryListCount/FetchDictionaryListCountUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchDictionaryListCountUseCase { - func execute(type: String, keyword: String?) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/LocalToken/DeleteTokenFromLocalUseCase.swift b/MLS/Domain/DomainInterface/UseCase/LocalToken/DeleteTokenFromLocalUseCase.swift deleted file mode 100644 index b135567e..00000000 --- a/MLS/Domain/DomainInterface/UseCase/LocalToken/DeleteTokenFromLocalUseCase.swift +++ /dev/null @@ -1,8 +0,0 @@ -import Foundation - -public protocol DeleteTokenFromLocalUseCase { - /// 토큰을 삭제하는 메서드 - /// - Parameter type: 삭제하려는 토큰의 타입 (`accessToken` 또는 `refreshToken`) - /// - Returns: 완료 시 `Result` - func execute(type: TokenType) -> Result -} diff --git a/MLS/Domain/DomainInterface/UseCase/LocalToken/FetchTokenFromLocalUseCase.swift b/MLS/Domain/DomainInterface/UseCase/LocalToken/FetchTokenFromLocalUseCase.swift deleted file mode 100644 index 1d914adf..00000000 --- a/MLS/Domain/DomainInterface/UseCase/LocalToken/FetchTokenFromLocalUseCase.swift +++ /dev/null @@ -1,8 +0,0 @@ -import Foundation - -public protocol FetchTokenFromLocalUseCase { - /// 토큰을 가져오는 메서드 - /// - Parameter type: 가져오려는 토큰의 타입 (`accessToken` 또는 `refreshToken`) - /// - Returns: 가져온 토큰을 담은 `Result` - func execute(type: TokenType) -> Result -} diff --git a/MLS/Domain/DomainInterface/UseCase/LocalToken/SaveTokenToLocalUseCase.swift b/MLS/Domain/DomainInterface/UseCase/LocalToken/SaveTokenToLocalUseCase.swift deleted file mode 100644 index 5c18a369..00000000 --- a/MLS/Domain/DomainInterface/UseCase/LocalToken/SaveTokenToLocalUseCase.swift +++ /dev/null @@ -1,9 +0,0 @@ -import Foundation - -public protocol SaveTokenToLocalUseCase { - /// 토큰을 저장하는 메서드 - /// - Parameter type: 저장하려는 토큰의 타입 (`accessToken` 또는 `refreshToken`) - /// - Parameter value: 저장할 토큰의 값 - /// - Returns: 완료 시 `Result` - func execute(type: TokenType, value: String) -> Result -} diff --git a/MLS/Domain/DomainInterface/UseCase/MyPage/FetchJobUseCase.swift b/MLS/Domain/DomainInterface/UseCase/MyPage/FetchJobUseCase.swift deleted file mode 100644 index bf7e719f..00000000 --- a/MLS/Domain/DomainInterface/UseCase/MyPage/FetchJobUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchJobUseCase { - func execute(jobId: String) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/MyPage/FetchProfileUseCase.swift b/MLS/Domain/DomainInterface/UseCase/MyPage/FetchProfileUseCase.swift deleted file mode 100644 index f8176cb4..00000000 --- a/MLS/Domain/DomainInterface/UseCase/MyPage/FetchProfileUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol FetchProfileUseCase { - func execute() -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/MyPage/UpdateNickNameUseCase.swift b/MLS/Domain/DomainInterface/UseCase/MyPage/UpdateNickNameUseCase.swift deleted file mode 100644 index 19638955..00000000 --- a/MLS/Domain/DomainInterface/UseCase/MyPage/UpdateNickNameUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol UpdateNickNameUseCase { - func execute(nickName: String) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/MyPage/UpdateProfileImageUseCase.swift b/MLS/Domain/DomainInterface/UseCase/MyPage/UpdateProfileImageUseCase.swift deleted file mode 100644 index 89f44160..00000000 --- a/MLS/Domain/DomainInterface/UseCase/MyPage/UpdateProfileImageUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol UpdateProfileImageUseCase { - func execute(url: String) -> Completable -} diff --git a/MLS/Domain/DomainInterface/UseCase/OnBoarding/CheckEmptyLevelAndRoleUseCase.swift b/MLS/Domain/DomainInterface/UseCase/OnBoarding/CheckEmptyLevelAndRoleUseCase.swift deleted file mode 100644 index f044413f..00000000 --- a/MLS/Domain/DomainInterface/UseCase/OnBoarding/CheckEmptyLevelAndRoleUseCase.swift +++ /dev/null @@ -1,10 +0,0 @@ -import RxSwift - -public protocol CheckEmptyLevelAndRoleUseCase { - /// 레벨의 범위가 0~200에 속하는지 + 직업이 유효한 값인지 확인 - /// - Parameters: - /// - level: 현재 입력된 레벨 - /// - job: 현재 입력된 직업 - /// - Returns: true / false - func execute(level: Int?, job: String?) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/OnBoarding/CheckNickNameUseCase.swift b/MLS/Domain/DomainInterface/UseCase/OnBoarding/CheckNickNameUseCase.swift deleted file mode 100644 index f57fb71d..00000000 --- a/MLS/Domain/DomainInterface/UseCase/OnBoarding/CheckNickNameUseCase.swift +++ /dev/null @@ -1,9 +0,0 @@ -import RxSwift - -public protocol CheckNickNameUseCase { - /// 닉네임에 비속어가 포함되어 있는지 판별 - /// - Parameters: - /// - nickName: 현재 입력된 닉네임 - /// - Returns: true / false - func execute(nickName: String) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/OnBoarding/CheckValidLevelUseCase.swift b/MLS/Domain/DomainInterface/UseCase/OnBoarding/CheckValidLevelUseCase.swift deleted file mode 100644 index 08b4683d..00000000 --- a/MLS/Domain/DomainInterface/UseCase/OnBoarding/CheckValidLevelUseCase.swift +++ /dev/null @@ -1,8 +0,0 @@ -import RxSwift - -public protocol CheckValidLevelUseCase { - /// 입력된 레벨의 범위가 0~200에 속하는지 확인 - /// - Parameter level: 입력된 레벨 - /// - Returns:true / false - func execute(level: Int?) -> Observable -} diff --git a/MLS/Domain/DomainInterface/UseCase/RecentSearch/RecentSearchAddUseCase.swift b/MLS/Domain/DomainInterface/UseCase/RecentSearch/RecentSearchAddUseCase.swift deleted file mode 100644 index c72bce96..00000000 --- a/MLS/Domain/DomainInterface/UseCase/RecentSearch/RecentSearchAddUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol RecentSearchAddUseCase { - func add(keyword: String) -> Completable -} diff --git a/MLS/Domain/DomainInterface/UseCase/RecentSearch/RecentSearchFetchUseCase.swift b/MLS/Domain/DomainInterface/UseCase/RecentSearch/RecentSearchFetchUseCase.swift deleted file mode 100644 index e03f81fc..00000000 --- a/MLS/Domain/DomainInterface/UseCase/RecentSearch/RecentSearchFetchUseCase.swift +++ /dev/null @@ -1,5 +0,0 @@ -import RxSwift - -public protocol RecentSearchFetchUseCase { - func fetch() -> Observable<[String]> -} diff --git a/MLS/Domain/DomainInterface/UseCase/RecentSearch/RecentSearchRemoveUseCase.swift b/MLS/Domain/DomainInterface/UseCase/RecentSearch/RecentSearchRemoveUseCase.swift deleted file mode 100644 index 5a6e9792..00000000 --- a/MLS/Domain/DomainInterface/UseCase/RecentSearch/RecentSearchRemoveUseCase.swift +++ /dev/null @@ -1,6 +0,0 @@ -import RxSwift - -public protocol RecentSearchRemoveUseCase { - func remove(keyword: String) -> Completable - func removeAll() -> Completable -} diff --git a/MLS/Domain/DomainInterface/UseCase/Shared/FetchSocialCredentialUseCase.swift b/MLS/Domain/DomainInterface/UseCase/Shared/FetchSocialCredentialUseCase.swift deleted file mode 100644 index c883ebd9..00000000 --- a/MLS/Domain/DomainInterface/UseCase/Shared/FetchSocialCredentialUseCase.swift +++ /dev/null @@ -1,7 +0,0 @@ -import Foundation - -import RxSwift - -public protocol FetchSocialCredentialUseCase { - func execute() -> Observable -} diff --git a/MLS/MLS.xcodeproj/project.pbxproj b/MLS/MLS.xcodeproj/project.pbxproj index b0ab1b5c..49b4a614 100644 --- a/MLS/MLS.xcodeproj/project.pbxproj +++ b/MLS/MLS.xcodeproj/project.pbxproj @@ -7,28 +7,10 @@ objects = { /* Begin PBXBuildFile section */ - 0801759F2DCD27E600D0919F /* DomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0801759E2DCD27E600D0919F /* DomainInterface.framework */; }; - 080175A02DCD27E600D0919F /* DomainInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0801759E2DCD27E600D0919F /* DomainInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 084A25522DB93BC500C395C0 /* Domain.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 084A25512DB93BC500C395C0 /* Domain.framework */; }; - 084A25532DB93BC500C395C0 /* Domain.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 084A25512DB93BC500C395C0 /* Domain.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 084A25552DB93BC800C395C0 /* Data.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 084A25542DB93BC800C395C0 /* Data.framework */; }; - 084A25562DB93BC800C395C0 /* Data.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 084A25542DB93BC800C395C0 /* Data.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 084A25D72DB93E2C00C395C0 /* Core.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 084A25D62DB93E2C00C395C0 /* Core.framework */; }; - 084A25D82DB93E2C00C395C0 /* Core.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 084A25D62DB93E2C00C395C0 /* Core.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 085598AC2FB4A6B7003F315F /* MLSRecommendationFeature in Frameworks */ = {isa = PBXBuildFile; productRef = 085598AB2FB4A6B7003F315F /* MLSRecommendationFeature */; }; - 085598AE2FB4A6BD003F315F /* MLSRecommendationFeatureInterface in Frameworks */ = {isa = PBXBuildFile; productRef = 085598AD2FB4A6BD003F315F /* MLSRecommendationFeatureInterface */; }; - 0858ABFC2DCFDBF20060EBCA /* DesignSystem.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0858ABFB2DCFDBF20060EBCA /* DesignSystem.framework */; }; - 0858ABFD2DCFDBF20060EBCA /* DesignSystem.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0858ABFB2DCFDBF20060EBCA /* DesignSystem.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 085A7F752DAF99570046663F /* .swiftlint.yml in Resources */ = {isa = PBXBuildFile; fileRef = 085A7F742DAF99570046663F /* .swiftlint.yml */; }; - 085BDF5E2DF6B6B3009CFB90 /* DataMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 085BDF5D2DF6B6B3009CFB90 /* DataMock.framework */; }; - 085BDF5F2DF6B6B3009CFB90 /* DataMock.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 085BDF5D2DF6B6B3009CFB90 /* DataMock.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 088636972FB4664E00006D4A /* MLSRecommendationFeatureTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 088636962FB4664E00006D4A /* MLSRecommendationFeatureTesting */; }; 08DA51B42E1B9827009097A6 /* FirebaseFirestore in Frameworks */ = {isa = PBXBuildFile; productRef = 08DA51B32E1B9827009097A6 /* FirebaseFirestore */; }; 08DA51B62E1B9827009097A6 /* FirebaseMessaging in Frameworks */ = {isa = PBXBuildFile; productRef = 08DA51B52E1B9827009097A6 /* FirebaseMessaging */; }; - 08DA58A72E1E5BE3009097A6 /* DictionaryFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08DA58A62E1E5BE3009097A6 /* DictionaryFeature.framework */; }; - 08DA58A82E1E5BE3009097A6 /* DictionaryFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 08DA58A62E1E5BE3009097A6 /* DictionaryFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 08DA58AA2E1E5BEB009097A6 /* DictionaryFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08DA58A92E1E5BEB009097A6 /* DictionaryFeatureInterface.framework */; }; - 08DA58AB2E1E5BEB009097A6 /* DictionaryFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 08DA58A92E1E5BEB009097A6 /* DictionaryFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 08ED49282DCFDED4002C21A2 /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 08ED49272DCFDED4002C21A2 /* RxCocoa */; }; 08ED492A2DCFDED4002C21A2 /* RxRelay in Frameworks */ = {isa = PBXBuildFile; productRef = 08ED49292DCFDED4002C21A2 /* RxRelay */; }; 08ED492C2DCFDED4002C21A2 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 08ED492B2DCFDED4002C21A2 /* RxSwift */; }; @@ -41,37 +23,23 @@ 08F7DC842F9DEA8100EF5C06 /* MLSCore in Frameworks */ = {isa = PBXBuildFile; productRef = 08F7DC852F9DEA8100EF5C06 /* MLSCore */; }; 770ADB1F2E433EDA00270506 /* RxKeyboard in Frameworks */ = {isa = PBXBuildFile; productRef = 770ADB1E2E433EDA00270506 /* RxKeyboard */; }; 77217FD42F9A05D7000915EF /* MLSMyPageFeature in Frameworks */ = {isa = PBXBuildFile; productRef = 77217FD32F9A05D7000915EF /* MLSMyPageFeature */; }; - 772199F22E0E7EC800A7B58C /* AuthFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 772199F12E0E7EC800A7B58C /* AuthFeatureInterface.framework */; }; - 772199F32E0E7EC800A7B58C /* AuthFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 772199F12E0E7EC800A7B58C /* AuthFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 7721A5042E0EE7AE00A7B58C /* BaseFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7721A5032E0EE7AE00A7B58C /* BaseFeature.framework */; }; - 7721A5052E0EE7AE00A7B58C /* BaseFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7721A5032E0EE7AE00A7B58C /* BaseFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 7721A5082E0EE7F100A7B58C /* ReactorKit in Frameworks */ = {isa = PBXBuildFile; productRef = 7721A5072E0EE7F100A7B58C /* ReactorKit */; }; 7736814E2F9A2CE3002DC773 /* MLSMyPageFeatureInterface in Frameworks */ = {isa = PBXBuildFile; productRef = 7736814D2F9A2CE3002DC773 /* MLSMyPageFeatureInterface */; }; 773681502F9A2CE3002DC773 /* MLSMyPageFeatureTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 7736814F2F9A2CE3002DC773 /* MLSMyPageFeatureTesting */; }; 77660AD22DD0D361007A4EF3 /* KakaoConfig.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 77660AD12DD0D361007A4EF3 /* KakaoConfig.xcconfig */; }; 77660AD52DD0D3DD007A4EF3 /* KakaoSDKAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 77660AD42DD0D3DD007A4EF3 /* KakaoSDKAuth */; }; 77660AD72DD0D3DD007A4EF3 /* KakaoSDKUser in Frameworks */ = {isa = PBXBuildFile; productRef = 77660AD62DD0D3DD007A4EF3 /* KakaoSDKUser */; }; - 7777F7022E9EAB8400F53D68 /* BookmarkFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7777F7002E9EAB8400F53D68 /* BookmarkFeature.framework */; }; - 7777F7032E9EAB8400F53D68 /* BookmarkFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7777F7002E9EAB8400F53D68 /* BookmarkFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 7777F7042E9EAB8400F53D68 /* BookmarkFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7777F7012E9EAB8400F53D68 /* BookmarkFeatureInterface.framework */; }; - 7777F7052E9EAB8400F53D68 /* BookmarkFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7777F7012E9EAB8400F53D68 /* BookmarkFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 7777F7082E9EAC0D00F53D68 /* MyPageFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7777F7062E9EAC0D00F53D68 /* MyPageFeature.framework */; }; - 7777F7092E9EAC0D00F53D68 /* MyPageFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7777F7062E9EAC0D00F53D68 /* MyPageFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 7777F70A2E9EAC0D00F53D68 /* MyPageFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7777F7072E9EAC0D00F53D68 /* MyPageFeatureInterface.framework */; }; - 7777F70B2E9EAC0D00F53D68 /* MyPageFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7777F7072E9EAC0D00F53D68 /* MyPageFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 779A490D2E1AD26700ABDE4F /* BookmarkFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 779A490C2E1AD26700ABDE4F /* BookmarkFeature.framework */; }; - 779A490E2E1AD26700ABDE4F /* BookmarkFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 779A490C2E1AD26700ABDE4F /* BookmarkFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 779A49102E1AD26D00ABDE4F /* BookmarkFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 779A490F2E1AD26D00ABDE4F /* BookmarkFeatureInterface.framework */; }; - 779A49112E1AD26D00ABDE4F /* BookmarkFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 779A490F2E1AD26D00ABDE4F /* BookmarkFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 77947A342FD802FC0010E7E9 /* MLSAppFeatureInterface in Frameworks */ = {isa = PBXBuildFile; productRef = 77947A332FD802FC0010E7E9 /* MLSAppFeatureInterface */; }; 77A293312F79989200845081 /* DesignSystem.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77A293302F79989200845081 /* DesignSystem.framework */; }; 77A293322F79989200845081 /* DesignSystem.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77A293302F79989200845081 /* DesignSystem.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 77AB59ED2FBE20FD00BAB8A3 /* MLSAuthFeatureTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 77AB59EC2FBE20FD00BAB8A3 /* MLSAuthFeatureTesting */; }; 77AB59EF2FBE20FD00BAB8A3 /* MLSMyPageFeatureTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 77AB59EE2FBE20FD00BAB8A3 /* MLSMyPageFeatureTesting */; }; + 77AF68822FD839E9008AAE68 /* MLSCore in Frameworks */ = {isa = PBXBuildFile; productRef = 77AF68812FD839E9008AAE68 /* MLSCore */; }; + 77AF68842FD839F3008AAE68 /* MLSDesignSystem in Frameworks */ = {isa = PBXBuildFile; productRef = 77AF68832FD839F3008AAE68 /* MLSDesignSystem */; }; 77B1F9952EE06A4E00AE4B4D /* RxGesture in Frameworks */ = {isa = PBXBuildFile; productRef = 77B1F9942EE06A4E00AE4B4D /* RxGesture */; }; + 77CEA6EE2FD70F2700E052BC /* MLSAppFeature in Frameworks */ = {isa = PBXBuildFile; productRef = 77CEA6ED2FD70F2700E052BC /* MLSAppFeature */; }; 77DE6DEF2F9F9EA1007FD8AC /* MLSAuthFeatureTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 77DE6DEE2F9F9EA1007FD8AC /* MLSAuthFeatureTesting */; }; 77E260412EEABEC40059E889 /* Settings.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 77E260402EEABEC40059E889 /* Settings.bundle */; }; - 77EB18D62DED9256004FB380 /* AuthFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77EB18D52DED9256004FB380 /* AuthFeature.framework */; }; - 77EB18D72DED9256004FB380 /* AuthFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77EB18D52DED9256004FB380 /* AuthFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 77F7C2262FBCB2A200D515A8 /* MLSDictionaryFeature in Frameworks */ = {isa = PBXBuildFile; productRef = 77F7C2252FBCB2A200D515A8 /* MLSDictionaryFeature */; }; 77F7C2282FBCB2A200D515A8 /* MLSDictionaryFeatureTesting in Frameworks */ = {isa = PBXBuildFile; productRef = 77F7C2272FBCB2A200D515A8 /* MLSDictionaryFeatureTesting */; }; 77F7C22C2FBE18D400D515A8 /* MLSDictionaryFeatureInterface in Frameworks */ = {isa = PBXBuildFile; productRef = 77F7C22B2FBE18D400D515A8 /* MLSDictionaryFeatureInterface */; }; @@ -98,33 +66,6 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ - 08A6761F2DB939A40028F72A /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 080175A02DCD27E600D0919F /* DomainInterface.framework in Embed Frameworks */, - 7777F70B2E9EAC0D00F53D68 /* MyPageFeatureInterface.framework in Embed Frameworks */, - 779A49112E1AD26D00ABDE4F /* BookmarkFeatureInterface.framework in Embed Frameworks */, - 7777F7092E9EAC0D00F53D68 /* MyPageFeature.framework in Embed Frameworks */, - 772199F32E0E7EC800A7B58C /* AuthFeatureInterface.framework in Embed Frameworks */, - 084A25562DB93BC800C395C0 /* Data.framework in Embed Frameworks */, - 08DA58A82E1E5BE3009097A6 /* DictionaryFeature.framework in Embed Frameworks */, - 7777F7052E9EAB8400F53D68 /* BookmarkFeatureInterface.framework in Embed Frameworks */, - 08DA58AB2E1E5BEB009097A6 /* DictionaryFeatureInterface.framework in Embed Frameworks */, - 084A25D82DB93E2C00C395C0 /* Core.framework in Embed Frameworks */, - 0858ABFD2DCFDBF20060EBCA /* DesignSystem.framework in Embed Frameworks */, - 779A490E2E1AD26700ABDE4F /* BookmarkFeature.framework in Embed Frameworks */, - 084A25532DB93BC500C395C0 /* Domain.framework in Embed Frameworks */, - 085BDF5F2DF6B6B3009CFB90 /* DataMock.framework in Embed Frameworks */, - 7721A5052E0EE7AE00A7B58C /* BaseFeature.framework in Embed Frameworks */, - 77EB18D72DED9256004FB380 /* AuthFeature.framework in Embed Frameworks */, - 7777F7032E9EAB8400F53D68 /* BookmarkFeature.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; 77A293332F79989200845081 /* Embed Frameworks */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -175,6 +116,21 @@ 77A293302F79989200845081 /* DesignSystem.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DesignSystem.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 77BEB0402DBA84B0002FFCFC /* MLSTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = MLSTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 77E260402EEABEC40059E889 /* Settings.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = Settings.bundle; path = MLS/Resource/Settings.bundle; sourceTree = ""; }; + 77E7B7112FD73F630077358E /* AuthFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AuthFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 77E7B7122FD73F630077358E /* AuthFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AuthFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 77E7B7132FD73F630077358E /* BaseFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BaseFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 77E7B7142FD73F630077358E /* BookmarkFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BookmarkFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 77E7B7152FD73F630077358E /* BookmarkFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BookmarkFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 77E7B7162FD73F630077358E /* Core.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Core.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 77E7B7172FD73F630077358E /* Data.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Data.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 77E7B7182FD73F630077358E /* DataMock.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DataMock.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 77E7B7192FD73F630077358E /* DesignSystem.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DesignSystem.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 77E7B71A2FD73F630077358E /* DictionaryFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DictionaryFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 77E7B71B2FD73F630077358E /* DictionaryFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DictionaryFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 77E7B71C2FD73F630077358E /* Domain.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Domain.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 77E7B71D2FD73F630077358E /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 77E7B71E2FD73F630077358E /* MyPageFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MyPageFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 77E7B71F2FD73F630077358E /* MyPageFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MyPageFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 77EB18D52DED9256004FB380 /* AuthFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AuthFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 77FA687A2F72C7360064B6EB /* MLSDesignSystemExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MLSDesignSystemExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; BBCC02002FA000000000BBCC /* MLSBookmarkFeatureExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MLSBookmarkFeatureExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -301,36 +257,20 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 77AF68842FD839F3008AAE68 /* MLSDesignSystem in Frameworks */, 08DA51B62E1B9827009097A6 /* FirebaseMessaging in Frameworks */, - 7777F70A2E9EAC0D00F53D68 /* MyPageFeatureInterface.framework in Frameworks */, 770ADB1F2E433EDA00270506 /* RxKeyboard in Frameworks */, + 77AF68822FD839E9008AAE68 /* MLSCore in Frameworks */, + 77CEA6EE2FD70F2700E052BC /* MLSAppFeature in Frameworks */, 08ED492C2DCFDED4002C21A2 /* RxSwift in Frameworks */, - 7721A5042E0EE7AE00A7B58C /* BaseFeature.framework in Frameworks */, - 08DA58AA2E1E5BEB009097A6 /* DictionaryFeatureInterface.framework in Frameworks */, 77B1F9952EE06A4E00AE4B4D /* RxGesture in Frameworks */, 7721A5082E0EE7F100A7B58C /* ReactorKit in Frameworks */, - 0801759F2DCD27E600D0919F /* DomainInterface.framework in Frameworks */, - 7777F7022E9EAB8400F53D68 /* BookmarkFeature.framework in Frameworks */, - 08DA58A72E1E5BE3009097A6 /* DictionaryFeature.framework in Frameworks */, 08DA51B42E1B9827009097A6 /* FirebaseFirestore in Frameworks */, - 7777F7042E9EAB8400F53D68 /* BookmarkFeatureInterface.framework in Frameworks */, - 084A25552DB93BC800C395C0 /* Data.framework in Frameworks */, - 085598AC2FB4A6B7003F315F /* MLSRecommendationFeature in Frameworks */, - 084A25D72DB93E2C00C395C0 /* Core.framework in Frameworks */, 08ED49282DCFDED4002C21A2 /* RxCocoa in Frameworks */, - 7777F7082E9EAC0D00F53D68 /* MyPageFeature.framework in Frameworks */, - 0858ABFC2DCFDBF20060EBCA /* DesignSystem.framework in Frameworks */, - 779A490D2E1AD26700ABDE4F /* BookmarkFeature.framework in Frameworks */, 77660AD52DD0D3DD007A4EF3 /* KakaoSDKAuth in Frameworks */, - 772199F22E0E7EC800A7B58C /* AuthFeatureInterface.framework in Frameworks */, - 779A49102E1AD26D00ABDE4F /* BookmarkFeatureInterface.framework in Frameworks */, - 085598AE2FB4A6BD003F315F /* MLSRecommendationFeatureInterface in Frameworks */, - 084A25522DB93BC500C395C0 /* Domain.framework in Frameworks */, 77660AD72DD0D3DD007A4EF3 /* KakaoSDKUser in Frameworks */, - 085BDF5E2DF6B6B3009CFB90 /* DataMock.framework in Frameworks */, 08ED492A2DCFDED4002C21A2 /* RxRelay in Frameworks */, 08ED4DB12DCFE098002C21A2 /* SnapKit in Frameworks */, - 77EB18D62DED9256004FB380 /* AuthFeature.framework in Frameworks */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -338,6 +278,7 @@ isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; files = ( + 77947A342FD802FC0010E7E9 /* MLSAppFeatureInterface in Frameworks */, 08F7AA012F86745C00EF5C06 /* MLSAuthFeature in Frameworks */, 08F7AA032F86745C00EF5C06 /* MLSAuthFeatureInterface in Frameworks */, 08F7AA052F86745C00EF5C06 /* MLSAuthFeatureTesting in Frameworks */, @@ -458,6 +399,21 @@ 084A25312DB93A5400C395C0 /* Frameworks */ = { isa = PBXGroup; children = ( + 77E7B7112FD73F630077358E /* AuthFeature.framework */, + 77E7B7122FD73F630077358E /* AuthFeatureInterface.framework */, + 77E7B7132FD73F630077358E /* BaseFeature.framework */, + 77E7B7142FD73F630077358E /* BookmarkFeature.framework */, + 77E7B7152FD73F630077358E /* BookmarkFeatureInterface.framework */, + 77E7B7162FD73F630077358E /* Core.framework */, + 77E7B7172FD73F630077358E /* Data.framework */, + 77E7B7182FD73F630077358E /* DataMock.framework */, + 77E7B7192FD73F630077358E /* DesignSystem.framework */, + 77E7B71A2FD73F630077358E /* DictionaryFeature.framework */, + 77E7B71B2FD73F630077358E /* DictionaryFeatureInterface.framework */, + 77E7B71C2FD73F630077358E /* Domain.framework */, + 77E7B71D2FD73F630077358E /* DomainInterface.framework */, + 77E7B71E2FD73F630077358E /* MyPageFeature.framework */, + 77E7B71F2FD73F630077358E /* MyPageFeatureInterface.framework */, 77A293302F79989200845081 /* DesignSystem.framework */, 7777F7062E9EAC0D00F53D68 /* MyPageFeature.framework */, 7777F7072E9EAC0D00F53D68 /* MyPageFeatureInterface.framework */, @@ -491,13 +447,13 @@ 77660AD12DD0D361007A4EF3 /* KakaoConfig.xcconfig */, 085A7F742DAF99570046663F /* .swiftlint.yml */, 087D3EEA2DA7972C002F924D /* MLS */, - 77BEB0412DBA84B0002FFCFC /* MLSTests */, - 77FA687B2F72C7360064B6EB /* MLSDesignSystemExample */, 08F7A9242F86745C00EF5C06 /* MLSAuthFeatureExample */, - 77217FBF2F9A04CF000915EF /* MLSMyPageFeatureExample */, - 08F7DC622F9DEA8000EF5C06 /* MLSRecommendationFeatureExample */, BBCC03002FA000000000BBCC /* MLSBookmarkFeatureExample */, + 77FA687B2F72C7360064B6EB /* MLSDesignSystemExample */, 7794E1072FBCA8AA001474A2 /* MLSDictionaryFeatureExample */, + 77217FBF2F9A04CF000915EF /* MLSMyPageFeatureExample */, + 08F7DC622F9DEA8000EF5C06 /* MLSRecommendationFeatureExample */, + 77BEB0412DBA84B0002FFCFC /* MLSTests */, 084A25312DB93A5400C395C0 /* Frameworks */, 087D3EE92DA7972C002F924D /* Products */, ); @@ -529,7 +485,6 @@ 087D3EE42DA7972C002F924D /* Sources */, 087D3EE52DA7972C002F924D /* Frameworks */, 087D3EE62DA7972C002F924D /* Resources */, - 08A6761F2DB939A40028F72A /* Embed Frameworks */, ); buildRules = ( ); @@ -551,8 +506,9 @@ 08DA51B52E1B9827009097A6 /* FirebaseMessaging */, 770ADB1E2E433EDA00270506 /* RxKeyboard */, 77B1F9942EE06A4E00AE4B4D /* RxGesture */, - 085598AB2FB4A6B7003F315F /* MLSRecommendationFeature */, - 085598AD2FB4A6BD003F315F /* MLSRecommendationFeatureInterface */, + 77CEA6ED2FD70F2700E052BC /* MLSAppFeature */, + 77AF68812FD839E9008AAE68 /* MLSCore */, + 77AF68832FD839F3008AAE68 /* MLSDesignSystem */, ); productName = MLS; productReference = 087D3EE82DA7972C002F924D /* MLS.app */; @@ -578,6 +534,7 @@ 08F7AA022F86745C00EF5C06 /* MLSAuthFeature */, 08F7AA042F86745C00EF5C06 /* MLSAuthFeatureInterface */, 08F7AA062F86745C00EF5C06 /* MLSAuthFeatureTesting */, + 77947A332FD802FC0010E7E9 /* MLSAppFeatureInterface */, ); productName = MLSAuthFeatureExample; productReference = 08F7A9232F86745C00EF5C06 /* MLSAuthFeatureExample.app */; @@ -1824,14 +1781,6 @@ /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ - 085598AB2FB4A6B7003F315F /* MLSRecommendationFeature */ = { - isa = XCSwiftPackageProductDependency; - productName = MLSRecommendationFeature; - }; - 085598AD2FB4A6BD003F315F /* MLSRecommendationFeatureInterface */ = { - isa = XCSwiftPackageProductDependency; - productName = MLSRecommendationFeatureInterface; - }; 088636962FB4664E00006D4A /* MLSRecommendationFeatureTesting */ = { isa = XCSwiftPackageProductDependency; productName = MLSRecommendationFeatureTesting; @@ -1922,6 +1871,10 @@ package = 77660AD32DD0D3DD007A4EF3 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; productName = KakaoSDKUser; }; + 77947A332FD802FC0010E7E9 /* MLSAppFeatureInterface */ = { + isa = XCSwiftPackageProductDependency; + productName = MLSAppFeatureInterface; + }; 77AB59EC2FBE20FD00BAB8A3 /* MLSAuthFeatureTesting */ = { isa = XCSwiftPackageProductDependency; productName = MLSAuthFeatureTesting; @@ -1930,11 +1883,23 @@ isa = XCSwiftPackageProductDependency; productName = MLSMyPageFeatureTesting; }; + 77AF68812FD839E9008AAE68 /* MLSCore */ = { + isa = XCSwiftPackageProductDependency; + productName = MLSCore; + }; + 77AF68832FD839F3008AAE68 /* MLSDesignSystem */ = { + isa = XCSwiftPackageProductDependency; + productName = MLSDesignSystem; + }; 77B1F9942EE06A4E00AE4B4D /* RxGesture */ = { isa = XCSwiftPackageProductDependency; package = 77B1F9932EE06A4E00AE4B4D /* XCRemoteSwiftPackageReference "RxGesture" */; productName = RxGesture; }; + 77CEA6ED2FD70F2700E052BC /* MLSAppFeature */ = { + isa = XCSwiftPackageProductDependency; + productName = MLSAppFeature; + }; 77DE6DEE2F9F9EA1007FD8AC /* MLSAuthFeatureTesting */ = { isa = XCSwiftPackageProductDependency; productName = MLSAuthFeatureTesting; diff --git a/MLS/MLS.xcworkspace/contents.xcworkspacedata b/MLS/MLS.xcworkspace/contents.xcworkspacedata index 952c7c53..711ac7d4 100644 --- a/MLS/MLS.xcworkspace/contents.xcworkspacedata +++ b/MLS/MLS.xcworkspace/contents.xcworkspacedata @@ -4,51 +4,20 @@ - - - - - - - - - - - - - - - - - - - - + location = "group:MLSCore"> + location = "group:MLSDesignSystem"> + location = "group:MLSAppFeature"> + location = "group:MLSAuthFeature"> + location = "group:MLSBookmarkFeature"> @@ -57,6 +26,6 @@ location = "group:MLSMyPageFeature"> + location = "group:MLSRecommendationFeature"> diff --git a/MLS/MLS/Application/AppDelegate.swift b/MLS/MLS/Application/AppDelegate.swift index ed7678b5..3678ace6 100644 --- a/MLS/MLS/Application/AppDelegate.swift +++ b/MLS/MLS/Application/AppDelegate.swift @@ -1,31 +1,18 @@ -// swiftlint:disable function_body_length -// swiftlint:disable file_length - -import AuthFeature -import AuthFeatureInterface -import BaseFeature -import BookmarkFeature -import BookmarkFeatureInterface -import Core -import Data -import DataMock -import DesignSystem -import DictionaryFeature -import DictionaryFeatureInterface -import Domain -import DomainInterface -import Firebase -import KakaoSDKCommon -import MLSRecommendationFeature -import MLSRecommendationFeatureInterface -import MyPageFeature -import MyPageFeatureInterface import os import UIKit import UserNotifications +import MLSAppFeature +import MLSCore +import MLSDesignSystem + +import Firebase +import KakaoSDKCommon + @main class AppDelegate: UIResponder, UIApplicationDelegate { + private let applauncher = AppLauncher() + func application( _ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication @@ -39,13 +26,12 @@ class AppDelegate: UIResponder, UIApplicationDelegate { // MARK: - Modules Set ImageLoader.shared.configure.diskCacheCountLimit = 10 // ImageLoader FontManager.registerFonts() // FontManager + applauncher.register() // MARK: - KakaoSDK Set let kakaoNativeAppKey: String = Bundle.main.infoDictionary?["KAKAO_NATIVE_APP_KEY"] as? String ?? "" KakaoSDK.initSDK(appKey: kakaoNativeAppKey) - - registerDependencies() return true } @@ -84,1182 +70,11 @@ extension AppDelegate: UNUserNotificationCenterDelegate, MessagingDelegate { _ messaging: Messaging, didReceiveRegistrationToken fcmToken: String? ) { - let dataDict: [String: String] = ["token": fcmToken ?? ""] - NotificationCenter.default.post( - name: Notification.Name("FCMToken"), - object: nil, - userInfo: dataDict - ) + let tokenLauncher = TokenLauncher() guard let fcmToken = fcmToken else { os_log("FCM token is nil") return } - - let saveTokenUseCase = DIContainer.resolve(type: SaveTokenToLocalUseCase.self) - let saveResult = saveTokenUseCase.execute(type: .fcmToken, value: fcmToken) - - switch saveResult { - case .success: - os_log("fcmToken Save Success: \(fcmToken)") - case .failure: - os_log("fcmToken Save Failure") - } - - let fetchTokenUseCase = DIContainer.resolve(type: FetchTokenFromLocalUseCase.self) - let putFCMTokenUseCase = DIContainer.resolve(type: PutFCMTokenUseCase.self) - - if case .success(let accessToken) = fetchTokenUseCase.execute(type: .accessToken), - !accessToken.isEmpty { - _ = putFCMTokenUseCase.execute(fcmToken: fcmToken) - os_log("Request to update FCM token on server") - } else { - os_log("Not logged in yet, skipping FCM update to server") - } - } -} - -// MARK: - registerDependencies -private extension AppDelegate { - func registerDependencies() { - registerProvider() - registerRepository() - registerUseCase() - registerFactory() - - DIContainer.register(type: AppCoordinatorProtocol.self) { - AppCoordinator( - window: nil, - recommendationMainFactory: DIContainer.resolve( - type: RecommendationMainFactory.self - ), - dictionaryMainViewFactory: DIContainer.resolve( - type: DictionaryMainViewFactory.self - ), - bookmarkMainFactory: DIContainer.resolve( - type: BookmarkMainFactory.self - ), - myPageMainFactory: DIContainer.resolve( - type: MyPageMainFactory.self - ), - loginFactory: DIContainer.resolve(type: LoginFactory.self) - ) - } - } - - func registerProvider() { - DIContainer.register(type: NetworkProvider.self) { - NetworkProviderImpl() - } - DIContainer.register( - type: SocialAuthenticatableProvider.self, - name: "kakao" - ) { - KakaoLoginProviderImpl() - } - DIContainer.register( - type: SocialAuthenticatableProvider.self, - name: "apple" - ) { - AppleLoginProviderImpl() - } - DIContainer.register(type: Interceptor.self, name: "tokenInterceptor") { - TokenInterceptor( - fetchTokenUseCase: DIContainer.resolve( - type: FetchTokenFromLocalUseCase.self - ) - ) - } - - DIContainer.register(type: Interceptor.self, name: "authInterceptor") { - AuthInterceptor(tokenRepository: DIContainer.resolve(type: TokenRepository.self), authRepository: { DIContainer.resolve(type: AuthAPIRepository.self) }) - } - } - - func registerRepository() { - DIContainer.register(type: AuthAPIRepository.self) { - AuthAPIRepositoryImpl( - provider: DIContainer.resolve(type: NetworkProvider.self), - tokenInterceptor: DIContainer.resolve(type: Interceptor.self, name: "tokenInterceptor"), - authInterceptor: DIContainer.resolve(type: Interceptor.self, name: "authInterceptor") - ) - } - DIContainer.register(type: TokenRepository.self) { - KeyChainRepositoryImpl() - } - DIContainer.register(type: DictionaryDetailAPIRepository.self) { - DictionaryDetailAPIRepositoryImpl( - provider: DIContainer.resolve(type: NetworkProvider.self), - tokenInterceptor: DIContainer.resolve(type: Interceptor.self, name: "tokenInterceptor") - ) - } - DIContainer.register(type: DictionaryListAPIRepository.self) { - DictionaryListAPIRepositoryImpl( - provider: DIContainer.resolve(type: NetworkProvider.self), - tokenInterceptor: DIContainer.resolve(type: Interceptor.self, name: "tokenInterceptor") - ) - } - DIContainer.register(type: BookmarkRepository.self) { - BookmarkRepositoryImpl( - provider: DIContainer.resolve(type: NetworkProvider.self), - interceptor: DIContainer.resolve(type: Interceptor.self, name: "tokenInterceptor") - ) - } - DIContainer.register(type: UserDefaultsRepository.self) { - UserDefaultsRepositoryImpl() - } - DIContainer.register(type: AlarmAPIRepository.self) { - AlarmAPIRepositoryImpl( - provider: DIContainer.resolve(type: NetworkProvider.self), - interceptor: DIContainer.resolve(type: Interceptor.self, name: "tokenInterceptor") - ) - } - DIContainer.register(type: CollectionAPIRepository.self) { - CollectionAPIRepositoryImpl( - provider: DIContainer.resolve(type: NetworkProvider.self), - tokenInterceptor: DIContainer.resolve(type: Interceptor.self, name: "tokenInterceptor") - ) - } - DIContainer.register(type: RecommendationRepository.self) { - RecommendationRepositoryImpl() - } - } - - func registerUseCase() { - DIContainer.register( - type: FetchSocialCredentialUseCase.self, - name: "kakao" - ) { - let provider = DIContainer.resolve( - type: SocialAuthenticatableProvider.self, - name: "kakao" - ) - return SocialLoginUseCaseImpl(provider: provider) - } - DIContainer.register( - type: FetchSocialCredentialUseCase.self, - name: "apple" - ) { - let provider = DIContainer.resolve( - type: SocialAuthenticatableProvider.self, - name: "apple" - ) - return SocialLoginUseCaseImpl(provider: provider) - } - DIContainer.register(type: CheckEmptyLevelAndRoleUseCase.self) { - CheckEmptyLevelAndRoleUseCaseImpl() - } - DIContainer.register(type: CheckValidLevelUseCase.self) { - CheckValidLevelUseCaseImpl() - } - DIContainer.register(type: FetchJobListUseCase.self) { - FetchJobListUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self) - ) - } - DIContainer.register(type: LoginWithAppleUseCase.self) { - LoginWithAppleUseCaseImpl( - authRepository: DIContainer.resolve( - type: AuthAPIRepository.self - ), - tokenRepository: DIContainer.resolve( - type: TokenRepository.self - ), - userDefaultsRepository: DIContainer.resolve( - type: UserDefaultsRepository.self - ) - ) - } - DIContainer.register(type: LoginWithKakaoUseCase.self) { - LoginWithKakaoUseCaseImpl( - authRepository: DIContainer.resolve( - type: AuthAPIRepository.self - ), - tokenRepository: DIContainer.resolve( - type: TokenRepository.self - ), - userDefaultsRepository: DIContainer.resolve( - type: UserDefaultsRepository.self - ) - ) - } - DIContainer.register(type: SignUpWithAppleUseCase.self) { - SignUpWithAppleUseCaseImpl( - authRepository: DIContainer.resolve(type: AuthAPIRepository.self), - tokenRepository: DIContainer.resolve(type: TokenRepository.self), - userDefaultsRepository: DIContainer.resolve(type: UserDefaultsRepository.self) - ) - } - DIContainer.register(type: SignUpWithKakaoUseCase.self) { - SignUpWithKakaoUseCaseImpl( - authRepository: DIContainer.resolve(type: AuthAPIRepository.self), - tokenRepository: DIContainer.resolve(type: TokenRepository.self), - userDefaultsRepository: DIContainer.resolve(type: UserDefaultsRepository.self) - ) - } - DIContainer.register(type: UpdateUserInfoUseCase.self) { - UpdateUserInfoUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self) - ) - } - DIContainer.register(type: ReissueUseCase.self) { - ReissueUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self), tokenRepository: DIContainer.resolve(type: TokenRepository.self) - ) - } - DIContainer.register(type: PutFCMTokenUseCase.self) { - PutFCMTokenUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self) - ) - } - DIContainer.register(type: FetchTokenFromLocalUseCase.self) { - FetchTokenFromLocalUseCaseImpl( - repository: DIContainer.resolve(type: TokenRepository.self) - ) - } - DIContainer.register(type: SaveTokenToLocalUseCase.self) { - SaveTokenToLocalUseCaseImpl( - repository: DIContainer.resolve(type: TokenRepository.self) - ) - } - DIContainer.register(type: DeleteTokenFromLocalUseCase.self) { - DeleteTokenFromLocalUseCaseImpl( - repository: DIContainer.resolve(type: TokenRepository.self) - ) - } - DIContainer.register(type: UpdateMarketingAgreementUseCase.self) { - UpdateMarketingAgreementUseCaseImpl( - authRepository: DIContainer.resolve( - type: AuthAPIRepository.self - ), - tokenRepository: DIContainer.resolve(type: TokenRepository.self) - ) - } - DIContainer.register(type: CheckNotificationPermissionUseCase.self) { - CheckNotificationPermissionUseCaseImpl() - } - DIContainer.register(type: OpenNotificationSettingUseCase.self) { - OpenNotificationSettingUseCaseImpl() - } - DIContainer.register(type: UpdateNotificationAgreementUseCase.self) { - UpdateNotificationAgreementUseCaseImpl( - authRepository: DIContainer.resolve( - type: AuthAPIRepository.self - ) - ) - } - DIContainer.register(type: CheckLoginUseCase.self) { - CheckLoginUseCaseImpl( - authRepository: DIContainer.resolve( - type: AuthAPIRepository.self - ), - tokenRepository: DIContainer.resolve(type: TokenRepository.self) - ) - } - DIContainer.register(type: FetchDictionaryAllListUseCase.self) { - FetchDictionaryAllListUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryListAPIRepository.self - ) - ) - } - DIContainer.register(type: SetBookmarkUseCase.self) { - SetBookmarkUseCaseImpl( - repository: DIContainer.resolve(type: BookmarkRepository.self) - ) - } - DIContainer.register(type: FetchPlatformUseCase.self) { - FetchPlatformUseCaseImpl( - repository: DIContainer.resolve( - type: UserDefaultsRepository.self - ) - ) - } - DIContainer.register(type: FetchDictionaryMapListUseCase.self) { - FetchDictionaryMapListUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryListAPIRepository.self - ) - ) - } - DIContainer.register(type: FetchDictionaryItemListUseCase.self) { - FetchDictionaryItemListUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryListAPIRepository.self - ) - ) - } - DIContainer.register(type: FetchDictionaryQuestListUseCase.self) { - FetchDictionaryQuestListUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryListAPIRepository.self - ) - ) - } - DIContainer.register(type: FetchDictionaryNpcListUseCase.self) { - FetchDictionaryNpcListUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryListAPIRepository.self - ) - ) - } - DIContainer.register(type: FetchDictionaryMonsterListUseCase.self) { - FetchDictionaryMonsterListUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryListAPIRepository.self - ) - ) - } - DIContainer.register(type: FetchDictionaryDetailMonsterUseCase.self) { - FetchDictionaryDetailMonsterUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self - ) - ) - } - DIContainer.register( - type: FetchDictionaryDetailMonsterItemsUseCase.self - ) { - FetchDictionaryDetailMonsterDropItemUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self - ) - ) - } - DIContainer.register(type: FetchDictionaryDetailMonsterMapUseCase.self) { - FetchDictionaryDetailMonsterMapUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self - ) - ) - } - DIContainer.register(type: FetchDictionaryDetailNpcUseCase.self) { - FetchDictionaryDetailNpcUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self - ) - ) - } - DIContainer.register(type: FetchDictionaryDetailNpcQuestUseCase.self) { - FetchDictionaryDetailNpcQuestUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self - ) - ) - } - DIContainer.register(type: FetchDictionaryDetailNpcMapUseCase.self) { - FetchDictionaryDetailNpcMapUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self - ) - ) - } - DIContainer.register(type: FetchDictionaryDetailItemUseCase.self) { - FetchDictionaryDetailItemUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self - ) - ) - } - DIContainer.register( - type: FetchDictionaryDetailItemDropMonsterUseCase.self - ) { - FetchDictionaryDetailItemDropMonsterUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self - ) - ) - } - DIContainer.register(type: FetchDictionaryDetailQuestUseCase.self) { - FetchDictionaryDetailQuestUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self - ) - ) - } - DIContainer.register( - type: FetchDictionaryDetailQuestLinkedQuestsUseCase.self - ) { - FetchDictionaryDetailQuestLinkedQuestsUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self - ) - ) - } - DIContainer.register(type: FetchDictionaryDetailMapUseCase.self) { - FetchDictionaryDetailMapUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self - ) - ) - } - DIContainer.register( - type: FetchDictionaryDetailMapSpawnMonsterUseCase.self - ) { - FetchDictionaryDetailMapSpawnMonsterUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self - ) - ) - } - DIContainer.register(type: FetchDictionaryDetailMapNpcUseCase.self) { - FetchDictionaryDetailMapNpcUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryDetailAPIRepository.self - ) - ) - } - DIContainer.register(type: RecentSearchRemoveUseCase.self) { - RecentSearchRemoveUseCaseImpl( - repository: DIContainer.resolve( - type: UserDefaultsRepository.self - ) - ) - } - DIContainer.register(type: RecentSearchAddUseCase.self) { - RecentSearchAddUseCaseImpl( - repository: DIContainer.resolve( - type: UserDefaultsRepository.self - ) - ) - } - DIContainer.register(type: FetchDictionaryListCountUseCase.self) { - FetchDictionaryListCountUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryListAPIRepository.self - ) - ) - } - DIContainer.register(type: FetchDictionarySearchListUseCase.self) { - FetchDictionarySearchListUseCaseImpl( - repository: DIContainer.resolve( - type: DictionaryListAPIRepository.self - ) - ) - } - DIContainer.register(type: RecentSearchFetchUseCase.self) { - RecentSearchFetchUseCaseImpl( - repository: DIContainer.resolve( - type: UserDefaultsRepository.self - ) - ) - } - DIContainer.register(type: FetchBookmarkUseCase.self) { - FetchBookmarkUseCaseImpl( - repository: DIContainer.resolve(type: BookmarkRepository.self) - ) - } - DIContainer.register(type: FetchMonsterBookmarkUseCase.self) { - FetchMonsterBookmarkUseCaseImpl( - repository: DIContainer.resolve(type: BookmarkRepository.self) - ) - } - DIContainer.register(type: FetchItemBookmarkUseCase.self) { - FetchItemBookmarkUseCaseImpl( - repository: DIContainer.resolve(type: BookmarkRepository.self) - ) - } - DIContainer.register(type: FetchNPCBookmarkUseCase.self) { - FetchNPCBookmarkUseCaseImpl( - repository: DIContainer.resolve(type: BookmarkRepository.self) - ) - } - DIContainer.register(type: FetchQuestBookmarkUseCase.self) { - FetchQuestBookmarkUseCaseImpl( - repository: DIContainer.resolve(type: BookmarkRepository.self) - ) - } - DIContainer.register(type: FetchMapBookmarkUseCase.self) { - FetchMapBookmarkUseCaseImpl( - repository: DIContainer.resolve(type: BookmarkRepository.self) - ) - } - DIContainer.register(type: UpdateProfileImageUseCase.self) { - UpdateProfileImageUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self) - ) - } - DIContainer.register(type: FetchJobUseCase.self) { - FetchJobUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self) - ) - } - DIContainer.register(type: FetchProfileUseCase.self) { - FetchProfileUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self), - fetchJobUseCase: DIContainer.resolve(type: FetchJobUseCase.self) - ) - } - DIContainer.register(type: CheckNickNameUseCase.self) { - CheckNickNameUseCaseImpl() - } - DIContainer.register(type: UpdateNickNameUseCase.self) { - UpdateNickNameUseCaseImpl( - repository: DIContainer.resolve(type: AuthAPIRepository.self) - ) - } - DIContainer.register(type: LogoutUseCase.self) { - LogoutUseCaseImpl( - repository: DIContainer.resolve(type: TokenRepository.self) - ) - } - DIContainer.register(type: WithdrawUseCase.self) { - WithdrawUseCaseImpl( - authRepository: DIContainer.resolve( - type: AuthAPIRepository.self - ), - tokenRepository: DIContainer.resolve(type: TokenRepository.self) - ) - } - DIContainer.register(type: FetchNoticesUseCase.self) { - FetchNoticesUseCaseImpl( - repository: DIContainer.resolve(type: AlarmAPIRepository.self) - ) - } - DIContainer.register(type: FetchOngoingEventsUseCase.self) { - FetchOngoingEventsUseCaseImpl( - repository: DIContainer.resolve(type: AlarmAPIRepository.self) - ) - } - DIContainer.register(type: FetchOutdatedEventsUseCase.self) { - FetchOutdatedEventsUseCaseImpl( - repository: DIContainer.resolve(type: AlarmAPIRepository.self) - ) - } - DIContainer.register(type: FetchPatchNotesUseCase.self) { - FetchPatchNotesUseCaseImpl( - repository: DIContainer.resolve(type: AlarmAPIRepository.self) - ) - } - DIContainer.register(type: SetReadUseCase.self) { - SetReadUseCaseImpl( - repository: DIContainer.resolve(type: AlarmAPIRepository.self) - ) - } - DIContainer.register(type: FetchAllAlarmUseCase.self) { - FetchAllAlarmUseCaseImpl( - repository: DIContainer.resolve(type: AlarmAPIRepository.self) - ) - } - DIContainer.register(type: ParseItemFilterResultUseCase.self) { - ParseItemFilterResultUseCaseImpl() - } - DIContainer.register(type: FetchCollectionListUseCase.self) { - FetchCollectionListUseCaseImpl( - repository: DIContainer.resolve( - type: CollectionAPIRepository.self - ) - ) - } - DIContainer.register(type: CreateCollectionListUseCase.self) { - CreateCollectionListUseCaseImpl( - repository: DIContainer.resolve( - type: CollectionAPIRepository.self - ) - ) - } - DIContainer.register(type: FetchCollectionUseCase.self) { - FetchCollectionUseCaseImpl( - repository: DIContainer.resolve( - type: CollectionAPIRepository.self - ) - ) - } - DIContainer.register(type: UpdateCollectionUseCase.self) { - UpdateCollectionUseCaseImpl( - repository: DIContainer.resolve( - type: CollectionAPIRepository.self - ) - ) - } - DIContainer.register(type: DeleteCollectionUseCase.self) { - DeleteCollectionUseCaseImpl( - repository: DIContainer.resolve( - type: CollectionAPIRepository.self - ) - ) - } - DIContainer.register(type: AddCollectionAndBookmarkUseCase.self) { - AddCollectionAndBookmarkUseCaseImpl( - repository: DIContainer.resolve( - type: CollectionAPIRepository.self - ) - ) - } - DIContainer.register(type: FetchVisitBookmarkUseCase.self) { - FetchVisitBookmarkUseCaseImpl( - repository: DIContainer.resolve( - type: UserDefaultsRepository.self - ) - ) - } - DIContainer.register(type: FetchVisitDictionaryDetailUseCase.self) { - FetchVisitDictionaryDetailUseCaseImpl(repository: DIContainer.resolve(type: UserDefaultsRepository.self)) - } - } - - func registerFactory() { - DIContainer.register(type: ItemFilterBottomSheetFactory.self) { - ItemFilterBottomSheetFactoryImpl() - } - DIContainer.register(type: MonsterFilterBottomSheetFactory.self) { - MonsterFilterBottomSheetFactoryImpl() - } - DIContainer.register(type: SortedBottomSheetFactory.self) { - SortedBottomSheetFactoryImpl() - } - DIContainer.register(type: AddCollectionFactory.self) { - AddCollectionFactoryImpl( - createCollectionListUseCase: DIContainer.resolve( - type: CreateCollectionListUseCase.self - ), - setCollectionUseCase: DIContainer.resolve( - type: UpdateCollectionUseCase.self - ) - ) - } - DIContainer.register(type: BookmarkModalFactory.self) { - BookmarkModalFactoryImpl( - addCollectionFactory: DIContainer.resolve( - type: AddCollectionFactory.self - ), - fetchCollectionListUseCase: DIContainer.resolve( - type: FetchCollectionListUseCase.self - ), - addCollectionAndBookmarkUseCase: DIContainer.resolve( - type: AddCollectionAndBookmarkUseCase.self - ) - ) - } - DIContainer.register(type: LoginFactory.self) { - LoginFactoryImpl( - termsAgreementsFactory: DIContainer.resolve( - type: TermsAgreementFactory.self - ), - appleLoginUseCase: DIContainer.resolve( - type: FetchSocialCredentialUseCase.self, - name: "apple" - ), - kakaoLoginUseCase: DIContainer.resolve( - type: FetchSocialCredentialUseCase.self, - name: "kakao" - ), - loginWithAppleUseCase: DIContainer.resolve( - type: LoginWithAppleUseCase.self - ), - loginWithKakaoUseCase: DIContainer.resolve( - type: LoginWithKakaoUseCase.self - ), - fetchTokenUseCase: DIContainer.resolve( - type: FetchTokenFromLocalUseCase.self - ), - putFCMTokenUseCase: DIContainer.resolve( - type: PutFCMTokenUseCase.self - ), - fetchPlatformUseCase: DIContainer.resolve( - type: FetchPlatformUseCase.self - ) - ) - } - DIContainer.register(type: DictionaryDetailFactory.self) { - DictionaryDetailFactoryImpl( - loginFactory: { DIContainer.resolve(type: LoginFactory.self) }, - bookmarkModalFactory: DIContainer.resolve( - type: BookmarkModalFactory.self - ), - dictionaryDetailFactory: { - DIContainer - .resolve(type: DictionaryDetailFactory.self) - }, - detailOnBoardingFactory: DIContainer.resolve( - type: DetailOnBoardingFactory.self - ), - appCoordinator: { - DIContainer.resolve(type: AppCoordinatorProtocol.self) - }, - dictionaryDetailMapUseCase: DIContainer.resolve( - type: FetchDictionaryDetailMapUseCase.self - ), - dictionaryDetailMapSpawnMonsterUseCase: DIContainer.resolve( - type: FetchDictionaryDetailMapSpawnMonsterUseCase.self - ), - dictionaryDetailMapNpcUseCase: DIContainer.resolve( - type: FetchDictionaryDetailMapNpcUseCase.self - ), - dictionaryDetailQuestLinkedQuestsUseCase: DIContainer.resolve( - type: FetchDictionaryDetailQuestLinkedQuestsUseCase.self - ), - dictionaryDetailQuestUseCase: DIContainer.resolve( - type: FetchDictionaryDetailQuestUseCase.self - ), - dictionaryDetailItemDropMonsterUseCase: DIContainer.resolve( - type: FetchDictionaryDetailItemDropMonsterUseCase.self - ), - dictionaryDetailItemUseCase: DIContainer.resolve( - type: FetchDictionaryDetailItemUseCase.self - ), - dictionaryDetailNpcUseCase: DIContainer.resolve( - type: FetchDictionaryDetailNpcUseCase.self - ), - dictionaryDetailNpcQuestUseCase: DIContainer.resolve( - type: FetchDictionaryDetailNpcQuestUseCase.self - ), - dictionaryDetailNpcMapUseCase: DIContainer.resolve( - type: FetchDictionaryDetailNpcMapUseCase.self - ), - dictionaryDetailMonsterUseCase: DIContainer.resolve( - type: FetchDictionaryDetailMonsterUseCase.self - ), - dictionaryDetailMonsterDropItemUseCase: DIContainer.resolve( - type: FetchDictionaryDetailMonsterItemsUseCase.self - ), - dictionaryDetailMonsterMapUseCase: DIContainer.resolve( - type: FetchDictionaryDetailMonsterMapUseCase.self - ), - checkLoginUseCase: DIContainer.resolve( - type: CheckLoginUseCase.self - ), - setBookmarkUseCase: DIContainer.resolve( - type: SetBookmarkUseCase.self - ), - fetchVisitDictionaryDetailUseCase: DIContainer.resolve( - type: FetchVisitDictionaryDetailUseCase.self - ) - ) - } - DIContainer.register(type: DictionaryMainListFactory.self) { - DictionaryListFactoryImpl( - checkLoginUseCase: DIContainer.resolve( - type: CheckLoginUseCase.self - ), - dictionaryAllListItemUseCase: DIContainer.resolve( - type: FetchDictionaryAllListUseCase.self - ), - dictionaryMapListItemUseCase: DIContainer.resolve( - type: FetchDictionaryMapListUseCase.self - ), - dictionaryItemListItemUseCase: DIContainer.resolve( - type: FetchDictionaryItemListUseCase.self - ), - dictionaryQuestListItemUseCase: DIContainer.resolve( - type: FetchDictionaryQuestListUseCase.self - ), - dictionaryNpcListItemUseCase: - DIContainer - .resolve(type: FetchDictionaryNpcListUseCase.self), - dictionaryListItemUseCase: DIContainer.resolve( - type: FetchDictionaryMonsterListUseCase.self - ), - setBookmarkUseCase: DIContainer.resolve( - type: SetBookmarkUseCase.self - ), - parseItemFilterResultUseCase: DIContainer.resolve( - type: ParseItemFilterResultUseCase.self - ), - itemFilterFactory: DIContainer.resolve( - type: ItemFilterBottomSheetFactory.self - ), - monsterFilterFactory: DIContainer.resolve( - type: MonsterFilterBottomSheetFactory.self - ), - sortedFactory: DIContainer.resolve( - type: SortedBottomSheetFactory.self - ), - bookmarkModalFactory: DIContainer.resolve( - type: BookmarkModalFactory.self - ), - detailFactory: DIContainer.resolve( - type: DictionaryDetailFactory.self - ), - loginFactory: { DIContainer.resolve(type: LoginFactory.self) } - ) - } - DIContainer.register(type: DictionarySearchResultFactory.self) { - DictionarySearchResultFactoryImpl( - dictionaryListCountUseCase: DIContainer.resolve( - type: FetchDictionaryListCountUseCase.self - ), - dictionaryMainListFactory: - DIContainer - .resolve(type: DictionaryMainListFactory.self), - dictionarySearchListUseCase: DIContainer.resolve( - type: FetchDictionarySearchListUseCase.self - ), recentSearchAddUseCase: DIContainer.resolve( - type: RecentSearchAddUseCase.self) - ) - } - DIContainer.register(type: DictionarySearchFactory.self) { - DictionarySearchFactoryImpl( - recentSearchRemoveUseCase: DIContainer.resolve( - type: RecentSearchRemoveUseCase.self - ), - recentSearchAddUseCase: DIContainer.resolve( - type: RecentSearchAddUseCase.self - ), - searchResultFactory: - DIContainer - .resolve(type: DictionarySearchResultFactory.self), - recentSearchFetchUseCase: DIContainer.resolve( - type: RecentSearchFetchUseCase.self - ) - ) - } - DIContainer.register(type: NotificationSettingFactory.self) { - NotificationSettingFactoryImpl( - checkNotificationPermissionUseCase: DIContainer.resolve( - type: CheckNotificationPermissionUseCase.self - ), - updateNotificationAgreementUseCase: DIContainer.resolve( - type: UpdateNotificationAgreementUseCase.self - ) - ) - } - DIContainer.register(type: DictionaryNotificationFactory.self) { - DictionaryNotificationFactoryImpl( - notificationSettingFactory: DIContainer.resolve( - type: NotificationSettingFactory.self - ), - fetchAllAlarmUseCase: DIContainer.resolve( - type: FetchAllAlarmUseCase.self - ), - fetchProfileUseCase: DIContainer.resolve( - type: FetchProfileUseCase.self - ), checkNotificationPermissionUseCase: DIContainer.resolve(type: CheckNotificationPermissionUseCase.self), - setReadUseCase: DIContainer.resolve( - type: SetReadUseCase.self) - ) - } - DIContainer.register(type: DictionaryMainViewFactory.self) { - DictionaryMainViewFactoryImpl( - dictionaryMainListFactory: DIContainer.resolve( - type: DictionaryMainListFactory.self - ), - searchFactory: DIContainer.resolve( - type: DictionarySearchFactory.self - ), - notificationFactory: DIContainer.resolve( - type: DictionaryNotificationFactory.self - ), - loginFactory: DIContainer.resolve(type: LoginFactory.self), - fetchProfileUseCase: DIContainer.resolve( - type: FetchProfileUseCase.self - ) - ) - } - DIContainer.register(type: OnBoardingNotificationSheetFactory.self) { - OnBoardingNotificationSheetFactoryImpl( - checkNotificationPermissionUseCase: - DIContainer - .resolve(type: CheckNotificationPermissionUseCase.self), - openNotificationSettingUseCase: - DIContainer - .resolve(type: OpenNotificationSettingUseCase.self), - updateNotificationAgreementUseCase: - DIContainer - .resolve(type: UpdateNotificationAgreementUseCase.self), - updateUserInfoUseCase: DIContainer.resolve( - type: UpdateUserInfoUseCase.self - ), - appCoordinator: { - DIContainer.resolve( - type: AppCoordinatorProtocol.self - ) - } - ) - } - DIContainer.register(type: OnBoardingInputFactory.self) { - OnBoardingInputFactoryImpl( - checkEmptyUseCase: DIContainer.resolve( - type: CheckEmptyLevelAndRoleUseCase.self - ), - checkValidLevelUseCase: DIContainer.resolve( - type: CheckValidLevelUseCase.self - ), - fetchJobListUseCase: DIContainer.resolve( - type: FetchJobListUseCase.self - ), - updateUserInfoUseCase: DIContainer.resolve( - type: UpdateUserInfoUseCase.self - ), - onBoardingNotificationFactory: DIContainer.resolve( - type: OnBoardingNotificationFactory.self - ), - appCoordinator: { - DIContainer.resolve(type: AppCoordinatorProtocol.self) - } - ) - } - DIContainer.register(type: OnBoardingQuestionFactory.self) { - OnBoardingQuestionFactoryImpl( - onBoardingInputFactory: DIContainer.resolve( - type: OnBoardingInputFactory.self - ) - ) - } - DIContainer.register(type: TermsAgreementFactory.self) { - TermsAgreementFactoryImpl( - onBoardingQuestionFactory: DIContainer.resolve( - type: OnBoardingQuestionFactory.self - ), - signUpWithKakaoUseCase: DIContainer.resolve( - type: SignUpWithKakaoUseCase.self - ), - signUpWithAppleUseCase: DIContainer.resolve( - type: SignUpWithAppleUseCase.self - ), - fetchTokenUseCase: DIContainer.resolve( - type: FetchTokenFromLocalUseCase.self - ), - updateMarketingAgreementUseCase: DIContainer.resolve( - type: UpdateMarketingAgreementUseCase.self - ) - ) - } - DIContainer.register(type: OnBoardingNotificationFactory.self) { - OnBoardingNotificationFactoryImpl( - onBoardingNotificationSheetFactory: DIContainer.resolve( - type: OnBoardingNotificationSheetFactory.self - ), - appCoordinator: { - DIContainer.resolve( - type: AppCoordinatorProtocol.self - ) - } - ) - } - DIContainer.register(type: BookmarkMainFactory.self) { - BookmarkMainFactoryImpl( - setBookmarkUseCase: - DIContainer - .resolve(type: SetBookmarkUseCase.self), - checkLoginUseCase: - DIContainer - .resolve(type: CheckLoginUseCase.self), - fetchVisitBookmarkUseCase: - DIContainer - .resolve(type: FetchVisitBookmarkUseCase.self), - onBoardingFactory: - DIContainer - .resolve(type: BookmarkOnBoardingFactory.self), - bookmarkListFactory: - DIContainer - .resolve(type: BookmarkListFactory.self), - collectionListFactory: - DIContainer - .resolve(type: CollectionListFactory.self), - searchFactory: - DIContainer - .resolve(type: DictionarySearchFactory.self), - notificationFactory: DIContainer.resolve( - type: DictionaryNotificationFactory.self - ), - loginFactory: DIContainer.resolve(type: LoginFactory.self) - ) - } - DIContainer.register(type: BookmarkOnBoardingFactory.self) { - BookmarkOnBoardingFactoryImpl() - } - DIContainer.register(type: BookmarkListFactory.self) { - BookmarkListFactoryImpl( - itemFilterFactory: DIContainer.resolve( - type: ItemFilterBottomSheetFactory.self - ), - monsterFilterFactory: DIContainer.resolve( - type: MonsterFilterBottomSheetFactory.self - ), - sortedFactory: DIContainer.resolve( - type: SortedBottomSheetFactory.self - ), - bookmarkModalFactory: DIContainer.resolve( - type: BookmarkModalFactory.self - ), - loginFactory: DIContainer.resolve(type: LoginFactory.self), - dictionaryDetailFactory: DIContainer.resolve( - type: DictionaryDetailFactory.self - ), - collectionEditFactory: DIContainer.resolve( - type: CollectionEditFactory.self - ), - setBookmarkUseCase: DIContainer.resolve( - type: SetBookmarkUseCase.self - ), - fetchProfileUseCase: DIContainer.resolve( - type: FetchProfileUseCase.self - ), - fetchBookmarkUseCase: DIContainer.resolve( - type: FetchBookmarkUseCase.self - ), - fetchMonsterBookmarkUseCase: DIContainer.resolve( - type: FetchMonsterBookmarkUseCase.self - ), - fetchItemBookmarkUseCase: DIContainer.resolve( - type: FetchItemBookmarkUseCase.self - ), - fetchNPCBookmarkUseCase: DIContainer.resolve( - type: FetchNPCBookmarkUseCase.self - ), - fetchQuestBookmarkUseCase: DIContainer.resolve( - type: FetchQuestBookmarkUseCase.self - ), - fetchMapBookmarkUseCase: DIContainer.resolve( - type: FetchMapBookmarkUseCase.self - ), - parseItemFilterResultUseCase: DIContainer.resolve( - type: ParseItemFilterResultUseCase.self - ) - ) - } - DIContainer.register(type: CollectionListFactory.self) { - CollectionListFactoryImpl( - fetchCollectionListUseCase: DIContainer.resolve( - type: FetchCollectionListUseCase.self - ), - addCollectionFactory: DIContainer.resolve( - type: AddCollectionFactory.self - ), - bookmarkDetailFactory: DIContainer.resolve( - type: CollectionDetailFactory.self - ), - sortedBottomSheetFactory: - DIContainer - .resolve(type: SortedBottomSheetFactory.self) - ) - } - DIContainer.register(type: CollectionDetailFactory.self) { - CollectionDetailFactoryImpl( - bookmarkModalFactory: - DIContainer - .resolve(type: BookmarkModalFactory.self), - collectionSettingFactory: - DIContainer - .resolve(type: CollectionSettingFactory.self), - addCollectionFactory: - DIContainer - .resolve(type: AddCollectionFactory.self), - collectionEditFactory: - DIContainer - .resolve(type: CollectionEditFactory.self), - dictionaryDetailFactory: - DIContainer - .resolve(type: DictionaryDetailFactory.self), - setBookmarkUseCase: - DIContainer - .resolve(type: SetBookmarkUseCase.self), - fetchCollectionUseCase: DIContainer.resolve( - type: FetchCollectionUseCase.self - ), - deleteCollectionUseCase: - DIContainer - .resolve(type: DeleteCollectionUseCase.self), - addCollectionAndBookmarkUseCase: DIContainer.resolve( - type: AddCollectionAndBookmarkUseCase.self - ) - ) - } - DIContainer.register(type: CollectionSettingFactory.self) { - CollectionSettingFactoryImpl() - } - DIContainer.register(type: CollectionEditFactory.self) { - CollectionEditFactoryImpl( - setBookmarkUseCase: DIContainer.resolve( - type: SetBookmarkUseCase.self - ), - bookmarkModalFactory: DIContainer.resolve( - type: BookmarkModalFactory.self - ) - ) - } - DIContainer.register(type: MyPageMainFactory.self) { - MyPageMainFactoryImpl( - loginFactory: DIContainer.resolve(type: LoginFactory.self), - setProfileFactory: - DIContainer - .resolve(type: SetProfileFactory.self), - customerSupportFactory: - DIContainer - .resolve(type: CustomerSupportFactory.self), - notificationSettingFactory: - DIContainer - .resolve(type: NotificationSettingFactory.self), - setCharacterFactory: - DIContainer - .resolve(type: SetCharacterFactory.self), - fetchProfileUseCase: DIContainer.resolve( - type: FetchProfileUseCase.self - ) - ) - } - DIContainer.register(type: CustomerSupportFactory.self) { - CustomerSupportBaseViewFactoryImpl( - policyFactory: DIContainer.resolve( - type: PolicyFactory.self), - fetchNoticesUseCase: DIContainer.resolve( - type: FetchNoticesUseCase.self - ), - fetchOngoingEventsUseCase: DIContainer.resolve( - type: FetchOngoingEventsUseCase.self - ), - fetchOutdatedEventsUseCase: DIContainer.resolve( - type: FetchOutdatedEventsUseCase.self - ), - fetchPatchNotesUseCase: DIContainer.resolve( - type: FetchPatchNotesUseCase.self - ), - setReadUseCase: DIContainer.resolve(type: SetReadUseCase.self) - ) - } - DIContainer.register(type: SetProfileFactory.self) { - SetProfileFactoryImpl( - selectImageFactory: DIContainer.resolve( - type: SelectImageFactory.self - ), - checkNickNameUseCase: DIContainer.resolve( - type: CheckNickNameUseCase.self - ), - updateNickNameUseCase: DIContainer.resolve( - type: UpdateNickNameUseCase.self - ), - logoutUseCase: DIContainer.resolve(type: LogoutUseCase.self), - withdrawUseCase: DIContainer.resolve( - type: WithdrawUseCase.self - ), - fetchProfileUseCase: DIContainer.resolve( - type: FetchProfileUseCase.self - ) - ) - } - DIContainer.register(type: SetCharacterFactory.self) { - SetCharacterFactoryImpl( - checkEmptyUseCase: - DIContainer - .resolve(type: CheckEmptyLevelAndRoleUseCase.self), - checkValidLevelUseCase: - DIContainer - .resolve(type: CheckValidLevelUseCase.self), - fetchJobListUseCase: - DIContainer - .resolve(type: FetchJobListUseCase.self), - updateUserInfoUseCase: - DIContainer - .resolve(type: UpdateUserInfoUseCase.self) - ) - } - DIContainer.register(type: SelectImageFactory.self) { - SelectImageFactoryImpl( - updateProfileImageUseCase: DIContainer.resolve( - type: UpdateProfileImageUseCase.self - ) - ) - } - DIContainer.register(type: DetailOnBoardingFactory.self) { - DetailOnBoardingFactoryImpl() - } - DIContainer.register(type: PolicyFactory.self) { - PolicyFactoryImpl() - } - DIContainer.register(type: RecommendationMainFactory.self) { - RecommendationMainFactoryImpl( - repository: DIContainer.resolve(type: RecommendationRepository.self) - ) - } + tokenLauncher.didReceiveFCMToken(fcmToken) } } diff --git a/MLS/MLS/Application/SceneDelegate.swift b/MLS/MLS/Application/SceneDelegate.swift index cf82223f..9b510fad 100644 --- a/MLS/MLS/Application/SceneDelegate.swift +++ b/MLS/MLS/Application/SceneDelegate.swift @@ -1,20 +1,13 @@ import UIKit -import AuthFeatureInterface -import BaseFeature -import BookmarkFeatureInterface -import Core -import DictionaryFeatureInterface -import DomainInterface -import MyPageFeatureInterface +import MLSAppFeature import KakaoSDKAuth import RxSwift final class SceneDelegate: UIResponder, UIWindowSceneDelegate { var window: UIWindow? - var appCoordinator: AppCoordinatorProtocol? - var disposeBag = DisposeBag() + private let launcher = AppLauncher() func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } @@ -22,12 +15,7 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { let window = UIWindow(windowScene: windowScene) window.makeKeyAndVisible() self.window = window - - let coordinator = DIContainer.resolve(type: AppCoordinatorProtocol.self) - coordinator.window = window - appCoordinator = coordinator - - startScene(coordinator: coordinator) + launcher.launch(window: window) } func scene(_ scene: UIScene, openURLContexts URLContexts: Set) { @@ -37,32 +25,4 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate { } } } - - private func startScene(coordinator: AppCoordinatorProtocol) { - let fetchTokenUseCase = DIContainer.resolve(type: FetchTokenFromLocalUseCase.self) - let reissueUseCase = DIContainer.resolve(type: ReissueUseCase.self) - - let fetchResult = fetchTokenUseCase.execute(type: .refreshToken) - - switch fetchResult { - case .success(let refreshToken): - #if DEBUG - print("refreshToken: \(refreshToken)") - #endif - reissueUseCase.execute(refreshToken: refreshToken) - .observe(on: MainScheduler.instance) - .subscribe( - onNext: { _ in - coordinator.showMainTab() - }, - onError: { _ in - coordinator.showLogin(exitRoute: .home) - } - ) - .disposed(by: disposeBag) - - case .failure: - coordinator.showLogin(exitRoute: .home) - } - } } diff --git a/MLS/MLSAppFeature/Package.swift b/MLS/MLSAppFeature/Package.swift index 895561cb..0f4711aa 100644 --- a/MLS/MLSAppFeature/Package.swift +++ b/MLS/MLSAppFeature/Package.swift @@ -23,6 +23,16 @@ let package = Package( targets: ["MLSAppFeatureTesting"] ) ], + dependencies: [ + .package(path: "../MLSAppFeature"), + .package(path: "../MLSAuthFeature"), + .package(path: "../MLSBookmarkFeature"), + .package(path: "../MLSCore"), + .package(path: "../MLSDictionaryFeature"), + .package(path: "../MLSMyPageFeature"), + .package(path: "../MLSRecommendationFeature"), + .package(url: "https://github.com/ReactiveX/RxSwift.git", from: "6.7.0") + ], targets: [ // Interface 모듈 (도메인 모델 및 프로토콜) .target( @@ -32,7 +42,22 @@ let package = Package( // Feature 모듈 (실제 구현) .target( name: "MLSAppFeature", - dependencies: ["MLSAppFeatureInterface"] + dependencies: [ + "MLSAppFeatureInterface", + .product(name: "MLSAuthFeature", package: "MLSAuthFeature"), + .product(name: "MLSAppFeatureInterface", package: "MLSAppFeature"), + .product(name: "MLSAuthFeatureInterface", package: "MLSAuthFeature"), + .product(name: "MLSBookmarkFeature", package: "MLSBookmarkFeature"), + .product(name: "MLSBookmarkFeatureInterface", package: "MLSBookmarkFeature"), + .product(name: "MLSCore", package: "MLSCore"), + .product(name: "MLSDictionaryFeature", package: "MLSDictionaryFeature"), + .product(name: "MLSDictionaryFeatureInterface", package: "MLSDictionaryFeature"), + .product(name: "MLSMyPageFeature", package: "MLSMyPageFeature"), + .product(name: "MLSMyPageFeatureInterface", package: "MLSMyPageFeature"), + .product(name: "MLSRecommendationFeature", package: "MLSRecommendationFeature"), + .product(name: "MLSRecommendationFeatureInterface", package: "MLSRecommendationFeature"), + .product(name: "RxSwift", package: "RxSwift") + ] ), // Testing 모듈 (Mock 객체) .target( diff --git a/MLS/MLS/Application/AppCoordinator.swift b/MLS/MLSAppFeature/Sources/MLSAppFeature/Coordinator/AppCoordinator.swift similarity index 87% rename from MLS/MLS/Application/AppCoordinator.swift rename to MLS/MLSAppFeature/Sources/MLSAppFeature/Coordinator/AppCoordinator.swift index 03f1764b..023293cb 100644 --- a/MLS/MLS/Application/AppCoordinator.swift +++ b/MLS/MLSAppFeature/Sources/MLSAppFeature/Coordinator/AppCoordinator.swift @@ -1,16 +1,18 @@ import UIKit -import AuthFeature -import AuthFeatureInterface -import BaseFeature -import BookmarkFeatureInterface -import DesignSystem -import DictionaryFeatureInterface +import MLSAppFeatureInterface +import MLSAuthFeature +import MLSAuthFeatureInterface +import MLSBookmarkFeatureInterface +import MLSCore +import MLSDesignSystem +import MLSDictionaryFeatureInterface +import MLSMyPageFeatureInterface import MLSRecommendationFeatureInterface -import MyPageFeatureInterface import RxSwift +@MainActor public final class AppCoordinator: AppCoordinatorProtocol { // MARK: - Properties public var window: UIWindow? @@ -43,15 +45,15 @@ public final class AppCoordinator: AppCoordinatorProtocol { public func showMainTab() { let tabItems: [TabItem] = [ TabItem(title: "추천", icon: UIImage(systemName: "star.fill") ?? UIImage()), - TabItem(title: "도감", icon: DesignSystemAsset.image(named: "dictionary") ?? UIImage()), - TabItem(title: "북마크", icon: DesignSystemAsset.image(named: "bookmarkList") ?? UIImage()), - TabItem(title: "MY", icon: DesignSystemAsset.image(named: "mypage") ?? UIImage()) + TabItem(title: "도감", icon: DesignSystemAsset.image(named: "dictionary")), + TabItem(title: "북마크", icon: DesignSystemAsset.image(named: "bookmarkList")), + TabItem(title: "MY", icon: DesignSystemAsset.image(named: "mypage")) ] let tabBar = BottomTabBarController( viewControllers: [ recommendationMainFactory.make(), dictionaryMainViewFactory.make(), - bookmarkMainFactory.make(), + bookmarkMainFactory.make(bottomInset: 64), myPageMainFactory.make() ], tabItems: tabItems diff --git a/MLS/MLSAppFeature/Sources/MLSAppFeature/Dependency/DependencyAssembler.swift b/MLS/MLSAppFeature/Sources/MLSAppFeature/Dependency/DependencyAssembler.swift new file mode 100644 index 00000000..289073ed --- /dev/null +++ b/MLS/MLSAppFeature/Sources/MLSAppFeature/Dependency/DependencyAssembler.swift @@ -0,0 +1,40 @@ +import UIKit + +import MLSAppFeatureInterface +import MLSAuthFeatureInterface +import MLSBookmarkFeatureInterface +import MLSCore +import MLSDictionaryFeatureInterface +import MLSMyPageFeatureInterface +import MLSRecommendationFeatureInterface + +public enum DependencyAssembler { + public static func register() { + ProviderAssembly.register() + RepositoryAssembly.register() + UseCaseAssembly.register() + FactoryAssembly.register() + } + + @MainActor + public static func launch(window: UIWindow?) { + DIContainer.register(type: AppCoordinatorProtocol.self) { + AppCoordinator( + window: window, + recommendationMainFactory: DIContainer.resolve( + type: RecommendationMainFactory.self + ), + dictionaryMainViewFactory: DIContainer.resolve( + type: DictionaryMainViewFactory.self + ), + bookmarkMainFactory: DIContainer.resolve( + type: BookmarkMainFactory.self + ), + myPageMainFactory: DIContainer.resolve( + type: MyPageMainFactory.self + ), + loginFactory: DIContainer.resolve(type: LoginFactory.self) + ) + } + } +} diff --git a/MLS/MLSAppFeature/Sources/MLSAppFeature/Dependency/FactoryAssembly.swift b/MLS/MLSAppFeature/Sources/MLSAppFeature/Dependency/FactoryAssembly.swift new file mode 100644 index 00000000..8f1ef38e --- /dev/null +++ b/MLS/MLSAppFeature/Sources/MLSAppFeature/Dependency/FactoryAssembly.swift @@ -0,0 +1,441 @@ +// swiftlint:disable type_body_length +// swiftlint:disable function_body_length + +import MLSAppFeatureInterface +import MLSAuthFeature +import MLSAuthFeatureInterface +import MLSBookmarkFeature +import MLSBookmarkFeatureInterface +import MLSCore +import MLSDictionaryFeature +import MLSDictionaryFeatureInterface +import MLSMyPageFeature +import MLSMyPageFeatureInterface +import MLSRecommendationFeature +import MLSRecommendationFeatureInterface + +public enum FactoryAssembly { + public static func register() { + DIContainer.register(type: ItemFilterBottomSheetFactory.self) { + ItemFilterBottomSheetFactoryImpl() + } + DIContainer.register(type: MonsterFilterBottomSheetFactory.self) { + MonsterFilterBottomSheetFactoryImpl() + } + DIContainer.register(type: SortedBottomSheetFactory.self) { + SortedBottomSheetFactoryImpl() + } + DIContainer.register(type: AddCollectionFactory.self) { + AddCollectionFactoryImpl( + collectionRepository: DIContainer.resolve( + type: CollectionRepository.self + ) + ) + } + DIContainer.register(type: BookmarkModalFactory.self) { + BookmarkModalFactoryImpl( + addCollectionFactory: DIContainer.resolve( + type: AddCollectionFactory.self + ), + collectionRepository: DIContainer.resolve( + type: CollectionRepository.self + ) + ) + } + DIContainer.register(type: LoginFactory.self) { + LoginFactoryImpl( + termsAgreementsFactory: DIContainer.resolve( + type: TermsAgreementFactory.self + ), + appleProvider: DIContainer.resolve( + type: SocialCredentialProvider.self, name: "apple" + ), + kakaoProvider: DIContainer.resolve( + type: SocialCredentialProvider.self, name: "kakao" + ), + socialLoginUseCase: DIContainer.resolve( + type: SocialLoginUseCase.self + ), + userDefaultsRepository: DIContainer.resolve( + type: UserDefaultsRepository.self, name: "authUserDefaultsRepository" + ) + ) + } + DIContainer.register(type: DictionaryDetailFactory.self) { + DictionaryDetailFactoryImpl( + loginFactory: { + DIContainer.resolve(type: LoginFactory.self) + }, + bookmarkModalFactory: DIContainer.resolve( + type: BookmarkModalFactory.self + ), + detailOnBoardingFactory: DIContainer.resolve( + type: DetailOnBoardingFactory.self + ), + appCoordinator: { + DIContainer.resolve(type: AppCoordinator.self) + }, + dictionaryDetailAPIRepository: DIContainer.resolve( + type: DictionaryDetailAPIRepository.self + ), + bookmarkRepository: DIContainer + .resolve(type: BookmarkRepository.self), + checkLoginUseCase: DIContainer.resolve( + type: CheckLoginUseCase.self + ), + fetchVisitDictionaryDetailUseCase: DIContainer.resolve( + type: FetchVisitDictionaryDetailUseCase.self + ) + ) + } + DIContainer.register(type: DictionaryMainListFactory.self) { + DictionaryListFactoryImpl( + checkLoginUseCase: DIContainer.resolve( + type: CheckLoginUseCase.self + ), + bookmarkRepository: DIContainer.resolve( + type: BookmarkRepository.self + ), + parseItemFilterResultUseCase: DIContainer.resolve( + type: ParseItemFilterResultUseCase.self + ), + dictionaryListAPIRepository: DIContainer.resolve( + type: DictionaryListAPIRepository.self + ), + itemFilterFactory: DIContainer.resolve( + type: ItemFilterBottomSheetFactory.self + ), + monsterFilterFactory: DIContainer.resolve( + type: MonsterFilterBottomSheetFactory.self + ), + sortedFactory: DIContainer.resolve( + type: SortedBottomSheetFactory.self + ), + bookmarkModalFactory: DIContainer.resolve( + type: BookmarkModalFactory.self + ), + detailFactory: DIContainer.resolve( + type: DictionaryDetailFactory.self + ) + ) { + DIContainer.resolve(type: LoginFactory.self) + } + } + DIContainer.register(type: DictionarySearchResultFactory.self) { + DictionarySearchResultFactoryImpl( + dictionaryListAPIRepository: DIContainer.resolve( + type: DictionaryListAPIRepository.self + ), + recentSearchRepository: DIContainer.resolve( + type: RecentSearchRepository.self + ), + dictionaryMainListFactory: DIContainer.resolve( + type: DictionaryMainListFactory.self + ) + ) + } + DIContainer.register(type: DictionarySearchFactory.self) { + DictionarySearchFactoryImpl( + recentSearchRepository: + DIContainer + .resolve(type: RecentSearchRepository.self), + searchResultFactory: + DIContainer + .resolve(type: DictionarySearchResultFactory.self) + ) + } + DIContainer.register(type: NotificationSettingFactory.self) { + NotificationSettingFactoryImpl( + notificationRepository: DIContainer.resolve( + type: NotificationPermissionRepository.self + ), + authRepository: DIContainer.resolve( + type: AuthAPIRepository.self + ) + ) + } + DIContainer.register(type: DictionaryNotificationFactory.self) { + DictionaryNotificationFactoryImpl( + notificationSettingFactory: + DIContainer + .resolve( + type: NotificationSettingFactory.self + ), + fetchProfileUseCase: + DIContainer + .resolve(type: FetchProfileUseCase.self), + checkNotificationPermissionUseCase: + DIContainer + .resolve(type: CheckNotificationPermissionUseCase.self), + alarmRepository: + DIContainer + .resolve(type: AlarmRepository.self) + ) + } + DIContainer.register(type: DictionaryMainViewFactory.self) { + DictionaryMainViewFactoryImpl( + dictionaryMainListFactory: DIContainer.resolve( + type: DictionaryMainListFactory.self + ), + searchFactory: DIContainer.resolve( + type: DictionarySearchFactory.self + ), + notificationFactory: DIContainer.resolve( + type: DictionaryNotificationFactory.self + ), + loginFactory: DIContainer.resolve(type: LoginFactory.self), + fetchProfileUseCase: DIContainer.resolve( + type: FetchProfileUseCase.self + ) + ) + } + DIContainer.register(type: OnBoardingNotificationSheetFactory.self) { + OnBoardingNotificationSheetFactoryImpl( + authRepository: DIContainer.resolve( + type: AuthAPIRepository.self + ), + appCoordinator: { + DIContainer.resolve( + type: AppCoordinatorProtocol.self + ) + } + ) + } + DIContainer.register(type: OnBoardingInputFactory.self) { + OnBoardingInputFactoryImpl( + checkEmptyUseCase: DIContainer.resolve( + type: CheckEmptyLevelAndRoleUseCase.self + ), + checkValidLevelUseCase: DIContainer.resolve( + type: CheckValidLevelUseCase.self + ), + authRepository: + DIContainer + .resolve(type: AuthAPIRepository.self), + onBoardingNotificationFactory: DIContainer.resolve( + type: OnBoardingNotificationFactory.self + ), + appCoordinator: { + DIContainer.resolve(type: AppCoordinatorProtocol.self) + } + ) + } + DIContainer.register(type: OnBoardingQuestionFactory.self) { + OnBoardingQuestionFactoryImpl( + onBoardingInputFactory: DIContainer.resolve( + type: OnBoardingInputFactory.self + ) + ) + } + DIContainer.register(type: TermsAgreementFactory.self) { + TermsAgreementFactoryImpl( + onBoardingQuestionFactory: DIContainer.resolve( + type: OnBoardingQuestionFactory.self + ), + socialSignUpUseCase: + DIContainer + .resolve(type: SocialSignUpUseCase.self), + tokenRepository: + DIContainer + .resolve(type: TokenRepository.self) + ) + } + DIContainer.register(type: OnBoardingNotificationFactory.self) { + OnBoardingNotificationFactoryImpl( + onBoardingNotificationSheetFactory: DIContainer.resolve( + type: OnBoardingNotificationSheetFactory.self + ), + appCoordinator: { + DIContainer.resolve( + type: AppCoordinatorProtocol.self + ) + } + ) + } + DIContainer.register(type: BookmarkMainFactory.self) { + BookmarkMainFactoryImpl( + authRepository: + DIContainer + .resolve(type: BookmarkAuthRepository.self), + userDefaultsRepository: + DIContainer + .resolve(type: BookmarkUserDefaultsRepository.self), + onBoardingFactory: + DIContainer + .resolve(type: BookmarkOnBoardingFactory.self), + bookmarkListFactory: + DIContainer + .resolve(type: BookmarkListFactory.self), + collectionListFactory: + DIContainer + .resolve(type: CollectionListFactory.self), + searchFactory: + DIContainer + .resolve(type: DictionarySearchFactory.self), + notificationFactory: DIContainer.resolve( + type: DictionaryNotificationFactory.self + ), + loginFactory: DIContainer.resolve(type: LoginFactory.self) + ) + } + DIContainer.register(type: BookmarkOnBoardingFactory.self) { + BookmarkOnBoardingFactoryImpl() + } + DIContainer.register(type: BookmarkListFactory.self) { + BookmarkListFactoryImpl( + itemFilterFactory: DIContainer.resolve( + type: ItemFilterBottomSheetFactory.self + ), + monsterFilterFactory: DIContainer.resolve( + type: MonsterFilterBottomSheetFactory.self + ), + sortedFactory: DIContainer.resolve( + type: SortedBottomSheetFactory.self + ), + bookmarkModalFactory: DIContainer.resolve( + type: BookmarkModalFactory.self + ), + loginFactory: DIContainer.resolve(type: LoginFactory.self), + dictionaryDetailFactory: DIContainer.resolve( + type: DictionaryDetailFactory.self + ), + collectionEditFactory: DIContainer.resolve( + type: CollectionEditFactory.self + ), + authRepository: DIContainer + .resolve(type: BookmarkAuthRepository.self), + bookmarkRepository: DIContainer + .resolve(type: BookmarkRepository.self), + parseItemFilterResultUseCase: DIContainer.resolve( + type: ParseItemFilterResultUseCase.self + ) + ) + } + DIContainer.register(type: CollectionListFactory.self) { + CollectionListFactoryImpl( + collectionRepository: DIContainer.resolve( + type: CollectionRepository.self + ), + addCollectionFactory: DIContainer.resolve( + type: AddCollectionFactory.self + ), + collectionDetailFactory: DIContainer + .resolve(type: CollectionDetailFactory.self), + sortedBottomSheetFactory: + DIContainer + .resolve(type: SortedBottomSheetFactory.self) + ) + } + DIContainer.register(type: CollectionDetailFactory.self) { + CollectionDetailFactoryImpl( + bookmarkModalFactory: + DIContainer + .resolve(type: BookmarkModalFactory.self), + collectionSettingFactory: + DIContainer + .resolve(type: CollectionSettingFactory.self), + addCollectionFactory: + DIContainer + .resolve(type: AddCollectionFactory.self), + collectionEditFactory: + DIContainer + .resolve(type: CollectionEditFactory.self), + dictionaryDetailFactory: + DIContainer + .resolve(type: DictionaryDetailFactory.self), + collectionRepository: DIContainer + .resolve(type: CollectionRepository.self) + ) + } + DIContainer.register(type: CollectionSettingFactory.self) { + CollectionSettingFactoryImpl() + } + DIContainer.register(type: CollectionEditFactory.self) { + CollectionEditFactoryImpl( + bookmarkModalFactory: DIContainer.resolve( + type: BookmarkModalFactory.self + ) + ) + } + DIContainer.register(type: MyPageMainFactory.self) { + MyPageMainFactoryImpl( + loginFactory: DIContainer.resolve(type: LoginFactory.self), + setProfileFactory: + DIContainer + .resolve(type: SetProfileFactory.self), + customerSupportFactory: + DIContainer + .resolve(type: CustomerSupportFactory.self), + notificationSettingFactory: + DIContainer + .resolve(type: NotificationSettingFactory.self), + setCharacterFactory: + DIContainer + .resolve(type: SetCharacterFactory.self), + fetchProfileUseCase: DIContainer.resolve( + type: FetchProfileUseCase.self + ) + ) + } + DIContainer.register(type: CustomerSupportFactory.self) { + CustomerSupportBaseViewFactoryImpl( + policyFactory: DIContainer.resolve( + type: PolicyFactory.self + ), + alarmRepository: DIContainer.resolve( + type: AlarmRepository.self + ) + ) + } + DIContainer.register(type: SetProfileFactory.self) { + SetProfileFactoryImpl( + selectImageFactory: DIContainer.resolve( + type: SelectImageFactory.self + ), + checkNickNameUseCase: DIContainer.resolve( + type: CheckNickNameUseCase.self + ), + logoutUseCase: DIContainer.resolve(type: LogoutUseCase.self), + withdrawUseCase: DIContainer.resolve( + type: WithdrawUseCase.self + ), + fetchProfileUseCase: DIContainer.resolve( + type: FetchProfileUseCase.self + ), + myPageRepository: DIContainer + .resolve(type: MyPageRepository.self) + ) + } + DIContainer.register(type: SetCharacterFactory.self) { + SetCharacterFactoryImpl( + checkEmptyUseCase: + DIContainer + .resolve(type: CheckEmptyLevelAndRoleUseCase.self), + checkValidLevelUseCase: + DIContainer + .resolve(type: CheckValidLevelUseCase.self), + authRepository: DIContainer + .resolve(type: AuthAPIRepository.self) + ) + } + DIContainer.register(type: SelectImageFactory.self) { + SelectImageFactoryImpl( + myPageRepository: DIContainer + .resolve(type: MyPageRepository.self) + ) + } + DIContainer.register(type: DetailOnBoardingFactory.self) { + DetailOnBoardingFactoryImpl() + } + DIContainer.register(type: PolicyFactory.self) { + PolicyFactoryImpl() + } + DIContainer.register(type: RecommendationMainFactory.self) { + RecommendationMainFactoryImpl( + repository: DIContainer.resolve( + type: RecommendationRepository.self + ) + ) + } + } +} diff --git a/MLS/MLSAppFeature/Sources/MLSAppFeature/Dependency/ProviderAssembly.swift b/MLS/MLSAppFeature/Sources/MLSAppFeature/Dependency/ProviderAssembly.swift new file mode 100644 index 00000000..3f5afac6 --- /dev/null +++ b/MLS/MLSAppFeature/Sources/MLSAppFeature/Dependency/ProviderAssembly.swift @@ -0,0 +1,30 @@ +import MLSAuthFeature +import MLSAuthFeatureInterface +import MLSCore + +public enum ProviderAssembly { + public static func register() { + DIContainer.register(type: NetworkProvider.self) { + NetworkProviderImpl() + } + DIContainer.register( + type: SocialCredentialProvider.self, + name: "kakao" + ) { + KakaoCredentialProvider() + } + DIContainer.register( + type: SocialCredentialProvider.self, + name: "apple" + ) { + AppleCredentialProvider() + } + DIContainer.register(type: Interceptor.self, name: "tokenInterceptor") { + TokenInterceptor() + } + + DIContainer.register(type: Interceptor.self, name: "authInterceptor") { + AuthInterceptor(tokenRepository: DIContainer.resolve(type: TokenRepository.self), authRepository: { DIContainer.resolve(type: AuthAPIRepository.self) }) + } + } +} diff --git a/MLS/MLSAppFeature/Sources/MLSAppFeature/Dependency/RepositoryAssembly.swift b/MLS/MLSAppFeature/Sources/MLSAppFeature/Dependency/RepositoryAssembly.swift new file mode 100644 index 00000000..ac64a654 --- /dev/null +++ b/MLS/MLSAppFeature/Sources/MLSAppFeature/Dependency/RepositoryAssembly.swift @@ -0,0 +1,84 @@ +import MLSAuthFeature +import MLSAuthFeatureInterface +import MLSBookmarkFeature +import MLSBookmarkFeatureInterface +import MLSCore +import MLSDictionaryFeature +import MLSDictionaryFeatureInterface +import MLSMyPageFeature +import MLSMyPageFeatureInterface +import MLSRecommendationFeature +import MLSRecommendationFeatureInterface + +public enum RepositoryAssembly { + public static func register() { + DIContainer.register(type: TokenRepository.self) { + KeyChainRepositoryImpl() + } + DIContainer.register(type: AuthAPIRepository.self) { + AuthAPIRepositoryImpl( + provider: DIContainer.resolve(type: NetworkProvider.self), + tokenInterceptor: DIContainer.resolve(type: Interceptor.self, name: "tokenInterceptor"), + authInterceptor: DIContainer.resolve(type: Interceptor.self, name: "authInterceptor") + ) + } + DIContainer.register(type: DictionaryDetailAPIRepository.self) { + DictionaryDetailAPIRepositoryImpl( + provider: DIContainer.resolve(type: NetworkProvider.self), + tokenInterceptor: DIContainer.resolve(type: Interceptor.self, name: "tokenInterceptor") + ) + } + DIContainer.register(type: DictionaryListAPIRepository.self) { + DictionaryListAPIRepositoryImpl( + provider: DIContainer.resolve(type: NetworkProvider.self), + tokenInterceptor: DIContainer.resolve(type: Interceptor.self, name: "tokenInterceptor") + ) + } + DIContainer.register(type: BookmarkRepository.self) { + BookmarkRepositoryImpl() + } + DIContainer.register(type: MLSAuthFeatureInterface.UserDefaultsRepository.self, name: "authUserDefaultsRepository") { + MLSAuthFeature.UserDefaultsRepositoryImpl() + } + DIContainer.register(type: MLSDictionaryFeatureInterface.UserDefaultsRepository.self, name: "dictionaryUserDefaultsRepository") { + MLSDictionaryFeature.UserDefaultsRepositoryImpl() + } + DIContainer.register(type: AlarmRepository.self) { + AlarmRepositoryImpl( + provider: DIContainer.resolve(type: NetworkProvider.self), + interceptor: DIContainer + .resolve(type: Interceptor.self, name: "tokenInterceptor") + ) + } + DIContainer.register(type: CollectionRepository.self) { + CollectionRepositoryImpl() + } + DIContainer.register(type: RecommendationRepository.self) { + RecommendationRepositoryImpl() + } + DIContainer.register(type: RecentSearchRepository.self) { + RecentSearchRepositoryImpl() + } + DIContainer.register(type: NotificationPermissionRepository.self) { + NotificationPermissionRepositoryImpl() + } + DIContainer.register(type: MyPageRepository.self) { + MyPageRepositoryImpl( + provider: DIContainer.resolve(type: NetworkProvider.self), + interceptor: DIContainer + .resolve(type: Interceptor.self, name: "tokenInterceptor") + ) + } + DIContainer.register(type: BookmarkAuthRepository.self) { + BookmarkAuthRepositoryImpl( + tokenRepository: DIContainer + .resolve(type: TokenRepository.self), + authAPIRepository: DIContainer + .resolve(type: AuthAPIRepository.self) + ) + } + DIContainer.register(type: BookmarkUserDefaultsRepository.self) { + BookmarkUserDefaultsRepositoryImpl() + } + } +} diff --git a/MLS/MLSAppFeature/Sources/MLSAppFeature/Dependency/UseCaseAssembly.swift b/MLS/MLSAppFeature/Sources/MLSAppFeature/Dependency/UseCaseAssembly.swift new file mode 100644 index 00000000..f7f52fd8 --- /dev/null +++ b/MLS/MLSAppFeature/Sources/MLSAppFeature/Dependency/UseCaseAssembly.swift @@ -0,0 +1,86 @@ +import MLSAuthFeature +import MLSAuthFeatureInterface +import MLSCore +import MLSDictionaryFeature +import MLSDictionaryFeatureInterface +import MLSMyPageFeature +import MLSMyPageFeatureInterface + +public enum UseCaseAssembly { + public static func register() { + DIContainer.register(type: CheckEmptyLevelAndRoleUseCase.self) { + CheckEmptyLevelAndRoleUseCaseImpl() + } + DIContainer.register(type: CheckValidLevelUseCase.self) { + CheckValidLevelUseCaseImpl() + } + DIContainer.register(type: SocialLoginUseCase.self) { + SocialLoginUseCaseImpl( + authRepository: DIContainer.resolve( + type: AuthAPIRepository.self + ), + tokenRepository: DIContainer.resolve( + type: TokenRepository.self + ), + userDefaultsRepository: DIContainer.resolve( + type: UserDefaultsRepository.self, name: "authUserDefaultsRepository" + ) + ) + } + DIContainer.register(type: SocialSignUpUseCaseImpl.self) { + SocialSignUpUseCaseImpl( + authRepository: DIContainer.resolve(type: AuthAPIRepository.self), + tokenRepository: DIContainer.resolve(type: TokenRepository.self), + userDefaultsRepository: DIContainer.resolve(type: UserDefaultsRepository.self, name: "authUserDefaultsRepository") + ) + } + DIContainer.register(type: CheckNotificationPermissionUseCase.self) { + CheckNotificationPermissionUseCaseImpl() + } + DIContainer.register(type: CheckLoginUseCase.self) { + CheckLoginUseCaseImpl( + authRepository: DIContainer.resolve( + type: AuthAPIRepository.self + ), + tokenRepository: DIContainer.resolve(type: TokenRepository.self) + ) + } + DIContainer.register(type: FetchProfileUseCase.self) { + FetchProfileUseCaseImpl( + repository: DIContainer.resolve(type: MyPageRepository.self) + ) + } + DIContainer.register(type: CheckNickNameUseCase.self) { + CheckNickNameUseCaseImpl() + } + DIContainer.register(type: LogoutUseCase.self) { + LogoutUseCaseImpl( + repository: DIContainer.resolve(type: TokenRepository.self) + ) + } + DIContainer.register(type: WithdrawUseCase.self) { + WithdrawUseCaseImpl( + authRepository: DIContainer.resolve( + type: AuthAPIRepository.self + ), + tokenRepository: DIContainer.resolve(type: TokenRepository.self) + ) + } + DIContainer.register(type: ParseItemFilterResultUseCase.self) { + ParseItemFilterResultUseCaseImpl() + } + DIContainer.register(type: FetchVisitDictionaryDetailUseCase.self) { + FetchVisitDictionaryDetailUseCaseImpl(repository: DIContainer.resolve(type: UserDefaultsRepository.self, name: "dictionaryUserDefaultsRepository")) + } + DIContainer.register(type: SocialSignUpUseCase.self) { + SocialSignUpUseCaseImpl( + authRepository: DIContainer + .resolve(type: AuthAPIRepository.self), + tokenRepository: DIContainer + .resolve(type: TokenRepository.self), + userDefaultsRepository: DIContainer + .resolve(type: UserDefaultsRepository.self, name: "authUserDefaultsRepository") + ) + } + } +} diff --git a/MLS/MLSAppFeature/Sources/MLSAppFeature/Launcher/AppLauncher.swift b/MLS/MLSAppFeature/Sources/MLSAppFeature/Launcher/AppLauncher.swift new file mode 100644 index 00000000..e6d8c598 --- /dev/null +++ b/MLS/MLSAppFeature/Sources/MLSAppFeature/Launcher/AppLauncher.swift @@ -0,0 +1,53 @@ +import UIKit + +import MLSAppFeatureInterface +import MLSAuthFeatureInterface +import MLSCore + +import RxSwift + +@MainActor +public final class AppLauncher { + private let disposeBag = DisposeBag() + + public init() {} + + public func launch(window: UIWindow?) { + DependencyAssembler.launch(window: window) + + let tokenRepository = DIContainer.resolve(type: TokenRepository.self) + let authRepository = DIContainer.resolve(type: AuthAPIRepository.self) + + switch tokenRepository.fetchToken(type: .refreshToken) { + case .success(let refreshToken): + #if DEBUG + print("refreshToken: \(refreshToken)") + #endif + authRepository.reissueToken(refreshToken: refreshToken) + .observe(on: MainScheduler.instance) + .subscribe( + onNext: { _ in + Task { @MainActor in + let coordinator = DIContainer.resolve(type: AppCoordinatorProtocol.self) + coordinator.showMainTab() + } + }, + onError: { _ in + Task { @MainActor in + let coordinator = DIContainer.resolve(type: AppCoordinatorProtocol.self) + coordinator.showLogin(exitRoute: .home) + } + } + ) + .disposed(by: disposeBag) + + case .failure: + let coordinator = DIContainer.resolve(type: AppCoordinatorProtocol.self) + coordinator.showLogin(exitRoute: .home) + } + } + + public func register() { + DependencyAssembler.register() + } +} diff --git a/MLS/MLSAppFeature/Sources/MLSAppFeature/Launcher/TokenLauncher.swift b/MLS/MLSAppFeature/Sources/MLSAppFeature/Launcher/TokenLauncher.swift new file mode 100644 index 00000000..4af69946 --- /dev/null +++ b/MLS/MLSAppFeature/Sources/MLSAppFeature/Launcher/TokenLauncher.swift @@ -0,0 +1,50 @@ +import Foundation +import os + +import MLSAuthFeatureInterface +import MLSCore + +public final class TokenLauncher { + private let tokenRepository: TokenRepository + + public init(tokenRepository: TokenRepository = DIContainer.resolve(type: TokenRepository.self)) { + self.tokenRepository = tokenRepository + } + + public func didReceiveFCMToken(_ token: String) { + let dataDict: [String: String] = [ + "token": token + ] + + NotificationCenter.default.post( + name: Notification.Name("FCMToken"), + object: nil, + userInfo: dataDict + ) + + let saveResult = tokenRepository.saveToken( + type: .fcmToken, + value: token + ) + + switch saveResult { + case .success: + os_log("fcmToken Save Success: \(token)") + case .failure: + os_log("fcmToken Save Failure") + } + + if case .success(let accessToken) = + tokenRepository.fetchToken(type: .accessToken), + !accessToken.isEmpty { + _ = tokenRepository.saveToken( + type: .fcmToken, + value: token + ) + + os_log("Request to update FCM token on server") + } else { + os_log("Not logged in yet, skipping FCM update to server") + } + } +} diff --git a/MLS/MLSAuthFeature/Sources/MLSAuthFeatureInterface/AppCoordinatorProtocol.swift b/MLS/MLSAppFeature/Sources/MLSAppFeatureInterface/Domain/Navigation/AppCoordinatorProtocol.swift similarity index 94% rename from MLS/MLSAuthFeature/Sources/MLSAuthFeatureInterface/AppCoordinatorProtocol.swift rename to MLS/MLSAppFeature/Sources/MLSAppFeatureInterface/Domain/Navigation/AppCoordinatorProtocol.swift index 24f9b2ca..94bf5903 100644 --- a/MLS/MLSAuthFeature/Sources/MLSAuthFeatureInterface/AppCoordinatorProtocol.swift +++ b/MLS/MLSAppFeature/Sources/MLSAppFeatureInterface/Domain/Navigation/AppCoordinatorProtocol.swift @@ -1,5 +1,6 @@ import UIKit +@MainActor public protocol AppCoordinatorProtocol: AnyObject { var window: UIWindow? { get set } func showMainTab() diff --git a/MLS/MLSCore/Sources/MLSCore/Navigation/DictionaryTabControllable.swift b/MLS/MLSAppFeature/Sources/MLSAppFeatureInterface/Domain/Navigation/DictionaryTabControllable.swift similarity index 100% rename from MLS/MLSCore/Sources/MLSCore/Navigation/DictionaryTabControllable.swift rename to MLS/MLSAppFeature/Sources/MLSAppFeatureInterface/Domain/Navigation/DictionaryTabControllable.swift diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/DictionaryTabRegistry.swift b/MLS/MLSAppFeature/Sources/MLSAppFeatureInterface/Domain/Navigation/DictionaryTabRegistry.swift similarity index 96% rename from MLS/Presentation/BaseFeature/BaseFeature/Utills/DictionaryTabRegistry.swift rename to MLS/MLSAppFeature/Sources/MLSAppFeatureInterface/Domain/Navigation/DictionaryTabRegistry.swift index 467443c7..e3fef082 100644 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/DictionaryTabRegistry.swift +++ b/MLS/MLSAppFeature/Sources/MLSAppFeatureInterface/Domain/Navigation/DictionaryTabRegistry.swift @@ -1,3 +1,4 @@ +@MainActor public enum DictionaryTabRegistry { private static weak var controller: DictionaryTabControllable? diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Interface/LoginExitRoute.swift b/MLS/MLSAppFeature/Sources/MLSAppFeatureInterface/Domain/Navigation/LoginExitRoute.swift similarity index 100% rename from MLS/Presentation/BaseFeature/BaseFeature/Interface/LoginExitRoute.swift rename to MLS/MLSAppFeature/Sources/MLSAppFeatureInterface/Domain/Navigation/LoginExitRoute.swift diff --git a/MLS/MLSAuthFeature/Package.swift b/MLS/MLSAuthFeature/Package.swift index 1e1db184..f08b56b4 100644 --- a/MLS/MLSAuthFeature/Package.swift +++ b/MLS/MLSAuthFeature/Package.swift @@ -22,6 +22,7 @@ let package = Package( ) ], dependencies: [ + .package(path: "../MLSAppFeature"), .package(path: "../MLSCore"), .package(path: "../MLSDesignSystem"), .package(url: "https://github.com/ReactorKit/ReactorKit.git", from: "3.2.0"), @@ -35,6 +36,7 @@ let package = Package( .target( name: "MLSAuthFeatureInterface", dependencies: [ + .product(name: "MLSAppFeatureInterface", package: "MLSAppFeature"), .product(name: "MLSCore", package: "MLSCore"), .product(name: "MLSDesignSystem", package: "MLSDesignSystem"), .product(name: "RxSwift", package: "RxSwift") @@ -46,6 +48,7 @@ let package = Package( name: "MLSAuthFeature", dependencies: [ "MLSAuthFeatureInterface", + .product(name: "MLSAppFeatureInterface", package: "MLSAppFeature"), .product(name: "MLSCore", package: "MLSCore"), .product(name: "MLSDesignSystem", package: "MLSDesignSystem"), .product(name: "ReactorKit", package: "ReactorKit"), diff --git a/MLS/Domain/Domain/Interceptor/AuthInterceptor.swift b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/AuthInterceptor.swift similarity index 97% rename from MLS/Domain/Domain/Interceptor/AuthInterceptor.swift rename to MLS/MLSAuthFeature/Sources/MLSAuthFeature/AuthInterceptor.swift index 26ce211a..8a9c5e66 100644 --- a/MLS/Domain/Domain/Interceptor/AuthInterceptor.swift +++ b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/AuthInterceptor.swift @@ -1,6 +1,7 @@ import Foundation -import DomainInterface +import MLSAuthFeatureInterface +import MLSCore public final class AuthInterceptor: Interceptor { private let tokenRepository: TokenRepository diff --git a/MLS/Data/Data/Repository/KeyChainRepositoryImpl.swift b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Data/Repositories/KeyChainRepositoryImpl.swift similarity index 99% rename from MLS/Data/Data/Repository/KeyChainRepositoryImpl.swift rename to MLS/MLSAuthFeature/Sources/MLSAuthFeature/Data/Repositories/KeyChainRepositoryImpl.swift index 287a8ec7..1e190abe 100644 --- a/MLS/Data/Data/Repository/KeyChainRepositoryImpl.swift +++ b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Data/Repositories/KeyChainRepositoryImpl.swift @@ -2,7 +2,7 @@ import Foundation import os import Security -import DomainInterface +import MLSAuthFeatureInterface import RxSwift diff --git a/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Data/Repositories/UserDefaultsRepositoryImpl.swift b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Data/Repositories/UserDefaultsRepositoryImpl.swift new file mode 100644 index 00000000..5c771f2c --- /dev/null +++ b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Data/Repositories/UserDefaultsRepositoryImpl.swift @@ -0,0 +1,32 @@ +import Foundation + +import MLSAuthFeatureInterface + +import RxSwift + +public final class UserDefaultsRepositoryImpl: UserDefaultsRepository { + private let platformKey = "platformKey" + + public init() {} + + public func fetchPlatform() -> Observable { + return Observable.create { observer in + if let rawValue = UserDefaults.standard.string(forKey: self.platformKey), + let platform = LoginPlatform(rawValue: rawValue) { + observer.onNext(platform) + } else { + observer.onNext(nil) + } + observer.onCompleted() + return Disposables.create() + } + } + + public func savePlatform(platform: LoginPlatform) -> Completable { + return Completable.create { completable in + UserDefaults.standard.set(platform.rawValue, forKey: self.platformKey) + completable(.completed) + return Disposables.create() + } + } +} diff --git a/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/Login/LoginFactoryImpl.swift b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/Login/LoginFactoryImpl.swift index 29d87721..5975d198 100644 --- a/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/Login/LoginFactoryImpl.swift +++ b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/Login/LoginFactoryImpl.swift @@ -1,3 +1,4 @@ +import MLSAppFeatureInterface import MLSAuthFeatureInterface import MLSCore diff --git a/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingInput/OnBoardingInputFactoryImpl.swift b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingInput/OnBoardingInputFactoryImpl.swift index e1e04104..ad1da9f3 100644 --- a/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingInput/OnBoardingInputFactoryImpl.swift +++ b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingInput/OnBoardingInputFactoryImpl.swift @@ -1,3 +1,4 @@ +import MLSAppFeatureInterface import MLSAuthFeatureInterface import MLSCore diff --git a/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingInput/OnBoardingInputViewController.swift b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingInput/OnBoardingInputViewController.swift index 0a2feebb..0608e966 100644 --- a/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingInput/OnBoardingInputViewController.swift +++ b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingInput/OnBoardingInputViewController.swift @@ -1,5 +1,6 @@ import UIKit +import MLSAppFeatureInterface import MLSAuthFeatureInterface import MLSCore import MLSDesignSystem diff --git a/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingNotification/OnBoardingNotificationFactoryImpl.swift b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingNotification/OnBoardingNotificationFactoryImpl.swift index bddcc1aa..bc846e0e 100644 --- a/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingNotification/OnBoardingNotificationFactoryImpl.swift +++ b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingNotification/OnBoardingNotificationFactoryImpl.swift @@ -1,3 +1,4 @@ +import MLSAppFeatureInterface import MLSAuthFeatureInterface import MLSCore diff --git a/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingNotification/OnBoardingNotificationViewController.swift b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingNotification/OnBoardingNotificationViewController.swift index 027544fd..f0f71c92 100644 --- a/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingNotification/OnBoardingNotificationViewController.swift +++ b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingNotification/OnBoardingNotificationViewController.swift @@ -1,6 +1,7 @@ import UIKit import UserNotifications +import MLSAppFeatureInterface import MLSAuthFeatureInterface import MLSCore diff --git a/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingNotificationSheet/OnBoardingNotificationSheetFactoryImpl.swift b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingNotificationSheet/OnBoardingNotificationSheetFactoryImpl.swift index 886ebcc4..81465827 100644 --- a/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingNotificationSheet/OnBoardingNotificationSheetFactoryImpl.swift +++ b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingNotificationSheet/OnBoardingNotificationSheetFactoryImpl.swift @@ -1,3 +1,4 @@ +import MLSAppFeatureInterface import MLSAuthFeatureInterface import MLSCore import MLSDesignSystem diff --git a/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingNotificationSheet/OnBoardingNotificationSheetViewController.swift b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingNotificationSheet/OnBoardingNotificationSheetViewController.swift index 971d5098..d7279549 100644 --- a/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingNotificationSheet/OnBoardingNotificationSheetViewController.swift +++ b/MLS/MLSAuthFeature/Sources/MLSAuthFeature/Presentation/OnBoardingNotificationSheet/OnBoardingNotificationSheetViewController.swift @@ -1,5 +1,6 @@ import UIKit +import MLSAppFeatureInterface import MLSAuthFeatureInterface import MLSCore import MLSDesignSystem diff --git a/MLS/MLSAuthFeature/Sources/MLSAuthFeatureInterface/Entities/LoginExitRoute.swift b/MLS/MLSAuthFeature/Sources/MLSAuthFeatureInterface/Entities/LoginExitRoute.swift deleted file mode 100644 index 597ae3e7..00000000 --- a/MLS/MLSAuthFeature/Sources/MLSAuthFeatureInterface/Entities/LoginExitRoute.swift +++ /dev/null @@ -1,4 +0,0 @@ -public enum LoginExitRoute { - case home - case pop -} diff --git a/MLS/MLSAuthFeature/Sources/MLSAuthFeatureInterface/Factories/LoginFactory.swift b/MLS/MLSAuthFeature/Sources/MLSAuthFeatureInterface/Factories/LoginFactory.swift index a7a7cd36..fc5095a0 100644 --- a/MLS/MLSAuthFeature/Sources/MLSAuthFeatureInterface/Factories/LoginFactory.swift +++ b/MLS/MLSAuthFeature/Sources/MLSAuthFeatureInterface/Factories/LoginFactory.swift @@ -1,3 +1,4 @@ +import MLSAppFeatureInterface import MLSCore public protocol LoginFactory { diff --git a/MLS/MLSAuthFeatureExample/SceneDelegate.swift b/MLS/MLSAuthFeatureExample/SceneDelegate.swift index 0e253ecd..5a1752c3 100644 --- a/MLS/MLSAuthFeatureExample/SceneDelegate.swift +++ b/MLS/MLSAuthFeatureExample/SceneDelegate.swift @@ -1,5 +1,6 @@ import UIKit +import MLSAppFeatureInterface import MLSAuthFeature import MLSAuthFeatureInterface import MLSAuthFeatureTesting diff --git a/MLS/MLSBookmarkFeature/Package.swift b/MLS/MLSBookmarkFeature/Package.swift index dda4b20d..884b025b 100644 --- a/MLS/MLSBookmarkFeature/Package.swift +++ b/MLS/MLSBookmarkFeature/Package.swift @@ -19,9 +19,11 @@ let package = Package( ) ], dependencies: [ + .package(path: "../MLSAppFeature"), .package(path: "../MLSAuthFeature"), .package(path: "../MLSCore"), .package(path: "../MLSDesignSystem"), + .package(path: "../MLSDictionaryFeature"), .package(url: "https://github.com/ReactorKit/ReactorKit.git", from: "3.2.0"), .package(url: "https://github.com/ReactiveX/RxSwift.git", from: "6.7.0"), .package(url: "https://github.com/SnapKit/SnapKit.git", from: "5.7.1") @@ -33,6 +35,7 @@ let package = Package( dependencies: [ .product(name: "MLSCore", package: "MLSCore"), .product(name: "MLSDesignSystem", package: "MLSDesignSystem"), + .product(name: "MLSDictionaryFeatureInterface", package: "MLSDictionaryFeature"), .product(name: "RxSwift", package: "RxSwift"), .product(name: "RxRelay", package: "RxSwift") ], @@ -43,9 +46,11 @@ let package = Package( name: "MLSBookmarkFeature", dependencies: [ "MLSBookmarkFeatureInterface", + .product(name: "MLSAppFeatureInterface", package: "MLSAppFeature"), .product(name: "MLSAuthFeatureInterface", package: "MLSAuthFeature"), .product(name: "MLSCore", package: "MLSCore"), .product(name: "MLSDesignSystem", package: "MLSDesignSystem"), + .product(name: "MLSDictionaryFeatureInterface", package: "MLSDictionaryFeature"), .product(name: "ReactorKit", package: "ReactorKit"), .product(name: "RxSwift", package: "RxSwift"), .product(name: "RxCocoa", package: "RxSwift"), @@ -60,6 +65,7 @@ let package = Package( dependencies: [ "MLSBookmarkFeatureInterface", .product(name: "MLSAuthFeatureInterface", package: "MLSAuthFeature"), + .product(name: "MLSDictionaryFeatureInterface", package: "MLSDictionaryFeature"), .product(name: "MLSCore", package: "MLSCore"), .product(name: "MLSDesignSystem", package: "MLSDesignSystem"), .product(name: "RxSwift", package: "RxSwift"), diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/DTOs/BookmarkDTO.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/DTOs/BookmarkDTO.swift index f5f9765b..c2b8b986 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/DTOs/BookmarkDTO.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/DTOs/BookmarkDTO.swift @@ -1,4 +1,5 @@ import MLSBookmarkFeatureInterface +import MLSDictionaryFeatureInterface struct BookmarkDTO: Decodable { let bookmarkId: Int diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/DTOs/EmptyResponseDTO.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/DTOs/EmptyResponseDTO.swift deleted file mode 100644 index fc48e0bd..00000000 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/DTOs/EmptyResponseDTO.swift +++ /dev/null @@ -1,5 +0,0 @@ -struct EmptyResponseDTO: Decodable { - func toBookmarkDomain() -> Int? { - return nil - } -} diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/Repositories/BookmarkAuthRepositoryImpl.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/Repositories/BookmarkAuthRepositoryImpl.swift index 2905423d..35e6aa80 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/Repositories/BookmarkAuthRepositoryImpl.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/Repositories/BookmarkAuthRepositoryImpl.swift @@ -2,16 +2,16 @@ import MLSAuthFeatureInterface import MLSBookmarkFeatureInterface import RxSwift -final class BookmarkAuthRepositoryImpl: BookmarkAuthRepository { +public final class BookmarkAuthRepositoryImpl: BookmarkAuthRepository { private let tokenRepository: TokenRepository private let authAPIRepository: AuthAPIRepository - init(tokenRepository: TokenRepository, authAPIRepository: AuthAPIRepository) { + public init(tokenRepository: TokenRepository, authAPIRepository: AuthAPIRepository) { self.tokenRepository = tokenRepository self.authAPIRepository = authAPIRepository } - func isLoggedIn() -> Observable { + public func isLoggedIn() -> Observable { switch tokenRepository.fetchToken(type: .refreshToken) { case .success(let token): guard !token.isEmpty else { return .just(false) } diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/Repositories/BookmarkRepositoryImpl.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/Repositories/BookmarkRepositoryImpl.swift index 49f33429..5a97ece0 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/Repositories/BookmarkRepositoryImpl.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/Repositories/BookmarkRepositoryImpl.swift @@ -1,59 +1,61 @@ import MLSBookmarkFeatureInterface import MLSCore +import MLSDictionaryFeatureInterface + import RxSwift -final class BookmarkRepositoryImpl: BookmarkRepository { +public final class BookmarkRepositoryImpl: BookmarkRepository { private let provider: NetworkProvider private let interceptor: Interceptor - init() { + public init() { self.provider = NetworkProviderImpl() self.interceptor = TokenInterceptor() } - func setBookmark(resourceId: Int, type: DictionaryItemType) -> Observable { + public func setBookmark(resourceId: Int, type: DictionaryItemType) -> Observable { let endpoint = BookmarkEndPoint.setBookmark(body: SetBookmarkBody(bookmarkType: type.rawValue, resourceId: resourceId)) return provider.requestData(endPoint: endpoint, interceptor: interceptor) .map { $0.toDomain() } } - func deleteBookmark(bookmarkId: Int) -> Observable { + public func deleteBookmark(bookmarkId: Int) -> Observable { let endpoint = BookmarkEndPoint.deleteBookmark(bookmarkId: bookmarkId) return provider.requestData(endPoint: endpoint, interceptor: interceptor) .map { $0.toBookmarkDomain() } } - func fetchBookmark(sort: String?) -> Observable<[BookmarkResponse]> { + public func fetchBookmark(sort: String?) -> Observable<[BookmarkResponse]> { let endpoint = BookmarkEndPoint.fetchBookmark(query: SortQuery(sort: sort)) return provider.requestData(endPoint: endpoint, interceptor: interceptor) .map { $0.toDomain() } } - func fetchMonsterBookmark(minLevel: Int?, maxLevel: Int?, sort: String?) -> Observable<[BookmarkResponse]> { + public func fetchMonsterBookmark(minLevel: Int?, maxLevel: Int?, sort: String?) -> Observable<[BookmarkResponse]> { let endpoint = BookmarkEndPoint.fetchMonsterBookmark(query: MonsterQuery(minLevel: minLevel, maxLevel: maxLevel, sort: sort)) return provider.requestData(endPoint: endpoint, interceptor: interceptor) .map { $0.toDomain() } } - func fetchNPCBookmark(sort: String?) -> Observable<[BookmarkResponse]> { + public func fetchNPCBookmark(sort: String?) -> Observable<[BookmarkResponse]> { let endpoint = BookmarkEndPoint.fetchNPCBookmark(query: SortQuery(sort: sort)) return provider.requestData(endPoint: endpoint, interceptor: interceptor) .map { $0.toDomain() } } - func fetchQuestBookmark(sort: String?) -> Observable<[BookmarkResponse]> { + public func fetchQuestBookmark(sort: String?) -> Observable<[BookmarkResponse]> { let endpoint = BookmarkEndPoint.fetchQuestBookmark(query: SortQuery(sort: sort)) return provider.requestData(endPoint: endpoint, interceptor: interceptor) .map { $0.toDomain() } } - func fetchItemBookmark(jobId: Int?, minLevel: Int?, maxLevel: Int?, categoryIds: [Int]?, sort: String?) -> Observable<[BookmarkResponse]> { + public func fetchItemBookmark(jobId: Int?, minLevel: Int?, maxLevel: Int?, categoryIds: [Int]?, sort: String?) -> Observable<[BookmarkResponse]> { let endpoint = BookmarkEndPoint.fetchItemBookmark(query: ItemQuery(jobId: jobId, minLevel: minLevel, maxLevel: maxLevel, categoryIds: categoryIds, sort: sort)) return provider.requestData(endPoint: endpoint, interceptor: interceptor) .map { $0.toDomain() } } - func fetchMapBookmark(sort: String?) -> Observable<[BookmarkResponse]> { + public func fetchMapBookmark(sort: String?) -> Observable<[BookmarkResponse]> { let endpoint = BookmarkEndPoint.fetchMapBookmark(query: SortQuery(sort: sort)) return provider.requestData(endPoint: endpoint, interceptor: interceptor) .map { $0.toDomain() } diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/Repositories/BookmarkUserDefaultsRepositoryImpl.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/Repositories/BookmarkUserDefaultsRepositoryImpl.swift index 8176ca4b..20e30838 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/Repositories/BookmarkUserDefaultsRepositoryImpl.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/Repositories/BookmarkUserDefaultsRepositoryImpl.swift @@ -1,11 +1,15 @@ import Foundation + import MLSBookmarkFeatureInterface + import RxSwift -final class BookmarkUserDefaultsRepositoryImpl: BookmarkUserDefaultsRepository { +public final class BookmarkUserDefaultsRepositoryImpl: BookmarkUserDefaultsRepository { private let key = "bookmark_onboarding_visited" - func hasVisitedOnboarding() -> Observable { + public init() {} + + public func hasVisitedOnboarding() -> Observable { let hasVisited = UserDefaults.standard.bool(forKey: key) if !hasVisited { UserDefaults.standard.set(true, forKey: key) @@ -14,7 +18,7 @@ final class BookmarkUserDefaultsRepositoryImpl: BookmarkUserDefaultsRepository { return .just(true) } - func markOnboardingVisited() -> Completable { + public func markOnboardingVisited() -> Completable { return Completable.create { [weak self] observer in guard let self else { observer(.completed) diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/Repositories/CollectionRepositoryImpl.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/Repositories/CollectionRepositoryImpl.swift index 903e6efd..57a7e926 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/Repositories/CollectionRepositoryImpl.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Data/Repositories/CollectionRepositoryImpl.swift @@ -2,43 +2,43 @@ import MLSBookmarkFeatureInterface import MLSCore import RxSwift -final class CollectionRepositoryImpl: CollectionRepository { +public final class CollectionRepositoryImpl: CollectionRepository { private let provider: NetworkProvider private let interceptor: Interceptor - init() { + public init() { self.provider = NetworkProviderImpl() self.interceptor = TokenInterceptor() } - func fetchCollectionList(sort: String?) -> Observable<[CollectionResponse]> { + public func fetchCollectionList(sort: String?) -> Observable<[CollectionResponse]> { let endpoint = CollectionEndPoint.fetchCollectionList(query: FetchListQuery(sort: sort)) return provider.requestData(endPoint: endpoint, interceptor: interceptor) .map { $0.map { $0.toDomain() } } } - func createCollectionList(name: String) -> Completable { + public func createCollectionList(name: String) -> Completable { let endpoint = CollectionEndPoint.createCollectionList(body: CreateBody(name: name)) return provider.requestData(endPoint: endpoint, interceptor: interceptor) } - func fetchCollection(id: Int) -> Observable<[BookmarkResponse]> { + public func fetchCollection(id: Int) -> Observable<[BookmarkResponse]> { let endpoint = CollectionEndPoint.fetchCollection(id: id) return provider.requestData(endPoint: endpoint, interceptor: interceptor) .map { $0.toDomain() } } - func updateCollectionName(collectionId: Int, name: String) -> Completable { + public func updateCollectionName(collectionId: Int, name: String) -> Completable { let endpoint = CollectionEndPoint.setCollectionName(id: collectionId, body: UpdateNameBody(name: name)) return provider.requestData(endPoint: endpoint, interceptor: interceptor) } - func deleteCollection(collectionId: Int) -> Completable { + public func deleteCollection(collectionId: Int) -> Completable { let endpoint = CollectionEndPoint.deleteCollection(id: collectionId) return provider.requestData(endPoint: endpoint, interceptor: interceptor) } - func addCollectionAndBookmark(collectionIds: [Int], bookmarkIds: [Int]) -> Completable { + public func addCollectionAndBookmark(collectionIds: [Int], bookmarkIds: [Int]) -> Completable { let endpoint = CollectionEndPoint.addCollectionAndBookmark(body: AddBody(collectionIds: collectionIds, bookmarkIds: bookmarkIds)) return provider.requestData(endPoint: endpoint, interceptor: interceptor) } diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkList/BookmarkListFactoryImpl.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkList/BookmarkListFactoryImpl.swift index ad3f231a..742b6cfc 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkList/BookmarkListFactoryImpl.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkList/BookmarkListFactoryImpl.swift @@ -1,6 +1,7 @@ import MLSAuthFeatureInterface import MLSBookmarkFeatureInterface import MLSCore +import MLSDictionaryFeatureInterface public final class BookmarkListFactoryImpl: BookmarkListFactory { private let itemFilterFactory: ItemFilterBottomSheetFactory diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkList/BookmarkListReactor.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkList/BookmarkListReactor.swift index a0201188..0b15e0df 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkList/BookmarkListReactor.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkList/BookmarkListReactor.swift @@ -1,4 +1,6 @@ import MLSBookmarkFeatureInterface +import MLSDictionaryFeatureInterface + import ReactorKit import RxSwift diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkList/BookmarkListViewController.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkList/BookmarkListViewController.swift index 31bbdfe3..0bb75f3f 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkList/BookmarkListViewController.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkList/BookmarkListViewController.swift @@ -1,12 +1,16 @@ +import UIKit + +import MLSAppFeatureInterface import MLSAuthFeatureInterface import MLSBookmarkFeatureInterface import MLSCore import MLSDesignSystem +import MLSDictionaryFeatureInterface + import ReactorKit import RxCocoa import RxRelay import RxSwift -import UIKit final class BookmarkListViewController: BaseViewController, View { typealias Reactor = BookmarkListReactor diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkMain/BookmarkMainFactoryImpl.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkMain/BookmarkMainFactoryImpl.swift index fe9cd5d0..6eea4d8e 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkMain/BookmarkMainFactoryImpl.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkMain/BookmarkMainFactoryImpl.swift @@ -1,7 +1,9 @@ +import UIKit + import MLSAuthFeatureInterface import MLSBookmarkFeatureInterface import MLSCore -import UIKit +import MLSDictionaryFeatureInterface public final class BookmarkMainFactoryImpl: BookmarkMainFactory { private let authRepository: BookmarkAuthRepository diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkMain/BookmarkMainReactor.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkMain/BookmarkMainReactor.swift index 404ab2c3..0384a091 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkMain/BookmarkMainReactor.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkMain/BookmarkMainReactor.swift @@ -1,4 +1,6 @@ import MLSBookmarkFeatureInterface +import MLSDictionaryFeatureInterface + import ReactorKit import RxSwift diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkMain/BookmarkMainView.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkMain/BookmarkMainView.swift index 5dc3caa5..cd79055b 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkMain/BookmarkMainView.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkMain/BookmarkMainView.swift @@ -1,8 +1,11 @@ +import UIKit + import MLSBookmarkFeatureInterface import MLSCore import MLSDesignSystem +import MLSDictionaryFeatureInterface + import SnapKit -import UIKit final class BookmarkMainView: UIView { enum Constant { diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkMain/BookmarkMainViewController.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkMain/BookmarkMainViewController.swift index 71f780e1..85182557 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkMain/BookmarkMainViewController.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/BookmarkMain/BookmarkMainViewController.swift @@ -1,12 +1,15 @@ +import UIKit + import MLSAuthFeatureInterface import MLSBookmarkFeatureInterface import MLSCore import MLSDesignSystem +import MLSDictionaryFeatureInterface + import ReactorKit import RxCocoa import RxSwift import SnapKit -import UIKit final class BookmarkMainViewController: BaseViewController, View { typealias Reactor = BookmarkMainReactor diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionDetail/CollectionDetailFactoryImpl.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionDetail/CollectionDetailFactoryImpl.swift index 63a2effa..5b0e3ae3 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionDetail/CollectionDetailFactoryImpl.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionDetail/CollectionDetailFactoryImpl.swift @@ -1,7 +1,9 @@ +import RxSwift + import MLSBookmarkFeatureInterface import MLSCore import MLSDesignSystem -import RxSwift +import MLSDictionaryFeatureInterface public final class CollectionDetailFactoryImpl: CollectionDetailFactory { private let bookmarkModalFactory: BookmarkModalFactory diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionDetail/CollectionDetailReactor.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionDetail/CollectionDetailReactor.swift index 9534d99e..f69ad8ce 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionDetail/CollectionDetailReactor.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionDetail/CollectionDetailReactor.swift @@ -1,4 +1,6 @@ import MLSBookmarkFeatureInterface +import MLSDictionaryFeatureInterface + import ReactorKit import RxSwift diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionDetail/CollectionDetailViewController.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionDetail/CollectionDetailViewController.swift index 1980ab53..3473fb96 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionDetail/CollectionDetailViewController.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionDetail/CollectionDetailViewController.swift @@ -1,10 +1,13 @@ +import UIKit + import MLSBookmarkFeatureInterface import MLSCore import MLSDesignSystem +import MLSDictionaryFeatureInterface + import ReactorKit import RxCocoa import RxSwift -import UIKit final class CollectionDetailViewController: BaseViewController, View { typealias Reactor = CollectionDetailReactor diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListCell.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListCell.swift index 639c520c..5fcffca1 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListCell.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListCell.swift @@ -34,6 +34,7 @@ extension CollectionListCell { } } +@MainActor private func loadImages(from urls: [String?], completion: @escaping ([UIImage?]) -> Void) { var results = [UIImage?](repeating: nil, count: urls.count) let group = DispatchGroup() diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListFactoryImpl.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListFactoryImpl.swift index ed1a23f8..ace20f08 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListFactoryImpl.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListFactoryImpl.swift @@ -1,5 +1,6 @@ import MLSBookmarkFeatureInterface import MLSCore +import MLSDictionaryFeatureInterface public final class CollectionListFactoryImpl: CollectionListFactory { private let collectionRepository: CollectionRepository diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListReactor.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListReactor.swift index a635b666..2193306c 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListReactor.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListReactor.swift @@ -1,4 +1,6 @@ import MLSBookmarkFeatureInterface +import MLSDictionaryFeatureInterface + import ReactorKit import RxSwift diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListView.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListView.swift index 16bbab66..c70cf340 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListView.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListView.swift @@ -1,7 +1,10 @@ +import UIKit + import MLSBookmarkFeatureInterface import MLSDesignSystem +import MLSDictionaryFeatureInterface + import SnapKit -import UIKit final class CollectionListView: UIView { private enum Constant { diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListViewController.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListViewController.swift index 94896690..c16c95f4 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListViewController.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/CollectionList/CollectionListViewController.swift @@ -1,9 +1,13 @@ +import UIKit + +import MLSAppFeatureInterface import MLSBookmarkFeatureInterface import MLSCore import MLSDesignSystem +import MLSDictionaryFeatureInterface + import ReactorKit import RxSwift -import UIKit final class CollectionListViewController: BaseViewController, View { typealias Reactor = CollectionListReactor diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/Common/DictionaryListCell.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/Common/DictionaryListCell.swift index ffac662e..5e02d5af 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/Common/DictionaryListCell.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeature/Presentation/Common/DictionaryListCell.swift @@ -1,8 +1,11 @@ +import UIKit + import MLSBookmarkFeatureInterface import MLSCore import MLSDesignSystem +import MLSDictionaryFeatureInterface + import SnapKit -import UIKit final class DictionaryListCell: UICollectionViewCell { private var onBookmarkTapped: (() -> Void)? diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/BookmarkResponse.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/BookmarkResponse.swift index e9934cd5..24cb421e 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/BookmarkResponse.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/BookmarkResponse.swift @@ -1,3 +1,5 @@ +import MLSDictionaryFeatureInterface + public struct BookmarkResponse: Equatable { public let name: String public let bookmarkId: Int diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/DictionaryItemType.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/DictionaryItemType.swift deleted file mode 100644 index f43d1d11..00000000 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/DictionaryItemType.swift +++ /dev/null @@ -1,17 +0,0 @@ -public enum DictionaryItemType: String { - case item - case monster - case map - case npc - case quest - - public var toDictionaryType: DictionaryType? { - switch self { - case .item: return .item - case .monster: return .monster - case .map: return .map - case .npc: return .npc - case .quest: return .quest - } - } -} diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/DictionaryMainViewType.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/DictionaryMainViewType.swift deleted file mode 100644 index 9ad16018..00000000 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/DictionaryMainViewType.swift +++ /dev/null @@ -1,16 +0,0 @@ -public enum DictionaryMainViewType { - case main - case search - case bookmark - - public var pageTabList: [DictionaryType] { - switch self { - case .main: - return [.total, .monster, .item, .map, .npc, .quest] - case .search: - return [.total, .monster, .item, .map, .npc, .quest] - case .bookmark: - return [.total, .collection, .monster, .item, .map, .npc, .quest] - } - } -} diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/DictionaryType.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/DictionaryType.swift deleted file mode 100644 index 2789524f..00000000 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/DictionaryType.swift +++ /dev/null @@ -1,49 +0,0 @@ -public enum DictionaryType: String, CaseIterable { - case total - case collection - case item - case monster - case map - case npc - case quest - - public var title: String { - switch self { - case .total: return "전체" - case .collection: return "컬렉션" - case .item: return "아이템" - case .monster: return "몬스터" - case .map: return "맵" - case .npc: return "NPC" - case .quest: return "퀘스트" - } - } - - public var bookmarkSortedFilter: [SortType] { - switch self { - case .total: return [.korean, .latest] - case .item: return [.korean, .levelDESC, .levelASC] - case .monster: return [.korean, .levelDESC, .levelASC] - case .map: return [.korean, .mostAppear] - case .npc: return [.korean] - case .quest: return [.korean, .levelLowest, .levelHighest] - case .collection: return [] - } - } - - public var isBookmarkSortHidden: Bool { - return bookmarkSortedFilter.count == 0 - } - - public var tabIndex: Int { - switch self { - case .total: return 0 - case .collection: return 1 - case .monster: return 2 - case .item: return 3 - case .map: return 4 - case .npc: return 5 - case .quest: return 6 - } - } -} diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/ItemFilterCriteria.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/ItemFilterCriteria.swift deleted file mode 100644 index 8fe61cd6..00000000 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/ItemFilterCriteria.swift +++ /dev/null @@ -1,13 +0,0 @@ -public struct ItemFilterCriteria { - public let jobIds: [Int] - public let startLevel: Int? - public let endLevel: Int? - public let categoryIds: [Int] - - public init(jobIds: [Int], startLevel: Int?, endLevel: Int?, categoryIds: [Int]) { - self.jobIds = jobIds - self.startLevel = startLevel - self.endLevel = endLevel - self.categoryIds = categoryIds - } -} diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/SortType.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/SortType.swift deleted file mode 100644 index b5848888..00000000 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Entities/SortType.swift +++ /dev/null @@ -1,37 +0,0 @@ -public enum SortType: String { - case korean = "가나다 순" - case levelDESC = "레벨 높은 순" - case levelASC = "레벨 낮은 순" - case expDESC = "획득 경험치 높은 순" - case expASC = "획득 경험치 낮은 순" - case latest = "최신순" - case mostAppear = "출현 많은 순" - case levelLowest = "수락 레벨 낮은 순" - case levelHighest = "수락 레벨 높은 순" - case mostDrop = "드롭률 높은 순" - - public var sortKey: String { - switch self { - case .korean: return "name" - case .levelDESC, .levelASC: return "level" - case .expDESC, .expASC: return "exp" - case .latest: return "createdAt" - case .mostAppear: return "count" - case .levelLowest, .levelHighest: return "minLevel" - case .mostDrop: return "dropRate" - } - } - - public var direction: String { - switch self { - case .korean, .levelASC, .expASC, .latest, .mostAppear, .levelLowest, .mostDrop: - return "asc" - case .levelDESC, .expDESC, .levelHighest: - return "desc" - } - } - - public var sortParameter: String { - return "\(sortKey),\(direction)" - } -} diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Factories/BookmarkListFactory.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Factories/BookmarkListFactory.swift index 4ffb7554..3ca92bd4 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Factories/BookmarkListFactory.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Factories/BookmarkListFactory.swift @@ -1,4 +1,5 @@ import MLSCore +import MLSDictionaryFeatureInterface public protocol BookmarkListFactory { func make(type: DictionaryType, listType: DictionaryMainViewType) -> BaseViewController diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Factories/DictionaryExternalFactories.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Factories/DictionaryExternalFactories.swift deleted file mode 100644 index a1ce47d7..00000000 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Factories/DictionaryExternalFactories.swift +++ /dev/null @@ -1,43 +0,0 @@ -import MLSCore -import MLSDesignSystem -import RxRelay - -// DictionaryFeature 모듈이 SPM으로 전환되기 전까지 임시로 정의하는 프로토콜들입니다. -// MLSDictionaryFeature 모듈이 생성되면 해당 모듈의 타입을 사용하도록 교체해야 합니다. - -public protocol DictionarySearchFactory { - func make() -> BaseViewController -} - -public protocol DictionaryNotificationFactory { - func make() -> BaseViewController -} - -public protocol DictionaryDetailFactory { - func make( - type: DictionaryType, - id: Int, - bookmarkRelay: PublishRelay<(id: Int, newBookmarkId: Int?)>?, - loginRelay: PublishRelay? - ) -> BaseViewController -} - -public protocol SortedBottomSheetFactory { - func make( - sortedOptions: [SortType], - selectedIndex: Int, - onSelectedIndex: @escaping (Int) -> Void - ) -> BaseViewController & ModalPresentable -} - -public protocol ItemFilterBottomSheetFactory { - func make(onFilterSelected: @escaping ([(String, String)]) -> Void) -> BaseViewController -} - -public protocol MonsterFilterBottomSheetFactory { - func make( - startLevel: Int, - endLevel: Int, - onFilterSelected: @escaping (Int, Int) -> Void - ) -> BaseViewController & ModalPresentable -} diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Repositories/BookmarkRepository.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Repositories/BookmarkRepository.swift index f3f31ff0..ed51aad8 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Repositories/BookmarkRepository.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/Repositories/BookmarkRepository.swift @@ -1,3 +1,5 @@ +import MLSDictionaryFeatureInterface + import RxSwift public protocol BookmarkRepository { diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/UseCases/ParseItemFilterResultUseCase.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/UseCases/ParseItemFilterResultUseCase.swift deleted file mode 100644 index 13a68723..00000000 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureInterface/UseCases/ParseItemFilterResultUseCase.swift +++ /dev/null @@ -1,3 +0,0 @@ -public protocol ParseItemFilterResultUseCase { - func execute(results: [(String, String)]) -> ItemFilterCriteria -} diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureTesting/MockBookmarkRepository.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureTesting/MockBookmarkRepository.swift index 1cc37895..4bae38a3 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureTesting/MockBookmarkRepository.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureTesting/MockBookmarkRepository.swift @@ -1,4 +1,6 @@ import MLSBookmarkFeatureInterface +import MLSDictionaryFeatureInterface + import RxSwift public final class MockBookmarkRepository: BookmarkRepository { diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureTesting/MockParseItemFilterResultUseCase.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureTesting/MockParseItemFilterResultUseCase.swift index 3dac15de..f3bc6635 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureTesting/MockParseItemFilterResultUseCase.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureTesting/MockParseItemFilterResultUseCase.swift @@ -1,4 +1,5 @@ import MLSBookmarkFeatureInterface +import MLSDictionaryFeatureInterface public final class MockParseItemFilterResultUseCase: ParseItemFilterResultUseCase { public var result: ItemFilterCriteria = ItemFilterCriteria(jobIds: [], startLevel: nil, endLevel: nil, categoryIds: []) diff --git a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureTesting/Stubs.swift b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureTesting/Stubs.swift index 81656be2..284c63db 100644 --- a/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureTesting/Stubs.swift +++ b/MLS/MLSBookmarkFeature/Sources/MLSBookmarkFeatureTesting/Stubs.swift @@ -1,9 +1,12 @@ +import UIKit + import MLSAuthFeatureInterface import MLSBookmarkFeatureInterface import MLSCore import MLSDesignSystem +import MLSDictionaryFeatureInterface + import RxRelay -import UIKit // MARK: - Stub Modal ViewController diff --git a/MLS/MLSBookmarkFeatureExample/MenuViewController.swift b/MLS/MLSBookmarkFeatureExample/MenuViewController.swift index 0a0f7e58..dd7fcc80 100644 --- a/MLS/MLSBookmarkFeatureExample/MenuViewController.swift +++ b/MLS/MLSBookmarkFeatureExample/MenuViewController.swift @@ -1,8 +1,10 @@ +import UIKit + import MLSBookmarkFeature import MLSBookmarkFeatureInterface import MLSBookmarkFeatureTesting import MLSCore -import UIKit +import MLSDictionaryFeatureInterface final class MenuViewController: UITableViewController { diff --git a/MLS/MLSCore/Sources/MLSCore/Navigation/DictionaryTabRegistry.swift b/MLS/MLSCore/Sources/MLSCore/Navigation/DictionaryTabRegistry.swift deleted file mode 100644 index 467443c7..00000000 --- a/MLS/MLSCore/Sources/MLSCore/Navigation/DictionaryTabRegistry.swift +++ /dev/null @@ -1,11 +0,0 @@ -public enum DictionaryTabRegistry { - private static weak var controller: DictionaryTabControllable? - - public static func register(controller: DictionaryTabControllable) { - self.controller = controller - } - - public static func changeTab(index: Int) { - controller?.changeTab(index: index) - } -} diff --git a/MLS/Data/Data/Network/DTO/APIDefaultResponseDTO.swift b/MLS/MLSCore/Sources/MLSCore/Network/APIDefaultResponseDTO.swift similarity index 89% rename from MLS/Data/Data/Network/DTO/APIDefaultResponseDTO.swift rename to MLS/MLSCore/Sources/MLSCore/Network/APIDefaultResponseDTO.swift index b190ce1f..8fd6e60b 100644 --- a/MLS/Data/Data/Network/DTO/APIDefaultResponseDTO.swift +++ b/MLS/MLSCore/Sources/MLSCore/Network/APIDefaultResponseDTO.swift @@ -1,7 +1,5 @@ import Foundation -import DomainInterface - public struct APIDefaultResponseDTO: Decodable { public let success: Bool public let code: String? diff --git a/MLS/Data/Data/Network/DTO/EmptyResponseDTO.swift b/MLS/MLSCore/Sources/MLSCore/Network/EmptyResponseDTO.swift similarity index 61% rename from MLS/Data/Data/Network/DTO/EmptyResponseDTO.swift rename to MLS/MLSCore/Sources/MLSCore/Network/EmptyResponseDTO.swift index 2f92153f..7dc2a765 100644 --- a/MLS/Data/Data/Network/DTO/EmptyResponseDTO.swift +++ b/MLS/MLSCore/Sources/MLSCore/Network/EmptyResponseDTO.swift @@ -1,5 +1,5 @@ public struct EmptyResponseDTO: Decodable { - func toBookmarkDomain() -> Int? { + public func toBookmarkDomain() -> Int? { return nil } } diff --git a/MLS/MLSCore/Sources/MLSCore/Network/NetworkProviderImpl.swift b/MLS/MLSCore/Sources/MLSCore/Network/NetworkProviderImpl.swift index fadff14a..70b8060f 100644 --- a/MLS/MLSCore/Sources/MLSCore/Network/NetworkProviderImpl.swift +++ b/MLS/MLSCore/Sources/MLSCore/Network/NetworkProviderImpl.swift @@ -28,9 +28,17 @@ public final class NetworkProviderImpl: NetworkProvider, Loggable { if let data = data { self?.logDebug("Core requestData: 응답 데이터 있음 - \(String(data: data, encoding: .utf8) ?? "디코딩 실패")") do { - let decoded = try JSONDecoder().decode(T.Response.self, from: data) + let decoded = try JSONDecoder().decode(APIDefaultResponseDTO.self, from: data) self?.logDebug("Core requestData: 디코딩 성공 - \(decoded)") - observer.onNext(decoded) + if let decodedData = decoded.data { + observer.onNext(decodedData) + } else { + if T.Response.self == EmptyResponseDTO.self { + observer.onNext(EmptyResponseDTO() as! T.Response) + } else { + observer.onError(NetworkError.invalidResponse) + } + } observer.onCompleted() } catch { self?.logError("Core requestData: 디코딩 실패 - \(error)") diff --git a/MLS/MLSCore/Sources/MLSCore/Utils/DictionaryTabControllable.swift b/MLS/MLSCore/Sources/MLSCore/Utils/DictionaryTabControllable.swift deleted file mode 100644 index 06ad3253..00000000 --- a/MLS/MLSCore/Sources/MLSCore/Utils/DictionaryTabControllable.swift +++ /dev/null @@ -1,15 +0,0 @@ -public protocol DictionaryTabControllable: AnyObject { - func changeTab(index: Int) -} - -public enum DictionaryTabRegistry { - private static weak var controller: DictionaryTabControllable? - - public static func register(controller: DictionaryTabControllable) { - self.controller = controller - } - - public static func changeTab(index: Int) { - controller?.changeTab(index: index) - } -} diff --git a/MLS/MLSDesignSystem/Sources/MLSDesignSystem/Components/Tabbar/BottomTabBar.swift b/MLS/MLSDesignSystem/Sources/MLSDesignSystem/Components/Tabbar/BottomTabBar.swift index 03dc2c5d..832a69db 100644 --- a/MLS/MLSDesignSystem/Sources/MLSDesignSystem/Components/Tabbar/BottomTabBar.swift +++ b/MLS/MLSDesignSystem/Sources/MLSDesignSystem/Components/Tabbar/BottomTabBar.swift @@ -6,6 +6,11 @@ import SnapKit public struct TabItem { var title: String var icon: UIImage + + public init(title: String, icon: UIImage) { + self.title = title + self.icon = icon + } } internal final class BottomTabBar: UIStackView { diff --git a/MLS/MLSDictionaryFeature/Package.swift b/MLS/MLSDictionaryFeature/Package.swift index d289a424..c4827025 100644 --- a/MLS/MLSDictionaryFeature/Package.swift +++ b/MLS/MLSDictionaryFeature/Package.swift @@ -21,10 +21,12 @@ let package = Package( ) ], dependencies: [ + .package(path: "../MLSAppFeature"), .package(path: "../MLSAuthFeature"), - .package(path: "../MLSMyPageFeature"), + .package(path: "../MLSBookmarkFeature"), .package(path: "../MLSCore"), .package(path: "../MLSDesignSystem"), + .package(path: "../MLSMyPageFeature"), .package(url: "https://github.com/ReactorKit/ReactorKit.git", from: "3.2.0"), .package(url: "https://github.com/ReactiveX/RxSwift.git", from: "6.7.0"), .package(url: "https://github.com/RxSwiftCommunity/RxKeyboard.git", from: "2.0.0"), @@ -46,7 +48,9 @@ let package = Package( name: "MLSDictionaryFeature", dependencies: [ "MLSDictionaryFeatureInterface", + .product(name: "MLSAppFeatureInterface", package: "MLSAppFeature"), .product(name: "MLSAuthFeatureInterface", package: "MLSAuthFeature"), + .product(name: "MLSBookmarkFeatureInterface", package: "MLSBookmarkFeature"), .product(name: "MLSCore", package: "MLSCore"), .product(name: "MLSDesignSystem", package: "MLSDesignSystem"), .product(name: "MLSMyPageFeatureInterface", package: "MLSMyPageFeature"), @@ -64,7 +68,9 @@ let package = Package( name: "MLSDictionaryFeatureTesting", dependencies: [ "MLSDictionaryFeatureInterface", + .product(name: "MLSAppFeatureInterface", package: "MLSAppFeature"), .product(name: "MLSAuthFeatureInterface", package: "MLSAuthFeature"), + .product(name: "MLSBookmarkFeatureInterface", package: "MLSBookmarkFeature"), .product(name: "MLSMyPageFeatureInterface", package: "MLSMyPageFeature"), .product(name: "RxSwift", package: "RxSwift") ], diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Domain/Usecases/SetBookmarkUseCaseImpl.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Domain/Usecases/SetBookmarkUseCaseImpl.swift deleted file mode 100644 index 3cf23f07..00000000 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Domain/Usecases/SetBookmarkUseCaseImpl.swift +++ /dev/null @@ -1,22 +0,0 @@ -import MLSDictionaryFeatureInterface - -import RxSwift - -public final class SetBookmarkUseCaseImpl: SetBookmarkUseCase { - private let repository: BookmarkRepository - - public init(repository: BookmarkRepository) { - self.repository = repository - } - - public func execute(bookmarkId: Int, isBookmark: IsBookmark) -> Observable { - switch isBookmark { - case .set(let type): - return repository - .setBookmark(bookmarkId: bookmarkId, type: type) - .map { Optional($0) } - case .delete: - return repository.deleteBookmark(bookmarkId: bookmarkId) - } - } -} diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/DictionaryDetailBaseViewController.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/DictionaryDetailBaseViewController.swift index 192b9bdb..d2523e73 100644 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/DictionaryDetailBaseViewController.swift +++ b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/DictionaryDetailBaseViewController.swift @@ -1,7 +1,8 @@ import UIKit +import MLSAppFeatureInterface import MLSAuthFeatureInterface -// import MLSBookmarkFeatureInterface 추가 예정 +import MLSBookmarkFeatureInterface import MLSCore import MLSDesignSystem import MLSDictionaryFeatureInterface diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/DictionaryDetailFactoryImpl.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/DictionaryDetailFactoryImpl.swift index 40949741..4ad2587d 100644 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/DictionaryDetailFactoryImpl.swift +++ b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/DictionaryDetailFactoryImpl.swift @@ -1,4 +1,6 @@ +import MLSAppFeatureInterface import MLSAuthFeatureInterface +import MLSBookmarkFeatureInterface import MLSCore import MLSDictionaryFeatureInterface @@ -10,8 +12,8 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { private let detailOnBoardingFactory: DetailOnBoardingFactory private let appCoordinator: () -> AppCoordinatorProtocol private let dictionaryDetailAPIRepository: DictionaryDetailAPIRepository + private let bookmarkRepository: BookmarkRepository private let checkLoginUseCase: CheckLoginUseCase - private let setBookmarkUseCase: SetBookmarkUseCase private let fetchVisitDictionaryDetailUseCase: FetchVisitDictionaryDetailUseCase public init( @@ -20,8 +22,8 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { detailOnBoardingFactory: DetailOnBoardingFactory, appCoordinator: @escaping () -> AppCoordinatorProtocol, dictionaryDetailAPIRepository: DictionaryDetailAPIRepository, + bookmarkRepository: BookmarkRepository, checkLoginUseCase: CheckLoginUseCase, - setBookmarkUseCase: SetBookmarkUseCase, fetchVisitDictionaryDetailUseCase: FetchVisitDictionaryDetailUseCase ) { self.loginFactory = loginFactory @@ -29,8 +31,8 @@ public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { self.detailOnBoardingFactory = detailOnBoardingFactory self.appCoordinator = appCoordinator self.dictionaryDetailAPIRepository = dictionaryDetailAPIRepository + self.bookmarkRepository = bookmarkRepository self.checkLoginUseCase = checkLoginUseCase - self.setBookmarkUseCase = setBookmarkUseCase self.fetchVisitDictionaryDetailUseCase = fetchVisitDictionaryDetailUseCase } @@ -109,8 +111,8 @@ private extension DictionaryDetailFactoryImpl { viewController.reactor = ItemDictionaryDetailReactor( dictionaryDetailAPIRepository: dictionaryDetailAPIRepository, + bookmarkRepository: bookmarkRepository, checkLoginUseCase: checkLoginUseCase, - setBookmarkUseCase: setBookmarkUseCase, id: id ) @@ -137,8 +139,8 @@ private extension DictionaryDetailFactoryImpl { viewController.reactor = MonsterDictionaryDetailReactor( dictionaryDetailAPIRepository: dictionaryDetailAPIRepository, + bookmarkRepository: bookmarkRepository, checkLoginUseCase: checkLoginUseCase, - setBookmarkUseCase: setBookmarkUseCase, id: id ) @@ -165,8 +167,8 @@ private extension DictionaryDetailFactoryImpl { viewController.reactor = MapDictionaryDetailReactor( dictionaryDetailAPIRepository: dictionaryDetailAPIRepository, + bookmarkRepository: bookmarkRepository, checkLoginUseCase: checkLoginUseCase, - setBookmarkUseCase: setBookmarkUseCase, id: id ) @@ -193,8 +195,8 @@ private extension DictionaryDetailFactoryImpl { viewController.reactor = NpcDictionaryDetailReactor( dictionaryDetailAPIRepository: dictionaryDetailAPIRepository, + bookmarkRepository: bookmarkRepository, checkLoginUseCase: checkLoginUseCase, - setBookmarkUseCase: setBookmarkUseCase, id: id ) @@ -221,8 +223,8 @@ private extension DictionaryDetailFactoryImpl { viewController.reactor = QuestDictionaryDetailReactor( dictionaryDetailAPIRepository: dictionaryDetailAPIRepository, + bookmarkRepository: bookmarkRepository, checkLoginUseCase: checkLoginUseCase, - setBookmarkUseCase: setBookmarkUseCase, id: id ) diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift index aca5520f..7f690b70 100644 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift +++ b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift @@ -1,3 +1,4 @@ +import MLSBookmarkFeatureInterface import MLSDictionaryFeatureInterface import ReactorKit @@ -53,19 +54,19 @@ public final class ItemDictionaryDetailReactor: Reactor { private let disposeBag = DisposeBag() private let dictionaryDetailAPIRepository: DictionaryDetailAPIRepository + private let bookmarkRepository: BookmarkRepository private let checkLoginUseCase: CheckLoginUseCase - private let setBookmarkUseCase: SetBookmarkUseCase // MARK: Init public init( dictionaryDetailAPIRepository: DictionaryDetailAPIRepository, + bookmarkRepository: BookmarkRepository, checkLoginUseCase: CheckLoginUseCase, - setBookmarkUseCase: SetBookmarkUseCase, id: Int ) { self.dictionaryDetailAPIRepository = dictionaryDetailAPIRepository + self.bookmarkRepository = bookmarkRepository self.checkLoginUseCase = checkLoginUseCase - self.setBookmarkUseCase = setBookmarkUseCase self.initialState = .init( itemDetailInfo: DictionaryDetailItemResponse( itemId: 0, nameKr: nil, nameEn: nil, descriptionText: nil, @@ -130,47 +131,55 @@ private extension ItemDictionaryDetailReactor { let isSelected = item.bookmarkId != nil guard let type = currentState.type.toItemType else { return .empty() } - return setBookmarkUseCase.execute( - bookmarkId: isSelected ? item.bookmarkId ?? item.itemId : item.itemId, - isBookmark: isSelected ? .delete : .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } + let bookmarkObservable: Observable - item.bookmarkId = newBookmarkId - let event: UIEvent = isSelected ? .delete(item) : .add(item) - let eventMutation = Observable.just(Mutation.setEvent(event)) + if isSelected, let bookmarkId = item.bookmarkId { + bookmarkObservable = bookmarkRepository + .deleteBookmark(bookmarkId: bookmarkId) + } else { + bookmarkObservable = bookmarkRepository + .setBookmark(resourceId: item.itemId, type: type) + .map { Optional($0) } + } - let refresh = self.dictionaryDetailAPIRepository.fetchItemDetail(id: self.currentState.id) - .map { Mutation.setDetailData($0) } + return bookmarkObservable + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigateTo(.bookmarkError)) - } + item.bookmarkId = newBookmarkId + let event: UIEvent = isSelected ? .delete(item) : .add(item) + let eventMutation = Observable.just(Mutation.setEvent(event)) + + let refresh = self.dictionaryDetailAPIRepository + .fetchItemDetail(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + .catch { _ in + .just(.navigateTo(.bookmarkError)) + } } func handleUndoLastDeletedBookmark() -> Observable { var item = currentState.itemDetailInfo guard let type = currentState.type.toItemType else { return .empty() } - return setBookmarkUseCase.execute( - bookmarkId: item.itemId, - isBookmark: .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } - - item.bookmarkId = newBookmarkId - let eventMutation = Observable.just(Mutation.setEvent(.add(item))) - let refresh = self.dictionaryDetailAPIRepository.fetchItemDetail(id: self.currentState.id) - .map { Mutation.setDetailData($0) } - - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigateTo(.bookmarkError)) - } + return bookmarkRepository + .setBookmark(resourceId: item.itemId, type: type) + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } + + item.bookmarkId = newBookmarkId + let eventMutation = Observable.just(Mutation.setEvent(.add(item))) + let refresh = self.dictionaryDetailAPIRepository + .fetchItemDetail(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + .catch { _ in + .just(.navigateTo(.bookmarkError)) + } } } diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/Map/MapDictionaryDetailReactor.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/Map/MapDictionaryDetailReactor.swift index a2cb3ac0..7ef80027 100644 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/Map/MapDictionaryDetailReactor.swift +++ b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/Map/MapDictionaryDetailReactor.swift @@ -1,3 +1,4 @@ +import MLSBookmarkFeatureInterface import MLSDictionaryFeatureInterface import ReactorKit @@ -40,8 +41,8 @@ public final class MapDictionaryDetailReactor: Reactor { } public let dictionaryDetailAPIRepository: DictionaryDetailAPIRepository + private let bookmarkRepository: BookmarkRepository private let checkLoginUseCase: CheckLoginUseCase - private let setBookmarkUseCase: SetBookmarkUseCase public struct State { @Pulse var event: UIEvent = .none @@ -63,8 +64,8 @@ public final class MapDictionaryDetailReactor: Reactor { public init( dictionaryDetailAPIRepository: DictionaryDetailAPIRepository, + bookmarkRepository: BookmarkRepository, checkLoginUseCase: CheckLoginUseCase, - setBookmarkUseCase: SetBookmarkUseCase, id: Int ) { initialState = State( @@ -86,8 +87,8 @@ public final class MapDictionaryDetailReactor: Reactor { ) self.dictionaryDetailAPIRepository = dictionaryDetailAPIRepository + self.bookmarkRepository = bookmarkRepository self.checkLoginUseCase = checkLoginUseCase - self.setBookmarkUseCase = setBookmarkUseCase } public func mutate(action: Action) -> Observable { @@ -151,47 +152,55 @@ private extension MapDictionaryDetailReactor { let isSelected = map.bookmarkId != nil guard let type = currentState.type.toItemType else { return .empty() } - return setBookmarkUseCase.execute( - bookmarkId: isSelected ? map.bookmarkId ?? map.mapId : map.mapId, - isBookmark: isSelected ? .delete : .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } + let bookmarkObservable: Observable - map.bookmarkId = newBookmarkId - let event: UIEvent = isSelected ? .delete(map) : .add(map) - let eventMutation = Observable.just(Mutation.setEvent(event)) + if isSelected, let bookmarkId = map.bookmarkId { + bookmarkObservable = bookmarkRepository + .deleteBookmark(bookmarkId: bookmarkId) + } else { + bookmarkObservable = bookmarkRepository + .setBookmark(resourceId: map.mapId, type: type) + .map { Optional($0) } + } - let refresh = self.dictionaryDetailAPIRepository.fetchMapDetail(id: self.currentState.id) - .map { Mutation.setDetailData($0) } + return bookmarkObservable + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigateTo(.bookmarkError)) - } + map.bookmarkId = newBookmarkId + let event: UIEvent = isSelected ? .delete(map) : .add(map) + let eventMutation = Observable.just(Mutation.setEvent(event)) + + let refresh = self.dictionaryDetailAPIRepository + .fetchMapDetail(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + .catch { _ in + .just(.navigateTo(.bookmarkError)) + } } func handleUndoLastDeletedBookmark() -> Observable { var map = currentState.mapDetailInfo guard let type = currentState.type.toItemType else { return .empty() } - return setBookmarkUseCase.execute( - bookmarkId: map.mapId, - isBookmark: .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } - - map.bookmarkId = newBookmarkId - let eventMutation = Observable.just(Mutation.setEvent(.add(map))) - let refresh = self.dictionaryDetailAPIRepository.fetchMapDetail(id: self.currentState.id) - .map { Mutation.setDetailData($0) } - - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigateTo(.bookmarkError)) - } + return bookmarkRepository + .setBookmark(resourceId: map.mapId, type: type) + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } + + map.bookmarkId = newBookmarkId + let eventMutation = Observable.just(Mutation.setEvent(.add(map))) + let refresh = self.dictionaryDetailAPIRepository + .fetchMapDetail(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + .catch { _ in + .just(.navigateTo(.bookmarkError)) + } } } diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift index 1b5c0598..4df54eb5 100644 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift +++ b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift @@ -1,3 +1,4 @@ +import MLSBookmarkFeatureInterface import MLSDictionaryFeatureInterface import ReactorKit @@ -77,22 +78,22 @@ public final class MonsterDictionaryDetailReactor: Reactor { // MARK: - Properties private let disposeBag = DisposeBag() private let dictionaryDetailAPIRepository: DictionaryDetailAPIRepository + private let bookmarkRepository: BookmarkRepository private let checkLoginUseCase: CheckLoginUseCase - private let setBookmarkUseCase: SetBookmarkUseCase public var initialState: State // MARK: - Init public init( dictionaryDetailAPIRepository: DictionaryDetailAPIRepository, + bookmarkRepository: BookmarkRepository, checkLoginUseCase: CheckLoginUseCase, - setBookmarkUseCase: SetBookmarkUseCase, id: Int ) { self.initialState = State(type: .monster, id: id) self.dictionaryDetailAPIRepository = dictionaryDetailAPIRepository + self.bookmarkRepository = bookmarkRepository self.checkLoginUseCase = checkLoginUseCase - self.setBookmarkUseCase = setBookmarkUseCase } // MARK: - Mutate @@ -187,47 +188,55 @@ private extension MonsterDictionaryDetailReactor { let isSelected = monster.bookmarkId != nil guard let type = currentState.type.toItemType else { return .empty() } - return setBookmarkUseCase.execute( - bookmarkId: isSelected ? monster.bookmarkId ?? monster.monsterId : monster.monsterId, - isBookmark: isSelected ? .delete : .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } + let bookmarkObservable: Observable - monster.bookmarkId = newBookmarkId - let event: UIEvent = isSelected ? .delete(monster) : .add(monster) - let eventMutation = Observable.just(Mutation.setEvent(event)) + if isSelected, let bookmarkId = monster.bookmarkId { + bookmarkObservable = bookmarkRepository + .deleteBookmark(bookmarkId: bookmarkId) + } else { + bookmarkObservable = bookmarkRepository + .setBookmark(resourceId: monster.monsterId, type: type) + .map { Optional($0) } + } - let refresh = self.dictionaryDetailAPIRepository.fetchMonsterDetail(id: self.currentState.id) - .map { Mutation.setDetailData($0) } + return bookmarkObservable + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigateTo(.bookmarkError)) - } + monster.bookmarkId = newBookmarkId + let event: UIEvent = isSelected ? .delete(monster) : .add(monster) + let eventMutation = Observable.just(Mutation.setEvent(event)) + + let refresh = self.dictionaryDetailAPIRepository + .fetchMonsterDetail(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + .catch { _ in + .just(.navigateTo(.bookmarkError)) + } } func handleUndoLastDeletedBookmark() -> Observable { var monster = currentState.monsterDetailInfo guard let type = currentState.type.toItemType else { return .empty() } - return setBookmarkUseCase.execute( - bookmarkId: monster.monsterId, - isBookmark: .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } + return bookmarkRepository + .setBookmark(resourceId: monster.monsterId, type: type) + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } - monster.bookmarkId = newBookmarkId - let eventMutation = Observable.just(Mutation.setEvent(.add(monster))) - let refresh = self.dictionaryDetailAPIRepository.fetchMonsterDetail(id: self.currentState.id) - .map { Mutation.setDetailData($0) } + monster.bookmarkId = newBookmarkId + let eventMutation = Observable.just(Mutation.setEvent(.add(monster))) + let refresh = self.dictionaryDetailAPIRepository + .fetchMonsterDetail(id: self.currentState.id) + .map { Mutation.setDetailData($0) } - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigateTo(.bookmarkError)) - } + return .concat([eventMutation, refresh]) + } + .catch { _ in + .just(.navigateTo(.bookmarkError)) + } } } diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift index d4dd5fe7..a3a3ebcb 100644 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift +++ b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift @@ -1,3 +1,4 @@ +import MLSBookmarkFeatureInterface import MLSDictionaryFeatureInterface import ReactorKit @@ -58,8 +59,8 @@ public final class NpcDictionaryDetailReactor: Reactor { // MARK: - UseCases private let dictionaryDetailAPIRepository: DictionaryDetailAPIRepository + private let bookmarkRepository: BookmarkRepository private let checkLoginUseCase: CheckLoginUseCase - private let setBookmarkUseCase: SetBookmarkUseCase public var initialState: State private let disposeBag = DisposeBag() @@ -67,13 +68,13 @@ public final class NpcDictionaryDetailReactor: Reactor { // MARK: - Init public init( dictionaryDetailAPIRepository: DictionaryDetailAPIRepository, + bookmarkRepository: BookmarkRepository, checkLoginUseCase: CheckLoginUseCase, - setBookmarkUseCase: SetBookmarkUseCase, id: Int ) { self.dictionaryDetailAPIRepository = dictionaryDetailAPIRepository + self.bookmarkRepository = bookmarkRepository self.checkLoginUseCase = checkLoginUseCase - self.setBookmarkUseCase = setBookmarkUseCase self.initialState = State( npcDetailInfo: DictionaryDetailNpcResponse( npcId: 0, nameKr: "", nameEn: "", iconUrlDetail: nil, bookmarkId: nil @@ -142,47 +143,55 @@ private extension NpcDictionaryDetailReactor { let isSelected = npc.bookmarkId != nil guard let type = currentState.type.toItemType else { return .empty() } - return setBookmarkUseCase.execute( - bookmarkId: isSelected ? npc.bookmarkId ?? npc.npcId : npc.npcId, - isBookmark: isSelected ? .delete : .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } + let bookmarkObservable: Observable - npc.bookmarkId = newBookmarkId - let event: UIEvent = isSelected ? .delete(npc) : .add(npc) - let eventMutation = Observable.just(Mutation.setEvent(event)) + if isSelected, let bookmarkId = npc.bookmarkId { + bookmarkObservable = bookmarkRepository + .deleteBookmark(bookmarkId: bookmarkId) + } else { + bookmarkObservable = bookmarkRepository + .setBookmark(resourceId: npc.npcId, type: type) + .map { Optional($0) } + } - let refresh = self.dictionaryDetailAPIRepository.fetchNpcDetail(id: self.currentState.id) - .map { Mutation.setDetailData($0) } + return bookmarkObservable + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigateTo(.bookmarkError)) - } + npc.bookmarkId = newBookmarkId + let event: UIEvent = isSelected ? .delete(npc) : .add(npc) + let eventMutation = Observable.just(Mutation.setEvent(event)) + + let refresh = self.dictionaryDetailAPIRepository + .fetchNpcDetail(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + .catch { _ in + .just(.navigateTo(.bookmarkError)) + } } func handleUndoLastDeletedBookmark() -> Observable { var npc = currentState.npcDetailInfo guard let type = currentState.type.toItemType else { return .empty() } - return setBookmarkUseCase.execute( - bookmarkId: npc.npcId, - isBookmark: .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } - - npc.bookmarkId = newBookmarkId - let eventMutation = Observable.just(Mutation.setEvent(.add(npc))) - let refresh = self.dictionaryDetailAPIRepository.fetchNpcDetail(id: self.currentState.id) - .map { Mutation.setDetailData($0) } - - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigateTo(.bookmarkError)) - } + return bookmarkRepository + .setBookmark(resourceId: npc.npcId, type: type) + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } + + npc.bookmarkId = newBookmarkId + let eventMutation = Observable.just(Mutation.setEvent(.add(npc))) + let refresh = self.dictionaryDetailAPIRepository + .fetchNpcDetail(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + .catch { _ in + .just(.navigateTo(.bookmarkError)) + } } } diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift index 981731eb..c3a91523 100644 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift +++ b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift @@ -1,3 +1,4 @@ +import MLSBookmarkFeatureInterface import MLSDictionaryFeatureInterface import ReactorKit @@ -58,21 +59,21 @@ public final class QuestDictionaryDetailReactor: Reactor { } private let dictionaryDetailAPIRepository: DictionaryDetailAPIRepository + private let bookmarkRepository: BookmarkRepository private let checkLoginUseCase: CheckLoginUseCase - private let setBookmarkUseCase: SetBookmarkUseCase public var initialState: State private let disposeBag = DisposeBag() public init( dictionaryDetailAPIRepository: DictionaryDetailAPIRepository, + bookmarkRepository: BookmarkRepository, checkLoginUseCase: CheckLoginUseCase, - setBookmarkUseCase: SetBookmarkUseCase, id: Int ) { self.dictionaryDetailAPIRepository = dictionaryDetailAPIRepository + self.bookmarkRepository = bookmarkRepository self.checkLoginUseCase = checkLoginUseCase - self.setBookmarkUseCase = setBookmarkUseCase self.initialState = .init( id: id, detailInfo: .init( @@ -189,47 +190,55 @@ private extension QuestDictionaryDetailReactor { let isSelected = quest.bookmarkId != nil guard let type = currentState.type.toItemType else { return .empty() } - return setBookmarkUseCase.execute( - bookmarkId: isSelected ? quest.bookmarkId ?? quest.questId : quest.questId, - isBookmark: isSelected ? .delete : .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } + let bookmarkObservable: Observable - quest.bookmarkId = newBookmarkId - let event: UIEvent = isSelected ? .delete(quest) : .add(quest) - let eventMutation = Observable.just(Mutation.setEvent(event)) + if isSelected, let bookmarkId = quest.bookmarkId { + bookmarkObservable = bookmarkRepository + .deleteBookmark(bookmarkId: bookmarkId) + } else { + bookmarkObservable = bookmarkRepository + .setBookmark(resourceId: quest.questId, type: type) + .map { Optional($0) } + } - let refresh = self.dictionaryDetailAPIRepository.fetchQuestDetail(id: self.currentState.id) - .map { Mutation.setDetailData($0) } + return bookmarkObservable + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigateTo(.bookmarkError)) - } + quest.bookmarkId = newBookmarkId + let event: UIEvent = isSelected ? .delete(quest) : .add(quest) + let eventMutation = Observable.just(Mutation.setEvent(event)) + + let refresh = self.dictionaryDetailAPIRepository + .fetchQuestDetail(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + .catch { _ in + .just(.navigateTo(.bookmarkError)) + } } func handleUndoLastDeletedBookmark() -> Observable { var quest = currentState.detailInfo guard let type = currentState.type.toItemType else { return .empty() } - return setBookmarkUseCase.execute( - bookmarkId: quest.questId, - isBookmark: .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } - - quest.bookmarkId = newBookmarkId - let eventMutation = Observable.just(Mutation.setEvent(.add(quest))) - let refresh = self.dictionaryDetailAPIRepository.fetchQuestDetail(id: self.currentState.id) - .map { Mutation.setDetailData($0) } - - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigateTo(.bookmarkError)) - } + return bookmarkRepository + .setBookmark(resourceId: quest.questId, type: type) + .flatMap { [weak self] newBookmarkId -> Observable in + guard let self else { return .empty() } + + quest.bookmarkId = newBookmarkId + let eventMutation = Observable.just(Mutation.setEvent(.add(quest))) + let refresh = self.dictionaryDetailAPIRepository + .fetchQuestDetail(id: self.currentState.id) + .map { Mutation.setDetailData($0) } + + return .concat([eventMutation, refresh]) + } + .catch { _ in + .just(.navigateTo(.bookmarkError)) + } } } diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryList/DictionaryListFactoryImpl.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryList/DictionaryListFactoryImpl.swift index d98f8a2b..a0851372 100644 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryList/DictionaryListFactoryImpl.swift +++ b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryList/DictionaryListFactoryImpl.swift @@ -1,10 +1,11 @@ import MLSAuthFeatureInterface +import MLSBookmarkFeatureInterface import MLSCore import MLSDictionaryFeatureInterface public final class DictionaryListFactoryImpl: DictionaryMainListFactory { private let checkLoginUseCase: CheckLoginUseCase - private let setBookmarkUseCase: SetBookmarkUseCase + private let bookmarkRepository: BookmarkRepository private let parseItemFilterResultUseCase: ParseItemFilterResultUseCase private let dictionaryListAPIRepository: DictionaryListAPIRepository @@ -18,7 +19,7 @@ public final class DictionaryListFactoryImpl: DictionaryMainListFactory { public init( checkLoginUseCase: CheckLoginUseCase, - setBookmarkUseCase: SetBookmarkUseCase, + bookmarkRepository: BookmarkRepository, parseItemFilterResultUseCase: ParseItemFilterResultUseCase, dictionaryListAPIRepository: DictionaryListAPIRepository, itemFilterFactory: ItemFilterBottomSheetFactory, @@ -29,7 +30,7 @@ public final class DictionaryListFactoryImpl: DictionaryMainListFactory { loginFactory: @escaping () -> LoginFactory ) { self.checkLoginUseCase = checkLoginUseCase - self.setBookmarkUseCase = setBookmarkUseCase + self.bookmarkRepository = bookmarkRepository self.parseItemFilterResultUseCase = parseItemFilterResultUseCase self.dictionaryListAPIRepository = dictionaryListAPIRepository self.itemFilterFactory = itemFilterFactory @@ -46,7 +47,7 @@ public final class DictionaryListFactoryImpl: DictionaryMainListFactory { keyword: keyword, dictionaryListAPIRepository: dictionaryListAPIRepository, checkLoginUseCase: checkLoginUseCase, - setBookmarkUseCase: setBookmarkUseCase, + bookmarkRepository: bookmarkRepository, parseItemFilterResultUseCase: parseItemFilterResultUseCase ) let viewController = DictionaryListViewController( diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryList/DictionaryListReactor.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryList/DictionaryListReactor.swift index eeeeadcb..bca71c61 100644 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryList/DictionaryListReactor.swift +++ b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryList/DictionaryListReactor.swift @@ -1,3 +1,4 @@ +import MLSBookmarkFeatureInterface import MLSCore import MLSDictionaryFeatureInterface @@ -82,7 +83,7 @@ public final class DictionaryListReactor: Reactor { // MARK: - UseCases private let dictionaryListAPIRepository: DictionaryListAPIRepository private let checkLoginUseCase: CheckLoginUseCase - private let setBookmarkUseCase: SetBookmarkUseCase + private let bookmarkRepository: BookmarkRepository private let parseItemFilterResultUseCase: ParseItemFilterResultUseCase private let disposeBag = DisposeBag() @@ -93,13 +94,13 @@ public final class DictionaryListReactor: Reactor { keyword: String?, dictionaryListAPIRepository: DictionaryListAPIRepository, checkLoginUseCase: CheckLoginUseCase, - setBookmarkUseCase: SetBookmarkUseCase, + bookmarkRepository: BookmarkRepository, parseItemFilterResultUseCase: ParseItemFilterResultUseCase ) { self.initialState = State(route: .none, type: type, keyword: keyword, isLogin: false) self.dictionaryListAPIRepository = dictionaryListAPIRepository self.checkLoginUseCase = checkLoginUseCase - self.setBookmarkUseCase = setBookmarkUseCase + self.bookmarkRepository = bookmarkRepository self.parseItemFilterResultUseCase = parseItemFilterResultUseCase } @@ -282,22 +283,28 @@ private extension DictionaryListReactor { let targetItem = currentState.listItems[index] let isSelected = targetItem.bookmarkId != nil - return setBookmarkUseCase.execute( - bookmarkId: isSelected ? targetItem.bookmarkId ?? targetItem.id : targetItem.id, - isBookmark: isSelected ? .delete : .set(targetItem.type) - ) - .flatMap { newBookmarkId -> Observable in - let lastItem = Mutation.setLastDeletedBookmark(targetItem) + let bookmarkObservable: Observable - let event: UIEvent = isSelected ? .delete(targetItem) : .add(targetItem) - let eventMutation = Mutation.setEvent(event) - - let updateMutation = Mutation.updateBookmarkId(id: id, newBookmarkId: newBookmarkId) - return .from([lastItem, updateMutation, eventMutation]) - } - .catch { _ in - .just(.navigateTo(.bookmarkError)) + if isSelected, let bookmarkId = targetItem.bookmarkId { + bookmarkObservable = bookmarkRepository + .deleteBookmark(bookmarkId: bookmarkId) + } else { + bookmarkObservable = bookmarkRepository + .setBookmark(resourceId: targetItem.id, type: targetItem.type) + .map { Optional($0) } } + + return bookmarkObservable + .flatMap { newBookmarkId -> Observable in + let lastItem = Mutation.setLastDeletedBookmark(targetItem) + let event: UIEvent = isSelected ? .delete(targetItem) : .add(targetItem) + let eventMutation = Mutation.setEvent(event) + let updateMutation = Mutation.updateBookmarkId(id: id, newBookmarkId: newBookmarkId) + return .from([lastItem, updateMutation, eventMutation]) + } + .catch { _ in + .just(.navigateTo(.bookmarkError)) + } } func handleUpdateBookmark(id: Int, newBookmarkId: Int?) -> Observable { @@ -337,22 +344,18 @@ private extension DictionaryListReactor { func handleUndoLastDeletedBookmark() -> Observable { guard let lastDeleted = currentState.lastDeletedBookmark else { return .empty() } - return setBookmarkUseCase.execute( - bookmarkId: lastDeleted.id, - isBookmark: .set(lastDeleted.type) - ) - .flatMap { newBookmarkId -> Observable in - let lastItem = Mutation.setLastDeletedBookmark(nil) - - let event: UIEvent = .add(lastDeleted) - let eventMutation = Mutation.setEvent(event) - - let updateMutation = Mutation.updateBookmarkId(id: lastDeleted.id, newBookmarkId: newBookmarkId) - return .from([lastItem, updateMutation, eventMutation]) - } - .catch { _ in - .just(.navigateTo(.bookmarkError)) - } + return bookmarkRepository + .setBookmark(resourceId: lastDeleted.id, type: lastDeleted.type) + .flatMap { newBookmarkId -> Observable in + let lastItem = Mutation.setLastDeletedBookmark(nil) + let event: UIEvent = .add(lastDeleted) + let eventMutation = Mutation.setEvent(event) + let updateMutation = Mutation.updateBookmarkId(id: lastDeleted.id, newBookmarkId: newBookmarkId) + return .from([lastItem, updateMutation, eventMutation]) + } + .catch { _ in + .just(.navigateTo(.bookmarkError)) + } } func handleItemFilterOptionSelected(results: [(String, String)]) -> Observable { diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryList/DictionaryListViewController.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryList/DictionaryListViewController.swift index 27fe9778..e4707c30 100644 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryList/DictionaryListViewController.swift +++ b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryList/DictionaryListViewController.swift @@ -1,9 +1,9 @@ import UIKit import MLSAuthFeatureInterface +import MLSBookmarkFeatureInterface import MLSCore import MLSDesignSystem -// import MLSBookmarkFeatureInterface로 수정 필요 import MLSDictionaryFeatureInterface import ReactorKit diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryMain/DictionaryMainViewController.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryMain/DictionaryMainViewController.swift index 75c8db9e..f1c16414 100644 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryMain/DictionaryMainViewController.swift +++ b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeature/Presentation/DictionaryMain/DictionaryMainViewController.swift @@ -1,5 +1,6 @@ import UIKit +import MLSAppFeatureInterface import MLSAuthFeatureInterface import MLSCore import MLSDesignSystem diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureInterface/Factories/BookmarkModalFactory.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureInterface/Factories/BookmarkModalFactory.swift deleted file mode 100644 index 4cfd8ea1..00000000 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureInterface/Factories/BookmarkModalFactory.swift +++ /dev/null @@ -1,7 +0,0 @@ -import MLSCore - -/// Bookmark 모듈 분리 후 제거 -public protocol BookmarkModalFactory { - func make(bookmarkIds: [Int]) -> BaseViewController - func make(bookmarkIds: [Int], onComplete: ((Bool) -> Void)?) -> BaseViewController -} diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureInterface/Repositories/BookmarkRepository.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureInterface/Repositories/BookmarkRepository.swift deleted file mode 100644 index 85f6a241..00000000 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureInterface/Repositories/BookmarkRepository.swift +++ /dev/null @@ -1,38 +0,0 @@ -import RxSwift - -/// Bookmark 모듈 분리 후 제거 -public struct BookmarkResponse: Equatable { - public let name: String - public let bookmarkId: Int - public let originalId: Int - public let imageUrl: String? - public let type: DictionaryItemType - public let level: Int? - - public init(name: String, bookmarkId: Int, originalId: Int, imageUrl: String?, type: DictionaryItemType, level: Int?) { - self.name = name - self.bookmarkId = bookmarkId - self.originalId = originalId - self.imageUrl = imageUrl - self.type = type - self.level = level - } -} - -public protocol BookmarkRepository { - func setBookmark(bookmarkId: Int, type: DictionaryItemType) -> Observable - - func deleteBookmark(bookmarkId: Int) -> Observable - - func fetchBookmark(sort: String?) -> Observable<[BookmarkResponse]> - - func fetchMonsterBookmark(minLevel: Int?, maxLevel: Int?, sort: String?) -> Observable<[BookmarkResponse]> - - func fetchNPCBookmark(sort: String?) -> Observable<[BookmarkResponse]> - - func fetchQuestBookmark(sort: String?) -> Observable<[BookmarkResponse]> - - func fetchItemBookmark(jobId: Int?, minLevel: Int?, maxLevel: Int?, categoryIds: [Int]?, sort: String?) -> Observable<[BookmarkResponse]> - - func fetchMapBookmark(sort: String?) -> Observable<[BookmarkResponse]> -} diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureInterface/UseCases/SetBookmarkUseCase.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureInterface/UseCases/SetBookmarkUseCase.swift deleted file mode 100644 index b20a53d3..00000000 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureInterface/UseCases/SetBookmarkUseCase.swift +++ /dev/null @@ -1,11 +0,0 @@ -import RxSwift - -/// Bookmark 모듈 분리 후 삭제 예정 -public protocol SetBookmarkUseCase { - func execute(bookmarkId: Int, isBookmark: IsBookmark) -> Observable -} - -public enum IsBookmark { - case set(DictionaryItemType) - case delete -} diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureTesting/Mock/MockAppCoordinator.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureTesting/Mock/MockAppCoordinator.swift index 37130ff2..105b5447 100644 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureTesting/Mock/MockAppCoordinator.swift +++ b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureTesting/Mock/MockAppCoordinator.swift @@ -1,5 +1,6 @@ import UIKit +import MLSAppFeatureInterface import MLSAuthFeatureInterface public final class MockAppCoordinator: AppCoordinatorProtocol { diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureTesting/Mock/MockBookmarkFailRepository.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureTesting/Mock/MockBookmarkFailRepository.swift index ff4908f2..fe3d4a33 100644 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureTesting/Mock/MockBookmarkFailRepository.swift +++ b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureTesting/Mock/MockBookmarkFailRepository.swift @@ -1,5 +1,6 @@ import Foundation +import MLSBookmarkFeatureInterface import MLSCore import MLSDictionaryFeatureInterface @@ -19,7 +20,7 @@ public final class MockBookmarkFailRepository: BookmarkRepository { ) } - public func setBookmark(bookmarkId: Int, type: DictionaryItemType) -> Observable { + public func setBookmark(resourceId: Int, type: DictionaryItemType) -> Observable { return failError() } diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureTesting/Mock/MockBookmarkModalFactory.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureTesting/Mock/MockBookmarkModalFactory.swift index dad5a899..c43b25c5 100644 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureTesting/Mock/MockBookmarkModalFactory.swift +++ b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureTesting/Mock/MockBookmarkModalFactory.swift @@ -1,5 +1,5 @@ +import MLSBookmarkFeatureInterface import MLSCore -import MLSDictionaryFeatureInterface public final class MockBookmarkModalFactory: BookmarkModalFactory { public init() {} diff --git a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureTesting/Mock/MockBookmarkRepository.swift b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureTesting/Mock/MockBookmarkRepository.swift index 78f9a20c..d7a5e856 100644 --- a/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureTesting/Mock/MockBookmarkRepository.swift +++ b/MLS/MLSDictionaryFeature/Sources/MLSDictionaryFeatureTesting/Mock/MockBookmarkRepository.swift @@ -1,3 +1,4 @@ +import MLSBookmarkFeatureInterface import MLSCore import MLSDictionaryFeatureInterface @@ -7,8 +8,8 @@ public final class MockBookmarkRepository: BookmarkRepository { public init() {} - public func setBookmark(bookmarkId: Int, type: DictionaryItemType) -> Observable { - return .just(bookmarkId) + public func setBookmark(resourceId: Int, type: DictionaryItemType) -> Observable { + return .just(resourceId) } public func deleteBookmark(bookmarkId: Int) -> Observable { diff --git a/MLS/MLSDictionaryFeatureExample/SceneDelegate.swift b/MLS/MLSDictionaryFeatureExample/SceneDelegate.swift index bfbbf06b..67d327e5 100644 --- a/MLS/MLSDictionaryFeatureExample/SceneDelegate.swift +++ b/MLS/MLSDictionaryFeatureExample/SceneDelegate.swift @@ -37,9 +37,6 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { authRepository: authRepository, tokenRepository: tokenRepository ) - let setBookmarkUseCase = SetBookmarkUseCaseImpl( - repository: bookmarkRepository - ) let parseItemFilterResultUseCase = ParseItemFilterResultUseCaseImpl() let fetchVisitDictionaryDetailUseCase = FetchVisitDictionaryDetailUseCaseImpl( @@ -60,21 +57,18 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { MockNotificationSettingFactory() // MARK: - Detail Factory - var detailFactory = DictionaryDetailFactoryImpl( + let detailFactory = DictionaryDetailFactoryImpl( loginFactory: { loginFactory }, bookmarkModalFactory: bookmarkModalFactory, -// dictionaryDetailFactory: { -// detailFactory -// }, detailOnBoardingFactory: detailOnBoardingFactory, appCoordinator: { MockAppCoordinator() }, dictionaryDetailAPIRepository: dictionaryDetailAPIRepository, + bookmarkRepository: bookmarkRepository, checkLoginUseCase: checkLoginUseCase, - setBookmarkUseCase: setBookmarkUseCase, fetchVisitDictionaryDetailUseCase: fetchVisitDictionaryDetailUseCase ) @@ -82,7 +76,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { // MARK: - Dictionary Main List Factory let dictionaryMainListFactory = DictionaryListFactoryImpl( checkLoginUseCase: checkLoginUseCase, - setBookmarkUseCase: setBookmarkUseCase, + bookmarkRepository: bookmarkRepository, parseItemFilterResultUseCase: parseItemFilterResultUseCase, dictionaryListAPIRepository: diff --git a/MLS/MLSMyPageFeature/Package.swift b/MLS/MLSMyPageFeature/Package.swift index 5e0dd527..96ac88da 100644 --- a/MLS/MLSMyPageFeature/Package.swift +++ b/MLS/MLSMyPageFeature/Package.swift @@ -21,6 +21,7 @@ let package = Package( ) ], dependencies: [ + .package(path: "../MLSAppFeature"), .package(path: "../MLSAuthFeature"), .package(path: "../MLSCore"), .package(path: "../MLSDesignSystem"), @@ -63,6 +64,7 @@ let package = Package( name: "MLSMyPageFeatureTesting", dependencies: [ "MLSMyPageFeatureInterface", + .product(name: "MLSAppFeatureTesting", package: "MLSAppFeature"), .product(name: "RxSwift", package: "RxSwift") ], swiftSettings: [.swiftLanguageMode(.v5)] diff --git a/MLS/MLSMyPageFeature/Sources/MLSMyPageFeature/Data/Repositories/AlarmAPIRepositoryImpl.swift b/MLS/MLSMyPageFeature/Sources/MLSMyPageFeature/Data/Repositories/AlarmRepositoryImpl.swift similarity index 96% rename from MLS/MLSMyPageFeature/Sources/MLSMyPageFeature/Data/Repositories/AlarmAPIRepositoryImpl.swift rename to MLS/MLSMyPageFeature/Sources/MLSMyPageFeature/Data/Repositories/AlarmRepositoryImpl.swift index 7a8f799e..45c02ebb 100644 --- a/MLS/MLSMyPageFeature/Sources/MLSMyPageFeature/Data/Repositories/AlarmAPIRepositoryImpl.swift +++ b/MLS/MLSMyPageFeature/Sources/MLSMyPageFeature/Data/Repositories/AlarmRepositoryImpl.swift @@ -5,7 +5,7 @@ import MLSMyPageFeatureInterface import RxSwift -public class AlarmAPIRepositoryImpl: AlarmRepository { +public class AlarmRepositoryImpl: AlarmRepository { private let provider: NetworkProvider private let tokenInterceptor: Interceptor @@ -51,7 +51,7 @@ public class AlarmAPIRepositoryImpl: AlarmRepository { } -private extension AlarmAPIRepositoryImpl { +private extension AlarmRepositoryImpl { struct AlarmQuery: Encodable { let cursor: Int? let pageSize: Int diff --git a/MLS/MLSMyPageFeature/Sources/MLSMyPageFeature/Domain/Usecases/CheckEmptyLevelAndRoleUseCaseImpl.swift b/MLS/MLSMyPageFeature/Sources/MLSMyPageFeature/Domain/Usecases/CheckEmptyLevelAndRoleUseCaseImpl.swift index 55ffeaee..fc171039 100644 --- a/MLS/MLSMyPageFeature/Sources/MLSMyPageFeature/Domain/Usecases/CheckEmptyLevelAndRoleUseCaseImpl.swift +++ b/MLS/MLSMyPageFeature/Sources/MLSMyPageFeature/Domain/Usecases/CheckEmptyLevelAndRoleUseCaseImpl.swift @@ -1,13 +1,13 @@ -import MLSAuthFeatureInterface - -import RxSwift - -public class CheckEmptyLevelAndRoleUseCaseImpl: CheckEmptyLevelAndRoleUseCase { - public init() {} - - public func execute(level: Int?, job: String?) -> Bool { - let isValidLevel = level.map { (1 ... 200).contains($0) } ?? false - let isValidRole = job != nil && job != "" - return isValidLevel && isValidRole - } -} +// import MLSAuthFeatureInterface +// +// import RxSwift +// +// public class CheckEmptyLevelAndRoleUseCaseImpl: CheckEmptyLevelAndRoleUseCase { +// public init() {} +// +// public func execute(level: Int?, job: String?) -> Bool { +// let isValidLevel = level.map { (1 ... 200).contains($0) } ?? false +// let isValidRole = job != nil && job != "" +// return isValidLevel && isValidRole +// } +// } diff --git a/MLS/MLSMyPageFeature/Sources/MLSMyPageFeature/Domain/Usecases/CheckValidLevelUseCaseImpl.swift b/MLS/MLSMyPageFeature/Sources/MLSMyPageFeature/Domain/Usecases/CheckValidLevelUseCaseImpl.swift deleted file mode 100644 index 9331638d..00000000 --- a/MLS/MLSMyPageFeature/Sources/MLSMyPageFeature/Domain/Usecases/CheckValidLevelUseCaseImpl.swift +++ /dev/null @@ -1,14 +0,0 @@ -import MLSAuthFeatureInterface - -import RxSwift - -public class CheckValidLevelUseCaseImpl: CheckValidLevelUseCase { - public init() {} - - public func execute(level: Int?) -> Bool? { - guard let level = level else { - return nil - } - return (1 ... 200).contains(level) - } -} diff --git a/MLS/MLSMyPageFeature/Sources/MLSMyPageFeature/Presentation/SetProfile/SetProfileViewController.swift b/MLS/MLSMyPageFeature/Sources/MLSMyPageFeature/Presentation/SetProfile/SetProfileViewController.swift index aaa81020..4a59646b 100644 --- a/MLS/MLSMyPageFeature/Sources/MLSMyPageFeature/Presentation/SetProfile/SetProfileViewController.swift +++ b/MLS/MLSMyPageFeature/Sources/MLSMyPageFeature/Presentation/SetProfile/SetProfileViewController.swift @@ -48,6 +48,18 @@ public final class SetProfileViewController: BaseViewController, View { addViews() setupConstraints() } + + public override func viewWillAppear(_ animated: Bool) { + super.viewWillAppear(animated) + (tabBarController as? BottomTabBarController)? + .setHidden(hidden: true, animated: false) + } + + public override func viewWillDisappear(_ animated: Bool) { + super.viewWillDisappear(animated) + (tabBarController as? BottomTabBarController)? + .setHidden(hidden: false, animated: true) + } } // MARK: - Setup diff --git a/MLS/MLSMyPageFeature/Sources/MLSMyPageFeatureTesting/Mock/MockLoginFactory.swift b/MLS/MLSMyPageFeature/Sources/MLSMyPageFeatureTesting/Mock/MockLoginFactory.swift index cf87876b..b450546b 100644 --- a/MLS/MLSMyPageFeature/Sources/MLSMyPageFeatureTesting/Mock/MockLoginFactory.swift +++ b/MLS/MLSMyPageFeature/Sources/MLSMyPageFeatureTesting/Mock/MockLoginFactory.swift @@ -1,3 +1,4 @@ +import MLSAppFeatureInterface import MLSAuthFeatureInterface import MLSCore diff --git a/MLS/MLSMyPageFeature/Tests/MLSMyPageFeatureTests/Repository/AlarmRepositoryTests.swift b/MLS/MLSMyPageFeature/Tests/MLSMyPageFeatureTests/Repository/AlarmRepositoryTests.swift index d32f16a1..71c7e911 100644 --- a/MLS/MLSMyPageFeature/Tests/MLSMyPageFeatureTests/Repository/AlarmRepositoryTests.swift +++ b/MLS/MLSMyPageFeature/Tests/MLSMyPageFeatureTests/Repository/AlarmRepositoryTests.swift @@ -197,8 +197,8 @@ private extension AlarmAPIRepositoryImplTests { func makeSUT( provider: MockNetworkProvider = MockNetworkProvider(), interceptor: MockInterceptor = MockInterceptor() - ) -> AlarmAPIRepositoryImpl { - AlarmAPIRepositoryImpl( + ) -> AlarmRepositoryImpl { + AlarmRepositoryImpl( provider: provider, interceptor: interceptor ) diff --git a/MLS/MLSTests/ProviderTests.swift b/MLS/MLSTests/ProviderTests.swift deleted file mode 100644 index be81daf3..00000000 --- a/MLS/MLSTests/ProviderTests.swift +++ /dev/null @@ -1,215 +0,0 @@ -import XCTest - -import Core -import Data -import DomainInterface - -import RxSwift - -// Post Model -struct Post: Decodable { - let id: Int - let title: String - let body: String - let userId: Int -} - -// Post Request Body -struct PostBody: Encodable { - let title: String - let body: String - let userId: Int -} - -class ProviderTests: XCTestCase { - var provider: NetworkProvider? - var disposeBag: DisposeBag? - - override func setUp() { - super.setUp() - provider = NetworkProviderImpl() - disposeBag = DisposeBag() - } - - override func tearDown() { - provider = nil - disposeBag = nil - super.tearDown() - } - - func testRequestableEndPoint() { - guard let provider = provider, - let disposeBag = disposeBag else { - XCTFail("provider or disposeBag is nil") - return - } - - let expectation = XCTestExpectation(description: "Request data success") - let request = ResponsableEndPoint<[Post]>( - baseURL: "https://jsonplaceholder.typicode.com", - path: "/posts", - method: .GET - ) - - provider.requestData(endPoint: request, interceptor: nil) - .subscribe(onNext: { (posts: [Post]) in - XCTAssertFalse(posts.isEmpty, "Posts should not be empty") - XCTAssertEqual(posts.first?.title, "sunt aut facere repellat provident occaecati excepturi optio reprehenderit") - expectation.fulfill() - }, onError: { error in - XCTFail("Expected success, but got error: \(error)") - }) - .disposed(by: disposeBag) - - wait(for: [expectation], timeout: 5.0) - } - - func testEndPoint() { - guard let provider = provider, - let disposeBag = disposeBag else { - XCTFail("provider or disposeBag is nil") - return - } - - let expectation = XCTestExpectation(description: "Request completable success") - let request = EndPoint( - baseURL: "https://jsonplaceholder.typicode.com", - path: "/posts", - method: .POST, - body: PostBody(title: "Test Title", body: "Test Body", userId: 1) - ) - - provider.requestData(endPoint: request, interceptor: nil) - .subscribe(onCompleted: { - expectation.fulfill() - }, onError: { error in - XCTFail("Expected completion, but got error: \(error)") - }) - .disposed(by: disposeBag) - - wait(for: [expectation], timeout: 5.0) - } - - func test404Error() { - guard let provider = provider, - let disposeBag = disposeBag else { - XCTFail("provider or disposeBag is nil") - return - } - - let expectation = XCTestExpectation(description: "Request 404 error") - let request = ResponsableEndPoint( - baseURL: "https://jsonplaceholder.typicode.com", - path: "/posts/999", - method: .GET - ) - - provider.requestData(endPoint: request, interceptor: nil) - .subscribe(onNext: { _ in - XCTFail("Expected error, but got success") - }, onError: { error in - if case NetworkError.statusError(let code, let message) = error { - XCTAssertEqual(code, 404, "Expected 404 status code") - XCTAssertEqual(message, "{}", "Expected empty JSON object") - expectation.fulfill() - } else { - XCTFail("Expected statusError, but got \(error)") - } - }) - .disposed(by: disposeBag) - - wait(for: [expectation], timeout: 5.0) - } - - func testInvalidURL() { - guard let provider = provider, - let disposeBag = disposeBag else { - XCTFail("provider or disposeBag is nil") - return - } - - let expectation = XCTestExpectation(description: "Invalid URL error") - let request = ResponsableEndPoint( - baseURL: "url", - path: "/posts", - method: .GET - ) - - provider.requestData(endPoint: request, interceptor: nil) - .subscribe(onNext: { _ in - XCTFail("Expected error, but got success") - }, onError: { error in - if case NetworkError.urlRequest(_) = error { - expectation.fulfill() - } else { - XCTFail("Expected urlRequest error, but got \(error)") - } - }) - .disposed(by: disposeBag) - - wait(for: [expectation], timeout: 5.0) - } - - func testDecodeError() { - guard let provider = provider, - let disposeBag = disposeBag else { - XCTFail("provider or disposeBag is nil") - return - } - - struct DecodeFailResponse: Decodable { - let invalidKey: String // API 응답에 없는 키 - } - - let expectation = XCTestExpectation(description: "Decode error") - let request = ResponsableEndPoint( - baseURL: "https://jsonplaceholder.typicode.com", - path: "/posts/1", - method: .GET - ) - - provider.requestData(endPoint: request, interceptor: nil) - .subscribe(onNext: { (_: DecodeFailResponse) in - XCTFail("Expected error, but got success") - }, onError: { error in - if case NetworkError.decodeError(_) = error { - expectation.fulfill() - } else { - XCTFail("Expected decodeError, but got \(error)") - } - }) - .disposed(by: disposeBag) - - wait(for: [expectation], timeout: 5.0) - } - - func testProviderDeallocated() { - guard let disposeBag = disposeBag else { - XCTFail("disposeBag is nil") - return - } - - let expectation = XCTestExpectation(description: "Provider deallocated error") - let request = ResponsableEndPoint<[Post]>( - baseURL: "https://jsonplaceholder.typicode.com", - path: "/posts", - method: .GET - ) - - var localProvider: NetworkProviderImpl? = NetworkProviderImpl() - localProvider?.requestData(endPoint: request, interceptor: nil) - .subscribe(onNext: { (_: [Post]) in - XCTFail("Expected error, but got success") - }, onError: { error in - if case NetworkError.providerDeallocated = error { - expectation.fulfill() - } else { - XCTFail("Expected providerDeallocated, but got \(error)") - } - }) - .disposed(by: disposeBag) - - localProvider = nil - wait(for: [expectation], timeout: 5.0) - } -} diff --git a/MLS/Presentation/.DS_Store b/MLS/Presentation/.DS_Store deleted file mode 100644 index a6dedd51..00000000 Binary files a/MLS/Presentation/.DS_Store and /dev/null differ diff --git a/MLS/Presentation/AuthFeature/.DS_Store b/MLS/Presentation/AuthFeature/.DS_Store deleted file mode 100644 index 1d52553e..00000000 Binary files a/MLS/Presentation/AuthFeature/.DS_Store and /dev/null differ diff --git a/MLS/Presentation/AuthFeature/AuthFeature.xcodeproj/project.pbxproj b/MLS/Presentation/AuthFeature/AuthFeature.xcodeproj/project.pbxproj deleted file mode 100644 index 414870e2..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature.xcodeproj/project.pbxproj +++ /dev/null @@ -1,969 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 77; - objects = { - -/* Begin PBXBuildFile section */ - 08501BEA2DDCACD20055CBCE /* AuthFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08501BC62DDCA9DF0055CBCE /* AuthFeatureInterface.framework */; }; - 0850205F2DDCD9240055CBCE /* BaseFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08EECF932DD908D00047AFE2 /* BaseFeature.framework */; }; - 085020612DDCD9250055CBCE /* DesignSystem.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0858ABEF2DCFDA450060EBCA /* DesignSystem.framework */; }; - 085020642DDCD9640055CBCE /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 085020632DDCD9640055CBCE /* RxCocoa */; }; - 085020662DDCD9640055CBCE /* RxRelay in Frameworks */ = {isa = PBXBuildFile; productRef = 085020652DDCD9640055CBCE /* RxRelay */; }; - 085020682DDCD9640055CBCE /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 085020672DDCD9640055CBCE /* RxSwift */; }; - 0850206A2DDCD9720055CBCE /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 085020692DDCD9720055CBCE /* SnapKit */; }; - 0850206C2DDCD97E0055CBCE /* ReactorKit in Frameworks */ = {isa = PBXBuildFile; productRef = 0850206B2DDCD97E0055CBCE /* ReactorKit */; }; - 085BDA622DF18617009CFB90 /* DomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 085BDA612DF18617009CFB90 /* DomainInterface.framework */; }; - 085BDA6D2DF1A4DA009CFB90 /* BaseFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 085BDA6C2DF1A4DA009CFB90 /* BaseFeature.framework */; }; - 085BDA6E2DF1A4DA009CFB90 /* BaseFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 085BDA6C2DF1A4DA009CFB90 /* BaseFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 085BDF572DF459FE009CFB90 /* DomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 085BDF562DF459FE009CFB90 /* DomainInterface.framework */; }; - 08E424F72DF0BB3C00D6ACD3 /* Domain.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08E424F62DF0BB3C00D6ACD3 /* Domain.framework */; }; - 08E424F82DF0BB3C00D6ACD3 /* Domain.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 08E424F62DF0BB3C00D6ACD3 /* Domain.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 08E424F92DF0BC5C00D6ACD3 /* AuthFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0858AB3F2DCFD62C0060EBCA /* AuthFeature.framework */; }; - 08E424FA2DF0BC5C00D6ACD3 /* AuthFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0858AB3F2DCFD62C0060EBCA /* AuthFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 08E424FB2DF0BC5E00D6ACD3 /* AuthFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08501BC62DDCA9DF0055CBCE /* AuthFeatureInterface.framework */; }; - 08E424FC2DF0BC5E00D6ACD3 /* AuthFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 08501BC62DDCA9DF0055CBCE /* AuthFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 08E424FD2DF0BC7800D6ACD3 /* DesignSystem.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0858ABEF2DCFDA450060EBCA /* DesignSystem.framework */; }; - 08E424FE2DF0BC7800D6ACD3 /* DesignSystem.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0858ABEF2DCFDA450060EBCA /* DesignSystem.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 08E425002DF0BC9F00D6ACD3 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 08E424FF2DF0BC9F00D6ACD3 /* RxSwift */; }; - 08E425022DF0BCA400D6ACD3 /* RxRelay in Frameworks */ = {isa = PBXBuildFile; productRef = 08E425012DF0BCA400D6ACD3 /* RxRelay */; }; - 08E425042DF0BCCC00D6ACD3 /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 08E425032DF0BCCC00D6ACD3 /* RxCocoa */; }; - 08E4255B2DF17D5300D6ACD3 /* DataMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08E4255A2DF17D5300D6ACD3 /* DataMock.framework */; }; - 08E4255C2DF17D5300D6ACD3 /* DataMock.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 08E4255A2DF17D5300D6ACD3 /* DataMock.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 7746ABE22E8BD9DC0046F603 /* RxKeyboard in Frameworks */ = {isa = PBXBuildFile; productRef = 7746ABE12E8BD9DC0046F603 /* RxKeyboard */; }; - 7787BFB92DED80ED0011C907 /* RxKeyboard in Frameworks */ = {isa = PBXBuildFile; productRef = 7787BFB82DED80ED0011C907 /* RxKeyboard */; }; - 77EB17C62DED816D004FB380 /* BaseFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77EB17C52DED816D004FB380 /* BaseFeature.framework */; }; - 77EB17CA2DED81E0004FB380 /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 77EB17C92DED81E0004FB380 /* SnapKit */; }; - 77EB17CC2DED81F2004FB380 /* ReactorKit in Frameworks */ = {isa = PBXBuildFile; productRef = 77EB17CB2DED81F2004FB380 /* ReactorKit */; }; - 77EB18E62DEDA126004FB380 /* Core.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77EB18E12DEDA126004FB380 /* Core.framework */; }; - 77EB18E72DEDA126004FB380 /* Core.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77EB18E12DEDA126004FB380 /* Core.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77EB18E82DEDA126004FB380 /* Data.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77EB18E22DEDA126004FB380 /* Data.framework */; }; - 77EB18E92DEDA126004FB380 /* Data.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77EB18E22DEDA126004FB380 /* Data.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77EB18EA2DEDA126004FB380 /* DomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77EB18E32DEDA126004FB380 /* DomainInterface.framework */; }; - 77EB18EB2DEDA126004FB380 /* DomainInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77EB18E32DEDA126004FB380 /* DomainInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 08501BD72DDCA9DF0055CBCE /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 0858AB362DCFD62C0060EBCA /* Project object */; - proxyType = 1; - remoteGlobalIDString = 08501BC52DDCA9DF0055CBCE; - remoteInfo = AuthFeatureInterface; - }; - 08501BEC2DDCACD20055CBCE /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 0858AB362DCFD62C0060EBCA /* Project object */; - proxyType = 1; - remoteGlobalIDString = 08501BC52DDCA9DF0055CBCE; - remoteInfo = AuthFeatureInterface; - }; - 08686A152DD1C0E300868C70 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 0858AB362DCFD62C0060EBCA /* Project object */; - proxyType = 1; - remoteGlobalIDString = 0858AB3E2DCFD62C0060EBCA; - remoteInfo = AuthFeature; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 77EB18EC2DEDA126004FB380 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 08E424FC2DF0BC5E00D6ACD3 /* AuthFeatureInterface.framework in Embed Frameworks */, - 08E424FE2DF0BC7800D6ACD3 /* DesignSystem.framework in Embed Frameworks */, - 08E424F82DF0BB3C00D6ACD3 /* Domain.framework in Embed Frameworks */, - 77EB18E92DEDA126004FB380 /* Data.framework in Embed Frameworks */, - 08E4255C2DF17D5300D6ACD3 /* DataMock.framework in Embed Frameworks */, - 77EB18EB2DEDA126004FB380 /* DomainInterface.framework in Embed Frameworks */, - 77EB18E72DEDA126004FB380 /* Core.framework in Embed Frameworks */, - 085BDA6E2DF1A4DA009CFB90 /* BaseFeature.framework in Embed Frameworks */, - 08E424FA2DF0BC5C00D6ACD3 /* AuthFeature.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 08501BC62DDCA9DF0055CBCE /* AuthFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AuthFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 0858AB3F2DCFD62C0060EBCA /* AuthFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = AuthFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 0858ABEF2DCFDA450060EBCA /* DesignSystem.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DesignSystem.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 0858ABF32DCFDA510060EBCA /* Presentation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Presentation.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 085BDA612DF18617009CFB90 /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 085BDA6C2DF1A4DA009CFB90 /* BaseFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BaseFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 085BDF562DF459FE009CFB90 /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 086869FE2DD1C08800868C70 /* AuthFeatureDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AuthFeatureDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 08E424F62DF0BB3C00D6ACD3 /* Domain.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Domain.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 08E4255A2DF17D5300D6ACD3 /* DataMock.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DataMock.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 08EECF932DD908D00047AFE2 /* BaseFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BaseFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77EB17C52DED816D004FB380 /* BaseFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BaseFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77EB18E02DEDA126004FB380 /* BaseFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BaseFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77EB18E12DEDA126004FB380 /* Core.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Core.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77EB18E22DEDA126004FB380 /* Data.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Data.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77EB18E32DEDA126004FB380 /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ - 08686A0F2DD1C08A00868C70 /* Exceptions for "AuthFeatureDemo" folder in "AuthFeatureDemo" target */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - membershipExceptions = ( - Info.plist, - ); - target = 086869FD2DD1C08800868C70 /* AuthFeatureDemo */; - }; -/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ - -/* Begin PBXFileSystemSynchronizedRootGroup section */ - 08501BC72DDCA9DF0055CBCE /* AuthFeatureInterface */ = { - isa = PBXFileSystemSynchronizedRootGroup; - path = AuthFeatureInterface; - sourceTree = ""; - }; - 0858AB412DCFD62C0060EBCA /* AuthFeature */ = { - isa = PBXFileSystemSynchronizedRootGroup; - path = AuthFeature; - sourceTree = ""; - }; - 086869FF2DD1C08800868C70 /* AuthFeatureDemo */ = { - isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - 08686A0F2DD1C08A00868C70 /* Exceptions for "AuthFeatureDemo" folder in "AuthFeatureDemo" target */, - ); - path = AuthFeatureDemo; - sourceTree = ""; - }; -/* End PBXFileSystemSynchronizedRootGroup section */ - -/* Begin PBXFrameworksBuildPhase section */ - 08501BC32DDCA9DF0055CBCE /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 085BDF572DF459FE009CFB90 /* DomainInterface.framework in Frameworks */, - 77EB17C62DED816D004FB380 /* BaseFeature.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 0858AB3C2DCFD62C0060EBCA /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 085BDA622DF18617009CFB90 /* DomainInterface.framework in Frameworks */, - 085020682DDCD9640055CBCE /* RxSwift in Frameworks */, - 7787BFB92DED80ED0011C907 /* RxKeyboard in Frameworks */, - 085020662DDCD9640055CBCE /* RxRelay in Frameworks */, - 0850206C2DDCD97E0055CBCE /* ReactorKit in Frameworks */, - 085020612DDCD9250055CBCE /* DesignSystem.framework in Frameworks */, - 0850206A2DDCD9720055CBCE /* SnapKit in Frameworks */, - 08501BEA2DDCACD20055CBCE /* AuthFeatureInterface.framework in Frameworks */, - 085020642DDCD9640055CBCE /* RxCocoa in Frameworks */, - 0850205F2DDCD9240055CBCE /* BaseFeature.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 086869FB2DD1C08800868C70 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 77EB17CA2DED81E0004FB380 /* SnapKit in Frameworks */, - 77EB18E62DEDA126004FB380 /* Core.framework in Frameworks */, - 08E424F92DF0BC5C00D6ACD3 /* AuthFeature.framework in Frameworks */, - 08E425042DF0BCCC00D6ACD3 /* RxCocoa in Frameworks */, - 7746ABE22E8BD9DC0046F603 /* RxKeyboard in Frameworks */, - 08E424F72DF0BB3C00D6ACD3 /* Domain.framework in Frameworks */, - 77EB18E82DEDA126004FB380 /* Data.framework in Frameworks */, - 085BDA6D2DF1A4DA009CFB90 /* BaseFeature.framework in Frameworks */, - 08E425022DF0BCA400D6ACD3 /* RxRelay in Frameworks */, - 08E424FB2DF0BC5E00D6ACD3 /* AuthFeatureInterface.framework in Frameworks */, - 08E424FD2DF0BC7800D6ACD3 /* DesignSystem.framework in Frameworks */, - 77EB17CC2DED81F2004FB380 /* ReactorKit in Frameworks */, - 77EB18EA2DEDA126004FB380 /* DomainInterface.framework in Frameworks */, - 08E4255B2DF17D5300D6ACD3 /* DataMock.framework in Frameworks */, - 08E425002DF0BC9F00D6ACD3 /* RxSwift in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 0858AB352DCFD62C0060EBCA = { - isa = PBXGroup; - children = ( - 0858AB412DCFD62C0060EBCA /* AuthFeature */, - 086869FF2DD1C08800868C70 /* AuthFeatureDemo */, - 08501BC72DDCA9DF0055CBCE /* AuthFeatureInterface */, - 0858ABEE2DCFDA450060EBCA /* Frameworks */, - 0858AB402DCFD62C0060EBCA /* Products */, - ); - sourceTree = ""; - }; - 0858AB402DCFD62C0060EBCA /* Products */ = { - isa = PBXGroup; - children = ( - 0858AB3F2DCFD62C0060EBCA /* AuthFeature.framework */, - 086869FE2DD1C08800868C70 /* AuthFeatureDemo.app */, - 08501BC62DDCA9DF0055CBCE /* AuthFeatureInterface.framework */, - ); - name = Products; - sourceTree = ""; - }; - 0858ABEE2DCFDA450060EBCA /* Frameworks */ = { - isa = PBXGroup; - children = ( - 085BDF562DF459FE009CFB90 /* DomainInterface.framework */, - 085BDA6C2DF1A4DA009CFB90 /* BaseFeature.framework */, - 085BDA612DF18617009CFB90 /* DomainInterface.framework */, - 08E4255A2DF17D5300D6ACD3 /* DataMock.framework */, - 08E424F62DF0BB3C00D6ACD3 /* Domain.framework */, - 77EB18E02DEDA126004FB380 /* BaseFeature.framework */, - 77EB18E12DEDA126004FB380 /* Core.framework */, - 77EB18E22DEDA126004FB380 /* Data.framework */, - 77EB18E32DEDA126004FB380 /* DomainInterface.framework */, - 77EB17C52DED816D004FB380 /* BaseFeature.framework */, - 08EECF932DD908D00047AFE2 /* BaseFeature.framework */, - 0858ABF32DCFDA510060EBCA /* Presentation.framework */, - 0858ABEF2DCFDA450060EBCA /* DesignSystem.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 08501BC12DDCA9DF0055CBCE /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 0858AB3A2DCFD62C0060EBCA /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 08501BC52DDCA9DF0055CBCE /* AuthFeatureInterface */ = { - isa = PBXNativeTarget; - buildConfigurationList = 08501BDF2DDCA9DF0055CBCE /* Build configuration list for PBXNativeTarget "AuthFeatureInterface" */; - buildPhases = ( - 08501BC12DDCA9DF0055CBCE /* Headers */, - 08501BC22DDCA9DF0055CBCE /* Sources */, - 08501BC32DDCA9DF0055CBCE /* Frameworks */, - 08501BC42DDCA9DF0055CBCE /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - fileSystemSynchronizedGroups = ( - 08501BC72DDCA9DF0055CBCE /* AuthFeatureInterface */, - ); - name = AuthFeatureInterface; - packageProductDependencies = ( - ); - productName = AuthFeatureInterface; - productReference = 08501BC62DDCA9DF0055CBCE /* AuthFeatureInterface.framework */; - productType = "com.apple.product-type.framework"; - }; - 0858AB3E2DCFD62C0060EBCA /* AuthFeature */ = { - isa = PBXNativeTarget; - buildConfigurationList = 0858AB452DCFD62C0060EBCA /* Build configuration list for PBXNativeTarget "AuthFeature" */; - buildPhases = ( - 0858AB3A2DCFD62C0060EBCA /* Headers */, - 0858AB3B2DCFD62C0060EBCA /* Sources */, - 0858AB3C2DCFD62C0060EBCA /* Frameworks */, - 0858AB3D2DCFD62C0060EBCA /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 08501BED2DDCACD20055CBCE /* PBXTargetDependency */, - ); - fileSystemSynchronizedGroups = ( - 0858AB412DCFD62C0060EBCA /* AuthFeature */, - ); - name = AuthFeature; - packageProductDependencies = ( - 085020632DDCD9640055CBCE /* RxCocoa */, - 085020652DDCD9640055CBCE /* RxRelay */, - 085020672DDCD9640055CBCE /* RxSwift */, - 085020692DDCD9720055CBCE /* SnapKit */, - 0850206B2DDCD97E0055CBCE /* ReactorKit */, - 7787BFB82DED80ED0011C907 /* RxKeyboard */, - ); - productName = AuthFeature; - productReference = 0858AB3F2DCFD62C0060EBCA /* AuthFeature.framework */; - productType = "com.apple.product-type.framework"; - }; - 086869FD2DD1C08800868C70 /* AuthFeatureDemo */ = { - isa = PBXNativeTarget; - buildConfigurationList = 08686A102DD1C08A00868C70 /* Build configuration list for PBXNativeTarget "AuthFeatureDemo" */; - buildPhases = ( - 086869FA2DD1C08800868C70 /* Sources */, - 086869FB2DD1C08800868C70 /* Frameworks */, - 086869FC2DD1C08800868C70 /* Resources */, - 77EB18EC2DEDA126004FB380 /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 08686A162DD1C0E300868C70 /* PBXTargetDependency */, - 08501BD82DDCA9DF0055CBCE /* PBXTargetDependency */, - ); - fileSystemSynchronizedGroups = ( - 086869FF2DD1C08800868C70 /* AuthFeatureDemo */, - ); - name = AuthFeatureDemo; - packageProductDependencies = ( - 77EB17C92DED81E0004FB380 /* SnapKit */, - 77EB17CB2DED81F2004FB380 /* ReactorKit */, - 08E424FF2DF0BC9F00D6ACD3 /* RxSwift */, - 08E425012DF0BCA400D6ACD3 /* RxRelay */, - 08E425032DF0BCCC00D6ACD3 /* RxCocoa */, - 7746ABE12E8BD9DC0046F603 /* RxKeyboard */, - ); - productName = AuthFeatureDemo; - productReference = 086869FE2DD1C08800868C70 /* AuthFeatureDemo.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 0858AB362DCFD62C0060EBCA /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1620; - LastUpgradeCheck = 1620; - TargetAttributes = { - 08501BC52DDCA9DF0055CBCE = { - CreatedOnToolsVersion = 16.2; - LastSwiftMigration = 1620; - }; - 0858AB3E2DCFD62C0060EBCA = { - CreatedOnToolsVersion = 16.2; - LastSwiftMigration = 1620; - }; - 086869FD2DD1C08800868C70 = { - CreatedOnToolsVersion = 16.2; - }; - }; - }; - buildConfigurationList = 0858AB392DCFD62C0060EBCA /* Build configuration list for PBXProject "AuthFeature" */; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 0858AB352DCFD62C0060EBCA; - minimizedProjectReferenceProxies = 1; - packageReferences = ( - 086869EE2DD1BF8F00868C70 /* XCRemoteSwiftPackageReference "ReactorKit" */, - 086869F12DD1BF9F00868C70 /* XCRemoteSwiftPackageReference "RxSwift" */, - 08686A392DD1C78500868C70 /* XCRemoteSwiftPackageReference "SnapKit" */, - 7787BFB72DED80ED0011C907 /* XCRemoteSwiftPackageReference "RxKeyboard" */, - ); - preferredProjectObjectVersion = 77; - productRefGroup = 0858AB402DCFD62C0060EBCA /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 0858AB3E2DCFD62C0060EBCA /* AuthFeature */, - 08501BC52DDCA9DF0055CBCE /* AuthFeatureInterface */, - 086869FD2DD1C08800868C70 /* AuthFeatureDemo */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 08501BC42DDCA9DF0055CBCE /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 0858AB3D2DCFD62C0060EBCA /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 086869FC2DD1C08800868C70 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 08501BC22DDCA9DF0055CBCE /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 0858AB3B2DCFD62C0060EBCA /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 086869FA2DD1C08800868C70 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 08501BD82DDCA9DF0055CBCE /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 08501BC52DDCA9DF0055CBCE /* AuthFeatureInterface */; - targetProxy = 08501BD72DDCA9DF0055CBCE /* PBXContainerItemProxy */; - }; - 08501BED2DDCACD20055CBCE /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 08501BC52DDCA9DF0055CBCE /* AuthFeatureInterface */; - targetProxy = 08501BEC2DDCACD20055CBCE /* PBXContainerItemProxy */; - }; - 08686A162DD1C0E300868C70 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 0858AB3E2DCFD62C0060EBCA /* AuthFeature */; - targetProxy = 08686A152DD1C0E300868C70 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 08501BDB2DDCA9DF0055CBCE /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = ( - "@executable_path/../Frameworks", - "@loader_path/Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 15.2; - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.AuthFeatureInterface; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = auto; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - XROS_DEPLOYMENT_TARGET = 2.2; - }; - name = Debug; - }; - 08501BDC2DDCA9DF0055CBCE /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = ( - "@executable_path/../Frameworks", - "@loader_path/Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 15.2; - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.AuthFeatureInterface; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = auto; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - XROS_DEPLOYMENT_TARGET = 2.2; - }; - name = Release; - }; - 0858AB462DCFD62C0060EBCA /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.AuthFeature; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 0858AB472DCFD62C0060EBCA /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.AuthFeature; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; - 0858AB482DCFD62C0060EBCA /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.2; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 0858AB492DCFD62C0060EBCA /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.2; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 08686A112DD1C08A00868C70 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5QTRMS954; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = AuthFeatureDemo/Info.plist; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.MLS.AuthFeatureDemo; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = MLSAuthFeatureProvisioningProfileDev; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 08686A122DD1C08A00868C70 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5QTRMS954; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = AuthFeatureDemo/Info.plist; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.MLS.AuthFeatureDemo; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = MLSAuthFeatureProvisioningProfile; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 08501BDF2DDCA9DF0055CBCE /* Build configuration list for PBXNativeTarget "AuthFeatureInterface" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 08501BDB2DDCA9DF0055CBCE /* Debug */, - 08501BDC2DDCA9DF0055CBCE /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 0858AB392DCFD62C0060EBCA /* Build configuration list for PBXProject "AuthFeature" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 0858AB482DCFD62C0060EBCA /* Debug */, - 0858AB492DCFD62C0060EBCA /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 0858AB452DCFD62C0060EBCA /* Build configuration list for PBXNativeTarget "AuthFeature" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 0858AB462DCFD62C0060EBCA /* Debug */, - 0858AB472DCFD62C0060EBCA /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 08686A102DD1C08A00868C70 /* Build configuration list for PBXNativeTarget "AuthFeatureDemo" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 08686A112DD1C08A00868C70 /* Debug */, - 08686A122DD1C08A00868C70 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - 086869EE2DD1BF8F00868C70 /* XCRemoteSwiftPackageReference "ReactorKit" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ReactorKit/ReactorKit"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 3.2.0; - }; - }; - 086869F12DD1BF9F00868C70 /* XCRemoteSwiftPackageReference "RxSwift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ReactiveX/RxSwift"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 6.9.0; - }; - }; - 08686A392DD1C78500868C70 /* XCRemoteSwiftPackageReference "SnapKit" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/SnapKit/SnapKit.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 5.7.1; - }; - }; - 7787BFB72DED80ED0011C907 /* XCRemoteSwiftPackageReference "RxKeyboard" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/RxSwiftCommunity/RxKeyboard.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.0.1; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 085020632DDCD9640055CBCE /* RxCocoa */ = { - isa = XCSwiftPackageProductDependency; - package = 086869F12DD1BF9F00868C70 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxCocoa; - }; - 085020652DDCD9640055CBCE /* RxRelay */ = { - isa = XCSwiftPackageProductDependency; - package = 086869F12DD1BF9F00868C70 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxRelay; - }; - 085020672DDCD9640055CBCE /* RxSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 086869F12DD1BF9F00868C70 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxSwift; - }; - 085020692DDCD9720055CBCE /* SnapKit */ = { - isa = XCSwiftPackageProductDependency; - package = 08686A392DD1C78500868C70 /* XCRemoteSwiftPackageReference "SnapKit" */; - productName = SnapKit; - }; - 0850206B2DDCD97E0055CBCE /* ReactorKit */ = { - isa = XCSwiftPackageProductDependency; - package = 086869EE2DD1BF8F00868C70 /* XCRemoteSwiftPackageReference "ReactorKit" */; - productName = ReactorKit; - }; - 08E424FF2DF0BC9F00D6ACD3 /* RxSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 086869F12DD1BF9F00868C70 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxSwift; - }; - 08E425012DF0BCA400D6ACD3 /* RxRelay */ = { - isa = XCSwiftPackageProductDependency; - package = 086869F12DD1BF9F00868C70 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxRelay; - }; - 08E425032DF0BCCC00D6ACD3 /* RxCocoa */ = { - isa = XCSwiftPackageProductDependency; - package = 086869F12DD1BF9F00868C70 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxCocoa; - }; - 7746ABE12E8BD9DC0046F603 /* RxKeyboard */ = { - isa = XCSwiftPackageProductDependency; - package = 7787BFB72DED80ED0011C907 /* XCRemoteSwiftPackageReference "RxKeyboard" */; - productName = RxKeyboard; - }; - 7787BFB82DED80ED0011C907 /* RxKeyboard */ = { - isa = XCSwiftPackageProductDependency; - package = 7787BFB72DED80ED0011C907 /* XCRemoteSwiftPackageReference "RxKeyboard" */; - productName = RxKeyboard; - }; - 77EB17C92DED81E0004FB380 /* SnapKit */ = { - isa = XCSwiftPackageProductDependency; - package = 08686A392DD1C78500868C70 /* XCRemoteSwiftPackageReference "SnapKit" */; - productName = SnapKit; - }; - 77EB17CB2DED81F2004FB380 /* ReactorKit */ = { - isa = XCSwiftPackageProductDependency; - package = 086869EE2DD1BF8F00868C70 /* XCRemoteSwiftPackageReference "ReactorKit" */; - productName = ReactorKit; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 0858AB362DCFD62C0060EBCA /* Project object */; -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/MLS/Presentation/AuthFeature/AuthFeature.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a6..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginFactoryImpl.swift b/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginFactoryImpl.swift deleted file mode 100644 index a75289b0..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginFactoryImpl.swift +++ /dev/null @@ -1,65 +0,0 @@ -import AuthFeatureInterface -import BaseFeature -import DomainInterface - -import RxSwift - -public struct LoginFactoryImpl: LoginFactory { - private let termsAgreementsFactory: TermsAgreementFactory - private let appleLoginUseCase: FetchSocialCredentialUseCase - private let kakaoLoginUseCase: FetchSocialCredentialUseCase - private let loginWithAppleUseCase: LoginWithAppleUseCase - private let loginWithKakaoUseCase: LoginWithKakaoUseCase - private let fetchTokenUseCase: FetchTokenFromLocalUseCase - private let putFCMTokenUseCase: PutFCMTokenUseCase - private let fetchPlatformUseCase: FetchPlatformUseCase - - public init( - termsAgreementsFactory: TermsAgreementFactory, - appleLoginUseCase: FetchSocialCredentialUseCase, - kakaoLoginUseCase: FetchSocialCredentialUseCase, - loginWithAppleUseCase: LoginWithAppleUseCase, - loginWithKakaoUseCase: LoginWithKakaoUseCase, - fetchTokenUseCase: FetchTokenFromLocalUseCase, - putFCMTokenUseCase: PutFCMTokenUseCase, - fetchPlatformUseCase: FetchPlatformUseCase - ) { - self.termsAgreementsFactory = termsAgreementsFactory - self.appleLoginUseCase = appleLoginUseCase - self.kakaoLoginUseCase = kakaoLoginUseCase - self.loginWithAppleUseCase = loginWithAppleUseCase - self.loginWithKakaoUseCase = loginWithKakaoUseCase - self.fetchTokenUseCase = fetchTokenUseCase - self.putFCMTokenUseCase = putFCMTokenUseCase - self.fetchPlatformUseCase = fetchPlatformUseCase - } - - public func make(exitRoute: LoginExitRoute, onLoginCompleted: (() -> Void)?) -> BaseViewController { - let viewController = LoginViewController(termsAgreementsFactory: termsAgreementsFactory) - viewController.isBottomTabbarHidden = true - - viewController.reactor = LoginReactor( - fetchAppleCredentialUseCase: appleLoginUseCase, - fetchKakaoCredentialUseCase: kakaoLoginUseCase, - loginWithAppleUseCase: loginWithAppleUseCase, - loginWithKakaoUseCase: loginWithKakaoUseCase, - fetchTokenUseCase: fetchTokenUseCase, - putFCMTokenUseCase: putFCMTokenUseCase, - fetchPlatformUseCase: fetchPlatformUseCase - ) - - viewController.routeToHome - .observe(on: MainScheduler.instance) - .subscribe(onNext: { [weak viewController] in - switch exitRoute { - case .home: - onLoginCompleted?() - case .pop: - viewController?.navigationController?.popViewController(animated: true) - } - }) - .disposed(by: viewController.disposeBag) - - return viewController - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginReactor.swift b/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginReactor.swift deleted file mode 100644 index 7bf0b45d..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginReactor.swift +++ /dev/null @@ -1,196 +0,0 @@ -import DomainInterface -import NotificationCenter - -import ReactorKit -import RxSwift - -public final class LoginReactor: Reactor { - public enum Route { - case none - case termsAgreements(credential: Credential, platform: LoginPlatform) - case error - case home - case dismiss - } - - // MARK: - Reactor - public enum Action { - case viewWillAppear - case kakaoLoginButtonTapped - case appleLoginButtonTapped - case guestLoginButtonTapped - case backButtonTapped - } - - public enum Mutation { - case navigateTo(route: Route) - case setRelogin(LoginPlatform?) - } - - public struct State { - @Pulse var route: Route = .none - var platform: LoginPlatform? - } - - // MARK: - properties - public var initialState: State - var disposeBag = DisposeBag() - private let fetchAppleCredentialUseCase: FetchSocialCredentialUseCase - private let fetchKakaoCredentialUseCase: FetchSocialCredentialUseCase - private let loginWithAppleUseCase: LoginWithAppleUseCase - private let loginWithKakaoUseCase: LoginWithKakaoUseCase - private let fetchTokenUseCase: FetchTokenFromLocalUseCase - private let putFCMTokenUseCase: PutFCMTokenUseCase - private let fetchPlatformUseCase: FetchPlatformUseCase - - // MARK: - init - public init( - fetchAppleCredentialUseCase: FetchSocialCredentialUseCase, - fetchKakaoCredentialUseCase: FetchSocialCredentialUseCase, - loginWithAppleUseCase: LoginWithAppleUseCase, - loginWithKakaoUseCase: LoginWithKakaoUseCase, - fetchTokenUseCase: FetchTokenFromLocalUseCase, - putFCMTokenUseCase: PutFCMTokenUseCase, - fetchPlatformUseCase: FetchPlatformUseCase - ) { - self.fetchAppleCredentialUseCase = fetchAppleCredentialUseCase - self.fetchKakaoCredentialUseCase = fetchKakaoCredentialUseCase - self.loginWithAppleUseCase = loginWithAppleUseCase - self.loginWithKakaoUseCase = loginWithKakaoUseCase - self.fetchTokenUseCase = fetchTokenUseCase - self.putFCMTokenUseCase = putFCMTokenUseCase - self.fetchPlatformUseCase = fetchPlatformUseCase - self.initialState = State() - } - - // MARK: - Reactor Methods - public func mutate(action: Action) -> Observable { - switch action { - case .viewWillAppear: - return fetchPlatformUseCase.execute() - .map { Mutation.setRelogin($0) } - case .kakaoLoginButtonTapped: - return handleKakaoLogin() - case .appleLoginButtonTapped: - return handleAppleLogin() - case .guestLoginButtonTapped: - return .just(.navigateTo(route: .home)) - case .backButtonTapped: - return .just(.navigateTo(route: .dismiss)) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - switch mutation { - case .navigateTo(let route): - newState.route = route - case .setRelogin(let platform): - newState.platform = platform - } - return newState - } -} - -// MARK: - Methods -private extension LoginReactor { - func handleKakaoLogin() -> Observable { - return checkNotificationPermissionAndFetchFCMToken() - .withUnretained(self) - .flatMap { owner, fcmToken in - // 1. 카카오 로그인 자격 증명 가져오기 - owner.fetchKakaoCredentialUseCase.execute() - .flatMap { credential in - // 2. 자격 증명을 바탕으로 로그인 요청 - owner.loginWithKakaoUseCase.execute(credential: credential) - .flatMap { response -> Observable in - if response.isRegister { - // 3. 회원가입된 유저면 FCM 토큰 등록 후 홈으로 이동 - return owner.putFCMTokenUseCase.execute(fcmToken: fcmToken) - .andThen(.just(.navigateTo(route: .home))) - } else { - // 4. 미가입 유저면 약관 동의 화면으로 이동 - return .just(.navigateTo(route: .termsAgreements( - credential: credential, - platform: .kakao - ))) - } - } - .catch { error in - // 5. 로그인 실패 예외 처리 - if case AuthError.userNotFound = error { - return .just(.navigateTo(route: .termsAgreements( - credential: credential, - platform: .kakao - ))) - } else { - return .just(.navigateTo(route: .error)) - } - } - } - } - } - - func handleAppleLogin() -> Observable { - return checkNotificationPermissionAndFetchFCMToken() - .withUnretained(self) - .flatMap { owner, fcmToken in - // 1. 애플 로그인 자격 증명 가져오기 - owner.fetchAppleCredentialUseCase.execute() - .flatMap { credential in - // 2. 자격 증명을 바탕으로 로그인 요청 - owner.loginWithAppleUseCase.execute(credential: credential) - .flatMap { response -> Observable in - if response.isRegister { - // 3. 회원가입된 유저면 FCM 토큰 등록 후 홈으로 이동 - return owner.putFCMTokenUseCase.execute(fcmToken: fcmToken) - .andThen(.just(.navigateTo(route: .home))) - } else { - // 4. 미가입 유저면 약관 동의 화면으로 이동 - return .just(.navigateTo(route: .termsAgreements( - credential: credential, - platform: .apple - ))) - } - } - .catch { error in - // 5. 로그인 실패 예외 처리 - if case AuthError.userNotFound = error { - return .just(.navigateTo(route: .termsAgreements( - credential: credential, - platform: .apple - ))) - } else { - return .just(.navigateTo(route: .error)) - } - } - } - } - } - - func checkNotificationPermissionAndFetchFCMToken() -> Observable { - return Observable.create { [weak self] observer in - guard let self else { - observer.onNext(nil) - observer.onCompleted() - return Disposables.create() - } - - UNUserNotificationCenter.current().getNotificationSettings { settings in - switch settings.authorizationStatus { - case .authorized, .provisional, .ephemeral: - let result = self.fetchTokenUseCase.execute(type: .fcmToken) - switch result { - case .success(let token): observer.onNext(token) - case .failure: observer.onNext(nil) - } - default: - observer.onNext(nil) - } - observer.onCompleted() - } - - return Disposables.create() - } - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginView.swift b/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginView.swift deleted file mode 100644 index f6f1fa32..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginView.swift +++ /dev/null @@ -1,238 +0,0 @@ -import UIKit - -import DesignSystem -import DomainInterface - -import SnapKit - -final class LoginView: UIView { - // MARK: - Type - private enum Constant { - static let buttonLogoImageSize: CGFloat = 18 - static let buttonLogoImageLeadingInset: CGFloat = 14 - static let buttonHeight: CGFloat = 44 - static let buttonCornerRadius: CGFloat = 8 - static let buttonSpacing: CGFloat = 8 - static let buttonStackViewBottomInset: CGFloat = 16 - static let horizontalInset: CGFloat = 16 - static let buttonCenterXInset: CGFloat = buttonLogoImageLeadingInset + buttonLogoImageSize - static let labelHeight: CGFloat = 28 - static let subTitleBottomSpacing: CGFloat = -25 - static let recentLogoWidth: CGFloat = 82 - static let recentLogoHeight: CGFloat = 30 - static let recentLogoInset: CGFloat = 8 - } - - // MARK: - Properties - public let header = NavigationBar(type: .arrowLeft) - - private let loginImageView: UIImageView = { - let image = DesignSystemAsset.image(named: "Login_KV_img") - let view = UIImageView(image: image) - return view - }() - - private let buttonStackView: UIStackView = { - let view = UIStackView() - view.axis = .vertical - view.spacing = Constant.buttonSpacing - return view - }() - - let kakaoLoginButton: UIButton = { - let button = UIButton() - button.backgroundColor = .init(hexCode: "#FEE500", alpha: 1) - button.layer.cornerRadius = Constant.buttonCornerRadius - return button - }() - - private let kakaoLogoImageView: UIImageView = { - let image = DesignSystemAsset.image(named: "kakaoLogo") - let view = UIImageView(image: image) - view.contentMode = .scaleAspectFit - return view - }() - - private let kakaoLoginLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .korFont(style: .semiBold, size: 15), text: "카카오로 계속하기", color: .init(hexCode: "#000000", alpha: 0.85)) - return label - }() - - let appleLoginButton: UIButton = { - let button = UIButton() - button.backgroundColor = .init(hexCode: "#000000", alpha: 1) - button.layer.cornerRadius = Constant.buttonCornerRadius - return button - }() - - private let appleLogoImageView: UIImageView = { - let image = DesignSystemAsset.image(named: "appleLogo") - let view = UIImageView(image: image) - view.contentMode = .scaleAspectFit - return view - }() - - let appleLoginLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .korFont(style: .semiBold, size: 15), text: "Apple로 계속하기", color: .init(hexCode: "#FFFFFF")) - return label - }() - - let guestLoginButton: CommonButton = { - let button = CommonButton(style: .text, title: "가입 없이 둘러보기", disabledTitle: "가입 없이 둘러보기") - return button - }() - - private let mainTitleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .h_xl_b, text: "모험가님,") - return label - }() - - private let subTitleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .h_xl_r, text: "다시 오신 걸 환영해요!") - return label - }() - - private let recentLoginImageView: UIImageView = { - let view = UIImageView(image: DesignSystemAsset.image(named: "recentLoginLogo")) - view.isHidden = true - return view - }() - - // MARK: - init - init() { - super.init(frame: .zero) - - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension LoginView { - func addViews() { - addSubview(loginImageView) - addSubview(buttonStackView) - addSubview(recentLoginImageView) - - buttonStackView.addArrangedSubview(kakaoLoginButton) - buttonStackView.addArrangedSubview(appleLoginButton) - - kakaoLoginButton.addSubview(kakaoLogoImageView) - kakaoLoginButton.addSubview(kakaoLoginLabel) - appleLoginButton.addSubview(appleLogoImageView) - appleLoginButton.addSubview(appleLoginLabel) - - addSubview(header) - } - - func setupConstraints() { - header.snp.makeConstraints { make in - make.top.horizontalEdges.equalTo(safeAreaLayoutGuide) - } - - loginImageView.snp.makeConstraints { make in - make.width.equalToSuperview() - make.height.equalTo(UIScreen.main.bounds.width * 1.49) - make.top.horizontalEdges.equalToSuperview() - } - - buttonStackView.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.bottom.equalToSuperview().inset(Constant.buttonStackViewBottomInset) - } - - kakaoLoginButton.snp.makeConstraints { make in - make.height.equalTo(Constant.buttonHeight) - } - - kakaoLogoImageView.snp.makeConstraints { make in - make.centerY.equalToSuperview() - make.leading.equalToSuperview().inset(Constant.buttonLogoImageLeadingInset) - make.size.equalTo(Constant.buttonLogoImageSize) - } - - kakaoLoginLabel.snp.makeConstraints { make in - make.centerY.equalToSuperview() - make.centerX.equalToSuperview().inset(Constant.buttonCenterXInset) - } - - appleLoginButton.snp.makeConstraints { make in - make.height.equalTo(Constant.buttonHeight) - } - - appleLogoImageView.snp.makeConstraints { make in - make.centerY.equalToSuperview() - make.leading.equalToSuperview().inset(Constant.buttonLogoImageLeadingInset) - make.size.equalTo(Constant.buttonLogoImageSize) - } - - appleLoginLabel.snp.makeConstraints { make in - make.centerY.equalToSuperview() - make.centerX.equalToSuperview().inset(Constant.buttonCenterXInset) - } - } - - func configureUI() {} -} - -extension LoginView { - func update(loginPlatform: LoginPlatform?) { - mainTitleLabel.removeFromSuperview() - subTitleLabel.removeFromSuperview() - guestLoginButton.removeFromSuperview() - - switch loginPlatform { - case .kakao, .apple: - // 최근로그인 라벨 추가 - addSubview(mainTitleLabel) - addSubview(subTitleLabel) - - subTitleLabel.snp.remakeConstraints { make in - make.bottom.equalTo(buttonStackView.snp.top).offset(Constant.subTitleBottomSpacing) - make.centerX.equalToSuperview() - make.height.equalTo(Constant.labelHeight) - } - mainTitleLabel.snp.remakeConstraints { make in - make.bottom.equalTo(subTitleLabel.snp.top) - make.centerX.equalToSuperview() - make.height.equalTo(Constant.labelHeight) - } - - recentLoginImageView.isHidden = false - - recentLoginImageView.snp.remakeConstraints { make in - switch loginPlatform { - case .apple: - make.leading.equalTo(appleLoginButton).offset(Constant.recentLogoInset) - make.bottom.equalTo(appleLoginButton.snp.top).offset(Constant.recentLogoInset) - case .kakao: - make.leading.equalTo(kakaoLoginButton).offset(Constant.recentLogoInset) - make.bottom.equalTo(kakaoLoginButton.snp.top).offset(Constant.recentLogoInset) - default: - break - } - make.width.equalTo(Constant.recentLogoWidth) - make.height.equalTo(Constant.recentLogoHeight) - } - case nil: - buttonStackView.addArrangedSubview(guestLoginButton) - guestLoginButton.snp.remakeConstraints { make in - make.height.equalTo(Constant.buttonHeight) - } - recentLoginImageView.isHidden = true - } - - setNeedsLayout() - layoutIfNeeded() - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginViewController.swift b/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginViewController.swift deleted file mode 100644 index 0fc4c2ba..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/Login/LoginViewController.swift +++ /dev/null @@ -1,168 +0,0 @@ -import UIKit - -import AuthFeatureInterface -import BaseFeature - -import ReactorKit -import RxCocoa -import RxSwift -import SnapKit - -public final class LoginViewController: BaseViewController, View { - public typealias Reactor = LoginReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - public let routeToHome = PublishRelay() - - private let mainView: LoginView - - private let termsAgreementsFactory: TermsAgreementFactory - - public init(termsAgreementsFactory: TermsAgreementFactory) { - self.mainView = LoginView() - self.termsAgreementsFactory = termsAgreementsFactory - super.init() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -public extension LoginViewController { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension LoginViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.top.horizontalEdges.equalToSuperview() - make.bottom.equalTo(view.safeAreaLayoutGuide) - } - } - - func configureUI() { - view.backgroundColor = .systemBackground - - if let navigationController = navigationController, - navigationController.viewControllers.count > 1 { - mainView.header.leftButton.isHidden = false - } else { - mainView.header.leftButton.isHidden = true - } - } -} - -public extension LoginViewController { - func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .map { _ in Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.kakaoLoginButton.rx.tap - .map { Reactor.Action.kakaoLoginButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.kakaoLoginButton.rx.controlEvent(.touchDown) - .withUnretained(self) - .subscribe { owner, _ in - owner.mainView.kakaoLoginButton.backgroundColor = .init(hexCode: "#E5CE00") - } - .disposed(by: disposeBag) - - mainView.kakaoLoginButton.rx.controlEvent([.touchUpInside, .touchUpOutside, .touchCancel]) - .withUnretained(self) - .subscribe { owner, _ in - owner.mainView.kakaoLoginButton.backgroundColor = .init(hexCode: "#FEE500") - } - .disposed(by: disposeBag) - - mainView.appleLoginButton.rx.tap - .map { Reactor.Action.appleLoginButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.appleLoginButton.rx.controlEvent(.touchDown) - .withUnretained(self) - .subscribe { owner, _ in - owner.mainView.appleLoginLabel.textColor = .init(hexCode: "#E5E5E5") - } - .disposed(by: disposeBag) - - mainView.appleLoginButton.rx.controlEvent([.touchUpInside, .touchUpOutside, .touchCancel]) - .withUnretained(self) - .subscribe { owner, _ in - owner.mainView.appleLoginLabel.textColor = .whiteMLS - } - .disposed(by: disposeBag) - - mainView.guestLoginButton.rx.tap - .map { Reactor.Action.guestLoginButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.header.leftButton.rx.tap - .map { Reactor.Action.backButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - reactor.state - .observe(on: MainScheduler.instance) - .map { $0.platform } - .distinctUntilChanged() - .withUnretained(self) - .subscribe { owner, platform in - owner.mainView.update(loginPlatform: platform) - } - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .observe(on: MainScheduler.instance) - .withUnretained(self) - .subscribe { owner, route in - switch route { - case .termsAgreements(let credential, let platform): - let controller = owner.termsAgreementsFactory.make(credential: credential, platform: platform) - owner.navigationController?.pushViewController(controller, animated: true) - case .home: - owner.routeToHome.accept(()) - case .error: - DispatchQueue.main.async { - let controller = BaseErrorViewController() - owner.present(controller, animated: true) - } - case .dismiss: - owner.navigationController?.popViewController(animated: true) - default: - break - } - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationFactoryImpl.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationFactoryImpl.swift deleted file mode 100644 index dbccc528..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationFactoryImpl.swift +++ /dev/null @@ -1,19 +0,0 @@ -import AuthFeatureInterface -import BaseFeature - -public struct OnBoardingNotificationFactoryImpl: OnBoardingNotificationFactory { - private let onBoardingNotificationSheetFactory: OnBoardingNotificationSheetFactory - private let appCoordinator: () -> AppCoordinatorProtocol - - public init(onBoardingNotificationSheetFactory: OnBoardingNotificationSheetFactory, appCoordinator: @escaping () -> AppCoordinatorProtocol) { - self.onBoardingNotificationSheetFactory = onBoardingNotificationSheetFactory - self.appCoordinator = appCoordinator - } - - public func make(selectedLevel: Int, selectedJobID: Int) -> BaseViewController { - let viewController = OnBoardingNotificationViewController(onBoardingNotificationSheetFactory: onBoardingNotificationSheetFactory, appCoordinator: appCoordinator()) - viewController.isBottomTabbarHidden = true - viewController.reactor = OnBoardingNotificationReactor(selectedLevel: selectedLevel, selectedJobID: selectedJobID) - return viewController - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationReactor.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationReactor.swift deleted file mode 100644 index 042dc04e..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationReactor.swift +++ /dev/null @@ -1,60 +0,0 @@ -import ReactorKit -import RxSwift - -public final class OnBoardingNotificationReactor: Reactor { - // MARK: - Reactor - public enum Route { - case none - case notificationAlert - case pop - case home - } - - public enum Action { - case nextButtonTapped - case skipButtonTapped - case backButtonTapped - } - - public enum Mutation { - case navigateTo(route: Route) - } - - public struct State { - @Pulse var route: Route = .none - let selectedLevel: Int - let selectedJobID: Int - } - - // MARK: - properties - public var initialState: State - var disposeBag = DisposeBag() - - // MARK: - init - public init(selectedLevel: Int, selectedJobID: Int) { - self.initialState = State(selectedLevel: selectedLevel, selectedJobID: selectedJobID) - } - - // MARK: - Reactor Methods - public func mutate(action: Action) -> Observable { - switch action { - case .nextButtonTapped: - return .just(.navigateTo(route: .notificationAlert)) - case .skipButtonTapped: - return .just(.navigateTo(route: .home)) - case .backButtonTapped: - return .just(.navigateTo(route: .pop)) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .navigateTo(let route): - newState.route = route - } - - return newState - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationView.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationView.swift deleted file mode 100644 index 2be88be7..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationView.swift +++ /dev/null @@ -1,82 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -public final class OnBoardingNotificationView: OnBoardingBaseView { - // MARK: - Type - private enum Constant { - static let horizontalInset = 16 - static let verticalInset = 16 - static let imgSize = 220 - static let resizeCenterY = 70 - } - - // MARK: - Components - private let imageView: UIImageView = { - let view = UIImageView() - view.image = DesignSystemAsset.image(named: "getNotify") - return view - }() - - private let boldTextLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .h_xxl_b, text: "메이플랜드에서 이벤트가 생기면\n알림을 보내드리고 있어요") - label.numberOfLines = 2 - return label - }() - - private lazy var contentView: UIView = { - let view = UIView() - view.addSubview(imageView) - view.addSubview(boldTextLabel) - - imageView.snp.makeConstraints { make in - make.top.equalToSuperview() - make.centerX.equalToSuperview() - make.size.equalTo(Constant.imgSize) - } - - boldTextLabel.snp.makeConstraints { make in - make.top.equalTo(imageView.snp.bottom).offset(4) - make.horizontalEdges.bottom.equalToSuperview() - } - - return view - }() - - public let nextButton = CommonButton(style: .normal, title: "다음", disabledTitle: "") - - // MARK: - init - init() { - super.init() - addViews() - setupConstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension OnBoardingNotificationView { - func addViews() { - addSubview(contentView) - addSubview(nextButton) - } - - func setupConstraints() { - contentView.snp.makeConstraints { make in - make.centerY.equalToSuperview().offset(-Constant.resizeCenterY) - make.horizontalEdges.equalToSuperview() - } - - nextButton.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.bottom.equalTo(safeAreaLayoutGuide).inset(Constant.verticalInset) - } - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationViewController.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationViewController.swift deleted file mode 100644 index 08566c23..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoadingNotification/OnBoardingNotificationViewController.swift +++ /dev/null @@ -1,112 +0,0 @@ -import UIKit -import UserNotifications - -import AuthFeatureInterface -import BaseFeature -import DictionaryFeatureInterface - -import ReactorKit -import RxCocoa -import RxSwift -import SnapKit - -public class OnBoardingNotificationViewController: BaseViewController, View { - // MARK: - Properties - public typealias Reactor = OnBoardingNotificationReactor - - public var disposeBag = DisposeBag() - - private let onBoardingNotificationSheetFactory: OnBoardingNotificationSheetFactory - private let appCoordinator: AppCoordinatorProtocol - - // MARK: - Components - - private var mainView = OnBoardingNotificationView() - - public init(onBoardingNotificationSheetFactory: OnBoardingNotificationSheetFactory, appCoordinator: AppCoordinatorProtocol) { - self.onBoardingNotificationSheetFactory = onBoardingNotificationSheetFactory - self.appCoordinator = appCoordinator - super.init() - } - - @available(*, unavailable) - @MainActor required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -public extension OnBoardingNotificationViewController { - override func viewDidLoad() { - super.viewDidLoad() - configureUI() - } -} - -// MARK: - SetUp -private extension OnBoardingNotificationViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } - - func configureUI() { - addViews() - setupConstraints() - } -} - -// MARK: - Private Methods -private extension OnBoardingNotificationViewController {} - -// MARK: - Bind -public extension OnBoardingNotificationViewController { - func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - mainView.nextButton.rx.tap - .map { Reactor.Action.nextButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.headerView.leftButton.rx.tap - .map { Reactor.Action.backButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.headerView.underlineTextButton.rx.tap - .map { Reactor.Action.skipButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, route in - switch route { - case .notificationAlert: - let viewController = owner.onBoardingNotificationSheetFactory.make(selectedLevel: reactor.currentState.selectedLevel, selectedJobID: reactor.currentState.selectedJobID) - owner.presentModal(viewController, hideTabBar: true) - case .home: - owner.appCoordinator.showMainTab() - case .pop: - owner.navigationController?.popViewController(animated: true) - default: - break - } - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoarding/OnBoardingBaseView.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoarding/OnBoardingBaseView.swift deleted file mode 100644 index 3f25b5f4..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoarding/OnBoardingBaseView.swift +++ /dev/null @@ -1,44 +0,0 @@ -import UIKit - -import DesignSystem - -/// 온보딩 화면에서 사용하기 위한 헤더(타이틀 버튼 포함)를 가진 뷰 -public class OnBoardingBaseView: UIView { - // MARK: - Components - public let headerView: NavigationBar = { - let view = NavigationBar(type: .withUnderLine("다음에 하기")) - return view - }() - - // MARK: - init - init(leftButtonIsHidden: Bool = false, underlineTextButtonIsHidden: Bool = false) { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - if leftButtonIsHidden { headerView.leftButton.isHidden = true } - if underlineTextButtonIsHidden { headerView.underlineTextButton.isHidden = true } - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension OnBoardingBaseView { - func addViews() { - addSubview(headerView) - } - - func setupConstraints() { - headerView.snp.makeConstraints { make in - make.top.horizontalEdges.equalToSuperview() - } - } - - func configureUI() { - backgroundColor = .clearMLS - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputFactoryImpl.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputFactoryImpl.swift deleted file mode 100644 index 19243aeb..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputFactoryImpl.swift +++ /dev/null @@ -1,40 +0,0 @@ -import AuthFeatureInterface -import BaseFeature -import DictionaryFeatureInterface -import DomainInterface - -public struct OnBoardingInputFactoryImpl: OnBoardingInputFactory { - private let checkEmptyUseCase: CheckEmptyLevelAndRoleUseCase - private let checkValidLevelUseCase: CheckValidLevelUseCase - private let fetchJobListUseCase: FetchJobListUseCase - private let updateUserInfoUseCase: UpdateUserInfoUseCase - private let onBoardingNotificationFactory: OnBoardingNotificationFactory - private let appCoordinator: () -> AppCoordinatorProtocol - - public init( - checkEmptyUseCase: CheckEmptyLevelAndRoleUseCase, - checkValidLevelUseCase: CheckValidLevelUseCase, - fetchJobListUseCase: FetchJobListUseCase, - updateUserInfoUseCase: UpdateUserInfoUseCase, - onBoardingNotificationFactory: OnBoardingNotificationFactory, - appCoordinator: @escaping () -> AppCoordinatorProtocol - ) { - self.checkEmptyUseCase = checkEmptyUseCase - self.checkValidLevelUseCase = checkValidLevelUseCase - self.fetchJobListUseCase = fetchJobListUseCase - self.updateUserInfoUseCase = updateUserInfoUseCase - self.onBoardingNotificationFactory = onBoardingNotificationFactory - self.appCoordinator = appCoordinator - } - - public func make() -> BaseViewController { - let viewController = OnBoardingInputViewController(onBoardingNotificationFactory: onBoardingNotificationFactory, appCoordinator: appCoordinator()) - viewController.isBottomTabbarHidden = true - viewController.reactor = OnBoardingInputReactor( - checkEmptyUseCase: checkEmptyUseCase, - checkValidLevelUseCase: checkValidLevelUseCase, - fetchJobListUseCase: fetchJobListUseCase - ) - return viewController - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputReactor.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputReactor.swift deleted file mode 100644 index 84b244c8..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputReactor.swift +++ /dev/null @@ -1,115 +0,0 @@ -import DomainInterface - -import ReactorKit -import RxSwift - -public final class OnBoardingInputReactor: Reactor { - // MARK: - Reactor - public enum Route { - case none - case dismiss - case home - case notification - case error - } - - public enum Action { - case viewWillAppear - case backButtonTapped - case skipButtonTapped - case nextButtonTapped - case inputLevel(Int?) - case inputRole(Job?) - } - - public enum Mutation { - case setJobList(jobList: [Job]) - case setButtonEnabled(Bool) - case setLevelValid(Bool?) - case setLevel(Int?) - case setRole(Job?) - case navigateTo(route: Route) - } - - public struct State { - @Pulse var route: Route = .none - - var level: Int? - var job: Job? - var isButtonEnabled: Bool = false - var isLevelValid: Bool? - var jobList: [Job] = [] - } - - // MARK: - properties - public var initialState: State - var disposeBag = DisposeBag() - - private let checkEmptyUseCase: CheckEmptyLevelAndRoleUseCase - private let checkValidLevelUseCase: CheckValidLevelUseCase - private let fetchJobListUseCase: FetchJobListUseCase - - // MARK: - init - public init( - checkEmptyUseCase: CheckEmptyLevelAndRoleUseCase, - checkValidLevelUseCase: CheckValidLevelUseCase, - fetchJobListUseCase: FetchJobListUseCase - ) { - self.checkEmptyUseCase = checkEmptyUseCase - self.checkValidLevelUseCase = checkValidLevelUseCase - self.fetchJobListUseCase = fetchJobListUseCase - self.initialState = State() - } - - // MARK: - Reactor Methods - public func mutate(action: Action) -> Observable { - switch action { - case .viewWillAppear: - return fetchJobListUseCase.execute() - .map { response in - .setJobList(jobList: response.jobList) - } - .catchAndReturn(.navigateTo(route: .error)) - case .backButtonTapped: - return Observable.just(.navigateTo(route: .dismiss)) - case .skipButtonTapped: - return Observable.just(.navigateTo(route: .home)) - case .nextButtonTapped: - return Observable.just(.navigateTo(route: .notification)) - case .inputLevel(let level): - let changeLevel = Observable.just(Mutation.setLevel(level)) - let validateJob = checkEmptyUseCase.execute(level: level, job: currentState.job?.name) - .map(Mutation.setButtonEnabled) - let validateLevel = checkValidLevelUseCase.execute(level: level) - .map(Mutation.setLevelValid) - return .merge(changeLevel, validateJob, validateLevel) - case .inputRole(let job): - return checkEmptyUseCase.execute(level: currentState.level, job: job?.name) - .map { isValid in - [.setRole(job), .setButtonEnabled(isValid)] - } - .flatMap { Observable.from($0) } - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .setJobList(let jobList): - newState.jobList = jobList - case .setButtonEnabled(let isEnabled): - newState.isButtonEnabled = isEnabled - case .setLevelValid(let isValid): - newState.isLevelValid = isValid - case .setLevel(let level): - newState.level = level - case .setRole(let role): - newState.job = role - case .navigateTo(let route): - newState.route = route - } - - return newState - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputView.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputView.swift deleted file mode 100644 index e21e0f05..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputView.swift +++ /dev/null @@ -1,57 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem - -import RxCocoa -import RxSwift -import SnapKit - -public final class OnBoardingInputView: CharacterInputView { - // MARK: - Type - - // MARK: - Properties - - // MARK: - Components - public let headerView: NavigationBar = { - let view = NavigationBar(type: .withUnderLine("다음에 하기")) - return view - }() - - // MARK: - init - init(leftButtonIsHidden: Bool = false, underlineTextButtonIsHidden: Bool = false) { - super.init() - addViews() - setupConstraints() - configureUI() - if leftButtonIsHidden { headerView.leftButton.isHidden = true } - if underlineTextButtonIsHidden { headerView.underlineTextButton.isHidden = true } - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension OnBoardingInputView { - func addViews() { - addSubview(headerView) - } - - func setupConstraints() { - headerView.snp.makeConstraints { make in - make.top.horizontalEdges.equalToSuperview() - } - - descriptionLabel.snp.makeConstraints { make in - make.top.equalTo(headerView.snp.bottom).offset(Constant.verticalInset) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - } - } - - func configureUI() { - backgroundColor = .clearMLS - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputViewController.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputViewController.swift deleted file mode 100644 index 1da435e4..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingInput/OnBoardingInputViewController.swift +++ /dev/null @@ -1,161 +0,0 @@ -import UIKit - -import AuthFeatureInterface -import BaseFeature -import DesignSystem -import DictionaryFeatureInterface - -import ReactorKit -import RxCocoa -import RxKeyboard -import RxSwift -import SnapKit - -public class OnBoardingInputViewController: BaseViewController, View { - // MARK: - Properties - public typealias Reactor = OnBoardingInputReactor - - public var disposeBag = DisposeBag() - - private let onBoardingNotificationFactory: OnBoardingNotificationFactory - private let appCoordinator: AppCoordinatorProtocol - - // MARK: - Components - - private var mainView = OnBoardingInputView() - - init(onBoardingNotificationFactory: OnBoardingNotificationFactory, appCoordinator: AppCoordinatorProtocol) { - self.onBoardingNotificationFactory = onBoardingNotificationFactory - self.appCoordinator = appCoordinator - super.init() - } -} - -// MARK: - Life Cycle -public extension OnBoardingInputViewController { - override func viewDidLoad() { - super.viewDidLoad() - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension OnBoardingInputViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } - - func configureUI() { - setupKeyboard() - } - - func setupKeyboard() { - setupKeyboard(inset: OnBoardingInputView.Constant.bottomInset) { [weak self] height in - self?.mainView.nextButtonBottomConstraint?.update(inset: height) - } - } -} - -// MARK: - Bind -public extension OnBoardingInputViewController { - func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .map { Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.nextButton.rx.tap - .map { Reactor.Action.nextButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.inputBox.textField.rx.text.orEmpty - .map { text -> Int? in - Int(text) - } - .map { Reactor.Action.inputLevel($0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.dropDownBox.onItemSelected = { [weak self] job in - guard let self = self else { return } - self.reactor?.action.onNext(.inputRole(.init(name: job.name, id: job.id))) - } - - mainView.headerView.leftButton.rx.tap - .map { Reactor.Action.backButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.headerView.underlineTextButton.rx.tap - .map { Reactor.Action.skipButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - reactor.state - .map { $0.jobList } - .observe(on: MainScheduler.instance) - .distinctUntilChanged() - .withUnretained(self) - .subscribe { owner, list in - owner.mainView.dropDownBox.items = list.map { .init(name: $0.name, id: $0.id) } - } - .disposed(by: disposeBag) - - reactor.state - .map { $0.isLevelValid } - .distinctUntilChanged() - .withUnretained(self) - .subscribe { owner, isLevelValid in - guard let isLevelValid = isLevelValid else { return } - owner.mainView.inputBox.setType(type: isLevelValid ? InputBoxType.edit : InputBoxType.error) - owner.mainView.errorMessage.isHidden = isLevelValid - } - .disposed(by: disposeBag) - - reactor.state - .map { $0.isButtonEnabled } - .bind(to: mainView.nextButton.rx.isEnabled) - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .observe(on: MainScheduler.instance) - .withUnretained(self) - .subscribe(onNext: { owner, route in - switch route { - case .dismiss: - owner.navigationController?.popViewController(animated: true) - case .home: - owner.appCoordinator.showMainTab() - case .error: - let errorViewController = BaseErrorViewController() - owner.present(errorViewController, animated: true) - case .notification: - guard let selecteLevel = reactor.currentState.level, - let selectedJobID = reactor.currentState.job?.id else { return } - let viewController = owner.onBoardingNotificationFactory.make(selectedLevel: selecteLevel, selectedJobID: selectedJobID) - owner.navigationController?.pushViewController(viewController, animated: true) - default: - break - } - }) - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetFactoryImpl.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetFactoryImpl.swift deleted file mode 100644 index 97613d4e..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetFactoryImpl.swift +++ /dev/null @@ -1,40 +0,0 @@ -import AuthFeatureInterface -import BaseFeature -import DictionaryFeatureInterface -import DomainInterface - -public struct OnBoardingNotificationSheetFactoryImpl: OnBoardingNotificationSheetFactory { - private let checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase - private let openNotificationSettingUseCase: OpenNotificationSettingUseCase - private let updateNotificationAgreementUseCase: UpdateNotificationAgreementUseCase - private let updateUserInfoUseCase: UpdateUserInfoUseCase - private let appCoordinator: () -> AppCoordinatorProtocol - - public init( - checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase, - openNotificationSettingUseCase: OpenNotificationSettingUseCase, - updateNotificationAgreementUseCase: UpdateNotificationAgreementUseCase, - updateUserInfoUseCase: UpdateUserInfoUseCase, - appCoordinator: @escaping () -> AppCoordinatorProtocol - ) { - self.checkNotificationPermissionUseCase = checkNotificationPermissionUseCase - self.openNotificationSettingUseCase = openNotificationSettingUseCase - self.updateNotificationAgreementUseCase = updateNotificationAgreementUseCase - self.updateUserInfoUseCase = updateUserInfoUseCase - self.appCoordinator = appCoordinator - } - - public func make(selectedLevel: Int, selectedJobID: Int) -> BaseViewController & ModalPresentable { - let viewController = OnBoardingNotificationSheetViewController(appCoordinator: appCoordinator()) - viewController.isBottomTabbarHidden = true - viewController.reactor = OnBoardingNotificationSheetReactor( - selectedLevel: selectedLevel, - selectedJobID: selectedJobID, - checkNotificationPermissionUseCase: checkNotificationPermissionUseCase, - openNotificationSettingUseCase: openNotificationSettingUseCase, - updateNotificationAgreementUseCase: updateNotificationAgreementUseCase, - updateUserInfoUseCase: updateUserInfoUseCase - ) - return viewController - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetReactor.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetReactor.swift deleted file mode 100644 index b9e1f8ce..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetReactor.swift +++ /dev/null @@ -1,113 +0,0 @@ -import DomainInterface - -import ReactorKit -import RxCocoa -import RxSwift - -public final class OnBoardingNotificationSheetReactor: Reactor { - public enum Route { - case none - case dismiss - case home - case setting - } - - // MARK: - Reactor - public enum Action { - case viewWillAppear - case toggleSwitchButton(Bool) - case setButtonTapped - case cancelButtonTapped - case applyButtonTapped - case skipButtonTapped - case updateAuthorization(Bool) - case appWillEnterForeground - } - - public enum Mutation { - case navigateTo(route: Route) - case setLocalNotification(Bool) - case setRemoteNotification(Bool) - case setAuthorized(Bool) - } - - public struct State { - @Pulse var route: Route = .none - var selectedLevel: Int - var selectedJobID: Int - var isAgreeLocalNotification = false - var isAgreeRemoteNotification = true - } - - // MARK: - properties - public var initialState: State - var disposeBag = DisposeBag() - - private let checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase - private let openNotificationSettingUseCase: OpenNotificationSettingUseCase - private let updateNotificationAgreementUseCase: UpdateNotificationAgreementUseCase - private let updateUserInfoUseCase: UpdateUserInfoUseCase - - // MARK: - init - public init( - selectedLevel: Int, - selectedJobID: Int, - checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase, - openNotificationSettingUseCase: OpenNotificationSettingUseCase, - updateNotificationAgreementUseCase: UpdateNotificationAgreementUseCase, - updateUserInfoUseCase: UpdateUserInfoUseCase - ) { - self.initialState = State(selectedLevel: selectedLevel, selectedJobID: selectedJobID) - self.checkNotificationPermissionUseCase = checkNotificationPermissionUseCase - self.openNotificationSettingUseCase = openNotificationSettingUseCase - self.updateNotificationAgreementUseCase = updateNotificationAgreementUseCase - self.updateUserInfoUseCase = updateUserInfoUseCase - } - - // MARK: - Reactor Methods - public func mutate(action: Action) -> Observable { - switch action { - case .viewWillAppear, .appWillEnterForeground: - return checkNotificationPermissionUseCase.execute() - .asObservable() - .map { .setLocalNotification($0) } - case .toggleSwitchButton(let isAgree): - return .just(.setRemoteNotification(isAgree)) - case .setButtonTapped: - openNotificationSettingUseCase.execute() - return .just(.navigateTo(route: .setting)) - case .applyButtonTapped: - return updateUserInfoUseCase.execute(level: currentState.selectedLevel, selectedJobID: currentState.selectedJobID) - .andThen(updateNotificationAgreementUseCase.execute( - noticeAgreement: true, - patchNoteAgreement: true, - eventAgreement: true - )) - .andThen(Observable.just(.navigateTo(route: .home))) - .catchAndReturn(.navigateTo(route: .dismiss)) - case .cancelButtonTapped: - return .just(.navigateTo(route: .dismiss)) - case .skipButtonTapped: - return .just(.navigateTo(route: .home)) - case .updateAuthorization(let authorized): - return .just(.setAuthorized(authorized)) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .navigateTo(let route): - newState.route = route - case .setLocalNotification(let isAgree): - newState.isAgreeLocalNotification = isAgree - case .setRemoteNotification(let isAgree): - newState.isAgreeRemoteNotification = isAgree - case let .setAuthorized(isAuthorized): - newState.isAgreeLocalNotification = isAuthorized - } - - return newState - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetView.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetView.swift deleted file mode 100644 index aacb3853..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetView.swift +++ /dev/null @@ -1,100 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -final class OnBoardingNotificationSheetView: UIView { - private enum Constant { - static let inset: CGFloat = 16 - static let spacing: CGFloat = 14 - static let buttonTopMargin: CGFloat = 20 - } - - // MARK: - Properties - let header: Header = { - let header = Header(style: .filter, title: "신규 이벤트 알림 설정") - return header - }() - - private let descriptionLabel: UILabel = { - let label = UILabel() - label.numberOfLines = 2 - return label - }() - - private let buttonStackView: UIStackView = { - let view = UIStackView() - view.axis = .vertical - view.spacing = Constant.spacing - return view - }() - - let notificationToggleBox = ToggleBox(text: "알림 설정") - let applyButton = CommonButton(style: .normal, title: "적용", disabledTitle: nil) - let settingButton = CommonButton(style: .normal, title: "변경하기", disabledTitle: nil) - let skipButton = CommonButton(style: .border, title: "나중에 하기", disabledTitle: nil) - - // MARK: - init - init() { - super.init(frame: .zero) - - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension OnBoardingNotificationSheetView { - func addViews() { - addSubview(header) - addSubview(descriptionLabel) - addSubview(buttonStackView) - } - - func setupConstraints() { - header.snp.makeConstraints { make in - make.top.equalToSuperview().inset(Constant.inset) - make.horizontalEdges.equalToSuperview() - } - - descriptionLabel.snp.makeConstraints { make in - make.top.equalTo(header.snp.bottom).offset(Constant.spacing) - make.horizontalEdges.equalToSuperview().inset(Constant.inset) - } - - buttonStackView.snp.makeConstraints { make in - make.top.equalTo(descriptionLabel.snp.bottom).offset(Constant.buttonTopMargin) - make.horizontalEdges.bottom.equalToSuperview().inset(Constant.inset) - } - } - - func configureUI() { - notificationToggleBox.toggle.isOn = true - } -} - -// MARK: - Methods -extension OnBoardingNotificationSheetView { - func setUI(isAgree: Bool) { - buttonStackView.arrangedSubviews.forEach { view in - buttonStackView.removeArrangedSubview(view) - view.removeFromSuperview() - } - - descriptionLabel.attributedText = .makeStyledString(font: .cp_s_r, text: isAgree ? "메이플랜드 이벤트 소식을\n푸시 알림으로 빠르게 받아보세요." : "기기 알림 설정을 변경해야 이벤트 소식을 받을 수 있어요.", color: .neutral700, alignment: .left) - if isAgree { - buttonStackView.addArrangedSubview(notificationToggleBox) - buttonStackView.addArrangedSubview(applyButton) - } else { - buttonStackView.addArrangedSubview(settingButton) - buttonStackView.addArrangedSubview(skipButton) - } - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetViewController.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetViewController.swift deleted file mode 100644 index ba30890a..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingNotificationSheet/OnBoardingNotificationSheetViewController.swift +++ /dev/null @@ -1,157 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem -import DictionaryFeatureInterface - -import ReactorKit -import RxCocoa -import RxSwift -import SnapKit - -public final class OnBoardingNotificationSheetViewController: BaseViewController, ModalPresentable, View { - public var modalHeight: CGFloat? - - public typealias Reactor = OnBoardingNotificationSheetReactor - - public var disposeBag = DisposeBag() - - // MARK: - Properties - - private let appCoordinator: AppCoordinatorProtocol - - // MARK: - Components - private var mainView = OnBoardingNotificationSheetView() - - init(appCoordinator: AppCoordinatorProtocol) { - self.appCoordinator = appCoordinator - super.init() - } -} - -// MARK: - Life Cycle -public extension OnBoardingNotificationSheetViewController { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - } -} - -// MARK: - SetUp -private extension OnBoardingNotificationSheetViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } -} - -extension OnBoardingNotificationSheetViewController { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .take(1) - .do(onNext: { [weak self] _ in - self?.checkNotificationAuthorization() - }) - .map { _ in Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - NotificationCenter.default.rx.notification(UIApplication.willEnterForegroundNotification) - .map { _ in Reactor.Action.appWillEnterForeground } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.header.firstIconButton.rx.tap - .map { Reactor.Action.cancelButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.skipButton.rx.tap - .map { Reactor.Action.skipButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.settingButton.rx.tap - .map { Reactor.Action.setButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.applyButton.rx.tap - .map { Reactor.Action.applyButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.notificationToggleBox.toggle.rx.isOn - .map { Reactor.Action.toggleSwitchButton($0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - reactor.state - .observe(on: MainScheduler.instance) - .map { $0.isAgreeLocalNotification } - .withUnretained(self) - .subscribe { owner, isAgree in - owner.mainView.setUI(isAgree: isAgree) - } - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .observe(on: MainScheduler.instance) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .subscribe { owner, route in - DispatchQueue.main.async { - switch route { - case .dismiss: - owner.dismissCurrentModal() - case .home: - owner.appCoordinator.showMainTab() - case .setting: - guard let url = URL(string: UIApplication.openSettingsURLString), - UIApplication.shared.canOpenURL(url) else { return } - UIApplication.shared.open(url, options: [:], completionHandler: nil) - default: - break - } - } - } - .disposed(by: disposeBag) - } -} - -// MARK: - Notification Authorization -private extension OnBoardingNotificationSheetViewController { - func checkNotificationAuthorization() { - guard let reactor = reactor else { return } - - NotificationPermissionManager.shared.getStatus { status in - switch status { - case .authorized, .provisional: - reactor.action.onNext(.updateAuthorization(true)) - case .denied: - reactor.action.onNext(.updateAuthorization(false)) - case .notDetermined: - NotificationPermissionManager.shared.requestIfNeeded { granted in - reactor.action.onNext(.updateAuthorization(granted)) - } - default: - reactor.action.onNext(.updateAuthorization(false)) - } - } - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingQuestion/OnBoardingQuestionFactoryImpl.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingQuestion/OnBoardingQuestionFactoryImpl.swift deleted file mode 100644 index 051cb8ba..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingQuestion/OnBoardingQuestionFactoryImpl.swift +++ /dev/null @@ -1,18 +0,0 @@ -import AuthFeatureInterface -import BaseFeature - -public struct OnBoardingQuestionFactoryImpl: OnBoardingQuestionFactory { - - private let onBoardingInputFactory: OnBoardingInputFactory - - public init(onBoardingInputFactory: OnBoardingInputFactory) { - self.onBoardingInputFactory = onBoardingInputFactory - } - - public func make() -> BaseViewController { - let viewController = OnBoardingQuestionViewController(factory: onBoardingInputFactory) - viewController.isBottomTabbarHidden = true - viewController.reactor = OnBoardingQuestionReactor() - return viewController - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingQuestion/OnBoardingQuestionReactor.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingQuestion/OnBoardingQuestionReactor.swift deleted file mode 100644 index 746674fc..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingQuestion/OnBoardingQuestionReactor.swift +++ /dev/null @@ -1,65 +0,0 @@ -import ReactorKit -import RxSwift - -public final class OnBoardingQuestionReactor: Reactor { - // MARK: - Reactor - public enum Route { - case none - case dismiss - case home - case input - } - - public enum Action { - case viewDidLoad - case nextButtonTapped - case backButtonTapped - case skipButtonTapped - } - - public enum Mutation { - case showToast - case navigateTo(route: Route) - } - - public struct State { - @Pulse var route: Route = .none - @Pulse var isShowToast: Bool = false - } - - // MARK: - properties - public var initialState: State - var disposeBag = DisposeBag() - - // MARK: - init - public init() { - self.initialState = State() - } - - // MARK: - Reactor Methods - public func mutate(action: Action) -> Observable { - switch action { - case .viewDidLoad: - return Observable.just(.showToast) - case .nextButtonTapped: - return Observable.just(.navigateTo(route: .input)) - case .backButtonTapped: - return Observable.just(.navigateTo(route: .dismiss)) - case .skipButtonTapped: - return Observable.just(.navigateTo(route: .home)) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .showToast: - newState.isShowToast.toggle() - case .navigateTo(let route): - newState.route = route - } - - return newState - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingQuestion/OnBoardingQuestionView.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingQuestion/OnBoardingQuestionView.swift deleted file mode 100644 index 160c0e83..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingQuestion/OnBoardingQuestionView.swift +++ /dev/null @@ -1,94 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -public final class OnBoardingQuestionView: OnBoardingBaseView { - // MARK: - Type - private enum Constant { - static let horizontalInset = 16 - static let verticalInset = 16 - static let imgSize = 220 - static let resizeCenterY = 70 - } - - // MARK: - Components - private let imageView: UIImageView = { - let view = UIImageView() - view.image = DesignSystemAsset.image(named: "questionNotify") - return view - }() - - private let boldTextLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .h_xxxl_b, text: "효율적인 메이플랜드 플레이를\n위해 몇가지만 물어볼게요") - label.numberOfLines = 2 - return label - }() - - private let regularTeextLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .b_m_r, text: "나도 예티를 잡을 수 있을까?", color: .neutral700) - return label - }() - - private lazy var contentView: UIView = { - let view = UIView() - view.addSubview(imageView) - view.addSubview(boldTextLabel) - view.addSubview(regularTeextLabel) - - imageView.snp.makeConstraints { make in - make.top.equalToSuperview() - make.centerX.equalToSuperview() - make.size.equalTo(Constant.imgSize) - } - - boldTextLabel.snp.makeConstraints { make in - make.top.equalTo(imageView.snp.bottom).offset(4) - make.horizontalEdges.equalToSuperview() - } - - regularTeextLabel.snp.makeConstraints { make in - make.top.equalTo(boldTextLabel.snp.bottom).offset(Constant.verticalInset) - make.horizontalEdges.bottom.equalToSuperview() - } - - return view - }() - - public let nextButton = CommonButton(style: .normal, title: "다음", disabledTitle: "") - - // MARK: - init - init() { - super.init(leftButtonIsHidden: true, underlineTextButtonIsHidden: true) - addViews() - setupConstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension OnBoardingQuestionView { - func addViews() { - addSubview(contentView) - addSubview(nextButton) - } - - func setupConstraints() { - contentView.snp.makeConstraints { make in - make.centerY.equalToSuperview().offset(-Constant.resizeCenterY) - make.horizontalEdges.equalToSuperview() - } - - nextButton.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.bottom.equalTo(safeAreaLayoutGuide).inset(Constant.verticalInset) - } - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingQuestion/OnBoardingQuestionViewController.swift b/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingQuestion/OnBoardingQuestionViewController.swift deleted file mode 100644 index c1dbcf47..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/OnBoardingQuestion/OnBoardingQuestionViewController.swift +++ /dev/null @@ -1,119 +0,0 @@ -import UIKit - -import AuthFeatureInterface -import BaseFeature - -import ReactorKit -import RxCocoa -import RxSwift -import SnapKit - -public class OnBoardingQuestionViewController: BaseViewController, View { - // MARK: - Properties - public typealias Reactor = OnBoardingQuestionReactor - - public var disposeBag = DisposeBag() - - private let onBoardingInputFactory: OnBoardingInputFactory - - // MARK: - Components - - private var mainView = OnBoardingQuestionView() - - public init(factory: OnBoardingInputFactory) { - self.onBoardingInputFactory = factory - super.init() - } - - @available(*, unavailable) - @MainActor required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -public extension OnBoardingQuestionViewController { - override func viewDidLoad() { - super.viewDidLoad() - addViews() - setupConstraints() - } -} - -// MARK: - SetUp -private extension OnBoardingQuestionViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } -} - -// MARK: - Bind -public extension OnBoardingQuestionViewController { - func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - rx.viewDidLoad - .map { Reactor.Action.viewDidLoad } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.nextButton.rx.tap - .map { Reactor.Action.nextButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.headerView.leftButton.rx.tap - .map { Reactor.Action.backButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.headerView.underlineTextButton.rx.tap - .map { Reactor.Action.skipButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - reactor.pulse(\.$isShowToast) - .subscribe { isShowToast in - if isShowToast { - let currentDate = Date() - let dateFormatter = DateFormatter() - dateFormatter.dateFormat = "yyyy.MM.dd" - let formattedDate = dateFormatter.string(from: currentDate) - ToastFactory.createToast(message: "\(formattedDate) 약관에 동의했어요.") - } - } - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .subscribe { owner, route in - switch route { - case .dismiss: - owner.navigationController?.popViewController(animated: true) - case .home: - let homeViewController = UIViewController() - homeViewController.view.backgroundColor = .green - owner.navigationController?.pushViewController(homeViewController, animated: true) - case .input: - let inputViewController = owner.onBoardingInputFactory.make() - owner.navigationController?.pushViewController(inputViewController, animated: true) - default: - break - } - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementFactoryImpl.swift b/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementFactoryImpl.swift deleted file mode 100644 index e069897f..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementFactoryImpl.swift +++ /dev/null @@ -1,39 +0,0 @@ -import AuthFeatureInterface -import BaseFeature -import DomainInterface - -public struct TermsAgreementFactoryImpl: TermsAgreementFactory { - private let onBoardingQuestionFactory: OnBoardingQuestionFactory - - private let signUpWithKakaoUseCase: SignUpWithKakaoUseCase - private let signUpWithAppleUseCase: SignUpWithAppleUseCase - private let fetchTokenUseCase: FetchTokenFromLocalUseCase - private let updateMarketingAgreementUseCase: UpdateMarketingAgreementUseCase - - public init( - onBoardingQuestionFactory: OnBoardingQuestionFactory, - signUpWithKakaoUseCase: SignUpWithKakaoUseCase, - signUpWithAppleUseCase: SignUpWithAppleUseCase, - fetchTokenUseCase: FetchTokenFromLocalUseCase, - updateMarketingAgreementUseCase: UpdateMarketingAgreementUseCase - ) { - self.onBoardingQuestionFactory = onBoardingQuestionFactory - self.signUpWithKakaoUseCase = signUpWithKakaoUseCase - self.signUpWithAppleUseCase = signUpWithAppleUseCase - self.fetchTokenUseCase = fetchTokenUseCase - self.updateMarketingAgreementUseCase = updateMarketingAgreementUseCase - } - - public func make(credential: Credential, platform: LoginPlatform) -> BaseViewController { - let viewController = TermsAgreementViewController(onBoardingQuestionFactory: onBoardingQuestionFactory) - viewController.isBottomTabbarHidden = true - viewController.reactor = TermsAgreementReactor( - credential: credential, - socialPlatform: platform, - signUpWithKakaoUseCase: signUpWithKakaoUseCase, - signUpWithAppleUseCase: signUpWithAppleUseCase, - fetchTokenUseCase: fetchTokenUseCase, updateMarketingAgreementUseCase: updateMarketingAgreementUseCase - ) - return viewController - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementReactor.swift b/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementReactor.swift deleted file mode 100644 index 3aeb36ce..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementReactor.swift +++ /dev/null @@ -1,155 +0,0 @@ -import DomainInterface -import NotificationCenter - -import ReactorKit -import RxSwift - -public final class TermsAgreementReactor: Reactor { - // MARK: - Type - public enum AgreeType { - case total, age, serviceTerms, personalInfo, marketing - } - - public enum Route { - case none - case dismiss - case onBoarding - case error - case ageAgreement - case serviceAgreement - case personalAgreement - case marketingAgreement - } - - // MARK: - Reactor - public enum Action { - case backButtonTapped - case toggleAgree(type: AgreeType) - case bottomButtonTapped - case navigateTo(route: Route) - } - - public enum Mutation { - case setAgreeState(type: AgreeType, isOn: Bool) - case navigateTo(route: Route) - } - - public struct State { - @Pulse var route: Route = .none - - var isTotalAgree: Bool = false - var isAgeAgree: Bool = false - var isServiceTermsAgree: Bool = false - var isPersonalInformationAgree: Bool = false - var isMarketingAgree: Bool = false - var bottomButtonIsEnabled: Bool = false - } - - // MARK: - properties - public var initialState: State - var disposeBag = DisposeBag() - private let credential: Credential - private let socialPlatform: LoginPlatform - private let signUpWithKakaoUseCase: SignUpWithKakaoUseCase - private let signUpWithAppleUseCase: SignUpWithAppleUseCase - private let fetchTokenUseCase: FetchTokenFromLocalUseCase - private let updateMarketingAgreementUseCase: UpdateMarketingAgreementUseCase - - // MARK: - init - public init( - credential: Credential, - socialPlatform: LoginPlatform, - signUpWithKakaoUseCase: SignUpWithKakaoUseCase, - signUpWithAppleUseCase: SignUpWithAppleUseCase, - fetchTokenUseCase: FetchTokenFromLocalUseCase, - updateMarketingAgreementUseCase: UpdateMarketingAgreementUseCase - ) { - self.credential = credential - self.socialPlatform = socialPlatform - self.signUpWithKakaoUseCase = signUpWithKakaoUseCase - self.signUpWithAppleUseCase = signUpWithAppleUseCase - self.fetchTokenUseCase = fetchTokenUseCase - self.updateMarketingAgreementUseCase = updateMarketingAgreementUseCase - self.initialState = State() - } - - // MARK: - Reactor Methods - public func mutate(action: Action) -> Observable { - switch action { - case .backButtonTapped: - return .just(.navigateTo(route: .dismiss)) - case .toggleAgree(let type): - let isOn: Bool - switch type { - case .total: - isOn = !currentState.isTotalAgree - case .age: - isOn = !currentState.isAgeAgree - case .serviceTerms: - isOn = !currentState.isServiceTermsAgree - case .personalInfo: - isOn = !currentState.isPersonalInformationAgree - case .marketing: - isOn = !currentState.isMarketingAgree - } - return .just(.setAgreeState(type: type, isOn: isOn)) - case .bottomButtonTapped: - let fcmToken: String? = { - if case .success(let token) = fetchTokenUseCase.execute(type: .fcmToken) { - return token - } else { - return nil - } - }() - - switch socialPlatform { - case .kakao: - return signUpWithKakaoUseCase - .execute(credential: credential, isMarketingAgreement: currentState.isMarketingAgree, fcmToken: fcmToken) - .map { _ in .navigateTo(route: .onBoarding) } - .catchAndReturn(.navigateTo(route: .error)) - - case .apple: - return signUpWithAppleUseCase - .execute(credential: credential, isMarketingAgreement: currentState.isMarketingAgree, fcmToken: fcmToken) - .map { _ in .navigateTo(route: .onBoarding) } - .catchAndReturn(.navigateTo(route: .error)) - } - - case .navigateTo(let route): - return .just(.navigateTo(route: route)) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - switch mutation { - case .setAgreeState(let type, let isOn): - switch type { - case .total: - newState.isTotalAgree = isOn - newState.isAgeAgree = isOn - newState.isServiceTermsAgree = isOn - newState.isPersonalInformationAgree = isOn - newState.isMarketingAgree = isOn - case .age: - newState.isAgeAgree = isOn - case .serviceTerms: - newState.isServiceTermsAgree = isOn - case .personalInfo: - newState.isPersonalInformationAgree = isOn - case .marketing: - newState.isMarketingAgree = isOn - } - case .navigateTo(let route): - newState.route = route - } - - // bottomButton 활성화 체크 - let allRequiredAgreed = newState.isAgeAgree && newState.isServiceTermsAgree && newState.isPersonalInformationAgree - newState.bottomButtonIsEnabled = allRequiredAgreed - newState.isTotalAgree = allRequiredAgreed && newState.isMarketingAgree - - return newState - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementView.swift b/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementView.swift deleted file mode 100644 index bd55eff5..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementView.swift +++ /dev/null @@ -1,148 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -public final class TermsAgreementView: UIView { - // MARK: - Type - private enum Constant { - static let imageTopSpacing: CGFloat = 20 - static let imageSize: CGFloat = 60 - static let horizontalInset: CGFloat = 16 - static let totalButtonBottomSpacing: CGFloat = -14 - static let titleLabelTopSpacing: CGFloat = 16 - static let titleLabelHeight: CGFloat = 30 - static let subTitleLabelTopSpacing: CGFloat = 4 - static let subTitleLabelHeight: CGFloat = 21 - static let stackViewBottomSpacing: CGFloat = -26 - static let bottomButtonBottomSpacing: CGFloat = 16 - static let termsSpacing: CGFloat = 4 - } - - // MARK: - Properties - let headerView: NavigationBar = { - let view = NavigationBar(type: .arrowLeft) - view.rightButton.isHidden = true - return view - }() - - private let logoImageView: UIImageView = { - let image = DesignSystemAsset.image(named: "logo") - let view = UIImageView(image: image) - view.contentMode = .scaleAspectFill - return view - }() - - private let titleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .h_xxxl_b, text: "필수약관에 동의해주세요") - return label - }() - - private let subTitleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .sub_m_m, text: "메랜사를 더 편하게 즐기기 위해 필요한 항목이에요", color: .neutral700) - return label - }() - - public let totalAgreeButton: CheckBoxButton = { - let button = CheckBoxButton(style: .normal, mainTitle: "전체동의", subTitle: "(선택 약관 포함)") - return button - }() - - private let termsStackView: UIStackView = { - let view = UIStackView() - view.axis = .vertical - view.isUserInteractionEnabled = true - view.spacing = Constant.termsSpacing - return view - }() - - public let ageAgreeButton: CheckBoxButton = { - let button = CheckBoxButton(style: .listMedium, mainTitle: "(필수) 만 14세 이상", subTitle: nil) - return button - }() - - public let serviceTermsAgreeButton: CheckBoxButton = { - let button = CheckBoxButton(style: .listMedium, mainTitle: "(필수) 메랜사 서비스 이용약관 동의", subTitle: nil) - return button - }() - - public let personalInformationAgreeButton: CheckBoxButton = { - let button = CheckBoxButton(style: .listMedium, mainTitle: "(필수) 개인정보 수집 및 이용 동의", subTitle: nil) - return button - }() - - public let marketingAgreeButton: CheckBoxButton = { - let button = CheckBoxButton(style: .listMedium, mainTitle: "(선택) 마케팅 정보 수신 동의", subTitle: nil) - return button - }() - - public let bottomButton: CommonButton = { - let button = CommonButton(style: .normal, title: "다음", disabledTitle: "다음") - return button - }() - - // MARK: - init - init() { - super.init(frame: .zero) - addViews() - setupConstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension TermsAgreementView { - func addViews() { - addSubview(headerView) - addSubview(logoImageView) - addSubview(titleLabel) - addSubview(subTitleLabel) - addSubview(totalAgreeButton) - addSubview(bottomButton) - addSubview(termsStackView) - termsStackView.addArrangedSubview(ageAgreeButton) - termsStackView.addArrangedSubview(serviceTermsAgreeButton) - termsStackView.addArrangedSubview(personalInformationAgreeButton) - termsStackView.addArrangedSubview(marketingAgreeButton) - } - - func setupConstraints() { - headerView.snp.makeConstraints { make in - make.top.horizontalEdges.equalToSuperview() - } - logoImageView.snp.makeConstraints { make in - make.top.equalTo(headerView.snp.bottom).offset(Constant.imageTopSpacing) - make.size.equalTo(Constant.imageSize) - make.leading.equalToSuperview().inset(Constant.horizontalInset) - } - titleLabel.snp.makeConstraints { make in - make.top.equalTo(logoImageView.snp.bottom).offset(Constant.titleLabelTopSpacing) - make.height.equalTo(Constant.titleLabelHeight) - make.leading.equalTo(logoImageView) - } - subTitleLabel.snp.makeConstraints { make in - make.top.equalTo(titleLabel.snp.bottom).offset(Constant.subTitleLabelTopSpacing) - make.height.equalTo(Constant.subTitleLabelHeight) - make.leading.equalTo(logoImageView) - } - bottomButton.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.bottom.equalToSuperview().inset(Constant.bottomButtonBottomSpacing) - } - termsStackView.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.bottom.equalTo(bottomButton.snp.top).offset(Constant.stackViewBottomSpacing) - } - totalAgreeButton.snp.makeConstraints { make in - make.bottom.equalTo(termsStackView.snp.top).offset(Constant.totalButtonBottomSpacing) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - } - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementViewController.swift b/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementViewController.swift deleted file mode 100644 index bb7d2325..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeature/TermsAgreement/TermsAgreementViewController.swift +++ /dev/null @@ -1,181 +0,0 @@ -import UIKit - -import AuthFeatureInterface -import BaseFeature - -import ReactorKit -import RxCocoa -import RxSwift -import SnapKit - -public class TermsAgreementViewController: BaseViewController, View { - public typealias Reactor = TermsAgreementReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - private let onBoardingQuestionFactory: OnBoardingQuestionFactory - - private var mainView = TermsAgreementView() - - public init(onBoardingQuestionFactory: OnBoardingQuestionFactory) { - self.onBoardingQuestionFactory = onBoardingQuestionFactory - super.init() - } - - @available(*, unavailable) - @MainActor required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -public extension TermsAgreementViewController { - override func viewDidLoad() { - super.viewDidLoad() - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension TermsAgreementViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } - - func configureUI() { - view.backgroundColor = .systemBackground - navigationController?.navigationBar.isHidden = true - } -} - -public extension TermsAgreementViewController { - func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - mainView.headerView.leftButton.rx.tap - .map { Reactor.Action.backButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - let agreeButtons: [(button: UIButton, type: TermsAgreementReactor.AgreeType, isRightButton: Bool)] = [ - (mainView.totalAgreeButton, .total, false), - (mainView.ageAgreeButton, .age, false), - (mainView.ageAgreeButton.rightButton, .age, true), - (mainView.serviceTermsAgreeButton, .serviceTerms, false), - (mainView.serviceTermsAgreeButton.rightButton, .serviceTerms, true), - (mainView.personalInformationAgreeButton, .personalInfo, false), - (mainView.personalInformationAgreeButton.rightButton, .personalInfo, true), - (mainView.marketingAgreeButton, .marketing, false), - (mainView.marketingAgreeButton.rightButton, .marketing, true) - ] - - agreeButtons.forEach { button, type, _ in - button.rx.tap - .map { Reactor.Action.toggleAgree(type: type) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - mainView.bottomButton.rx.tap - .map { Reactor.Action.bottomButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - reactor.state - .map { $0.isTotalAgree } - .distinctUntilChanged() - .withUnretained(self) - .subscribe { owner, isAgree in - owner.mainView.totalAgreeButton.isSelected = isAgree - } - .disposed(by: disposeBag) - - reactor.state - .map { $0.isAgeAgree } - .distinctUntilChanged() - .withUnretained(self) - .subscribe { owner, isAgree in - owner.mainView.ageAgreeButton.isSelected = isAgree - } - .disposed(by: disposeBag) - - reactor.state - .map { $0.isServiceTermsAgree } - .distinctUntilChanged() - .withUnretained(self) - .subscribe { owner, isAgree in - owner.mainView.serviceTermsAgreeButton.isSelected = isAgree - } - .disposed(by: disposeBag) - - reactor.state - .map { $0.isPersonalInformationAgree } - .distinctUntilChanged() - .withUnretained(self) - .subscribe { owner, isAgree in - owner.mainView.personalInformationAgreeButton.isSelected = isAgree - } - .disposed(by: disposeBag) - - reactor.state - .map { $0.isMarketingAgree } - .distinctUntilChanged() - .withUnretained(self) - .subscribe { owner, isAgree in - owner.mainView.marketingAgreeButton.isSelected = isAgree - } - .disposed(by: disposeBag) - - reactor.state - .map { $0.bottomButtonIsEnabled } - .distinctUntilChanged() - .withUnretained(self) - .subscribe { owner, isEnabled in - owner.mainView.bottomButton.isEnabled = isEnabled - } - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, route in - switch route { - case .dismiss: - owner.navigationController?.popViewController(animated: true) - case .onBoarding: - let questionViewController = owner.onBoardingQuestionFactory.make() - owner.navigationController?.setViewControllers([questionViewController], animated: true) - case .error: - let errorViewController = BaseErrorViewController() - owner.present(errorViewController, animated: true) - case .ageAgreement: - break - case .serviceAgreement: - break - case .personalAgreement: - break - case .marketingAgreement: - break - default: - break - } - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeatureDemo/.DS_Store b/MLS/Presentation/AuthFeature/AuthFeatureDemo/.DS_Store deleted file mode 100644 index c9b08e1e..00000000 Binary files a/MLS/Presentation/AuthFeature/AuthFeatureDemo/.DS_Store and /dev/null differ diff --git a/MLS/Presentation/AuthFeature/AuthFeatureDemo/AppDelegate.swift b/MLS/Presentation/AuthFeature/AuthFeatureDemo/AppDelegate.swift deleted file mode 100644 index 3238b4bf..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeatureDemo/AppDelegate.swift +++ /dev/null @@ -1,233 +0,0 @@ -import UIKit - -import AuthFeature -import AuthFeatureInterface -import BaseFeature -import Core -import Data -import DataMock -import DesignSystem -import DictionaryFeatureInterface -import Domain -import DomainInterface - -import KakaoSDKCommon - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - ImageLoader.shared.configure.diskCacheCountLimit = 10 - FontManager.registerFonts() - registerDependencies() - return true - } - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {} -} - -private extension AppDelegate { - func registerDependencies() { - registerProvider() - registerRepository() - registerUseCase() - registerFactory() - } - - func registerProvider() { - DIContainer.register(type: NetworkProvider.self) { - NetworkProviderImpl() - } - DIContainer.register(type: SocialAuthenticatableProvider.self, name: "kakao") { - KakaoLoginProviderImpl() - } - DIContainer.register(type: SocialAuthenticatableProvider.self, name: "apple") { - AppleLoginProviderImpl() - } - } - - func registerRepository() { - DIContainer.register(type: AuthAPIRepository.self) { - AuthAPIRepositoryImpl( - provider: DIContainer.resolve(type: NetworkProvider.self), - interceptor: TokenInterceptor(fetchTokenUseCase: DIContainer.resolve(type: FetchTokenFromLocalUseCase.self)) - ) - } - DIContainer.register(type: TokenRepository.self) { - KeyChainRepositoryImpl() - } - DIContainer.register(type: UserDefaultsRepository.self) { - UserDefaultsRepositoryImpl() - } - } - - func registerUseCase() { - DIContainer.register(type: FetchSocialCredentialUseCase.self, name: "kakao") { - let provider = DIContainer.resolve(type: SocialAuthenticatableProvider.self, name: "kakao") - return SocialLoginUseCaseImpl(provider: provider) - } - DIContainer.register(type: FetchSocialCredentialUseCase.self, name: "apple") { - let provider = DIContainer.resolve(type: SocialAuthenticatableProvider.self, name: "apple") - return SocialLoginUseCaseImpl(provider: provider) - } - DIContainer.register(type: CheckEmptyLevelAndRoleUseCase.self) { - CheckEmptyLevelAndRoleUseCaseImpl() - } - DIContainer.register(type: CheckValidLevelUseCase.self) { - CheckValidLevelUseCaseImpl() - } - DIContainer.register(type: FetchJobListUseCase.self) { - FetchJobListUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: LoginWithAppleUseCase.self) { - LoginWithAppleUseCaseImpl(authRepository: DIContainer.resolve(type: AuthAPIRepository.self), tokenRepository: DIContainer.resolve(type: TokenRepository.self), userDefaultsRepository: DIContainer.resolve(type: UserDefaultsRepository.self)) - } - DIContainer.register(type: LoginWithKakaoUseCase.self) { - LoginWithKakaoUseCaseImpl(authRepository: DIContainer.resolve(type: AuthAPIRepository.self), tokenRepository: DIContainer.resolve(type: TokenRepository.self), userDefaultsRepository: DIContainer.resolve(type: UserDefaultsRepository.self)) - } - DIContainer.register(type: SignUpWithAppleUseCase.self) { - SignUpWithAppleUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: SignUpWithKakaoUseCase.self) { - SignUpWithKakaoUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: UpdateUserInfoUseCase.self) { - UpdateUserInfoUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: FetchTokenFromLocalUseCase.self) { - FetchTokenFromLocalUseCaseImpl(repository: DIContainer.resolve(type: TokenRepository.self)) - } - DIContainer.register(type: SaveTokenToLocalUseCase.self) { - SaveTokenToLocalUseCaseImpl(repository: DIContainer.resolve(type: TokenRepository.self)) - } - DIContainer.register(type: DeleteTokenFromLocalUseCase.self) { - DeleteTokenFromLocalUseCaseImpl(repository: DIContainer.resolve(type: TokenRepository.self)) - } - DIContainer.register(type: UpdateMarketingAgreementUseCase.self) { - UpdateMarketingAgreementUseCaseImpl(authRepository: DIContainer.resolve(type: AuthAPIRepository.self), tokenRepository: DIContainer.resolve(type: TokenRepository.self)) - } - DIContainer.register(type: PutFCMTokenUseCase.self) { - PutFCMTokenUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: CheckNotificationPermissionUseCase.self) { - CheckNotificationPermissionUseCaseImpl() - } - DIContainer.register(type: OpenNotificationSettingUseCase.self) { - OpenNotificationSettingUseCaseImpl() - } - DIContainer.register(type: UpdateNotificationAgreementUseCase.self) { - UpdateNotificationAgreementUseCaseImpl(authRepository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryMapListUseCase.self) { - FetchDictionaryMapListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryItemListUseCase.self) { - FetchDictionaryItemListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryQuestListUseCase.self) { - FetchDictionaryQuestListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryNpcListUseCase.self) { - FetchDictionaryNpcListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryMonsterListUseCase.self) { - FetchDictionaryMonsterListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMonsterUseCase.self) { - FetchDictionaryDetailMonsterUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMonsterItemsUseCase.self) { - FetchDictionaryDetailMonsterDropItemUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMonsterMapUseCase.self) { - FetchDictionaryDetailMonsterMapUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailNpcUseCase.self) { - FetchDictionaryDetailNpcUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailNpcQuestUseCase.self) { - FetchDictionaryDetailNpcQuestUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailNpcMapUseCase.self) { - FetchDictionaryDetailNpcMapUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailItemUseCase.self) { - FetchDictionaryDetailItemUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailItemDropMonsterUseCase.self) { - FetchDictionaryDetailItemDropMonsterUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailQuestUseCase.self) { - FetchDictionaryDetailQuestUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailQuestLinkedQuestsUseCase.self) { - FetchDictionaryDetailQuestLinkedQuestsUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMapUseCase.self) { - FetchDictionaryDetailMapUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMapSpawnMonsterUseCase.self) { - FetchDictionaryDetailMapSpawnMonsterUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMapNpcUseCase.self) { - FetchDictionaryDetailMapNpcUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchPlatformUseCase.self) { - FetchPlatformUseCaseImpl(repository: DIContainer.resolve(type: UserDefaultsRepository.self)) - } - } - - func registerFactory() { - DIContainer.register(type: OnBoardingNotificationSheetFactory.self) { - OnBoardingNotificationSheetFactoryImpl( - checkNotificationPermissionUseCase: DIContainer - .resolve(type: CheckNotificationPermissionUseCase.self), - openNotificationSettingUseCase: DIContainer - .resolve(type: OpenNotificationSettingUseCase.self), - updateNotificationAgreementUseCase: DIContainer - .resolve(type: UpdateNotificationAgreementUseCase.self), updateUserInfoUseCase: DIContainer.resolve(type: UpdateUserInfoUseCase.self), dictionaryMainViewFactory: DictionaryFactoryMock() - ) - } - DIContainer.register(type: OnBoardingNotificationFactory.self) { - OnBoardingNotificationFactoryImpl(onBoardingNotificationSheetFactory: DIContainer.resolve(type: OnBoardingNotificationSheetFactory.self)) - } - DIContainer.register(type: OnBoardingInputFactory.self) { - OnBoardingInputFactoryImpl( - checkEmptyUseCase: DIContainer.resolve(type: CheckEmptyLevelAndRoleUseCase.self), - checkValidLevelUseCase: DIContainer.resolve(type: CheckValidLevelUseCase.self), - fetchJobListUseCase: DIContainer.resolve(type: FetchJobListUseCase.self), - updateUserInfoUseCase: DIContainer.resolve(type: UpdateUserInfoUseCase.self), - onBoardingNotificationFactory: DIContainer.resolve(type: OnBoardingNotificationFactory.self) - ) - } - DIContainer.register(type: OnBoardingQuestionFactory.self) { - OnBoardingQuestionFactoryImpl( - onBoardingInputFactory: DIContainer.resolve(type: OnBoardingInputFactory.self) - ) - } - DIContainer.register(type: TermsAgreementFactory.self) { - TermsAgreementFactoryImpl( - onBoardingQuestionFactory: DIContainer.resolve(type: OnBoardingQuestionFactory.self), - signUpWithKakaoUseCase: DIContainer.resolve(type: SignUpWithKakaoUseCase.self), - signUpWithAppleUseCase: DIContainer.resolve(type: SignUpWithAppleUseCase.self), - saveTokenUseCase: DIContainer.resolve(type: SaveTokenToLocalUseCase.self), - fetchTokenUseCase: DIContainer.resolve(type: FetchTokenFromLocalUseCase.self), updateMarketingAgreementUseCase: DIContainer.resolve(type: UpdateMarketingAgreementUseCase.self) - ) - } - DIContainer.register(type: LoginFactory.self) { - LoginFactoryImpl( - termsAgreementsFactory: DIContainer.resolve(type: TermsAgreementFactory.self), - appleLoginUseCase: DIContainer.resolve(type: FetchSocialCredentialUseCase.self, name: "apple"), - kakaoLoginUseCase: DIContainer.resolve(type: FetchSocialCredentialUseCase.self, name: "kakao"), - loginWithAppleUseCase: DIContainer.resolve(type: LoginWithAppleUseCase.self), - loginWithKakaoUseCase: DIContainer.resolve(type: LoginWithKakaoUseCase.self), - fetchTokenUseCase: DIContainer.resolve(type: FetchTokenFromLocalUseCase.self), - putFCMTokenUseCase: DIContainer.resolve(type: PutFCMTokenUseCase.self), - fetchPlatformUseCase: DIContainer.resolve(type: FetchPlatformUseCase.self) - ) - } - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeatureDemo/Assets.xcassets/AccentColor.colorset/Contents.json b/MLS/Presentation/AuthFeature/AuthFeatureDemo/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index eb878970..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeatureDemo/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeatureDemo/Assets.xcassets/AppIcon.appiconset/Contents.json b/MLS/Presentation/AuthFeature/AuthFeatureDemo/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index c68da6c9..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeatureDemo/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "images" : [ - { - "filename" : "icon.png", - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "tinted" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeatureDemo/Assets.xcassets/AppIcon.appiconset/icon.png b/MLS/Presentation/AuthFeature/AuthFeatureDemo/Assets.xcassets/AppIcon.appiconset/icon.png deleted file mode 100644 index 78870a63..00000000 Binary files a/MLS/Presentation/AuthFeature/AuthFeatureDemo/Assets.xcassets/AppIcon.appiconset/icon.png and /dev/null differ diff --git a/MLS/Presentation/AuthFeature/AuthFeatureDemo/Assets.xcassets/Contents.json b/MLS/Presentation/AuthFeature/AuthFeatureDemo/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeatureDemo/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeatureDemo/Base.lproj/LaunchScreen.storyboard b/MLS/Presentation/AuthFeature/AuthFeatureDemo/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 865e9329..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeatureDemo/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MLS/Presentation/AuthFeature/AuthFeatureDemo/Info.plist b/MLS/Presentation/AuthFeature/AuthFeatureDemo/Info.plist deleted file mode 100644 index 7d5d1c29..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeatureDemo/Info.plist +++ /dev/null @@ -1,27 +0,0 @@ - - - - - ITSAppUsesNonExemptEncryption - - NSUserNotificationAlertUsageDescription - 이벤트 소식을 알려드리기 위해 푸시 알림 권한이 필요합니다. - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - - - - - - diff --git a/MLS/Presentation/AuthFeature/AuthFeatureDemo/SceneDelegate.swift b/MLS/Presentation/AuthFeature/AuthFeatureDemo/SceneDelegate.swift deleted file mode 100644 index e4fcd4d6..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeatureDemo/SceneDelegate.swift +++ /dev/null @@ -1,26 +0,0 @@ -import UIKit - -import AuthFeature -import AuthFeatureInterface -import BaseFeature - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - var window: UIWindow? - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - guard let windowScene = (scene as? UIWindowScene) else { return } - window = UIWindow(windowScene: windowScene) - window?.rootViewController = UINavigationController(rootViewController: ViewController()) - window?.makeKeyAndVisible() - } - - func sceneDidDisconnect(_ scene: UIScene) {} - - func sceneDidBecomeActive(_ scene: UIScene) {} - - func sceneWillResignActive(_ scene: UIScene) {} - - func sceneWillEnterForeground(_ scene: UIScene) {} - - func sceneDidEnterBackground(_ scene: UIScene) {} -} diff --git a/MLS/Presentation/AuthFeature/AuthFeatureDemo/ViewController.swift b/MLS/Presentation/AuthFeature/AuthFeatureDemo/ViewController.swift deleted file mode 100644 index 75594d1d..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeatureDemo/ViewController.swift +++ /dev/null @@ -1,76 +0,0 @@ -import UIKit - -import AuthFeature -import AuthFeatureInterface -import Core -import Data -import Domain -import DomainInterface - -import RxCocoa -import RxSwift -import SnapKit - -class ViewController: UIViewController { - let tableView: UITableView = { - let view = UITableView(frame: .zero, style: .plain) - return view - }() - - lazy var views: [UIViewController] = { - let loginVC = DIContainer.resolve(type: LoginFactory.self).make(exitRoute: .pop) - loginVC.title = "로그인" - - let termVC = DIContainer.resolve(type: TermsAgreementFactory.self).make(credential: KakaoCredential(token: "", providerID: ""), platform: .apple) - termVC.title = "약관 동의" - - let questionVC = DIContainer.resolve(type: OnBoardingQuestionFactory.self).make() - questionVC.title = "온보딩 진입" - - let inputVC = DIContainer.resolve(type: OnBoardingInputFactory.self).make() - inputVC.title = "온보딩 입력" - - let notiVC = DIContainer.resolve(type: OnBoardingNotificationFactory.self).make(selectedLevel: 1, selectedJobID: 0) - notiVC.title = "알림" - - return [ - notiVC, - loginVC, - termVC, - questionVC, - inputVC - ] - }() - - override func viewDidLoad() { - super.viewDidLoad() - view.backgroundColor = .systemBackground - tableView.dataSource = self - tableView.delegate = self - navigationItem.title = "MLS Feature System" - - view.addSubview(tableView) - - tableView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } -} - -extension ViewController: UITableViewDataSource, UITableViewDelegate { - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return views.count - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = UITableViewCell() - cell.textLabel?.text = views[indexPath.row].title - cell.selectionStyle = .none - return cell - } - - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let nextController = views[indexPath.row] - navigationController?.pushViewController(nextController, animated: true) - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeatureInterface/LoginFactory.swift b/MLS/Presentation/AuthFeature/AuthFeatureInterface/LoginFactory.swift deleted file mode 100644 index 4231837f..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeatureInterface/LoginFactory.swift +++ /dev/null @@ -1,11 +0,0 @@ -import BaseFeature - -public protocol LoginFactory { - func make(exitRoute: LoginExitRoute, onLoginCompleted: (() -> Void)?) -> BaseViewController -} - -public extension LoginFactory { - func make(exitRoute: LoginExitRoute) -> BaseViewController { - make(exitRoute: exitRoute, onLoginCompleted: nil) - } -} diff --git a/MLS/Presentation/AuthFeature/AuthFeatureInterface/OnBoadingNotificationFactory.swift b/MLS/Presentation/AuthFeature/AuthFeatureInterface/OnBoadingNotificationFactory.swift deleted file mode 100644 index bfe601a8..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeatureInterface/OnBoadingNotificationFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol OnBoardingNotificationFactory { - func make(selectedLevel: Int, selectedJobID: Int) -> BaseViewController -} diff --git a/MLS/Presentation/AuthFeature/AuthFeatureInterface/OnBoardingInputFactory.swift b/MLS/Presentation/AuthFeature/AuthFeatureInterface/OnBoardingInputFactory.swift deleted file mode 100644 index e7a90517..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeatureInterface/OnBoardingInputFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol OnBoardingInputFactory { - func make() -> BaseViewController -} diff --git a/MLS/Presentation/AuthFeature/AuthFeatureInterface/OnBoardingModalFactory.swift b/MLS/Presentation/AuthFeature/AuthFeatureInterface/OnBoardingModalFactory.swift deleted file mode 100644 index 2e94bae9..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeatureInterface/OnBoardingModalFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol OnBoardingModalFactory { - func make() -> BaseViewController & ModalPresentable -} diff --git a/MLS/Presentation/AuthFeature/AuthFeatureInterface/OnBoardingNotificationSheetFactory.swift b/MLS/Presentation/AuthFeature/AuthFeatureInterface/OnBoardingNotificationSheetFactory.swift deleted file mode 100644 index 6add1e37..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeatureInterface/OnBoardingNotificationSheetFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol OnBoardingNotificationSheetFactory { - func make(selectedLevel: Int, selectedJobID: Int) -> BaseViewController & ModalPresentable -} diff --git a/MLS/Presentation/AuthFeature/AuthFeatureInterface/OnBoardingQuestionFactory.swift b/MLS/Presentation/AuthFeature/AuthFeatureInterface/OnBoardingQuestionFactory.swift deleted file mode 100644 index b196ecb9..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeatureInterface/OnBoardingQuestionFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol OnBoardingQuestionFactory { - func make() -> BaseViewController -} diff --git a/MLS/Presentation/AuthFeature/AuthFeatureInterface/TermsAgreementFactory.swift b/MLS/Presentation/AuthFeature/AuthFeatureInterface/TermsAgreementFactory.swift deleted file mode 100644 index a5b81ffa..00000000 --- a/MLS/Presentation/AuthFeature/AuthFeatureInterface/TermsAgreementFactory.swift +++ /dev/null @@ -1,7 +0,0 @@ -import BaseFeature - -import DomainInterface - -public protocol TermsAgreementFactory { - func make(credential: Credential, platform: LoginPlatform) -> BaseViewController -} diff --git a/MLS/Presentation/BaseFeature/.DS_Store b/MLS/Presentation/BaseFeature/.DS_Store deleted file mode 100644 index 82813aac..00000000 Binary files a/MLS/Presentation/BaseFeature/.DS_Store and /dev/null differ diff --git a/MLS/Presentation/BaseFeature/BaseFeature.xcodeproj/project.pbxproj b/MLS/Presentation/BaseFeature/BaseFeature.xcodeproj/project.pbxproj deleted file mode 100644 index 3a5733d0..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature.xcodeproj/project.pbxproj +++ /dev/null @@ -1,476 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 77; - objects = { - -/* Begin PBXBuildFile section */ - 0850204B2DDCD6AE0055CBCE /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 0850204A2DDCD6AE0055CBCE /* RxSwift */; }; - 0850204E2DDCD6C20055CBCE /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 0850204D2DDCD6C20055CBCE /* SnapKit */; }; - 085020542DDCD8E20055CBCE /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 085020532DDCD8E20055CBCE /* RxCocoa */; }; - 085020562DDCD8E20055CBCE /* RxRelay in Frameworks */ = {isa = PBXBuildFile; productRef = 085020552DDCD8E20055CBCE /* RxRelay */; }; - 085020592DDCD8EE0055CBCE /* ReactorKit in Frameworks */ = {isa = PBXBuildFile; productRef = 085020582DDCD8EE0055CBCE /* ReactorKit */; }; - 772022362DF6BE7800BF8B5D /* DesignSystem.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 085020452DDCD6040055CBCE /* DesignSystem.framework */; }; - 773A42D42E717BB800F75B30 /* DomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 773A42D32E717BB800F75B30 /* DomainInterface.framework */; }; - 777C28112E7D8787000765F2 /* RxKeyboard in Frameworks */ = {isa = PBXBuildFile; productRef = 777C28102E7D8787000765F2 /* RxKeyboard */; }; -/* End PBXBuildFile section */ - -/* Begin PBXFileReference section */ - 085020452DDCD6040055CBCE /* DesignSystem.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DesignSystem.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 08EECED12DD908400047AFE2 /* BaseFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BaseFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 773A42D32E717BB800F75B30 /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFileSystemSynchronizedRootGroup section */ - 08EECED32DD908400047AFE2 /* BaseFeature */ = { - isa = PBXFileSystemSynchronizedRootGroup; - path = BaseFeature; - sourceTree = ""; - }; -/* End PBXFileSystemSynchronizedRootGroup section */ - -/* Begin PBXFrameworksBuildPhase section */ - 08EECECE2DD908400047AFE2 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 085020562DDCD8E20055CBCE /* RxRelay in Frameworks */, - 0850204E2DDCD6C20055CBCE /* SnapKit in Frameworks */, - 0850204B2DDCD6AE0055CBCE /* RxSwift in Frameworks */, - 773A42D42E717BB800F75B30 /* DomainInterface.framework in Frameworks */, - 772022362DF6BE7800BF8B5D /* DesignSystem.framework in Frameworks */, - 777C28112E7D8787000765F2 /* RxKeyboard in Frameworks */, - 085020542DDCD8E20055CBCE /* RxCocoa in Frameworks */, - 085020592DDCD8EE0055CBCE /* ReactorKit in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 085020442DDCD6040055CBCE /* Frameworks */ = { - isa = PBXGroup; - children = ( - 773A42D32E717BB800F75B30 /* DomainInterface.framework */, - 085020452DDCD6040055CBCE /* DesignSystem.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; - 08EECEC72DD908400047AFE2 = { - isa = PBXGroup; - children = ( - 08EECED32DD908400047AFE2 /* BaseFeature */, - 085020442DDCD6040055CBCE /* Frameworks */, - 08EECED22DD908400047AFE2 /* Products */, - ); - sourceTree = ""; - }; - 08EECED22DD908400047AFE2 /* Products */ = { - isa = PBXGroup; - children = ( - 08EECED12DD908400047AFE2 /* BaseFeature.framework */, - ); - name = Products; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 08EECECC2DD908400047AFE2 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 08EECED02DD908400047AFE2 /* BaseFeature */ = { - isa = PBXNativeTarget; - buildConfigurationList = 08EECED72DD908400047AFE2 /* Build configuration list for PBXNativeTarget "BaseFeature" */; - buildPhases = ( - 08EECECC2DD908400047AFE2 /* Headers */, - 08EECECD2DD908400047AFE2 /* Sources */, - 08EECECE2DD908400047AFE2 /* Frameworks */, - 08EECECF2DD908400047AFE2 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - fileSystemSynchronizedGroups = ( - 08EECED32DD908400047AFE2 /* BaseFeature */, - ); - name = BaseFeature; - packageProductDependencies = ( - 0850204A2DDCD6AE0055CBCE /* RxSwift */, - 0850204D2DDCD6C20055CBCE /* SnapKit */, - 085020532DDCD8E20055CBCE /* RxCocoa */, - 085020552DDCD8E20055CBCE /* RxRelay */, - 085020582DDCD8EE0055CBCE /* ReactorKit */, - 777C28102E7D8787000765F2 /* RxKeyboard */, - ); - productName = BaseFeature; - productReference = 08EECED12DD908400047AFE2 /* BaseFeature.framework */; - productType = "com.apple.product-type.framework"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 08EECEC82DD908400047AFE2 /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastUpgradeCheck = 1620; - TargetAttributes = { - 08EECED02DD908400047AFE2 = { - CreatedOnToolsVersion = 16.2; - }; - }; - }; - buildConfigurationList = 08EECECB2DD908400047AFE2 /* Build configuration list for PBXProject "BaseFeature" */; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 08EECEC72DD908400047AFE2; - minimizedProjectReferenceProxies = 1; - packageReferences = ( - 085020492DDCD6AE0055CBCE /* XCRemoteSwiftPackageReference "RxSwift" */, - 0850204C2DDCD6C20055CBCE /* XCRemoteSwiftPackageReference "SnapKit" */, - 085020572DDCD8EE0055CBCE /* XCRemoteSwiftPackageReference "ReactorKit" */, - 777C280F2E7D8787000765F2 /* XCRemoteSwiftPackageReference "RxKeyboard" */, - ); - preferredProjectObjectVersion = 77; - productRefGroup = 08EECED22DD908400047AFE2 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 08EECED02DD908400047AFE2 /* BaseFeature */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 08EECECF2DD908400047AFE2 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 08EECECD2DD908400047AFE2 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin XCBuildConfiguration section */ - 08EECED82DD908400047AFE2 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.BaseFeature; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 08EECED92DD908400047AFE2 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.BaseFeature; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; - 08EECEDA2DD908400047AFE2 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.2; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 08EECEDB2DD908400047AFE2 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.2; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 08EECECB2DD908400047AFE2 /* Build configuration list for PBXProject "BaseFeature" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 08EECEDA2DD908400047AFE2 /* Debug */, - 08EECEDB2DD908400047AFE2 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 08EECED72DD908400047AFE2 /* Build configuration list for PBXNativeTarget "BaseFeature" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 08EECED82DD908400047AFE2 /* Debug */, - 08EECED92DD908400047AFE2 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - 085020492DDCD6AE0055CBCE /* XCRemoteSwiftPackageReference "RxSwift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ReactiveX/RxSwift"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 6.9.0; - }; - }; - 0850204C2DDCD6C20055CBCE /* XCRemoteSwiftPackageReference "SnapKit" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/SnapKit/SnapKit.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 5.7.1; - }; - }; - 085020572DDCD8EE0055CBCE /* XCRemoteSwiftPackageReference "ReactorKit" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ReactorKit/ReactorKit"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 3.2.0; - }; - }; - 777C280F2E7D8787000765F2 /* XCRemoteSwiftPackageReference "RxKeyboard" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/RxSwiftCommunity/RxKeyboard"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.0.1; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 0850204A2DDCD6AE0055CBCE /* RxSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 085020492DDCD6AE0055CBCE /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxSwift; - }; - 0850204D2DDCD6C20055CBCE /* SnapKit */ = { - isa = XCSwiftPackageProductDependency; - package = 0850204C2DDCD6C20055CBCE /* XCRemoteSwiftPackageReference "SnapKit" */; - productName = SnapKit; - }; - 085020532DDCD8E20055CBCE /* RxCocoa */ = { - isa = XCSwiftPackageProductDependency; - package = 085020492DDCD6AE0055CBCE /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxCocoa; - }; - 085020552DDCD8E20055CBCE /* RxRelay */ = { - isa = XCSwiftPackageProductDependency; - package = 085020492DDCD6AE0055CBCE /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxRelay; - }; - 085020582DDCD8EE0055CBCE /* ReactorKit */ = { - isa = XCSwiftPackageProductDependency; - package = 085020572DDCD8EE0055CBCE /* XCRemoteSwiftPackageReference "ReactorKit" */; - productName = ReactorKit; - }; - 777C28102E7D8787000765F2 /* RxKeyboard */ = { - isa = XCSwiftPackageProductDependency; - package = 777C280F2E7D8787000765F2 /* XCRemoteSwiftPackageReference "RxKeyboard" */; - productName = RxKeyboard; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 08EECEC82DD908400047AFE2 /* Project object */; -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/MLS/Presentation/BaseFeature/BaseFeature.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a6..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Base/BaseErrorViewController.swift b/MLS/Presentation/BaseFeature/BaseFeature/Base/BaseErrorViewController.swift deleted file mode 100644 index 6646537e..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Base/BaseErrorViewController.swift +++ /dev/null @@ -1,102 +0,0 @@ -import UIKit - -import DesignSystem - -import ReactorKit -import RxCocoa -import RxSwift -import SnapKit - -public final class BaseErrorViewController: BaseViewController { - // MARK: - Type - private enum Constant { - static let imageHeight: CGFloat = 171 - static let imageWidth: CGFloat = 165 - static let componentsSpacing: CGFloat = 24 - static let bottomButtonBottomSpacing: CGFloat = 16 - static let centerYMultiplied: CGFloat = 0.7 - } - - // MARK: - Properties - private var disposeBag = DisposeBag() - - private let containerView: UIView = UIView() - - private let imageView: UIImageView = { - let image = DesignSystemAsset.image(named: "errorImage") - let view = UIImageView(image: image) - return view - }() - - private let descriptionLabel: UILabel = { - let label = UILabel() - label.numberOfLines = 0 - label.attributedText = .makeStyledString(font: .b_m_r, text: "알 수 없는 오류가 발생했어요.\n이전 화면으로 돌아가 다시 시도해 주세요.") - return label - }() - - private let backButton = CommonButton(style: .normal, title: "뒤로가기", disabledTitle: nil) - - public override init() { - super.init() - modalPresentationStyle = .fullScreen - } - - @MainActor public required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -extension BaseErrorViewController { - public override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - bind() - } -} - -// MARK: - SetUp -private extension BaseErrorViewController { - func addViews() { - view.addSubview(backButton) - containerView.addSubview(imageView) - containerView.addSubview(descriptionLabel) - view.addSubview(containerView) - } - - func setupConstraints() { - backButton.snp.makeConstraints { make in - make.bottom.horizontalEdges.equalTo(view.safeAreaLayoutGuide).inset(Constant.bottomButtonBottomSpacing) - } - imageView.snp.makeConstraints { make in - make.height.equalTo(Constant.imageHeight) - make.width.equalTo(Constant.imageWidth) - make.top.equalToSuperview().inset(Constant.componentsSpacing) - make.centerX.equalToSuperview() - } - descriptionLabel.snp.makeConstraints { make in - make.top.equalTo(imageView.snp.bottom).offset(Constant.componentsSpacing) - make.horizontalEdges.equalToSuperview() - make.bottom.equalToSuperview() - } - containerView.snp.makeConstraints { make in - make.centerX.equalToSuperview() - make.centerY.equalToSuperview().multipliedBy(Constant.centerYMultiplied) - } - } - - func configureUI() { } - - func bind() { - backButton.rx.tap - .withUnretained(self) - .subscribe { (owner, _) in - owner.dismiss(animated: true) - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Base/BaseViewController.swift b/MLS/Presentation/BaseFeature/BaseFeature/Base/BaseViewController.swift deleted file mode 100644 index ed78ec89..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Base/BaseViewController.swift +++ /dev/null @@ -1,73 +0,0 @@ -import os -import UIKit - -import DesignSystem - -import RxKeyboard -import RxSwift - -open class BaseViewController: UIViewController { - private let disposeBag = DisposeBag() - - open var isBottomTabbarHidden: Bool = false { - didSet { - if let tabBarController = tabBarController as? BottomTabBarController { - tabBarController.setHidden(hidden: isBottomTabbarHidden, animated: false) - } - } - } - - public init() { - super.init(nibName: nil, bundle: nil) - os_log("➕init: \(String(describing: self))") - } - - @available(*, unavailable) - public required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - deinit { - os_log("➖deinit: \(String(describing: self))") - } -} - -// MARK: - Life Cycle -extension BaseViewController { - override open func viewDidLoad() { - super.viewDidLoad() - configureUI() - } - - override open func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - - if let tabBarController = tabBarController as? BottomTabBarController { - tabBarController.setHidden(hidden: isBottomTabbarHidden, animated: animated) - } - } -} - -// MARK: - SetUp -private extension BaseViewController { - func configureUI() { - navigationController?.navigationBar.isHidden = true - view.backgroundColor = .systemBackground - } -} - -// MARK: - Methods -public extension BaseViewController { - func setupKeyboard(inset: CGFloat = 0, completion: @escaping (CGFloat) -> Void) { - RxKeyboard.instance.visibleHeight - .drive(onNext: { [weak self] height in - guard let self = self else { return } - let safeBottom = self.view.safeAreaInsets.bottom - let inset = height > 0 - ? height - safeBottom + inset - : inset - completion(inset) - }) - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Interface/AppCoordinatorProtocol.swift b/MLS/Presentation/BaseFeature/BaseFeature/Interface/AppCoordinatorProtocol.swift deleted file mode 100644 index 24f9b2ca..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Interface/AppCoordinatorProtocol.swift +++ /dev/null @@ -1,7 +0,0 @@ -import UIKit - -public protocol AppCoordinatorProtocol: AnyObject { - var window: UIWindow? { get set } - func showMainTab() - func showLogin(exitRoute: LoginExitRoute) -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Interface/DictionaryTabControllable.swift b/MLS/Presentation/BaseFeature/BaseFeature/Interface/DictionaryTabControllable.swift deleted file mode 100644 index 1f0e5479..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Interface/DictionaryTabControllable.swift +++ /dev/null @@ -1,3 +0,0 @@ -public protocol DictionaryTabControllable: AnyObject { - func changeTab(index: Int) -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Shared/BaseListView.swift b/MLS/Presentation/BaseFeature/BaseFeature/Shared/BaseListView.swift deleted file mode 100644 index bfad802d..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Shared/BaseListView.swift +++ /dev/null @@ -1,178 +0,0 @@ -import UIKit - -import DesignSystem -import DomainInterface - -import SnapKit - -open class BaseListView: UIView { - // MARK: - Type - enum Constant { - static let filterInset: CGFloat = 6 - static let filterHeight: CGFloat = 32 - static let iconSize: CGFloat = 24 - static let stackViewSpacing: CGFloat = 12 - static let topMargin: CGFloat = 12 - static let cellSpacing: CGFloat = 10 - static let cellWidth: CGFloat = 343 - static let cellHeight: CGFloat = 104 - static let horizontalMargin: CGFloat = 16 - static let bottomInset: CGFloat = 64 - } - - // MARK: - Components - public let editButton: UIButton? - public let listCollectionView: UICollectionView - public let sortButton: UIButton - public let filterButton: UIButton - public let emptyView: DataEmptyView - - private lazy var filterStackView: UIStackView = { - var subviews: [UIView] = [] - - if let editButton = editButton { - subviews.append(editButton) - } - subviews.append(UIView()) - subviews.append(sortButton) - subviews.append(filterButton) - - let view = UIStackView(arrangedSubviews: subviews) - view.axis = .horizontal - view.spacing = Constant.stackViewSpacing - view.alignment = .fill - return view - }() - - // MARK: - Init - public init(editButton: UIButton? = nil, - sortButton: UIButton, - filterButton: UIButton, - emptyView: DataEmptyView, - isFilterHidden: Bool) { - self.editButton = editButton - self.sortButton = sortButton - self.filterButton = filterButton - self.emptyView = emptyView - self.listCollectionView = UICollectionView(frame: .zero, collectionViewLayout: UICollectionViewLayout()) - - super.init(frame: .zero) - addViews(isFilterHidden: isFilterHidden) - setupConstraints(isFilterHidden: isFilterHidden) - configureUI() - } - - @available(*, unavailable) - public required init?(coder: NSCoder) { fatalError() } -} - -// MARK: - Setup -private extension BaseListView { - func addViews(isFilterHidden: Bool) { - if !isFilterHidden { - addSubview(filterStackView) - } - addSubview(listCollectionView) - addSubview(emptyView) - } - - func setupConstraints(isFilterHidden: Bool) { - if isFilterHidden { - listCollectionView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - - emptyView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } else { - filterStackView.snp.makeConstraints { make in - make.top.equalToSuperview().inset(Constant.topMargin) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalMargin) - make.height.equalTo(Constant.filterHeight) - } - - listCollectionView.snp.makeConstraints { make in - make.top.equalTo(filterStackView.snp.bottom).offset(Constant.topMargin) - make.horizontalEdges.bottom.equalToSuperview() - } - - emptyView.snp.makeConstraints { make in - make.top.equalTo(filterStackView.snp.bottom).offset(Constant.topMargin) - make.horizontalEdges.bottom.equalToSuperview() - } - } - } - - func configureUI() { - backgroundColor = .neutral100 - listCollectionView.backgroundColor = .neutral100 - } -} - -// MARK: - Methods -public extension BaseListView { - func updateFilter(sortType: SortType?) { - let hasFilter = sortType != nil - filterStackView.isHidden = !hasFilter - - listCollectionView.snp.remakeConstraints { make in - if hasFilter { - make.top.equalTo(filterStackView.snp.bottom).offset(Constant.topMargin) - } else { - make.top.equalToSuperview() - } - make.horizontalEdges.bottom.equalToSuperview() - } - - if let sortType = sortType { - sortButton.setAttributedTitle(.makeStyledString(font: .b_s_r, text: sortType.rawValue, color: sortButton.tintColor), for: .normal) - } - } - - func updateBookmarkFilter(type: DictionaryType) { - if type == .total { - filterButton.isHidden = true - } - } - - static func makeSortButton(title: String, tintColor: UIColor) -> UIButton { - let button = UIButton() - button.setAttributedTitle(.makeStyledString(font: .b_s_r, text: title), for: .normal) - button.setImage(DesignSystemAsset.image(named: "lineArrowDown")?.withRenderingMode(.alwaysTemplate), for: .normal) - button.tintColor = tintColor - button.setTitleColor(tintColor, for: .normal) - button.semanticContentAttribute = .forceRightToLeft - return button - } - - static func makeFilterButton(title: String, tintColor: UIColor) -> UIButton { - let button = UIButton() - button.setAttributedTitle(.makeStyledString(font: .b_s_r, text: title), for: .normal) - button.setImage(DesignSystemAsset.image(named: "filter")?.withRenderingMode(.alwaysTemplate), for: .normal) - button.tintColor = tintColor - button.setTitleColor(tintColor, for: .normal) - button.semanticContentAttribute = .forceRightToLeft - return button - } - - func selectSort(selectedType: SortType) { - sortButton.setAttributedTitle(.makeStyledString(font: .b_s_r, text: selectedType.rawValue, color: .primary700), for: .normal) - sortButton.tintColor = .primary700 - } - - func selectFilter() { - filterButton.setAttributedTitle(.makeStyledString(font: .b_s_r, text: "필터", color: .primary700), for: .normal) - filterButton.tintColor = .primary700 - } - - func resetFilter() { - filterButton.setAttributedTitle(.makeStyledString(font: .b_s_r, text: "필터"), for: .normal) - filterButton.tintColor = .black - } - - func checkEmptyData(isEmpty: Bool) { - emptyView.isHidden = !isEmpty - listCollectionView.isHidden = isEmpty - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Shared/CharacterInputView.swift b/MLS/Presentation/BaseFeature/BaseFeature/Shared/CharacterInputView.swift deleted file mode 100644 index 82aef9a5..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Shared/CharacterInputView.swift +++ /dev/null @@ -1,133 +0,0 @@ -import UIKit - -import DesignSystem - -import RxCocoa -import RxSwift -import SnapKit - -open class CharacterInputView: UIView { - // MARK: - Type - public enum Constant { - public static let horizontalInset: CGFloat = 16 - public static let verticalInset: CGFloat = 40 - static let verticalSpacing: CGFloat = 28 - static let horizontalSpacing: CGFloat = 8 - public static let bottomInset: CGFloat = 16 - static let messageSpacing: CGFloat = 8 - static let boxInset: CGFloat = (horizontalInset + (horizontalSpacing / 2)) / 2 - } - - // MARK: - Properties - private let disposeBag = DisposeBag() - public var nextButtonBottomConstraint: Constraint? - - // MARK: - Components - public let descriptionLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .h_xxl_b, text: "현재 레벨과 직업을\n입력해주세요.", alignment: .left) - label.numberOfLines = 2 - return label - }() - - public let inputBox: InputBox = { - let box = InputBox(label: "레벨", placeHodler: "1~200") - box.textField.keyboardType = .numberPad - return box - }() - - public let dropDownBox = DropDownBox(label: "직업", placeHodler: "선택", items: []) - - public let errorMessage = ErrorMessage(message: "1에서 200까지 숫자만 입력해주세요") - - public let nextButton = CommonButton(style: .normal, title: "다음", disabledTitle: "다음") - - // MARK: - init - public init() { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - setGesture() - } - - @available(*, unavailable) - required public init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension CharacterInputView { - func addViews() { - addSubview(descriptionLabel) - addSubview(inputBox) - addSubview(dropDownBox) - addSubview(errorMessage) - addSubview(nextButton) - } - - func setupConstraints() { - inputBox.snp.makeConstraints { make in - make.top.equalTo(descriptionLabel.snp.bottom).offset(Constant.verticalSpacing) - make.leading.equalToSuperview().inset(Constant.horizontalInset) - make.width.equalToSuperview().multipliedBy(0.5).inset(Constant.boxInset) - } - - dropDownBox.snp.makeConstraints { make in - make.top.equalTo(inputBox) - make.leading.equalTo(inputBox.snp.trailing).offset(Constant.horizontalSpacing) - make.trailing.equalToSuperview().inset(Constant.horizontalInset) - make.width.equalToSuperview().multipliedBy(0.5).inset(Constant.boxInset) - } - - errorMessage.snp.makeConstraints { make in - make.centerX.equalToSuperview() - } - - nextButton.snp.makeConstraints { make in - make.top.equalTo(errorMessage.snp.bottom).offset(Constant.messageSpacing) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - nextButtonBottomConstraint = make.bottom.equalToSuperview().inset(Constant.bottomInset).constraint - } - } - - func configureUI() { - inputBox.textField.delegate = self - errorMessage.isHidden = true - } - - /// inputBox를 제외한 영역 선택시 키보드 제거 - func setGesture() { - let tapGesture = UITapGestureRecognizer() - tapGesture.cancelsTouchesInView = false - addGestureRecognizer(tapGesture) - - Observable.merge( - tapGesture.rx.event.map { $0.location(in: self) }.asObservable() - ) - .withUnretained(self) - .filter { owner, location in - !owner.inputBox.frame.contains(location) - } - .subscribe { owner, _ in - owner.inputBox.textField.resignFirstResponder() - } - .disposed(by: disposeBag) - } -} - -// MARK: - UITextFieldDelegate -extension CharacterInputView: UITextFieldDelegate { - /// textField의 붙여넣기 기능 차단 - /// - Parameters: - /// - action: 선택자를 나타내는 selector - /// - sender: 동작을 트리거한 객체 - /// - Returns: 붙여넣기가 허용되면 true / 허용되지 않으면 false - override public func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool { - if action == #selector(paste(_:)) { - return false - } - return super.canPerformAction(action, withSender: sender) - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Shared/DataEmptyView.swift b/MLS/Presentation/BaseFeature/BaseFeature/Shared/DataEmptyView.swift deleted file mode 100644 index f92b8c2b..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Shared/DataEmptyView.swift +++ /dev/null @@ -1,104 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -public enum EmptyViewType { - case dictionary - case bookmark -} - -public final class DataEmptyView: UIView { - // MARK: - Type - enum Constant { - static let imageSize: CGFloat = 220 - static let textSpacing: CGFloat = 10 - static let buttonSpacing: CGFloat = 24 - static let buttonWidth: CGFloat = 186 - } - - // MARK: - Components - public let imageView = UIImageView() - private let mainLabel = UILabel() - private let subLabel = UILabel() - - public let button = CommonButton() - - // MARK: - Init - public init(type: EmptyViewType) { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI(type: type) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension DataEmptyView { - func addViews() { - addSubview(imageView) - addSubview(mainLabel) - addSubview(subLabel) - addSubview(button) - } - - func setupConstraints() { - imageView.snp.makeConstraints { make in - make.centerX.equalToSuperview() - make.size.equalTo(Constant.imageSize) - } - - mainLabel.snp.makeConstraints { make in - make.top.equalTo(imageView.snp.bottom) - make.centerY.equalToSuperview() - make.horizontalEdges.equalToSuperview() - } - - subLabel.snp.makeConstraints { make in - make.top.equalTo(mainLabel.snp.bottom).offset(Constant.textSpacing) - make.centerX.equalToSuperview() - } - - button.snp.makeConstraints { make in - make.top.equalTo(subLabel.snp.bottom).offset(Constant.buttonSpacing) - make.centerX.equalToSuperview() - make.width.equalTo(Constant.buttonWidth) - } - } - - func configureUI(type: EmptyViewType) { - backgroundColor = .neutral100 - - switch type { - case .dictionary: - imageView.image = DesignSystemAsset.image(named: "noResult") - mainLabel.attributedText = .makeStyledString( - font: .b_m_r, - text: "검색 결과가 없습니다." - ) - - subLabel.isHidden = true - button.isHidden = true - case .bookmark: - imageView.image = DesignSystemAsset.image(named: "noShowList") - mainLabel.attributedText = .makeStyledString( - font: .h_xl_b, - text: "아직 아무것도 없어요!" - ) - - subLabel.attributedText = .makeStyledString( - font: .cp_s_r, - text: "북마크해서 추가해보세요.", - color: .neutral600 - ) - - button.updateTitle(title: "북마크하러 가기") - } - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Shared/ToLoginView.swift b/MLS/Presentation/BaseFeature/BaseFeature/Shared/ToLoginView.swift deleted file mode 100644 index 5be73445..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Shared/ToLoginView.swift +++ /dev/null @@ -1,86 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -public final class ToLoginView: UIView { - // MARK: - Type - enum Constant { - static let imageSize: CGFloat = 220 - static let textSpacing: CGFloat = 10 - static let buttonSpacing: CGFloat = 24 - static let buttonWidth: CGFloat = 186 - } - - // MARK: - Components - public let imageView = UIImageView() - private let mainLabel = UILabel() - private let subLabel = UILabel() - - public let button = CommonButton() - - // MARK: - Init - public init() { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension ToLoginView { - func addViews() { - addSubview(imageView) - addSubview(mainLabel) - addSubview(subLabel) - addSubview(button) - } - - func setupConstraints() { - imageView.snp.makeConstraints { make in - make.centerX.equalToSuperview() - make.size.equalTo(Constant.imageSize) - } - - mainLabel.snp.makeConstraints { make in - make.top.equalTo(imageView.snp.bottom) - make.centerY.equalToSuperview() - make.horizontalEdges.equalToSuperview() - } - - subLabel.snp.makeConstraints { make in - make.top.equalTo(mainLabel.snp.bottom).offset(Constant.textSpacing) - make.centerX.equalToSuperview() - } - - button.snp.makeConstraints { make in - make.top.equalTo(subLabel.snp.bottom).offset(Constant.buttonSpacing) - make.centerX.equalToSuperview() - make.width.equalTo(Constant.buttonWidth) - } - } - - func configureUI() { - backgroundColor = .neutral100 - imageView.image = DesignSystemAsset.image(named: "noShowList") - mainLabel.attributedText = .makeStyledString( - font: .h_xl_b, - text: "북마크는 로그인 후 이용 가능해요!" - ) - - subLabel.attributedText = .makeStyledString( - font: .cp_s_r, - text: "자주 보는 정보, 검색 없이 바로 확인 할 수 있어요.", - color: .neutral600 - ) - - button.updateTitle(title: "로그인하러 가기") - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Shared/WebViewController.swift b/MLS/Presentation/BaseFeature/BaseFeature/Shared/WebViewController.swift deleted file mode 100644 index 08e4128e..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Shared/WebViewController.swift +++ /dev/null @@ -1,10 +0,0 @@ -import SafariServices -import UIKit - -public final class WebViewController { - - public static func make(urlString: String) -> SFSafariViewController? { - guard let url = URL(string: urlString) else { return nil } - return SFSafariViewController(url: url) - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/AddFolderCell.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/AddFolderCell.swift deleted file mode 100644 index 5632d0ad..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/AddFolderCell.swift +++ /dev/null @@ -1,86 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift -import SnapKit - -public class AddFolderCell: UICollectionViewCell { - // MARK: - Type - private enum Constant { - static let iconInset: CGFloat = 8 - static let radius: CGFloat = 8 - static let margin: CGFloat = 16 - static let buttonSize: CGFloat = 40 - } - - // MARK: - Components - private lazy var addIconView: UIView = { - let view = UIView() - view.layer.cornerRadius = Constant.radius - view.backgroundColor = .primary100 - - view.addSubview(iconView) - iconView.snp.makeConstraints { make in - make.center.equalTo(view).inset(Constant.iconInset) - } - return view - }() - - private let iconView: UIImageView = { - let view = UIImageView() - view.image = DesignSystemAsset.image(named: "addIcon")?.withRenderingMode(.alwaysTemplate) - view.tintColor = .whiteMLS - return view - }() - - private let titleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .b_m_r, text: "새로운 컬렉션 추가하기", alignment: .left) - return label - }() - - private let divider: UIView = { - let view = UIView() - view.backgroundColor = .neutral100 - return view - }() - - private var disposeBag = DisposeBag() - - override init(frame: CGRect) { - super.init(frame: frame) - addViews() - setupConstraints() } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension AddFolderCell { - func addViews() { - contentView.addSubview(addIconView) - contentView.addSubview(titleLabel) - contentView.addSubview(divider) - } - - func setupConstraints() { - addIconView.snp.makeConstraints { make in - make.leading.verticalEdges.equalToSuperview().inset(Constant.margin) - make.size.equalTo(Constant.buttonSize) - } - - titleLabel.snp.makeConstraints { make in - make.leading.equalTo(addIconView.snp.trailing).offset(Constant.margin) - make.centerY.equalToSuperview() - make.trailing.equalToSuperview().inset(Constant.margin) - } - - divider.snp.makeConstraints { make in - make.height.equalTo(1) - make.horizontalEdges.bottom.equalToSuperview() - } - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/BadgeCell.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/BadgeCell.swift deleted file mode 100644 index 81884c57..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/BadgeCell.swift +++ /dev/null @@ -1,50 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift -import SnapKit - -public class BadgeCell: UICollectionViewCell { - - public var badge = Badge(style: .currentQuest) - - override init(frame: CGRect) { - super.init(frame: frame) - addViews() - setupConstraints() - configureUI() - } - - public var disposeBag = DisposeBag() - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - public override func prepareForReuse() { - super.prepareForReuse() - self.disposeBag = DisposeBag() - } -} - -// MARK: - SetUp -private extension BadgeCell { - func addViews() { - contentView.addSubview(badge) - } - - func setupConstraints() { - badge.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } - - func configureUI() { } -} - -public extension BadgeCell { - func inject(name: String) { - badge.update(style: .element(name)) - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/CheckBoxButtonListSmallCell.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/CheckBoxButtonListSmallCell.swift deleted file mode 100644 index ed43d99c..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/CheckBoxButtonListSmallCell.swift +++ /dev/null @@ -1,56 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift -import SnapKit - -public class CheckBoxButtonListSmallCell: UICollectionViewCell { - - private let checkBoxButton: CheckBoxButton = { - let button = CheckBoxButton(style: .listSmall, mainTitle: nil, subTitle: nil) - button.isUserInteractionEnabled = false - return button - }() - - private var disposeBag = DisposeBag() - - override init(frame: CGRect) { - super.init(frame: frame) - addViews() - setupConstraints() - configureUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - public override var isSelected: Bool { - didSet { - checkBoxButton.isSelected = isSelected - } - } -} - -// MARK: - SetUp -private extension CheckBoxButtonListSmallCell { - func addViews() { - contentView.addSubview(checkBoxButton) - } - - func setupConstraints() { - checkBoxButton.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } - - func configureUI() { - } -} - -public extension CheckBoxButtonListSmallCell { - func inject(title: String?) { - checkBoxButton.mainTitle = title - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/DictionaryListCell.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/DictionaryListCell.swift deleted file mode 100644 index 33361c55..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/DictionaryListCell.swift +++ /dev/null @@ -1,121 +0,0 @@ -import UIKit - -import DesignSystem -import DomainInterface - -public final class DictionaryListCell: UICollectionViewCell { - // MARK: - Properties - private var onBookmarkTapped: (() -> Void)? - - // MARK: - Components - public let cellView = CardList() - - // MARK: - init - override init(frame: CGRect) { - super.init(frame: frame) - - addViews() - setupContstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } - - override public func prepareForReuse() { - super.prepareForReuse() - - onBookmarkTapped = nil - cellView.onIconTapped = nil - cellView.setMainText(text: "") - cellView.setSubText(text: nil) - cellView.setSelected(isSelected: false) - } -} - -// MARK: - SetUp -private extension DictionaryListCell { - func addViews() { - contentView.addSubview(cellView) - } - - func setupContstraints() { - cellView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } -} - -public extension DictionaryListCell { - struct Input { - public let type: DictionaryItemType - public let mainText: String - public let subText: String? - public let imageUrl: String - public let isBookmarked: Bool - - public init(type: DictionaryItemType, mainText: String, subText: String?, imageUrl: String, isBookmarked: Bool) { - self.type = type - self.mainText = mainText - self.subText = subText - self.imageUrl = imageUrl - self.isBookmarked = isBookmarked - } - } - - func inject( - type: CardList.CardListType, - input: Input, - indexPath: IndexPath, - collectionView: UICollectionView, - isMap: Bool = false, - onBookmarkTapped: @escaping () -> Void - ) { - cellView.setType(type: type) - cellView.setImage(image: UIImage(), backgroundColor: input.type.backgroundColor) // 초기화 - - if let url = URL(string: input.imageUrl) { - ImageLoader.shared.loadImage(url: url) { [weak self] image in - guard let self = self else { return } - // 셀이 재사용된 경우, indexPath가 다르면 무시 - if let currentIndex = collectionView.indexPath(for: self), - currentIndex == indexPath { - if isMap { - self.cellView.setMapImage(image: image ?? UIImage(), backgroundColor: input.type.backgroundColor) - } else { - self.cellView.setImage(image: image ?? UIImage(), backgroundColor: input.type.backgroundColor) - } - } - } - } - - cellView.setMainText(text: input.mainText) - cellView.setSubText(text: input.subText) - cellView.setSelected(isSelected: input.isBookmarked) - self.onBookmarkTapped = onBookmarkTapped - cellView.onIconTapped = { [weak self] in - self?.onBookmarkTapped?() - } - } - func updateBookmarkState(isBookmarked: Bool) { - cellView.setSelected(isSelected: isBookmarked) - } -} - -public extension DictionaryItemType { - var backgroundColor: UIColor { - switch self { - case .item: - .listItem - case .monster: - .listMonster - case .map: - .listMap - case .npc: - .listNPC - case .quest: - .listQuest - } - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/DictionaryNotificationCell.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/DictionaryNotificationCell.swift deleted file mode 100644 index db03aa1d..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/DictionaryNotificationCell.swift +++ /dev/null @@ -1,89 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift -import SnapKit - -public class DictionaryNotificationCell: UICollectionViewCell { - // MARK: - Type - private enum Constant { - static let inset: CGFloat = 20 - static let spacing: CGFloat = 4 - static let radius: CGFloat = 8 - static let iconSize: CGFloat = 8 - static let iconMargin: CGFloat = 12 - } - - // MARK: - Components - private let titleLabel = UILabel() - private let subTitleLabel = UILabel() - private let checkIcon: UIView = { - let view = UIView() - view.backgroundColor = .primary700 - view.layer.cornerRadius = Constant.iconSize / 2 - return view - }() - - override init(frame: CGRect) { - super.init(frame: frame) - addViews() - setupConstraints() - } - - public var disposeBag = DisposeBag() - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension DictionaryNotificationCell { - func addViews() { - contentView.addSubview(titleLabel) - contentView.addSubview(subTitleLabel) - contentView.addSubview(checkIcon) - } - - func setupConstraints() { - titleLabel.snp.makeConstraints { make in - make.top.equalToSuperview().inset(Constant.inset) - make.horizontalEdges.equalToSuperview().inset(Constant.inset) - } - - subTitleLabel.snp.makeConstraints { make in - make.top.equalTo(titleLabel.snp.bottom).offset(Constant.spacing) - make.horizontalEdges.equalToSuperview().inset(Constant.inset) - make.bottom.equalToSuperview().inset(Constant.inset) - } - - checkIcon.snp.makeConstraints { make in - make.trailing.equalToSuperview().inset(Constant.iconMargin) - make.centerY.equalToSuperview() - make.size.equalTo(Constant.iconSize) - } - } -} - -public extension DictionaryNotificationCell { - struct Input { - let title: String - let subTitle: String - let isChecked: Bool - - public init(title: String, subTitle: String, isChecked: Bool) { - self.title = title - self.subTitle = subTitle - self.isChecked = isChecked - } - } - - func inject(input: Input) { - titleLabel.attributedText = .makeStyledString(font: .sub_m_sb, text: input.title, color: input.isChecked ? .neutral500 : .textColor, alignment: .left) - subTitleLabel.attributedText = .makeStyledString(font: .b_s_r, text: input.subTitle, color: input.isChecked ? .neutral500 : .neutral700, alignment: .left) - backgroundColor = input.isChecked ? .neutral100 : .clearMLS - layer.cornerRadius = input.isChecked ? Constant.radius : 0 - checkIcon.isHidden = input.isChecked - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/FolderCell.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/FolderCell.swift deleted file mode 100644 index 73e28adb..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/FolderCell.swift +++ /dev/null @@ -1,113 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift -import SnapKit - -public class FolderCell: UICollectionViewCell { - private enum Constant { - static let iconInset: CGFloat = 8 - static let radius: CGFloat = 8 - static let margin: CGFloat = 16 - static let iconSize: CGFloat = 24 - static let buttonSize: CGFloat = 40 - } - - private lazy var imageView: UIView = { - let view = UIView() - view.layer.cornerRadius = Constant.radius - view.backgroundColor = .neutral200 - - view.addSubview(iconView) - iconView.snp.makeConstraints { make in - make.center.equalTo(view).inset(Constant.iconInset) - } - return view - }() - - private let iconView: UIImageView = { - let view = UIImageView() - view.image = DesignSystemAsset.image(named: "bookmark")?.withRenderingMode(.alwaysTemplate) - view.tintColor = .neutral300 - return view - }() - - private let titleLabel: UILabel = { - let label = UILabel() - label.numberOfLines = 1 - label.lineBreakMode = .byTruncatingTail - return label - }() - - public let checkBoxButton: UIButton = { - let button = UIButton() - button.setImage(DesignSystemAsset.image(named: "checkSquareFill")?.withRenderingMode(.alwaysTemplate), for: .normal) - button.tintColor = .neutral300 - button.isUserInteractionEnabled = false - return button - }() - - private let divider: UIView = { - let view = UIView() - view.backgroundColor = .neutral100 - return view - }() - - public var isChecked: Bool = false { - didSet { - checkBoxButton.tintColor = isChecked ? .primary700 : .neutral300 - } - } - - override init(frame: CGRect) { - super.init(frame: frame) - addViews() - setupConstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension FolderCell { - func addViews() { - contentView.addSubview(imageView) - contentView.addSubview(titleLabel) - contentView.addSubview(checkBoxButton) - contentView.addSubview(divider) - } - - func setupConstraints() { - imageView.snp.makeConstraints { make in - make.leading.verticalEdges.equalToSuperview().inset(Constant.margin) - make.size.equalTo(Constant.buttonSize) - } - - titleLabel.snp.makeConstraints { make in - make.leading.equalTo(imageView.snp.trailing).offset(Constant.margin) - make.centerY.equalToSuperview() - } - - checkBoxButton.snp.makeConstraints { make in - make.leading.equalTo(titleLabel.snp.trailing).offset(Constant.margin) - make.centerY.equalToSuperview() - make.trailing.equalToSuperview().inset(Constant.margin) - make.size.equalTo(Constant.iconSize) - } - - divider.snp.makeConstraints { make in - make.height.equalTo(1) - make.horizontalEdges.bottom.equalToSuperview() - } - } -} - -public extension FolderCell { - func inject(title: String?) { - titleLabel.attributedText = .makeStyledString(font: .b_m_r, text: title, alignment: .left) - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/PageTabbarCell.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/PageTabbarCell.swift deleted file mode 100644 index 87a4941b..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/PageTabbarCell.swift +++ /dev/null @@ -1,60 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -public class PageTabbarCell: UICollectionViewCell { - - private let titleLabel: UILabel = { - let label = UILabel() - label.font = .b_m_r - label.textColor = .neutral600 - label.numberOfLines = 1 - label.adjustsFontSizeToFitWidth = true - label.minimumScaleFactor = 0.8 - return label - }() - - override init(frame: CGRect) { - super.init(frame: frame) - addViews() - setupConstraints() - configureUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - public override var isSelected: Bool { - didSet { - let font: UIFont? = isSelected ? .sub_m_b : .b_m_r - let textColor: UIColor? = isSelected ? .textColor : .neutral600 - titleLabel.font = font - titleLabel.textColor = textColor - } - } -} - -// MARK: - SetUp -private extension PageTabbarCell { - func addViews() { - contentView.addSubview(titleLabel) - } - - func setupConstraints() { - titleLabel.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview() - make.centerY.equalToSuperview() - } - } - - func configureUI() { } -} - -public extension PageTabbarCell { - func inject(title: String?) { - titleLabel.text = title - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/TagChipCell.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/TagChipCell.swift deleted file mode 100644 index f273bca0..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/TagChipCell.swift +++ /dev/null @@ -1,54 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift -import SnapKit - -public class TagChipCell: UICollectionViewCell { - - public let button: TagChip = { - let button = TagChip(style: .normal, text: "") - return button - }() - - override init(frame: CGRect) { - super.init(frame: frame) - addViews() - setupConstraints() - configureUI() - } - - public var disposeBag = DisposeBag() - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - public override func prepareForReuse() { - super.prepareForReuse() - self.disposeBag = DisposeBag() - } -} - -// MARK: - SetUp -private extension TagChipCell { - func addViews() { - contentView.addSubview(button) - } - - func setupConstraints() { - button.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } - - func configureUI() { } -} - -public extension TagChipCell { - func inject(title: String?) { - button.text = title ?? "" - button.titleLabel?.numberOfLines = 1 - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/TapButtonCell.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/TapButtonCell.swift deleted file mode 100644 index ef26dbb3..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/CollectionViewCells/TapButtonCell.swift +++ /dev/null @@ -1,52 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -public class TapButtonCell: UICollectionViewCell { - - public let button: TapButton = { - let button = TapButton() - return button - }() - - override init(frame: CGRect) { - super.init(frame: frame) - addViews() - setupConstraints() - configureUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - public override var isSelected: Bool { - didSet { - button.isSelected = isSelected - } - } -} - -// MARK: - SetUp -private extension TapButtonCell { - func addViews() { - contentView.addSubview(button) - } - - func setupConstraints() { - button.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } - - func configureUI() { } -} - -public extension TapButtonCell { - func inject(title: String?) { - button.text = title - button.isUserInteractionEnabled = false - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/DescriptionBackgroundView.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/DescriptionBackgroundView.swift deleted file mode 100644 index 87cd1f98..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/DescriptionBackgroundView.swift +++ /dev/null @@ -1,45 +0,0 @@ -import DesignSystem -import UIKit - -final public class DescriptionBackgroundView: UICollectionReusableView { - // MARK: - Type - enum Constant { - static let horizontalInset: CGFloat = 16 - static let topInset: CGFloat = 60 - static let bottomInset: CGFloat = 20 - } - - private let containerView: UIView = { - let view = UIView() - view.backgroundColor = .whiteMLS - view.layer.cornerRadius = 16 - view.layer.masksToBounds = true - return view - }() - - override init(frame: CGRect) { - super.init(frame: frame) - backgroundColor = .neutral200 - addViews() - setConstraints() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} - -private extension DescriptionBackgroundView { - private func addViews() { - addSubview(containerView) - } - - func setConstraints() { - containerView.snp.makeConstraints { make in - make.top.equalToSuperview().inset(Constant.topInset) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.bottom.equalToSuperview().inset(Constant.bottomInset) - } - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/Neutral100BackgroundView.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/Neutral100BackgroundView.swift deleted file mode 100644 index e65412fc..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/Neutral100BackgroundView.swift +++ /dev/null @@ -1,35 +0,0 @@ -import DesignSystem -import UIKit - -final public class Neutral100BackgroundView: UICollectionReusableView { - // MARK: - Type - private let containerView: UIView = { - let view = UIView() - view.backgroundColor = .neutral100 - return view - }() - - override init(frame: CGRect) { - super.init(frame: frame) - backgroundColor = .neutral200 - addViews() - setConstraints() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} - -private extension Neutral100BackgroundView { - private func addViews() { - addSubview(containerView) - } - - func setConstraints() { - containerView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/Neutral200DividerView.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/Neutral200DividerView.swift deleted file mode 100644 index 914f1c1b..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/Neutral200DividerView.swift +++ /dev/null @@ -1,20 +0,0 @@ -import UIKit - -import DesignSystem - -final public class Neutral200DividerView: UICollectionReusableView { - override init(frame: CGRect) { - super.init(frame: frame) - backgroundColor = .neutral200 - layer.zPosition = -1 - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - public override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) { - super.apply(layoutAttributes) - self.frame.size.height = 1 - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/Neutral300DividerView.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/Neutral300DividerView.swift deleted file mode 100644 index 551557c0..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/Neutral300DividerView.swift +++ /dev/null @@ -1,20 +0,0 @@ -import UIKit - -import DesignSystem - -final public class Neutral300DividerView: UICollectionReusableView { - override init(frame: CGRect) { - super.init(frame: frame) - backgroundColor = .neutral300 - layer.zPosition = -1 - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - public override func apply(_ layoutAttributes: UICollectionViewLayoutAttributes) { - super.apply(layoutAttributes) - self.frame.size.height = 1 - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/PopularSearchHeaderView.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/PopularSearchHeaderView.swift deleted file mode 100644 index bf633d0d..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/PopularSearchHeaderView.swift +++ /dev/null @@ -1,78 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -public final class PopularSearchHeaderView: UICollectionReusableView { - // MARK: - Type - private enum Constant { - static let spacing: CGFloat = 4 - static let topInset: CGFloat = 24 - } - - // MARK: - Components - private let titleLabel = UILabel() - private let subtitleLabel = UILabel() - - // MARK: - Init - override init(frame: CGRect) { - super.init(frame: frame) - addViews() - setupConstraints() - configureUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MAKR: - SetUp -private extension PopularSearchHeaderView { - func addViews() { - addSubview(titleLabel) - addSubview(subtitleLabel) - } - - func setupConstraints() { - titleLabel.snp.makeConstraints { make in - make.top.equalToSuperview().inset(Constant.topInset) - make.leading.equalToSuperview() - } - - subtitleLabel.snp.makeConstraints { make in - make.leading.equalTo(titleLabel.snp.trailing).priority(.low) - make.trailing.equalToSuperview().priority(.high) - make.centerY.equalTo(titleLabel) - } - } - - func configureUI() { - titleLabel.font = .sub_l_b - titleLabel.textAlignment = .left - - subtitleLabel.font = .cp_s_r - subtitleLabel.textColor = .neutral500 - subtitleLabel.textAlignment = .left - } -} - -// MARK: - Methods -public extension PopularSearchHeaderView { - func inject(mainText: String, subText: String, hasRecent: Bool) { - titleLabel.text = mainText - subtitleLabel.text = subText - if hasRecent { - titleLabel.snp.remakeConstraints { make in - make.top.equalToSuperview().inset(Constant.topInset) - make.horizontalEdges.equalToSuperview() - } - } else { - titleLabel.snp.remakeConstraints { make in - make.top.equalToSuperview() - make.horizontalEdges.equalToSuperview() - } - } - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/RecentSearchHeaderView.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/RecentSearchHeaderView.swift deleted file mode 100644 index 878213a8..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/RecentSearchHeaderView.swift +++ /dev/null @@ -1,62 +0,0 @@ -import DesignSystem -import SnapKit -import UIKit - -public final class RecentSearchHeaderView: UICollectionReusableView { - // MARK: - Components - private let titleLabel = UILabel() - public let deleteButton = UIButton() - private let spacer = UIView() - - // MARK: - Init - public override init(frame: CGRect) { - super.init(frame: frame) - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Setup -private extension RecentSearchHeaderView { - func addViews() { - addSubview(titleLabel) - addSubview(spacer) - addSubview(deleteButton) - } - - func setupConstraints() { - titleLabel.snp.makeConstraints { make in - make.leading.equalToSuperview() - make.centerY.equalToSuperview() - } - - spacer.snp.makeConstraints { make in - make.verticalEdges.equalToSuperview() - make.leading.equalTo(titleLabel.snp.trailing) - make.trailing.equalTo(deleteButton.snp.leading) - } - - deleteButton.snp.makeConstraints { make in - make.trailing.equalToSuperview() - make.centerY.equalToSuperview() - } - } - - func configureUI() { - titleLabel.attributedText = .makeStyledString( - font: .sub_m_b, - text: "최근 검색어", - alignment: .left - ) - - deleteButton.setTitle("모두 지우기", for: .normal) - deleteButton.titleLabel?.font = .b_s_r - deleteButton.setTitleColor(.neutral600, for: .normal) - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/SearchDividerView.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/SearchDividerView.swift deleted file mode 100644 index 63e4b8c4..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/SearchDividerView.swift +++ /dev/null @@ -1,35 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -final public class SearchDividerView: UICollectionReusableView { - let view: UIView = { - let view = UIView() - view.backgroundColor = .neutral100 - return view - }() - - override init(frame: CGRect) { - super.init(frame: frame) - - addViews() - setupConstraints() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - func addViews() { - addSubview(view) - } - - func setupConstraints() { - view.snp.makeConstraints { make in - make.centerY.horizontalEdges.equalToSuperview() - make.height.equalTo(10) - } - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/SettingBackgroundView.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/SettingBackgroundView.swift deleted file mode 100644 index 6f8dc1e4..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/SettingBackgroundView.swift +++ /dev/null @@ -1,44 +0,0 @@ -import DesignSystem -import UIKit - -final public class SettingBackgroundView: UICollectionReusableView { - // MARK: - Type - enum Constant { - static let radius: CGFloat = 16 - static let topInset: CGFloat = 20 - static let horizontalInset: CGFloat = 16 - } - - private let containerView: UIView = { - let view = UIView() - view.backgroundColor = .whiteMLS - view.layer.cornerRadius = Constant.radius - return view - }() - - override init(frame: CGRect) { - super.init(frame: frame) - backgroundColor = .neutral100 - addViews() - setConstraints() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} - -private extension SettingBackgroundView { - private func addViews() { - addSubview(containerView) - } - - func setConstraints() { - containerView.snp.makeConstraints { make in - make.top.equalToSuperview().inset(Constant.topInset) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.bottom.equalToSuperview() - } - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/SubTitleBoldHeaderView.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/SubTitleBoldHeaderView.swift deleted file mode 100644 index ea34e22b..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/SubTitleBoldHeaderView.swift +++ /dev/null @@ -1,42 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -final public class SubTitleBoldHeaderView: UICollectionReusableView { - - private let headerLabel: UILabel = { - let label = UILabel() - return label - }() - - override init(frame: CGRect) { - super.init(frame: frame) - addViews() - setupConstraints() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension SubTitleBoldHeaderView { - func addViews() { - addSubview(headerLabel) - } - - func setupConstraints() { - headerLabel.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } -} - -public extension SubTitleBoldHeaderView { - func inject(title: String?) { - headerLabel.attributedText = .makeStyledString(font: .sub_m_b, text: title, alignment: .left) - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/SupportBackgroundView.swift b/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/SupportBackgroundView.swift deleted file mode 100644 index 2a5d5153..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/UICollectionReusableViews/Views/SupportBackgroundView.swift +++ /dev/null @@ -1,45 +0,0 @@ -import DesignSystem -import UIKit - -final public class SupportBackgroundView: UICollectionReusableView { - // MARK: - Type - enum Constant { - static let radius: CGFloat = 16 - static let topInset: CGFloat = 16 - static let bottomInset: CGFloat = 20 - static let horizontalInset: CGFloat = 16 - } - - private let containerView: UIView = { - let view = UIView() - view.backgroundColor = .whiteMLS - view.layer.cornerRadius = Constant.radius - return view - }() - - override init(frame: CGRect) { - super.init(frame: frame) - backgroundColor = .neutral100 - addViews() - setConstraints() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} - -private extension SupportBackgroundView { - private func addViews() { - addSubview(containerView) - } - - func setConstraints() { - containerView.snp.makeConstraints { make in - make.top.equalToSuperview().inset(Constant.topInset) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.bottom.equalToSuperview().inset(Constant.bottomInset) - } - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/AppRouter.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/AppRouter.swift deleted file mode 100644 index 1a74585b..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/AppRouter.swift +++ /dev/null @@ -1,20 +0,0 @@ -import UIKit - -public enum AppRouter { - public static func setRoot(_ viewController: UIViewController, animated: Bool = true) { - guard let window = UIApplication.shared.connectedScenes - .compactMap({ $0 as? UIWindowScene }) - .flatMap({ $0.windows }) - .first(where: { $0.isKeyWindow }) else { return } - - if animated { - UIView.transition(with: window, duration: 0.3, options: .transitionCrossDissolve, animations: { - window.rootViewController = viewController - }) - } else { - window.rootViewController = viewController - } - - window.makeKeyAndVisible() - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/CompositionalLayoutBuilder/CompositionalLayoutBuilder.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/CompositionalLayoutBuilder/CompositionalLayoutBuilder.swift deleted file mode 100644 index 358cdad1..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/CompositionalLayoutBuilder/CompositionalLayoutBuilder.swift +++ /dev/null @@ -1,28 +0,0 @@ -import UIKit - -public final class CompositionalLayoutBuilder { - private var sections: [NSCollectionLayoutSection] = [] - - public init() {} - - @discardableResult - public func section(_ build: (CompositionalSectionBuilder) -> CompositionalSectionBuilder) -> Self { - let builder = CompositionalSectionBuilder() - if let section = build(builder).build() { - sections.append(section) - } - return self - } - - public func build() -> UICollectionViewCompositionalLayout { - return UICollectionViewCompositionalLayout { index, _ in - guard index < self.sections.count else { return nil } - return self.sections[index] - } - } - - public func setSections(_ sections: [NSCollectionLayoutSection]) -> Self { - self.sections = sections - return self - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/CompositionalLayoutBuilder/CompositionalSectionBuilder.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/CompositionalLayoutBuilder/CompositionalSectionBuilder.swift deleted file mode 100644 index 98a39810..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/CompositionalLayoutBuilder/CompositionalSectionBuilder.swift +++ /dev/null @@ -1,201 +0,0 @@ -import UIKit - -public final class CompositionalSectionBuilder { - private var item: NSCollectionLayoutItem? - private var group: NSCollectionLayoutGroup? - private var section: NSCollectionLayoutSection? - - public enum Direction { - case horizontal, vertical - } - - public init(item: NSCollectionLayoutItem? = nil, group: NSCollectionLayoutGroup? = nil, section: NSCollectionLayoutSection? = nil) { - self.item = item - self.group = group - self.section = section - } - - @discardableResult - public func item(width: NSCollectionLayoutDimension, height: NSCollectionLayoutDimension) -> Self { - let size = NSCollectionLayoutSize(widthDimension: width, heightDimension: height) - item = NSCollectionLayoutItem(layoutSize: size) - return self - } - - @discardableResult - public func group(_ direction: Direction, width: NSCollectionLayoutDimension, height: NSCollectionLayoutDimension, count: Int? = nil) -> Self { - guard let item = item else { return self } - let size = NSCollectionLayoutSize(widthDimension: width, heightDimension: height) - switch direction { - case .horizontal: - if let count = count { - group = NSCollectionLayoutGroup.horizontal(layoutSize: size, subitem: item, count: count) - } else { - group = NSCollectionLayoutGroup.horizontal(layoutSize: size, subitems: [item]) - } - case .vertical: - if let count = count { - group = NSCollectionLayoutGroup.vertical(layoutSize: size, subitem: item, count: count) - } else { - group = NSCollectionLayoutGroup.vertical(layoutSize: size, subitems: [item]) - } - } - return self - } - - @discardableResult - public func customGroup(group: (NSCollectionLayoutItem) -> NSCollectionLayoutGroup) -> Self { - guard let item = item else { return self } - self.group = group(item) - return self - } - - @discardableResult - public func buildSection() -> Self { - guard let group = group else { return self } - section = NSCollectionLayoutSection(group: group) - return self - } - - @discardableResult - public func visibleItemsInvalidationHandler( - handler: @escaping ([any NSCollectionLayoutVisibleItem], CGPoint, any NSCollectionLayoutEnvironment) -> Void - ) -> Self { - section?.visibleItemsInvalidationHandler = { visibleItems, scrollOffset, environment in - handler(visibleItems, scrollOffset, environment) - } - return self - } - - @discardableResult - public func orthogonalScrolling(_ behavior: UICollectionLayoutSectionOrthogonalScrollingBehavior) -> Self { - section?.orthogonalScrollingBehavior = behavior - return self - } - - @discardableResult - public func contentInsets(_ insets: NSDirectionalEdgeInsets) -> Self { - section?.contentInsets = insets - return self - } - - @discardableResult - public func header(height: CGFloat, isSticky: Bool = false) -> Self { - guard let section = section else { return self } - - let size = NSCollectionLayoutSize(widthDimension: .fractionalWidth(1), heightDimension: .absolute(height)) - let header = NSCollectionLayoutBoundarySupplementaryItem( - layoutSize: size, - elementKind: UICollectionView.elementKindSectionHeader, - alignment: .top - ) - - header.pinToVisibleBounds = isSticky - section.boundarySupplementaryItems = [header] - return self - } - - public func build() -> NSCollectionLayoutSection? { - return section - } - - @discardableResult - public func interGroupSpacing(_ spacing: CGFloat) -> Self { - section?.interGroupSpacing = spacing - return self - } - - @discardableResult - public func interItemSpacing(_ spacing: NSCollectionLayoutSpacing) -> Self { - group?.interItemSpacing = spacing - return self - } - - @discardableResult - public func footer(height: CGFloat) -> Self { - let footer = NSCollectionLayoutBoundarySupplementaryItem( - layoutSize: .init( - widthDimension: .fractionalWidth(1), - heightDimension: .absolute(height) - ), - elementKind: UICollectionView.elementKindSectionFooter, - alignment: .bottom - ) - section?.boundarySupplementaryItems.append(footer) - return self - } - - @discardableResult - public func supplementaryItem( - kind: String, - height: CGFloat, - alignment: NSRectAlignment - ) -> Self { - let header = NSCollectionLayoutBoundarySupplementaryItem( - layoutSize: .init( - widthDimension: .fractionalWidth(1), - heightDimension: .absolute(height) - ), - elementKind: kind, - alignment: alignment - ) - section?.boundarySupplementaryItems.append(header) - return self - } - - @discardableResult - public func decorationItem( - kind: String, - insets: NSDirectionalEdgeInsets = .zero - ) -> Self { - let decoration = NSCollectionLayoutDecorationItem.background(elementKind: kind) - decoration.contentInsets = insets - section?.decorationItems.append(decoration) - return self - } - - @discardableResult - public func nestedGroup( - outerDirection: Direction, - outerWidth: NSCollectionLayoutDimension, - outerHeight: NSCollectionLayoutDimension, - innerDirection: Direction, - innerWidth: NSCollectionLayoutDimension, - innerHeight: NSCollectionLayoutDimension, - innerCount: Int? = nil, - innerSpacing: CGFloat - ) -> Self { - guard let item = item else { return self } - - // 내부 그룹 - let innerSize = NSCollectionLayoutSize(widthDimension: innerWidth, heightDimension: innerHeight) - let innerGroup: NSCollectionLayoutGroup - switch innerDirection { - case .horizontal: - if let count = innerCount { - innerGroup = NSCollectionLayoutGroup.horizontal(layoutSize: innerSize, subitem: item, count: count) - } else { - innerGroup = NSCollectionLayoutGroup.horizontal(layoutSize: innerSize, subitems: [item]) - } - innerGroup.interItemSpacing = .fixed(innerSpacing) - case .vertical: - if let count = innerCount { - innerGroup = NSCollectionLayoutGroup.vertical(layoutSize: innerSize, subitem: item, count: count) - } else { - innerGroup = NSCollectionLayoutGroup.vertical(layoutSize: innerSize, subitems: [item]) - } - innerGroup.interItemSpacing = .fixed(innerSpacing) - } - - // 외부 그룹 - let outerSize = NSCollectionLayoutSize(widthDimension: outerWidth, heightDimension: outerHeight) - switch outerDirection { - case .horizontal: - group = NSCollectionLayoutGroup.horizontal(layoutSize: outerSize, subitems: [innerGroup]) - case .vertical: - group = NSCollectionLayoutGroup.vertical(layoutSize: outerSize, subitems: [innerGroup]) - } - - return self - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/CompositionalLayoutBuilder/LayoutFactory.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/CompositionalLayoutBuilder/LayoutFactory.swift deleted file mode 100644 index a79c95f7..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/CompositionalLayoutBuilder/LayoutFactory.swift +++ /dev/null @@ -1,157 +0,0 @@ -import UIKit - -public class LayoutFactory { - public init() {} - - public static func getPageTabbarLayout(underLineController: TabBarUnderlineController? = nil) -> CompositionalSectionBuilder { - return CompositionalSectionBuilder() - .item(width: .estimated(100), height: .absolute(40)) - .group(.horizontal, width: .estimated(100), height: .absolute(40)) - .buildSection() - .orthogonalScrolling(.continuous) - .interGroupSpacing(28) - .contentInsets(.init(top: 0, leading: 16, bottom: 0, trailing: 16)) - .visibleItemsInvalidationHandler { _, offset, _ in - underLineController?.updateScrollOffset(offset) - } - } - - public static func getItemTagListSection(width: CGFloat = 50) -> CompositionalSectionBuilder { - return CompositionalSectionBuilder() - .item(width: .estimated(width), height: .absolute(34)) - .group(.horizontal, width: .fractionalWidth(1), height: .absolute(34)) - .interItemSpacing(.fixed(8)) - .buildSection() - .header(height: 22) - .interGroupSpacing(8) - .contentInsets(.init(top: 12, leading: 16, bottom: 32, trailing: 16)) - } - - public static func getLevelRangeSection() -> CompositionalSectionBuilder { - return CompositionalSectionBuilder() - .item(width: .fractionalWidth(1), height: .estimated(100)) - .group(.horizontal, width: .fractionalWidth(1), height: .estimated(100)) - .buildSection() - .header(height: 22) - .contentInsets(.init(top: 12, leading: 16, bottom: 32, trailing: 16)) - } - - public func getDictionaryListLayout(isFilterHidden: Bool = true) -> CompositionalSectionBuilder { - return CompositionalSectionBuilder() - .item(width: .fractionalWidth(1.0), height: .absolute(104)) - .group(.horizontal, width: .fractionalWidth(1.0), height: .absolute(104)) - .buildSection() - .interGroupSpacing(10) - .contentInsets(.init(top: isFilterHidden ? 20 : 0, leading: 16, bottom: 0, trailing: 16)) - } - - public func getTagChipLayout() -> CompositionalSectionBuilder { - return CompositionalSectionBuilder() - .item(width: .estimated(70), height: .estimated(32)) - .group(.horizontal, width: .estimated(70), height: .estimated(32)) - .buildSection() - .header(height: 44) - .orthogonalScrolling(.continuous) - .interGroupSpacing(8) - .contentInsets(.init(top: 24, leading: 16, bottom: 24, trailing: 16)) - } - - public func getDecorationSection() -> CompositionalSectionBuilder { - return CompositionalSectionBuilder() - .item(width: .fractionalWidth(1.0), height: .absolute(1)) - .group(.vertical, width: .fractionalWidth(1.0), height: .absolute(10)) - .buildSection() - .decorationItem(kind: SearchDividerView.identifier) - .contentInsets(.init(top: 5, leading: 0, bottom: 5, trailing: 0)) - } - - public func getPopularResultLayout() -> CompositionalSectionBuilder { - return CompositionalSectionBuilder() - .item(width: .fractionalWidth(1.0), height: .estimated(40)) - .group(.horizontal, width: .fractionalWidth(1.0), height: .estimated(40), count: 2) - .buildSection() - .header(height: 44) - .contentInsets(.init(top: 16, leading: 16, bottom: 16, trailing: 16)) - } - - public static func getNotificationLayout() -> CompositionalSectionBuilder { - return CompositionalSectionBuilder() - .item(width: .fractionalWidth(1.0), height: .estimated(86)) - .group(.vertical, width: .fractionalWidth(1.0), height: .estimated(86)) - .buildSection() - .interGroupSpacing(8) - .contentInsets(.init(top: 0, leading: 16, bottom: 0, trailing: 16)) - } - - public func getCollectionModalLayout() -> CompositionalSectionBuilder { - return CompositionalSectionBuilder() - .item(width: .fractionalWidth(1.0), height: .absolute(72)) - .group(.vertical, width: .fractionalWidth(1.0), height: .absolute(72)) - .buildSection() - .interGroupSpacing(1) - } - - public func getCollectionListLayout() -> CompositionalSectionBuilder { - return CompositionalSectionBuilder() - .item(width: .fractionalWidth(1.0), height: .absolute(96)) - .group(.vertical, width: .fractionalWidth(1.0), height: .absolute(96)) - .buildSection() - .interGroupSpacing(10) - .contentInsets(.init(top: 0, leading: 16, bottom: 0, trailing: 16)) - } - - public func getCollectionListEditLayout() -> CompositionalSectionBuilder { - return CompositionalSectionBuilder() - .item(width: .fractionalWidth(1.0), height: .absolute(104)) - .group(.vertical, width: .fractionalWidth(1.0), height: .absolute(104)) - .buildSection() - .interGroupSpacing(10) - .contentInsets(.init(top: 20, leading: 16, bottom: 20, trailing: 16)) - } - - // 이 아래는 정리 - public func getMyPageMainLayout() -> CompositionalSectionBuilder { - return CompositionalSectionBuilder() - .item(width: .fractionalWidth(1.0), height: .estimated(200)) - .group(.vertical, width: .fractionalWidth(1.0), height: .estimated(200)) - .buildSection() - } - - public func getMyPageSettingLayout() -> CompositionalSectionBuilder { - return CompositionalSectionBuilder() - .item(width: .fractionalWidth(1.0), height: .absolute(50)) - .group(.vertical, width: .fractionalWidth(1.0), height: .estimated(100)) - .buildSection() - .decorationItem(kind: SettingBackgroundView.identifier) - .contentInsets(.init(top: 20 + 10, leading: 16 + 10, bottom: 10, trailing: 16 + 10)) - } - - public func getMyPageSupportLayout() -> CompositionalSectionBuilder { - return CompositionalSectionBuilder() - .item(width: .fractionalWidth(1.0), height: .absolute(50)) - .group(.vertical, width: .fractionalWidth(1.0), height: .estimated(100)) - .buildSection() - .decorationItem(kind: SupportBackgroundView.identifier) - .contentInsets(.init(top: 16 + 10, leading: 16 + 10, bottom: 20 + 10, trailing: 16 + 10)) - } - - public func getSelectImageLayout() -> CompositionalSectionBuilder { - let itemSize = NSCollectionLayoutSize( - widthDimension: .fractionalWidth(1.0/3.0), - heightDimension: .fractionalWidth(1.0/3.0) - ) - let item = NSCollectionLayoutItem(layoutSize: itemSize) - - let groupSize = NSCollectionLayoutSize( - widthDimension: .fractionalWidth(1.0), - heightDimension: .fractionalWidth(1.0/3.0) - ) - let group = NSCollectionLayoutGroup.horizontal(layoutSize: groupSize, subitems: [item, item, item]) - group.interItemSpacing = .fixed(16) - - let section = NSCollectionLayoutSection(group: group) - section.contentInsets = NSDirectionalEdgeInsets(top: 20, leading: 16, bottom: 16, trailing: 16) - - return CompositionalSectionBuilder(section: section) - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/Int+.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/Int+.swift deleted file mode 100644 index 26a74e1b..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/Int+.swift +++ /dev/null @@ -1,16 +0,0 @@ -import Foundation - -extension Array where Element == Int { - public func changeKoreanDate() -> String { - return "\(self[0])년 \(self[1])월 \(self[2])일 \(self[3]):\(String(format: "%02d", self[4]))" - } -} - -extension Int { - var formatted: String { - let formatter = NumberFormatter() - formatter.numberStyle = .decimal - formatter.locale = Locale(identifier: "ko_KR") - return formatter.string(from: NSNumber(value: self)) ?? "\(self)" - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/Reactive+.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/Reactive+.swift deleted file mode 100644 index 68a22b6c..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/Reactive+.swift +++ /dev/null @@ -1,32 +0,0 @@ -import UIKit - -import RxCocoa -import RxSwift - -public extension Reactive where Base: UIViewController { - - var viewDidLoad: ControlEvent { - let source = self.methodInvoked(#selector(Base.viewDidLoad)).map( { _ in }) - return ControlEvent(events: source) - } - - var viewWillAppear: ControlEvent { - let source = self.methodInvoked(#selector(Base.viewWillAppear)).map( { _ in }) - return ControlEvent(events: source) - } - - var viewDidAppear: ControlEvent { - let source = self.methodInvoked(#selector(Base.viewDidAppear)).map( { _ in }) - return ControlEvent(events: source) - } - - var viewWillDisappear: ControlEvent { - let source = self.methodInvoked(#selector(Base.viewWillDisappear)).map( { _ in }) - return ControlEvent(events: source) - } - - var viewDidDisappear: ControlEvent { - let source = self.methodInvoked(#selector(Base.viewDidDisappear)).map( { _ in }) - return ControlEvent(events: source) - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift deleted file mode 100644 index 59cf62a1..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/String+.swift +++ /dev/null @@ -1,33 +0,0 @@ -import Foundation - -extension String { - public func isOnlyKorean() -> Bool { - return !self.contains { char in - guard let scalar = char.unicodeScalars.first else { return false } - return (0x3131 ... 0x3163).contains(scalar.value) - } - } - - private static let inputDateFormatter: DateFormatter = { - let formatter = DateFormatter() - formatter.locale = Locale(identifier: "ko_KR") - formatter.timeZone = TimeZone(identifier: "Asia/Seoul") - formatter.dateFormat = "yyyy-MM-dd'T'HH:mm:ss" - return formatter - - }() - - private static let outputDateFormatter: DateFormatter = { - let formatter = DateFormatter() - formatter.locale = Locale(identifier: "ko_KR") - formatter.dateFormat = "yyyy.MM.dd HH:mm" - return formatter - }() - - public func toDisplayDateString() -> String { - guard let date = Self.inputDateFormatter.date(from: self) else { - return self - } - return Self.outputDateFormatter.string(from: date) - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/UICollectionReusableView+.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/UICollectionReusableView+.swift deleted file mode 100644 index 19232f48..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/Extension/UICollectionReusableView+.swift +++ /dev/null @@ -1,7 +0,0 @@ -import UIKit - -extension UICollectionReusableView { - public static var identifier: String { - return String(describing: self) - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/GuideAlertFactory.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/GuideAlertFactory.swift deleted file mode 100644 index d5d39683..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/GuideAlertFactory.swift +++ /dev/null @@ -1,109 +0,0 @@ -import UIKit - -import DesignSystem - -import RxCocoa -import RxSwift -import SnapKit - -public enum GuideAlertFactory { - private static var currentAlertView: GuideAlert? - private static var dimmedView: UIView? - private static var containerView: UIView? - private static var disposeBag = DisposeBag() - - public static func show( - mainText: String, - ctaText: String, - cancelText: String? = nil, - ctaAction: @escaping () -> Void, - cancelAction: (() -> Void)? = nil - ) { - let alert = GuideAlert(mainText: mainText, ctaText: ctaText, cancelText: cancelText) - presentAlert(alert: alert, ctaAction: ctaAction, cancelAction: cancelAction) - } - - public static func showAuthAlert( - type: AuthGuideAlert.AuthGuideAlertType, - ctaAction: @escaping () -> Void, - cancelAction: (() -> Void)? = nil - ) { - let alert = AuthGuideAlert(type: type) - presentAlert(alert: alert, ctaAction: ctaAction, cancelAction: cancelAction) - } - - private static func presentAlert( - alert: GuideAlert, - ctaAction: @escaping () -> Void, - cancelAction: (() -> Void)? = nil - ) { - guard currentAlertView == nil, dimmedView == nil else { return } - guard let windowScene = UIApplication.shared.connectedScenes - .first(where: { $0.activationState == .foregroundActive }) as? UIWindowScene, - let window = windowScene.windows.first(where: { $0.isKeyWindow }) else { return } - - let container = UIView(frame: window.bounds) - window.addSubview(container) - - let dimmed = UIView() - dimmed.backgroundColor = UIColor.black.withAlphaComponent(0.4) - dimmed.alpha = 0 - container.addSubview(dimmed) - dimmed.snp.makeConstraints { $0.edges.equalToSuperview() } - - alert.alpha = 0 - container.addSubview(alert) - alert.snp.makeConstraints { - $0.center.equalToSuperview() - $0.leading.greaterThanOrEqualToSuperview().offset(16) - $0.trailing.lessThanOrEqualToSuperview().offset(-16) - } - - disposeBag = DisposeBag() - - alert.ctaButton.rx.tap - .bind { - dismiss() - ctaAction() - } - .disposed(by: disposeBag) - - if let cancelButton = alert.cancelButton { - cancelButton.rx.tap - .bind { - dismiss() - cancelAction?() - } - .disposed(by: disposeBag) - } - - currentAlertView = alert - dimmedView = dimmed - containerView = container - - UIView.animate(withDuration: 0.25) { - dimmed.alpha = 1 - alert.alpha = 1 - } - } - - public static func dismiss() { - guard let alert = currentAlertView, - let dimmed = dimmedView, - let container = containerView - else { return } - - UIView.animate(withDuration: 0.25, animations: { - alert.alpha = 0 - dimmed.alpha = 0 - }, completion: { _ in - alert.removeFromSuperview() - dimmed.removeFromSuperview() - container.removeFromSuperview() - currentAlertView = nil - dimmedView = nil - containerView = nil - disposeBag = DisposeBag() - }) - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/ImageLoader/ImageLoader.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/ImageLoader/ImageLoader.swift deleted file mode 100644 index 16bcd70d..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/ImageLoader/ImageLoader.swift +++ /dev/null @@ -1,173 +0,0 @@ -import UIKit - -import DesignSystem - -public enum ImageLoaderError: Error { - case invalidURL - case networkError(description: String?) - case convertError(description: String?) - case cacheNotFoundError -} - -/// 이미지 로더 설정 클래스 -public final class ImageLoaderConfigure { - /// 메모리 캐시 만료 시간 (기본값 300초) - public var memoryCacheExpiration: TimeInterval = 300 - /// 메모리 캐시 갯수 제한 (기본값 100개) - public var memoryCacheCountLimit = 100 // 최대 100개까지 저장 - /// 메모리 코스트 제한 (최대 50MB까지 저장 기본 값 50MB) - public var memoryCacheTotalCostLimit = 50 * 1024 * 1024 - /// 디스크 캐시 만료 시간 (기본값 일주일) - public var diskCacheExpiration: TimeInterval = 7 * 24 * 60 * 60 // 7일 - /// 디스크 캐시 갯수 제한 - public var diskCacheCountLimit = 1000 // 최대 1000개 파일 - /// 디스크 캐시 용량 제한 (최대 500MB) - public var diskCacheSizeLimit = 500 * 1024 * 1024 // 500MB -} - -/// URL을 통해 이미지를 비동기적으로 로드하는 클래스 -public final class ImageLoader { - public static let shared = ImageLoader() - - /// 이미지 로더 설정 객체 - public let configure = ImageLoaderConfigure() - - private init() {} - - public func loadImage(stringURL: String?, defaultImage: UIImage? = DesignSystemAsset.image(named: "connectionError"), completion: @escaping (UIImage?) -> Void) { - guard let stringURL, - let url = URL(string: stringURL), - ["http", "https"].contains(url.scheme?.lowercased() ?? "") - else { - DispatchQueue.main.async { - completion(defaultImage) - } - return - } - loadImage(url: url, defaultImage: defaultImage, completion: completion) - } - - /// URL을 통해 이미지를 로드하고, 실패 시 기본 이미지를 반환하는 메서드 - /// - Parameters: - /// - stringURL: 이미지 URL 문자열 - /// - defaultImage: 로드 실패 시 반환할 기본 이미지 - /// - completion: 로드 완료 후 호출되는 클로저 - public func loadImage(url: URL?, defaultImage: UIImage? = DesignSystemAsset.image(named: "connectionError"), completion: @escaping (UIImage?) -> Void) { - loadImage(url: url) { result in - DispatchQueue.main.async { - switch result { - case .success(let image): - completion(image) - case .failure: - completion(defaultImage) - } - } - } - } -} - -private extension ImageLoader { - /// 네트워크 및 스토리지를 통해 이미지를 로드하는 내부 메서드 - /// - Parameters: - /// - stringURL: 이미지 URL 문자열 - /// - completion: 로드 완료 후 호출되는 클로저 - func loadImage(url: URL?, completion: @escaping (Result) -> Void) { - guard let url else { - completion(.failure(ImageLoaderError.invalidURL)) - return - } - - // 1. 메모리 캐시 확인 - if let cachedImage = MemoryStorage.shared.fetchImage(stringURL: url.absoluteString) { - completion(.success(cachedImage)) - return - } - - // 2. 디스크 캐시 확인 - DiskStorage.shared.fetchImage(url: url) { image in - if let image { - MemoryStorage.shared.saveImage(image: image, stringURL: url.absoluteString) - completion(.success(image)) - } else { - // 3. 네트워크 요청 - self.fetchDataFrom(url: url) { result in - switch result { - case .success(let data): - guard let data else { - completion(.failure(ImageLoaderError.convertError(description: "No data received"))) - return - } - - self.decodeImageData(data, url: url, completion: completion) - - case .failure(let error): - completion(.failure(error)) - } - } - } - } - } - - private func decodeImageData(_ data: Data, url: URL, completion: @escaping (Result) -> Void) { - if let gifImage = decodeGIF(data: data, url: url) { - completion(.success(gifImage)) - return - } - - // 정적 이미지 처리 - if let image = UIImage(data: data) { - MemoryStorage.shared.saveImage(image: image, stringURL: url.absoluteString) - DiskStorage.shared.saveImage(image: image, url: url) - completion(.success(image)) - } else { - completion(.failure(ImageLoaderError.convertError(description: "Failed to convert data to UIImage"))) - } - } - - private func decodeGIF(data: Data, url: URL) -> UIImage? { - guard let source = CGImageSourceCreateWithData(data as CFData, nil) else { return nil } - - let frameCount = CGImageSourceGetCount(source) - guard frameCount > 1 else { return nil } // GIF가 아님 - - var images: [UIImage] = [] - var duration: TimeInterval = 0 - - for index in 0 ..< frameCount { - guard let cgImage = CGImageSourceCreateImageAtIndex(source, index, nil) else { continue } - let uiImage = UIImage(cgImage: cgImage) - images.append(uiImage) - - if let properties = CGImageSourceCopyPropertiesAtIndex(source, index, nil) as? [String: Any], - let gifProps = properties[kCGImagePropertyGIFDictionary as String] as? [String: Any], - let delay = gifProps[kCGImagePropertyGIFUnclampedDelayTime as String] as? Double { - duration += delay - } - } - - let finalDuration = duration > 0 ? duration : Double(frameCount) * 0.1 - let animatedImage = UIImage.animatedImage(with: images, duration: finalDuration) - - if let animatedImage { - MemoryStorage.shared.saveImage(image: animatedImage, stringURL: url.absoluteString) - DiskStorage.shared.saveImage(image: animatedImage, url: url) - } - - return animatedImage - } - - /// URL을 통해 데이터를 요청하는 메서드 - /// - Parameters: - /// - url: 요청할 URL 객체 - /// - completion: 요청 완료 후 호출되는 클로저 - func fetchDataFrom(url: URL, completion: @escaping (Result) -> Void) { - let task = URLSession.shared.dataTask(with: url) { data, _, error in - if let error = error { - completion(.failure(ImageLoaderError.networkError(description: "Network Error: \(error.localizedDescription)"))) - return - } - completion(.success(data)) - } - task.resume() - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/ImageLoader/Storage/DiskStorage.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/ImageLoader/Storage/DiskStorage.swift deleted file mode 100644 index e4c1cd0c..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/ImageLoader/Storage/DiskStorage.swift +++ /dev/null @@ -1,209 +0,0 @@ -import os -import UIKit - -/// 캐시할 이미지와 추가 데이터를 저장하는 구조체 -internal struct CacheData { - let fileName: String - let creationDate: Date - let expirationDate: Date - let fileSize: Int - - /// 초기화 메소드 - /// - Parameters: - /// - fileName: 재구성한 파일명 - /// - creationDate: 만료일 계산을 위한 생성날짜 - /// - expiration: 계산된 만료기간 - /// - fileSize: 파일 크기 - init(fileName: String, creationDate: Date, expiration: TimeInterval, fileSize: Int) { - self.fileName = fileName - self.creationDate = creationDate - self.expirationDate = creationDate.addingTimeInterval(expiration) - self.fileSize = fileSize - } - - var isExpired: Bool { - return Date() > expirationDate - } -} - -internal final class DiskStorage { - // 싱글톤 인스턴스 - static let shared = DiskStorage() - - private let fileManager = FileManager.default - private let cacheDirectory: URL - // 우선순위 보장과 저장시 안정성을 위한 큐 - private let queue = DispatchQueue(label: "com.diskStorage", attributes: .concurrent) - // fileName을 키로 캐시데이터 저장 - private var cacheDatas: [String: CacheData] = [:] - private var totalCacheSize: Int = 0 - - private init() { - guard let cacheDirectory = fileManager.urls(for: .cachesDirectory, in: .userDomainMask).first else { - fatalError("시스템 손상") - } - self.cacheDirectory = cacheDirectory.appendingPathComponent("ImageCache") - try? fileManager.createDirectory(at: cacheDirectory, withIntermediateDirectories: true) - // 캐시저장소 로드 - loadCacheData() - // 주기적으로 정리 - startCacheCleanup() - } - - /// 캐싱된 이미지를 불러오는 메소드 - /// - Parameters: - /// - url: 이미지 주소 - /// - completion: url에 해당하는 이미지를 return (없으면 nil) - func fetchImage(url: URL, completion: @escaping (UIImage?) -> Void) { - queue.async { [weak self] in - guard let self else { - DispatchQueue.main.async { completion(nil) } - return - } - - let fileName = self.createFilePath(url: url) - let fileURL = self.cacheDirectory.appendingPathComponent(fileName) - - // 기존 저장소 확인 - guard let cacheData = self.cacheDatas[fileName], !cacheData.isExpired else { - self.cleanCache(key: fileName) - DispatchQueue.main.async { completion(nil) } - return - } - - if self.fileManager.fileExists(atPath: fileURL.path), - let imageData = try? Data(contentsOf: fileURL), - let image = UIImage(data: imageData) { - DispatchQueue.main.async { completion(image) } - } else { - // 파일이 손상된 경우에만 cleanCache 호출 - self.cleanCache(key: fileName) - DispatchQueue.main.async { completion(nil) } - } - } - } - - /// 이미지를 캐시에 저장하는 메소드 - /// - Parameters: - /// - image: 이미지 - /// - url: 이미지 주소 - func saveImage(image: UIImage, url: URL) { - queue.async(flags: .barrier) { [weak self] in - guard let self, let data = image.jpegData(compressionQuality: 0.8) else { return } - - let fileName = self.createFilePath(url: url) - let fileURL = self.cacheDirectory.appendingPathComponent(fileName) - - if !self.fileManager.fileExists(atPath: fileURL.path) { - do { - try data.write(to: fileURL) - let cacheData = CacheData( - fileName: fileName, - creationDate: Date(), - expiration: ImageLoader.shared.configure.diskCacheExpiration, - fileSize: data.count - ) - self.cacheDatas[fileName] = cacheData - self.totalCacheSize += data.count - self.checkCache() - } catch { - os_log("디스크 캐시 저장 실패") - } - } - } - } - - /// 충돌 방지를 위한 파일 이름 재구성 메소드 - /// - Parameter url: 이미지 주소 - /// - Returns: 변경된 파일명을 return - private func createFilePath(url: URL) -> String { - // ToBe: - 파일명 길이 확인 - url.absoluteString - .replacingOccurrences(of: "/", with: "_") - .replacingOccurrences(of: ":", with: "_") - .addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) ?? url.lastPathComponent - } - - /// 캐시저장소를 로드하는 메소드 - private func loadCacheData() { - queue.async(flags: .barrier) { [weak self] in - guard let self else { return } - - do { - let files = try self.fileManager.contentsOfDirectory(at: self.cacheDirectory, includingPropertiesForKeys: [.creationDateKey, .fileSizeKey]) - for fileURL in files { - let fileName = fileURL.lastPathComponent - let attributes = try fileURL.resourceValues(forKeys: [.creationDateKey, .fileSizeKey]) - let creationDate = attributes.creationDate ?? Date() - let fileSize = attributes.fileSize ?? 0 - - // 기본 만료 시간 적용 - let cacheData = CacheData( - fileName: fileName, - creationDate: creationDate, - expiration: ImageLoader.shared.configure.diskCacheExpiration, - fileSize: fileSize - ) - self.cacheDatas[fileName] = cacheData - self.totalCacheSize += fileSize - } - } catch { - os_log("캐시 로드 실패") - } - } - } - - /// 캐시 삭제를 위한 제약을 검사하는 메소드 - private func checkCache() { - queue.async(flags: .barrier) { [weak self] in - guard let self else { return } - - let config = ImageLoader.shared.configure - - /// 만료된 캐시 제거 - self.cacheDatas.forEach { key, data in - if data.isExpired { - self.cleanCache(key: key) - } - } - - /// 개수 제한 - while self.cacheDatas.count > config.diskCacheCountLimit { - if let oldest = self.cacheDatas.min(by: { $0.value.creationDate < $1.value.creationDate }) { - self.cleanCache(key: oldest.key) - } - } - - /// 용량 제한 - while self.totalCacheSize > config.diskCacheSizeLimit { - if let oldest = self.cacheDatas.min(by: { $0.value.creationDate < $1.value.creationDate }) { - self.cleanCache(key: oldest.key) - } - } - } - } - - /// 저장된 캐시를 제거하는 메소드 - private func cleanCache(key: String) { - queue.async(flags: .barrier) { [weak self] in - guard let self, let cacheData = self.cacheDatas[key] else { return } - let fileURL = self.cacheDirectory.appendingPathComponent(cacheData.fileName) - try? self.fileManager.removeItem(at: fileURL) - self.totalCacheSize -= cacheData.fileSize - self.cacheDatas.removeValue(forKey: key) - } - } - - /// 주기적으로 캐시를 정리하는 메소드 - private func startCacheCleanup() { - DispatchQueue.global(qos: .background).async { [weak self] in - let timer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { _ in - self?.checkCache() - } - // 백그라운드에서 실행되는 타이머를 메인 루프에 추가 - RunLoop.current.add(timer, forMode: .common) - // 백그라운드 스레드에서 타이머를 계속 실행하기 위해 RunLoop를 유지 - RunLoop.current.run() - } - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/ImageLoader/Storage/MemoryStorage.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/ImageLoader/Storage/MemoryStorage.swift deleted file mode 100644 index 65f936cf..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/ImageLoader/Storage/MemoryStorage.swift +++ /dev/null @@ -1,101 +0,0 @@ -import UIKit - -/// 캐시할 이미지와 만료 시간을 저장하는 클래스 -internal class StorageData: NSObject { - let image: UIImage? /// 캐시된 이미지 - let expirationDate: Date /// 캐시 만료 시간 - - /// 초기화 메서드 - /// - Parameters: - /// - image: 저장할 이미지 - /// - expiration: 만료 시간 (초 단위) - init(image: UIImage?, expiration: TimeInterval) { - self.image = image - self.expirationDate = Date().addingTimeInterval(expiration) - } - - /// 캐시가 만료되었는지 확인하는 메서드 - /// - Returns: 만료 여부 (true: 만료됨, false: 유효함) - func isExpired() -> Bool { - return Date() > expirationDate - } -} - -/// 메모리 캐시를 관리하는 클래스 -internal final class MemoryStorage { - - /// 싱글톤 인스턴스 - static let shared = MemoryStorage() - - /// 이미지 캐시 저장소 - private let cache: NSCache = { - let cache = NSCache() - cache.countLimit = ImageLoader.shared.configure.memoryCacheCountLimit - cache.totalCostLimit = ImageLoader.shared.configure.memoryCacheTotalCostLimit - return cache - }() - - /// 현재 캐시에 저장된 키 목록 - private var cachedKeys: Set = [] - - /// 초기화 (자동 캐시 정리 시작) - private init() { - startCacheCleanup() - } - - /// 이미지를 캐시에 저장하는 메서드 - /// - Parameters: - /// - image: 저장할 이미지 - /// - stringURL: 이미지 URL 문자열 - func saveImage(image: UIImage?, stringURL: String) { - let cachedData = StorageData(image: image, expiration: ImageLoader.shared.configure.memoryCacheExpiration) - let cost = image?.jpegData(compressionQuality: 1.0)?.count ?? 1 - cache.setObject(cachedData, forKey: stringURL as NSString, cost: cost) - cachedKeys.insert(stringURL) - } - - /// 캐시에서 이미지를 가져오는 메서드 - /// - Parameter stringURL: 이미지 URL 문자열 - /// - Returns: 캐시된 UIImage (없으면 nil) - func fetchImage(stringURL: String) -> UIImage? { - if let cachedData = cache.object(forKey: stringURL as NSString), !cachedData.isExpired() { - return cachedData.image - } else { - removeData(stringURL: stringURL) - return nil - } - } - - /// 특정 URL의 캐시 데이터를 제거하는 메서드 - /// - Parameter stringURL: 제거할 이미지의 URL 문자열 - func removeData(stringURL: String) { - cache.removeObject(forKey: stringURL as NSString) - cachedKeys.remove(stringURL) - } - - /// 모든 캐시 데이터를 삭제하는 메서드 - func clearCache() { - cache.removeAllObjects() - cachedKeys.removeAll() - } - - /// 주기적으로 만료된 캐시를 정리하는 메서드 - private func startCacheCleanup() { - DispatchQueue.global(qos: .background).async { [weak self] in - guard let self = self else { return } - let cleanTimer = Timer.scheduledTimer(withTimeInterval: 60, repeats: true) { _ in - for key in self.cachedKeys { - let nsKey = key as NSString - if let cachedData = self.cache.object(forKey: nsKey), cachedData.isExpired() { - self.cache.removeObject(forKey: nsKey) - self.cachedKeys.remove(key) - } - } - } - // 백그라운드에서 실행되는 타이머를 메인 루프에 추가 - RunLoop.current.add(cleanTimer, forMode: .common) - // 백그라운드 스레드에서 타이머를 계속 실행하기 위해 RunLoop를 유지 - RunLoop.current.run() - } - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/ModalPresentable/ModalPresentable.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/ModalPresentable/ModalPresentable.swift deleted file mode 100644 index 8d2b0a76..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/ModalPresentable/ModalPresentable.swift +++ /dev/null @@ -1,25 +0,0 @@ -import UIKit - -public protocol ModalPresentable { - var modalHeight: CGFloat? { get } - var allowsTapToDismiss: Bool { get } -} - -public extension ModalPresentable { - var allowsTapToDismiss: Bool { return false } -} - -// 모달 구성 관련 상수 정의 -internal enum ModalConfig { - static let containerTransformY: CGFloat = 400 - static let containerBottomInset: CGFloat = 8 - static let containerHorizontalInset: CGFloat = 8 - static let containerCornerRadius: CGFloat = 20 - static let bottomSheetStyleBottomInset: CGFloat = 34 - static let bottomSheetStyleHorizontalInset: CGFloat = 20 - static let alertSheetStyleInset: CGFloat = 20 - - static let gestureBarTopInset: CGFloat = 12 - static let gestureBarWidth: CGFloat = 60 - static let gestureBarHeight: CGFloat = 4 -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/ModalPresentable/ModalWrapperView.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/ModalPresentable/ModalWrapperView.swift deleted file mode 100644 index 62b04e92..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/ModalPresentable/ModalWrapperView.swift +++ /dev/null @@ -1,74 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -final class ModalWrapperView: UIView { - - weak var parentViewController: UIViewController? - - let dimView = UIView() - let containerView = UIView() - - private var initialY: CGFloat = 0 - private var containerBottomConstraint: Constraint? - - init(contentViewController: UIViewController & ModalPresentable, parent: UIViewController) { - super.init(frame: .zero) - self.parentViewController = parent - - // 뒷배경 뷰 (반투명) - dimView.backgroundColor = .overlays - dimView.alpha = 0 - addSubview(dimView) - dimView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - - if contentViewController.allowsTapToDismiss { - // 탭 시 모달 닫기 - let tap = UITapGestureRecognizer(target: parent, action: #selector(parent.dismissCurrentModal)) - dimView.addGestureRecognizer(tap) - } - - // 모달 컨테이너 - containerView.backgroundColor = .systemBackground - containerView.layer.cornerRadius = ModalConfig.containerCornerRadius - containerView.clipsToBounds = true - containerView.transform = CGAffineTransform(translationX: 0, y: ModalConfig.containerTransformY) - addSubview(containerView) - - containerView.snp.makeConstraints { make in - self.containerBottomConstraint = make.bottom.equalToSuperview().constraint - make.horizontalEdges.equalToSuperview() - } - - // 자식 뷰컨트롤러 embed - parent.addChild(contentViewController) - containerView.addSubview(contentViewController.view) - contentViewController.view.snp.makeConstraints { make in - make.bottom.equalToSuperview().inset(ModalConfig.bottomSheetStyleBottomInset) - make.top.horizontalEdges.equalToSuperview() - if let height = contentViewController.modalHeight { make.height.equalTo(height) } - } - contentViewController.didMove(toParent: parent) - } - - func animateDismiss(completion: @escaping () -> Void) { - if let bottomConstraint = containerBottomConstraint { - // 아래로 내리기 위해 음수 inset - bottomConstraint.update(inset: -containerView.bounds.height) - UIView.animate(withDuration: 0.35, delay: 0, options: [.curveEaseIn], animations: { - self.layoutIfNeeded() - self.dimView.alpha = 0 - }, completion: { _ in - completion() - }) - } - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/ModalPresentable/UIViewController+.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/ModalPresentable/UIViewController+.swift deleted file mode 100644 index eec0382f..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/ModalPresentable/UIViewController+.swift +++ /dev/null @@ -1,133 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -private var modalWrapperKey: UInt8 = 0 -private var modalHideTabBarKey: UInt8 = 0 - -public extension UIViewController { - - private var modalWrapperView: ModalWrapperView? { - get { objc_getAssociatedObject(self, &modalWrapperKey) as? ModalWrapperView } - set { objc_setAssociatedObject(self, &modalWrapperKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } - } - - private var modalHideTabBar: Bool { - get { (objc_getAssociatedObject(self, &modalHideTabBarKey) as? Bool) ?? false } - set { objc_setAssociatedObject(self, &modalHideTabBarKey, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) } - } - - /// 커스텀 모달 프레젠트 - /// - Parameters: - /// - viewController: 표시할 모달 뷰컨 - /// - hideTabBar: 탭바를 숨길지 여부 (기본값: true) - func presentModal( - _ viewController: UIViewController & ModalPresentable, - hideTabBar: Bool = false - ) { - let wrapper = ModalWrapperView(contentViewController: viewController, parent: self) - - // 이전 상태 초기화 - modalHideTabBar = false - modalWrapperView = wrapper - - // 새 설정 적용 - modalHideTabBar = hideTabBar - - view.addSubview(wrapper) - wrapper.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - - // 필요 시 탭바 숨김 - if hideTabBar, let tabBarController = findTabBarController() { - tabBarController.setHidden(hidden: true, animated: false) - } - - // present 애니메이션 - UIView.animate( - withDuration: 0.5, - delay: 0, - usingSpringWithDamping: 0.85, - initialSpringVelocity: 0.8, - options: [.curveEaseOut] - ) { - wrapper.dimView.alpha = 1 - wrapper.containerView.transform = .identity - DispatchQueue.main.async { - viewController.beginAppearanceTransition(true, animated: true) - viewController.endAppearanceTransition() - } - } - } - - /// 현재 모달 닫기 - @objc internal func dismissCurrentModal() { - guard let wrapper = modalWrapperView else { return } - - let shouldKeepHidden = modalHideTabBar - let tabBarController = findTabBarController() - - if shouldKeepHidden, let tabBarController { - tabBarController.setHidden(hidden: true, animated: false) - } - - UIView.animate(withDuration: 0.35, delay: 0, options: [.curveEaseInOut]) { - wrapper.dimView.alpha = 0 - wrapper.containerView.transform = CGAffineTransform(translationX: 0, y: 300) - } completion: { _ in - wrapper.removeFromSuperview() - self.modalWrapperView = nil - - // false인 경우 복원 - if !shouldKeepHidden, let tabBarController { - tabBarController.setHidden(hidden: false, animated: false) - } - - self.modalHideTabBar = false - } - } - - private func findTabBarController() -> BottomTabBarController? { - var parentVC: UIViewController? = self - while let current = parentVC { - if let tabBarController = current as? BottomTabBarController { - return tabBarController - } - parentVC = current.parent - } - return nil - } -} - -// 모달 내부에서 닫기 기능 제공 -extension ModalPresentable where Self: UIViewController { - public func dismissCurrentModal() { - parent?.dismissCurrentModal() - } -} - -private var fabKey: UInt8 = 0 - -public extension UIViewController { - func addFloatingButton(_ action: @escaping () -> Void) { - let fab = FloatingActionButton(action: action) - objc_setAssociatedObject(self, &fabKey, fab, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) - - view.addSubview(fab) - fab.snp.makeConstraints { make in - make.trailing.equalTo(view.safeAreaLayoutGuide).inset(16) - make.bottom.equalTo(view.safeAreaLayoutGuide).inset(16) - make.size.equalTo(CGSize(width: 48, height: 48)) - } - } - - func removeFloatingButton() { - if let fab = objc_getAssociatedObject(self, &fabKey) as? UIView { - fab.removeFromSuperview() - objc_setAssociatedObject(self, &fabKey, nil, .OBJC_ASSOCIATION_RETAIN_NONATOMIC) - } - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/NotificationPermissionManager.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/NotificationPermissionManager.swift deleted file mode 100644 index 8f41e7cd..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/NotificationPermissionManager.swift +++ /dev/null @@ -1,56 +0,0 @@ -import UIKit -import UserNotifications - -public final class NotificationPermissionManager { - - public static let shared = NotificationPermissionManager() - private init() {} - - public func getStatus(completion: @escaping (UNAuthorizationStatus) -> Void) { - UNUserNotificationCenter.current().getNotificationSettings { settings in - completion(settings.authorizationStatus) - } - } - - public func requestIfNeeded( - application: UIApplication = .shared, - completion: ((Bool) -> Void)? = nil - ) { - let center = UNUserNotificationCenter.current() - center.getNotificationSettings { settings in - switch settings.authorizationStatus { - case .notDetermined: - center.requestAuthorization(options: [.alert, .badge, .sound]) { granted, error in - if let error = error { - print("error: \(error.localizedDescription)") - completion?(false) - return - } - if granted { - DispatchQueue.main.async { - application.registerForRemoteNotifications() - } - print("알림 권한 허용") - completion?(true) - } else { - print("알림 권한 거부") - completion?(false) - } - } - - case .authorized, .provisional: - DispatchQueue.main.async { - application.registerForRemoteNotifications() - } - completion?(true) - - case .denied: - print("🚫 알림 권한 거부 상태입니다. 설정에서 변경해야 함") - completion?(false) - - default: - completion?(false) - } - } - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/SnackBarFactory.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/SnackBarFactory.swift deleted file mode 100644 index 2c215ff4..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/SnackBarFactory.swift +++ /dev/null @@ -1,111 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift -import SnapKit - -public enum SnackBarFactory { - // MARK: - Properties - - /// 현재 디바이스 최상단 Window를 지정 - static var window: UIWindow? { - return UIApplication - .shared - .connectedScenes - .flatMap { ($0 as? UIWindowScene)?.windows ?? [] } - .first { $0.isKeyWindow } - } - - /// 최상단의 ViewController를 가져오는 메서드 - private static func topViewController( - _ rootViewController: UIViewController? = window?.rootViewController - ) -> UIViewController? { - if let navigationController = rootViewController as? UINavigationController { - return topViewController(navigationController.visibleViewController) - } - if let tabBarController = rootViewController as? UITabBarController { - return topViewController(tabBarController.selectedViewController) - } - if let presentedViewController = rootViewController?.presentedViewController { - return topViewController(presentedViewController) - } - return rootViewController - } - - private static var currentSnackBar: SnackBar? - private static var disposeBag = DisposeBag() -} - -public extension SnackBarFactory { - // MARK: - Method - - /// SnackBar를 생성하는 메소드 - /// - Parameters: - /// - type: normal / delete - /// - image: 스낵바 이미지 - /// - imageBackgroundColor: 이미지 배경색상 - /// - text: 스낵바에 들어갈 내용 - /// - buttonText: 버튼 제목 - /// - buttonAction: 버튼이 눌렸을때의 액션 - static func createSnackBar( - type: SnackBar.SnackBarType, - image: UIImage? = nil, - imageUrl: String? = nil, - imageBackgroundColor: UIColor, - text: String, - buttonText: String, - buttonAction: (() -> Void)?, - bottomMargin: CGFloat = 76 - ) { - DispatchQueue.main.async { - currentSnackBar?.removeFromSuperview() - currentSnackBar = nil - - let snackBar = SnackBar( - type: type, - image: image, - imageBackgroundColor: imageBackgroundColor, - text: text, - buttonText: buttonText, - buttonAction: buttonAction - ) - snackBar.alpha = 0 - - // ✅ window 대신 topViewController의 view 사용 - guard let topVC = topViewController() else { return } - topVC.view.addSubview(snackBar) - currentSnackBar = snackBar - - snackBar.snp.makeConstraints { make in - make.bottom.equalTo(topVC.view.safeAreaLayoutGuide.snp.bottom).inset(bottomMargin) - make.centerX.equalToSuperview() - } - - if let img = image { - snackBar.imageView.setImage(image: img, backgroundColor: imageBackgroundColor) - } else if let urlString = imageUrl, let url = URL(string: urlString) { - ImageLoader.shared.loadImage(stringURL: urlString) { image in - DispatchQueue.main.async { - snackBar.imageView.setImage(image: image, backgroundColor: imageBackgroundColor) - } - } - } - - UIView.animate(withDuration: 0.25) { - snackBar.alpha = 1 - } - - DispatchQueue.main.asyncAfter(deadline: .now() + 2.3) { - UIView.animate(withDuration: 0.6, animations: { - snackBar.alpha = 0 - }, completion: { _ in - snackBar.removeFromSuperview() - if currentSnackBar == snackBar { - currentSnackBar = nil - } - }) - } - } - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/TabBarUnderlineController.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/TabBarUnderlineController.swift deleted file mode 100644 index e6ff6130..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/TabBarUnderlineController.swift +++ /dev/null @@ -1,144 +0,0 @@ -import UIKit - -import DesignSystem - -import RxCocoa -import RxSwift -import SnapKit - -public final class TabBarUnderlineController { - // MARK: - UI Components - - /// 선택된 탭 아래를 표시하는 인디케이터 뷰 - private let selectionIndicatorView: UIView = { - let view = UIView() - view.backgroundColor = .textColor - return view - }() - - /// 탭 바 하단의 구분선 - private let bottomUnderlineView: UIView = { - let view = UIView() - view.backgroundColor = .neutral300 - return view - }() - - // MARK: - Properties - - private var collectionView: UICollectionView? - private let disposeBag = DisposeBag() - - /// 현재 컬렉션 뷰의 스크롤 오프셋 (인디케이터 위치 계산용) - private var currentScrollOffset: CGPoint? - - // MARK: - Initialization - - public init() {} - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Setup - -private extension TabBarUnderlineController { - func addIndicatorViews(to collectionView: UICollectionView) { - guard let superview = collectionView.superview else { return } - - superview.addSubview(bottomUnderlineView) - bottomUnderlineView.snp.makeConstraints { make in - make.horizontalEdges.bottom.equalTo(collectionView) - make.height.equalTo(1) - } - - superview.addSubview(selectionIndicatorView) - selectionIndicatorView.frame = CGRect( - x: 0, - y: collectionView.frame.maxY - 2, - width: 0, - height: 2 - ) - } -} - -// MARK: - Public Interface - -public extension TabBarUnderlineController { - /// 컬렉션 뷰에 인디케이터 컨트롤러 연결 - func configure(with collectionView: UICollectionView) { - self.collectionView = collectionView - addIndicatorViews(to: collectionView) - } - - /// 컬렉션 뷰 스크롤 오프셋이 변경될 때 호출 (scrollViewDidScroll 등에서) - func updateScrollOffset(_ offset: CGPoint) { - currentScrollOffset = offset - updateIndicatorFrameWithoutAnimation() - } - - /// 선택된 셀 위치에 인디케이터를 즉시 이동 - func updateIndicatorFrameWithoutAnimation() { - guard let collectionView, - let indexPath = collectionView.indexPathsForSelectedItems?.first, - let selectedFrame = collectionView.cellForItem(at: indexPath)?.frame - else { return } - - let xOffset = selectedFrame.minX - (currentScrollOffset?.x ?? 0) - selectionIndicatorView.frame.origin.x = xOffset - } - - /// 선택된 셀 위치로 인디케이터를 애니메이션으로 이동 - func animateIndicatorToSelectedItem() { - guard let collectionView, - let indexPath = collectionView.indexPathsForSelectedItems?.first, - let selectedFrame = collectionView.cellForItem(at: indexPath)?.frame - else { return } - - let xOffset = selectedFrame.minX - (currentScrollOffset?.x ?? 0) - let targetFrame = CGRect( - x: xOffset, - y: collectionView.frame.maxY - 2, - width: selectedFrame.width, - height: 2 - ) - - UIView.animate(withDuration: 0.2, delay: 0, options: [.curveEaseInOut], animations: { [weak self] in - self?.selectionIndicatorView.frame = targetFrame - }) - } - - /// 선택된 셀 위치로 인디케이터를 애니메이션으로 이동 - func setInitialIndicator() { - guard let collectionView, - let indexPath = collectionView.indexPathsForSelectedItems?.first, - let selectedFrame = collectionView.cellForItem(at: indexPath)?.frame - else { return } - - let xOffset = selectedFrame.minX - (currentScrollOffset?.x ?? 0) - let targetFrame = CGRect( - x: xOffset, - y: collectionView.frame.maxY - 2, - width: selectedFrame.width, - height: 2 - ) - selectionIndicatorView.frame = targetFrame - } - - func setHidden(hidden: Bool, animated: Bool = false) { - let alpha: CGFloat = hidden ? 0 : 1 - if animated { - UIView.animate(withDuration: 0.25) { - self.selectionIndicatorView.alpha = alpha - self.bottomUnderlineView.alpha = alpha - } - } else { - selectionIndicatorView.alpha = alpha - bottomUnderlineView.alpha = alpha - } - - selectionIndicatorView.isHidden = hidden - bottomUnderlineView.isHidden = hidden - } -} diff --git a/MLS/Presentation/BaseFeature/BaseFeature/Utills/ToastFactory.swift b/MLS/Presentation/BaseFeature/BaseFeature/Utills/ToastFactory.swift deleted file mode 100644 index 7e571b85..00000000 --- a/MLS/Presentation/BaseFeature/BaseFeature/Utills/ToastFactory.swift +++ /dev/null @@ -1,77 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift -import SnapKit - -public final class ToastFactory { - - // MARK: - Properties - - /// 현재 디바이스 최상단 Window를 지정 - static var window: UIWindow? { - return UIApplication - .shared - .connectedScenes - .flatMap { ($0 as? UIWindowScene)?.windows ?? [] } - .first { $0.isKeyWindow } - } - - /// 최상단의 ViewController를 가져오는 메서드 - private static func topViewController( - _ rootViewController: UIViewController? = window?.rootViewController - ) -> UIViewController? { - if let navigationController = rootViewController as? UINavigationController { - return topViewController(navigationController.visibleViewController) - } - if let tabBarController = rootViewController as? UITabBarController { - return topViewController(tabBarController.selectedViewController) - } - if let presentedViewController = rootViewController?.presentedViewController { - return topViewController(presentedViewController) - } - return rootViewController - } - - private static var currentToast: Toast? - private static var disposeBag = DisposeBag() -} - -extension ToastFactory { - - // MARK: - Method - - /// 토스트 메시지를 생성하는 메서드 - /// - Parameter message: 토스트 메세지에 담길 String 타입 - public static func createToast(message: String) { - - currentToast?.removeFromSuperview() - currentToast = nil - let toastMSG = Toast(message: message) - guard let window = window else { return } - window.addSubview(toastMSG) - currentToast = toastMSG - - toastMSG.snp.makeConstraints { make in - make.bottom.equalTo(window.snp.bottom).inset(120) - make.centerX.equalTo(window.snp.centerX) - } - - toastMSG.alpha = 0 - UIView.animate(withDuration: 0.25) { - toastMSG.alpha = 1 - } - - UIView.animate( - withDuration: 0.6, - delay: 2.3, - options: .curveEaseOut - ) { - toastMSG.alpha = 0 - } completion: { _ in - toastMSG.removeFromSuperview() - if currentToast == toastMSG { currentToast = nil } - } - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature.xcodeproj/project.pbxproj b/MLS/Presentation/BookmarkFeature/BookmarkFeature.xcodeproj/project.pbxproj deleted file mode 100644 index 9a3405e5..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature.xcodeproj/project.pbxproj +++ /dev/null @@ -1,981 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 77; - objects = { - -/* Begin PBXBuildFile section */ - 778C5E442E7D78DA00FD8439 /* MyPageFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 778C5E422E7D78DA00FD8439 /* MyPageFeature.framework */; }; - 778C5E452E7D78DA00FD8439 /* MyPageFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 778C5E422E7D78DA00FD8439 /* MyPageFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 778C5E462E7D78DA00FD8439 /* MyPageFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 778C5E432E7D78DA00FD8439 /* MyPageFeatureInterface.framework */; }; - 778C5E472E7D78DA00FD8439 /* MyPageFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 778C5E432E7D78DA00FD8439 /* MyPageFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 779360FC2E38C2D20099B107 /* RxRelay in Frameworks */ = {isa = PBXBuildFile; productRef = 779360FB2E38C2D20099B107 /* RxRelay */; }; - 779360FE2E38C4BF0099B107 /* ReactorKit in Frameworks */ = {isa = PBXBuildFile; productRef = 779360FD2E38C4BF0099B107 /* ReactorKit */; }; - 779361002E38C7240099B107 /* RxKeyboard in Frameworks */ = {isa = PBXBuildFile; productRef = 779360FF2E38C7240099B107 /* RxKeyboard */; }; - 779A50BA2E2E1DC100ABDE4F /* BookmarkFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77DBC78C2E182A9200529428 /* BookmarkFeatureInterface.framework */; }; - 77C97A752E37AF83007198DA /* BookmarkFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77DBC7742E1829AB00529428 /* BookmarkFeature.framework */; }; - 77C97A762E37AF83007198DA /* BookmarkFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77DBC7742E1829AB00529428 /* BookmarkFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77C97A792E37AF83007198DA /* BookmarkFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77DBC78C2E182A9200529428 /* BookmarkFeatureInterface.framework */; }; - 77C97A7A2E37AF83007198DA /* BookmarkFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77DBC78C2E182A9200529428 /* BookmarkFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77C97A802E37AF8D007198DA /* AuthFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A7E2E37AF8D007198DA /* AuthFeature.framework */; }; - 77C97A812E37AF8D007198DA /* AuthFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A7E2E37AF8D007198DA /* AuthFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77C97A822E37AF8D007198DA /* AuthFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A7F2E37AF8D007198DA /* AuthFeatureInterface.framework */; }; - 77C97A832E37AF8D007198DA /* AuthFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A7F2E37AF8D007198DA /* AuthFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77C97A8F2E37AF97007198DA /* Core.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A852E37AF97007198DA /* Core.framework */; }; - 77C97A902E37AF97007198DA /* Core.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A852E37AF97007198DA /* Core.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77C97A912E37AF97007198DA /* Data.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A862E37AF97007198DA /* Data.framework */; }; - 77C97A922E37AF97007198DA /* Data.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A862E37AF97007198DA /* Data.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77C97A932E37AF97007198DA /* DataMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A872E37AF97007198DA /* DataMock.framework */; }; - 77C97A942E37AF97007198DA /* DataMock.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A872E37AF97007198DA /* DataMock.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77C97A952E37AF97007198DA /* DesignSystem.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A882E37AF97007198DA /* DesignSystem.framework */; }; - 77C97A962E37AF97007198DA /* DesignSystem.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A882E37AF97007198DA /* DesignSystem.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77C97A972E37AF97007198DA /* DictionaryFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A892E37AF97007198DA /* DictionaryFeature.framework */; }; - 77C97A982E37AF97007198DA /* DictionaryFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A892E37AF97007198DA /* DictionaryFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77C97A992E37AF97007198DA /* DictionaryFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A8A2E37AF97007198DA /* DictionaryFeatureInterface.framework */; }; - 77C97A9A2E37AF97007198DA /* DictionaryFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A8A2E37AF97007198DA /* DictionaryFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77C97A9B2E37AF97007198DA /* Domain.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A8B2E37AF97007198DA /* Domain.framework */; }; - 77C97A9C2E37AF97007198DA /* Domain.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A8B2E37AF97007198DA /* Domain.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77C97A9D2E37AF97007198DA /* DomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A8C2E37AF97007198DA /* DomainInterface.framework */; }; - 77C97A9E2E37AF97007198DA /* DomainInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A8C2E37AF97007198DA /* DomainInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77C97AA02E37AFAA007198DA /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 77C97A9F2E37AFAA007198DA /* SnapKit */; }; - 77C97AA22E37AFC9007198DA /* BaseFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97AA12E37AFC9007198DA /* BaseFeature.framework */; }; - 77C97AA72E37B1B7007198DA /* BaseFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97AA52E37B1B7007198DA /* BaseFeature.framework */; }; - 77C97AA92E37B1B7007198DA /* DesignSystem.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97AA62E37B1B7007198DA /* DesignSystem.framework */; }; - 77C97AAD2E37B1D5007198DA /* DomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97AAC2E37B1D5007198DA /* DomainInterface.framework */; }; - 77C97AB02E37B27A007198DA /* DomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97AAF2E37B27A007198DA /* DomainInterface.framework */; }; - 77C97DA22E37B493007198DA /* BaseFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A842E37AF97007198DA /* BaseFeature.framework */; }; - 77C97DA32E37B493007198DA /* BaseFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97A842E37AF97007198DA /* BaseFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77C97DA52E37CF26007198DA /* RxRelay in Frameworks */ = {isa = PBXBuildFile; productRef = 77C97DA42E37CF26007198DA /* RxRelay */; }; - 77C97DA72E37D46E007198DA /* AuthFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97DA62E37D46E007198DA /* AuthFeatureInterface.framework */; }; - 77C97DAF2E37D4B6007198DA /* AuthFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97DAE2E37D4B6007198DA /* AuthFeatureInterface.framework */; }; - 77DBC7B62E182BD900529428 /* ReactorKit in Frameworks */ = {isa = PBXBuildFile; productRef = 77DBC7B52E182BD900529428 /* ReactorKit */; }; - 77DBC7B92E182BE200529428 /* RxKeyboard in Frameworks */ = {isa = PBXBuildFile; productRef = 77DBC7B82E182BE200529428 /* RxKeyboard */; }; - 77DBC7BC2E182BF500529428 /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 77DBC7BB2E182BF500529428 /* RxCocoa */; }; - 77DBC7C02E182BF500529428 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 77DBC7BF2E182BF500529428 /* RxSwift */; }; - 77DBC7C32E182BFE00529428 /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 77DBC7C22E182BFE00529428 /* SnapKit */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 779A50BC2E2E1DC100ABDE4F /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 77DBC76B2E1829AB00529428 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 77DBC78B2E182A9200529428; - remoteInfo = BookmarkFeatureInterface; - }; - 77C97A772E37AF83007198DA /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 77DBC76B2E1829AB00529428 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 77DBC7732E1829AB00529428; - remoteInfo = BookmarkFeature; - }; - 77C97A7B2E37AF83007198DA /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 77DBC76B2E1829AB00529428 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 77DBC78B2E182A9200529428; - remoteInfo = BookmarkFeatureInterface; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 77C97A7D2E37AF83007198DA /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 77C97DA32E37B493007198DA /* BaseFeature.framework in Embed Frameworks */, - 77C97A9C2E37AF97007198DA /* Domain.framework in Embed Frameworks */, - 77C97A762E37AF83007198DA /* BookmarkFeature.framework in Embed Frameworks */, - 77C97A902E37AF97007198DA /* Core.framework in Embed Frameworks */, - 778C5E472E7D78DA00FD8439 /* MyPageFeatureInterface.framework in Embed Frameworks */, - 77C97A942E37AF97007198DA /* DataMock.framework in Embed Frameworks */, - 77C97A982E37AF97007198DA /* DictionaryFeature.framework in Embed Frameworks */, - 778C5E452E7D78DA00FD8439 /* MyPageFeature.framework in Embed Frameworks */, - 77C97A9A2E37AF97007198DA /* DictionaryFeatureInterface.framework in Embed Frameworks */, - 77C97A962E37AF97007198DA /* DesignSystem.framework in Embed Frameworks */, - 77C97A9E2E37AF97007198DA /* DomainInterface.framework in Embed Frameworks */, - 77C97A832E37AF8D007198DA /* AuthFeatureInterface.framework in Embed Frameworks */, - 77C97A922E37AF97007198DA /* Data.framework in Embed Frameworks */, - 77C97A7A2E37AF83007198DA /* BookmarkFeatureInterface.framework in Embed Frameworks */, - 77C97A812E37AF8D007198DA /* AuthFeature.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 777313172E7DB00700AA92F6 /* MyPageFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MyPageFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 778C5E422E7D78DA00FD8439 /* MyPageFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MyPageFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 778C5E432E7D78DA00FD8439 /* MyPageFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MyPageFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97A7E2E37AF8D007198DA /* AuthFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AuthFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97A7F2E37AF8D007198DA /* AuthFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AuthFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97A842E37AF97007198DA /* BaseFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BaseFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97A852E37AF97007198DA /* Core.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Core.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97A862E37AF97007198DA /* Data.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Data.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97A872E37AF97007198DA /* DataMock.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DataMock.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97A882E37AF97007198DA /* DesignSystem.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DesignSystem.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97A892E37AF97007198DA /* DictionaryFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DictionaryFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97A8A2E37AF97007198DA /* DictionaryFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DictionaryFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97A8B2E37AF97007198DA /* Domain.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Domain.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97A8C2E37AF97007198DA /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97AA12E37AFC9007198DA /* BaseFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BaseFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97AA52E37B1B7007198DA /* BaseFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BaseFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97AA62E37B1B7007198DA /* DesignSystem.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DesignSystem.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97AAC2E37B1D5007198DA /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97AAF2E37B27A007198DA /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97DA62E37D46E007198DA /* AuthFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AuthFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97DAE2E37D4B6007198DA /* AuthFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AuthFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77DBC7742E1829AB00529428 /* BookmarkFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BookmarkFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77DBC78C2E182A9200529428 /* BookmarkFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = BookmarkFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77DBC7D52E1833FC00529428 /* BookmarkFeatureDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = BookmarkFeatureDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ - 77DBC7E62E1833FD00529428 /* Exceptions for "BookmarkFeatureDemo" folder in "BookmarkFeatureDemo" target */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - membershipExceptions = ( - Info.plist, - ); - target = 77DBC7D42E1833FC00529428 /* BookmarkFeatureDemo */; - }; -/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ - -/* Begin PBXFileSystemSynchronizedRootGroup section */ - 77DBC7762E1829AB00529428 /* BookmarkFeature */ = { - isa = PBXFileSystemSynchronizedRootGroup; - path = BookmarkFeature; - sourceTree = ""; - }; - 77DBC78D2E182A9200529428 /* BookmarkFeatureInterface */ = { - isa = PBXFileSystemSynchronizedRootGroup; - path = BookmarkFeatureInterface; - sourceTree = ""; - }; - 77DBC7D62E1833FC00529428 /* BookmarkFeatureDemo */ = { - isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - 77DBC7E62E1833FD00529428 /* Exceptions for "BookmarkFeatureDemo" folder in "BookmarkFeatureDemo" target */, - ); - path = BookmarkFeatureDemo; - sourceTree = ""; - }; -/* End PBXFileSystemSynchronizedRootGroup section */ - -/* Begin PBXFrameworksBuildPhase section */ - 77DBC7712E1829AB00529428 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 77C97DA52E37CF26007198DA /* RxRelay in Frameworks */, - 77C97AAD2E37B1D5007198DA /* DomainInterface.framework in Frameworks */, - 77C97AA72E37B1B7007198DA /* BaseFeature.framework in Frameworks */, - 77DBC7C02E182BF500529428 /* RxSwift in Frameworks */, - 779A50BA2E2E1DC100ABDE4F /* BookmarkFeatureInterface.framework in Frameworks */, - 77C97AA92E37B1B7007198DA /* DesignSystem.framework in Frameworks */, - 77DBC7B62E182BD900529428 /* ReactorKit in Frameworks */, - 77DBC7C32E182BFE00529428 /* SnapKit in Frameworks */, - 77C97DA72E37D46E007198DA /* AuthFeatureInterface.framework in Frameworks */, - 77C97DAF2E37D4B6007198DA /* AuthFeatureInterface.framework in Frameworks */, - 77DBC7B92E182BE200529428 /* RxKeyboard in Frameworks */, - 77DBC7BC2E182BF500529428 /* RxCocoa in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 77DBC7892E182A9200529428 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 77C97AB02E37B27A007198DA /* DomainInterface.framework in Frameworks */, - 77C97AA22E37AFC9007198DA /* BaseFeature.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 77DBC7D22E1833FC00529428 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 779360FC2E38C2D20099B107 /* RxRelay in Frameworks */, - 77C97A9B2E37AF97007198DA /* Domain.framework in Frameworks */, - 779360FE2E38C4BF0099B107 /* ReactorKit in Frameworks */, - 779361002E38C7240099B107 /* RxKeyboard in Frameworks */, - 77C97A752E37AF83007198DA /* BookmarkFeature.framework in Frameworks */, - 77C97A8F2E37AF97007198DA /* Core.framework in Frameworks */, - 77C97AA02E37AFAA007198DA /* SnapKit in Frameworks */, - 77C97A932E37AF97007198DA /* DataMock.framework in Frameworks */, - 77C97A972E37AF97007198DA /* DictionaryFeature.framework in Frameworks */, - 77C97DA22E37B493007198DA /* BaseFeature.framework in Frameworks */, - 77C97A992E37AF97007198DA /* DictionaryFeatureInterface.framework in Frameworks */, - 77C97A952E37AF97007198DA /* DesignSystem.framework in Frameworks */, - 778C5E442E7D78DA00FD8439 /* MyPageFeature.framework in Frameworks */, - 77C97A9D2E37AF97007198DA /* DomainInterface.framework in Frameworks */, - 778C5E462E7D78DA00FD8439 /* MyPageFeatureInterface.framework in Frameworks */, - 77C97A822E37AF8D007198DA /* AuthFeatureInterface.framework in Frameworks */, - 77C97A912E37AF97007198DA /* Data.framework in Frameworks */, - 77C97A792E37AF83007198DA /* BookmarkFeatureInterface.framework in Frameworks */, - 77C97A802E37AF8D007198DA /* AuthFeature.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 77DBC76A2E1829AB00529428 = { - isa = PBXGroup; - children = ( - 77DBC7762E1829AB00529428 /* BookmarkFeature */, - 77DBC78D2E182A9200529428 /* BookmarkFeatureInterface */, - 77DBC7D62E1833FC00529428 /* BookmarkFeatureDemo */, - 77DBC7A52E182AFF00529428 /* Frameworks */, - 77DBC7752E1829AB00529428 /* Products */, - ); - sourceTree = ""; - }; - 77DBC7752E1829AB00529428 /* Products */ = { - isa = PBXGroup; - children = ( - 77DBC7742E1829AB00529428 /* BookmarkFeature.framework */, - 77DBC78C2E182A9200529428 /* BookmarkFeatureInterface.framework */, - 77DBC7D52E1833FC00529428 /* BookmarkFeatureDemo.app */, - ); - name = Products; - sourceTree = ""; - }; - 77DBC7A52E182AFF00529428 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 777313172E7DB00700AA92F6 /* MyPageFeatureInterface.framework */, - 778C5E422E7D78DA00FD8439 /* MyPageFeature.framework */, - 778C5E432E7D78DA00FD8439 /* MyPageFeatureInterface.framework */, - 77C97DAE2E37D4B6007198DA /* AuthFeatureInterface.framework */, - 77C97DA62E37D46E007198DA /* AuthFeatureInterface.framework */, - 77C97AAF2E37B27A007198DA /* DomainInterface.framework */, - 77C97AAC2E37B1D5007198DA /* DomainInterface.framework */, - 77C97AA52E37B1B7007198DA /* BaseFeature.framework */, - 77C97AA62E37B1B7007198DA /* DesignSystem.framework */, - 77C97AA12E37AFC9007198DA /* BaseFeature.framework */, - 77C97A842E37AF97007198DA /* BaseFeature.framework */, - 77C97A852E37AF97007198DA /* Core.framework */, - 77C97A862E37AF97007198DA /* Data.framework */, - 77C97A872E37AF97007198DA /* DataMock.framework */, - 77C97A882E37AF97007198DA /* DesignSystem.framework */, - 77C97A892E37AF97007198DA /* DictionaryFeature.framework */, - 77C97A8A2E37AF97007198DA /* DictionaryFeatureInterface.framework */, - 77C97A8B2E37AF97007198DA /* Domain.framework */, - 77C97A8C2E37AF97007198DA /* DomainInterface.framework */, - 77C97A7E2E37AF8D007198DA /* AuthFeature.framework */, - 77C97A7F2E37AF8D007198DA /* AuthFeatureInterface.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 77DBC76F2E1829AB00529428 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 77DBC7872E182A9200529428 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 77DBC7732E1829AB00529428 /* BookmarkFeature */ = { - isa = PBXNativeTarget; - buildConfigurationList = 77DBC77C2E1829AB00529428 /* Build configuration list for PBXNativeTarget "BookmarkFeature" */; - buildPhases = ( - 77DBC76F2E1829AB00529428 /* Headers */, - 77DBC7702E1829AB00529428 /* Sources */, - 77DBC7712E1829AB00529428 /* Frameworks */, - 77DBC7722E1829AB00529428 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 779A50BD2E2E1DC100ABDE4F /* PBXTargetDependency */, - ); - fileSystemSynchronizedGroups = ( - 77DBC7762E1829AB00529428 /* BookmarkFeature */, - ); - name = BookmarkFeature; - packageProductDependencies = ( - 77DBC7B52E182BD900529428 /* ReactorKit */, - 77DBC7B82E182BE200529428 /* RxKeyboard */, - 77DBC7BB2E182BF500529428 /* RxCocoa */, - 77DBC7BF2E182BF500529428 /* RxSwift */, - 77DBC7C22E182BFE00529428 /* SnapKit */, - 77C97DA42E37CF26007198DA /* RxRelay */, - ); - productName = BookmarkFeature; - productReference = 77DBC7742E1829AB00529428 /* BookmarkFeature.framework */; - productType = "com.apple.product-type.framework"; - }; - 77DBC78B2E182A9200529428 /* BookmarkFeatureInterface */ = { - isa = PBXNativeTarget; - buildConfigurationList = 77DBC7932E182A9200529428 /* Build configuration list for PBXNativeTarget "BookmarkFeatureInterface" */; - buildPhases = ( - 77DBC7872E182A9200529428 /* Headers */, - 77DBC7882E182A9200529428 /* Sources */, - 77DBC7892E182A9200529428 /* Frameworks */, - 77DBC78A2E182A9200529428 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - fileSystemSynchronizedGroups = ( - 77DBC78D2E182A9200529428 /* BookmarkFeatureInterface */, - ); - name = BookmarkFeatureInterface; - packageProductDependencies = ( - ); - productName = BookmarkFeatureInterface; - productReference = 77DBC78C2E182A9200529428 /* BookmarkFeatureInterface.framework */; - productType = "com.apple.product-type.framework"; - }; - 77DBC7D42E1833FC00529428 /* BookmarkFeatureDemo */ = { - isa = PBXNativeTarget; - buildConfigurationList = 77DBC7E72E1833FD00529428 /* Build configuration list for PBXNativeTarget "BookmarkFeatureDemo" */; - buildPhases = ( - 77DBC7D12E1833FC00529428 /* Sources */, - 77DBC7D22E1833FC00529428 /* Frameworks */, - 77DBC7D32E1833FC00529428 /* Resources */, - 77C97A7D2E37AF83007198DA /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 77C97A782E37AF83007198DA /* PBXTargetDependency */, - 77C97A7C2E37AF83007198DA /* PBXTargetDependency */, - ); - fileSystemSynchronizedGroups = ( - 77DBC7D62E1833FC00529428 /* BookmarkFeatureDemo */, - ); - name = BookmarkFeatureDemo; - packageProductDependencies = ( - 77C97A9F2E37AFAA007198DA /* SnapKit */, - 779360FB2E38C2D20099B107 /* RxRelay */, - 779360FD2E38C4BF0099B107 /* ReactorKit */, - 779360FF2E38C7240099B107 /* RxKeyboard */, - ); - productName = BookmarkFeatureDemo; - productReference = 77DBC7D52E1833FC00529428 /* BookmarkFeatureDemo.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 77DBC76B2E1829AB00529428 /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1620; - LastUpgradeCheck = 1620; - TargetAttributes = { - 77DBC7732E1829AB00529428 = { - CreatedOnToolsVersion = 16.2; - LastSwiftMigration = 1620; - }; - 77DBC78B2E182A9200529428 = { - CreatedOnToolsVersion = 16.2; - LastSwiftMigration = 1620; - }; - 77DBC7D42E1833FC00529428 = { - CreatedOnToolsVersion = 16.2; - }; - }; - }; - buildConfigurationList = 77DBC76E2E1829AB00529428 /* Build configuration list for PBXProject "BookmarkFeature" */; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 77DBC76A2E1829AB00529428; - minimizedProjectReferenceProxies = 1; - packageReferences = ( - 77DBC7B42E182BD900529428 /* XCRemoteSwiftPackageReference "ReactorKit" */, - 77DBC7B72E182BE200529428 /* XCRemoteSwiftPackageReference "RxKeyboard" */, - 77DBC7BA2E182BF500529428 /* XCRemoteSwiftPackageReference "RxSwift" */, - 77DBC7C12E182BFE00529428 /* XCRemoteSwiftPackageReference "SnapKit" */, - ); - preferredProjectObjectVersion = 77; - productRefGroup = 77DBC7752E1829AB00529428 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 77DBC7732E1829AB00529428 /* BookmarkFeature */, - 77DBC78B2E182A9200529428 /* BookmarkFeatureInterface */, - 77DBC7D42E1833FC00529428 /* BookmarkFeatureDemo */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 77DBC7722E1829AB00529428 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 77DBC78A2E182A9200529428 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 77DBC7D32E1833FC00529428 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 77DBC7702E1829AB00529428 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 77DBC7882E182A9200529428 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 77DBC7D12E1833FC00529428 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 779A50BD2E2E1DC100ABDE4F /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 77DBC78B2E182A9200529428 /* BookmarkFeatureInterface */; - targetProxy = 779A50BC2E2E1DC100ABDE4F /* PBXContainerItemProxy */; - }; - 77C97A782E37AF83007198DA /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 77DBC7732E1829AB00529428 /* BookmarkFeature */; - targetProxy = 77C97A772E37AF83007198DA /* PBXContainerItemProxy */; - }; - 77C97A7C2E37AF83007198DA /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 77DBC78B2E182A9200529428 /* BookmarkFeatureInterface */; - targetProxy = 77C97A7B2E37AF83007198DA /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 77DBC77D2E1829AB00529428 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.BookmarkFeature; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 77DBC77E2E1829AB00529428 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.BookmarkFeature; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; - 77DBC77F2E1829AB00529428 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 77DBC7802E1829AB00529428 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 77DBC7942E182A9200529428 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.BookmarkFeatureInterface; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 77DBC7952E182A9200529428 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.BookmarkFeatureInterface; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; - 77DBC7E82E1833FD00529428 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5QTRMS954; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = BookmarkFeatureDemo/Info.plist; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.BookmarkFeatureDemo; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = MLSBookMarkFeatureProvisioningProfileDev; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 77DBC7E92E1833FD00529428 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5QTRMS954; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = BookmarkFeatureDemo/Info.plist; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.BookmarkFeatureDemo; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = MLSBookMarkFeatureProvisioningProfile; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 77DBC76E2E1829AB00529428 /* Build configuration list for PBXProject "BookmarkFeature" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 77DBC77F2E1829AB00529428 /* Debug */, - 77DBC7802E1829AB00529428 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 77DBC77C2E1829AB00529428 /* Build configuration list for PBXNativeTarget "BookmarkFeature" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 77DBC77D2E1829AB00529428 /* Debug */, - 77DBC77E2E1829AB00529428 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 77DBC7932E182A9200529428 /* Build configuration list for PBXNativeTarget "BookmarkFeatureInterface" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 77DBC7942E182A9200529428 /* Debug */, - 77DBC7952E182A9200529428 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 77DBC7E72E1833FD00529428 /* Build configuration list for PBXNativeTarget "BookmarkFeatureDemo" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 77DBC7E82E1833FD00529428 /* Debug */, - 77DBC7E92E1833FD00529428 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - 77DBC7B42E182BD900529428 /* XCRemoteSwiftPackageReference "ReactorKit" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ReactorKit/ReactorKit.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 3.2.0; - }; - }; - 77DBC7B72E182BE200529428 /* XCRemoteSwiftPackageReference "RxKeyboard" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/RxSwiftCommunity/RxKeyboard"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.0.1; - }; - }; - 77DBC7BA2E182BF500529428 /* XCRemoteSwiftPackageReference "RxSwift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ReactiveX/RxSwift"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 6.9.0; - }; - }; - 77DBC7C12E182BFE00529428 /* XCRemoteSwiftPackageReference "SnapKit" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/SnapKit/SnapKit"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 5.7.1; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 779360FB2E38C2D20099B107 /* RxRelay */ = { - isa = XCSwiftPackageProductDependency; - package = 77DBC7BA2E182BF500529428 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxRelay; - }; - 779360FD2E38C4BF0099B107 /* ReactorKit */ = { - isa = XCSwiftPackageProductDependency; - package = 77DBC7B42E182BD900529428 /* XCRemoteSwiftPackageReference "ReactorKit" */; - productName = ReactorKit; - }; - 779360FF2E38C7240099B107 /* RxKeyboard */ = { - isa = XCSwiftPackageProductDependency; - package = 77DBC7B72E182BE200529428 /* XCRemoteSwiftPackageReference "RxKeyboard" */; - productName = RxKeyboard; - }; - 77C97A9F2E37AFAA007198DA /* SnapKit */ = { - isa = XCSwiftPackageProductDependency; - package = 77DBC7C12E182BFE00529428 /* XCRemoteSwiftPackageReference "SnapKit" */; - productName = SnapKit; - }; - 77C97DA42E37CF26007198DA /* RxRelay */ = { - isa = XCSwiftPackageProductDependency; - package = 77DBC7BA2E182BF500529428 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxRelay; - }; - 77DBC7B52E182BD900529428 /* ReactorKit */ = { - isa = XCSwiftPackageProductDependency; - package = 77DBC7B42E182BD900529428 /* XCRemoteSwiftPackageReference "ReactorKit" */; - productName = ReactorKit; - }; - 77DBC7B82E182BE200529428 /* RxKeyboard */ = { - isa = XCSwiftPackageProductDependency; - package = 77DBC7B72E182BE200529428 /* XCRemoteSwiftPackageReference "RxKeyboard" */; - productName = RxKeyboard; - }; - 77DBC7BB2E182BF500529428 /* RxCocoa */ = { - isa = XCSwiftPackageProductDependency; - package = 77DBC7BA2E182BF500529428 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxCocoa; - }; - 77DBC7BF2E182BF500529428 /* RxSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 77DBC7BA2E182BF500529428 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxSwift; - }; - 77DBC7C22E182BFE00529428 /* SnapKit */ = { - isa = XCSwiftPackageProductDependency; - package = 77DBC7C12E182BFE00529428 /* XCRemoteSwiftPackageReference "SnapKit" */; - productName = SnapKit; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 77DBC76B2E1829AB00529428 /* Project object */; -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/MLS/Presentation/BookmarkFeature/BookmarkFeature.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 94b2795e..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,4 +0,0 @@ - - - diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature.xcodeproj/xcshareddata/xcschemes/BookmarkFeatureDemo.xcscheme b/MLS/Presentation/BookmarkFeature/BookmarkFeature.xcodeproj/xcshareddata/xcschemes/BookmarkFeatureDemo.xcscheme deleted file mode 100644 index 5fb069c5..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature.xcodeproj/xcshareddata/xcschemes/BookmarkFeatureDemo.xcscheme +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionFactoryImpl.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionFactoryImpl.swift deleted file mode 100644 index dd6e1a8f..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionFactoryImpl.swift +++ /dev/null @@ -1,19 +0,0 @@ -import BaseFeature -import BookmarkFeatureInterface -import DomainInterface - -public final class AddCollectionFactoryImpl: AddCollectionFactory { - private let createCollectionListUseCase: CreateCollectionListUseCase - private let setCollectionUseCase: UpdateCollectionUseCase - - public init(createCollectionListUseCase: CreateCollectionListUseCase, setCollectionUseCase: UpdateCollectionUseCase) { - self.createCollectionListUseCase = createCollectionListUseCase - self.setCollectionUseCase = setCollectionUseCase - } - - public func make(collection: CollectionResponse?) -> BaseViewController { - let viewController = AddCollectionViewController() - viewController.reactor = AddCollectionModalReactor(collection: collection, createCollectionListUseCase: createCollectionListUseCase, setCollectionUseCase: setCollectionUseCase) - return viewController - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift deleted file mode 100644 index 2a3c4952..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionReactor.swift +++ /dev/null @@ -1,110 +0,0 @@ -import BookmarkFeatureInterface -import DomainInterface - -import ReactorKit - -public final class AddCollectionModalReactor: Reactor { - // MARK: - Route - public enum Route { - case dismiss - case dismissWithData - case createError - case updateError - } - - // MARK: - Action - public enum Action { - case inputTextChanged(String?) - case backButtonTapped - case completeButtonTapped - } - - // MARK: - Mutation - public enum Mutation { - case saveInput(String) - case setError(Bool) - case setButtonEnabled(Bool) - case toNavigate(Route) - } - - // MARK: - State - public struct State { - @Pulse var route: Route? - var collection: CollectionResponse? - var inputText: String? - var isError: Bool = false - var isButtonEnabled: Bool = false - } - - // MARK: - Properties - public var initialState = State(collection: nil) - - private let createCollectionListUseCase: CreateCollectionListUseCase - private let setCollectionUseCase: UpdateCollectionUseCase - - // MARK: - Init - public init(collection: CollectionResponse?, createCollectionListUseCase: CreateCollectionListUseCase, setCollectionUseCase: UpdateCollectionUseCase) { - self.initialState = State(collection: collection, inputText: collection?.name) - self.createCollectionListUseCase = createCollectionListUseCase - self.setCollectionUseCase = setCollectionUseCase - } - - // MARK: - Mutate - public func mutate(action: Action) -> Observable { - switch action { - case .inputTextChanged(let text): - let trimmed = text?.trimmingCharacters(in: .whitespacesAndNewlines) ?? "" - return Observable.from([ - .setButtonEnabled(!trimmed.isEmpty), - .saveInput(trimmed) - ]) - - case .backButtonTapped: - return .just(.toNavigate(.dismiss)) - - case .completeButtonTapped: - guard let text = currentState.inputText else { return .empty() } - let trimmed = text.trimmingCharacters(in: .whitespacesAndNewlines) - - if trimmed.count > 18 { - return .just(.setError(true)) - } - - if currentState.collection == nil { - return createCollectionListUseCase.execute(name: trimmed) - .andThen(.just(.toNavigate(.dismissWithData))) - .catch { _ in - return .just(.toNavigate(.createError)) - } - } else { - guard let id = currentState.collection?.collectionId else { return .empty() } - return setCollectionUseCase.execute( - collectionId: id, - name: trimmed - ) - .andThen(.just(.toNavigate(.dismissWithData))) - .catch { _ in - return .just(.toNavigate(.updateError)) - } - } - } - } - - // MARK: - Reduce - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .saveInput(let text): - newState.inputText = text - case .setError(let isError): - newState.isError = isError - case .setButtonEnabled(let isEnabled): - newState.isButtonEnabled = isEnabled - case .toNavigate(let route): - newState.route = route - } - - return newState - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionView.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionView.swift deleted file mode 100644 index 385f3acc..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionView.swift +++ /dev/null @@ -1,182 +0,0 @@ -import UIKit - -import BookmarkFeatureInterface -import DesignSystem -import DomainInterface - -import SnapKit - -public final class AddCollectionView: UIView { - // MARK: - Type - enum Constant { - static let radius: CGFloat = 8 - static let titleTopMargin: CGFloat = 20 - static let imageViewSize: CGFloat = 40 - static let iconInset: CGFloat = 8 - static let inputInset: CGFloat = 10 - static let inputSpacing: CGFloat = 16 - static let inputHeight: CGFloat = 60 - static let horizontalMargin: CGFloat = 16 - static let nameLabelTopMargin: CGFloat = 20 - static let nameLabelBottomMargin: CGFloat = 14 - static let buttonTopMargin: CGFloat = 68 - static let buttonBottomMargin: CGFloat = 10 - } - - // MARK: - Properties - public var addButtonBottomConstraint: Constraint? - - // MARK: - Components - private let titleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .h_xl_b, text: "컬렉션", alignment: .left) - return label - }() - - public let backButton: UIButton = { - let button = UIButton() - button.setImage(DesignSystemAsset.image(named: "largeX"), for: .normal) - return button - }() - - private lazy var inputTextView: UIView = { - let view = UIView() - view.backgroundColor = .neutral100 - view.layer.cornerRadius = Constant.radius - view.addSubview(imageView) - view.addSubview(inputTextField) - - imageView.snp.makeConstraints { make in - make.verticalEdges.leading.equalToSuperview().inset(Constant.inputInset) - make.size.equalTo(Constant.imageViewSize) - } - - inputTextField.snp.makeConstraints { make in - make.centerY.trailing.equalToSuperview() - make.leading.equalTo(imageView.snp.trailing).offset(Constant.inputSpacing) - } - return view - }() - - private let nameLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .sub_m_sb, text: "컬렉션 이름 입력", alignment: .left) - return label - }() - - private lazy var imageView: UIView = { - let view = UIView() - view.layer.cornerRadius = Constant.radius - view.backgroundColor = .neutral200 - view.addSubview(iconView) - iconView.snp.makeConstraints { make in - make.center.equalTo(view).inset(Constant.iconInset) - } - return view - }() - - private let iconView: UIImageView = { - let view = UIImageView() - view.image = DesignSystemAsset.image(named: "bookmark")?.withRenderingMode(.alwaysTemplate) - view.tintColor = .neutral300 - return view - }() - - public let inputTextField: UITextField = { - let textField = UITextField() - textField.backgroundColor = .clearMLS - textField.tintColor = .primary300 - textField.textAlignment = .left - textField.font = .korFont(style: .semiBold, size: 14) - textField.attributedPlaceholder = NSAttributedString( - string: "컬렉션 이름을 입력해주세요 (최대 18자)", - attributes: [.foregroundColor: UIColor.neutral500] - ) - return textField - }() - - private let errorMessage = ErrorMessage(message: "폴더명은 18자 이하로 입력해주세요.") - - public let completeButton = CommonButton(style: .normal, title: "완료", disabledTitle: "완료") - - // MARK: - init - public init() { - super.init(frame: .zero) - addViews() - setupConstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension AddCollectionView { - func addViews() { - addSubview(titleLabel) - addSubview(backButton) - addSubview(nameLabel) - addSubview(inputTextView) - addSubview(errorMessage) - addSubview(completeButton) - } - - func setupConstraints() { - titleLabel.snp.makeConstraints { - $0.top.equalToSuperview().inset(Constant.titleTopMargin) - $0.leading.equalToSuperview().inset(Constant.horizontalMargin) - } - - backButton.snp.makeConstraints { - $0.top.equalTo(titleLabel) - $0.leading.equalTo(titleLabel.snp.trailing) - $0.trailing.equalToSuperview().inset(Constant.horizontalMargin) - } - - nameLabel.snp.makeConstraints { - $0.top.equalTo(titleLabel.snp.bottom).offset(Constant.nameLabelTopMargin) - $0.horizontalEdges.equalToSuperview().inset(Constant.horizontalMargin) - } - - inputTextView.snp.makeConstraints { - $0.top.equalTo(nameLabel.snp.bottom).offset(Constant.nameLabelBottomMargin) - $0.horizontalEdges.equalToSuperview().inset(Constant.horizontalMargin) - $0.height.equalTo(Constant.inputHeight) - } - - errorMessage.snp.makeConstraints { - $0.bottom.equalTo(completeButton.snp.top).offset(-Constant.buttonBottomMargin) - $0.centerX.equalToSuperview() - } - - completeButton.snp.makeConstraints { - $0.top.equalTo(inputTextView.snp.bottom).offset(Constant.buttonTopMargin) - $0.horizontalEdges.equalToSuperview().inset(Constant.horizontalMargin) - addButtonBottomConstraint = $0.bottom.equalToSuperview().inset(Constant.buttonBottomMargin).constraint - } - } -} - -extension AddCollectionView { - func setError(isError: Bool) { - errorMessage.isHidden = !isError - } - - func setButtonEnabled(isEnabled: Bool) { - completeButton.isEnabled = isEnabled - } - - func checkIsEmptyCollection(collection: CollectionResponse?) { - if collection != nil { - nameLabel.attributedText = .makeStyledString(font: .sub_m_sb, text: "컬렉션 이름 수정", alignment: .left) - } - } - - func updateTextField(text: String?) { - if let text = text { - inputTextField.attributedText = .makeStyledString(font: .b_s_sb, text: text, color: .textColor, alignment: .left) - } - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionViewController.swift deleted file mode 100644 index fd32d227..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/AddCollection/AddCollectionViewController.swift +++ /dev/null @@ -1,235 +0,0 @@ -import UIKit - -import BaseFeature -import BookmarkFeatureInterface -import DesignSystem - -import ReactorKit -import RxKeyboard -import RxSwift -import SnapKit - -public final class AddCollectionViewController: BaseViewController, View { - public typealias Reactor = AddCollectionModalReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - public let dismissed = PublishSubject() - - // MARK: - Components - private let mainView = AddCollectionView() - private let addCollectionContainer = UIView() - private let dimmedBackgroundView: UIView = { - let view = UIView() - view.backgroundColor = UIColor.black.withAlphaComponent(0.5) - view.alpha = 0 - view.isHidden = true - view.isUserInteractionEnabled = true - return view - }() - - // MARK: - Init - override public init() { - super.init() - modalPresentationStyle = .overFullScreen - modalTransitionStyle = .crossDissolve - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // MARK: - Lifecycle - override public func viewDidLoad() { - super.viewDidLoad() - setupViews() - setupConstraints() - setupGestures() - } - - override public func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - setupKeyboard() - presentWithAnimation() - } -} - -// MARK: - Setup -private extension AddCollectionViewController { - func setupViews() { - view.backgroundColor = .clear - - view.addSubview(dimmedBackgroundView) - view.addSubview(addCollectionContainer) - addCollectionContainer.addSubview(mainView) - - addCollectionContainer.layer.cornerRadius = 16 - addCollectionContainer.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner] - addCollectionContainer.backgroundColor = .whiteMLS - - addCollectionContainer.isHidden = true - mainView.isHidden = false - } - - func setupConstraints() { - dimmedBackgroundView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - - addCollectionContainer.snp.makeConstraints { make in - make.horizontalEdges.bottom.equalTo(view.safeAreaLayoutGuide) - } - - mainView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } - - func setupGestures() { - let tapGesture = UITapGestureRecognizer() - dimmedBackgroundView.addGestureRecognizer(tapGesture) - - tapGesture.rx.event - .withUnretained(self) - .subscribe(onNext: { owner, _ in - owner.dismissWithAnimation(withData: false) - }) - .disposed(by: disposeBag) - } - - func setupKeyboard() { - setupKeyboard(inset: AddCollectionView.Constant.buttonBottomMargin) { [weak self] height in - self?.mainView.addButtonBottomConstraint?.update(inset: height) - } - } -} - -// MARK: - Bind -extension AddCollectionViewController { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindState(reactor: reactor) - } - - private func bindUserActions(reactor: Reactor) { - mainView.inputTextField.rx.text - .distinctUntilChanged() - .map { Reactor.Action.inputTextChanged($0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.backButton.rx.tap - .map { Reactor.Action.backButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.completeButton.rx.tap - .map { Reactor.Action.completeButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - private func bindState(reactor: Reactor) { - reactor.state - .map(\.inputText) - .take(1) - .withUnretained(self) - .bind(onNext: { owner, text in - owner.mainView.updateTextField(text: text) - }) - .disposed(by: disposeBag) - - reactor.state - .map(\.isError) - .distinctUntilChanged() - .withUnretained(self) - .bind { owner, isError in - owner.mainView.setError(isError: isError) - } - .disposed(by: disposeBag) - - reactor.state - .map(\.collection) - .distinctUntilChanged() - .withUnretained(self) - .bind { owner, collection in - owner.mainView.checkIsEmptyCollection(collection: collection) - } - .disposed(by: disposeBag) - - reactor.state - .map(\.isButtonEnabled) - .distinctUntilChanged() - .withUnretained(self) - .bind { owner, isEnabled in - owner.mainView.setButtonEnabled(isEnabled: isEnabled) - } - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .observe(on: MainScheduler.asyncInstance) - .withUnretained(self) - .subscribe(onNext: { owner, route in - switch route { - case .dismiss: - owner.dismissWithAnimation(withData: false) { - owner.dismiss(animated: false) - } - case .dismissWithData: - owner.dismissWithAnimation(withData: true) { - owner.dismiss(animated: false) - } - case .updateError: - ToastFactory.createToast(message: "컬렉션 수정에 실패했어요. 다시 시도해주세요.") - case .createError: - ToastFactory.createToast(message: "컬렉션 생성에 실패했어요. 다시 시도해주세요.") - default: - break - } - }) - .disposed(by: disposeBag) - } -} - -// MARK: - Animation -private extension AddCollectionViewController { - func presentWithAnimation() { - dimmedBackgroundView.alpha = 0 - dimmedBackgroundView.isHidden = false - addCollectionContainer.isHidden = false - addCollectionContainer.transform = CGAffineTransform(translationX: 0, y: 400) - - UIView.animate(withDuration: 0.25) { - self.dimmedBackgroundView.alpha = 1 - self.addCollectionContainer.transform = .identity - } - - mainView.setError(isError: false) - mainView.setButtonEnabled(isEnabled: false) - mainView.inputTextField.becomeFirstResponder() - } - - func dismissWithAnimation(withData: Bool, completion: (() -> Void)? = nil) { - mainView.endEditing(true) - - UIView.animate(withDuration: 0.25, animations: { - self.dimmedBackgroundView.alpha = 0 - self.addCollectionContainer.transform = CGAffineTransform(translationX: 0, y: 400) - }, completion: { _ in - self.addCollectionContainer.isHidden = true - self.dimmedBackgroundView.isHidden = true - - if withData { - guard let text = self.mainView.inputTextField.text else { return } - self.dismissed.onNext((text)) - self.dismissed.onCompleted() - } - - self.dismiss(animated: false, completion: completion) - }) - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListFactoryImpl.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListFactoryImpl.swift deleted file mode 100644 index edb8ceb6..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListFactoryImpl.swift +++ /dev/null @@ -1,90 +0,0 @@ -import AuthFeatureInterface -import BaseFeature -import BookmarkFeatureInterface -import DictionaryFeatureInterface -import DomainInterface - -public final class BookmarkListFactoryImpl: BookmarkListFactory { - private let itemFilterFactory: ItemFilterBottomSheetFactory - private let monsterFilterFactory: MonsterFilterBottomSheetFactory - private let sortedFactory: SortedBottomSheetFactory - private let bookmarkModalFactory: BookmarkModalFactory - private let loginFactory: LoginFactory - private let dictionaryDetailFactory: DictionaryDetailFactory - private let collectionEditFactory: CollectionEditFactory - - private let setBookmarkUseCase: SetBookmarkUseCase - private let fetchProfileUseCase: FetchProfileUseCase - private let fetchBookmarkUseCase: FetchBookmarkUseCase - private let fetchMonsterBookmarkUseCase: FetchMonsterBookmarkUseCase - private let fetchItemBookmarkUseCase: FetchItemBookmarkUseCase - private let fetchNPCBookmarkUseCase: FetchNPCBookmarkUseCase - private let fetchQuestBookmarkUseCase: FetchQuestBookmarkUseCase - private let fetchMapBookmarkUseCase: FetchMapBookmarkUseCase - private let parseItemFilterResultUseCase: ParseItemFilterResultUseCase - - public init( - itemFilterFactory: ItemFilterBottomSheetFactory, - monsterFilterFactory: MonsterFilterBottomSheetFactory, - sortedFactory: SortedBottomSheetFactory, - bookmarkModalFactory: BookmarkModalFactory, - loginFactory: LoginFactory, - dictionaryDetailFactory: DictionaryDetailFactory, - collectionEditFactory: CollectionEditFactory, - setBookmarkUseCase: SetBookmarkUseCase, - fetchProfileUseCase: FetchProfileUseCase, - fetchBookmarkUseCase: FetchBookmarkUseCase, - fetchMonsterBookmarkUseCase: FetchMonsterBookmarkUseCase, - fetchItemBookmarkUseCase: FetchItemBookmarkUseCase, - fetchNPCBookmarkUseCase: FetchNPCBookmarkUseCase, - fetchQuestBookmarkUseCase: FetchQuestBookmarkUseCase, - fetchMapBookmarkUseCase: FetchMapBookmarkUseCase, - parseItemFilterResultUseCase: ParseItemFilterResultUseCase - ) { - self.itemFilterFactory = itemFilterFactory - self.monsterFilterFactory = monsterFilterFactory - self.sortedFactory = sortedFactory - self.bookmarkModalFactory = bookmarkModalFactory - self.loginFactory = loginFactory - self.dictionaryDetailFactory = dictionaryDetailFactory - self.collectionEditFactory = collectionEditFactory - self.setBookmarkUseCase = setBookmarkUseCase - self.fetchProfileUseCase = fetchProfileUseCase - self.fetchBookmarkUseCase = fetchBookmarkUseCase - self.fetchNPCBookmarkUseCase = fetchNPCBookmarkUseCase - self.fetchMonsterBookmarkUseCase = fetchMonsterBookmarkUseCase - self.fetchItemBookmarkUseCase = fetchItemBookmarkUseCase - self.fetchQuestBookmarkUseCase = fetchQuestBookmarkUseCase - self.fetchMapBookmarkUseCase = fetchMapBookmarkUseCase - self.parseItemFilterResultUseCase = parseItemFilterResultUseCase - } - - public func make(type: DictionaryType, listType: DictionaryMainViewType) -> BaseViewController { - let reactor = BookmarkListReactor( - type: type, - fetchProfileUseCase: fetchProfileUseCase, - setBookmarkUseCase: setBookmarkUseCase, - fetchBookmarkUseCase: fetchBookmarkUseCase, - fetchMonsterBookmarkUseCase: fetchMonsterBookmarkUseCase, - fetchItemBookmarkUseCase: fetchItemBookmarkUseCase, - fetchNPCBookmarkUseCase: fetchNPCBookmarkUseCase, - fetchQuestBookmarkUseCase: fetchQuestBookmarkUseCase, - fetchMapBookmarkUseCase: fetchMapBookmarkUseCase, - parseItemFilterResultUseCase: parseItemFilterResultUseCase - ) - let viewController = BookmarkListViewController( - reactor: reactor, - itemFilterFactory: itemFilterFactory, - monsterFilterFactory: monsterFilterFactory, - sortedFactory: sortedFactory, - bookmarkModalFactory: bookmarkModalFactory, - loginFactory: loginFactory, - dictionaryDetailFactory: dictionaryDetailFactory, - collectionEditFactory: collectionEditFactory - ) - if listType == .search { - viewController.isBottomTabbarHidden = true - } - return viewController - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListReactor.swift deleted file mode 100644 index 38e19e26..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListReactor.swift +++ /dev/null @@ -1,319 +0,0 @@ -import DomainInterface - -import ReactorKit -import RxSwift - -public final class BookmarkListReactor: Reactor { - // MARK: - Type - public enum Route { - case none - case sort(DictionaryType) - case filter(DictionaryType) - case detail(DictionaryType, Int) - case dictionary - case login - case edit - case bookmarkError - } - - public enum UIEvent { - case none - case add(BookmarkResponse) - case delete(BookmarkResponse) - case undo - case login - } - - enum ViewState: Equatable { - case loginWithData - case loginWithoutData - case logout - } - - // MARK: - Action - public enum Action { - case viewWillAppear - case toggleBookmark(Int) - case sortButtonTapped - case filterButtonTapped - case editButtonTapped - case fetchList - case sortOptionSelected(SortType) - case filterOptionSelected(startLevel: Int, endLevel: Int) - case undoLastDeletedBookmark - case dataTapped(Int) - case emptyButtonTapped - case itemFilterOptionSelected([(String, String)]) - case showLogin - } - - // MARK: - Mutation - public enum Mutation { - case setItems([BookmarkResponse]) - case setLoginState(Bool) - case setSort(SortType) - case setFilter(start: Int?, end: Int?) - case setLastDeletedBookmark(BookmarkResponse?) - case navigatTo(Route) - case setJobId([Int]) - case setCategoryId([Int]) - case setEvent(UIEvent) - } - - // MARK: - State - public struct State { - @Pulse var uiEvent: UIEvent = .none - @Pulse var route: Route - var items: [BookmarkResponse] = [] - var type: DictionaryType - var isLogin: Bool - var jobId: [Int]? - var categoryIds: [Int]? - var sort: SortType? - var startLevel: Int? - var endLevel: Int? - var lastDeletedBookmark: BookmarkResponse? - var viewState: ViewState { - if !isLogin { - return .logout - } else if items.isEmpty { - return .loginWithoutData - } else { - return .loginWithData - } - } - } - - public var initialState: State - - // MARK: - UseCases - private let fetchProfileUseCase: FetchProfileUseCase - private let setBookmarkUseCase: SetBookmarkUseCase - - private let fetchTotalBookmarkUseCase: FetchBookmarkUseCase - private let fetchMonsterBookmarkUseCase: FetchMonsterBookmarkUseCase - private let fetchItemBookmarkUseCase: FetchItemBookmarkUseCase - private let fetchNPCBookmarkUseCase: FetchNPCBookmarkUseCase - private let fetchQuestBookmarkUseCase: FetchQuestBookmarkUseCase - private let fetchMapBookmarkUseCase: FetchMapBookmarkUseCase - private let parseItemFilterResultUseCase: ParseItemFilterResultUseCase - - private let disposeBag = DisposeBag() - - // MARK: - Init - public init( - type: DictionaryType, - fetchProfileUseCase: FetchProfileUseCase, - setBookmarkUseCase: SetBookmarkUseCase, - fetchBookmarkUseCase: FetchBookmarkUseCase, - fetchMonsterBookmarkUseCase: FetchMonsterBookmarkUseCase, - fetchItemBookmarkUseCase: FetchItemBookmarkUseCase, - fetchNPCBookmarkUseCase: FetchNPCBookmarkUseCase, - fetchQuestBookmarkUseCase: FetchQuestBookmarkUseCase, - fetchMapBookmarkUseCase: FetchMapBookmarkUseCase, - parseItemFilterResultUseCase: ParseItemFilterResultUseCase - ) { - self.initialState = State(route: .none, type: type, isLogin: false) - self.fetchProfileUseCase = fetchProfileUseCase - self.setBookmarkUseCase = setBookmarkUseCase - self.fetchTotalBookmarkUseCase = fetchBookmarkUseCase - self.fetchMonsterBookmarkUseCase = fetchMonsterBookmarkUseCase - self.fetchItemBookmarkUseCase = fetchItemBookmarkUseCase - self.fetchNPCBookmarkUseCase = fetchNPCBookmarkUseCase - self.fetchQuestBookmarkUseCase = fetchQuestBookmarkUseCase - self.fetchMapBookmarkUseCase = fetchMapBookmarkUseCase - self.parseItemFilterResultUseCase = parseItemFilterResultUseCase - } - - // MARK: - Mutate - public func mutate(action: Action) -> Observable { - switch action { - case .viewWillAppear: - return fetchProfileUseCase.execute() - .flatMap { [weak self] profile -> Observable in - guard let self = self else { return .empty() } - if profile == nil { - return .just(.setLoginState(false)) - } else { - return Observable.concat([ - .just(.setLoginState(true)), - self.fetchList() - ]) - } - } - - case let .toggleBookmark(id): - return handleTogle(id: id) - - case .sortButtonTapped: - return .just(.navigatTo(.sort(currentState.type))) - - case .filterButtonTapped: - return .just(.navigatTo(.filter(currentState.type))) - - case .fetchList: - guard currentState.isLogin else { return .empty() } - return fetchList() - - case let .sortOptionSelected(sort): - return Observable.concat([ - .just(.setSort(sort)), - fetchList(sort: sort) - ]) - - case let .filterOptionSelected(startLevel, endLevel): - return Observable.concat([ - .just(.setFilter(start: startLevel, end: endLevel)), - fetchList() - ]) - - case .undoLastDeletedBookmark: - return handleUndo() - - case let .dataTapped(index): - let item = currentState.items[index] - guard let type = item.type.toDictionaryType else { return .empty() } - return .just(.navigatTo(.detail(type, item.originalId))) - case .emptyButtonTapped: - if currentState.viewState == .logout { - return .just(.navigatTo(.login)) - } else { - return .just(.navigatTo(.dictionary)) - } - case .editButtonTapped: - return .just(.navigatTo(.edit)) - case let .itemFilterOptionSelected(results): - let criteria = parseItemFilterResultUseCase.execute(results: results) - - return .concat([ - .just(.setJobId(criteria.jobIds)), - .just(.setFilter(start: criteria.startLevel, end: criteria.endLevel)), - .just(.setCategoryId(criteria.categoryIds)) - ]) - .concat(Observable.deferred { [weak self] in - guard let self = self else { return .empty() } - return self.fetchList() - }) - case .showLogin: - return .just(.setEvent(.login)) - } - } - - // MARK: - Fetch List - private func fetchList(sort: SortType? = nil) -> Observable { - switch currentState.type { - case .total: - return fetchTotalBookmarkUseCase.execute( - sort: sort ?? currentState.sort - ).map { .setItems($0) } - - case .monster: - return fetchMonsterBookmarkUseCase.execute( - minLevel: currentState.startLevel ?? 1, - maxLevel: currentState.endLevel ?? 200, - sort: sort ?? currentState.sort - ).map { .setItems($0) } - - case .item: - return fetchItemBookmarkUseCase.execute( - jobId: nil, - minLevel: currentState.startLevel, - maxLevel: currentState.endLevel, - categoryIds: nil, - sort: sort ?? currentState.sort - ).map { .setItems($0) } - - case .npc: - return fetchNPCBookmarkUseCase.execute(sort: sort ?? currentState.sort) - .map { .setItems($0) } - - case .quest: - return fetchQuestBookmarkUseCase.execute(sort: sort ?? currentState.sort) - .map { .setItems($0) } - - case .map: - return fetchMapBookmarkUseCase.execute(sort: sort ?? currentState.sort) - .map { .setItems($0) } - - default: - return .empty() - } - } - - // MARK: - Reduce - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case let .setItems(response): - newState.items = response - case let .setLoginState(isLogin): - newState.isLogin = isLogin - case let .setSort(sort): - newState.sort = sort - case let .setFilter(start, end): - newState.startLevel = start - newState.endLevel = end - case let .setLastDeletedBookmark(item): - newState.lastDeletedBookmark = item - case let .navigatTo(route): - newState.route = route - case let .setJobId(ids): - newState.jobId = ids - case let .setCategoryId(ids): - newState.categoryIds = ids - case let .setEvent(event): - newState.uiEvent = event - } - - return newState - } -} - -private extension BookmarkListReactor { - func handleTogle(id: Int) -> Observable { - guard let index = currentState.items.firstIndex(where: { $0.originalId == id }) else { - return .empty() - } - - let targetItem = currentState.items[index] - - return setBookmarkUseCase.execute(bookmarkId: targetItem.bookmarkId, isBookmark: .delete) - .flatMap { _ -> Observable in - let lastItem = Mutation.setLastDeletedBookmark(targetItem) - - let eventMutation = Mutation.setEvent(.delete(targetItem)) - - return Observable.concat([ - .from([lastItem, eventMutation]), - self.fetchList() - ]) - } - .catch { _ in - .just(.navigatTo(.bookmarkError)) - } - } - - func handleUndo() -> Observable { - guard let lastDeleted = currentState.lastDeletedBookmark else { return .empty() } - - return setBookmarkUseCase.execute( - bookmarkId: lastDeleted.originalId, - isBookmark: .set(lastDeleted.type) - ) - .flatMap { _ -> Observable in - let lastItem = Mutation.setLastDeletedBookmark(nil) - - let event: UIEvent = .add(lastDeleted) - let eventMutation = Mutation.setEvent(event) - - return Observable.concat([ - .from([lastItem, eventMutation]), - self.fetchList() - ]) - } - .catch { _ in - .just(.navigatTo(.bookmarkError)) - } - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListView.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListView.swift deleted file mode 100644 index fe335d9a..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListView.swift +++ /dev/null @@ -1,26 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem - -final class BookmarkListView: BaseListView { - let bookmarkEmptyView: DataEmptyView - - // MARK: - Init - init(isFilterHidden: Bool, bookmarkEmptyView: DataEmptyView) { - let editButton = TextButton() - let sortButton = BaseListView.makeSortButton(title: "가나다 순", tintColor: .textColor) - let filterButton = BaseListView.makeFilterButton(title: "필터", tintColor: .textColor) - self.bookmarkEmptyView = bookmarkEmptyView - super.init( - editButton: editButton, - sortButton: sortButton, - filterButton: filterButton, - emptyView: bookmarkEmptyView, - isFilterHidden: isFilterHidden - ) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { fatalError() } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift deleted file mode 100644 index 853d175a..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkList/BookmarkListViewController.swift +++ /dev/null @@ -1,356 +0,0 @@ -import UIKit - -import AuthFeatureInterface -import BaseFeature -import BookmarkFeatureInterface -import DesignSystem -import DictionaryFeatureInterface -import DomainInterface - -import ReactorKit -import RxCocoa -import RxSwift - -public final class BookmarkListViewController: BaseViewController, View { - public typealias Reactor = BookmarkListReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - private let bookmarkChangeRelay = PublishRelay<(id: Int, newBookmarkId: Int?)>() - private var undoRelay = PublishRelay() - private var addCollectionRelay = PublishRelay() - - private let itemFilterFactory: ItemFilterBottomSheetFactory - private let monsterFilterFactory: MonsterFilterBottomSheetFactory - private let bookmarkModalFactory: BookmarkModalFactory - private let sortedFactory: SortedBottomSheetFactory - private let loginFactory: LoginFactory - private let dictionaryDetailFactory: DictionaryDetailFactory - private let collectionEditFactory: CollectionEditFactory - - private var selectedSortIndex = 0 - - // MARK: - Components - private var mainView: BookmarkListView - private var emptyView = DataEmptyView(type: .bookmark) - - public init( - reactor: BookmarkListReactor, - itemFilterFactory: ItemFilterBottomSheetFactory, - monsterFilterFactory: MonsterFilterBottomSheetFactory, - sortedFactory: SortedBottomSheetFactory, - bookmarkModalFactory: BookmarkModalFactory, - loginFactory: LoginFactory, - dictionaryDetailFactory: DictionaryDetailFactory, - collectionEditFactory: CollectionEditFactory - ) { - self.itemFilterFactory = itemFilterFactory - self.monsterFilterFactory = monsterFilterFactory - self.sortedFactory = sortedFactory - self.bookmarkModalFactory = bookmarkModalFactory - self.loginFactory = loginFactory - self.dictionaryDetailFactory = dictionaryDetailFactory - self.collectionEditFactory = collectionEditFactory - self.mainView = BookmarkListView(isFilterHidden: reactor.currentState.type.isBookmarkSortHidden, bookmarkEmptyView: emptyView) - super.init() - self.reactor = reactor - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override public func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension BookmarkListViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide) - make.horizontalEdges.bottom.equalToSuperview() - } - } - - func configureUI() { - mainView.listCollectionView.collectionViewLayout = createListLayout() - mainView.listCollectionView.delegate = self - mainView.listCollectionView.dataSource = self - mainView.listCollectionView.register(DictionaryListCell.self, forCellWithReuseIdentifier: DictionaryListCell.identifier) - } - - func createListLayout() -> UICollectionViewLayout { - guard let isHidden = reactor?.currentState.type.isBookmarkSortHidden else { return UICollectionViewLayout() } - let layoutFactory = LayoutFactory() - let layout = CompositionalLayoutBuilder() - .section { _ in layoutFactory.getDictionaryListLayout(isFilterHidden: isHidden) } - .build() - layout.register(Neutral300DividerView.self, forDecorationViewOfKind: Neutral300DividerView.identifier) - return layout - } -} - -// MARK: - Bind -extension BookmarkListViewController { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .map { _ in Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.sortButton.rx.tap - .map { Reactor.Action.sortButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.filterButton.rx.tap - .map { Reactor.Action.filterButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.editButton?.rx.tap - .map { Reactor.Action.editButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - emptyView.button.rx.tap - .map { .emptyButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - reactor.state - .map(\.items) - .distinctUntilChanged() - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind(onNext: { owner, items in - owner.mainView.checkEmptyData(isEmpty: items.isEmpty) - owner.mainView.listCollectionView.reloadData() - }) - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, route in - switch route { - case .sort(let type): - let viewController = owner.sortedFactory.make(sortedOptions: type.bookmarkSortedFilter, selectedIndex: owner.selectedSortIndex) { index in - owner.selectedSortIndex = index - let selectedFilter = reactor.currentState.type.bookmarkSortedFilter[index] - reactor.action.onNext(.sortOptionSelected(selectedFilter)) - owner.mainView.selectSort(selectedType: selectedFilter) - } - owner.tabBarController?.presentModal(viewController) - case .filter(let type): - switch type { - case .item: - let viewController = owner.itemFilterFactory.make { results in - reactor.action.onNext(.itemFilterOptionSelected(results)) - - if results.isEmpty { - owner.mainView.resetFilter() - } else { - owner.mainView.selectFilter() - } - } - owner.present(viewController, animated: true) - case .monster: - let viewController = owner.monsterFilterFactory.make(startLevel: reactor.currentState.startLevel ?? 1, endLevel: reactor.currentState.endLevel ?? 200) { startLevel, endLevel in - owner.mainView.selectFilter() - reactor.action.onNext(.filterOptionSelected(startLevel: startLevel, endLevel: endLevel)) - } - owner.tabBarController?.presentModal(viewController) - default: - break - } - case .detail(let type, let id): - let viewcontroller = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkChangeRelay, loginRelay: nil) - owner.navigationController?.pushViewController(viewcontroller, animated: true) - case .login: - let viewcontroller = owner.loginFactory.make(exitRoute: .pop) - owner.navigationController?.pushViewController(viewcontroller, animated: true) - - case .dictionary: - if let tabBarController = owner.tabBarController as? BottomTabBarController { - tabBarController.selectTab(index: 0) - DictionaryTabRegistry.changeTab(index: reactor.currentState.type.tabIndex) - } - case .edit: - let viewController = owner.collectionEditFactory.make(bookmarks: reactor.currentState.items) - owner.navigationController?.pushViewController(viewController, animated: true) - case .bookmarkError: - ToastFactory.createToast(message: "북마크 요청에 실패했어요. 다시 시도해주세요.") - default: - break - } - } - .disposed(by: disposeBag) - - reactor.state - .map(\.type) - .distinctUntilChanged() - .withUnretained(self) - .bind(onNext: { owner, type in - owner.mainView.updateBookmarkFilter(type: type) - owner.mainView.updateFilter(sortType: type.bookmarkSortedFilter.first) - }) - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$uiEvent) } - .withUnretained(self) - .subscribe(onNext: { owner, event in - switch event { - case .add(let item): - owner.presentAddSnackBar(item: item) - case .delete(let item): - owner.presentDeleteSnackBar(item: item) - case .login: - owner.presentLoginGuide() - default: - break - } - }) - .disposed(by: disposeBag) - } - - private func presentAddSnackBar(item: BookmarkResponse) { - SnackBarFactory.createSnackBar( - type: .normal, - imageUrl: item.imageUrl, - imageBackgroundColor: item.type.backgroundColor, - text: "아이템을 북마크에 추가했어요.", - buttonText: "컬렉션 추가", - buttonAction: { [weak self] in - self?.reactor?.state.map(\.items) - .compactMap { items in - items.first(where: { $0.originalId == item.originalId })?.bookmarkId - } - .take(1) - .observe(on: MainScheduler.instance) - .subscribe(onNext: { [weak self] bookmarkId in - guard let self else { return } - let vc = self.bookmarkModalFactory.make(bookmarkIds: [bookmarkId]) { isAdd in - if isAdd { - ToastFactory.createToast( - message: "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요." - ) - } - } - vc.modalPresentationStyle = .pageSheet - if let sheet = vc.sheetPresentationController { - sheet.detents = [.medium(), .large()] - sheet.prefersGrabberVisible = true - sheet.preferredCornerRadius = 16 - } - self.present(vc, animated: true) - }) - .disposed(by: self?.disposeBag ?? DisposeBag()) - } - ) - } - - private func presentDeleteSnackBar(item: BookmarkResponse) { - SnackBarFactory.createSnackBar( - type: .delete, - imageUrl: item.imageUrl, - imageBackgroundColor: item.type.backgroundColor, - text: "아이템을 북마크에서 삭제했어요.", - buttonText: "되돌리기", - buttonAction: { [weak self] in - self?.undoRelay.accept(()) - self?.reactor?.action.onNext(.undoLastDeletedBookmark) - } - ) - } - - private func presentLoginGuide() { - GuideAlertFactory.show( - mainText: "북마크를 하려면 로그인이 필요해요.", - ctaText: "로그인 하기", - cancelText: "취소", - ctaAction: { [weak self] in - guard let self else { return } - let vc = self.loginFactory.make(exitRoute: .pop) - self.navigationController?.pushViewController(vc, animated: true) - }, - cancelAction: nil - ) - } - -} - -// MARK: - Delegate -extension BookmarkListViewController: UICollectionViewDelegate, UICollectionViewDataSource { - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - reactor?.currentState.items.count ?? 0 - } - - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let state = reactor?.currentState else { return UICollectionViewCell() } - guard - let cell = collectionView.dequeueReusableCell( - withReuseIdentifier: DictionaryListCell.identifier, - for: indexPath - ) as? DictionaryListCell - else { - return UICollectionViewCell() - } - - let item = state.items[indexPath.row] - var subText: String? { - [.item, .monster, .quest].contains(item.type) ? item.level.map { "Lv. \($0)" } : nil - } - cell.inject( - type: .bookmark, - input: DictionaryListCell.Input( - type: item.type, - mainText: item.name, - subText: subText, - imageUrl: item.imageUrl ?? "", - isBookmarked: true - ), - indexPath: indexPath, - collectionView: collectionView, - isMap: item.type == .map, - - onBookmarkTapped: { [weak self] in - guard let self else { return } - guard self.reactor?.currentState.isLogin == true else { - self.reactor?.action.onNext(.showLogin) - return - } - self.reactor?.action.onNext(.toggleBookmark(item.originalId)) - } - ) - - return cell - } - - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - reactor?.action.onNext(.dataTapped(indexPath.item)) - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkMain/BookmarkMainFactoryImpl.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkMain/BookmarkMainFactoryImpl.swift deleted file mode 100644 index 8d1aaa9c..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkMain/BookmarkMainFactoryImpl.swift +++ /dev/null @@ -1,56 +0,0 @@ -import AuthFeatureInterface -import BaseFeature -import BookmarkFeatureInterface -import DictionaryFeatureInterface -import DomainInterface - -public final class BookmarkMainFactoryImpl: BookmarkMainFactory { - private let setBookmarkUseCase: SetBookmarkUseCase - private let checkLoginUseCase: CheckLoginUseCase - private let fetchVisitBookmarkUseCase: FetchVisitBookmarkUseCase - - private let onBoardingFactory: BookmarkOnBoardingFactory - private let bookmarkListFactory: BookmarkListFactory - private let collectionListFactory: CollectionListFactory - private let searchFactory: DictionarySearchFactory - private let notificationFactory: DictionaryNotificationFactory - private let loginFactory: LoginFactory - - public init( - setBookmarkUseCase: SetBookmarkUseCase, - checkLoginUseCase: CheckLoginUseCase, - fetchVisitBookmarkUseCase: FetchVisitBookmarkUseCase, - onBoardingFactory: BookmarkOnBoardingFactory, - bookmarkListFactory: BookmarkListFactory, - collectionListFactory: CollectionListFactory, - searchFactory: DictionarySearchFactory, - notificationFactory: DictionaryNotificationFactory, - loginFactory: LoginFactory - ) { - self.setBookmarkUseCase = setBookmarkUseCase - self.checkLoginUseCase = checkLoginUseCase - self.fetchVisitBookmarkUseCase = fetchVisitBookmarkUseCase - self.onBoardingFactory = onBoardingFactory - self.bookmarkListFactory = bookmarkListFactory - self.collectionListFactory = collectionListFactory - self.searchFactory = searchFactory - self.notificationFactory = notificationFactory - self.loginFactory = loginFactory - } - - public func make() -> BaseViewController { - let reactor = BookmarkMainReactor( - setBookmarkUseCase: setBookmarkUseCase, checkLoginUseCase: checkLoginUseCase, fetchVisitBookmarkUseCase: fetchVisitBookmarkUseCase - ) - let viewController = BookmarkMainViewController( - onBoardingFactory: onBoardingFactory, - bookmarkListFactory: bookmarkListFactory, - collectionListFactory: collectionListFactory, - searchFactory: searchFactory, - notificationFactory: notificationFactory, - loginFactory: loginFactory, - reactor: reactor - ) - return viewController - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkMain/BookmarkMainReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkMain/BookmarkMainReactor.swift deleted file mode 100644 index 1c9d5da2..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkMain/BookmarkMainReactor.swift +++ /dev/null @@ -1,86 +0,0 @@ -import DomainInterface - -import ReactorKit - -public final class BookmarkMainReactor: Reactor { - public enum Route { - case none - case search - case onBoarding - case notification - case edit - case login - } - - public enum Action { - case viewWillAppear - case searchButtonTapped - case notificationButtonTapped - case loginButtonTapped - } - - public enum Mutation { - case navigateTo(Route) - case setLogin(Bool) - } - - public struct State { - @Pulse var route: Route - let type = DictionaryMainViewType.bookmark - var sections: [String] { - return type.pageTabList.map { $0.title } - } - - var isLogin = false - } - - // MARK: - Properties - private let setBookmarkUseCase: SetBookmarkUseCase - private let checkLoginUseCase: CheckLoginUseCase - private let fetchVisitBookmarkUseCase: FetchVisitBookmarkUseCase - - public var initialState: State - - private let disposeBag = DisposeBag() - - public init(setBookmarkUseCase: SetBookmarkUseCase, checkLoginUseCase: CheckLoginUseCase, fetchVisitBookmarkUseCase: FetchVisitBookmarkUseCase) { - self.initialState = State(route: .none) - self.setBookmarkUseCase = setBookmarkUseCase - self.checkLoginUseCase = checkLoginUseCase - self.fetchVisitBookmarkUseCase = fetchVisitBookmarkUseCase - } - - public func mutate(action: Action) -> Observable { - switch action { - case .viewWillAppear: - let onboardingMutation = fetchVisitBookmarkUseCase.execute() - .flatMap { hasVisited -> Observable in - if hasVisited { - return .empty() - } else { - return .just(.navigateTo(.onBoarding)) - } - } - let loginMutation = checkLoginUseCase.execute() - .map { Mutation.setLogin($0) } - return .concat([onboardingMutation, loginMutation]) - case .searchButtonTapped: - return Observable.just(.navigateTo(.search)) - case .notificationButtonTapped: - return Observable.just(.navigateTo(.notification)) - case .loginButtonTapped: - return .just(.navigateTo(.login)) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - switch mutation { - case let .navigateTo(route): - newState.route = route - case let .setLogin(isLogin): - newState.isLogin = isLogin - } - return newState - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkMain/BookmarkMainView.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkMain/BookmarkMainView.swift deleted file mode 100644 index f58e0cfa..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkMain/BookmarkMainView.swift +++ /dev/null @@ -1,101 +0,0 @@ -import BaseFeature -import DesignSystem -import DomainInterface -import SnapKit -import UIKit - -final class BookmarkMainView: UIView { - enum Constant { - static let topMargin: CGFloat = 20 - static let pageTabHeight: CGFloat = 40 - static let bottomTabHeight: CGFloat = 64 - } - - // MARK: - Components - public let headerView = Header(style: .main, title: "북마크") - public let searchBar = SearchBar() - - public let tabCollectionView: UICollectionView = { - let layout = UICollectionViewLayout() - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) - collectionView.isScrollEnabled = false - return collectionView - }() - - public let pageViewController = UIPageViewController( - transitionStyle: .scroll, - navigationOrientation: .horizontal - ) - - public let emptyView = ToLoginView() - - // MARK: - Init - public init(type: DictionaryMainViewType) { - super.init(frame: .zero) - setupBaseLayout(type: type) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Base Layout -private extension BookmarkMainView { - func setupBaseLayout(type: DictionaryMainViewType) { - switch type { - case .search: - addSubview(searchBar) - searchBar.snp.makeConstraints { make in - make.top.equalTo(safeAreaLayoutGuide) - make.horizontalEdges.equalToSuperview() - } - default: - addSubview(headerView) - headerView.snp.makeConstraints { make in - make.top.equalTo(safeAreaLayoutGuide) - make.horizontalEdges.equalToSuperview() - } - - addSubview(tabCollectionView) - addSubview(pageViewController.view) - addSubview(emptyView) - - tabCollectionView.snp.makeConstraints { make in - make.top.equalTo(headerView.snp.bottom).offset(Constant.topMargin) - make.horizontalEdges.equalToSuperview() - make.height.equalTo(Constant.pageTabHeight) - } - - pageViewController.view.snp.makeConstraints { make in - make.top.equalTo(tabCollectionView.snp.bottom) - make.horizontalEdges.equalTo(safeAreaLayoutGuide) - make.bottom.equalToSuperview().inset(Constant.bottomTabHeight) - } - - emptyView.snp.makeConstraints { make in - make.top.equalTo(headerView.snp.bottom).offset(Constant.topMargin) - make.horizontalEdges.equalToSuperview() - make.bottom.equalToSuperview().inset(Constant.bottomTabHeight) - } - - tabCollectionView.isHidden = true - pageViewController.view.isHidden = true - emptyView.isHidden = false - } - } -} - -// MARK: - Public Update -extension BookmarkMainView { - public func updateLoginState(isLogin: Bool) { - tabCollectionView.isHidden = !isLogin - pageViewController.view.isHidden = !isLogin - - emptyView.isHidden = isLogin - - tabCollectionView.isUserInteractionEnabled = isLogin - pageViewController.view.isUserInteractionEnabled = isLogin - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkMain/BookmarkMainViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkMain/BookmarkMainViewController.swift deleted file mode 100644 index d1fd9e50..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkMain/BookmarkMainViewController.swift +++ /dev/null @@ -1,257 +0,0 @@ -import UIKit - -import AuthFeatureInterface -import BaseFeature -import BookmarkFeatureInterface -import DictionaryFeatureInterface - -import ReactorKit -import RxCocoa -import RxSwift -import SnapKit - -public final class BookmarkMainViewController: BaseViewController, View { - public typealias Reactor = BookmarkMainReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - private let initialIndex: Int - private lazy var currentPageIndex = BehaviorRelay(value: initialIndex) - - private var onBoardingFactory: BookmarkOnBoardingFactory - private let searchFactory: DictionarySearchFactory - private let notificationFactory: DictionaryNotificationFactory - private let loginFactory: LoginFactory - - private var viewControllers: [UIViewController] - - private let mainView: BookmarkMainView - private let underLineController = TabBarUnderlineController() - - public init( - initialIndex: Int = 0, - onBoardingFactory: BookmarkOnBoardingFactory, - bookmarkListFactory: BookmarkListFactory, - collectionListFactory: CollectionListFactory, - searchFactory: DictionarySearchFactory, - notificationFactory: DictionaryNotificationFactory, - loginFactory: LoginFactory, - reactor: BookmarkMainReactor - ) { - let type = reactor.currentState.type - self.mainView = BookmarkMainView(type: type) - self.viewControllers = type.pageTabList.enumerated().map { index, tabType in - if index == 1 { - return collectionListFactory.make() - } else { - return bookmarkListFactory.make(type: tabType, listType: type) - } - } - self.onBoardingFactory = onBoardingFactory - self.searchFactory = searchFactory - self.notificationFactory = notificationFactory - self.loginFactory = loginFactory - self.initialIndex = initialIndex - super.init() - self.reactor = reactor - } - - @available(*, unavailable) - @MainActor required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -public extension BookmarkMainViewController { - override func viewDidLoad() { - super.viewDidLoad() - addViews() - setupConstraints() - configureUI() - setInitialIndex() - } -} - -// MARK: - SetUp -private extension BookmarkMainViewController { - func addViews() { - addChild(mainView.pageViewController) - mainView.pageViewController.didMove(toParent: self) - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } - - func configureUI() { - mainView.pageViewController.delegate = self - mainView.pageViewController.dataSource = self - configureTabCollectionView() - } - - func configureTabCollectionView() { - mainView.tabCollectionView.collectionViewLayout = createTabLayout() - mainView.tabCollectionView.delegate = self - mainView.tabCollectionView.dataSource = self - mainView.tabCollectionView.register(PageTabbarCell.self, forCellWithReuseIdentifier: PageTabbarCell.identifier) - underLineController.configure(with: mainView.tabCollectionView) - } - - func createTabLayout() -> UICollectionViewLayout { - let layout = CompositionalLayoutBuilder() - .section { _ in LayoutFactory.getPageTabbarLayout(underLineController: underLineController) } - .build() - return layout - } - - func setInitialIndex() { - let indexPath = IndexPath(item: initialIndex, section: 0) - - mainView.pageViewController.setViewControllers( - [viewControllers[initialIndex]], - direction: .forward, - animated: false, - completion: nil - ) - - mainView.tabCollectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredHorizontally) - DispatchQueue.main.async { [weak self] in - self?.underLineController.setInitialIndicator() - } - } -} - -// MARK: - Bind -public extension BookmarkMainViewController { - func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .map { _ in Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.headerView.firstIconButton.rx.tap - .map { Reactor.Action.searchButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.headerView.secondIconButton.rx.tap - .map { Reactor.Action.notificationButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.emptyView.button.rx.tap - .map { Reactor.Action.loginButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .subscribe { owner, route in - switch route { - case .search: - let controller = owner.searchFactory.make() - owner.navigationController?.pushViewController(controller, animated: true) - case .notification: - let controller = owner.notificationFactory.make() - owner.navigationController?.pushViewController(controller, animated: true) - case .onBoarding: - let viewController = owner.onBoardingFactory.make() - viewController.modalPresentationStyle = .fullScreen - owner.present(viewController, animated: true) - case .login: - let controller = owner.loginFactory.make(exitRoute: .pop, onLoginCompleted: nil) - owner.navigationController?.pushViewController(controller, animated: true) - default: - break - } - } - .disposed(by: disposeBag) - - reactor.state - .map { $0.isLogin } - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind { owner, isLogin in - owner.mainView.updateLoginState(isLogin: isLogin) - owner.underLineController.setHidden(hidden: !isLogin) - } - .disposed(by: disposeBag) - - } -} - -// MARK: - UIPageViewController DataSource & Delegate -extension BookmarkMainViewController: UIPageViewControllerDataSource, UIPageViewControllerDelegate { - public func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { - guard let index = viewControllers.firstIndex(of: viewController) else { return nil } - let previousIndex = index - 1 - return previousIndex >= 0 ? viewControllers[previousIndex] : nil - } - - public func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { - guard let index = viewControllers.firstIndex(of: viewController) else { return nil } - let nextIndex = index + 1 - return nextIndex < viewControllers.count ? viewControllers[nextIndex] : nil - } - - public func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { - if completed, let visibleViewController = pageViewController.viewControllers?.first, - let newIndex = viewControllers.firstIndex(of: visibleViewController) { - currentPageIndex.accept(newIndex) - mainView.tabCollectionView.selectItem(at: IndexPath(item: newIndex, section: 0), animated: true, scrollPosition: .centeredHorizontally) - underLineController.animateIndicatorToSelectedItem() - } - } -} - -// MARK: - UICollectionView DataSource & Delegate -extension BookmarkMainViewController: UICollectionViewDataSource, UICollectionViewDelegate { - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - guard let reactor = reactor else { return 0 } - return reactor.currentState.sections.count - } - - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let reactor = reactor else { return UICollectionViewCell() } - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PageTabbarCell.identifier, for: indexPath) as? PageTabbarCell else { - return UICollectionViewCell() - } - let title = reactor.currentState.sections[indexPath.row] - cell.inject(title: title) - cell.isSelected = indexPath.row == currentPageIndex.value - return cell - } - - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - let newIndex = indexPath.row - let oldIndex = currentPageIndex.value - - guard newIndex != oldIndex else { return } - - let direction: UIPageViewController.NavigationDirection = newIndex > oldIndex ? .forward : .reverse - - mainView.pageViewController.setViewControllers( - [viewControllers[newIndex]], - direction: direction, - animated: true, - completion: nil - ) - - currentPageIndex.accept(newIndex) - underLineController.animateIndicatorToSelectedItem() - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalFactoryImpl.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalFactoryImpl.swift deleted file mode 100644 index 669604f3..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalFactoryImpl.swift +++ /dev/null @@ -1,30 +0,0 @@ -import BaseFeature -import BookmarkFeatureInterface -import DomainInterface - -public final class BookmarkModalFactoryImpl: BookmarkModalFactory { - private let addCollectionFactory: AddCollectionFactory - private let fetchCollectionListUseCase: FetchCollectionListUseCase - private let addCollectionAndBookmarkUseCase: AddCollectionAndBookmarkUseCase - - public init(addCollectionFactory: AddCollectionFactory, fetchCollectionListUseCase: FetchCollectionListUseCase, addCollectionAndBookmarkUseCase: AddCollectionAndBookmarkUseCase) { - self.addCollectionFactory = addCollectionFactory - self.fetchCollectionListUseCase = fetchCollectionListUseCase - self.addCollectionAndBookmarkUseCase = addCollectionAndBookmarkUseCase - } - - public func make(bookmarkIds: [Int]) -> BaseViewController { - let reactor = BookmarkModalReactor(bookmarkIds: bookmarkIds, fetchCollectionListUseCase: fetchCollectionListUseCase, addCollectionAndBookmarkUseCase: addCollectionAndBookmarkUseCase) - let viewController = BookmarkModalViewController(addCollectionFactory: addCollectionFactory) - viewController.reactor = reactor - return viewController - } - - public func make(bookmarkIds: [Int], onComplete: ((Bool) -> Void)? = nil) -> BaseViewController { - let viewController = make(bookmarkIds: bookmarkIds) - if let viewController = viewController as? BookmarkModalViewController { - viewController.onCompleted = onComplete - } - return viewController - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalReactor.swift deleted file mode 100644 index 88011427..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalReactor.swift +++ /dev/null @@ -1,97 +0,0 @@ -import BookmarkFeatureInterface -import DomainInterface - -import ReactorKit -import RxSwift - -public final class BookmarkModalReactor: Reactor { - public enum Route { - case none - case dismiss - case dismissWithData - case addCollection - case collectionError - } - - public enum Action { - case backButtonTapped - case addButtonTapped - case completeAdding - case addCollectionTapped - case selectItem(Int) - case viewWillAppear - } - - public enum Mutation { - case navigatTo(Route) - case checkCollection([CollectionResponse]) - case setCollection([CollectionResponse]) - } - - public struct State { - @Pulse var route: Route - var bookmarkIds: [Int] - var collections = [CollectionResponse]() - var selectedItems = [CollectionResponse]() - } - - public var initialState: State - - private let disposeBag = DisposeBag() - - private let fetchCollectionListUseCase: FetchCollectionListUseCase - private let addCollectionAndBookmarkUseCase: AddCollectionAndBookmarkUseCase - - public init(bookmarkIds: [Int], fetchCollectionListUseCase: FetchCollectionListUseCase, addCollectionAndBookmarkUseCase: AddCollectionAndBookmarkUseCase) { - self.initialState = State(route: .none, bookmarkIds: bookmarkIds) - self.fetchCollectionListUseCase = fetchCollectionListUseCase - self.addCollectionAndBookmarkUseCase = addCollectionAndBookmarkUseCase - } - - public func mutate(action: Action) -> Observable { - switch action { - case .viewWillAppear, .completeAdding: - return fetchCollectionListUseCase.execute(sort: nil) - .map { .setCollection($0) } - - case .addButtonTapped: - return addCollectionAndBookmarkUseCase - .execute( - collectionIds: currentState.selectedItems.map { $0.collectionId }, - bookmarkIds: currentState.bookmarkIds - ) - .andThen(.just(.navigatTo(.dismissWithData))) - .catch { _ in - .just(.navigatTo(.collectionError)) - } - - case .backButtonTapped: - return .just(.navigatTo(.dismiss)) - - case .addCollectionTapped: - return .just(.navigatTo(.addCollection)) - - case .selectItem(let id): - var newItems = currentState.selectedItems - if let index = newItems.firstIndex(where: { $0.collectionId == id }) { - newItems.remove(at: index) - } else if let collection = currentState.collections.first(where: { $0.collectionId == id }) { - newItems.append(collection) - } - return .just(.checkCollection(newItems)) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - switch mutation { - case .navigatTo(let route): - newState.route = route - case .checkCollection(let collections): - newState.selectedItems = collections - case .setCollection(let collections): - newState.collections = collections - } - return newState - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalView.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalView.swift deleted file mode 100644 index 428e9326..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalView.swift +++ /dev/null @@ -1,104 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -final class BookmarkModalView: UIView { - // MARK: - Type - enum Constant { - static let buttonTopMargin: CGFloat = 12 - static let buttonBottomMargin: CGFloat = 14 - static let horizontalMargin: CGFloat = 16 - static let backButtonSize: CGFloat = 24 - static let titleTopMargin: CGFloat = 20 - static let titleBottomMargin: CGFloat = 12 - } - - // MARK: - Components - private let titleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .h_xl_b, text: "컬렉션", alignment: .left) - return label - }() - - public let backButton: UIButton = { - let button = UIButton() - button.setImage(DesignSystemAsset.image(named: "largeX"), for: .normal) - return button - }() - - public let folderCollectionView: UICollectionView = { - let layout = UICollectionViewLayout() - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) - return collectionView - }() - - private let divider = DividerView() - - public let addButtton = CommonButton(style: .normal, title: "", disabledTitle: "추가하기") - - // MARK: - Init - init() { - super.init(frame: .zero) - addViews() - setupConstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension BookmarkModalView { - func addViews() { - addSubview(titleLabel) - addSubview(backButton) - addSubview(folderCollectionView) - addSubview(addButtton) - addSubview(divider) - } - - func setupConstraints() { - titleLabel.snp.makeConstraints { make in - make.top.equalToSuperview().inset(40) - make.leading.equalToSuperview().inset(Constant.horizontalMargin) - } - - backButton.snp.makeConstraints { make in - make.top.equalTo(titleLabel) - make.leading.equalTo(titleLabel.snp.trailing) - make.trailing.equalToSuperview().inset(Constant.horizontalMargin) - } - - folderCollectionView.snp.makeConstraints { make in - make.top.equalTo(titleLabel.snp.bottom).offset(Constant.titleBottomMargin) - make.horizontalEdges.equalToSuperview() - } - - divider.snp.makeConstraints { make in - make.top.equalTo(folderCollectionView.snp.bottom) - make.horizontalEdges.equalToSuperview() - } - - addButtton.snp.makeConstraints { make in - make.top.equalTo(folderCollectionView.snp.bottom).offset(Constant.buttonTopMargin) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalMargin) - make.bottom.equalToSuperview().inset(Constant.buttonBottomMargin) - } - } -} - -// MARK: - Methods -extension BookmarkModalView { - func setButtonTitle(count: Int) { - if count == 0 { - addButtton.isEnabled = false - } else { - addButtton.isEnabled = true - addButtton.updateTitle(title: "\(count)개의 컬렉션 추가하기") - } - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalViewController.swift deleted file mode 100644 index ce1d4aa3..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkModal/BookmarkModalViewController.swift +++ /dev/null @@ -1,181 +0,0 @@ -import UIKit - -import BaseFeature -import BookmarkFeatureInterface -import DomainInterface - -import ReactorKit -import RxCocoa -import RxSwift -import SnapKit - -public final class BookmarkModalViewController: BaseViewController, View { - public typealias Reactor = BookmarkModalReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - public var onCompleted: ((Bool) -> Void)? - - private let addCollectionFactory: AddCollectionFactory - - // MARK: - Components - private let mainView = BookmarkModalView() - - // MARK: - Init - public init(addCollectionFactory: AddCollectionFactory) { - self.addCollectionFactory = addCollectionFactory - super.init() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // MARK: - Lifecycle - override public func viewDidLoad() { - super.viewDidLoad() - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - Setup -private extension BookmarkModalViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } - - func configureUI() { - mainView.folderCollectionView.collectionViewLayout = createListLayout() - mainView.folderCollectionView.delegate = self - mainView.folderCollectionView.dataSource = self - - mainView.folderCollectionView.register(AddFolderCell.self, forCellWithReuseIdentifier: AddFolderCell.identifier) - mainView.folderCollectionView.register(FolderCell.self, forCellWithReuseIdentifier: FolderCell.identifier) - } - - func createListLayout() -> UICollectionViewLayout { - let layoutFactory = LayoutFactory() - return CompositionalLayoutBuilder() - .section { _ in layoutFactory.getCollectionModalLayout() } - .build() - } -} - -// MARK: - Bind -extension BookmarkModalViewController { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - private func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .map { .viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.backButton.rx.tap - .map { Reactor.Action.backButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.addButtton.rx.tap - .map { Reactor.Action.addButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - private func bindViewState(reactor: Reactor) { - reactor.state - .map(\.collections) - .observe(on: MainScheduler.instance) - .withUnretained(self) - .bind(onNext: { owner, _ in - owner.mainView.folderCollectionView.reloadData() - }) - .disposed(by: disposeBag) - - reactor.state - .map(\.selectedItems) - .observe(on: MainScheduler.instance) - .withUnretained(self) - .bind(onNext: { owner, items in - owner.mainView.setButtonTitle(count: items.count) - }) - .disposed(by: disposeBag) - - rx.viewDidAppear - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe(onNext: { owner, route in - switch route { - case .dismissWithData: - owner.onCompleted?(true) - owner.dismiss(animated: true) - case .dismiss: - owner.onCompleted?(false) - owner.dismiss(animated: true) - case .addCollection: - let viewController = owner.addCollectionFactory.make(collection: nil) - - guard let viewController = viewController as? AddCollectionViewController else { return } - - viewController.dismissed - .withUnretained(self) - .subscribe { owner, _ in - owner.reactor?.action.onNext(.completeAdding) - } - .disposed(by: owner.disposeBag) - - owner.present(viewController, animated: true) - case .collectionError: - ToastFactory.createToast(message: "컬렉션 저장에 실패했어요. 다시 시도해주세요.") - default: - break - } - }) - .disposed(by: disposeBag) - } -} - -// MARK: - UICollectionView Delegate -extension BookmarkModalViewController: UICollectionViewDelegate, UICollectionViewDataSource { - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - (reactor?.currentState.collections.count ?? 0) + 1 - } - - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - if indexPath.row == 0 { - return collectionView.dequeueReusableCell(withReuseIdentifier: AddFolderCell.identifier, for: indexPath) as? AddFolderCell ?? UICollectionViewCell() - } else { - guard let reactor = reactor else { return UICollectionViewCell() } - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: FolderCell.identifier, for: indexPath) as? FolderCell else { - return UICollectionViewCell() - } - let collection = reactor.currentState.collections[indexPath.row - 1] - let isSelected = reactor.currentState.selectedItems.contains(where: { $0.collectionId == collection.collectionId }) - cell.isChecked = isSelected - cell.inject(title: collection.name) - return cell - } - } - - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - if indexPath.row == 0 { - reactor?.action.onNext(.addCollectionTapped) - } else { - guard let collection = reactor?.currentState.collections[indexPath.row - 1] else { return } - reactor?.action.onNext(.selectItem(collection.collectionId)) - } - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkOnBoarding/BookmarkOnBoardingFactoryImpl.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkOnBoarding/BookmarkOnBoardingFactoryImpl.swift deleted file mode 100644 index 6d40fae3..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkOnBoarding/BookmarkOnBoardingFactoryImpl.swift +++ /dev/null @@ -1,13 +0,0 @@ -import BaseFeature -import BookmarkFeatureInterface - -public final class BookmarkOnBoardingFactoryImpl: BookmarkOnBoardingFactory { - public init() {} - - public func make() -> BaseViewController { - let reactor = BookmarkOnBoardingReactor() - let viewController = BookmarkOnBoardingViewController() - viewController.reactor = reactor - return viewController - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkOnBoarding/BookmarkOnBoardingReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkOnBoarding/BookmarkOnBoardingReactor.swift deleted file mode 100644 index 76639b60..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkOnBoarding/BookmarkOnBoardingReactor.swift +++ /dev/null @@ -1,58 +0,0 @@ -import ReactorKit - -public final class BookmarkOnBoardingReactor: Reactor { - public enum Route { - case none - case dismiss - } - - public enum Action { - case nextButtonTapped - case backButtonTapped - } - - public enum Mutation { - case setStep(BookmarkOnBoardingView.OnBoardingIndexType) - case dismiss - } - - public struct State { - @Pulse var route: Route = .none - var step: BookmarkOnBoardingView.OnBoardingIndexType = .first - } - - public var initialState: State - - private let disposeBag = DisposeBag() - - public init() { - self.initialState = State() - } - - public func mutate(action: Action) -> Observable { - switch action { - case .nextButtonTapped: - let next = currentState.step.next() - if next == .end { - return .just(.dismiss) - } else { - return .just(.setStep(next)) - } - - case .backButtonTapped: - let prev = currentState.step.previous() - return .just(.setStep(prev)) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - switch mutation { - case .setStep(let step): - newState.step = step - case .dismiss: - newState.route = .dismiss - } - return newState - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkOnBoarding/BookmarkOnBoardingView.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkOnBoarding/BookmarkOnBoardingView.swift deleted file mode 100644 index 44fa7c75..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkOnBoarding/BookmarkOnBoardingView.swift +++ /dev/null @@ -1,159 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -public final class BookmarkOnBoardingView: UIView { - // MARK: - Type - public enum OnBoardingIndexType: Int { - case first = 0 - case second - case end - - var content: OnboardingContent? { - switch self { - case .first: - return .init( - imageName: "onBoardingBookmark", - title: "내가 찜한 정보, 한곳에!", - description: "아이템, 몬스터, 맵, NPC, 퀘스트를\n북마크하면 자동으로 여기에 모여요.", - isBackButtonHidden: true, - buttonTitle: "다음" - ) - case .second: - return .init( - imageName: "addToCollection", - title: "나만의 컬렉션 만들기", - description: "북마크한 정보들을 폴더로 정리해보세요.", - isBackButtonHidden: false, - buttonTitle: "북마크 열기" - ) - default: - return nil - } - } - - func next() -> Self { - switch self { - case .first: return .second - case .second: return .end - case .end: return .end - } - } - - func previous() -> Self { - switch self { - case .first: return .first - case .second: return .first - case .end: return .second - } - } - } - - struct OnboardingContent { - let imageName: String - let title: String - let description: String - let isBackButtonHidden: Bool - let buttonTitle: String - } - - enum Constant { - static let imageSize: CGFloat = 220 - static let imageSpacing: CGFloat = 4 - static let labelSpacing: CGFloat = 16 - static let indicatorSpacing: CGFloat = 29 - static let bottomInset: CGFloat = 16 - static let horizontalMargin: CGFloat = 16 - static let backButtonTrailing: CGFloat = -28 - static let backButtonBottom: CGFloat = 10 - static let backButtonSize: CGFloat = 24 - static let imageYOffset: CGFloat = -116 - } - - // MARK: - Components - private let imageView = UIImageView() - private let titleLabel = UILabel() - private let descLabel = UILabel() - - public let backButton: UIButton = { - let button = UIButton() - button.setImage(DesignSystemAsset.image(named: "arrowBack"), for: .normal) - return button - }() - - private let stepIndicator = StepIndicator(circleCount: 2) - - public let nextButton = CommonButton(style: .normal, title: "다음", disabledTitle: nil) - - // MARK: - Init - init() { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI(type: .first) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension BookmarkOnBoardingView { - func addViews() { - addSubview(imageView) - addSubview(titleLabel) - addSubview(descLabel) - addSubview(backButton) - addSubview(stepIndicator) - addSubview(nextButton) - } - - func setupConstraints() { - imageView.snp.makeConstraints { make in - make.centerX.equalToSuperview() - make.centerY.equalToSuperview().offset(Constant.imageYOffset) - make.size.equalTo(Constant.imageSize) - } - - titleLabel.snp.makeConstraints { make in - make.top.equalTo(imageView.snp.bottom).offset(Constant.imageSpacing) - make.centerX.equalToSuperview() - } - - descLabel.snp.makeConstraints { make in - make.top.equalTo(titleLabel.snp.bottom).offset(Constant.labelSpacing) - make.centerX.equalToSuperview() - } - - backButton.snp.makeConstraints { make in - make.trailing.equalTo(imageView.snp.leading).inset(Constant.backButtonTrailing) - make.bottom.equalTo(imageView.snp.bottom).inset(Constant.backButtonBottom) - } - - stepIndicator.snp.makeConstraints { make in - make.top.equalTo(descLabel.snp.bottom).offset(Constant.indicatorSpacing) - make.centerX.equalToSuperview() - } - - nextButton.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalMargin) - make.bottom.equalToSuperview().inset(Constant.bottomInset) - } - } -} - -public extension BookmarkOnBoardingView { - func configureUI(type: OnBoardingIndexType) { - guard let content = type.content else { return } - imageView.image = DesignSystemAsset.image(named: content.imageName) - titleLabel.attributedText = .makeStyledString(font: .h_xxxl_b, text: content.title) - descLabel.attributedText = .makeStyledString(font: .b_m_r, text: content.description, color: .neutral700) - nextButton.updateTitle(title: content.buttonTitle) - backButton.isHidden = content.isBackButtonHidden - stepIndicator.selectIndicator(index: type.rawValue) - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkOnBoarding/BookmarkOnBoardingViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkOnBoarding/BookmarkOnBoardingViewController.swift deleted file mode 100644 index 101c9aad..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/BookmarkOnBoarding/BookmarkOnBoardingViewController.swift +++ /dev/null @@ -1,97 +0,0 @@ -import UIKit - -import BaseFeature - -import ReactorKit -import RxCocoa -import RxSwift -import SnapKit - -public final class BookmarkOnBoardingViewController: BaseViewController, View { - public typealias Reactor = BookmarkOnBoardingReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - // MARK: - Components - private let mainView = BookmarkOnBoardingView() - - // MARK: - Init - override public init() { - super.init() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // MARK: - Lifecycle - override public func viewDidLoad() { - super.viewDidLoad() - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - Setup -private extension BookmarkOnBoardingViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } - - func configureUI() {} -} - -// MARK: - Bind -extension BookmarkOnBoardingViewController { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - private func bindUserActions(reactor: Reactor) { - mainView.backButton.rx.tap - .map { Reactor.Action.backButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.nextButton.rx.tap - .map { Reactor.Action.nextButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - private func bindViewState(reactor: Reactor) { - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .subscribe(onNext: { owner, route in - switch route { - case .dismiss: - owner.dismiss(animated: true) - default: - break - } - }) - .disposed(by: disposeBag) - - reactor.state - .map(\.step) - .distinctUntilChanged() - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind(onNext: { owner, step in - owner.mainView.configureUI(type: step) - }) - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailEmptyView.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailEmptyView.swift deleted file mode 100644 index 15387f47..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailEmptyView.swift +++ /dev/null @@ -1,87 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -final class CollectionDetailEmptyView: UIView { - // MARK: - Type - enum Constant { - static let imageSize: CGFloat = 220 - static let textSpacing: CGFloat = 10 - static let buttonSpacing: CGFloat = 24 - static let buttonWidth: CGFloat = 186 - } - - // MARK: - Components - public let imageView: UIImageView = { - let view = UIImageView() - view.image = DesignSystemAsset.image(named: "connectionError") - return view - }() - - private let mainLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .h_xl_b, text: "아직 아무것도 없어요!", color: .textColor) - return label - }() - - private let subLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .b_s_r, text: "북마크해서 추가해보세요.", color: .neutral600) - label.numberOfLines = 2 - return label - }() - - public let bookmarkButton = CommonButton(style: .normal, title: "북마크하러 가기", disabledTitle: nil) - - // MARK: - Init - init() { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension CollectionDetailEmptyView { - func addViews() { - addSubview(imageView) - addSubview(mainLabel) - addSubview(subLabel) - addSubview(bookmarkButton) - } - - func setupConstraints() { - imageView.snp.makeConstraints { make in - make.centerX.equalToSuperview() - make.size.equalTo(Constant.imageSize) - } - - mainLabel.snp.makeConstraints { make in - make.top.equalTo(imageView.snp.bottom) - make.center.equalToSuperview() - } - - subLabel.snp.makeConstraints { make in - make.top.equalTo(mainLabel.snp.bottom).offset(Constant.textSpacing) - make.centerX.equalToSuperview() - } - - bookmarkButton.snp.makeConstraints { make in - make.top.equalTo(subLabel.snp.bottom).offset(Constant.buttonSpacing) - make.width.equalTo(Constant.buttonWidth) - make.centerX.equalToSuperview() - } - } - - func configureUI() { - backgroundColor = .clearMLS - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailFactoryImpl.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailFactoryImpl.swift deleted file mode 100644 index 83341f3f..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailFactoryImpl.swift +++ /dev/null @@ -1,77 +0,0 @@ -import BaseFeature -import BookmarkFeatureInterface -import DesignSystem -import DictionaryFeatureInterface -import DomainInterface - -import RxSwift - -public final class CollectionDetailFactoryImpl: CollectionDetailFactory { - private let bookmarkModalFactory: BookmarkModalFactory - private let collectionSettingFactory: CollectionSettingFactory - private let addCollectionFactory: AddCollectionFactory - private let collectionEditFactory: CollectionEditFactory - private let dictionaryDetailFactory: DictionaryDetailFactory - - private let setBookmarkUseCase: SetBookmarkUseCase - private let fetchCollectionUseCase: FetchCollectionUseCase - private let deleteCollectionUseCase: DeleteCollectionUseCase - private let addCollectionAndBookmarkUseCase: AddCollectionAndBookmarkUseCase - - public init( - bookmarkModalFactory: BookmarkModalFactory, - collectionSettingFactory: CollectionSettingFactory, - addCollectionFactory: AddCollectionFactory, - collectionEditFactory: CollectionEditFactory, - dictionaryDetailFactory: DictionaryDetailFactory, - setBookmarkUseCase: SetBookmarkUseCase, - fetchCollectionUseCase: FetchCollectionUseCase, - deleteCollectionUseCase: DeleteCollectionUseCase, - addCollectionAndBookmarkUseCase: AddCollectionAndBookmarkUseCase - ) { - self.bookmarkModalFactory = bookmarkModalFactory - self.collectionSettingFactory = collectionSettingFactory - self.addCollectionFactory = addCollectionFactory - self.collectionEditFactory = collectionEditFactory - self.dictionaryDetailFactory = dictionaryDetailFactory - self.setBookmarkUseCase = setBookmarkUseCase - self.fetchCollectionUseCase = fetchCollectionUseCase - self.deleteCollectionUseCase = deleteCollectionUseCase - self.addCollectionAndBookmarkUseCase = addCollectionAndBookmarkUseCase - } - - public func make(collection: CollectionResponse, onMoveToMain: (() -> Void)?) -> BaseViewController { - let reactor = CollectionDetailReactor( - collection: collection, - setBookmarkUseCase: setBookmarkUseCase, - fetchCollectionUseCase: fetchCollectionUseCase, - deleteCollectionUseCase: deleteCollectionUseCase, - addCollectionAndBookmarkUseCase: addCollectionAndBookmarkUseCase - ) - - let viewController = CollectionDetailViewController( - reactor: reactor, - bookmarkModalFactory: bookmarkModalFactory, - collectionSettingFactory: collectionSettingFactory, - addCollectionFactory: addCollectionFactory, - collectionEditFactory: collectionEditFactory, - dictionaryDetailFactory: dictionaryDetailFactory - ) - - reactor.pulse(\.$route) - .compactMap { $0 } - .observe(on: MainScheduler.instance) - .bind(onNext: { [weak viewController] route in - switch route { - case .toMain: - onMoveToMain?() - viewController?.navigationController?.popToRootViewController(animated: true) - default: - break - } - }) - .disposed(by: viewController.disposeBag) - - return viewController - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailReactor.swift deleted file mode 100644 index 5dd270c7..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailReactor.swift +++ /dev/null @@ -1,113 +0,0 @@ -import BookmarkFeatureInterface -import DomainInterface - -import ReactorKit - -public final class CollectionDetailReactor: Reactor { - public enum Route { - case none - case toMain - case dismiss - case edit - case detail(DictionaryType, Int) - } - - public enum Action { - case viewWillAppear - case backButtonTapped - case editButtonTapped - case addButtonTapped - case bookmarkButtonTapped - case selectSetting(CollectionSettingMenu) - case changeName(String) - case dataTapped(Int) - case deleteCollection - } - - public enum Mutation { - case navigateTo(Route) - case setItems([BookmarkResponse]) - case setMenu(CollectionSettingMenu) - case setName(String) - case setLastDeletedBookmark(BookmarkResponse?) - } - - public struct State { - @Pulse var route: Route - @Pulse var collectionMenu: CollectionSettingMenu? - var sections: [String] { - return type.pageTabList.map { $0.title } - } - let type = DictionaryMainViewType.bookmark - var collection: CollectionResponse - var lastDeletedBookmark: BookmarkResponse? - } - - // MARK: - Properties - private let setBookmarkUseCase: SetBookmarkUseCase - private let fetchCollectionUseCase: FetchCollectionUseCase - private let deleteCollectionUseCase: DeleteCollectionUseCase - private let addCollectionAndBookmarkUseCase: AddCollectionAndBookmarkUseCase - - public var initialState: State - - private let disposeBag = DisposeBag() - - public init( - collection: CollectionResponse, - setBookmarkUseCase: SetBookmarkUseCase, - fetchCollectionUseCase: FetchCollectionUseCase, - deleteCollectionUseCase: DeleteCollectionUseCase, - addCollectionAndBookmarkUseCase: AddCollectionAndBookmarkUseCase - ) { - self.initialState = State(route: .none, collection: collection) - self.setBookmarkUseCase = setBookmarkUseCase - self.fetchCollectionUseCase = fetchCollectionUseCase - self.deleteCollectionUseCase = deleteCollectionUseCase - self.addCollectionAndBookmarkUseCase = addCollectionAndBookmarkUseCase - } - - public func mutate(action: Action) -> Observable { - switch action { - case .backButtonTapped: - return .just(.navigateTo(.dismiss)) - case .editButtonTapped: - return .just(.navigateTo(.edit)) - case .viewWillAppear: - return fetchCollectionUseCase.execute(id: currentState.collection.collectionId) - .map { .setItems($0) } - case .addButtonTapped: - return .just(.navigateTo(.toMain)) - case .bookmarkButtonTapped: - return .just(.navigateTo(.toMain)) - case .selectSetting(let menu): - return .just(.setMenu(menu)) - case .changeName(let name): - return .just(.setName(name)) - case .dataTapped(let index): - let item = currentState.collection.recentBookmarks[index] - guard let type = item.type.toDictionaryType else { return .empty() } - return .just(.navigateTo(.detail(type, item.originalId))) - case .deleteCollection: - return deleteCollectionUseCase.execute(collectionId: currentState.collection.collectionId) - .andThen(.just(.navigateTo(.dismiss))) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - switch mutation { - case .setItems(let items): - newState.collection.recentBookmarks = items - case .navigateTo(let route): - newState.route = route - case .setMenu(let menu): - newState.collectionMenu = menu - case .setName(let name): - newState.collection.name = name - case .setLastDeletedBookmark(let bookmark): - newState.lastDeletedBookmark = bookmark - } - return newState - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailView.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailView.swift deleted file mode 100644 index 655275dc..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailView.swift +++ /dev/null @@ -1,101 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -final class CollectionDetailView: UIView { - // MARK: - Type - enum Constant { - static let topMargin: CGFloat = 12 - static let collectionViewMargin: CGFloat = 24 - } - - // MARK: - Components - public let navigation: NavigationBar - - public let spacer: UIView = { - let view = UIView() - view.backgroundColor = .whiteMLS - return view - }() - - public let listCollectionView: UICollectionView = { - let layout = UICollectionViewLayout() - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) - return collectionView - }() - - public let emptyContainerView = UIView() - public let emptyView = CollectionDetailEmptyView() - - // MARK: - Init - init(navTitle: String) { - self.navigation = NavigationBar(type: .collection(navTitle)) - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension CollectionDetailView { - func addViews() { - addSubview(navigation) - addSubview(spacer) - addSubview(listCollectionView) - addSubview(emptyContainerView) - emptyContainerView.addSubview(emptyView) - } - - func setupConstraints() { - navigation.snp.makeConstraints { make in - make.top.horizontalEdges.equalTo(safeAreaLayoutGuide) - } - - spacer.snp.makeConstraints { make in - make.top.equalTo(navigation.snp.bottom) - make.horizontalEdges.equalToSuperview() - make.height.equalTo(Constant.topMargin) - } - - listCollectionView.snp.makeConstraints { make in - make.top.equalTo(spacer.snp.bottom).offset(Constant.collectionViewMargin) - make.horizontalEdges.bottom.equalToSuperview() - } - - emptyContainerView.snp.makeConstraints { make in - make.top.equalTo(navigation.snp.bottom).offset(Constant.collectionViewMargin) - make.horizontalEdges.bottom.equalTo(safeAreaLayoutGuide) - } - - emptyView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } - - func configureUI() { - navigation.backgroundColor = .whiteMLS - backgroundColor = .neutral100 - emptyContainerView.backgroundColor = .neutral100 - listCollectionView.backgroundColor = .neutral100 - } -} - -// MARK: - Methods -extension CollectionDetailView { - func isEmptyData(isEmpty: Bool) { - listCollectionView.isHidden = isEmpty - emptyContainerView.isHidden = !isEmpty - } - - func setName(name: String) { - navigation.setTitle(title: name) - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift deleted file mode 100644 index 9c11aa03..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionDetail/CollectionDetailViewController.swift +++ /dev/null @@ -1,248 +0,0 @@ -import UIKit - -import BaseFeature -import BookmarkFeatureInterface -import DictionaryFeatureInterface - -import ReactorKit -import RxCocoa -import RxSwift - -public final class CollectionDetailViewController: BaseViewController, View { - public var modalHeight: CGFloat? - - public typealias Reactor = CollectionDetailReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - private let bookmarkModalFactory: BookmarkModalFactory - private let collectionSettingFactory: CollectionSettingFactory - private let addCollectionFactory: AddCollectionFactory - private let collectionEditFactory: CollectionEditFactory - private let dictionaryDetailFactory: DictionaryDetailFactory - - private var selectedSortIndex = 0 - - // MARK: - Components - private var mainView: CollectionDetailView - - public init( - reactor: CollectionDetailReactor, - bookmarkModalFactory: BookmarkModalFactory, - collectionSettingFactory: CollectionSettingFactory, - addCollectionFactory: AddCollectionFactory, - collectionEditFactory: CollectionEditFactory, - dictionaryDetailFactory: DictionaryDetailFactory - ) { - self.mainView = CollectionDetailView(navTitle: reactor.currentState.collection.name) - self.bookmarkModalFactory = bookmarkModalFactory - self.collectionSettingFactory = collectionSettingFactory - self.addCollectionFactory = addCollectionFactory - self.collectionEditFactory = collectionEditFactory - self.dictionaryDetailFactory = dictionaryDetailFactory - super.init() - self.reactor = reactor - navigationController?.navigationBar.isHidden = true - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override public func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension CollectionDetailViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide) - make.horizontalEdges.bottom.equalToSuperview() - } - } - - func configureUI() { - mainView.listCollectionView.collectionViewLayout = createListLayout() - mainView.listCollectionView.delegate = self - mainView.listCollectionView.dataSource = self - mainView.listCollectionView.register(DictionaryListCell.self, forCellWithReuseIdentifier: DictionaryListCell.identifier) - } - - func createListLayout() -> UICollectionViewLayout { - let layoutFactory = LayoutFactory() - let layout = CompositionalLayoutBuilder() - .section { _ in layoutFactory.getDictionaryListLayout() } - .build() - layout.register(Neutral300DividerView.self, forDecorationViewOfKind: Neutral300DividerView.identifier) - return layout - } -} - -// MARK: - Bind -extension CollectionDetailViewController { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .map { _ in Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.emptyView.bookmarkButton.rx.tap - .map { Reactor.Action.bookmarkButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.navigation.leftButton.rx.tap - .map { Reactor.Action.backButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.navigation.editButton.rx.tap - .map { Reactor.Action.editButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.navigation.addButton.rx.tap - .map { Reactor.Action.addButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - reactor.state - .map(\.collection.recentBookmarks) - .distinctUntilChanged() - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind(onNext: { owner, items in - owner.mainView.listCollectionView.reloadData() - owner.mainView.isEmptyData(isEmpty: items.isEmpty) - }) - .disposed(by: disposeBag) - - reactor.state - .map(\.collection.name) - .distinctUntilChanged() - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind(onNext: { owner, name in - owner.mainView.setName(name: name) - }) - .disposed(by: disposeBag) - - reactor.pulse(\.$collectionMenu) - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind(onNext: { owner, menu in - switch menu { - case .editBookmark: - let viewController = owner.collectionEditFactory.make(bookmarks: reactor.currentState.collection.recentBookmarks) - owner.navigationController?.pushViewController(viewController, animated: true) - case .editName: - let viewController = owner.addCollectionFactory.make(collection: reactor.currentState.collection) - - guard let viewController = viewController as? AddCollectionViewController else { return } - - viewController.dismissed - .subscribe { name in - reactor.action.onNext(.changeName(name)) - } - .disposed(by: owner.disposeBag) - - owner.present(viewController, animated: true) - case .delete: - GuideAlertFactory.show( - mainText: "컬렉션을 삭제하시겠어요?", - ctaText: "삭제하기", - cancelText: "취소", - ctaAction: { - reactor.action.onNext(.deleteCollection) - }, - cancelAction: {} - ) - default: - break - } - }) - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, route in - switch route { - case .dismiss: - owner.navigationController?.popViewController(animated: true) - case .edit: - let viewController = owner.collectionSettingFactory.make(setEditMenu: { menu in - owner.reactor?.action.onNext(.selectSetting(menu)) - }) - owner.presentModal(viewController) - case .detail(let type, let id): - let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: nil, loginRelay: nil) - owner.navigationController?.pushViewController(viewController, animated: true) - default: - break - } - } - .disposed(by: disposeBag) - } -} - -// MARK: - Delegate -extension CollectionDetailViewController: UICollectionViewDelegate, UICollectionViewDataSource { - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - reactor?.currentState.collection.recentBookmarks.count ?? 0 - } - - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard - let cell = collectionView.dequeueReusableCell( - withReuseIdentifier: DictionaryListCell.identifier, - for: indexPath - ) as? DictionaryListCell, - let item = reactor?.currentState.collection.recentBookmarks[indexPath.row] - else { - return UICollectionViewCell() - } - var subText: String? { - [.item, .monster, .quest].contains(item.type) ? item.level.map { "Lv. \($0)" } : nil - } - cell.inject( - type: .bookmark, - input: DictionaryListCell.Input( - type: item.type, - mainText: item.name, - subText: subText, - imageUrl: item.imageUrl ?? "", - isBookmarked: true - ), - indexPath: indexPath, - collectionView: collectionView, - onBookmarkTapped: { } - ) - return cell - } - - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - reactor?.action.onNext(.dataTapped(indexPath.row)) - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditFactoryImpl.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditFactoryImpl.swift deleted file mode 100644 index 02533220..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditFactoryImpl.swift +++ /dev/null @@ -1,21 +0,0 @@ -import BaseFeature -import BookmarkFeatureInterface -import DomainInterface - -public final class CollectionEditFactoryImpl: CollectionEditFactory { - private let setBookmarkUseCase: SetBookmarkUseCase - private let bookmarkModalFactory: BookmarkModalFactory - - public init(setBookmarkUseCase: SetBookmarkUseCase, bookmarkModalFactory: BookmarkModalFactory) { - self.setBookmarkUseCase = setBookmarkUseCase - self.bookmarkModalFactory = bookmarkModalFactory - } - - public func make(bookmarks: [BookmarkResponse]) -> BaseViewController { - let reactor = CollectionEditReactor(bookmarks: bookmarks) - let viewController = CollectionEditViewController(bookmarkModalFactory: bookmarkModalFactory) - viewController.reactor = reactor - viewController.isBottomTabbarHidden = true - return viewController - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditReactor.swift deleted file mode 100644 index c9616086..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditReactor.swift +++ /dev/null @@ -1,73 +0,0 @@ -import UIKit - -import BookmarkFeatureInterface -import DomainInterface - -import ReactorKit - -public final class CollectionEditReactor: Reactor { - public enum Route { - case none - case dismiss - case collcectionList - } - - public enum Action { - case backButtonTapped - case addCollectionButtonTapped - case itemTapped(Int) - } - - public enum Mutation { - case navigateTo(Route) - case checkBookMarks([BookmarkResponse]) - case checkCollections([CollectionResponse]) - } - - public struct State { - @Pulse var route: Route - var bookmarks: [BookmarkResponse] - var selectedItems = [BookmarkResponse]() - var selectedCollections = [CollectionResponse]() - } - - // MARK: - Properties - public var initialState: State - - private let disposeBag = DisposeBag() - - public init(bookmarks: [BookmarkResponse]) { - self.initialState = State(route: .none, bookmarks: bookmarks) - } - - public func mutate(action: Action) -> Observable { - switch action { - case .backButtonTapped: - return .just(.navigateTo(.dismiss)) - case .addCollectionButtonTapped: - return .just(.navigateTo(.collcectionList)) - case .itemTapped(let index): - let item = currentState.bookmarks[index] - var newItems = currentState.selectedItems - if let index = newItems.firstIndex(where: { $0.originalId == item.originalId }) { - newItems.remove(at: index) - } else { - newItems.append(item) - } - return .just(.checkBookMarks(newItems)) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - switch mutation { - case .navigateTo(let route): - newState.route = route - case .checkBookMarks(let bookmarks): - newState.selectedItems = bookmarks - case .checkCollections(let collections): - newState.selectedCollections = collections - } - return newState - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditView.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditView.swift deleted file mode 100644 index 878c03e4..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditView.swift +++ /dev/null @@ -1,110 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -final class CollectionEditView: UIView { - // MARK: - Type - enum Constant { - static let imageViewSize: CGFloat = 44 - static let iconSize: CGFloat = 24 - static let horizontalMargin: CGFloat = 16 - static let topMargin: CGFloat = 12 - static let bottomMargin: CGFloat = 14 - } - - // MARK: - Components - private lazy var imageView: UIView = { - let view = UIView() - - view.addSubview(cancelButton) - - cancelButton.snp.makeConstraints { make in - make.center.equalToSuperview() - make.size.equalTo(Constant.iconSize) - } - - return view - }() - - public let cancelButton: UIButton = { - let button = UIButton() - button.setImage(DesignSystemAsset.image(named: "largeX"), for: .normal) - return button - }() - - private let titleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .korFont(style: .semiBold, size: 16), text: "리스트 편집") - return label - }() - - public let listCollectionView: UICollectionView = { - let layout = UICollectionViewLayout() - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) - return collectionView - }() - - private let divider = DividerView() - - public let addButtton = CommonButton(style: .normal, title: "컬렉션에 추가하기", disabledTitle: nil) - - // MARK: - Init - init() { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension CollectionEditView { - func addViews() { - addSubview(imageView) - addSubview(titleLabel) - addSubview(listCollectionView) - addSubview(divider) - addSubview(addButtton) - } - - func setupConstraints() { - imageView.snp.makeConstraints { make in - make.top.equalTo(safeAreaLayoutGuide) - make.leading.equalToSuperview() - make.size.equalTo(Constant.imageViewSize) - } - - titleLabel.snp.makeConstraints { make in - make.centerX.equalToSuperview() - make.centerY.equalTo(imageView) - } - - listCollectionView.snp.makeConstraints { make in - make.top.equalTo(imageView.snp.bottom) - make.horizontalEdges.equalToSuperview() - } - - divider.snp.makeConstraints { make in - make.top.equalTo(listCollectionView.snp.bottom) - make.horizontalEdges.equalToSuperview() - } - - addButtton.snp.makeConstraints { make in - make.top.equalTo(divider.snp.bottom).offset(Constant.topMargin) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalMargin) - make.bottom.equalToSuperview().inset(Constant.bottomMargin) - } - } - - func configureUI() { - backgroundColor = .whiteMLS - listCollectionView.backgroundColor = .neutral100 - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditViewController.swift deleted file mode 100644 index af476175..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionEdit/CollectionEditViewController.swift +++ /dev/null @@ -1,186 +0,0 @@ -import UIKit - -import BaseFeature -import BookmarkFeatureInterface - -import ReactorKit -import RxCocoa -import RxSwift - -public final class CollectionEditViewController: BaseViewController, View { - public typealias Reactor = CollectionEditReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - private let bookmarkModalFactory: BookmarkModalFactory - - // MARK: - Components - private var mainView = CollectionEditView() - - public init(bookmarkModalFactory: BookmarkModalFactory) { - self.bookmarkModalFactory = bookmarkModalFactory - super.init() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override public func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension CollectionEditViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } - - func configureUI() { - mainView.listCollectionView.collectionViewLayout = createListLayout() - mainView.listCollectionView.delegate = self - mainView.listCollectionView.dataSource = self - mainView.listCollectionView.register(DictionaryListCell.self, forCellWithReuseIdentifier: DictionaryListCell.identifier) - } - - func createListLayout() -> UICollectionViewLayout { - let layoutFactory = LayoutFactory() - let layout = CompositionalLayoutBuilder() - .section { _ in layoutFactory.getCollectionListEditLayout() } - .build() - return layout - } -} - -// MARK: - Bind -extension CollectionEditViewController { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - mainView.cancelButton.rx.tap - .map { Reactor.Action.backButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.addButtton.rx.tap - .map { Reactor.Action.addCollectionButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .subscribe { _, route in - switch route { - default: - break - } - } - .disposed(by: disposeBag) - - reactor.state - .map(\.bookmarks) - .distinctUntilChanged() - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, _ in - owner.mainView.listCollectionView.reloadData() - } - .disposed(by: disposeBag) - - reactor.state - .map(\.selectedItems) - .distinctUntilChanged() - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, _ in - owner.mainView.listCollectionView.reloadData() - } - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, route in - switch route { - case .dismiss: - owner.navigationController?.popViewController(animated: true) - case .collcectionList: - let viewController = owner.bookmarkModalFactory.make(bookmarkIds: reactor.currentState.selectedItems.map { $0.bookmarkId }) { isSave in - if isSave { - owner.navigationController?.popToRootViewController(animated: true) - } - } - owner.present(viewController, animated: true) - default: - break - } - } - .disposed(by: disposeBag) - } -} - -// MARK: - Delegate -extension CollectionEditViewController: UICollectionViewDelegate, UICollectionViewDataSource { - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - reactor?.currentState.bookmarks.count ?? 0 - } - - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard - let cell = collectionView.dequeueReusableCell( - withReuseIdentifier: DictionaryListCell.identifier, - for: indexPath - ) as? DictionaryListCell, - let item = reactor?.currentState.bookmarks[indexPath.row] - else { - return UICollectionViewCell() - } - let isSelected = reactor?.currentState.selectedItems.contains(where: { $0.originalId == item.originalId }) ?? false - var subText: String? { - [.item, .monster, .quest].contains(item.type) ? item.level.map { "Lv. \($0)" } : nil - } - - cell.inject( - type: .checkbox, - input: DictionaryListCell.Input( - type: item.type, - mainText: item.name, - subText: subText, - imageUrl: item.imageUrl ?? "", - isBookmarked: isSelected - ), - indexPath: indexPath, - collectionView: collectionView, - onBookmarkTapped: { [weak self] in - self?.reactor?.action.onNext(.itemTapped(indexPath.row)) - } - ) - return cell - } - - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - reactor?.action.onNext(.itemTapped(indexPath.row)) - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListCell.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListCell.swift deleted file mode 100644 index 6a19c9cd..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListCell.swift +++ /dev/null @@ -1,79 +0,0 @@ -import BaseFeature -import UIKit - -import DesignSystem - -public final class CollectionListCell: UICollectionViewCell { - // MARK: - Properties - - // MARK: - Components - public let cellView = CollectionList() - - // MARK: - init - override init(frame: CGRect) { - super.init(frame: frame) - - addViews() - setupContstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension CollectionListCell { - func addViews() { - contentView.addSubview(cellView) - } - - func setupContstraints() { - cellView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } -} - -public extension CollectionListCell { - struct Input { - let title: String - let count: Int - let images: [String?] - - public init(title: String, count: Int, images: [String?]) { - self.title = title - self.count = count - self.images = images - } - } - - func inject(input: Input) { - loadImages(from: input.images) { [weak self] images in - print("이미지:\(images)") - self?.cellView.setImages(images: images) - } - cellView.setTitle(text: input.title) - cellView.setSubtitle(text: "\(String(input.count))개") - } -} - -private func loadImages(from urls: [String?], completion: @escaping ([UIImage?]) -> Void) { - - var results = [UIImage?](repeating: nil, count: urls.count) - let dispatchGroup = DispatchGroup() - - for (index, urlString) in urls.enumerated() { - dispatchGroup.enter() - - ImageLoader.shared.loadImage(stringURL: urlString) { image in - results[index] = image - dispatchGroup.leave() - } - } - - dispatchGroup.notify(queue: .main) { - completion(results) - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListEmptyView.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListEmptyView.swift deleted file mode 100644 index e50a1ee4..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListEmptyView.swift +++ /dev/null @@ -1,78 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -final class CollectionListEmptyView: UIView { - // MARK: - Type - enum Constant { - static let topInset: CGFloat = 60 - static let imageSize: CGFloat = 220 - static let textSpacing: CGFloat = 10 - } - - // MARK: - Components - public let imageView: UIImageView = { - let view = UIImageView() - view.image = DesignSystemAsset.image(named: "fabHint") - return view - }() - - private let mainLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .h_xl_b, text: "첫 컬렉션을 만들어보세요", color: .textColor) - return label - }() - - private let subLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .cp_s_r, text: "컬렉션을 만들면 북마크한 리스트틀\n내 취향대로 정리할 수 있어요.", color: .neutral600) - label.numberOfLines = 2 - return label - }() - - // MARK: - Init - init() { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension CollectionListEmptyView { - func addViews() { - addSubview(imageView) - addSubview(mainLabel) - addSubview(subLabel) - } - - func setupConstraints() { - imageView.snp.makeConstraints { make in - make.top.equalToSuperview().inset(Constant.topInset) - make.centerX.equalToSuperview() - make.size.equalTo(Constant.imageSize) - } - - mainLabel.snp.makeConstraints { make in - make.top.equalTo(imageView.snp.bottom) - make.centerX.equalToSuperview() - } - - subLabel.snp.makeConstraints { make in - make.top.equalTo(mainLabel.snp.bottom).offset(Constant.textSpacing) - make.centerX.equalToSuperview() - } - } - - func configureUI() { -// backgroundColor = .clearMLS - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListFactoryImpl.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListFactoryImpl.swift deleted file mode 100644 index 6d0d0513..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListFactoryImpl.swift +++ /dev/null @@ -1,25 +0,0 @@ -import BaseFeature -import BookmarkFeatureInterface -import DictionaryFeatureInterface -import DomainInterface - -public final class CollectionListFactoryImpl: CollectionListFactory { - private let fetchCollectionListUseCase: FetchCollectionListUseCase - private let addCollectionFactory: AddCollectionFactory - private let bookmarkDetailFactory: CollectionDetailFactory - private let sortedBottomSheetFactory: SortedBottomSheetFactory - - public init(fetchCollectionListUseCase: FetchCollectionListUseCase, addCollectionFactory: AddCollectionFactory, bookmarkDetailFactory: CollectionDetailFactory, sortedBottomSheetFactory: SortedBottomSheetFactory) { - self.fetchCollectionListUseCase = fetchCollectionListUseCase - self.addCollectionFactory = addCollectionFactory - self.bookmarkDetailFactory = bookmarkDetailFactory - self.sortedBottomSheetFactory = sortedBottomSheetFactory - } - - public func make() -> BaseViewController { - let reactor = CollectionListReactor(fetchCollectionListUseCase: fetchCollectionListUseCase) - let viewController = CollectionListViewController(addCollectionFactory: addCollectionFactory, detailFactory: bookmarkDetailFactory, sortedBottomSheetFactory: sortedBottomSheetFactory) - viewController.reactor = reactor - return viewController - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListReactor.swift deleted file mode 100644 index d621baf3..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListReactor.swift +++ /dev/null @@ -1,78 +0,0 @@ -import UIKit - -import BookmarkFeatureInterface -import DomainInterface - -import ReactorKit - -public final class CollectionListReactor: Reactor { - public enum Route { - case none - case detail(CollectionResponse) - case sortFilter - } - - public enum Action { - case itemTapped(Int) - case viewWillAppear - case completeAdding - case sortButtonTapped - case sortOptionSelected(SortType) - } - - public enum Mutation { - case navigateTo(Route) - case setListData([CollectionResponse]) - case setSort(SortType) - } - - public struct State { - @Pulse var route: Route - var collectionList: [CollectionResponse] - var sortFilter: [SortType] = [.korean, .latest] - var selectedSort: SortType? - } - - // MARK: - Properties - public var initialState: State - private let disposeBag = DisposeBag() - - private let fetchCollectionListUseCase: FetchCollectionListUseCase - - public init(fetchCollectionListUseCase: FetchCollectionListUseCase) { - self.fetchCollectionListUseCase = fetchCollectionListUseCase - self.initialState = State(route: .none, collectionList: []) - } - - public func mutate(action: Action) -> Observable { - switch action { - case .viewWillAppear: - return fetchCollectionListUseCase.execute(sort: currentState.selectedSort).map { .setListData($0) } - case .itemTapped(let index): - return .just(.navigateTo(.detail(currentState.collectionList[index]))) - case .completeAdding: - return fetchCollectionListUseCase.execute(sort: currentState.selectedSort) - .map {.setListData($0)} - case .sortButtonTapped: - return .just(.navigateTo(.sortFilter)) - case .sortOptionSelected(let sort): - return Observable.concat([ - .just(.setSort(sort)), - fetchCollectionListUseCase.execute(sort: currentState.selectedSort).map { .setListData($0) } - ]) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - switch mutation { - case .setListData(let data): - newState.collectionList = data - case .navigateTo(let route): - newState.route = route - case .setSort(let sort): - newState.selectedSort = sort - } - return newState - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListView.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListView.swift deleted file mode 100644 index 48c57b5f..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListView.swift +++ /dev/null @@ -1,130 +0,0 @@ -import UIKit - -import DesignSystem -import DomainInterface - -import SnapKit - -final class CollectionListView: UIView { - // MARK: - Type - enum Constant { - static let stackViewSpacing: CGFloat = 12 - static let topMargin: CGFloat = 12 - static let filterHeight: CGFloat = 32 - static let horizontalMargin: CGFloat = 16 - static let nonFilterTopMargin: CGFloat = 20 - } - - // MARK: - Components - public let listCollectionView: UICollectionView = { - let layout = UICollectionViewLayout() - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) - return collectionView - }() - - private lazy var filterStackView: UIStackView = { - let view = UIStackView(arrangedSubviews: [sortButton]) - view.axis = .horizontal - view.spacing = Constant.stackViewSpacing - view.distribution = .fillProportionally - return view - }() - - public lazy var sortButton: UIButton = { - let button = UIButton() - button.setAttributedTitle(.makeStyledString(font: .b_s_r, text: "최신 순", color: .textColor), for: .normal) - button.setImage(DesignSystemAsset.image(named: "lineArrowDown")?.withRenderingMode(.alwaysTemplate), for: .normal) - button.tintColor = .textColor - button.semanticContentAttribute = .forceRightToLeft - return button - }() - - public let emptyView: CollectionListEmptyView = { - let view = CollectionListEmptyView() - view.isHidden = true - return view - }() - - // MARK: - Init - init() { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension CollectionListView { - func addViews() { - addSubview(filterStackView) - addSubview(listCollectionView) - addSubview(emptyView) - } - - func setupConstraints() { - filterStackView.snp.makeConstraints { make in - make.top.equalToSuperview().inset(Constant.topMargin) - make.trailing.equalToSuperview().inset(Constant.horizontalMargin) - } - - sortButton.snp.makeConstraints { make in - make.height.equalTo(Constant.filterHeight) - } - - listCollectionView.snp.makeConstraints { make in - make.top.equalTo(filterStackView.snp.bottom).offset(Constant.topMargin) - make.horizontalEdges.equalToSuperview() - make.bottom.equalToSuperview() - } - - emptyView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } - - func configureUI() { - backgroundColor = .neutral100 - listCollectionView.backgroundColor = .neutral100 - } -} - -extension CollectionListView { - func updateView(isEmptyData: Bool) { - emptyView.isHidden = !isEmptyData - filterStackView.isHidden = isEmptyData - listCollectionView.isHidden = isEmptyData - - if isEmptyData { - listCollectionView.snp.remakeConstraints { make in - make.top.equalToSuperview().inset(Constant.nonFilterTopMargin) - make.horizontalEdges.bottom.equalToSuperview() - } - } else { - filterStackView.snp.remakeConstraints { make in - make.top.equalToSuperview().inset(Constant.topMargin) - make.trailing.equalToSuperview().inset(Constant.horizontalMargin) - } - - listCollectionView.snp.remakeConstraints { make in - make.top.equalTo(filterStackView.snp.bottom).offset(Constant.topMargin) - make.horizontalEdges.bottom.equalToSuperview() - } - } - } - - func selectFilter(selectedType: SortType) { - sortButton.setAttributedTitle(.makeStyledString(font: .b_s_r, text: selectedType.rawValue, color: .primary700), for: .normal) - sortButton.tintColor = .primary700 - } - - func selectSort(selectedType: SortType) { - sortButton.setAttributedTitle(.makeStyledString(font: .b_s_r, text: selectedType.rawValue, color: .primary700), for: .normal) - sortButton.tintColor = .primary700 - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListViewController.swift deleted file mode 100644 index f1175a4b..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionList/CollectionListViewController.swift +++ /dev/null @@ -1,174 +0,0 @@ -import UIKit - -import BaseFeature -import BookmarkFeatureInterface -import DesignSystem -import DictionaryFeatureInterface -import DomainInterface - -import ReactorKit -import RxSwift - -public final class CollectionListViewController: BaseViewController, View { - public typealias Reactor = CollectionListReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - private var selectedSortIndex = 0 - - private let addCollectionFactory: AddCollectionFactory - private let detailFactory: CollectionDetailFactory - private let sortedBottomSheetFactory: SortedBottomSheetFactory - - // MARK: - Components - private var mainView = CollectionListView() - - public init(addCollectionFactory: AddCollectionFactory, detailFactory: CollectionDetailFactory, sortedBottomSheetFactory: SortedBottomSheetFactory) { - self.addCollectionFactory = addCollectionFactory - self.detailFactory = detailFactory - self.sortedBottomSheetFactory = sortedBottomSheetFactory - super.init() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override public func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension CollectionListViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } - - func configureUI() { - mainView.listCollectionView.collectionViewLayout = createListLayout() - mainView.listCollectionView.delegate = self - mainView.listCollectionView.dataSource = self - mainView.listCollectionView.register(CollectionListCell.self, forCellWithReuseIdentifier: CollectionListCell.identifier) - - addFloatingButton { [weak self] in - guard let self = self else { return } - let viewController = self.addCollectionFactory.make(collection: nil) - - guard let viewController = viewController as? AddCollectionViewController else { return } - viewController.dismissed - .withUnretained(self) - .subscribe { owner, _ in - owner.reactor?.action.onNext(.completeAdding) - } - .disposed(by: disposeBag) - - self.present(viewController, animated: true) - } - } - - func createListLayout() -> UICollectionViewLayout { - let layoutFactory = LayoutFactory() - let layout = CompositionalLayoutBuilder() - .section { _ in layoutFactory.getCollectionListLayout() } - .build() - return layout - } -} - -// MARK: - Bind -extension CollectionListViewController { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .map { Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.sortButton.rx.tap - .map { .sortButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, route in - switch route { - case .detail(let collection): - let viewController = owner.detailFactory.make(collection: collection, onMoveToMain: { - if let tabBarController = owner.tabBarController as? BottomTabBarController { - tabBarController.selectTab(index: 0) - DictionaryTabRegistry.changeTab(index: 0) - } - }) - owner.tabBarController?.navigationController?.pushViewController(viewController, animated: true) - case .sortFilter: - let viewController = owner.sortedBottomSheetFactory.make(sortedOptions: reactor.currentState.sortFilter, selectedIndex: owner.selectedSortIndex) { index in - owner.selectedSortIndex = index - let selectedFilter = reactor.currentState.sortFilter[index] - reactor.action.onNext(.sortOptionSelected(selectedFilter)) - owner.mainView.selectSort(selectedType: selectedFilter) - } - owner.tabBarController?.presentModal(viewController) - default: - break - } - } - .disposed(by: disposeBag) - - reactor.state - .map(\.collectionList) - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, collectionList in - owner.mainView.updateView(isEmptyData: collectionList.isEmpty) - owner.mainView.listCollectionView.reloadData() - } - .disposed(by: disposeBag) - } -} - -// MARK: - Delegate -extension CollectionListViewController: UICollectionViewDelegate, UICollectionViewDataSource { - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - reactor?.currentState.collectionList.count ?? 0 - } - - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard - let cell = collectionView.dequeueReusableCell( - withReuseIdentifier: CollectionListCell.identifier, - for: indexPath - ) as? CollectionListCell, - let item = reactor?.currentState.collectionList[indexPath.row] - else { - return UICollectionViewCell() - } - cell.inject(input: CollectionListCell.Input(title: item.name, count: item.recentBookmarks.count, images: item.recentBookmarks.map { $0.imageUrl })) - return cell - } - - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - reactor?.action.onNext(.itemTapped(indexPath.row)) - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionSettingSheet/CollectionSettingFactoryImpl.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionSettingSheet/CollectionSettingFactoryImpl.swift deleted file mode 100644 index 5a66eea4..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionSettingSheet/CollectionSettingFactoryImpl.swift +++ /dev/null @@ -1,13 +0,0 @@ -import BaseFeature -import BookmarkFeatureInterface - -public struct CollectionSettingFactoryImpl: CollectionSettingFactory { - public init() {} - - public func make(setEditMenu: ((CollectionSettingMenu) -> Void)?) -> BaseViewController & ModalPresentable { - let viewController = CollectionSettingViewController() - viewController.reactor = CollectionSettingReactor() - viewController.setMenu = setEditMenu - return viewController - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionSettingSheet/CollectionSettingReactor.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionSettingSheet/CollectionSettingReactor.swift deleted file mode 100644 index a593f52f..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionSettingSheet/CollectionSettingReactor.swift +++ /dev/null @@ -1,66 +0,0 @@ -import UIKit - -import BookmarkFeatureInterface - -import ReactorKit -import RxCocoa -import RxSwift - -public final class CollectionSettingReactor: Reactor { - public enum Route { - case none - case dismiss - case dismissWithMenu(CollectionSettingMenu) - } - - // MARK: - Reactor - public enum Action { - case cancelButtonTapped - case editBookmarkButtonTapped - case editNameButtonTapped - case deleteButtonTapped - } - - public enum Mutation { - case navigateTo(route: Route) - } - - public struct State { - @Pulse var route: Route = .none - var menu = CollectionSettingMenu.allCases - } - - // MARK: - properties - public var initialState: State - var disposeBag = DisposeBag() - - // MARK: - init - public init() { - self.initialState = State() - } - - // MARK: - Reactor Methods - public func mutate(action: Action) -> Observable { - switch action { - case .cancelButtonTapped: - return Observable.just(.navigateTo(route: .dismiss)) - case .editBookmarkButtonTapped: - return Observable.just(.navigateTo(route: .dismissWithMenu(.editBookmark))) - case .editNameButtonTapped: - return Observable.just(.navigateTo(route: .dismissWithMenu(.editName))) - case .deleteButtonTapped: - return Observable.just(.navigateTo(route: .dismissWithMenu(.delete))) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .navigateTo(let route): - newState.route = route - } - - return newState - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionSettingSheet/CollectionSettingView.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionSettingSheet/CollectionSettingView.swift deleted file mode 100644 index b7bb8d95..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionSettingSheet/CollectionSettingView.swift +++ /dev/null @@ -1,60 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -final class CollectionSettingView: UIView { - private enum Constant { - static let topInset: CGFloat = 16 - static let tableViewInset: CGFloat = 14 - static let tableViewHeight: CGFloat = 284 - } - - // MARK: - Properties - let header: Header = { - let header = Header(style: .filter, title: "컬렉션") - return header - }() - - public let menuTableView: UITableView = { - let view = UITableView() - view.isScrollEnabled = false - view.separatorStyle = .none - return view - }() - - // MARK: - init - init() { - super.init(frame: .zero) - - addViews() - setupConstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension CollectionSettingView { - func addViews() { - addSubview(header) - addSubview(menuTableView) - } - - func setupConstraints() { - header.snp.makeConstraints { make in - make.top.equalToSuperview().inset(Constant.topInset) - make.horizontalEdges.equalToSuperview() - } - - menuTableView.snp.makeConstraints { make in - make.top.equalTo(header.snp.bottom).offset(Constant.tableViewInset) - make.horizontalEdges.equalToSuperview() - make.bottom.equalToSuperview() - } - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionSettingSheet/CollectionSettingViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionSettingSheet/CollectionSettingViewController.swift deleted file mode 100644 index 30f06bb2..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeature/CollectionSettingSheet/CollectionSettingViewController.swift +++ /dev/null @@ -1,130 +0,0 @@ -import UIKit - -import BaseFeature -import BookmarkFeatureInterface - -import ReactorKit -import RxCocoa -import RxSwift -import SnapKit - -public final class CollectionSettingViewController: BaseViewController, ModalPresentable, View { - public var modalHeight: CGFloat? = 284 - - public typealias Reactor = CollectionSettingReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - public var setMenu: ((CollectionSettingMenu) -> Void)? - - private var mainView = CollectionSettingView() -} - -// MARK: - Life Cycle -public extension CollectionSettingViewController { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension CollectionSettingViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } - - func configureUI() { - mainView.menuTableView.delegate = self - mainView.menuTableView.dataSource = self - } -} - -extension CollectionSettingViewController { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - mainView.header.firstIconButton.rx.tap - .map { Reactor.Action.cancelButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .subscribe { owner, route in - switch route { - case .dismiss: - owner.dismissCurrentModal() - case .dismissWithMenu(let menu): - owner.setMenu?(menu) - owner.dismissCurrentModal() - default: - break - } - } - .disposed(by: disposeBag) - } -} - -extension CollectionSettingViewController: UITableViewDelegate, UITableViewDataSource { - public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - guard let reactor = reactor else { return 0 } - return reactor.currentState.menu.count - } - - public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = UITableViewCell() - guard let reactor = reactor else { return cell } - let item = reactor.currentState.menu[indexPath.row] - cell.textLabel?.textAlignment = .center - cell.textLabel?.autoresizingMask = [.flexibleWidth, .flexibleHeight] - cell.textLabel?.attributedText = .makeStyledString(font: .b_m_r, text: item.title, color: item.titleColor) - if indexPath.row < reactor.currentState.menu.count - 1 { - let divider = UIView() - divider.backgroundColor = .lightGray.withAlphaComponent(0.3) - cell.contentView.addSubview(divider) - divider.snp.makeConstraints { make in - make.horizontalEdges.bottom.equalToSuperview() - make.height.equalTo(1) - } - } - cell.selectionStyle = .none - return cell - } - - public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - guard let reactor = reactor else { return } - let item = reactor.currentState.menu[indexPath.row] - switch item { - case .editBookmark: - reactor.action.onNext(.editBookmarkButtonTapped) - case .editName: - reactor.action.onNext(.editNameButtonTapped) - case .delete: - reactor.action.onNext(.deleteButtonTapped) - case .cancel: - reactor.action.onNext(.cancelButtonTapped) - } - } - - public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - return 54 - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/AppDelegate.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/AppDelegate.swift deleted file mode 100644 index 3dfa35d1..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/AppDelegate.swift +++ /dev/null @@ -1,405 +0,0 @@ -// swiftlint:disable function_body_length -// swiftlint:disable line_length - -import UIKit - -import AuthFeature -import AuthFeatureInterface -import BaseFeature -import BookmarkFeature -import BookmarkFeatureInterface -import Core -import Data -import DataMock -import DesignSystem -import DictionaryFeature -import DictionaryFeatureInterface -import Domain -import DomainInterface -import MyPageFeature -import MyPageFeatureInterface - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - ImageLoader.shared.configure.diskCacheCountLimit = 10 - FontManager.registerFonts() - registerDependencies() - return true - } - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {} -} - -private extension AppDelegate { - func registerDependencies() { - registerProvider() - registerRepository() - registerUseCase() - registerFactory() - } - - func registerProvider() { - DIContainer.register(type: NetworkProvider.self) { - NetworkProviderImpl() - } - DIContainer.register(type: SocialAuthenticatableProvider.self, name: "kakao") { - KakaoLoginProviderMock() - } - DIContainer.register(type: SocialAuthenticatableProvider.self, name: "apple") { - AppleLoginProviderMock() - } - } - - func registerRepository() { - DIContainer.register(type: AuthAPIRepository.self) { - AuthAPIRepositoryMock(provider: DIContainer.resolve(type: NetworkProvider.self)) - } - DIContainer.register(type: TokenRepository.self) { - KeyChainRepositoryImpl() - } - DIContainer.register(type: DictionaryListAPIRepository.self) { - return DictionaryListAPIRepositoryImpl(provider: DIContainer.resolve(type: NetworkProvider.self), tokenInterceptor: TokenInterceptor(fetchTokenUseCase: DIContainer.resolve(type: FetchTokenFromLocalUseCase.self))) - } - DIContainer.register(type: BookmarkRepository.self) { - return BookmarkRepositoryImpl(provider: DIContainer.resolve(type: NetworkProvider.self), interceptor: TokenInterceptor(fetchTokenUseCase: DIContainer.resolve(type: FetchTokenFromLocalUseCase.self))) - } - DIContainer.register(type: DictionaryDetailAPIRepository.self) { - return DictionaryDetailAPIRepositoryImpl(provider: DIContainer.resolve(type: NetworkProvider.self), tokenInterceptor: TokenInterceptor(fetchTokenUseCase: DIContainer.resolve(type: FetchTokenFromLocalUseCase.self))) - } - DIContainer.register(type: UserDefaultsRepository.self) { - UserDefaultsRepositoryImpl() - } - } - - func registerUseCase() { - DIContainer.register(type: FetchSocialCredentialUseCase.self, name: "kakao") { - let provider = DIContainer.resolve(type: SocialAuthenticatableProvider.self, name: "kakao") - return SocialLoginUseCaseImpl(provider: provider) - } - DIContainer.register(type: FetchSocialCredentialUseCase.self, name: "apple") { - let provider = DIContainer.resolve(type: SocialAuthenticatableProvider.self, name: "apple") - return SocialLoginUseCaseImpl(provider: provider) - } - DIContainer.register(type: CheckEmptyLevelAndRoleUseCase.self) { - CheckEmptyLevelAndRoleUseCaseImpl() - } - DIContainer.register(type: CheckValidLevelUseCase.self) { - CheckValidLevelUseCaseImpl() - } - DIContainer.register(type: FetchJobListUseCase.self) { - FetchJobListUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: LoginWithAppleUseCase.self) { - LoginWithAppleUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: LoginWithKakaoUseCase.self) { - LoginWithKakaoUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: SignUpWithAppleUseCase.self) { - SignUpWithAppleUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: SignUpWithKakaoUseCase.self) { - SignUpWithKakaoUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: UpdateUserInfoUseCase.self) { - UpdateUserInfoUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: FetchTokenFromLocalUseCase.self) { - FetchTokenFromLocalUseCaseImpl(repository: DIContainer.resolve(type: TokenRepository.self)) - } - DIContainer.register(type: SaveTokenToLocalUseCase.self) { - SaveTokenToLocalUseCaseImpl(repository: DIContainer.resolve(type: TokenRepository.self)) - } - DIContainer.register(type: DeleteTokenFromLocalUseCase.self) { - DeleteTokenFromLocalUseCaseImpl(repository: DIContainer.resolve(type: TokenRepository.self)) - } - DIContainer.register(type: FetchNotificationUseCase.self) { - FetchNotificationUseCaseImpl() - } - DIContainer.register(type: SetBookmarkUseCase.self) { - SetBookmarkUseCaseImpl(repository: DIContainer.resolve(type: BookmarkRepository.self)) - } - DIContainer.register(type: CheckLoginUseCase.self) { - CheckLoginUseCaseImpl(authRepository: DIContainer.resolve(type: AuthAPIRepository.self), tokenRepository: DIContainer.resolve(type: TokenRepository.self)) - } - DIContainer.register(type: CheckNotificationPermissionUseCase.self) { - return CheckNotificationPermissionUseCaseImpl() - } - DIContainer.register(type: OpenNotificationSettingUseCase.self) { - return OpenNotificationSettingUseCaseImpl() - } - DIContainer.register(type: UpdateNotificationAgreementUseCase.self) { - return UpdateNotificationAgreementUseCaseImpl(authRepository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: UpdateMarketingAgreementUseCase.self) { - return UpdateMarketingAgreementUseCaseImpl(authRepository: DIContainer.resolve(type: AuthAPIRepository.self), tokenRepository: DIContainer.resolve(type: TokenRepository.self)) - } - DIContainer.register(type: FetchDictionaryMapListUseCase.self) { - return FetchDictionaryMapListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryItemListUseCase.self) { - return FetchDictionaryItemListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryQuestListUseCase.self) { - return FetchDictionaryQuestListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryNpcListUseCase.self) { - return FetchDictionaryNpcListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryMonsterListUseCase.self) { - return FetchDictionaryMonsterListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMonsterUseCase.self) { - return FetchDictionaryDetailMonsterUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMonsterItemsUseCase.self) { - return FetchDictionaryDetailMonsterDropItemUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMonsterMapUseCase.self) { - return FetchDictionaryDetailMonsterMapUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailNpcUseCase.self) { - return FetchDictionaryDetailNpcUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailNpcQuestUseCase.self) { - return FetchDictionaryDetailNpcQuestUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailNpcMapUseCase.self) { - return FetchDictionaryDetailNpcMapUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailItemUseCase.self) { - return FetchDictionaryDetailItemUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailItemDropMonsterUseCase.self) { - return FetchDictionaryDetailItemDropMonsterUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailQuestUseCase.self) { - return FetchDictionaryDetailQuestUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailQuestLinkedQuestsUseCase.self) { - return FetchDictionaryDetailQuestLinkedQuestsUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMapUseCase.self) { - return FetchDictionaryDetailMapUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMapSpawnMonsterUseCase.self) { - return FetchDictionaryDetailMapSpawnMonsterUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMapNpcUseCase.self) { - return FetchDictionaryDetailMapNpcUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchMonsterBookmarkUseCase.self) { - FetchMonsterBookmarkUseCaseImpl(repository: DIContainer.resolve(type: BookmarkRepository.self)) - } - DIContainer.register(type: FetchItemBookmarkUseCase.self) { - FetchItemBookmarkUseCaseImpl(repository: DIContainer.resolve(type: BookmarkRepository.self)) - } - DIContainer.register(type: FetchMapBookmarkUseCase.self) { - FetchMapBookmarkUseCaseImpl(repository: DIContainer.resolve(type: BookmarkRepository.self)) - } - DIContainer.register(type: FetchQuestBookmarkUseCase.self) { - FetchQuestBookmarkUseCaseImpl(repository: DIContainer.resolve(type: BookmarkRepository.self)) - } - DIContainer.register(type: FetchNPCBookmarkUseCase.self) { - FetchNPCBookmarkUseCaseImpl(repository: DIContainer.resolve(type: BookmarkRepository.self)) - } - DIContainer.register(type: FetchBookmarkUseCase.self) { - FetchBookmarkUseCaseImpl(repository: DIContainer.resolve(type: BookmarkRepository.self)) - } - DIContainer.register(type: FetchDictionaryAllListUseCase.self) { - FetchDictionaryAllListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: RecentSearchRemoveUseCase.self) { - RecentSearchRemoveUseCaseImpl(repository: DIContainer.resolve(type: UserDefaultsRepository.self)) - } - DIContainer.register(type: RecentSearchAddUseCase.self) { - RecentSearchAddUseCaseImpl(repository: DIContainer.resolve(type: UserDefaultsRepository.self)) - } - DIContainer.register(type: FetchDictionaryListCountUseCase.self) { - FetchDictionaryListCountUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionarySearchListUseCase.self) { - FetchDictionarySearchListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: RecentSearchFetchUseCase.self) { - RecentSearchFetchUseCaseImpl(repository: DIContainer.resolve(type: UserDefaultsRepository.self)) - } - } - - func registerFactory() { - DIContainer.register(type: ItemFilterBottomSheetFactory.self) { - ItemFilterBottomSheetFactoryImpl() - } - DIContainer.register(type: MonsterFilterBottomSheetFactory.self) { - MonsterFilterBottomSheetFactoryImpl() - } - DIContainer.register(type: SortedBottomSheetFactory.self) { - SortedBottomSheetFactoryImpl() - } - DIContainer.register(type: AddCollectionFactory.self) { - AddCollectionFactoryImpl() - } - DIContainer.register(type: BookmarkModalFactory.self) { - BookmarkModalFactoryImpl(addCollectionFactory: DIContainer.resolve(type: AddCollectionFactory.self)) - } - DIContainer.register(type: DictionaryDetailFactory.self) { - return DictionaryDetailFactoryImpl(dictionaryDetailMapUseCase: DIContainer.resolve(type: FetchDictionaryDetailMapUseCase.self), dictionaryDetailMapSpawnMonsterUseCase: DIContainer.resolve(type: FetchDictionaryDetailMapSpawnMonsterUseCase.self), dictionaryDetailMapNpcUseCase: DIContainer.resolve(type: FetchDictionaryDetailMapNpcUseCase.self), dictionaryDetailQuestLinkedQuestsUseCase: DIContainer.resolve(type: FetchDictionaryDetailQuestLinkedQuestsUseCase.self), dictionaryDetailQuestUseCase: DIContainer.resolve(type: FetchDictionaryDetailQuestUseCase.self), dictionaryDetailItemDropMonsterUseCase: DIContainer.resolve(type: FetchDictionaryDetailItemDropMonsterUseCase.self), dictionaryDetailItemUseCase: DIContainer.resolve(type: FetchDictionaryDetailItemUseCase.self), dictionaryDetailNpcUseCase: DIContainer.resolve(type: FetchDictionaryDetailNpcUseCase.self), dictionaryDetailNpcQuestUseCase: DIContainer.resolve(type: FetchDictionaryDetailNpcQuestUseCase.self), dictionaryDetailNpcMapUseCase: DIContainer.resolve(type: FetchDictionaryDetailNpcMapUseCase.self), dictionaryDetailMonsterUseCase: DIContainer.resolve(type: FetchDictionaryDetailMonsterUseCase.self), dictionaryDetailMonsterDropItemUseCase: DIContainer.resolve(type: FetchDictionaryDetailMonsterItemsUseCase.self), dictionaryDetailMonsterMapUseCase: DIContainer.resolve(type: FetchDictionaryDetailMonsterMapUseCase.self)) - } - DIContainer.register(type: DictionaryMainListFactory.self) { - DictionaryListFactoryImpl( - checkLoginUseCase: DIContainer.resolve(type: CheckLoginUseCase.self), - dictionaryAllListItemUseCase: DIContainer.resolve(type: FetchDictionaryAllListUseCase.self), - dictionaryMapListItemUseCase: DIContainer.resolve(type: FetchDictionaryMapListUseCase.self), - dictionaryItemListItemUseCase: DIContainer.resolve(type: FetchDictionaryItemListUseCase.self), - dictionaryQuestListItemUseCase: DIContainer.resolve(type: FetchDictionaryQuestListUseCase.self), - dictionaryNpcListItemUseCase: DIContainer.resolve(type: FetchDictionaryNpcListUseCase.self), - dictionaryListItemUseCase: DIContainer.resolve(type: FetchDictionaryMonsterListUseCase.self), - setBookmarkUseCase: DIContainer.resolve(type: SetBookmarkUseCase.self), - itemFilterFactory: DIContainer.resolve(type: ItemFilterBottomSheetFactory.self), - monsterFilterFactory: DIContainer.resolve(type: MonsterFilterBottomSheetFactory.self), - sortedFactory: DIContainer.resolve(type: SortedBottomSheetFactory.self), - bookmarkModalFactory: DIContainer.resolve(type: BookmarkModalFactory.self), - detailFactory: DIContainer.resolve(type: DictionaryDetailFactory.self) - ) - } - DIContainer.register(type: DictionarySearchResultFactory.self) { - DictionarySearchResultFactoryImpl( - dictionaryListCountUseCase: DIContainer.resolve(type: FetchDictionaryListCountUseCase.self), - dictionaryMainListFactory: DIContainer - .resolve(type: DictionaryMainListFactory.self), - dictionarySearchListUseCase: DIContainer.resolve(type: FetchDictionarySearchListUseCase.self) - ) - } - DIContainer.register(type: DictionarySearchFactory.self) { - DictionarySearchFactoryImpl(recentSearchRemoveUseCase: DIContainer.resolve(type: RecentSearchRemoveUseCase.self), - recentSearchAddUseCase: DIContainer.resolve(type: RecentSearchAddUseCase.self), - searchResultFactory: DIContainer - .resolve(type: DictionarySearchResultFactory.self), recentSearchFetchUseCase: DIContainer.resolve(type: RecentSearchFetchUseCase.self) - ) - } - DIContainer.register(type: NotificationSettingFactory.self) { - NotificationSettingFactoryImpl(checkNotificationPermissionUseCase: DIContainer.resolve(type: CheckNotificationPermissionUseCase.self), updateNotificationAgreementUseCase: DIContainer.resolve(type: UpdateNotificationAgreementUseCase.self)) - } - DIContainer.register(type: DictionaryNotificationFactory.self) { - DictionaryNotificationFactoryImpl( - fetchNotificationUseCase: DIContainer - .resolve(type: FetchNotificationUseCase.self), - notificationSettingFactory: DIContainer - .resolve(type: NotificationSettingFactory.self) - ) - } - DIContainer.register(type: DictionaryMainViewFactory.self) { - DictionaryMainViewFactoryImpl( - dictionaryMainListFactory: DIContainer - .resolve(type: DictionaryMainListFactory.self), - searchFactory: DIContainer.resolve(type: DictionarySearchFactory.self), - notificationFactory: DIContainer - .resolve(type: DictionaryNotificationFactory.self), checkLoginUseCase: DIContainer.resolve(type: CheckLoginUseCase.self)) - } - DIContainer.register(type: BookmarkOnBoardingFactory.self) { - BookmarkOnBoardingFactoryImpl() - } - DIContainer.register(type: OnBoardingNotificationSheetFactory.self) { - return OnBoardingNotificationSheetFactoryImpl(checkNotificationPermissionUseCase: DIContainer.resolve(type: CheckNotificationPermissionUseCase.self), openNotificationSettingUseCase: DIContainer.resolve(type: OpenNotificationSettingUseCase.self), updateNotificationAgreementUseCase: DIContainer.resolve(type: UpdateNotificationAgreementUseCase.self), updateUserInfoUseCase: DIContainer.resolve(type: UpdateUserInfoUseCase.self), dictionaryMainViewFactory: DIContainer.resolve(type: DictionaryMainViewFactory.self)) - } - DIContainer.register(type: OnBoardingNotificationFactory.self) { - return OnBoardingNotificationFactoryImpl(onBoardingNotificationSheetFactory: DIContainer.resolve(type: OnBoardingNotificationSheetFactory.self)) - } - DIContainer.register(type: OnBoardingInputFactory.self) { - return OnBoardingInputFactoryImpl( - checkEmptyUseCase: DIContainer - .resolve(type: CheckEmptyLevelAndRoleUseCase.self), - checkValidLevelUseCase: DIContainer - .resolve(type: CheckValidLevelUseCase.self), - fetchJobListUseCase: DIContainer - .resolve(type: FetchJobListUseCase.self), updateUserInfoUseCase: DIContainer.resolve(type: UpdateUserInfoUseCase.self), - onBoardingNotificationFactory: DIContainer - .resolve(type: OnBoardingNotificationFactory.self) - ) - } - DIContainer.register(type: OnBoardingQuestionFactory.self) { - OnBoardingQuestionFactoryImpl(onBoardingInputFactory: DIContainer.resolve(type: OnBoardingInputFactory.self)) - } - DIContainer.register(type: TermsAgreementFactory.self) { - TermsAgreementFactoryImpl( - onBoardingQuestionFactory: DIContainer - .resolve(type: OnBoardingQuestionFactory.self), - signUpWithKakaoUseCase: DIContainer - .resolve(type: SignUpWithKakaoUseCase.self), - signUpWithAppleUseCase: DIContainer - .resolve(type: SignUpWithAppleUseCase.self), - saveTokenUseCase: DIContainer - .resolve(type: SaveTokenToLocalUseCase.self), - fetchTokenUseCase: DIContainer - .resolve(type: FetchTokenFromLocalUseCase.self), updateMarketingAgreementUseCase: DIContainer.resolve(type: UpdateMarketingAgreementUseCase.self) - ) - } - DIContainer.register(type: PutFCMTokenUseCase.self) { - PutFCMTokenUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: LoginFactory.self) { - LoginFactoryImpl( - termsAgreementsFactory: DIContainer - .resolve(type: TermsAgreementFactory.self), - appleLoginUseCase: DIContainer - .resolve(type: FetchSocialCredentialUseCase.self, name: "apple"), - kakaoLoginUseCase: DIContainer - .resolve(type: FetchSocialCredentialUseCase.self, name: "kakao"), - loginWithAppleUseCase: DIContainer - .resolve(type: LoginWithAppleUseCase.self), - loginWithKakaoUseCase: DIContainer - .resolve(type: LoginWithKakaoUseCase.self), - fetchTokenUseCase: DIContainer.resolve(type: FetchTokenFromLocalUseCase.self), - putFCMTokenUseCase: DIContainer.resolve(type: PutFCMTokenUseCase.self) - ) - } - DIContainer.register(type: BookmarkListFactory.self) { - BookmarkListFactoryImpl(itemFilterFactory: DIContainer.resolve(type: ItemFilterBottomSheetFactory.self), monsterFilterFactory: DIContainer.resolve(type: MonsterFilterBottomSheetFactory.self), sortedFactory: DIContainer.resolve(type: SortedBottomSheetFactory.self), bookmarkModalFactory: DIContainer.resolve(type: BookmarkModalFactory.self), loginFactory: DIContainer.resolve(type: LoginFactory.self), dictionaryDetailFactory: DIContainer.resolve(type: DictionaryDetailFactory.self), setBookmarkUseCase: DIContainer.resolve(type: SetBookmarkUseCase.self), checkLoginUseCase: DIContainer.resolve(type: CheckLoginUseCase.self), fetchBookmarkUseCase: DIContainer.resolve(type: FetchBookmarkUseCase.self), fetchMonsterBookmarkUseCase: DIContainer.resolve(type: FetchMonsterBookmarkUseCase.self), fetchItemBookmarkUseCase: DIContainer.resolve(type: FetchItemBookmarkUseCase.self), fetchNPCBookmarkUseCase: DIContainer.resolve(type: FetchNPCBookmarkUseCase.self), fetchQuestBookmarkUseCase: DIContainer.resolve(type: FetchQuestBookmarkUseCase.self), fetchMapBookmarkUseCase: DIContainer.resolve(type: FetchMapBookmarkUseCase.self)) - } - DIContainer.register(type: CollectionSettingFactory.self) { - CollectionSettingFactoryImpl() - } - DIContainer.register(type: CollectionEditFactory.self) { - CollectionEditFactoryImpl(setBookmarkUseCase: DIContainer.resolve(type: SetBookmarkUseCase.self), bookmarkModalFactory: DIContainer.resolve(type: BookmarkModalFactory.self)) - } - DIContainer.register(type: CollectionDetailFactory.self) { - CollectionDetailFactoryImpl( - setBookmarkUseCase: DIContainer - .resolve(type: SetBookmarkUseCase.self), - bookmarkModalFactory: DIContainer - .resolve(type: BookmarkModalFactory.self), - collectionSettingFactory: DIContainer - .resolve(type: CollectionSettingFactory.self), - addCollectionFactory: DIContainer - .resolve(type: AddCollectionFactory.self), - collectionEditFactory: DIContainer - .resolve(type: CollectionEditFactory.self) - ) - } - DIContainer.register(type: CollectionListFactory.self) { - CollectionListFactoryImpl(addCollectionFactory: DIContainer.resolve(type: AddCollectionFactory.self), bookmarkDetailFactory: DIContainer.resolve(type: CollectionDetailFactory.self)) - } - DIContainer.register(type: BookmarkMainFactory.self) { - BookmarkMainFactoryImpl( - setBookmarkUseCase: DIContainer - .resolve(type: SetBookmarkUseCase.self), - onBoardingFactory: DIContainer - .resolve(type: BookmarkOnBoardingFactory.self), - bookmarkListFactory: DIContainer - .resolve(type: BookmarkListFactory.self), - collectionListFactory: DIContainer - .resolve(type: CollectionListFactory.self), - searchFactory: DIContainer - .resolve(type: DictionarySearchFactory.self), - notificationFactory: DIContainer.resolve( - type: DictionaryNotificationFactory.self - ) - ) - } - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Assets.xcassets/AccentColor.colorset/Contents.json b/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index eb878970..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Assets.xcassets/AppIcon.appiconset/Contents.json b/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index c68da6c9..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "images" : [ - { - "filename" : "icon.png", - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "tinted" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Assets.xcassets/AppIcon.appiconset/icon.png b/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Assets.xcassets/AppIcon.appiconset/icon.png deleted file mode 100644 index 6f9fcee3..00000000 Binary files a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Assets.xcassets/AppIcon.appiconset/icon.png and /dev/null differ diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Assets.xcassets/Contents.json b/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Base.lproj/LaunchScreen.storyboard b/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 865e9329..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Info.plist b/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Info.plist deleted file mode 100644 index 7c5f0be1..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/Info.plist +++ /dev/null @@ -1,25 +0,0 @@ - - - - - ITSAppUsesNonExemptEncryption - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - - - - - - diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/SceneDelegate.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/SceneDelegate.swift deleted file mode 100644 index 2e5908b1..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/SceneDelegate.swift +++ /dev/null @@ -1,23 +0,0 @@ -import UIKit - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - var window: UIWindow? - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - guard let windowScene = (scene as? UIWindowScene) else { return } - window = UIWindow(windowScene: windowScene) - let startVC = ViewController() - window?.rootViewController = UINavigationController(rootViewController: startVC) - window?.makeKeyAndVisible() - } - - func sceneDidDisconnect(_ scene: UIScene) {} - - func sceneDidBecomeActive(_ scene: UIScene) {} - - func sceneWillResignActive(_ scene: UIScene) {} - - func sceneWillEnterForeground(_ scene: UIScene) {} - - func sceneDidEnterBackground(_ scene: UIScene) {} -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/ViewController.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/ViewController.swift deleted file mode 100644 index d62fd169..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureDemo/ViewController.swift +++ /dev/null @@ -1,69 +0,0 @@ -import UIKit - -import BaseFeature -import BookmarkFeatureInterface -import Core -import DesignSystem -import DictionaryFeatureInterface - -import SnapKit - -class ViewController: UIViewController { - let tableView: UITableView = { - let view = UITableView(frame: .zero, style: .plain) - return view - }() - - lazy var views: [[UIViewController]] = { - let dictionaryMainVC = DIContainer.resolve(type: DictionaryMainViewFactory.self).make() - - let bookmarkMainVC = DIContainer.resolve(type: BookmarkMainFactory.self).make() - - let dictView = BottomTabBarController(viewControllers: [ - dictionaryMainVC, - bookmarkMainVC, - BaseViewController() - ]) - dictView.title = "도감 메인" - - return [ - [dictView] - ] - }() - - override func viewDidLoad() { - super.viewDidLoad() - view.backgroundColor = .systemBackground - tableView.dataSource = self - tableView.delegate = self - navigationItem.title = "MLS Feature System" - - view.addSubview(tableView) - - tableView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } -} - -extension ViewController: UITableViewDataSource, UITableViewDelegate { - func numberOfSections(in tableView: UITableView) -> Int { - return views.count - } - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return views[section].count - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = UITableViewCell() - cell.textLabel?.text = views[indexPath.section][indexPath.row].title - cell.selectionStyle = .none - return cell - } - - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let nextController = views[indexPath.section][indexPath.row] - navigationController?.pushViewController(nextController, animated: true) - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/AddCollectionFactory.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/AddCollectionFactory.swift deleted file mode 100644 index de84a042..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/AddCollectionFactory.swift +++ /dev/null @@ -1,6 +0,0 @@ -import BaseFeature -import DomainInterface - -public protocol AddCollectionFactory { - func make(collection: CollectionResponse?) -> BaseViewController -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/BookmarkListFactory.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/BookmarkListFactory.swift deleted file mode 100644 index 712c2201..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/BookmarkListFactory.swift +++ /dev/null @@ -1,6 +0,0 @@ -import BaseFeature -import DomainInterface - -public protocol BookmarkListFactory { - func make(type: DictionaryType, listType: DictionaryMainViewType) -> BaseViewController -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/BookmarkMainFactory.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/BookmarkMainFactory.swift deleted file mode 100644 index 0b8deb2b..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/BookmarkMainFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol BookmarkMainFactory { - func make() -> BaseViewController -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/BookmarkModalFactory.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/BookmarkModalFactory.swift deleted file mode 100644 index 8c96281c..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/BookmarkModalFactory.swift +++ /dev/null @@ -1,7 +0,0 @@ -import BaseFeature -import DomainInterface - -public protocol BookmarkModalFactory { - func make(bookmarkIds: [Int]) -> BaseViewController - func make(bookmarkIds: [Int], onComplete: ((Bool) -> Void)?) -> BaseViewController -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/BookmarkOnBoardingFactory.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/BookmarkOnBoardingFactory.swift deleted file mode 100644 index 665830ec..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/BookmarkOnBoardingFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol BookmarkOnBoardingFactory { - func make() -> BaseViewController -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/CollectionDetailFactory.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/CollectionDetailFactory.swift deleted file mode 100644 index 67d08357..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/CollectionDetailFactory.swift +++ /dev/null @@ -1,6 +0,0 @@ -import BaseFeature -import DomainInterface - -public protocol CollectionDetailFactory { - func make(collection: CollectionResponse, onMoveToMain: (() -> Void)?) -> BaseViewController -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/CollectionEditFactory.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/CollectionEditFactory.swift deleted file mode 100644 index affdca0b..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/CollectionEditFactory.swift +++ /dev/null @@ -1,6 +0,0 @@ -import BaseFeature -import DomainInterface - -public protocol CollectionEditFactory { - func make(bookmarks: [BookmarkResponse]) -> BaseViewController -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/CollectionEditMenu.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/CollectionEditMenu.swift deleted file mode 100644 index 08b4b81e..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/CollectionEditMenu.swift +++ /dev/null @@ -1,30 +0,0 @@ -import UIKit - -public enum CollectionSettingMenu: CaseIterable { - case editBookmark - case editName - case delete - case cancel - - public var title: String { - switch self { - case .editBookmark: - return "컬렉션 북마크 수정" - case .editName: - return "컬렉션 이름 수정" - case .delete: - return "컬렉션 삭제" - case .cancel: - return "취소" - } - } - - public var titleColor: UIColor { - switch self { - case .delete: - return .red - default: - return .textColor - } - } -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/CollectionListFactory.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/CollectionListFactory.swift deleted file mode 100644 index 142b498d..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/CollectionListFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol CollectionListFactory { - func make() -> BaseViewController -} diff --git a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/CollectionSettingFactory.swift b/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/CollectionSettingFactory.swift deleted file mode 100644 index 934ed890..00000000 --- a/MLS/Presentation/BookmarkFeature/BookmarkFeatureInterface/CollectionSettingFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol CollectionSettingFactory { - func make(setEditMenu: ((CollectionSettingMenu) -> Void)?) -> BaseViewController & ModalPresentable -} diff --git a/MLS/Presentation/DesignSystem/.DS_Store b/MLS/Presentation/DesignSystem/.DS_Store deleted file mode 100644 index ce009ba5..00000000 Binary files a/MLS/Presentation/DesignSystem/.DS_Store and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/BookmarkModalFactory.swift b/MLS/Presentation/DesignSystem/BookmarkModalFactory.swift deleted file mode 100644 index 90b5b5b0..00000000 --- a/MLS/Presentation/DesignSystem/BookmarkModalFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol BookmarkModalFactory { - func make(onDismissWithMessage: @escaping (String) -> Void) -> BaseViewController -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem.xcodeproj/project.pbxproj b/MLS/Presentation/DesignSystem/DesignSystem.xcodeproj/project.pbxproj deleted file mode 100644 index d3ede243..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem.xcodeproj/project.pbxproj +++ /dev/null @@ -1,704 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 77; - objects = { - -/* Begin PBXBuildFile section */ - 08686A3D2DD1C8F400868C70 /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 08686A3C2DD1C8F400868C70 /* SnapKit */; }; - 08686A702DD1E70500868C70 /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 08686A6F2DD1E70500868C70 /* SnapKit */; }; - 08E424E32DF0B9D800D6ACD3 /* BaseFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 776AD6822DE985C300991745 /* BaseFeature.framework */; }; - 08E424E42DF0B9D800D6ACD3 /* BaseFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 776AD6822DE985C300991745 /* BaseFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 08E424E62DF0B9D900D6ACD3 /* Core.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 778F55F62DE8D7E500684E34 /* Core.framework */; }; - 08E424E72DF0B9D900D6ACD3 /* Core.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 778F55F62DE8D7E500684E34 /* Core.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 08E424E82DF0B9DB00D6ACD3 /* Data.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 778F55FC2DE8D87000684E34 /* Data.framework */; }; - 08E424E92DF0B9DB00D6ACD3 /* Data.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 778F55FC2DE8D87000684E34 /* Data.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 08E424EC2DF0B9DD00D6ACD3 /* Domain.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 778F55F82DE8D7E500684E34 /* Domain.framework */; }; - 08E424ED2DF0B9DD00D6ACD3 /* Domain.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 778F55F82DE8D7E500684E34 /* Domain.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 08E424EE2DF0B9DE00D6ACD3 /* DomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 778F55FA2DE8D7E500684E34 /* DomainInterface.framework */; }; - 08E424EF2DF0B9DE00D6ACD3 /* DomainInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 778F55FA2DE8D7E500684E34 /* DomainInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 08E424F42DF0BA2F00D6ACD3 /* DesignSystem.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0858ABAE2DCFD6940060EBCA /* DesignSystem.framework */; }; - 08E424F52DF0BA2F00D6ACD3 /* DesignSystem.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0858ABAE2DCFD6940060EBCA /* DesignSystem.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 08ED4DD22DCFF895002C21A2 /* RxRelay in Frameworks */ = {isa = PBXBuildFile; productRef = 08ED4DD12DCFF895002C21A2 /* RxRelay */; }; - 08ED4DD42DCFF899002C21A2 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 08ED4DD32DCFF899002C21A2 /* RxSwift */; }; - 778F56002DE8D8D900684E34 /* ReactorKit in Frameworks */ = {isa = PBXBuildFile; productRef = 778F55FF2DE8D8D900684E34 /* ReactorKit */; }; - 77A33E952DD89FB800F14EC1 /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 77A33E942DD89FB800F14EC1 /* RxCocoa */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 0858ABE12DCFD7700060EBCA /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 0858ABA52DCFD6940060EBCA /* Project object */; - proxyType = 1; - remoteGlobalIDString = 0858ABAD2DCFD6940060EBCA; - remoteInfo = DesignSystem; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 08E424E52DF0B9D800D6ACD3 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 08E424EF2DF0B9DE00D6ACD3 /* DomainInterface.framework in Embed Frameworks */, - 08E424F52DF0BA2F00D6ACD3 /* DesignSystem.framework in Embed Frameworks */, - 08E424ED2DF0B9DD00D6ACD3 /* Domain.framework in Embed Frameworks */, - 08E424E92DF0B9DB00D6ACD3 /* Data.framework in Embed Frameworks */, - 08E424E42DF0B9D800D6ACD3 /* BaseFeature.framework in Embed Frameworks */, - 08E424E72DF0B9D900D6ACD3 /* Core.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 0858ABAE2DCFD6940060EBCA /* DesignSystem.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DesignSystem.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 0858ABC92DCFD7560060EBCA /* DesignSystemDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DesignSystemDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 776AD6822DE985C300991745 /* BaseFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BaseFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 778F55F22DE8D7E500684E34 /* AuthFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AuthFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 778F55F42DE8D7E500684E34 /* AuthFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AuthFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 778F55F62DE8D7E500684E34 /* Core.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Core.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 778F55F82DE8D7E500684E34 /* Domain.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Domain.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 778F55FA2DE8D7E500684E34 /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 778F55FC2DE8D87000684E34 /* Data.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Data.framework; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ - 0858ABDA2DCFD7580060EBCA /* Exceptions for "DesignSystemDemo" folder in "DesignSystemDemo" target */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - membershipExceptions = ( - Info.plist, - ); - target = 0858ABC82DCFD7560060EBCA /* DesignSystemDemo */; - }; - 0858ABF72DCFDBB90060EBCA /* Exceptions for "DesignSystem" folder in "DesignSystemDemo" target */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - membershipExceptions = ( - Resource/Image.xcassets, - ); - target = 0858ABC82DCFD7560060EBCA /* DesignSystemDemo */; - }; - 08ED4E072DD07FC5002C21A2 /* Exceptions for "DesignSystem" folder in "DesignSystem" target */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - membershipExceptions = ( - Info.plist, - ); - target = 0858ABAD2DCFD6940060EBCA /* DesignSystem */; - }; -/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ - -/* Begin PBXFileSystemSynchronizedRootGroup section */ - 0858ABB02DCFD6940060EBCA /* DesignSystem */ = { - isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - 08ED4E072DD07FC5002C21A2 /* Exceptions for "DesignSystem" folder in "DesignSystem" target */, - 0858ABF72DCFDBB90060EBCA /* Exceptions for "DesignSystem" folder in "DesignSystemDemo" target */, - ); - path = DesignSystem; - sourceTree = ""; - }; - 0858ABCA2DCFD7560060EBCA /* DesignSystemDemo */ = { - isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - 0858ABDA2DCFD7580060EBCA /* Exceptions for "DesignSystemDemo" folder in "DesignSystemDemo" target */, - ); - path = DesignSystemDemo; - sourceTree = ""; - }; -/* End PBXFileSystemSynchronizedRootGroup section */ - -/* Begin PBXFrameworksBuildPhase section */ - 0858ABAB2DCFD6940060EBCA /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 08686A3D2DD1C8F400868C70 /* SnapKit in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 0858ABC62DCFD7560060EBCA /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 08E424E32DF0B9D800D6ACD3 /* BaseFeature.framework in Frameworks */, - 08ED4DD42DCFF899002C21A2 /* RxSwift in Frameworks */, - 77A33E952DD89FB800F14EC1 /* RxCocoa in Frameworks */, - 08E424E62DF0B9D900D6ACD3 /* Core.framework in Frameworks */, - 08E424F42DF0BA2F00D6ACD3 /* DesignSystem.framework in Frameworks */, - 08E424E82DF0B9DB00D6ACD3 /* Data.framework in Frameworks */, - 08ED4DD22DCFF895002C21A2 /* RxRelay in Frameworks */, - 08E424EE2DF0B9DE00D6ACD3 /* DomainInterface.framework in Frameworks */, - 08E424EC2DF0B9DD00D6ACD3 /* Domain.framework in Frameworks */, - 778F56002DE8D8D900684E34 /* ReactorKit in Frameworks */, - 08686A702DD1E70500868C70 /* SnapKit in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 0858ABA42DCFD6940060EBCA = { - isa = PBXGroup; - children = ( - 0858ABB02DCFD6940060EBCA /* DesignSystem */, - 0858ABCA2DCFD7560060EBCA /* DesignSystemDemo */, - 0858ABDE2DCFD7700060EBCA /* Frameworks */, - 0858ABAF2DCFD6940060EBCA /* Products */, - ); - sourceTree = ""; - }; - 0858ABAF2DCFD6940060EBCA /* Products */ = { - isa = PBXGroup; - children = ( - 0858ABAE2DCFD6940060EBCA /* DesignSystem.framework */, - 0858ABC92DCFD7560060EBCA /* DesignSystemDemo.app */, - ); - name = Products; - sourceTree = ""; - }; - 0858ABDE2DCFD7700060EBCA /* Frameworks */ = { - isa = PBXGroup; - children = ( - 776AD6822DE985C300991745 /* BaseFeature.framework */, - 778F55FC2DE8D87000684E34 /* Data.framework */, - 778F55F22DE8D7E500684E34 /* AuthFeature.framework */, - 778F55F42DE8D7E500684E34 /* AuthFeatureInterface.framework */, - 778F55F62DE8D7E500684E34 /* Core.framework */, - 778F55F82DE8D7E500684E34 /* Domain.framework */, - 778F55FA2DE8D7E500684E34 /* DomainInterface.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 0858ABA92DCFD6940060EBCA /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 0858ABAD2DCFD6940060EBCA /* DesignSystem */ = { - isa = PBXNativeTarget; - buildConfigurationList = 0858ABB42DCFD6940060EBCA /* Build configuration list for PBXNativeTarget "DesignSystem" */; - buildPhases = ( - 0858ABA92DCFD6940060EBCA /* Headers */, - 0858ABAA2DCFD6940060EBCA /* Sources */, - 0858ABAB2DCFD6940060EBCA /* Frameworks */, - 0858ABAC2DCFD6940060EBCA /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - fileSystemSynchronizedGroups = ( - 0858ABB02DCFD6940060EBCA /* DesignSystem */, - ); - name = DesignSystem; - packageProductDependencies = ( - 08686A3C2DD1C8F400868C70 /* SnapKit */, - ); - productName = DesignSystem; - productReference = 0858ABAE2DCFD6940060EBCA /* DesignSystem.framework */; - productType = "com.apple.product-type.framework"; - }; - 0858ABC82DCFD7560060EBCA /* DesignSystemDemo */ = { - isa = PBXNativeTarget; - buildConfigurationList = 0858ABDB2DCFD7580060EBCA /* Build configuration list for PBXNativeTarget "DesignSystemDemo" */; - buildPhases = ( - 0858ABC52DCFD7560060EBCA /* Sources */, - 0858ABC62DCFD7560060EBCA /* Frameworks */, - 0858ABC72DCFD7560060EBCA /* Resources */, - 08E424E52DF0B9D800D6ACD3 /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 0858ABE22DCFD7700060EBCA /* PBXTargetDependency */, - ); - fileSystemSynchronizedGroups = ( - 0858ABCA2DCFD7560060EBCA /* DesignSystemDemo */, - ); - name = DesignSystemDemo; - packageProductDependencies = ( - 08ED4DD12DCFF895002C21A2 /* RxRelay */, - 08ED4DD32DCFF899002C21A2 /* RxSwift */, - 08686A6F2DD1E70500868C70 /* SnapKit */, - 77A33E942DD89FB800F14EC1 /* RxCocoa */, - 778F55FF2DE8D8D900684E34 /* ReactorKit */, - ); - productName = DesignSystemDemo; - productReference = 0858ABC92DCFD7560060EBCA /* DesignSystemDemo.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 0858ABA52DCFD6940060EBCA /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1620; - LastUpgradeCheck = 1620; - TargetAttributes = { - 0858ABAD2DCFD6940060EBCA = { - CreatedOnToolsVersion = 16.2; - LastSwiftMigration = 1620; - }; - 0858ABC82DCFD7560060EBCA = { - CreatedOnToolsVersion = 16.2; - }; - }; - }; - buildConfigurationList = 0858ABA82DCFD6940060EBCA /* Build configuration list for PBXProject "DesignSystem" */; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 0858ABA42DCFD6940060EBCA; - minimizedProjectReferenceProxies = 1; - packageReferences = ( - 0858ABE62DCFD8610060EBCA /* XCRemoteSwiftPackageReference "SnapKit" */, - 08ED4DB82DCFE91F002C21A2 /* XCRemoteSwiftPackageReference "RxSwift" */, - 778F55FE2DE8D8D900684E34 /* XCRemoteSwiftPackageReference "ReactorKit" */, - ); - preferredProjectObjectVersion = 77; - productRefGroup = 0858ABAF2DCFD6940060EBCA /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 0858ABAD2DCFD6940060EBCA /* DesignSystem */, - 0858ABC82DCFD7560060EBCA /* DesignSystemDemo */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 0858ABAC2DCFD6940060EBCA /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 0858ABC72DCFD7560060EBCA /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 0858ABAA2DCFD6940060EBCA /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 0858ABC52DCFD7560060EBCA /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 0858ABE22DCFD7700060EBCA /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 0858ABAD2DCFD6940060EBCA /* DesignSystem */; - targetProxy = 0858ABE12DCFD7700060EBCA /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 0858ABB52DCFD6940060EBCA /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = DesignSystem/Info.plist; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.DesignSystem; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 0858ABB62DCFD6940060EBCA /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = DesignSystem/Info.plist; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.DesignSystem; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; - 0858ABB72DCFD6940060EBCA /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.2; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 0858ABB82DCFD6940060EBCA /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.2; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 0858ABDC2DCFD7580060EBCA /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5QTRMS954; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = DesignSystemDemo/Info.plist; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.MLS.DesignSystemDemo; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = MLSDesignSystemProvisioningProfileDev; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 0858ABDD2DCFD7580060EBCA /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5QTRMS954; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = DesignSystemDemo/Info.plist; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.MLS.DesignSystemDemo; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = MLSDesignSystemProvisioningProfileDev; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 0858ABA82DCFD6940060EBCA /* Build configuration list for PBXProject "DesignSystem" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 0858ABB72DCFD6940060EBCA /* Debug */, - 0858ABB82DCFD6940060EBCA /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 0858ABB42DCFD6940060EBCA /* Build configuration list for PBXNativeTarget "DesignSystem" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 0858ABB52DCFD6940060EBCA /* Debug */, - 0858ABB62DCFD6940060EBCA /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 0858ABDB2DCFD7580060EBCA /* Build configuration list for PBXNativeTarget "DesignSystemDemo" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 0858ABDC2DCFD7580060EBCA /* Debug */, - 0858ABDD2DCFD7580060EBCA /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - 0858ABE62DCFD8610060EBCA /* XCRemoteSwiftPackageReference "SnapKit" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/SnapKit/SnapKit.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 5.7.1; - }; - }; - 08ED4DB82DCFE91F002C21A2 /* XCRemoteSwiftPackageReference "RxSwift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ReactiveX/RxSwift"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 6.9.0; - }; - }; - 778F55FE2DE8D8D900684E34 /* XCRemoteSwiftPackageReference "ReactorKit" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ReactorKit/ReactorKit.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 3.2.0; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 08686A3C2DD1C8F400868C70 /* SnapKit */ = { - isa = XCSwiftPackageProductDependency; - package = 0858ABE62DCFD8610060EBCA /* XCRemoteSwiftPackageReference "SnapKit" */; - productName = SnapKit; - }; - 08686A6F2DD1E70500868C70 /* SnapKit */ = { - isa = XCSwiftPackageProductDependency; - package = 0858ABE62DCFD8610060EBCA /* XCRemoteSwiftPackageReference "SnapKit" */; - productName = SnapKit; - }; - 08ED4DD12DCFF895002C21A2 /* RxRelay */ = { - isa = XCSwiftPackageProductDependency; - package = 08ED4DB82DCFE91F002C21A2 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxRelay; - }; - 08ED4DD32DCFF899002C21A2 /* RxSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 08ED4DB82DCFE91F002C21A2 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxSwift; - }; - 778F55FF2DE8D8D900684E34 /* ReactorKit */ = { - isa = XCSwiftPackageProductDependency; - package = 778F55FE2DE8D8D900684E34 /* XCRemoteSwiftPackageReference "ReactorKit" */; - productName = ReactorKit; - }; - 77A33E942DD89FB800F14EC1 /* RxCocoa */ = { - isa = XCSwiftPackageProductDependency; - package = 08ED4DB82DCFE91F002C21A2 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxCocoa; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 0858ABA52DCFD6940060EBCA /* Project object */; -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/MLS/Presentation/DesignSystem/DesignSystem.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a6..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem.xcodeproj/xcshareddata/xcschemes/DesignSystemDemo.xcscheme b/MLS/Presentation/DesignSystem/DesignSystem.xcodeproj/xcshareddata/xcschemes/DesignSystemDemo.xcscheme deleted file mode 100644 index 76a5f02d..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem.xcodeproj/xcshareddata/xcschemes/DesignSystemDemo.xcscheme +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/.DS_Store b/MLS/Presentation/DesignSystem/DesignSystem/.DS_Store deleted file mode 100644 index 530d0a5a..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/.DS_Store and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/AuthGuideAlert.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/AuthGuideAlert.swift deleted file mode 100644 index f619a3de..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/AuthGuideAlert.swift +++ /dev/null @@ -1,130 +0,0 @@ -import UIKit - -import SnapKit - -public class AuthGuideAlert: GuideAlert { - // MARK: - Type - private enum Constant { - static let iconSize: CGFloat = 24 - static let topSpacing: CGFloat = 14 - static let stackViewTopSpacing: CGFloat = stackViewBottomSpacing * 2 - static let stackViewBottomSpacing: CGFloat = 8 - static let iconSpacing: CGFloat = 5 - } - - public enum AuthGuideAlertType { - case logout - case withdraw - - var mainText: String { - switch self { - case .logout: - "정말 로그아웃 하시겠어요?" - case .withdraw: - "정말 탈퇴 하시겠어요?" - } - } - - var subText: String { - switch self { - case .logout: - "로그아웃하면 저장한 캐릭터,\n북마크한 아이템 정보를 볼 수 없어요." - case .withdraw: - "탈퇴 시, 아래 정보가 삭제 되어 복구가 불가능해요." - } - } - - var ctaText: String { - switch self { - case .logout: - "로그아웃 하기" - case .withdraw: - "탈퇴하기" - } - } - } - - // MARK: - Components - private let contentStackView: UIStackView = { - let view = UIStackView() - view.axis = .vertical - return view - }() - - private let subTextLabel: UILabel = { - let label = UILabel() - label.numberOfLines = 2 - return label - }() - - private lazy var bookmarkStackView = makeStack(icon: .checkMarkFill, text: "북마크 컬렉션") - private lazy var characterStackView = makeStack(icon: .checkMarkFill, text: "캐릭터 정보") - - // MARK: - init - public init(type: AuthGuideAlertType) { - super.init(mainText: type.mainText, ctaText: type.ctaText, cancelText: "취소") - addViews(type: type) - setupConstraints(type: type) - configureUI(type: type) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension AuthGuideAlert { - func addViews(type: AuthGuideAlertType) { - addSubview(contentStackView) - - contentStackView.addArrangedSubview(subTextLabel) - if type == .withdraw { - contentStackView.addArrangedSubview(bookmarkStackView) - contentStackView.addArrangedSubview(characterStackView) - } - } - - func setupConstraints(type: AuthGuideAlertType) { - contentStackView.snp.makeConstraints { make in - make.top.equalTo(mainTextLabel.snp.bottom).offset(Constant.topSpacing) - make.horizontalEdges.equalToSuperview().inset(GuideAlert.Constant.horizontalInset) - } - - if type == .withdraw { - contentStackView.setCustomSpacing(Constant.stackViewTopSpacing, after: subTextLabel) - contentStackView.setCustomSpacing(Constant.stackViewBottomSpacing, after: bookmarkStackView) - } - - buttonStackView.snp.remakeConstraints { make in - make.top.equalTo(contentStackView.snp.bottom).offset(GuideAlert.Constant.verticalSpacing) - make.horizontalEdges.equalToSuperview().inset(GuideAlert.Constant.horizontalInset) - make.bottom.equalToSuperview().inset(GuideAlert.Constant.verticalInset) - make.height.equalTo(GuideAlert.Constant.buttonHeight) - } - } - - func configureUI(type: AuthGuideAlertType) { - subTextLabel.attributedText = .makeStyledString(font: .b_s_r, text: type.subText, color: .neutral700) - } - - func makeStack(icon: UIImage, text: String) -> UIStackView { - let iconView = UIImageView(image: icon) - - let label: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .cp_s_r, text: text, color: .neutral700, alignment: .left) - return label - }() - - iconView.snp.makeConstraints { make in - make.size.equalTo(Constant.iconSize) - } - - let stackView = UIStackView(arrangedSubviews: [iconView, label]) - stackView.axis = .horizontal - stackView.spacing = Constant.stackViewBottomSpacing - return stackView - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/Badge.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/Badge.swift deleted file mode 100644 index 6d7ff623..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/Badge.swift +++ /dev/null @@ -1,102 +0,0 @@ -import UIKit - -import SnapKit - -public final class Badge: UIView { - // MARK: - Type - public enum BadgeStyle { - case element(String) - case preQuest - case currentQuest - case nextQuest - - var font: UIFont? { - switch self { - case .element: - return .cp_s_sb - case .currentQuest: - return .cp_xs_sb - default: - return .cp_xs_r - } - } - - var fontColor: UIColor { - switch self { - case .element, .currentQuest: - return .primary700 - default: - return .neutral600 - } - } - - var backgroundColor: UIColor { - switch self { - case .element, .currentQuest: - return .primary25 - default: - return .neutral100 - } - } - - var text: String { - switch self { - case .element(let text): - return text - case .preQuest: - return "이전 퀘스트" - case .currentQuest: - return "현재 퀘스트" - case .nextQuest: - return "다음 퀘스트" - } - } - } - - private enum Constant { - static let radius: CGFloat = 4 - static let contentInsets: CGFloat = 6 - } - - // MARK: - Components - private let textLabel = UILabel() - - // MARK: - init - public init(style: BadgeStyle) { - super.init(frame: .zero) - - addViews() - setupConstraints() - configureUI(style: style) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension Badge { - func addViews() { - addSubview(textLabel) - } - - func setupConstraints() { - textLabel.snp.makeConstraints { make in - make.edges.equalToSuperview().inset(Constant.contentInsets) - } - } - - func configureUI(style: BadgeStyle) { - layer.cornerRadius = Constant.radius - backgroundColor = style.backgroundColor - textLabel.attributedText = .makeStyledString(font: style.font, text: style.text, color: style.fontColor, lineHeight: 1) - } -} - -public extension Badge { - func update(style: BadgeStyle) { - configureUI(style: style) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/CardList.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/CardList.swift deleted file mode 100644 index 312ac972..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/CardList.swift +++ /dev/null @@ -1,264 +0,0 @@ -import UIKit - -import SnapKit - -public final class CardList: UIView { - // MARK: - Type - public enum CardListType { - case bookmark - case checkbox - case detailStack - case detailStackText // 몬스터 카드일 경우 드롭률 - case detailStackBadge(Badge.BadgeStyle) - - var icon: UIImage? { - switch self { - case .bookmark: - return .bookmarkBorderList - case .checkbox: - return .checkSquare - case .detailStack, .detailStackText, .detailStackBadge: - return nil - } - } - - var selectedIcon: UIImage? { - switch self { - case .bookmark: - return .bookmarkList - case .checkbox: - return .checkSquareFill - case .detailStack, .detailStackText, .detailStackBadge: - return nil - } - } - } - - enum Constant { - static let cardRadius: CGFloat = 16 - static let cardLeadingInset: CGFloat = 12 - static let cardTrailingInset: CGFloat = 16 - static let infoLabelInset: CGFloat = 16 - static let imageRadius: CGFloat = 8 - static let imageInset: CGFloat = 10 - static let imageContentViewSize: CGFloat = 80 - static let stackViewSpacing: CGFloat = 4 - static let iconSize: CGFloat = 24 - static let mapImageSize: CGFloat = 40 - } - - // MARK: - Properties - private var type = CardListType.bookmark - private var icon = UIImage() - private var selectedIcon = UIImage() - - public var isIconSelected: Bool = false { - didSet { - updateIcon() - } - } - - public var mainText: String? { - didSet { - updateMainText() - } - } - - public var subText: String? { - didSet { - updateSubText() - } - } - - public var onIconTapped: (() -> Void)? - - // MARK: - Components - public let imageView = ItemImageView(image: nil, cornerRadius: Constant.imageRadius, inset: Constant.imageInset, backgroundColor: .listMap) - - private lazy var textLabelStackView: UIStackView = { - let view = UIStackView(arrangedSubviews: [mainTextLabel, subTextLabel]) - view.axis = .vertical - view.spacing = Constant.stackViewSpacing - return view - }() - - private let mainTextLabel: UILabel = { - let label = UILabel() - label.numberOfLines = 2 - label.lineBreakMode = .byTruncatingTail - label.lineBreakStrategy = .pushOut - return label - }() - - private let subTextLabel: UILabel = { - let label = UILabel() - label.numberOfLines = 1 - return label - }() - - private let iconButton: UIButton = { - let button = UIButton() - button.setImage(.bookmarkBorder, for: .normal) - return button - }() - - // 드롭률 표시용 라벨 2개 - private let dropTitleLabel: UILabel = { - let label = UILabel() - label.numberOfLines = 1 - return label - }() - - private let dropValueLabel: UILabel = { - let label = UILabel() - label.numberOfLines = 1 - return label - }() - - // 2개 라벨을 세로로 묶는 스택뷰 - private lazy var dropInfoStack: UIStackView = { - let stack = UIStackView(arrangedSubviews: [dropTitleLabel, dropValueLabel]) - stack.axis = .vertical - stack.alignment = .trailing - stack.isHidden = true // 기본은 숨김 - return stack - }() - - private let badge = Badge(style: .currentQuest) - - public init() { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - bindButton() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension CardList { - func addViews() { - addSubview(imageView) - addSubview(textLabelStackView) - addSubview(iconButton) - addSubview(dropInfoStack) - addSubview(badge) - } - - func setupConstraints() { - imageView.snp.makeConstraints { make in - make.top.leading.bottom.equalToSuperview().inset(Constant.cardLeadingInset) - make.size.equalTo(Constant.imageContentViewSize) - } - - textLabelStackView.snp.makeConstraints { make in - make.leading.equalTo(imageView.snp.trailing).offset(Constant.cardLeadingInset) - make.centerY.equalToSuperview() - make.trailing.lessThanOrEqualToSuperview().inset(Constant.cardTrailingInset) - } - - dropInfoStack.snp.makeConstraints { make in - make.centerY.equalToSuperview() - make.trailing.equalToSuperview().inset(Constant.cardTrailingInset) - } - - badge.snp.makeConstraints { make in - make.centerY.equalToSuperview() - make.trailing.equalToSuperview().inset(Constant.cardTrailingInset) - } - - iconButton.snp.makeConstraints { make in - make.centerY.equalToSuperview() - make.trailing.equalToSuperview().inset(Constant.cardTrailingInset) - make.size.equalTo(Constant.iconSize) - } - - textLabelStackView.snp.makeConstraints { make in - make.trailing.lessThanOrEqualTo(dropInfoStack.snp.leading).offset(-Constant.cardLeadingInset) - make.trailing.lessThanOrEqualTo(badge.snp.leading).offset(-Constant.cardLeadingInset) - make.trailing.lessThanOrEqualTo(iconButton.snp.leading).offset(-Constant.cardLeadingInset) - } - } - - func configureUI() { - backgroundColor = .whiteMLS - layer.cornerRadius = Constant.cardRadius - } - - func bindButton() { - iconButton.addAction(UIAction(handler: { [weak self] _ in - guard let self = self else { return } - self.onIconTapped?() - }), for: .touchUpInside) - } - - func updateMainText() { - mainTextLabel.attributedText = .makeStyledString(font: .sub_m_sb, text: mainText, alignment: .left) - } - - func updateSubText() { - subTextLabel.attributedText = .makeStyledString(font: .cp_s_r, text: subText, color: .neutral500, alignment: .left) - } - - func updateIcon() { - iconButton.setImage(isIconSelected ? selectedIcon : icon, for: .normal) - } -} - -public extension CardList { - func setMainText(text: String) { - mainText = text - } - - func setSubText(text: String?) { - subText = text - } - - func setImage(image: UIImage, backgroundColor: UIColor) { - imageView.setImage(image: image, backgroundColor: backgroundColor) - } - - func setMapImage(image: UIImage, backgroundColor: UIColor) { - imageView.setMapImage(image: image, backgroundColor: backgroundColor) - } - - func setSelected(isSelected: Bool) { - isIconSelected = isSelected - } - - func setType(type: CardListType) { - self.type = type - icon = type.icon ?? UIImage() - selectedIcon = type.selectedIcon ?? UIImage() - - switch type { - case .detailStack: - iconButton.isHidden = true - dropInfoStack.isHidden = true - badge.isHidden = true - case .detailStackText: - iconButton.isHidden = true - dropInfoStack.isHidden = false - badge.isHidden = true - case .detailStackBadge(let type): - iconButton.isHidden = true - dropInfoStack.isHidden = false - badge.isHidden = false - badge.update(style: type) - default: - iconButton.isHidden = false - dropInfoStack.isHidden = true - badge.isHidden = true - } - } - - func setDropInfoText(title: String, value: String?) { - dropTitleLabel.attributedText = .makeStyledString(font: .cp_s_r, text: title, color: .neutral700) - dropValueLabel.attributedText = .makeStyledString(font: .sub_m_b, text: value, color: .primary700) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/CheckBoxButton.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/CheckBoxButton.swift deleted file mode 100644 index 96f8553f..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/CheckBoxButton.swift +++ /dev/null @@ -1,253 +0,0 @@ -import UIKit - -import SnapKit - -public final class CheckBoxButton: UIButton { - // MARK: - Types - public enum CheckBoxButtonStyle { - case normal - case listSmall - case listMedium - case listLarge - - public var font: UIFont? { - switch self { - case .normal: - return .sub_m_b - case .listSmall, .listMedium: - return .b_s_r - case .listLarge: - return .b_m_r - } - } - - public var verticalInset: CGFloat { - switch self { - case .normal, .listLarge: - return 16 - case .listSmall: - return 4 - case .listMedium: - return 10 - } - } - - public var subtitleIsHidden: Bool { - switch self { - case .normal: - return false - default: - return true - } - } - - public var rightButtonIsHidden: Bool { - switch self { - case .listMedium: - return false - default: - return true - } - } - - public var backgroundColor: UIColor { - switch self { - case .normal: - return .neutral100 - default: - return .clearMLS - } - } - - public var textColor: UIColor { - switch self { - case .listSmall: - return .neutral700 - default: - return .textColor - } - } - - public var selecteTextColor: UIColor { - switch self { - case .listSmall: - return .primary700 - default: - return .textColor - } - } - - public var height: CGFloat? { - switch self { - case .normal: - return 56 - case .listSmall: - return 32 - case .listMedium: - return 44 - case .listLarge: - return nil - } - } - } - - private enum Constant { - static let imageSize: CGFloat = 24 - static let horizontalInset: CGFloat = 20 - static let labelSpacing: CGFloat = 4 - static let spacing: CGFloat = 8 - static let radius: CGFloat = 8 - } - - // MARK: - Properties - private let style: CheckBoxButtonStyle - - public var mainTitle: String? { - didSet { - updateText() - } - } - - public var subTitle: String? { - didSet { - updateText() - } - } - - override public var isSelected: Bool { - didSet { - updateTintColor() - } - } - - private lazy var contentStackView: UIStackView = { [weak self] in - let view = UIStackView() - view.isUserInteractionEnabled = false - view.spacing = Constant.spacing - return view - }() - - private let labelTrailingView: UIView = .init() - - private let checkIconImageView: UIImageView = { - let image = DesignSystemAsset.image(named: "checkCircleFill")?.withRenderingMode(.alwaysTemplate) - let view = UIImageView(image: image) - return view - }() - - private let buttonTitleLabel: UILabel = .init() - - private let buttonSubTitleLabel: UILabel = .init() - - public let rightButton: UIButton = { - let button = UIButton() - let image = DesignSystemAsset.image(named: "arrowForwardSmall")?.withRenderingMode(.alwaysTemplate) - button.setImage(image, for: .normal) - button.tintColor = .textColor - return button - }() - - // MARK: - init - public init(style: CheckBoxButtonStyle, mainTitle: String?, subTitle: String?) { - self.style = style - self.mainTitle = mainTitle - self.subTitle = subTitle - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } - - override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { - guard !isHidden, isUserInteractionEnabled, alpha > 0.01 else { return nil } - let view = super.hitTest(point, with: event) - if view != self { return view } - let rightPoint = convert(point, to: rightButton) - if rightButton.bounds.contains(rightPoint) && !rightButton.isHidden && rightButton.isUserInteractionEnabled { - return rightButton - } - return view - } -} - -// MARK: - SetUp -private extension CheckBoxButton { - func addViews() { - addSubview(contentStackView) - labelTrailingView.addSubview(buttonTitleLabel) - labelTrailingView.addSubview(buttonSubTitleLabel) - - if style == .listLarge { - contentStackView.addArrangedSubview(labelTrailingView) - contentStackView.addArrangedSubview(UIView()) - contentStackView.addArrangedSubview(checkIconImageView) - } else { - contentStackView.addArrangedSubview(checkIconImageView) - contentStackView.addArrangedSubview(labelTrailingView) - contentStackView.addArrangedSubview(UIView()) - contentStackView.addArrangedSubview(rightButton) - } - } - - func setupConstraints() { - snp.makeConstraints { make in - if let height = style.height { - make.height.equalTo(height) - } - } - - contentStackView.snp.makeConstraints { make in - if style == .listSmall { - make.horizontalEdges.equalToSuperview() - } else { - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - } - make.verticalEdges.equalToSuperview().inset(style.verticalInset) - } - - checkIconImageView.snp.makeConstraints { make in - make.size.equalTo(Constant.imageSize) - } - - buttonTitleLabel.snp.makeConstraints { make in - make.leading.verticalEdges.equalToSuperview() - make.centerY.equalToSuperview() - } - - buttonSubTitleLabel.snp.makeConstraints { make in - make.leading.equalTo(buttonTitleLabel.snp.trailing).offset(Constant.labelSpacing) - make.trailing.equalToSuperview() - make.centerY.equalToSuperview() - } - - rightButton.snp.makeConstraints { make in - make.size.equalTo(Constant.imageSize) - } - } - - func configureUI() { - updateTintColor() - updateText() - - buttonTitleLabel.font = style.font - buttonSubTitleLabel.isHidden = style.subtitleIsHidden - backgroundColor = style.backgroundColor - layer.cornerRadius = Constant.radius - rightButton.isHidden = style.rightButtonIsHidden - } - - func updateTintColor() { - checkIconImageView.tintColor = isSelected ? .primary700 : .neutral300 - buttonTitleLabel.attributedText = .makeStyledString(font: style.font, text: mainTitle, color: isSelected ? style.selecteTextColor : style.textColor) - } - - func updateText() { - buttonTitleLabel.attributedText = .makeStyledString(font: style.font, text: mainTitle, color: style.textColor) - buttonSubTitleLabel.attributedText = .makeStyledString(font: .b_m_r, text: subTitle) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/CollectionList.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/CollectionList.swift deleted file mode 100644 index b6543477..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/CollectionList.swift +++ /dev/null @@ -1,143 +0,0 @@ -import UIKit - -import SnapKit - -public final class CollectionList: UIView { - private enum Constant { - static let imageSize: CGFloat = 36 - static let imageInset: CGFloat = 4 - static let imageSpacing: CGFloat = 4 - static let imageRadius: CGFloat = 6 - static let contentInset: CGFloat = 10 - static let labelLeadingMargin: CGFloat = 20 - static let labelTrailingMargin: CGFloat = 64 - static let iconSize: CGFloat = 24 - static let radius: CGFloat = 12 - } - - // MARK: - Components - private lazy var imageViews: [ItemImageView] = (0 ..< 4).map { _ in - let view = ItemImageView( - image: nil, - cornerRadius: Constant.imageRadius, - inset: Constant.imageInset, - backgroundColor: .neutral200 - ) - return view - } - - private lazy var imageGridView: UIStackView = { - let topRow = UIStackView(arrangedSubviews: Array(imageViews[0...1])) - topRow.axis = .horizontal - topRow.spacing = Constant.imageSpacing - topRow.distribution = .fillEqually - - let bottomRow = UIStackView(arrangedSubviews: Array(imageViews[2...3])) - bottomRow.axis = .horizontal - bottomRow.spacing = Constant.imageSpacing - bottomRow.distribution = .fillEqually - - let stack = UIStackView(arrangedSubviews: [topRow, bottomRow]) - stack.axis = .vertical - stack.spacing = Constant.imageSpacing - return stack - }() - - private let titleLabel: UILabel = { - let label = UILabel() - label.numberOfLines = 1 - label.lineBreakMode = .byTruncatingTail - return label - }() - - private let subtitleLabel: UILabel = { - let label = UILabel() - label.numberOfLines = 1 - return label - }() - - private lazy var textStackView: UIStackView = { - let stack = UIStackView(arrangedSubviews: [titleLabel, subtitleLabel]) - stack.axis = .vertical - stack.spacing = 4 - return stack - }() - - private let clickIcon: UIImageView = { - let view = UIImageView(image: .arrowForwardSmall) - view.tintColor = .black - return view - }() - - // MARK: - Init - override public init(frame: CGRect) { - super.init(frame: frame) - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension CollectionList { - func addViews() { - addSubview(imageGridView) - addSubview(textStackView) - addSubview(clickIcon) - } - - func setupConstraints() { - imageGridView.snp.makeConstraints { make in - make.leading.equalToSuperview().inset(Constant.contentInset) - make.verticalEdges.equalToSuperview().inset(Constant.contentInset) - make.width.height.equalTo((Constant.imageSize * 2) + Constant.imageSpacing) - } - - textStackView.snp.makeConstraints { make in - make.leading.equalTo(imageGridView.snp.trailing).offset(Constant.labelLeadingMargin) - make.centerY.equalToSuperview() - } - - clickIcon.snp.makeConstraints { make in - make.leading.equalTo(textStackView.snp.trailing).offset(Constant.labelTrailingMargin) - make.trailing.equalToSuperview().inset(Constant.contentInset) - make.centerY.equalToSuperview() - make.width.height.equalTo(Constant.iconSize) - } - - imageViews.forEach { - $0.snp.makeConstraints { make in - make.width.height.equalTo(Constant.imageSize) - } - } - } - - func configureUI() { - backgroundColor = .whiteMLS - layer.cornerRadius = Constant.radius - clipsToBounds = true - } -} - -public extension CollectionList { - func setTitle(text: String) { - titleLabel.attributedText = .makeStyledString(font: .b_s_m, text: text, alignment: .left) - } - - func setSubtitle(text: String) { - subtitleLabel.attributedText = .makeStyledString(font: .cp_xs_r, text: text, color: .neutral500, alignment: .left) - } - - func setImages(images: [UIImage?]) { - for (index, view) in imageViews.enumerated() { - let imageView = view.subviews.compactMap { $0 as? UIImageView }.first - print("이미지 뷰 설정") - imageView?.image = index < images.count ? images[index] : nil - } - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/CommonButton.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/CommonButton.swift deleted file mode 100644 index 738acf56..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/CommonButton.swift +++ /dev/null @@ -1,193 +0,0 @@ -import UIKit - -import SnapKit - -public final class CommonButton: UIButton { - // MARK: - Type - public enum CommonButtonStyle { - case normal - case text - case border - - public var height: CGFloat { - switch self { - case .normal, .border: - return 54 - case .text: - return 44 - } - } - - public var backgroundColor: UIColor { - switch self { - case .normal: - .primary700 - case .text, .border: - .clearMLS - } - } - - public var borderColor: UIColor { - switch self { - case .normal, .text: - UIColor.clearMLS - case .border: - UIColor.neutral300 - } - } - - public var textColor: UIColor { - switch self { - case .normal: - .whiteMLS - case .text, .border: - .textColor - } - } - - public var font: UIFont? { - switch self { - case .normal: - .btn_m_b - case .text: - .btn_s_r - case .border: - .btn_m_r - } - } - } - - private enum Constant { - static let height: CGFloat = 54 - static let normalStyleCornerRadius: CGFloat = 8 - static let textLineHeight: CGFloat = 1.2 - static let buttonInsets = NSDirectionalEdgeInsets(top: 16, leading: 20, bottom: 16, trailing: 20) - } - - // MARK: - Properties - private let style: CommonButtonStyle - private var title: String? - private var disabledTitle: String? - - override public var isEnabled: Bool { - didSet { - configureUI() - } - } - - // MARK: - init - public init(style: CommonButtonStyle, title: String?, disabledTitle: String?) { - self.style = style - self.title = title - self.disabledTitle = disabledTitle - super.init(frame: .zero) - configureUI() - } - - public init() { - self.style = .normal - self.title = nil - self.disabledTitle = nil - super.init(frame: .zero) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension CommonButton { - func configureUI() { - var config = UIButton.Configuration.plain() - config.contentInsets = Constant.buttonInsets - - switch style { - case .normal, .border: - config.background.backgroundColor = isEnabled ? style.backgroundColor : .neutral300 - config.background.cornerRadius = Constant.normalStyleCornerRadius - let currentTitle = isEnabled ? title : disabledTitle - config.attributedTitle = AttributedString(.makeStyledString(font: style.font, text: currentTitle, color: isEnabled ? style.textColor : .whiteMLS) ?? .init()) - config.baseForegroundColor = isEnabled ? style.textColor : .whiteMLS - switch style { - case .border: - config.background.strokeColor = isEnabled ? style.borderColor : .neutral300 - config.background.strokeWidth = 1 - default: - break - } - configuration = config - snp.makeConstraints { make in - make.height.equalTo(style.height) - } - case .text: - config.background.backgroundColor = .clear - let currentTitle = isEnabled ? title : disabledTitle - if let textButtonTitle = currentTitle, - let lineHeight = style.font?.lineHeight { - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.minimumLineHeight = lineHeight * Constant.textLineHeight - paragraphStyle.maximumLineHeight = lineHeight * Constant.textLineHeight - paragraphStyle.alignment = .center - - let enabledAttributedString = NSAttributedString( - string: textButtonTitle, - attributes: [ - .foregroundColor: isEnabled ? style.textColor : .neutral700, - .underlineStyle: NSUnderlineStyle.single.rawValue, - .underlineColor: isEnabled ? style.textColor : .neutral700, - .paragraphStyle: paragraphStyle, - .font: style.font ?? UIFont() - ] - ) - config.attributedTitle = AttributedString(enabledAttributedString) - } - configuration = config - } - - configurationUpdateHandler = { [weak self] button in - guard let self = self else { return } - var updatedConfig = button.configuration - switch button.state { - case .highlighted: - switch style { - case .normal: - updatedConfig?.background.backgroundColor = self.style.backgroundColor.withAlphaComponent(0.9) - case .border: - updatedConfig?.background.backgroundColor = UIColor.neutral100 - default: - break - } - default: - updatedConfig?.background.backgroundColor = self.isEnabled ? self.style.backgroundColor : .neutral300 - } - button.configuration = updatedConfig - } - } -} - -public extension CommonButton { - func updateTitle(title: String, disabledTitle: String? = nil) { - self.title = title - if let disabledTitle = disabledTitle { - self.disabledTitle = disabledTitle - } - configureUI() - } - - func updateTitleColor(color: UIColor, for state: UIControl.State = .normal) { - var config = configuration ?? UIButton.Configuration.plain() - - if var attributedTitle = config.attributedTitle { - var container = AttributeContainer() - container.foregroundColor = color - attributedTitle.mergeAttributes(container, mergePolicy: .keepNew) - config.attributedTitle = attributedTitle - } else if let title = title(for: state) { - config.attributedTitle = AttributedString(title, attributes: AttributeContainer([.foregroundColor: color])) - } - - configuration = config - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/DictionaryDetailListView.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/DictionaryDetailListView.swift deleted file mode 100644 index e46953ba..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/DictionaryDetailListView.swift +++ /dev/null @@ -1,132 +0,0 @@ -import SnapKit -import UIKit - -public final class DictionaryDetailListView: UIStackView { - // MARK: - Type - private enum Constant { - static let height: CGFloat = 50 - static let horizontalInset: CGFloat = 7 - static let iconSize: CGFloat = 24 - static let spacing: CGFloat = 9 - } - - // MARK: - Components - private let mainLabel = UILabel() - private let mainButtonLabel = UILabel() - private lazy var mainButton = makeButton(label: mainButtonLabel) - - private let leftSpacer = UIView() - private let rightSpacer = UIView() - - private let mainAdditionalLabel = UILabel() - private let spacer = UIView() - - private let subLabel = UILabel() - private let subButtonLabel = UILabel() - private lazy var subButton = makeButton(label: subButtonLabel) - - private let underLine: UIView = { - let view = UIView() - view.backgroundColor = .neutral200 - return view - }() - - // MARK: - init - public init() { - super.init(frame: .zero) - axis = .horizontal - spacing = Constant.spacing - alignment = .center - - addBaseViews() - setupConstraints() - } - - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -private extension DictionaryDetailListView { - func addBaseViews() { - addArrangedSubview(leftSpacer) - addArrangedSubview(spacer) - addArrangedSubview(rightSpacer) - addSubview(underLine) - } - - func setupConstraints() { - snp.makeConstraints { make in - make.height.equalTo(Constant.height) - } - - leftSpacer.snp.makeConstraints { make in - make.width.equalTo(Constant.horizontalInset) - } - - rightSpacer.snp.makeConstraints { make in - make.width.equalTo(Constant.horizontalInset) - } - - underLine.snp.makeConstraints { make in - make.horizontalEdges.bottom.equalToSuperview() - make.height.equalTo(1) - } - } - - func makeButton(label: UILabel) -> UIButton { - let button = UIButton() - let icon = UIImageView(image: .rightArrow) - - button.addSubview(label) - button.addSubview(icon) - - label.snp.makeConstraints { make in - make.leading.verticalEdges.equalToSuperview() - } - - icon.snp.makeConstraints { make in - make.leading.equalTo(label.snp.trailing) - make.trailing.centerY.equalToSuperview() - make.size.equalTo(Constant.iconSize) - } - - return button - } -} - -extension DictionaryDetailListView { - public func update(mainText: String? = nil, clickableMainText: String? = nil, additionalText: String? = nil, subText: String? = nil, clickableSubText: String? = nil) { - let fixedViews: Set = [leftSpacer, spacer, rightSpacer] - arrangedSubviews - .filter { !fixedViews.contains($0) } - .forEach { removeArrangedSubview($0); $0.removeFromSuperview() } - - insertArrangedSubview(leftSpacer, at: 0) - - if let mainText = mainText { - mainLabel.attributedText = .makeStyledString(font: .sub_m_sb, text: mainText) - insertArrangedSubview(mainLabel, at: 1) - } - - if let clickableMainText = clickableMainText { - mainButtonLabel.attributedText = .makeStyledUnderlinedString(font: .sub_m_sb, text: clickableMainText) - insertArrangedSubview(mainButton, at: arrangedSubviews.firstIndex(of: spacer) ?? 0) - } - - if let additionalText = additionalText { - mainAdditionalLabel.attributedText = .makeStyledString(font: .sub_m_sb, text: additionalText) - insertArrangedSubview(mainAdditionalLabel, at: arrangedSubviews.firstIndex(of: spacer) ?? 0) - } - - if let subText = subText { - subLabel.attributedText = .makeStyledString(font: .btn_s_r, text: subText) - insertArrangedSubview(subLabel, at: arrangedSubviews.firstIndex(of: rightSpacer) ?? 0) - } - - if let clickableSubText = clickableSubText { - subButtonLabel.attributedText = .makeStyledUnderlinedString(font: .btn_s_r, text: clickableSubText) - insertArrangedSubview(subButton, at: arrangedSubviews.firstIndex(of: rightSpacer) ?? 0) - } - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/DividerView.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/DividerView.swift deleted file mode 100644 index 8f636bae..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/DividerView.swift +++ /dev/null @@ -1,19 +0,0 @@ -import UIKit - -import SnapKit - -public final class DividerView: UIView { - // MARK: - init - public init() { - super.init(frame: .zero) - self.backgroundColor = .neutral200 - self.snp.makeConstraints { make in - make.height.equalTo(1) - } - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/DropDownBox/DropDownBox.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/DropDownBox/DropDownBox.swift deleted file mode 100644 index 6e3dbd30..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/DropDownBox/DropDownBox.swift +++ /dev/null @@ -1,184 +0,0 @@ -import UIKit - -import SnapKit - -public final class DropDownBox: UIStackView { - // MARK: - Properties - private var isExpanded = false - private var tableViewHeightConstraint: Constraint? - private var selectedIndex: Int? { - didSet { - tableView.reloadData() - } - } - - public var selectedItem: Item? { - guard let index = selectedIndex, items.indices.contains(index) else { - return nil - } - return items[index] - } - - // 선택 이벤트 콜백 - public var onItemSelected: ((Item) -> Void)? - - public var items = [Item]() { - didSet { - tableView.reloadData() - } - } - - // MARK: - Components - public let inputBox = InputBox() - - private let iconButton: UIButton = { - let view = UIButton() - view.setImage(.arrowDropdown, for: .normal) - return view - }() - - public let tableView: UITableView = { - let tableView = UITableView() - tableView.isHidden = true - tableView.layer.borderWidth = 1 - tableView.layer.cornerRadius = 8 - tableView.layer.borderColor = UIColor.neutral300.cgColor - tableView.separatorStyle = .none - tableView.isScrollEnabled = false - tableView.contentInset = UIEdgeInsets(top: 4, left: 0, bottom: 4, right: 0) - tableView.register(DropDownBoxCell.self, forCellReuseIdentifier: "DropDownCell") - return tableView - }() - - // MARK: - Init - public init(label: String? = nil, placeHodler: String? = nil, items: [Item]) { - self.items = items - super.init(frame: .zero) - - inputBox.label.attributedText = .makeStyledString(font: .b_s_r, text: label, color: .neutral700, alignment: .left) - inputBox.textField.attributedPlaceholder = .makeStyledString(font: .b_m_r, text: placeHodler, color: .neutral500, alignment: .left) - - setupStackView() - setupInputBox() - setupTableView() - configureTap() - } - - @available(*, unavailable) - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Setup -private extension DropDownBox { - func setupStackView() { - axis = .vertical - spacing = 4 - alignment = .fill - addArrangedSubview(inputBox) - addArrangedSubview(tableView) - } - - func setupInputBox() { - inputBox.borderView.addSubview(iconButton) - - inputBox.textField.snp.remakeConstraints { make in - make.verticalEdges.equalToSuperview().inset(16) - make.leading.equalToSuperview().inset(20) - } - - iconButton.snp.makeConstraints { make in - make.centerY.equalToSuperview() - make.leading.equalTo(inputBox.textField.snp.trailing).offset(8) - make.trailing.equalToSuperview().inset(20) - make.size.equalTo(24) - } - - inputBox.borderView.layer.borderColor = UIColor.neutral300.cgColor - inputBox.textField.isUserInteractionEnabled = false - - let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap)) - inputBox.borderView.addGestureRecognizer(tapGesture) - inputBox.borderView.isUserInteractionEnabled = true - } - - func setupTableView() { - tableView.delegate = self - tableView.dataSource = self - - tableView.snp.makeConstraints { make in - make.horizontalEdges.equalTo(inputBox) - tableViewHeightConstraint = make.height.equalTo(0).constraint - } - } - - func configureTap() { - let action = UIAction { [weak self] _ in - self?.toggleDropdown() - } - iconButton.addAction(action, for: .touchUpInside) - } - - func toggleDropdown() { - isExpanded.toggle() - tableView.isHidden = !isExpanded - iconButton.setImage(isExpanded ? .arrowDropUp : .arrowDropdown, for: .normal) - let height = CGFloat(items.count) * 44 + tableView.contentInset.top + tableView.contentInset.bottom - tableViewHeightConstraint?.update(offset: isExpanded ? height : 0) - } - - func removeKeyboard() { - UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) - } - - @objc private func handleTap() { - toggleDropdown() - removeKeyboard() - } -} - -// MARK: - UITableView -extension DropDownBox: UITableViewDataSource, UITableViewDelegate { - public func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return items.count - } - - public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - guard let cell = tableView.dequeueReusableCell(withIdentifier: "DropDownCell", for: indexPath) as? DropDownBoxCell else { - return UITableViewCell() - } - let isSelected = selectedIndex == indexPath.row - cell.injection(with: items[indexPath.row].name, isSelected: isSelected) - cell.selectionStyle = .none - return cell - } - - public func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - selectedIndex = indexPath.row - let selectedItem = items[indexPath.row] - inputBox.textField.attributedText = .makeStyledString(font: .b_m_r, text: selectedItem.name, alignment: .left, lineHeight: 1.0) - inputBox.textField.sendActions(for: .editingChanged) - toggleDropdown() - - onItemSelected?(selectedItem) - } - - public func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { - return 44 - } -} - -// MARK: Model -extension DropDownBox { - public struct Item { - public let name: String - public let id: Int - - public init(name: String, id: Int) { - self.name = name - self.id = id - } - } - -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/DropDownBox/DropDownBoxCell.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/DropDownBox/DropDownBoxCell.swift deleted file mode 100644 index 42c9ee32..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/DropDownBox/DropDownBoxCell.swift +++ /dev/null @@ -1,61 +0,0 @@ -import UIKit - -import SnapKit - -final class DropDownBoxCell: UITableViewCell { - // MARK: - Type - private enum Constant { - static var horizontalInset: CGFloat = 20 - static var verticalInset: CGFloat = 10 - static var cellInset: CGFloat = 4 - static var radius: CGFloat = 8 - } - - // MARK: - Components - private let titleLabel = UILabel() - - private let backgroundColorView: UIView = { - let view = UIView() - view.layer.cornerRadius = Constant.radius - return view - }() - - // MARK: - init - override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) { - super.init(style: style, reuseIdentifier: reuseIdentifier) - addViews() - setupContstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension DropDownBoxCell { - func addViews() { - contentView.addSubview(backgroundColorView) - backgroundColorView.addSubview(titleLabel) - } - - func setupContstraints() { - titleLabel.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.verticalEdges.equalToSuperview().inset(Constant.verticalInset) - } - - backgroundColorView.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.cellInset) - make.verticalEdges.equalToSuperview() - } - } -} - -extension DropDownBoxCell { - func injection(with input: String, isSelected: Bool) { - titleLabel.attributedText = .makeStyledString(font: .b_m_r, text: input, color: isSelected ? .textColor : .neutral500, alignment: .left) - backgroundColorView.backgroundColor = isSelected ? .neutral100 : .clearMLS - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/ErrorMessage.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/ErrorMessage.swift deleted file mode 100644 index fbd63cca..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/ErrorMessage.swift +++ /dev/null @@ -1,69 +0,0 @@ -import UIKit - -import SnapKit - -public final class ErrorMessage: UIView { - private enum Constant { - static let verticalEdgesInset: CGFloat = 8 - static let horizontalEdges: CGFloat = 20 - static let cornerRadius: CGFloat = 18 - static let spacing: CGFloat = 4 - static let height: CGFloat = 36 - static let iconSize: CGFloat = 16 - } - - // MARK: - Properties - private let iconView: UIImageView = { - let view = UIImageView() - view.image = .error - return view - }() - - public let label = UILabel() - - // MARK: - init - public init(message: String?) { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI(message: message) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension ErrorMessage { - func addViews() { - addSubview(iconView) - addSubview(label) - } - - func setupConstraints() { - snp.makeConstraints { make in - make.height.equalTo(Constant.height) - } - - iconView.snp.makeConstraints { make in - make.centerY.equalToSuperview() - make.leading.equalToSuperview().inset(Constant.horizontalEdges) - make.size.equalTo(Constant.iconSize) - } - - label.snp.makeConstraints { make in - make.verticalEdges.equalToSuperview().inset(Constant.verticalEdgesInset) - make.leading.equalTo(self.iconView.snp.trailing).offset(Constant.spacing) - make.trailing.equalToSuperview().inset(Constant.horizontalEdges) - } - } - - func configureUI(message: String?) { - self.backgroundColor = .error100 - self.layer.cornerRadius = Constant.cornerRadius - self.clipsToBounds = true - self.label.attributedText = .makeStyledString(font: .b_s_r, text: message, color: .error900) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/FloatingActionButton.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/FloatingActionButton.swift deleted file mode 100644 index d59f7b17..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/FloatingActionButton.swift +++ /dev/null @@ -1,34 +0,0 @@ -import UIKit - -import SnapKit - -public final class FloatingActionButton: UIButton { - // MARK: - Properties - private var action: (() -> Void)? - - // MARK: - LifeCycle - public init(action: @escaping () -> Void) { - self.action = action - super.init(frame: .zero) - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension FloatingActionButton { - func configureUI() { - setImage(.fab, for: .normal) - layer.cornerRadius = 24 - clipsToBounds = true - addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) - } - - @objc private func buttonTapped() { - action?() - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/GuideAlert.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/GuideAlert.swift deleted file mode 100644 index 0674eddf..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/GuideAlert.swift +++ /dev/null @@ -1,110 +0,0 @@ -import UIKit - -import SnapKit - -public class GuideAlert: UIView { - // MARK: - Type - enum Constant { - static let verticalInset: CGFloat = 20 - static let horizontalInset: CGFloat = 20 - static let iconSize: CGFloat = 48 - static let verticalSpacing: CGFloat = 24 - static let buttonSpacing: CGFloat = 4 - static let buttonHeight: CGFloat = 48 - static let alertWidth: CGFloat = 327 - static let radius: CGFloat = 24 - } - - // MARK: - Components - private let warningIconView: UIImageView = { - let view = UIImageView() - view.image = .warning - return view - }() - - public let mainTextLabel = UILabel() - public let buttonStackView: UIStackView = { - let view = UIStackView() - view.spacing = Constant.buttonSpacing - return view - }() - - public var ctaButton: CommonButton - public var cancelButton: CommonButton? - - // MARK: - init - public init(mainText: String, ctaText: String, cancelText: String?, ctaRatio: Double = 0.7) { - mainTextLabel.attributedText = .makeStyledString(font: .sub_l_b, text: mainText) - self.ctaButton = CommonButton(style: .normal, title: ctaText, disabledTitle: nil) - self.cancelButton = cancelText.map { CommonButton(style: .border, title: $0, disabledTitle: nil) } - mainTextLabel.numberOfLines = 0 - super.init(frame: .zero) - - addViews(cancelText: cancelText) - setupConstraints(ctaRatio: ctaRatio) - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension GuideAlert { - func addViews(cancelText: String?) { - addSubview(warningIconView) - addSubview(mainTextLabel) - addSubview(buttonStackView) - - if let cancelButton = cancelButton { - buttonStackView.addArrangedSubview(cancelButton) - } - buttonStackView.addArrangedSubview(ctaButton) - } - - func setupConstraints(ctaRatio: Double) { - snp.makeConstraints { make in - make.width.equalTo(Constant.alertWidth) - } - - warningIconView.snp.makeConstraints { make in - make.top.equalToSuperview().inset(Constant.verticalInset) - make.centerX.equalToSuperview() - make.size.equalTo(Constant.iconSize) - } - - mainTextLabel.snp.makeConstraints { make in - make.top.equalTo(warningIconView.snp.bottom).offset(Constant.verticalInset) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - } - - buttonStackView.snp.makeConstraints { make in - make.top.equalTo(mainTextLabel.snp.bottom).offset(Constant.verticalSpacing) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.bottom.equalToSuperview().inset(Constant.verticalInset) - make.height.equalTo(Constant.buttonHeight) - } - - if let cancelButton = cancelButton { - let cancelRatio = 1 - ctaRatio - - cancelButton.snp.makeConstraints { make in - make.width.equalTo(buttonStackView.snp.width).multipliedBy(cancelRatio).offset(-Constant.buttonSpacing) - } - ctaButton.snp.makeConstraints { make in - make.width.equalTo(buttonStackView.snp.width).multipliedBy(ctaRatio).offset(-Constant.buttonSpacing) - } - } else { - ctaButton.snp.makeConstraints { make in - make.width.equalTo(buttonStackView.snp.width) - } - } - } - - func configureUI() { - backgroundColor = .whiteMLS - layer.cornerRadius = Constant.radius - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/Header.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/Header.swift deleted file mode 100644 index c0705ed2..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/Header.swift +++ /dev/null @@ -1,102 +0,0 @@ -import UIKit - -import SnapKit - -public final class Header: UIStackView { - // MARK: - Type - public enum HeaderStyle { - case main - case filter - - public var titleFont: UIFont? { - switch self { - case .main: - return .h_xxxl_sb - case .filter: - return .h_xl_sb - } - } - - var icons: [UIImage] { - switch self { - case .main: - return [.search, .bell] - case .filter: - return [.largeX] - } - } - } - - private enum Constant { - static let iconSize: CGFloat = 24 - static let spacing: CGFloat = 16 - static let mainTypeHeight: CGFloat = 44 - } - - // MARK: - Properties - public let style: HeaderStyle - - // MARK: - Components - public let titleLabel = UILabel() - private let spacer = UIView() - public let firstIconButton = UIButton() - public let secondIconButton = UIButton() - - // MARK: - init - public init(style: HeaderStyle, title: String) { - titleLabel.attributedText = .makeStyledString(font: .h_xxxl_sb, text: title) - self.style = style - super.init(frame: .zero) - - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension Header { - func addViews() { - addArrangedSubview(titleLabel) - addArrangedSubview(spacer) - addArrangedSubview(firstIconButton) - if style == .main { - addArrangedSubview(secondIconButton) - } - } - - func setupConstraints() { - if style == .main { - snp.makeConstraints { make in - make.height.equalTo(Constant.mainTypeHeight) - } - } - - firstIconButton.snp.makeConstraints { make in - make.size.equalTo(Constant.iconSize) - } - - secondIconButton.snp.makeConstraints { make in - make.size.equalTo(Constant.iconSize) - } - } - - func configureUI() { - alignment = .center - isLayoutMarginsRelativeArrangement = true - layoutMargins = UIEdgeInsets(top: 0, left: Constant.spacing, bottom: 0, right: Constant.spacing) - axis = .horizontal - spacing = Constant.spacing - titleLabel.font = style.titleFont - titleLabel.textColor = .textColor - firstIconButton.setImage(style.icons[0], for: .normal) - if style == .main { - secondIconButton.setImage(style.icons[1], for: .normal) - } - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/InputBox.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/InputBox.swift deleted file mode 100644 index 9ee776a5..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/InputBox.swift +++ /dev/null @@ -1,105 +0,0 @@ -import UIKit - -import SnapKit - -public final class InputBox: UIStackView { - // MARK: - Properties - private var type: InputBoxType = .edit { - didSet { - setBorderColor() - } - } - - // MARK: - Components - public let label = UILabel() - public let textField: UITextField = { - let textField = UITextField() - textField.clearButtonMode = .whileEditing - return textField - }() - - public lazy var borderView: UIView = { - let view = UIView() - view.layer.cornerRadius = 8 - view.layer.borderWidth = 1 - view.layer.borderColor = UIColor.neutral300.cgColor - - view.addSubview(textField) - - textField.snp.makeConstraints { make in - make.verticalEdges.equalToSuperview().inset(16) - make.leading.equalToSuperview().inset(20) - make.trailing.equalToSuperview().inset(10) - } - return view - }() - - // MARK: - Init - public init(label: String? = nil, placeHodler: String? = nil) { - super.init(frame: .zero) - configureUI(label: label, placeHodler: placeHodler) - } - - @available(*, unavailable) - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension InputBox { - func setupStackView() { - addArrangedSubview(label) - addArrangedSubview(borderView) - - spacing = 4 - axis = .vertical - alignment = .leading - } - - func setupLabel(label: String?) { - self.label.attributedText = .makeStyledString(font: .b_s_r, text: label, color: .neutral700, alignment: .left) - } - - func setupTextField(placeHolder: String?) { - textField.attributedPlaceholder = .makeStyledString(font: .b_m_r, text: placeHolder, color: .neutral500, alignment: .left) - } - - func setupConstaraints() { - borderView.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview() - } - } - - func configureUI(label: String?, placeHodler: String?) { - setupStackView() - setupLabel(label: label) - setupTextField(placeHolder: placeHodler) - setupConstaraints() - } - - func setBorderColor() { - borderView.layer.borderColor = type.borderColor.cgColor - } -} - -// MARK: - Mothods -public extension InputBox { - func setType(type: InputBoxType) { - self.type = type - } -} - -public enum InputBoxType { - case edit - case error - - var borderColor: UIColor { - switch self { - case .edit: - return .neutral300 - case .error: - return .error900 - } - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/ItemImageView.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/ItemImageView.swift deleted file mode 100644 index 57a15624..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/ItemImageView.swift +++ /dev/null @@ -1,54 +0,0 @@ -import UIKit - -import SnapKit - -public final class ItemImageView: UIView { - private let imageView = UIImageView() - - init(image: UIImage?, cornerRadius: CGFloat, inset: CGFloat, backgroundColor: UIColor) { - super.init(frame: .zero) - addViews() - setUpConstraints(inset: inset) - configureUI(radius: cornerRadius) - setImage(image: image, backgroundColor: backgroundColor) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension ItemImageView { - func addViews() { - addSubview(imageView) - } - - func setUpConstraints(inset: CGFloat) { - imageView.snp.makeConstraints { make in - make.edges.equalToSuperview().inset(inset) - } - } - - func configureUI(radius: CGFloat) { - layer.cornerRadius = radius - imageView.contentMode = .scaleAspectFit - imageView.backgroundColor = .clearMLS - } -} - -public extension ItemImageView { - func setImage(image: UIImage?, backgroundColor: UIColor) { - imageView.image = image - self.backgroundColor = backgroundColor - } - - func setMapImage(image: UIImage?, backgroundColor: UIColor) { - setImage(image: image, backgroundColor: backgroundColor) - imageView.snp.remakeConstraints { make in - make.center.equalToSuperview() - make.size.equalTo(40) - } - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/NavigationBar.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/NavigationBar.swift deleted file mode 100644 index a57506b9..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/NavigationBar.swift +++ /dev/null @@ -1,182 +0,0 @@ -import UIKit - -import SnapKit - -public final class NavigationBar: UIView { - // MARK: - Types - public enum NavigationType { - case withUnderLine(String) - case arrowRightLeft - case arrowLeft - case withString(String) - case collection(String) - } - - private enum Constant { - static let spacing: CGFloat = 8 - static let imageSize: CGFloat = 44 - static let rightInset: CGFloat = 16 - static let lineHeight: CGFloat = 1.17 - } - - // MARK: - Properties - private let contentStackView: UIStackView = { - let view = UIStackView() - view.alignment = .center - view.spacing = Constant.spacing - return view - }() - - public let leftButton: UIButton = { - let button = UIButton(type: .system) - button.setImage(.arrowBack.withRenderingMode(.alwaysTemplate), for: .normal) - button.tintColor = .textColor - return button - }() - - public let rightButton: UIButton = { - let button = UIButton(type: .system) - button.setImage(.arrowForward.withRenderingMode(.alwaysTemplate), for: .normal) - button.tintColor = .textColor - return button - }() - - public let underlineTextButton: UIButton = { - let button = UIButton() - button.contentEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10) - return button - }() - - public let boldTextButton: UIButton = { - let button = UIButton() - button.contentEdgeInsets = UIEdgeInsets(top: 0, left: 10, bottom: 0, right: 10) - return button - }() - - private let collectionTitleLabel = UILabel() - public let editButton: UIButton = { - let button = UIButton() - button.setImage(.edit, for: .normal) - return button - }() - - public let addButton: UIButton = { - let button = UIButton() - button.setImage(.addIcon, for: .normal) - return button - }() - - // MARK: - init - public init(type: NavigationType) { - super.init(frame: .zero) - addViews(type: type) - setupConstraints(type: type) - configureUI(type: type) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension NavigationBar { - func addViews(type: NavigationType) { - addSubview(contentStackView) - - switch type { - case .withUnderLine: - contentStackView.addArrangedSubview(leftButton) - contentStackView.addArrangedSubview(UIView()) - contentStackView.addArrangedSubview(underlineTextButton) - case .arrowRightLeft: - contentStackView.addArrangedSubview(leftButton) - contentStackView.addArrangedSubview(UIView()) - contentStackView.addArrangedSubview(rightButton) - case .arrowLeft: - contentStackView.addArrangedSubview(leftButton) - contentStackView.addArrangedSubview(UIView()) - case .withString: - contentStackView.addArrangedSubview(leftButton) - contentStackView.addArrangedSubview(UIView()) - contentStackView.addArrangedSubview(boldTextButton) - case .collection: - contentStackView.addArrangedSubview(leftButton) - contentStackView.addArrangedSubview(collectionTitleLabel) - contentStackView.addArrangedSubview(UIView()) - contentStackView.addArrangedSubview(editButton) - contentStackView.addArrangedSubview(addButton) - } - } - - func setupConstraints(type: NavigationType) { - contentStackView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - leftButton.snp.makeConstraints { make in - make.size.equalTo(Constant.imageSize) - } - switch type { - case .withUnderLine, .arrowRightLeft: - rightButton.snp.makeConstraints { make in - make.size.equalTo(Constant.imageSize) - } - case .withString: - boldTextButton.snp.makeConstraints { make in - make.trailing.equalToSuperview().inset(10) - } - case .collection: - editButton.snp.makeConstraints { make in - make.size.equalTo(Constant.imageSize) - } - addButton.snp.makeConstraints { make in - make.size.equalTo(Constant.imageSize) - } - default: - break - } - } - - func configureUI(type: NavigationType) { - switch type { - case .withUnderLine(let title): - guard let lineHeight = UIFont.b_s_r?.lineHeight, - let font = UIFont.b_m_r else { return } - - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.minimumLineHeight = lineHeight * Constant.lineHeight - paragraphStyle.maximumLineHeight = lineHeight * Constant.lineHeight - paragraphStyle.alignment = .center - - let attributedString = NSAttributedString( - string: title, - attributes: [ - .font: font, - .foregroundColor: UIColor.neutral700, - .underlineStyle: NSUnderlineStyle.single.rawValue, - .underlineColor: UIColor.neutral700, - .paragraphStyle: paragraphStyle - ] - ) - underlineTextButton.setAttributedTitle(attributedString, for: .normal) - case .withString(let title): - boldTextButton.setAttributedTitle( - .makeStyledString(font: .btn_m_b, text: title), - for: .normal - ) - case .collection(let title): - collectionTitleLabel.text = title - collectionTitleLabel.font = .b_m_r - collectionTitleLabel.textColor = .textColor - case .arrowRightLeft, .arrowLeft: - break - } - } -} - -public extension NavigationBar { - func setTitle(title: String) { - collectionTitleLabel.text = title - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/SearchBar.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/SearchBar.swift deleted file mode 100644 index 67008b75..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/SearchBar.swift +++ /dev/null @@ -1,163 +0,0 @@ -import UIKit - -import SnapKit - -public protocol SearchBarDelegate: AnyObject { - func searchBarDidReturn(_ searchBar: SearchBar, text: String) -} - -public final class SearchBar: UIView { - // MARK: - Properties - public weak var searchDelegate: SearchBarDelegate? - - // MARK: - Components - public let backButton: UIButton = { - let button = UIButton(type: .system) - let image = DesignSystemAsset.image(named: "arrowBack")?.withRenderingMode(.alwaysTemplate) - button.setImage(image, for: .normal) - button.tintColor = .textColor - return button - }() - - public let textField: UITextField = { - let textField = UITextField() - textField.font = .b_l_r - textField.textColor = .textColor - textField.attributedPlaceholder = .makeStyledString(font: .b_l_r, text: "찾는 정보를 검색해 보세요", color: .neutral300) - textField.textAlignment = .left - textField.tintColor = .primary300 - textField.returnKeyType = .search - return textField - }() - - private let contentStackView: UIStackView = { - let view = UIStackView() - view.axis = .horizontal - view.alignment = .center - view.spacing = 8 - return view - }() - - public let searchButton: UIButton = { - let button = UIButton(type: .system) - let image = DesignSystemAsset.image(named: "search")?.withRenderingMode(.alwaysTemplate) - button.setImage(image, for: .normal) - button.tintColor = .textColor - return button - }() - - public let clearButton: UIButton = { - let button = UIButton(type: .custom) - let image = DesignSystemAsset.image(named: "textFieldClear") - button.setImage(image, for: .normal) - button.isHidden = true - return button - }() - - private let lineView: UIView = { - let view = UIView() - view.backgroundColor = .neutral300 - return view - }() - - private let fillLineView: UIView = { - let view = UIView() - view.backgroundColor = .primary700 - view.transform = CGAffineTransform(scaleX: 0, y: 1) - return view - }() - - // MARK: - init - public init() { - super.init(frame: .zero) - - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension SearchBar { - func addViews() { - addSubview(contentStackView) - addSubview(lineView) - lineView.addSubview(fillLineView) - - contentStackView.addArrangedSubview(backButton) - contentStackView.addArrangedSubview(textField) - contentStackView.addArrangedSubview(clearButton) - contentStackView.addArrangedSubview(searchButton) - } - - func setupConstraints() { - contentStackView.snp.makeConstraints { make in - make.verticalEdges.leading.equalToSuperview() - make.trailing.equalToSuperview().inset(10) - } - lineView.snp.makeConstraints { make in - make.horizontalEdges.bottom.equalToSuperview() - make.height.equalTo(2) - } - backButton.snp.makeConstraints { make in - make.size.equalTo(44) - } - searchButton.snp.makeConstraints { make in - make.size.equalTo(44) - } - textField.snp.makeConstraints { make in - make.height.equalTo(25) - } - clearButton.snp.makeConstraints { make in - make.size.equalTo(19) - } - fillLineView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } - - func configureUI() { - textField.delegate = self - clearButton.addAction(.init(handler: { [weak self] _ in self?.textField.text = "" }), for: .touchUpInside) - searchButton.addAction(.init(handler: { [weak self] _ in self?.endEditing(true) }), for: .touchUpInside) - } -} - -extension SearchBar: UITextFieldDelegate { - public func textFieldDidBeginEditing(_ textField: UITextField) { - clearButton.isHidden = (textField.text ?? "").isEmpty - UIView.animate(withDuration: 0.35, delay: 0, options: [.curveEaseOut]) { - self.fillLineView.transform = CGAffineTransform.identity - } - } - - public func textFieldDidEndEditing(_ textField: UITextField) { - clearButton.isHidden = true - UIView.animate(withDuration: 0.35, delay: 0, options: [.curveEaseIn]) { - self.fillLineView.transform = CGAffineTransform(scaleX: 0.001, y: 1) - } completion: { _ in - self.fillLineView.transform = CGAffineTransform(scaleX: 0, y: 1) - } - } - - public func textFieldShouldReturn(_ textField: UITextField) -> Bool { - searchDelegate?.searchBarDidReturn(self, text: textField.text ?? "") - - endEditing(true) - clearButton.isHidden = true - return true - } - - public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool { - let currentText = textField.text ?? "" - guard let textRange = Range(range, in: currentText) else { return true } - let updatedText = currentText.replacingCharacters(in: textRange, with: string) - clearButton.isHidden = updatedText.isEmpty || !textField.isFirstResponder - return true - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/SnackBar.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/SnackBar.swift deleted file mode 100644 index d093cf82..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/SnackBar.swift +++ /dev/null @@ -1,115 +0,0 @@ -import UIKit - -import SnapKit - -public final class SnackBar: UIView { - private enum Constant { - static let imageSize: CGFloat = 32 - static let imageInset: CGFloat = 5 - static let horizontalInset: CGFloat = 16 - static let width: CGFloat = 343 - static let height: CGFloat = 48 - static let spacing: CGFloat = 8 - static let radius: CGFloat = 8 - } - - // MARK: - ProPerties - private let type: SnackBarType - - // MARK: - Components - public let imageView: ItemImageView - private let label = UILabel() - private let button = UIButton() - - // MARK: - init - public init(type: SnackBarType, image: UIImage?, imageBackgroundColor: UIColor, text: String, buttonText: String, buttonAction: (() -> Void)?) { - self.type = type - imageView = ItemImageView(image: image, cornerRadius: 3.432, inset: 5, backgroundColor: imageBackgroundColor) - super.init(frame: .zero) - - addViews() - setupConstraints() - configureUI(text: text, buttonText: buttonText, buttonAction: buttonAction) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension SnackBar { - func addViews() { - addSubview(imageView) - addSubview(label) - addSubview(button) - } - - func setupConstraints() { - snp.makeConstraints { make in - make.width.equalTo(Constant.width) - make.height.equalTo(Constant.height) - } - - imageView.snp.makeConstraints { make in - make.centerY.equalToSuperview() - make.leading.equalToSuperview().inset(Constant.horizontalInset) - make.size.equalTo(Constant.imageSize) - } - - label.snp.makeConstraints { make in - make.centerY.equalToSuperview() - make.leading.equalTo(imageView.snp.trailing).offset(Constant.spacing) - } - - button.snp.makeConstraints { make in - make.centerY.equalToSuperview() - make.leading.equalTo(label.snp.trailing) - make.trailing.equalToSuperview().inset(Constant.horizontalInset) - } - - label.setContentHuggingPriority(.defaultLow, for: .horizontal) - label.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - - button.setContentHuggingPriority(.required, for: .horizontal) - button.setContentCompressionResistancePriority(.required, for: .horizontal) - } - - func configureUI(text: String, buttonText: String, buttonAction: (() -> Void)?) { - layer.cornerRadius = Constant.radius - clipsToBounds = true - - label.adjustsFontSizeToFitWidth = true - label.attributedText = .makeStyledString(font: .b_s_r, text: text, color: .whiteMLS, alignment: .left) - - let attributedTitle = NSAttributedString( - string: buttonText, - attributes: [ - .font: UIFont.btn_xs_r ?? UIFont.systemFont(ofSize: 12), - .foregroundColor: UIColor.whiteMLS, - .underlineStyle: NSUnderlineStyle.single.rawValue, - .underlineColor: UIColor.whiteMLS - ] - ) - button.setAttributedTitle(attributedTitle, for: .normal) - button.backgroundColor = .clear - button.addAction(UIAction { _ in - buttonAction?() - }, for: .touchUpInside) - - switch type { - case .normal: - backgroundColor = .neutral900 - case .delete: - backgroundColor = .error900 - } - } -} - -public extension SnackBar { - enum SnackBarType { - case normal - case delete - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/StepIndicator.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/StepIndicator.swift deleted file mode 100644 index 06ffaa7d..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/StepIndicator.swift +++ /dev/null @@ -1,57 +0,0 @@ -import UIKit - -import SnapKit - -public final class StepIndicator: UIStackView { - // MARK: - Type - private enum Constant { - static let circleSize: CGFloat = 8 - static let spacing: CGFloat = 8 - } - - // MARK: - Components - - // MARK: - init - public init(circleCount: Int) { - super.init(frame: .zero) - configureUI(circleCount: circleCount) - } - - @available(*, unavailable) - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension StepIndicator { - func configureUI(circleCount: Int) { - axis = .horizontal - distribution = .fillEqually - spacing = Constant.spacing - - for _ in 0 ..< circleCount { - let view = UIImageView(image: DesignSystemAsset.image(named: "circle")?.withRenderingMode(.alwaysTemplate)) - view.contentMode = .scaleAspectFit - view.tintColor = .neutral300 - addArrangedSubview(view) - } - - arrangedSubviews.forEach { view in - view.snp.makeConstraints { make in - make.size.equalTo(Constant.circleSize) - } - } - } -} - -public extension StepIndicator { - func selectIndicator(index: Int) { - guard index >= 0, index < arrangedSubviews.count else { return } - - arrangedSubviews.enumerated().forEach { circleIndex, view in - guard let circle = view as? UIImageView else { return } - circle.tintColor = (index == circleIndex) ? .primary700 : .neutral300 - } - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/Tabbar/BottomTabBar.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/Tabbar/BottomTabBar.swift deleted file mode 100644 index ab2a2a50..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/Tabbar/BottomTabBar.swift +++ /dev/null @@ -1,105 +0,0 @@ -import UIKit - -import SnapKit - -// MARK: - Model -public struct TabItem { - public var title: String - public var icon: UIImage - - public init(title: String, icon: UIImage) { - self.title = title - self.icon = icon - } -} - -public final class BottomTabBar: UIStackView { - // MARK: - Type - private enum Constant { - static let height: CGFloat = 64 - static let buttonSize: CGFloat = 64 - } - - // MARK: - Properties - public var onTabSelected: ((Int) -> Void)? - - private var tabButtons: [TabButton] = [] - private var selectedIndex: Int = 0 { - didSet { - selectIndex() - } - } - - // MARK: - Init - public init(tabItems: [TabItem], selectedIndex: Int) { - self.selectedIndex = selectedIndex - super.init(frame: .zero) - setUpConstraints() - configureUI(tabItems: tabItems) - setupStackView() - selectIndex() - } - - @available(*, unavailable) - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // MARK: - Setup - - private func setUpConstraints() { - snp.makeConstraints { make in - make.height.equalTo(Constant.height) - } - } - - private func configureUI(tabItems: [TabItem]) { - tabButtons.forEach { $0.removeFromSuperview() } - tabButtons.removeAll() - arrangedSubviews.forEach { removeArrangedSubview($0); $0.removeFromSuperview() } - - for (index, item) in tabItems.enumerated() { - if index > 0 { - let spacer = UIView() - spacer.setContentHuggingPriority(.defaultLow, for: .horizontal) - spacer.setContentCompressionResistancePriority(.defaultLow, for: .horizontal) - addArrangedSubview(spacer) - } - - let button = TabButton(icon: item.icon, text: item.title) - button.tag = index - button.addTarget(self, action: #selector(tabButtonTapped(_:)), for: .touchUpInside) - addArrangedSubview(button) - tabButtons.append(button) - - button.snp.makeConstraints { make in - make.width.equalTo(Constant.buttonSize) - } - } - } - - private func setupStackView() { - backgroundColor = .systemBackground - axis = .horizontal - distribution = .equalSpacing - spacing = 0 - } - - @objc private func tabButtonTapped(_ sender: TabButton) { - let newIndex = sender.tag - guard newIndex != selectedIndex else { return } - selectedIndex = newIndex - onTabSelected?(newIndex) - } - - private func selectIndex() { - for (index, button) in tabButtons.enumerated() { - button.isSelected = (index == selectedIndex) - } - } - - public func selectTab(index: Int) { - guard index != selectedIndex else { return } - selectedIndex = index - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/Tabbar/BottomTabBarController.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/Tabbar/BottomTabBarController.swift deleted file mode 100644 index 5dc4a601..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/Tabbar/BottomTabBarController.swift +++ /dev/null @@ -1,106 +0,0 @@ -import UIKit - -import SnapKit - -public final class BottomTabBarController: UITabBarController { - // MARK: - Type - private enum Constant { - static let horizontalInset: CGFloat = 24 - } - - // MARK: - Components - private let divider = DividerView() - private let tabItems: [TabItem] - private let customTabBar: BottomTabBar - - // MARK: - Init - public init(viewControllers: [UIViewController], tabItems: [TabItem]? = nil, initialIndex: Int = 0) { - let resolvedItems = tabItems ?? [ - TabItem(title: "도감", icon: .dictionary), - TabItem(title: "북마크", icon: .bookmarkList), - TabItem(title: "MY", icon: .mypage) - ] - self.tabItems = resolvedItems - customTabBar = BottomTabBar(tabItems: resolvedItems, selectedIndex: initialIndex) - super.init(nibName: nil, bundle: nil) - configureUI(controllers: viewControllers) - selectedIndex = initialIndex - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override public func viewDidLoad() { - super.viewDidLoad() - addViews() - setupConstraints() - } -} - -// MARK: - SetUp -private extension BottomTabBarController { - func addViews() { - view.addSubview(customTabBar) - view.addSubview(divider) - } - - func setupConstraints() { - divider.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview() - make.bottom.equalTo(customTabBar.snp.top) - } - - customTabBar.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.bottom.equalTo(view.safeAreaLayoutGuide) - } - } - - func configureUI(controllers: [UIViewController]) { - viewControllers = controllers.map { - if $0 is UINavigationController { - return $0 - } else { - return UINavigationController(rootViewController: $0) - } - } - tabBar.isHidden = true - - customTabBar.onTabSelected = { [weak self] index in - UIView.performWithoutAnimation { - self?.selectedIndex = index - self?.customTabBar.selectTab(index: index) - } - } - } -} - -public extension BottomTabBarController { - func setHidden(hidden: Bool, animated: Bool = false) { - guard customTabBar.isHidden != hidden else { return } - - if animated { - UIView.animate(withDuration: 0.3) { - self.customTabBar.alpha = hidden ? 0 : 1 - self.divider.alpha = hidden ? 0 : 1 - } completion: { _ in - self.customTabBar.isHidden = hidden - self.divider.isHidden = hidden - } - } else { - customTabBar.isHidden = hidden - customTabBar.alpha = hidden ? 0 : 1 - divider.isHidden = hidden - divider.alpha = hidden ? 0 : 1 - } - } - - func selectTab(index: Int, animated: Bool = false) { - UIView.performWithoutAnimation { - selectedIndex = index - customTabBar.selectTab(index: index) - } - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/Tabbar/TabButton.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/Tabbar/TabButton.swift deleted file mode 100644 index 664c2ea1..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/Tabbar/TabButton.swift +++ /dev/null @@ -1,73 +0,0 @@ -import UIKit - -import SnapKit - -public final class TabButton: UIButton { - // MARK: - Type - private enum Constant { - static let spacing: CGFloat = 4 - static let iconSize: CGFloat = 24 - } - - // MARK: - Properties - override public var isSelected: Bool { - didSet { - updateUI() - } - } - - // MARK: - Components - private lazy var contentView: UIStackView = { - let view = UIStackView(arrangedSubviews: [iconView, textLabel]) - view.axis = .vertical - view.spacing = Constant.spacing - view.alignment = .center - view.isUserInteractionEnabled = false - return view - }() - - private let iconView = UIImageView() - private let textLabel: UILabel = { - let label = UILabel() - label.textAlignment = .center - return label - }() - - // MARK: - Init - public init(icon: UIImage, text: String) { - super.init(frame: .zero) - iconView.image = icon.withRenderingMode(.alwaysTemplate) - textLabel.text = text - addViews() - setupConstraints() - updateUI() - } - - @available(*, unavailable) - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension TabButton { - func addViews() { - addSubview(contentView) - } - - func setupConstraints() { - contentView.snp.makeConstraints { make in - make.center.equalToSuperview() - } - - iconView.snp.makeConstraints { make in - make.size.equalTo(Constant.iconSize) - } - } - - func updateUI() { - iconView.tintColor = isSelected ? .primary700 : .neutral300 - textLabel.textColor = isSelected ? .primary700 : .neutral700 - textLabel.font = .systemFont(ofSize: 11, weight: isSelected ? .semibold : .regular) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/TagChip.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/TagChip.swift deleted file mode 100644 index 3bb5c967..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/TagChip.swift +++ /dev/null @@ -1,144 +0,0 @@ -import UIKit - -import SnapKit - -public final class TagChip: UIButton { - // MARK: - Type - public enum TagChipStyle { - case normal - case search - - var borderWidth: CGFloat { - switch self { - case .normal: - return 0 - case .search: - return 1 - } - } - - var borderColor: CGColor { - switch self { - case .normal: - return UIColor.clearMLS.cgColor - case .search: - return UIColor.neutral300.cgColor - } - } - - var fontColor: UIColor { - switch self { - case .normal: - return .primary700 - case .search: - return .textColor - } - } - - var backgroundColor: UIColor { - switch self { - case .normal: - return .primary50 - case .search: - return .clearMLS - } - } - - var radius: CGFloat { - switch self { - case .normal: - return 16 - case .search: - return 8 - } - } - - var contentInsets: NSDirectionalEdgeInsets { - switch self { - case .normal: - return .init(top: 4, leading: 12, bottom: 4, trailing: 8) - case .search: - return .init(top: 4, leading: 10, bottom: 4, trailing: 10) - } - } - } - - private enum Constant { - static let height: CGFloat = 32 - static let imageSize: CGFloat = 24 - } - - // MARK: - Properties - public var style: TagChipStyle { - didSet { - updateUI() - } - } - - public var text: String? { - didSet { - updateUI() - } - } - - public let mainTitleLabel: UILabel = { - let label = UILabel() - return label - }() - - public let cancelButton: UIButton = { - let button = UIButton(type: .custom) - return button - }() - - // MARK: - init - public init(style: TagChipStyle, text: String?) { - self.style = style - self.text = text - super.init(frame: .zero) - - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension TagChip { - func setupConstraints() { - addSubview(mainTitleLabel) - addSubview(cancelButton) - snp.makeConstraints { make in - make.height.equalTo(Constant.height) - } - mainTitleLabel.snp.makeConstraints { make in - make.leading.equalToSuperview().inset(style.contentInsets.leading) - make.centerY.equalToSuperview() - } - cancelButton.snp.makeConstraints { make in - make.leading.equalTo(mainTitleLabel.snp.trailing) - make.verticalEdges.equalToSuperview().inset(style.contentInsets.top) - make.size.equalTo(24) - make.trailing.equalToSuperview().inset(style.contentInsets.trailing) - } - } - - func configureUI() { - let image = UIImage.smallX.withRenderingMode(.alwaysTemplate) - cancelButton.setImage(image, for: .normal) - cancelButton.tintColor = style.fontColor - } - - func updateUI() { - backgroundColor = style.backgroundColor - mainTitleLabel.attributedText = .makeStyledString(font: .cp_s_r, text: text, color: style.fontColor) - layer.borderColor = style.borderColor - layer.borderWidth = style.borderWidth - layer.cornerRadius = style.radius - cancelButton.tintColor = style.fontColor - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/TapButton.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/TapButton.swift deleted file mode 100644 index 629fd51b..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/TapButton.swift +++ /dev/null @@ -1,75 +0,0 @@ -import UIKit - -import SnapKit - -public final class TapButton: UIButton { - // MARK: - Type - private enum Constant { - static let height: CGFloat = 34 - static let borderWidth: CGFloat = 1 - static let radius: CGFloat = 17 - static let contentInsets: NSDirectionalEdgeInsets = .init(top: 10, leading: 16, bottom: 10, trailing: 16) - } - - public let mainTitleLabel: UILabel = { - let label = UILabel() - return label - }() - - // MARK: - Properties - override public var isSelected: Bool { - didSet { - updateUI() - } - } - - public var text: String? { - didSet { - updateUI() - } - } - - // MARK: - init - public init(text: String? = nil) { - self.text = text - super.init(frame: .zero) - - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension TapButton { - func setupConstraints() { - snp.makeConstraints { make in - make.height.equalTo(Constant.height) - } - addSubview(mainTitleLabel) - mainTitleLabel.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.contentInsets.leading) - make.verticalEdges.equalToSuperview().inset(Constant.contentInsets.top) - } - } - - func configureUI() { - backgroundColor = .clear - layer.borderWidth = Constant.borderWidth - layer.cornerRadius = Constant.radius - layer.borderColor = isSelected ? UIColor.primary700.cgColor : UIColor.neutral200.cgColor - } - - func updateUI() { - mainTitleLabel.attributedText = .makeStyledString( - font: isSelected ? .cp_s_sb : .cp_s_r, - text: text, - color: isSelected ? .primary700 : .neutral700 - ) - layer.borderColor = isSelected ? UIColor.primary700.cgColor : UIColor.neutral200.cgColor - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/TextButton.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/TextButton.swift deleted file mode 100644 index fa57221a..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/TextButton.swift +++ /dev/null @@ -1,75 +0,0 @@ -import UIKit - -import SnapKit - -public final class TextButton: UIButton { - // MARK: - Type - - private enum Constant { - static let height: CGFloat = 32 - static let iconSize: CGFloat = 16 - static let horizontalInset: CGFloat = 12 - static let spacing: CGFloat = 4 - static let radius: CGFloat = 16 - } - - // MARK: - Properties - public let iconView: UIImageView = { - let view = UIImageView() - view.image = .edit.withRenderingMode(.alwaysTemplate) - view.tintColor = .neutral700 - return view - }() - - public let textLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .btn_s_r, text: "편집", color: .neutral700) - return label - }() - - // MARK: - init - public init() { - super.init(frame: .zero) - - addViews() - setupConstraints() - configureUI() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension TextButton { - func addViews() { - addSubview(iconView) - addSubview(textLabel) - } - - func setupConstraints() { - snp.makeConstraints { make in - make.height.equalTo(Constant.height) - } - - iconView.snp.makeConstraints { make in - make.leading.equalToSuperview().inset(Constant.horizontalInset) - make.centerY.equalToSuperview() - make.size.equalTo(Constant.iconSize) - } - - textLabel.snp.makeConstraints { make in - make.leading.equalTo(iconView.snp.trailing).offset(Constant.spacing) - make.centerY.equalToSuperview() - make.trailing.equalToSuperview().inset(Constant.horizontalInset) - } - } - - func configureUI() { - backgroundColor = .whiteMLS - layer.cornerRadius = Constant.radius - layer.borderWidth = 1 - layer.borderColor = UIColor.neutral300.cgColor - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/Toast.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/Toast.swift deleted file mode 100644 index a889b4c6..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/Toast.swift +++ /dev/null @@ -1,59 +0,0 @@ -import UIKit - -import SnapKit - -public final class Toast: UIView { - private enum Constant { - static let verticalEdgesInset: CGFloat = 16 - static let horizontalEdges: CGFloat = 16 - static let cornerRadius: CGFloat = 8 - } - - // MARK: - Properties - private let toastContentView: UIView = { - let view = UIView() - view.backgroundColor = .neutral900 - return view - }() - - private let label: UILabel = .init() - - // MARK: - init - public init(message: String?) { - super.init(frame: .zero) - - self.addViews() - self.setupConstraints() - self.configureUI(message: message) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension Toast { - func addViews() { - addSubview(self.toastContentView) - toastContentView.addSubview(self.label) - } - - func setupConstraints() { - toastContentView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - - label.snp.makeConstraints { make in - make.verticalEdges.equalToSuperview().inset(Constant.verticalEdgesInset) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalEdges) - } - } - - func configureUI(message: String?) { - layer.cornerRadius = Constant.cornerRadius - clipsToBounds = true - label.attributedText = .makeStyledString(font: .b_s_r, text: message, color: .whiteMLS) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Components/ToggleBox.swift b/MLS/Presentation/DesignSystem/DesignSystem/Components/ToggleBox.swift deleted file mode 100644 index 890de020..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Components/ToggleBox.swift +++ /dev/null @@ -1,69 +0,0 @@ -import UIKit - -import SnapKit - -public final class ToggleBox: UIView { - // MARK: - Type - enum Constant { - static let margin: CGFloat = 20 - static let toggleWidth: CGFloat = 51 - static let toggleHeight: CGFloat = 31 - static let radius: CGFloat = 8 - static let height: CGFloat = 60 - } - - // MARK: - Components - private let textLabel = UILabel() - - public let toggle: UISwitch = { - let button = UISwitch() - button.thumbTintColor = .whiteMLS - button.onTintColor = .primary700 - button.isOn = false - return button - }() - - public init(text: String?) { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI(text: text) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension ToggleBox { - func addViews() { - addSubview(textLabel) - addSubview(toggle) - } - - func setupConstraints() { - snp.makeConstraints { make in - make.height.equalTo(Constant.height) - } - - textLabel.snp.makeConstraints { make in - make.verticalEdges.equalToSuperview().inset(Constant.margin) - make.leading.equalToSuperview().inset(Constant.margin) - } - - toggle.snp.makeConstraints { make in - make.leading.equalTo(textLabel.snp.trailing) - make.trailing.centerY.equalToSuperview().inset(Constant.margin) - make.width.equalTo(Constant.toggleWidth) - make.height.equalTo(Constant.toggleHeight) - } - } - - func configureUI(text: String?) { - textLabel.attributedText = .makeStyledString(font: .sub_m_b, text: text, alignment: .left) - backgroundColor = .neutral100 - layer.cornerRadius = Constant.radius - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Info.plist b/MLS/Presentation/DesignSystem/DesignSystem/Info.plist deleted file mode 100644 index fee620f3..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Info.plist +++ /dev/null @@ -1,15 +0,0 @@ - - - - - ITSAppUsesNonExemptEncryption - - UIAppFonts - - Resource/Fonts/Pretendard-Bold.ttf - Resource/Fonts/Pretendard-SemiBold.ttf - Resource/Fonts/Pretendard-Medium.ttf - Resource/Fonts/Pretendard-Regular.ttf - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Fonts/Pretendard-Bold.ttf b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Fonts/Pretendard-Bold.ttf deleted file mode 100644 index fb07fc65..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Fonts/Pretendard-Bold.ttf and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Fonts/Pretendard-Medium.ttf b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Fonts/Pretendard-Medium.ttf deleted file mode 100644 index 1db67c68..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Fonts/Pretendard-Medium.ttf and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Fonts/Pretendard-Regular.ttf b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Fonts/Pretendard-Regular.ttf deleted file mode 100644 index 01147e99..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Fonts/Pretendard-Regular.ttf and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Fonts/Pretendard-SemiBold.ttf b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Fonts/Pretendard-SemiBold.ttf deleted file mode 100644 index 9f2690f0..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Fonts/Pretendard-SemiBold.ttf and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/AppleLogo.imageset/AppleLogo.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/AppleLogo.imageset/AppleLogo.svg deleted file mode 100644 index 39e20f52..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/AppleLogo.imageset/AppleLogo.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/AppleLogo.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/AppleLogo.imageset/Contents.json deleted file mode 100644 index 52803e85..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/AppleLogo.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "AppleLogo.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideAlert.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideAlert.imageset/Contents.json deleted file mode 100644 index 7911bc12..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideAlert.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "guideAlert.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideAlert.imageset/guideAlert.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideAlert.imageset/guideAlert.png deleted file mode 100644 index c7fa2f9f..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideAlert.imageset/guideAlert.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideArrow1.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideArrow1.imageset/Contents.json deleted file mode 100644 index c540110a..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideArrow1.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "guideArrow1.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideArrow1.imageset/guideArrow1.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideArrow1.imageset/guideArrow1.png deleted file mode 100644 index 07e674cb..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideArrow1.imageset/guideArrow1.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideArrow2.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideArrow2.imageset/Contents.json deleted file mode 100644 index 4e3272ad..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideArrow2.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "guideArrow2.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideArrow2.imageset/guideArrow2.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideArrow2.imageset/guideArrow2.png deleted file mode 100644 index 2b33ee8b..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideArrow2.imageset/guideArrow2.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideIcon.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideIcon.imageset/Contents.json deleted file mode 100644 index 6d1fa50c..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideIcon.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "guideIcon.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideIcon.imageset/guideIcon.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideIcon.imageset/guideIcon.png deleted file mode 100644 index d92f19e2..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/BookmarkOnboarding/guideIcon.imageset/guideIcon.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/DropDown.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/DropDown.imageset/Contents.json deleted file mode 100644 index cd7ddaee..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/DropDown.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "dropDown.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/DropDown.imageset/dropDown.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/DropDown.imageset/dropDown.svg deleted file mode 100644 index 67225443..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/DropDown.imageset/dropDown.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/Fab.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/Fab.imageset/Contents.json deleted file mode 100644 index 4b7e95d7..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/Fab.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "Fab.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/Fab.imageset/Fab.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/Fab.imageset/Fab.svg deleted file mode 100644 index b3840368..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/Fab.imageset/Fab.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/addIcon.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/addIcon.imageset/Contents.json deleted file mode 100644 index b4988ec2..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/addIcon.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "add.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/addIcon.imageset/add.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/addIcon.imageset/add.svg deleted file mode 100644 index 0530ce26..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/addIcon.imageset/add.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowBack.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowBack.imageset/Contents.json deleted file mode 100644 index fa1b15e0..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowBack.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "arrowBack.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowBack.imageset/arrowBack.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowBack.imageset/arrowBack.svg deleted file mode 100644 index 690091c6..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowBack.imageset/arrowBack.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowDropUp.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowDropUp.imageset/Contents.json deleted file mode 100644 index 9df632b0..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowDropUp.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "arrowDropUp.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowDropUp.imageset/arrowDropUp.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowDropUp.imageset/arrowDropUp.svg deleted file mode 100644 index 20352b31..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowDropUp.imageset/arrowDropUp.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowDropdown.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowDropdown.imageset/Contents.json deleted file mode 100644 index 62f4cae1..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowDropdown.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "arrowDropdown.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowDropdown.imageset/arrowDropdown.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowDropdown.imageset/arrowDropdown.svg deleted file mode 100644 index bc11335c..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowDropdown.imageset/arrowDropdown.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowForward.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowForward.imageset/Contents.json deleted file mode 100644 index 21e06750..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowForward.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "arrwoForward.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowForward.imageset/arrwoForward.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowForward.imageset/arrwoForward.svg deleted file mode 100644 index 93f8e30d..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowForward.imageset/arrwoForward.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowForwardSmall.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowForwardSmall.imageset/Contents.json deleted file mode 100644 index 2d79acc7..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowForwardSmall.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "arrowForwordSmall.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowForwardSmall.imageset/arrowForwordSmall.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowForwardSmall.imageset/arrowForwordSmall.svg deleted file mode 100644 index f0d29991..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/arrowForwardSmall.imageset/arrowForwordSmall.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bell.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bell.imageset/Contents.json deleted file mode 100644 index b0db2947..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bell.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "bell.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bell.imageset/bell.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bell.imageset/bell.svg deleted file mode 100644 index 389cbbae..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bell.imageset/bell.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/blurImage.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/blurImage.imageset/Contents.json deleted file mode 100644 index e5e139a0..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/blurImage.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "blurImage.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/blurImage.imageset/blurImage.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/blurImage.imageset/blurImage.png deleted file mode 100644 index c40f1df1..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/blurImage.imageset/blurImage.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmark.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmark.imageset/Contents.json deleted file mode 100644 index b9a0914c..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmark.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "bookmark.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmark.imageset/bookmark.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmark.imageset/bookmark.svg deleted file mode 100644 index 4df98315..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmark.imageset/bookmark.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkBorder.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkBorder.imageset/Contents.json deleted file mode 100644 index 718b074b..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkBorder.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "bookmark_border.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkBorder.imageset/bookmark_border.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkBorder.imageset/bookmark_border.svg deleted file mode 100644 index bf456cff..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkBorder.imageset/bookmark_border.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkBorderList.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkBorderList.imageset/Contents.json deleted file mode 100644 index 684a4e90..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkBorderList.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "bookmarkBorderList.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkBorderList.imageset/bookmarkBorderList.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkBorderList.imageset/bookmarkBorderList.png deleted file mode 100644 index 9fe9661a..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkBorderList.imageset/bookmarkBorderList.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkGrayBorder.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkGrayBorder.imageset/Contents.json deleted file mode 100644 index dda7fb83..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkGrayBorder.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "bookmarkBorder.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkGrayBorder.imageset/bookmarkBorder.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkGrayBorder.imageset/bookmarkBorder.svg deleted file mode 100644 index c3875680..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkGrayBorder.imageset/bookmarkBorder.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkGrayBorderList.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkGrayBorderList.imageset/Contents.json deleted file mode 100644 index e279269b..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkGrayBorderList.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "bookmarkGrayBorderList.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkGrayBorderList.imageset/bookmarkGrayBorderList.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkGrayBorderList.imageset/bookmarkGrayBorderList.svg deleted file mode 100644 index d5ace6ae..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkGrayBorderList.imageset/bookmarkGrayBorderList.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkList.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkList.imageset/Contents.json deleted file mode 100644 index 78cce243..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkList.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "bookmarkList.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkList.imageset/bookmarkList.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkList.imageset/bookmarkList.svg deleted file mode 100644 index dc45cef0..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/bookmarkList.imageset/bookmarkList.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkCircle.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkCircle.imageset/Contents.json deleted file mode 100644 index ce4dc702..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkCircle.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "checkCircle.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkCircle.imageset/checkCircle.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkCircle.imageset/checkCircle.svg deleted file mode 100644 index fd0968fd..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkCircle.imageset/checkCircle.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkCircleFill.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkCircleFill.imageset/Contents.json deleted file mode 100644 index e2e75972..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkCircleFill.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "checkCircleFill.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkCircleFill.imageset/checkCircleFill.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkCircleFill.imageset/checkCircleFill.svg deleted file mode 100644 index cc39a399..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkCircleFill.imageset/checkCircleFill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkMark.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkMark.imageset/Contents.json deleted file mode 100644 index 7f105edc..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkMark.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "checkMark.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkMark.imageset/checkMark.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkMark.imageset/checkMark.svg deleted file mode 100644 index d6f5372f..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkMark.imageset/checkMark.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkMarkFill.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkMarkFill.imageset/Contents.json deleted file mode 100644 index 9976bef5..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkMarkFill.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "checkMarkFill.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkMarkFill.imageset/checkMarkFill.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkMarkFill.imageset/checkMarkFill.svg deleted file mode 100644 index b8409aae..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkMarkFill.imageset/checkMarkFill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkSquare.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkSquare.imageset/Contents.json deleted file mode 100644 index c9e9b7f5..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkSquare.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "checkSquare.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkSquare.imageset/checkSquare.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkSquare.imageset/checkSquare.svg deleted file mode 100644 index 4707e286..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkSquare.imageset/checkSquare.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkSquareFill.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkSquareFill.imageset/Contents.json deleted file mode 100644 index f5c7ed27..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkSquareFill.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "checkSquareFill.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkSquareFill.imageset/checkSquareFill.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkSquareFill.imageset/checkSquareFill.svg deleted file mode 100644 index 7e06b1ad..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/checkSquareFill.imageset/checkSquareFill.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/circle.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/circle.imageset/Contents.json deleted file mode 100644 index acd6921d..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/circle.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "icon_circle.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/circle.imageset/icon_circle.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/circle.imageset/icon_circle.svg deleted file mode 100644 index 54655880..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/circle.imageset/icon_circle.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/dictionary.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/dictionary.imageset/Contents.json deleted file mode 100644 index 2475455d..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/dictionary.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "dictionary.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/dictionary.imageset/dictionary.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/dictionary.imageset/dictionary.svg deleted file mode 100644 index f09313b4..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/dictionary.imageset/dictionary.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/edit.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/edit.imageset/Contents.json deleted file mode 100644 index 13f9713f..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/edit.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "edit.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/edit.imageset/edit.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/edit.imageset/edit.svg deleted file mode 100644 index 35c2ed7d..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/edit.imageset/edit.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/error.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/error.imageset/Contents.json deleted file mode 100644 index 8d95c25b..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/error.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "error.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/error.imageset/error.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/error.imageset/error.svg deleted file mode 100644 index 049788c6..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/error.imageset/error.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/errorBlack.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/errorBlack.imageset/Contents.json deleted file mode 100644 index 8d95c25b..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/errorBlack.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "error.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/errorBlack.imageset/error.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/errorBlack.imageset/error.svg deleted file mode 100644 index e74491e2..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/errorBlack.imageset/error.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/errorImage.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/errorImage.imageset/Contents.json deleted file mode 100644 index 5179fc52..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/errorImage.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "errorImage.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/errorImage.imageset/errorImage.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/errorImage.imageset/errorImage.png deleted file mode 100644 index e5204398..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/errorImage.imageset/errorImage.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/favorite.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/favorite.imageset/Contents.json deleted file mode 100644 index 33e62908..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/favorite.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "favorite_true.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/favorite.imageset/favorite_true.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/favorite.imageset/favorite_true.svg deleted file mode 100644 index d47569a5..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/favorite.imageset/favorite_true.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/filter.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/filter.imageset/Contents.json deleted file mode 100644 index 01d6c7dd..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/filter.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "filter.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/filter.imageset/filter.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/filter.imageset/filter.svg deleted file mode 100644 index 131b98da..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/filter.imageset/filter.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/blueSnail.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/blueSnail.imageset/Contents.json deleted file mode 100644 index f0818241..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/blueSnail.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "blueSnail.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/blueSnail.imageset/blueSnail.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/blueSnail.imageset/blueSnail.png deleted file mode 100644 index 50788978..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/blueSnail.imageset/blueSnail.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/blueSnailSelected.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/blueSnailSelected.imageset/Contents.json deleted file mode 100644 index b936cfb1..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/blueSnailSelected.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "blueSnailSelected.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/blueSnailSelected.imageset/blueSnailSelected.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/blueSnailSelected.imageset/blueSnailSelected.png deleted file mode 100644 index ccac9342..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/blueSnailSelected.imageset/blueSnailSelected.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/juniorYeti.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/juniorYeti.imageset/Contents.json deleted file mode 100644 index d25c043c..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/juniorYeti.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "juniorYeti.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/juniorYeti.imageset/juniorYeti.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/juniorYeti.imageset/juniorYeti.png deleted file mode 100644 index 7d692953..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/juniorYeti.imageset/juniorYeti.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/juniorYetiSelected.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/juniorYetiSelected.imageset/Contents.json deleted file mode 100644 index 52ceecf0..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/juniorYetiSelected.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "juniorYetiSelected.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/juniorYetiSelected.imageset/juniorYetiSelected.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/juniorYetiSelected.imageset/juniorYetiSelected.png deleted file mode 100644 index c81772ef..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/juniorYetiSelected.imageset/juniorYetiSelected.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroom.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroom.imageset/Contents.json deleted file mode 100644 index 3a330589..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroom.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "mushroom.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroom.imageset/mushroom.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroom.imageset/mushroom.png deleted file mode 100644 index 0773ae4f..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroom.imageset/mushroom.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroomSelected.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroomSelected.imageset/Contents.json deleted file mode 100644 index be7cc9af..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroomSelected.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "mushroomSelected.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroomSelected.imageset/mushroomSelected.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroomSelected.imageset/mushroomSelected.png deleted file mode 100644 index a502b616..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroomSelected.imageset/mushroomSelected.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroomTest.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroomTest.imageset/Contents.json deleted file mode 100644 index a6efc45b..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroomTest.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "mushroomTest.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroomTest.imageset/mushroomTest.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroomTest.imageset/mushroomTest.png deleted file mode 100644 index 9a90b6c9..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/mushroomTest.imageset/mushroomTest.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/pepe.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/pepe.imageset/Contents.json deleted file mode 100644 index b50a2622..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/pepe.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "pepe.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/pepe.imageset/pepe.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/pepe.imageset/pepe.png deleted file mode 100644 index 69653047..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/pepe.imageset/pepe.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/pepeSelected.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/pepeSelected.imageset/Contents.json deleted file mode 100644 index d2fd897d..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/pepeSelected.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "pepeSelected.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/pepeSelected.imageset/pepeSelected.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/pepeSelected.imageset/pepeSelected.png deleted file mode 100644 index 3657aa09..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/pepeSelected.imageset/pepeSelected.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/rash.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/rash.imageset/Contents.json deleted file mode 100644 index 9c8da93a..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/rash.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "rash.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/rash.imageset/rash.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/rash.imageset/rash.png deleted file mode 100644 index 5f095627..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/rash.imageset/rash.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/rashSelected.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/rashSelected.imageset/Contents.json deleted file mode 100644 index 11fa673c..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/rashSelected.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "rashSelected.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/rashSelected.imageset/rashSelected.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/rashSelected.imageset/rashSelected.png deleted file mode 100644 index f63ae757..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/rashSelected.imageset/rashSelected.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/slime.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/slime.imageset/Contents.json deleted file mode 100644 index 4ced3bf3..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/slime.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "slime.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/slime.imageset/slime.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/slime.imageset/slime.png deleted file mode 100644 index 4278e35a..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/slime.imageset/slime.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/slimeSelected.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/slimeSelected.imageset/Contents.json deleted file mode 100644 index 5722705d..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/slimeSelected.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "slimeSelected.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/slimeSelected.imageset/slimeSelected.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/slimeSelected.imageset/slimeSelected.png deleted file mode 100644 index fdb91b6f..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/slimeSelected.imageset/slimeSelected.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/starPixie.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/starPixie.imageset/Contents.json deleted file mode 100644 index 70545b1b..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/starPixie.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "starpixie.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/starPixie.imageset/starpixie.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/starPixie.imageset/starpixie.png deleted file mode 100644 index 6cd9d7de..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/starPixie.imageset/starpixie.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/starPixieSelected.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/starPixieSelected.imageset/Contents.json deleted file mode 100644 index e68397ab..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/starPixieSelected.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "starPixieSelected.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/starPixieSelected.imageset/starPixieSelected.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/starPixieSelected.imageset/starPixieSelected.png deleted file mode 100644 index 09fd755c..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/starPixieSelected.imageset/starPixieSelected.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/wraith.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/wraith.imageset/Contents.json deleted file mode 100644 index 18c2f1df..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/wraith.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "wraith.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/wraith.imageset/wraith.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/wraith.imageset/wraith.png deleted file mode 100644 index b6c4015e..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/wraith.imageset/wraith.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/wraithSelected.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/wraithSelected.imageset/Contents.json deleted file mode 100644 index 170ee7e2..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/wraithSelected.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "wraithSelected.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/wraithSelected.imageset/wraithSelected.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/wraithSelected.imageset/wraithSelected.png deleted file mode 100644 index 335885e3..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/wraithSelected.imageset/wraithSelected.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/yeti.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/yeti.imageset/Contents.json deleted file mode 100644 index 01fd28ee..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/yeti.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "yeti.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/yeti.imageset/yeti.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/yeti.imageset/yeti.png deleted file mode 100644 index 190ceb41..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/yeti.imageset/yeti.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/yetiSelected.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/yetiSelected.imageset/Contents.json deleted file mode 100644 index 439a9018..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/yetiSelected.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "yetiSelected.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/yetiSelected.imageset/yetiSelected.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/yetiSelected.imageset/yetiSelected.png deleted file mode 100644 index 4db0974f..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/illustration/yetiSelected.imageset/yetiSelected.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/Login_KV_img.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/Login_KV_img.imageset/Contents.json deleted file mode 100644 index 0ec129e8..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/Login_KV_img.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "Login_KV_img.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/Login_KV_img.imageset/Login_KV_img.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/Login_KV_img.imageset/Login_KV_img.png deleted file mode 100644 index 1e6d15d3..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/Login_KV_img.imageset/Login_KV_img.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/addToCollection.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/addToCollection.imageset/Contents.json deleted file mode 100644 index ed70f822..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/addToCollection.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "addToCollection.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/addToCollection.imageset/addToCollection.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/addToCollection.imageset/addToCollection.png deleted file mode 100644 index 4c38fbf8..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/addToCollection.imageset/addToCollection.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/appleImage.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/appleImage.imageset/Contents.json deleted file mode 100644 index b3712ae4..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/appleImage.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "appleImage.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/appleImage.imageset/appleImage.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/appleImage.imageset/appleImage.png deleted file mode 100644 index e6038fb5..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/appleImage.imageset/appleImage.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/connectionError.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/connectionError.imageset/Contents.json deleted file mode 100644 index fac1a53c..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/connectionError.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "connectionError.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/connectionError.imageset/connectionError.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/connectionError.imageset/connectionError.png deleted file mode 100644 index 75604d9b..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/connectionError.imageset/connectionError.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/fabHint.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/fabHint.imageset/Contents.json deleted file mode 100644 index e1484a1b..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/fabHint.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "fabHint.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/fabHint.imageset/fabHint.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/fabHint.imageset/fabHint.png deleted file mode 100644 index 82a2ea35..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/fabHint.imageset/fabHint.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/getNotify.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/getNotify.imageset/Contents.json deleted file mode 100644 index d14b19a0..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/getNotify.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "getNotify.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/getNotify.imageset/getNotify.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/getNotify.imageset/getNotify.png deleted file mode 100644 index 9fee5ecf..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/getNotify.imageset/getNotify.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/kakaoImage.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/kakaoImage.imageset/Contents.json deleted file mode 100644 index 8298ca5d..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/kakaoImage.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "kakaoImage.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/kakaoImage.imageset/kakaoImage.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/kakaoImage.imageset/kakaoImage.png deleted file mode 100644 index ef883fa6..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/kakaoImage.imageset/kakaoImage.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/noResult.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/noResult.imageset/Contents.json deleted file mode 100644 index e0b54f5a..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/noResult.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "noResult.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/noResult.imageset/noResult.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/noResult.imageset/noResult.png deleted file mode 100644 index 574e37d7..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/noResult.imageset/noResult.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/noShowList.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/noShowList.imageset/Contents.json deleted file mode 100644 index 402e6280..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/noShowList.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "noShowList.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/noShowList.imageset/noShowList.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/noShowList.imageset/noShowList.png deleted file mode 100644 index e90300c0..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/noShowList.imageset/noShowList.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/onBoardingBookmark.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/onBoardingBookmark.imageset/Contents.json deleted file mode 100644 index ed18840a..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/onBoardingBookmark.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "bookmarkList.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/onBoardingBookmark.imageset/bookmarkList.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/onBoardingBookmark.imageset/bookmarkList.png deleted file mode 100644 index 988fc8e7..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/onBoardingBookmark.imageset/bookmarkList.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/questionNotify.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/questionNotify.imageset/Contents.json deleted file mode 100644 index a71a5df4..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/questionNotify.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "questionNotify.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/questionNotify.imageset/questionNotify.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/questionNotify.imageset/questionNotify.png deleted file mode 100644 index d7c51a5d..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/questionNotify.imageset/questionNotify.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/recentLoginLogo.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/recentLoginLogo.imageset/Contents.json deleted file mode 100644 index c1fb5668..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/recentLoginLogo.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "recentLoginLogo.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/recentLoginLogo.imageset/recentLoginLogo.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/recentLoginLogo.imageset/recentLoginLogo.png deleted file mode 100644 index 4afde34f..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/recentLoginLogo.imageset/recentLoginLogo.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/settingsHint.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/settingsHint.imageset/Contents.json deleted file mode 100644 index 4c241a10..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/settingsHint.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "settingsHint.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/settingsHint.imageset/settingsHint.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/settingsHint.imageset/settingsHint.png deleted file mode 100644 index 76be1394..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/image/settingsHint.imageset/settingsHint.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/kakaoLogo.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/kakaoLogo.imageset/Contents.json deleted file mode 100644 index 332f97e7..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/kakaoLogo.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "kakaoLogo.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/kakaoLogo.imageset/kakaoLogo.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/kakaoLogo.imageset/kakaoLogo.svg deleted file mode 100644 index 43ac1413..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/kakaoLogo.imageset/kakaoLogo.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/largeX.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/largeX.imageset/Contents.json deleted file mode 100644 index f93a7f69..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/largeX.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "x-black_big.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/largeX.imageset/x-black_big.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/largeX.imageset/x-black_big.svg deleted file mode 100644 index d793ff8a..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/largeX.imageset/x-black_big.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/lineArrowDown.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/lineArrowDown.imageset/Contents.json deleted file mode 100644 index 1012cc97..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/lineArrowDown.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "lineArrowDown.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/lineArrowDown.imageset/lineArrowDown.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/lineArrowDown.imageset/lineArrowDown.svg deleted file mode 100644 index 67225443..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/lineArrowDown.imageset/lineArrowDown.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/logo.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/logo.imageset/Contents.json deleted file mode 100644 index 5f670ca8..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/logo.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "logo.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/logo.imageset/logo.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/logo.imageset/logo.png deleted file mode 100644 index 0c524885..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/logo.imageset/logo.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/mypage.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/mypage.imageset/Contents.json deleted file mode 100644 index 171be441..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/mypage.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "mypage_true.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/mypage.imageset/mypage_true.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/mypage.imageset/mypage_true.svg deleted file mode 100644 index 89cd6bd5..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/mypage.imageset/mypage_true.svg +++ /dev/null @@ -1,5 +0,0 @@ - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/plusIcon.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/plusIcon.imageset/Contents.json deleted file mode 100644 index ccdb0f7e..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/plusIcon.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "plusicon.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/plusIcon.imageset/plusicon.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/plusIcon.imageset/plusicon.svg deleted file mode 100644 index c1ecbac2..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/plusIcon.imageset/plusicon.svg +++ /dev/null @@ -1,10 +0,0 @@ - - - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/rightArrow.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/rightArrow.imageset/Contents.json deleted file mode 100644 index bfef48d9..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/rightArrow.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "rightArrow.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/rightArrow.imageset/rightArrow.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/rightArrow.imageset/rightArrow.svg deleted file mode 100644 index d722791e..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/rightArrow.imageset/rightArrow.svg +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/search.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/search.imageset/Contents.json deleted file mode 100644 index e4d0b2c4..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/search.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "seach.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/search.imageset/seach.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/search.imageset/seach.svg deleted file mode 100644 index e1f774eb..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/search.imageset/seach.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/smallX.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/smallX.imageset/Contents.json deleted file mode 100644 index e29acd20..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/smallX.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "x-black.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/smallX.imageset/x-black.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/smallX.imageset/x-black.svg deleted file mode 100644 index e530a67c..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/smallX.imageset/x-black.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/testImage.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/testImage.imageset/Contents.json deleted file mode 100644 index 6a9ec0f9..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/testImage.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "testImage.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/testImage.imageset/testImage.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/testImage.imageset/testImage.png deleted file mode 100644 index 95973c2a..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/testImage.imageset/testImage.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/testImage2.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/testImage2.imageset/Contents.json deleted file mode 100644 index d114ab7e..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/testImage2.imageset/Contents.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "images" : [ - { - "filename" : "image.png", - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/testImage2.imageset/image.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/testImage2.imageset/image.png deleted file mode 100644 index 0fc3ba70..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/testImage2.imageset/image.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/textFieldClear.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/textFieldClear.imageset/Contents.json deleted file mode 100644 index 7080485b..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/textFieldClear.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "textFieldClear.png", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/textFieldClear.imageset/textFieldClear.png b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/textFieldClear.imageset/textFieldClear.png deleted file mode 100644 index 5be83d97..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/textFieldClear.imageset/textFieldClear.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/warning.imageset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/warning.imageset/Contents.json deleted file mode 100644 index d07182d3..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/warning.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "warning.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/warning.imageset/warning.svg b/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/warning.imageset/warning.svg deleted file mode 100644 index e6980bf6..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Resource/Image.xcassets/warning.imageset/warning.svg +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Utills/DesignSystemAsset.swift b/MLS/Presentation/DesignSystem/DesignSystem/Utills/DesignSystemAsset.swift deleted file mode 100644 index 44dbad79..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Utills/DesignSystemAsset.swift +++ /dev/null @@ -1,50 +0,0 @@ -import UIKit - -public enum DesignSystemAsset { - static let bundle: Bundle = { - // 모듈의 번들을 특정 클래스 기반으로 가져옴 - return Bundle(for: DesignSystemMarker.self) - }() - - public static func image(named name: String) -> UIImage? { - return UIImage(named: name, in: bundle, compatibleWith: nil) - } -} - -/// Marker 클래스 - 번들 식별용 -private class DesignSystemMarker {} - -public enum MapleIllustration { - case mushroom - case slime - case blueSnail - case juniorYeti - case yeti - case pepe - case wraith - case starPixie - case rash - - public var url: String { - switch self { - case .mushroom: - "https://maple-db-team-s3.s3.ap-northeast-2.amazonaws.com/profile-images/profile_1.jpg" - case .slime: - "https://maple-db-team-s3.s3.ap-northeast-2.amazonaws.com/profile-images/profile_2.jpg" - case .blueSnail: - "https://maple-db-team-s3.s3.ap-northeast-2.amazonaws.com/profile-images/profile_3.jpg" - case .juniorYeti: - "https://maple-db-team-s3.s3.ap-northeast-2.amazonaws.com/profile-images/profile_4.jpg" - case .yeti: - "https://maple-db-team-s3.s3.ap-northeast-2.amazonaws.com/profile-images/profile_5.jpg" - case .pepe: - "https://maple-db-team-s3.s3.ap-northeast-2.amazonaws.com/profile-images/profile_6.jpg" - case .wraith: - "https://maple-db-team-s3.s3.ap-northeast-2.amazonaws.com/profile-images/profile_7.jpg" - case .starPixie: - "https://maple-db-team-s3.s3.ap-northeast-2.amazonaws.com/profile-images/profile_8.jpg" - case .rash: - "https://maple-db-team-s3.s3.ap-northeast-2.amazonaws.com/profile-images/profile_9.jpg" - } - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Utills/Extension/UIButton+.swift b/MLS/Presentation/DesignSystem/DesignSystem/Utills/Extension/UIButton+.swift deleted file mode 100644 index 5c6822be..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Utills/Extension/UIButton+.swift +++ /dev/null @@ -1,21 +0,0 @@ -import UIKit - -extension UIButton { - func setUnderlinedTitle(title: String, font: UIFont?, state: UIControl.State = .normal, textInsets: UIEdgeInsets = .zero) { - guard let font = font else { return } - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.minimumLineHeight = 0 - paragraphStyle.lineBreakMode = .byTruncatingTail - paragraphStyle.maximumLineHeight = font.lineHeight * 1.17 - - let attributes: [NSAttributedString.Key: Any] = [ - .underlineStyle: NSUnderlineStyle.single.rawValue, - .font: font, - .paragraphStyle: paragraphStyle - ] - - let attributedString = NSAttributedString(string: title, attributes: attributes) - setAttributedTitle(attributedString, for: state) - titleEdgeInsets = textInsets - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Utills/Extension/UIColor+.swift b/MLS/Presentation/DesignSystem/DesignSystem/Utills/Extension/UIColor+.swift deleted file mode 100644 index b3c62f6e..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Utills/Extension/UIColor+.swift +++ /dev/null @@ -1,58 +0,0 @@ -import UIKit - -public extension UIColor { - static let primary900 = UIColor(hexCode: "EE500C") - static let primary700 = UIColor(hexCode: "FF5C00") - static let primary500 = UIColor(hexCode: "FF7D33") - static let primary300 = UIColor(hexCode: "FF9D66") - static let primary100 = UIColor(hexCode: "FFBE9A") - static let primary50 = UIColor(hexCode: "FFE6D8") - static let primary25 = UIColor(hexCode: "FFF1E9") - - static let secondary = UIColor(hexCode: "FFAA00") - static let textColor = UIColor(hexCode: "1D1D1F") - - static let neutral900 = UIColor(hexCode: "313131") - static let neutral700 = UIColor(hexCode: "575757") - static let neutral600 = UIColor(hexCode: "848484") - static let neutral500 = UIColor(hexCode: "AFAFAF") - static let neutral300 = UIColor(hexCode: "CFCFCF") - static let neutral200 = UIColor(hexCode: "E9E9E9") - static let neutral100 = UIColor(hexCode: "F5F5F5") - - static let whiteMLS = UIColor(hexCode: "FFFFFF") - static let clearMLS = UIColor(hexCode: "FFFFFF", alpha: 0) - - static let error900 = UIColor(hexCode: "FF4B4B") - static let error100 = UIColor(hexCode: "FFEFEF") - - static let success = UIColor(hexCode: "15CC00") - static let redMLS = UIColor(hexCode: "FF0000") - static let overlays = UIColor(hexCode: "000000", alpha: 0.2) - - static let listMonster = UIColor(hexCode: "FFEFCE") - static let listItem = UIColor(hexCode: "F1EEFC") - static let listMap = UIColor(hexCode: "EEF9E0") - static let listNPC = UIColor(hexCode: "E0EFF9") - static let listQuest = UIColor(hexCode: "FFECEF") - - convenience init(hexCode: String, alpha: CGFloat = 1.0) { - var hexFormatted: String = hexCode.trimmingCharacters(in: CharacterSet.whitespacesAndNewlines).uppercased() - - if hexFormatted.hasPrefix("#") { - hexFormatted = String(hexFormatted.dropFirst()) - } - - assert(hexFormatted.count == 6, "Invalid hex code used.") - - var rgbValue: UInt64 = 0 - Scanner(string: hexFormatted).scanHexInt64(&rgbValue) - - self.init( - red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0, - green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0, - blue: CGFloat(rgbValue & 0x0000FF) / 255.0, - alpha: alpha - ) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Utills/Extension/UIFont+.swift b/MLS/Presentation/DesignSystem/DesignSystem/Utills/Extension/UIFont+.swift deleted file mode 100644 index 3873351e..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Utills/Extension/UIFont+.swift +++ /dev/null @@ -1,48 +0,0 @@ -// swiftlint:disable all - -import UIKit - -public extension UIFont { - static let h_xxxl_b = korFont(style: .bold, size: 24) - static let h_xxxl_sb = korFont(style: .semiBold, size: 24) - - static let h_xxl_b = korFont(style: .bold, size: 22) - - static let h_xl_b = korFont(style: .bold, size: 20) - static let h_xl_sb = korFont(style: .semiBold, size: 20) - static let h_xl_r = korFont(style: .regular, size: 20) - - static let b_l_r = korFont(style: .regular, size: 18) - static let b_m_r = korFont(style: .regular, size: 16) - static let b_s_sb = korFont(style: .semiBold, size: 14) - static let b_s_m = korFont(style: .medium, size: 14) - static let b_s_r = korFont(style: .regular, size: 14) - - static let sub_l_b = korFont(style: .bold, size: 18) - static let sub_l_m = korFont(style: .medium, size: 18) - static let sub_m_b = korFont(style: .bold, size: 16) - static let sub_m_sb = korFont(style: .semiBold, size: 16) - static let sub_m_m = korFont(style: .medium, size: 16) - - static let cp_s_sb = korFont(style: .semiBold, size: 14) - static let cp_s_m = korFont(style: .medium, size: 14) - static let cp_s_r = korFont(style: .regular, size: 14) - static let cp_xs_sb = korFont(style: .semiBold, size: 12) - static let cp_xs_r = korFont(style: .regular, size: 12) - - static let btn_m_b = korFont(style: .bold, size: 16) - static let btn_m_r = korFont(style: .regular, size: 16) - static let btn_s_r = korFont(style: .regular, size: 14) - static let btn_xs_r = korFont(style: .regular, size: 12) - - static func korFont(style: FontStyle, size: CGFloat) -> UIFont? { - return UIFont(name: "Pretendard\(style.rawValue)", size: size) - } - - enum FontStyle: String { - case bold = "-Bold" - case semiBold = "-SemiBold" - case medium = "-Medium" - case regular = "-Regular" - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Utills/Extension/UIImage+.swift b/MLS/Presentation/DesignSystem/DesignSystem/Utills/Extension/UIImage+.swift deleted file mode 100644 index 90112d88..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Utills/Extension/UIImage+.swift +++ /dev/null @@ -1,29 +0,0 @@ -import UIKit - -extension UIImage { - static func fromColor(_ color: UIColor?) -> UIImage { - guard let color else { return UIImage() } - let rect = CGRect(x: 0, y: 0, width: 1, height: 1) - UIGraphicsBeginImageContext(rect.size) - color.setFill() - UIRectFill(rect) - let image = UIGraphicsGetImageFromCurrentImageContext() ?? UIImage() - UIGraphicsEndImageContext() - return image - } - - func resizeImage(to targetSize: CGSize, preserveAspectRatio: Bool = true) -> UIImage? { - let size: CGSize - if preserveAspectRatio { - let aspectRatio = min(targetSize.width / self.size.width, targetSize.height / self.size.height) - size = CGSize(width: self.size.width * aspectRatio, height: self.size.height * aspectRatio) - } else { - size = targetSize - } - - let renderer = UIGraphicsImageRenderer(size: size) - return renderer.image { _ in - self.draw(in: CGRect(origin: .zero, size: size)) - } - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Utills/FontManager.swift b/MLS/Presentation/DesignSystem/DesignSystem/Utills/FontManager.swift deleted file mode 100644 index 35c89907..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Utills/FontManager.swift +++ /dev/null @@ -1,36 +0,0 @@ -import os -import UIKit - -public class FontManager { - /// 폰트를 등록하는 메서드 - public static func registerFonts() { - let fontNames = [ - "Pretendard-Bold", - "Pretendard-SemiBold", - "Pretendard-Medium", - "Pretendard-Regular" - ] - - fontNames.forEach { fontName in - guard let fontURL = Bundle.designSystem.url(forResource: fontName, withExtension: "ttf") else { - os_log(.error, "Font file not found: \(fontName)") - return - } - - var error: Unmanaged? - CTFontManagerRegisterFontsForURL(fontURL as CFURL, .process, &error) - - if let error = error { - os_log(.error, "Error registering font: \(error.takeUnretainedValue())") - } else { - os_log(.error, "\(fontName) registered successfully") - } - } - } -} - -extension Bundle { - static var designSystem: Bundle { - return Bundle(for: FontManager.self) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystem/Utills/NSAttributedString.swift b/MLS/Presentation/DesignSystem/DesignSystem/Utills/NSAttributedString.swift deleted file mode 100644 index a7d131bb..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystem/Utills/NSAttributedString.swift +++ /dev/null @@ -1,60 +0,0 @@ -import UIKit - -public extension NSAttributedString { - static func makeStyledString( - font: UIFont?, - text: String?, - color: UIColor? = .textColor, - alignment: NSTextAlignment = .center, - lineHeight: CGFloat = 1.17 - ) -> NSAttributedString? { - guard let text, let color, let font else { return nil } - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.minimumLineHeight = 0 - paragraphStyle.lineBreakMode = .byTruncatingTail - paragraphStyle.lineHeightMultiple = lineHeight - paragraphStyle.alignment = alignment - - let actualLineHeight = font.lineHeight * lineHeight - let baselineOffset = (actualLineHeight - font.lineHeight) / 2 - - let attributedString = NSAttributedString( - string: text, - attributes: [ - .font: font, - .foregroundColor: color, - .paragraphStyle: paragraphStyle, - .baselineOffset: baselineOffset - ] - ) - return attributedString - } - - static func makeStyledUnderlinedString( - font: UIFont?, - text: String?, - color: UIColor? = .textColor, - alignment: NSTextAlignment = .center, - lineHeight: CGFloat = 1.17, - underlineStyle: NSUnderlineStyle = .single - ) -> NSAttributedString? { - guard let text, let color, let font else { return nil } - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.minimumLineHeight = 0 - paragraphStyle.lineBreakMode = .byTruncatingTail - paragraphStyle.maximumLineHeight = font.lineHeight * lineHeight - paragraphStyle.alignment = alignment - - let attributedString = NSAttributedString( - string: text, - attributes: [ - .font: font, - .foregroundColor: color, - .paragraphStyle: paragraphStyle, - .underlineStyle: underlineStyle.rawValue - ] - ) - - return attributedString - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/.DS_Store b/MLS/Presentation/DesignSystem/DesignSystemDemo/.DS_Store deleted file mode 100644 index df07e1cb..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystemDemo/.DS_Store and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/Application/AppDelegate.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/Application/AppDelegate.swift deleted file mode 100644 index cbff7ead..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/Application/AppDelegate.swift +++ /dev/null @@ -1,50 +0,0 @@ -import UIKit - -import Core -import Data -import DesignSystem -import Domain -import DomainInterface - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - FontManager.registerFonts() - registerDependencies() - return true - } - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {} -} - -private extension AppDelegate { - func registerDependencies() { - registerProvider() - registerUseCase() - } - - func registerProvider() { - DIContainer.register(type: NetworkProvider.self) { - NetworkProviderImpl() - } - DIContainer.register(type: SocialAuthenticatableProvider.self, name: "kakao") { - KakaoLoginProviderImpl() - } - DIContainer.register(type: SocialAuthenticatableProvider.self, name: "apple") { - AppleLoginProviderImpl() - } - } - - func registerUseCase() { - DIContainer.register(type: CheckEmptyLevelAndRoleUseCase.self) { - CheckEmptyLevelAndRoleUseCaseImpl() - } - DIContainer.register(type: CheckValidLevelUseCase.self) { - CheckValidLevelUseCaseImpl() - } - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/Application/SceneDelegate.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/Application/SceneDelegate.swift deleted file mode 100644 index 6ef7f387..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/Application/SceneDelegate.swift +++ /dev/null @@ -1,28 +0,0 @@ -import UIKit - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - - var window: UIWindow? - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - guard let windowScene = (scene as? UIWindowScene) else { return } - window = UIWindow(windowScene: windowScene) - window?.rootViewController = UINavigationController(rootViewController: ViewController()) - window?.makeKeyAndVisible() - } - - func sceneDidDisconnect(_ scene: UIScene) { - } - - func sceneDidBecomeActive(_ scene: UIScene) { - } - - func sceneWillResignActive(_ scene: UIScene) { - } - - func sceneWillEnterForeground(_ scene: UIScene) { - } - - func sceneDidEnterBackground(_ scene: UIScene) { - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/Assets.xcassets/AccentColor.colorset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystemDemo/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index eb878970..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/Assets.xcassets/AppIcon.appiconset/Contents.json b/MLS/Presentation/DesignSystem/DesignSystemDemo/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 8562116f..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "images" : [ - { - "filename" : "DesignSystemLogo.png", - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "tinted" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/Assets.xcassets/AppIcon.appiconset/DesignSystemLogo.png b/MLS/Presentation/DesignSystem/DesignSystemDemo/Assets.xcassets/AppIcon.appiconset/DesignSystemLogo.png deleted file mode 100644 index 5d3e8292..00000000 Binary files a/MLS/Presentation/DesignSystem/DesignSystemDemo/Assets.xcassets/AppIcon.appiconset/DesignSystemLogo.png and /dev/null differ diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/Assets.xcassets/Contents.json b/MLS/Presentation/DesignSystem/DesignSystemDemo/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/Base.lproj/LaunchScreen.storyboard b/MLS/Presentation/DesignSystem/DesignSystemDemo/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 865e9329..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/BadgeTestController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/BadgeTestController.swift deleted file mode 100644 index 7ffd7866..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/BadgeTestController.swift +++ /dev/null @@ -1,70 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift - -final class BadgeTestController: UIViewController { - - // MARK: - Properties - var disposeBag = DisposeBag() - private let currentBadge = Badge(style: .currentQuest) - private let preBadge = Badge(style: .preQuest) - private let nextBadge = Badge(style: .nextQuest) - private let elementBadge = Badge(style: .element("불 약점")) - - init() { - super.init(nibName: nil, bundle: nil) - title = "Badge" - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -extension BadgeTestController { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension BadgeTestController { - func addViews() { - view.addSubview(currentBadge) - view.addSubview(preBadge) - view.addSubview(nextBadge) - view.addSubview(elementBadge) - } - - func setupConstraints() { - currentBadge.snp.makeConstraints { make in - make.center.equalToSuperview() - } - - preBadge.snp.makeConstraints { make in - make.top.equalTo(currentBadge.snp.bottom).offset(16) - make.centerX.equalToSuperview() - } - - nextBadge.snp.makeConstraints { make in - make.top.equalTo(preBadge.snp.bottom).offset(16) - make.centerX.equalToSuperview() - } - - elementBadge.snp.makeConstraints { make in - make.top.equalTo(nextBadge.snp.bottom).offset(16) - make.centerX.equalToSuperview() - } - } - - func configureUI() { - view.backgroundColor = .systemBackground - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/CardListTestViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/CardListTestViewController.swift deleted file mode 100644 index f993a6ba..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/CardListTestViewController.swift +++ /dev/null @@ -1,146 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem - -import RxSwift - -final class CardListTestViewController: UIViewController { - - // MARK: - Properties - var disposeBag = DisposeBag() - private let cardList = CardList() - - private let mainTextTextField: UITextField = { - let view = UITextField() - view.placeholder = "main" - view.text = "text" - view.layer.borderColor = UIColor.gray.cgColor - view.layer.borderWidth = 1 - return view - }() - - private let mainTextTextLabel: UILabel = { - let label = UILabel() - label.text = "main" - return label - }() - - private let subTextTextField: UITextField = { - let view = UITextField() - view.placeholder = "sub" - view.text = "text" - view.layer.borderColor = UIColor.gray.cgColor - view.layer.borderWidth = 1 - return view - }() - - private let subTextTextLabel: UILabel = { - let label = UILabel() - label.text = "sub" - return label - }() - - private let cardListToggle = ToggleBox(text: "isBookmark") - - init() { - super.init(nibName: nil, bundle: nil) - self.title = "CardList" - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -extension CardListTestViewController { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - bind() - } -} - -// MARK: - SetUp -private extension CardListTestViewController { - func addViews() { - view.addSubview(cardList) - view.addSubview(mainTextTextLabel) - view.addSubview(mainTextTextField) - view.addSubview(subTextTextLabel) - view.addSubview(subTextTextField) - view.addSubview(cardListToggle) - } - - func setupConstraints() { - cardList.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide).inset(16) - make.horizontalEdges.equalToSuperview().inset(16) - } - - mainTextTextLabel.snp.makeConstraints { make in - make.top.equalTo(cardList.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - mainTextTextField.snp.makeConstraints { make in - make.top.equalTo(mainTextTextLabel.snp.bottom).offset(10) - make.horizontalEdges.equalToSuperview().inset(16) - } - - subTextTextLabel.snp.makeConstraints { make in - make.top.equalTo(mainTextTextField.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - subTextTextField.snp.makeConstraints { make in - make.top.equalTo(subTextTextLabel.snp.bottom).offset(10) - make.horizontalEdges.equalToSuperview().inset(16) - } - - cardListToggle.snp.makeConstraints { make in - make.top.equalTo(subTextTextField.snp.bottom).offset(10) - make.horizontalEdges.equalToSuperview().inset(16) - } - } - - func configureUI() { - view.backgroundColor = .systemBackground - ImageLoader.shared.loadImage(stringURL: "https://maplestory.io/api/gms/62/mob/2100101/render/stand") { [weak self] image in - if let image { - DispatchQueue.main.async { - self?.cardList.setImage(image: image, backgroundColor: .listMap) - } - } else { - print("fail to load image") - } - } - } - - func bind() { - mainTextTextField.rx.text - .withUnretained(self) - .subscribe { (owner, text) in - owner.cardList.mainText = text - } - .disposed(by: disposeBag) - - subTextTextField.rx.text - .withUnretained(self) - .subscribe { (owner, text) in - owner.cardList.subText = text - } - .disposed(by: disposeBag) - - cardListToggle.toggle.rx.isOn - .withUnretained(self) - .subscribe { (owner, isOn) in - owner.cardList.isIconSelected = isOn - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/CheckBoxButtonTestViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/CheckBoxButtonTestViewController.swift deleted file mode 100644 index 2fea084a..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/CheckBoxButtonTestViewController.swift +++ /dev/null @@ -1,211 +0,0 @@ -import UIKit - -import DesignSystem - -import RxCocoa -import RxSwift -import SnapKit - -final class CheckBoxButtonTestViewController: UIViewController { - // MARK: - Properties - private var disposeBag = DisposeBag() - private var normalButton = CheckBoxButton(style: .normal, mainTitle: nil, subTitle: nil) - private var smallButton = CheckBoxButton(style: .listSmall, mainTitle: nil, subTitle: nil) - private var mediumButton = CheckBoxButton(style: .listMedium, mainTitle: nil, subTitle: nil) - private var largeButton = CheckBoxButton(style: .listLarge, mainTitle: nil, subTitle: nil) - - private let typeSegmentControl: UISegmentedControl = { - let items = ["normal", "listSmall", "listMedium", "listLarge"] - let control = UISegmentedControl(items: items) - control.selectedSegmentIndex = 0 - return control - }() - - private let mainTitleTextField: UITextField = { - let view = UITextField() - view.placeholder = "MainTitle" - view.text = "MainTitle" - view.layer.borderColor = UIColor.gray.cgColor - view.layer.borderWidth = 1 - return view - }() - - private let subTitleTextField: UITextField = { - let view = UITextField() - view.placeholder = "SubTitle" - view.text = "SubTitle" - view.layer.borderColor = UIColor.gray.cgColor - view.layer.borderWidth = 1 - return view - }() - - private let mainTitleTextLabel: UILabel = { - let label = UILabel() - label.text = "MainTitle" - return label - }() - - private let subTitleTextLabel: UILabel = { - let label = UILabel() - label.text = "SubTitle" - return label - }() - - init() { - super.init(nibName: nil, bundle: nil) - self.title = "CheckBoxButton" - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} - -// MARK: - Life Cycle -extension CheckBoxButtonTestViewController { - override func viewDidLoad() { - super.viewDidLoad() - self.addViews() - self.setupConstraints() - self.configureUI() - self.bind() - } -} - -// MARK: - SetUp -private extension CheckBoxButtonTestViewController { - func addViews() { - view.addSubview(normalButton) - view.addSubview(smallButton) - view.addSubview(mediumButton) - view.addSubview(largeButton) - view.addSubview(typeSegmentControl) - view.addSubview(mainTitleTextLabel) - view.addSubview(mainTitleTextField) - view.addSubview(subTitleTextLabel) - view.addSubview(subTitleTextField) - } - - func setupConstraints() { - normalButton.snp.makeConstraints { make in - make.horizontalEdges.top.equalTo(view.safeAreaLayoutGuide).inset(16) - } - - smallButton.snp.makeConstraints { make in - make.horizontalEdges.top.equalTo(view.safeAreaLayoutGuide).inset(16) - } - - mediumButton.snp.makeConstraints { make in - make.horizontalEdges.top.equalTo(view.safeAreaLayoutGuide).inset(16) - } - - largeButton.snp.makeConstraints { make in - make.horizontalEdges.top.equalTo(view.safeAreaLayoutGuide).inset(16) - } - - typeSegmentControl.snp.makeConstraints { make in - make.top.equalTo(normalButton.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - mainTitleTextLabel.snp.makeConstraints { make in - make.top.equalTo(typeSegmentControl.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - mainTitleTextField.snp.makeConstraints { make in - make.top.equalTo(mainTitleTextLabel.snp.bottom).offset(10) - make.horizontalEdges.equalToSuperview().inset(16) - } - - subTitleTextLabel.snp.makeConstraints { make in - make.top.equalTo(mainTitleTextField.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - subTitleTextField.snp.makeConstraints { make in - make.top.equalTo(subTitleTextLabel.snp.bottom).offset(10) - make.horizontalEdges.equalToSuperview().inset(16) - } - } - - func configureUI() { - view.backgroundColor = .systemBackground - } - - func bind() { - normalButton.rx.tap - .withUnretained(self) - .subscribe { (owner, _) in - owner.normalButton.isSelected.toggle() - } - .disposed(by: disposeBag) - - smallButton.rx.tap - .withUnretained(self) - .subscribe { (owner, _) in - owner.smallButton.isSelected.toggle() - } - .disposed(by: disposeBag) - - mediumButton.rx.tap - .withUnretained(self) - .subscribe { (owner, _) in - owner.mediumButton.isSelected.toggle() - } - .disposed(by: disposeBag) - - largeButton.rx.tap - .withUnretained(self) - .subscribe { (owner, _) in - owner.largeButton.isSelected.toggle() - } - .disposed(by: disposeBag) - - typeSegmentControl.rx.selectedSegmentIndex - .withUnretained(self) - .subscribe { (owner, index) in - switch index { - case 0: - owner.normalButton.isHidden = false - owner.smallButton.isHidden = true - owner.mediumButton.isHidden = true - owner.largeButton.isHidden = true - case 1: - owner.normalButton.isHidden = true - owner.smallButton.isHidden = false - owner.mediumButton.isHidden = true - owner.largeButton.isHidden = true - case 2: - owner.normalButton.isHidden = true - owner.smallButton.isHidden = true - owner.mediumButton.isHidden = false - owner.largeButton.isHidden = true - default: - owner.normalButton.isHidden = true - owner.smallButton.isHidden = true - owner.mediumButton.isHidden = true - owner.largeButton.isHidden = false - } - } - .disposed(by: disposeBag) - - mainTitleTextField.rx.text - .withUnretained(self) - .subscribe { (owner, text) in - owner.normalButton.mainTitle = text - owner.smallButton.mainTitle = text - owner.mediumButton.mainTitle = text - owner.largeButton.mainTitle = text - } - .disposed(by: disposeBag) - - subTitleTextField.rx.text - .withUnretained(self) - .subscribe { (owner, text) in - owner.normalButton.subTitle = text - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/CollectionListTestViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/CollectionListTestViewController.swift deleted file mode 100644 index db3a20cc..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/CollectionListTestViewController.swift +++ /dev/null @@ -1,54 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift -import SnapKit - -final class CollectionListTestViewController: UIViewController { - - // MARK: - Properties - var disposeBag = DisposeBag() - - let collection = CollectionList() - - init() { - super.init(nibName: nil, bundle: nil) - self.title = "CollectionList" - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -extension CollectionListTestViewController { - override func viewDidLoad() { - super.viewDidLoad() - - self.addViews() - self.setupConstraints() - self.configureUI() - } -} - -// MARK: - SetUp -private extension CollectionListTestViewController { - func addViews() { - self.view.addSubview(collection) - } - - func setupConstraints() { - collection.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide).inset(16) - make.horizontalEdges.equalToSuperview().inset(16) - } - } - - func configureUI() { - self.view.backgroundColor = .neutral200 - collection.setTitle(text: "글자수는 10글자 이후부터 생략입니다.") - collection.setSubtitle(text: "$n개") - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/CommonButtonTestViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/CommonButtonTestViewController.swift deleted file mode 100644 index 66247791..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/CommonButtonTestViewController.swift +++ /dev/null @@ -1,117 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift - -final class CommonButtonTestViewController: UIViewController { - - // MARK: - Properties - var disposeBag = DisposeBag() - private let commonButton = CommonButton(style: .normal, title: "NormalTitle", disabledTitle: "DisabledTitle") - private let textButton = CommonButton(style: .text, title: "NormalTitle", disabledTitle: "DisabledTitle") - private let borderButton = CommonButton(style: .border, title: "NormalTitle", disabledTitle: "DisabledTitle") - - private let typeSegmentControl: UISegmentedControl = { - let items = ["normal", "text", "border"] - let control = UISegmentedControl(items: items) - control.selectedSegmentIndex = 0 - return control - }() - - private let buttonStateToggle = ToggleBox(text: "isEnabled") - init() { - super.init(nibName: nil, bundle: nil) - self.title = "CommonButton" - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -extension CommonButtonTestViewController { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - bind() - } -} - -// MARK: - SetUp -private extension CommonButtonTestViewController { - func addViews() { - view.addSubview(commonButton) - view.addSubview(textButton) - view.addSubview(borderButton) - view.addSubview(typeSegmentControl) - view.addSubview(buttonStateToggle) - } - - func setupConstraints() { - commonButton.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide).inset(16) - make.horizontalEdges.equalToSuperview().inset(16) - } - - textButton.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide).inset(16) - make.centerX.equalToSuperview() - } - - borderButton.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide).inset(16) - make.horizontalEdges.equalToSuperview().inset(16) - } - - typeSegmentControl.snp.makeConstraints { make in - make.top.equalTo(textButton.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - buttonStateToggle.snp.makeConstraints { make in - make.top.equalTo(typeSegmentControl.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - } - - func configureUI() { - self.view.backgroundColor = .systemBackground - self.title = "CommonButton" - } - - func bind() { - self.typeSegmentControl.rx.selectedSegmentIndex - .withUnretained(self) - .subscribe { owner, selectedIndex in - switch selectedIndex { - case 0: - owner.commonButton.isHidden = false - owner.textButton.isHidden = true - owner.borderButton.isHidden = true - case 1: - owner.commonButton.isHidden = true - owner.textButton.isHidden = false - owner.borderButton.isHidden = true - default: - owner.commonButton.isHidden = true - owner.textButton.isHidden = true - owner.borderButton.isHidden = false - } - } - .disposed(by: disposeBag) - - self.buttonStateToggle.toggle.rx.isOn - .withUnretained(self) - .subscribe { (owner, isOn) in - owner.commonButton.isEnabled = isOn - owner.textButton.isEnabled = isOn - owner.borderButton.isEnabled = isOn - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/DictionaryDetailViewTestController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/DictionaryDetailViewTestController.swift deleted file mode 100644 index ad87f7a9..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/DictionaryDetailViewTestController.swift +++ /dev/null @@ -1,74 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift - -final class DictionaryDetailViewTestController: UIViewController { - - // MARK: - Properties - var disposeBag = DisposeBag() - private let first = DictionaryDetailListView() - private let second = DictionaryDetailListView() - private let third = DictionaryDetailListView() - private let forth = DictionaryDetailListView() - - init() { - super.init(nibName: nil, bundle: nil) - title = "DictionaryDetailView" - first.update(clickableMainText: "mainText", additionalText: "text", clickableSubText: "text") - second.update(mainText: "mainText", clickableSubText: "text") - third.update(mainText: "mainText", subText: "text") - forth.update(clickableMainText: "mainText", clickableSubText: "text") - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -extension DictionaryDetailViewTestController { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension DictionaryDetailViewTestController { - func addViews() { - view.addSubview(first) - view.addSubview(second) - view.addSubview(third) - view.addSubview(forth) - } - - func setupConstraints() { - first.snp.makeConstraints { make in - make.horizontalEdges.centerY.equalToSuperview() - } - - second.snp.makeConstraints { make in - make.top.equalTo(first.snp.bottom).offset(16) - make.horizontalEdges.equalToSuperview() - } - - third.snp.makeConstraints { make in - make.top.equalTo(second.snp.bottom).offset(16) - make.horizontalEdges.equalToSuperview() - } - - forth.snp.makeConstraints { make in - make.top.equalTo(third.snp.bottom).offset(16) - make.horizontalEdges.equalToSuperview() - } - } - - func configureUI() { - view.backgroundColor = .systemBackground - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/DropDwonBoxTestViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/DropDwonBoxTestViewController.swift deleted file mode 100644 index 7ab543ec..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/DropDwonBoxTestViewController.swift +++ /dev/null @@ -1,161 +0,0 @@ -import UIKit - -import DesignSystem - -import RxCocoa -import RxSwift -import SnapKit - -final class DropDownBoxTextViewController: UIViewController { - // MARK: - Properties - private var disposeBag = DisposeBag() - private var dropDownBox = DropDownBox(menus: ["1", "2"]) - private lazy var inputBox = dropDownBox.inputBox - - private let labelTextField: UITextField = { - let view = UITextField() - view.placeholder = "label" - view.text = "label" - view.layer.borderColor = UIColor.gray.cgColor - view.layer.borderWidth = 1 - return view - }() - - private let placeHolderTextField: UITextField = { - let view = UITextField() - view.placeholder = "placeHolder" - view.text = "placeHolder" - view.layer.borderColor = UIColor.gray.cgColor - view.layer.borderWidth = 1 - return view - }() - - private let countTextField: UITextField = { - let view = UITextField() - view.placeholder = "count" - view.text = "4" - view.layer.borderColor = UIColor.gray.cgColor - view.layer.borderWidth = 1 - view.keyboardType = .numberPad - return view - }() - - private let labelTextLabel: UILabel = { - let label = UILabel() - label.text = "label" - return label - }() - - private let placeHolderTextLabel: UILabel = { - let label = UILabel() - label.text = "placeHolder" - return label - }() - - private let countTextLabel: UILabel = { - let label = UILabel() - label.text = "메뉴개수" - return label - }() - - init() { - super.init(nibName: nil, bundle: nil) - self.title = "DropDownBox" - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} - -// MARK: - Life Cycle -extension DropDownBoxTextViewController { - override func viewDidLoad() { - super.viewDidLoad() - self.addViews() - self.setupConstraints() - self.configureUI() - self.bind() - } -} - -// MARK: - SetUp -private extension DropDownBoxTextViewController { - func addViews() { - view.addSubview(labelTextLabel) - view.addSubview(labelTextField) - view.addSubview(placeHolderTextLabel) - view.addSubview(placeHolderTextField) - view.addSubview(countTextLabel) - view.addSubview(countTextField) - view.addSubview(dropDownBox) - } - - func setupConstraints() { - dropDownBox.snp.makeConstraints { make in - make.horizontalEdges.top.equalTo(view.safeAreaLayoutGuide).inset(16) - } - - labelTextLabel.snp.makeConstraints { make in - make.top.equalTo(dropDownBox.snp.bottom).offset(10) - make.horizontalEdges.equalToSuperview().inset(16) - } - - labelTextField.snp.makeConstraints { make in - make.top.equalTo(labelTextLabel.snp.bottom).offset(10) - make.horizontalEdges.equalToSuperview().inset(16) - } - - placeHolderTextLabel.snp.makeConstraints { make in - make.top.equalTo(labelTextField.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - placeHolderTextField.snp.makeConstraints { make in - make.top.equalTo(placeHolderTextLabel.snp.bottom).offset(10) - make.horizontalEdges.equalToSuperview().inset(16) - } - - countTextLabel.snp.makeConstraints { make in - make.top.equalTo(placeHolderTextField.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - countTextField.snp.makeConstraints { make in - make.top.equalTo(countTextLabel.snp.bottom).offset(10) - make.horizontalEdges.equalToSuperview().inset(16) - } - } - - func configureUI() { - view.backgroundColor = .systemBackground - } - - func bind() { - labelTextField.rx.text - .withUnretained(self) - .subscribe { owner, text in - owner.inputBox.label.attributedText = .makeStyledString(font: .b_s_r, text: text, color: .neutral700, alignment: .left) - } - .disposed(by: disposeBag) - - placeHolderTextField.rx.text - .withUnretained(self) - .subscribe { owner, text in - owner.inputBox.textField.attributedPlaceholder = .makeStyledString(font: .b_m_r, text: text, color: .neutral500, alignment: .left) - } - .disposed(by: disposeBag) - - countTextField.rx.text - .withUnretained(self) - .subscribe { (owner, count) in - guard let count = Int(count ?? "") else { return } - owner.dropDownBox.menus = [] - for index in 1...count { - owner.dropDownBox.menus.append("메뉴\(index)") - } - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/ErrorMessageTextViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/ErrorMessageTextViewController.swift deleted file mode 100644 index a3e3b278..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/ErrorMessageTextViewController.swift +++ /dev/null @@ -1,88 +0,0 @@ -import UIKit - -import DesignSystem - -import RxCocoa -import RxSwift -import SnapKit - -final class ErrorMessageTextViewController: UIViewController { - // MARK: - Properties - private var disposeBag = DisposeBag() - private var errorMessage = ErrorMessage(message: nil) - - private let messageTextField: UITextField = { - let view = UITextField() - view.placeholder = "message" - view.text = "error" - view.layer.borderColor = UIColor.gray.cgColor - view.layer.borderWidth = 1 - return view - }() - - private let messageTextLabel: UILabel = { - let label = UILabel() - label.text = "message" - return label - }() - - init() { - super.init(nibName: nil, bundle: nil) - self.title = "ErrorMessage" - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} - -// MARK: - Life Cycle -extension ErrorMessageTextViewController { - override func viewDidLoad() { - super.viewDidLoad() - self.addViews() - self.setupConstraints() - self.configureUI() - self.bind() - } -} - -// MARK: - SetUp -private extension ErrorMessageTextViewController { - func addViews() { - view.addSubview(errorMessage) - view.addSubview(messageTextLabel) - view.addSubview(messageTextField) - } - - func setupConstraints() { - errorMessage.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide).inset(16) - make.centerX.equalToSuperview() - } - - messageTextLabel.snp.makeConstraints { make in - make.top.equalTo(errorMessage.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - messageTextField.snp.makeConstraints { make in - make.top.equalTo(messageTextLabel.snp.bottom).offset(10) - make.horizontalEdges.equalToSuperview().inset(16) - } - } - - func configureUI() { - view.backgroundColor = .systemBackground - } - - func bind() { - messageTextField.rx.text - .withUnretained(self) - .subscribe { owner, message in - owner.errorMessage.label.attributedText = .makeStyledString(font: .b_s_r, text: message, color: .error900) - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/GuideAlertTestViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/GuideAlertTestViewController.swift deleted file mode 100644 index 60431590..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/GuideAlertTestViewController.swift +++ /dev/null @@ -1,105 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem - -import RxSwift -import SnapKit - -final class GuideAlertTestViewController: UIViewController { - // MARK: - Properties - var disposeBag = DisposeBag() - - let oneButton = CommonButton(style: .normal, title: "oneButtonModal", disabledTitle: nil) - let twoButton = CommonButton(style: .normal, title: "twoButtonModal", disabledTitle: nil) - let logoutButton = CommonButton(style: .normal, title: "logoutButtonModal", disabledTitle: nil) - let withdrawButton = CommonButton(style: .normal, title: "withdrawButtonModal", disabledTitle: nil) - - init() { - super.init(nibName: nil, bundle: nil) - self.title = "GuideAlert" - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -extension GuideAlertTestViewController { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - bind() - } -} - -// MARK: - SetUp -private extension GuideAlertTestViewController { - func addViews() { - view.addSubview(oneButton) - view.addSubview(twoButton) - view.addSubview(logoutButton) - view.addSubview(withdrawButton) - } - - func setupConstraints() { - oneButton.snp.makeConstraints { make in - make.bottom.equalToSuperview().inset(16) - make.centerX.equalToSuperview() - } - - twoButton.snp.makeConstraints { make in - make.bottom.equalTo(oneButton.snp.top).offset(-16) - make.centerX.equalToSuperview() - } - - logoutButton.snp.makeConstraints { make in - make.bottom.equalTo(twoButton.snp.top).offset(-16) - make.centerX.equalToSuperview() - } - - withdrawButton.snp.makeConstraints { make in - make.bottom.equalTo(logoutButton.snp.top).offset(-16) - make.centerX.equalToSuperview() - } - } - - func configureUI() { - view.backgroundColor = .systemBackground - } - - func bind() { - oneButton.rx.tap - .withUnretained(self) - .subscribe { _, _ in - GuideAlertFactory.show(mainText: "버튼 하나", ctaText: "확인", ctaAction: {}) - } - .disposed(by: disposeBag) - - twoButton.rx.tap - .withUnretained(self) - .subscribe { _, _ in - GuideAlertFactory.show(mainText: "버튼 두개", ctaText: "확인", cancelText: "취소", ctaAction: {}) - } - .disposed(by: disposeBag) - - logoutButton.rx.tap - .withUnretained(self) - .subscribe { _, _ in - GuideAlertFactory.showAuthAlert(type: .logout, ctaAction: {}) - } - .disposed(by: disposeBag) - - withdrawButton.rx.tap - .withUnretained(self) - .subscribe { _, _ in - GuideAlertFactory.showAuthAlert(type: .withdraw, ctaAction: {}) - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/HeaderTestViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/HeaderTestViewController.swift deleted file mode 100644 index 8f23db73..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/HeaderTestViewController.swift +++ /dev/null @@ -1,155 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift - -final class HeaderTestViewController: UIViewController { - - // MARK: - Properties - var disposeBag = DisposeBag() - private let mainHeader = Header(style: .main, title: "메인") - private let filterHeader = Header(style: .filter, title: "필터") - - private let typeSegmentControl: UISegmentedControl = { - let items = ["main", "filter"] - let control = UISegmentedControl(items: items) - control.selectedSegmentIndex = 0 - return control - }() - - private let mainTextTextField: UITextField = { - let view = UITextField() - view.placeholder = "text" - view.text = "text" - view.layer.borderColor = UIColor.gray.cgColor - view.layer.borderWidth = 1 - return view - }() - - private let mainTextTextLabel: UILabel = { - let label = UILabel() - label.text = "text" - return label - }() - - private let filterTextTextField: UITextField = { - let view = UITextField() - view.placeholder = "text" - view.text = "text" - view.layer.borderColor = UIColor.gray.cgColor - view.layer.borderWidth = 1 - return view - }() - - private let filterTextTextLabel: UILabel = { - let label = UILabel() - label.text = "text" - return label - }() - - init() { - super.init(nibName: nil, bundle: nil) - self.title = "Header" - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -extension HeaderTestViewController { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - bind() - } -} - -// MARK: - SetUp -private extension HeaderTestViewController { - func addViews() { - view.addSubview(mainHeader) - view.addSubview(filterHeader) - view.addSubview(typeSegmentControl) - view.addSubview(mainTextTextLabel) - view.addSubview(mainTextTextField) - view.addSubview(filterTextTextLabel) - view.addSubview(filterTextTextField) - } - - func setupConstraints() { - mainHeader.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide).inset(16) - make.horizontalEdges.equalToSuperview().inset(16) - } - - filterHeader.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide).inset(16) - make.horizontalEdges.equalToSuperview().inset(16) - } - - typeSegmentControl.snp.makeConstraints { make in - make.top.equalTo(mainHeader.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - mainTextTextLabel.snp.makeConstraints { make in - make.top.equalTo(typeSegmentControl.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - mainTextTextField.snp.makeConstraints { make in - make.top.equalTo(mainTextTextLabel.snp.bottom).offset(10) - make.horizontalEdges.equalToSuperview().inset(16) - } - - filterTextTextLabel.snp.makeConstraints { make in - make.top.equalTo(mainTextTextField.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - filterTextTextField.snp.makeConstraints { make in - make.top.equalTo(filterTextTextLabel.snp.bottom).offset(10) - make.horizontalEdges.equalToSuperview().inset(16) - } - } - - func configureUI() { - self.view.backgroundColor = .systemBackground - } - - func bind() { - typeSegmentControl.rx.selectedSegmentIndex - .withUnretained(self) - .subscribe { owner, selectedIndex in - switch selectedIndex { - case 0: - owner.mainHeader.isHidden = false - owner.filterHeader.isHidden = true - default: - owner.mainHeader.isHidden = true - owner.filterHeader.isHidden = false - } - } - .disposed(by: disposeBag) - - mainTextTextField.rx.text - .withUnretained(self) - .subscribe { (owner, text) in - owner.mainHeader.titleLabel.attributedText = .makeStyledString(font: owner.mainHeader.style.titleFont, text: text) - } - .disposed(by: disposeBag) - - filterTextTextField.rx.text - .withUnretained(self) - .subscribe { (owner, text) in - owner.filterHeader.titleLabel.attributedText = .makeStyledString(font: owner.filterHeader.style.titleFont, text: text) - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/InputBoxTextViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/InputBoxTextViewController.swift deleted file mode 100644 index ab32c630..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/InputBoxTextViewController.swift +++ /dev/null @@ -1,179 +0,0 @@ -import UIKit - -import DesignSystem - -import RxCocoa -import RxSwift -import SnapKit - -final class InputBoxTextViewController: UIViewController { - // MARK: - Properties - private var disposeBag = DisposeBag() - private var inputBox = InputBox(label: "label", placeHodler: "placeHolder") - - private let typeSegmentControl: UISegmentedControl = { - let items = ["edit", "error"] - let control = UISegmentedControl(items: items) - control.selectedSegmentIndex = 0 - return control - }() - - private let labelTextField: UITextField = { - let view = UITextField() - view.placeholder = "label" - view.text = "label" - view.layer.borderColor = UIColor.gray.cgColor - view.layer.borderWidth = 1 - return view - }() - - private let placeHolderTextField: UITextField = { - let view = UITextField() - view.placeholder = "placeHolder" - view.text = "placeHolder" - view.layer.borderColor = UIColor.gray.cgColor - view.layer.borderWidth = 1 - return view - }() - - private let textTextField: UITextField = { - let view = UITextField() - view.placeholder = "text" - view.text = "text" - view.layer.borderColor = UIColor.gray.cgColor - view.layer.borderWidth = 1 - return view - }() - - private let labelTextLabel: UILabel = { - let label = UILabel() - label.text = "label" - return label - }() - - private let placeHolderTextLabel: UILabel = { - let label = UILabel() - label.text = "placeHolder" - return label - }() - - private let textTextLabel: UILabel = { - let label = UILabel() - label.text = "text" - return label - }() - - init() { - super.init(nibName: nil, bundle: nil) - self.title = "InputBox" - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} - -// MARK: - Life Cycle -extension InputBoxTextViewController { - override func viewDidLoad() { - super.viewDidLoad() - self.addViews() - self.setupConstraints() - self.configureUI() - self.bind() - } -} - -// MARK: - SetUp -private extension InputBoxTextViewController { - func addViews() { - view.addSubview(inputBox) - view.addSubview(typeSegmentControl) - view.addSubview(labelTextLabel) - view.addSubview(labelTextField) - view.addSubview(placeHolderTextLabel) - view.addSubview(placeHolderTextField) - view.addSubview(textTextLabel) - view.addSubview(textTextField) - } - - func setupConstraints() { - inputBox.snp.makeConstraints { make in - make.horizontalEdges.top.equalTo(view.safeAreaLayoutGuide).inset(16) - } - - typeSegmentControl.snp.makeConstraints { make in - make.top.equalTo(inputBox.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - labelTextLabel.snp.makeConstraints { make in - make.top.equalTo(typeSegmentControl.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - labelTextField.snp.makeConstraints { make in - make.top.equalTo(labelTextLabel.snp.bottom).offset(10) - make.horizontalEdges.equalToSuperview().inset(16) - } - - placeHolderTextLabel.snp.makeConstraints { make in - make.top.equalTo(labelTextField.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - placeHolderTextField.snp.makeConstraints { make in - make.top.equalTo(placeHolderTextLabel.snp.bottom).offset(10) - make.horizontalEdges.equalToSuperview().inset(16) - } - - textTextLabel.snp.makeConstraints { make in - make.top.equalTo(placeHolderTextField.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - textTextField.snp.makeConstraints { make in - make.top.equalTo(textTextLabel.snp.bottom).offset(10) - make.horizontalEdges.equalToSuperview().inset(16) - } - } - - func configureUI() { - view.backgroundColor = .systemBackground - } - - func bind() { - typeSegmentControl.rx.selectedSegmentIndex - .withUnretained(self) - .subscribe { (owner, index) in - if index == 0 { - owner.inputBox.setType(type: .edit) - } else { - owner.inputBox.setType(type: .error) - } - } - .disposed(by: disposeBag) - - labelTextField.rx.text - .withUnretained(self) - .subscribe { owner, text in - owner.inputBox.label.attributedText = .makeStyledString(font: .b_s_r, text: text, color: .neutral700, alignment: .left) - } - .disposed(by: disposeBag) - - placeHolderTextField.rx.text - .withUnretained(self) - .subscribe { owner, text in - owner.inputBox.textField.attributedPlaceholder = .makeStyledString(font: .b_m_r, text: text, color: .neutral500, alignment: .left) - } - .disposed(by: disposeBag) - - textTextField.rx.text - .withUnretained(self) - .subscribe { (owner, text) in - owner.inputBox.textField.attributedText = .makeStyledString(font: .b_m_r, text: text, alignment: .left) - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/NavigationBarTestViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/NavigationBarTestViewController.swift deleted file mode 100644 index b6e76241..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/NavigationBarTestViewController.swift +++ /dev/null @@ -1,99 +0,0 @@ -import UIKit - -import DesignSystem - -import RxCocoa -import RxSwift -import SnapKit - -final class NavigationBarTestViewController: UIViewController { - - // MARK: - Properties - var disposeBag = DisposeBag() - - private let headerView1: NavigationBar = { - let view = NavigationBar(type: .withUnderLine("null")) - return view - }() - - private let headerView2: NavigationBar = { - let view = NavigationBar(type: .arrowRightLeft) - return view - }() - - private let headerView3: NavigationBar = { - let view = NavigationBar(type: .arrowLeft) - return view - }() - - private let headerView4: NavigationBar = { - let view = NavigationBar(type: .withString("null")) - return view - }() - - private let headerView5: NavigationBar = { - let view = NavigationBar(type: .collection("컬렉션 이름")) - return view - }() - - init() { - super.init(nibName: nil, bundle: nil) - self.title = "NavigationBar" - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -extension NavigationBarTestViewController { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension NavigationBarTestViewController { - func addViews() { - view.addSubview(headerView1) - view.addSubview(headerView2) - view.addSubview(headerView3) - view.addSubview(headerView4) - view.addSubview(headerView5) - } - - func setupConstraints() { - headerView1.snp.makeConstraints { make in - make.top.horizontalEdges.equalTo(view.safeAreaLayoutGuide) - } - - headerView2.snp.makeConstraints { make in - make.top.equalTo(headerView1.snp.bottom).offset(16) - make.horizontalEdges.equalTo(view.safeAreaLayoutGuide) - } - - headerView3.snp.makeConstraints { make in - make.top.equalTo(headerView2.snp.bottom).offset(16) - make.horizontalEdges.equalTo(view.safeAreaLayoutGuide) - } - - headerView4.snp.makeConstraints { make in - make.top.equalTo(headerView3.snp.bottom).offset(16) - make.horizontalEdges.equalTo(view.safeAreaLayoutGuide) - } - - headerView5.snp.makeConstraints { make in - make.top.equalTo(headerView4.snp.bottom).offset(16) - make.horizontalEdges.equalTo(view.safeAreaLayoutGuide) - } - } - - func configureUI() { - view.backgroundColor = .systemBackground - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/SearchBarTestViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/SearchBarTestViewController.swift deleted file mode 100644 index bbfd740b..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/SearchBarTestViewController.swift +++ /dev/null @@ -1,61 +0,0 @@ -import UIKit - -import DesignSystem - -import RxCocoa -import RxSwift -import SnapKit - -final class SearchBarTestViewController: UIViewController { - - // MARK: - Properties - var disposeBag = DisposeBag() - - let searchBar: SearchBar = SearchBar() - - init() { - super.init(nibName: nil, bundle: nil) - self.title = "SearchBar" - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -extension SearchBarTestViewController { - override func viewDidLoad() { - super.viewDidLoad() - - self.addViews() - self.setupConstraints() - self.configureUI() - } -} - -// MARK: - SetUp -private extension SearchBarTestViewController { - func addViews() { - view.addSubview(searchBar) - } - - func setupConstraints() { - searchBar.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide).inset(16) - make.horizontalEdges.equalToSuperview() - } - } - - func configureUI() { - self.view.backgroundColor = .systemBackground - let tapGesture = UITapGestureRecognizer() - view.addGestureRecognizer(tapGesture) - - tapGesture.rx.event - .bind { [weak self] _ in - self?.view.endEditing(true) - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/SnackBarTestViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/SnackBarTestViewController.swift deleted file mode 100644 index dd040d12..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/SnackBarTestViewController.swift +++ /dev/null @@ -1,61 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift -import SnapKit - -final class SnackBarTestViewController: UIViewController { - - // MARK: - Properties - var disposeBag = DisposeBag() - - let normalSnackBar = SnackBar(type: .normal, image: .appleLogo, imageBackgroundColor: .listNPC, text: "제목제목", buttonText: "되돌리기", buttonAction: nil) - - let deleteSnackBar = SnackBar(type: .delete, image: DesignSystemAsset.image(named: "testImage"), imageBackgroundColor: .listNPC, text: "제목제목", buttonText: "되돌리기", buttonAction: nil) - - init() { - super.init(nibName: nil, bundle: nil) - self.title = "SnackBar" - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -extension SnackBarTestViewController { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension SnackBarTestViewController { - func addViews() { - view.addSubview(normalSnackBar) - view.addSubview(deleteSnackBar) - } - - func setupConstraints() { - normalSnackBar.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide).inset(16) - make.centerX.equalToSuperview() - } - - deleteSnackBar.snp.makeConstraints { make in - make.top.equalTo(normalSnackBar.snp.bottom).offset(16) - make.centerX.equalToSuperview() - } - } - - func configureUI() { - self.view.backgroundColor = .systemBackground - - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/StepIndicatorTestViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/StepIndicatorTestViewController.swift deleted file mode 100644 index e2a5e294..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/StepIndicatorTestViewController.swift +++ /dev/null @@ -1,70 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift -import SnapKit - -final class StepIndicatorTestViewController: UIViewController { - - // MARK: - Properties - var disposeBag = DisposeBag() - - let firstIndicator = StepIndicator(circleCount: 3) - let secondIndicator = StepIndicator(circleCount: 3) - let thirdIndicator = StepIndicator(circleCount: 3) - - init() { - super.init(nibName: nil, bundle: nil) - self.title = "StepIndicator" - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -extension StepIndicatorTestViewController { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension StepIndicatorTestViewController { - func addViews() { - view.addSubview(firstIndicator) - view.addSubview(secondIndicator) - view.addSubview(thirdIndicator) - } - - func setupConstraints() { - firstIndicator.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide).offset(16) - make.centerX.equalToSuperview() - } - - secondIndicator.snp.makeConstraints { make in - make.top.equalTo(firstIndicator.snp.bottom).offset(16) - make.centerX.equalToSuperview() - } - - thirdIndicator.snp.makeConstraints { make in - make.top.equalTo(secondIndicator.snp.bottom).offset(16) - make.centerX.equalToSuperview() - } - } - - func configureUI() { - view.backgroundColor = .systemBackground - - firstIndicator.selectIndicator(index: 0) - secondIndicator.selectIndicator(index: 1) - thirdIndicator.selectIndicator(index: 2) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/TagChipTestViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/TagChipTestViewController.swift deleted file mode 100644 index 8721e54e..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/TagChipTestViewController.swift +++ /dev/null @@ -1,155 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift - -final class TagChipTestViewController: UIViewController { - - // MARK: - Properties - var disposeBag = DisposeBag() - private let normalTagChip = TagChip(style: .normal, text: "text") - private let searchTagChip = TagChip(style: .search, text: "text") - - private let typeSegmentControl: UISegmentedControl = { - let items = ["normal", "search"] - let control = UISegmentedControl(items: items) - control.selectedSegmentIndex = 0 - return control - }() - - private let normalTextLabel: UILabel = { - let label = UILabel() - label.text = "normal" - return label - }() - - private let normalTextField: UITextField = { - let view = UITextField() - view.placeholder = "text" - view.text = "text" - view.layer.borderColor = UIColor.gray.cgColor - view.layer.borderWidth = 1 - return view - }() - - private let searchTextLabel: UILabel = { - let label = UILabel() - label.text = "search" - return label - }() - - private let searchTextField: UITextField = { - let view = UITextField() - view.placeholder = "text" - view.text = "text" - view.layer.borderColor = UIColor.gray.cgColor - view.layer.borderWidth = 1 - return view - }() - - init() { - super.init(nibName: nil, bundle: nil) - title = "TagChip" - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -extension TagChipTestViewController { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - bind() - } -} - -// MARK: - SetUp -private extension TagChipTestViewController { - func addViews() { - view.addSubview(normalTagChip) - view.addSubview(searchTagChip) - view.addSubview(typeSegmentControl) - view.addSubview(normalTextLabel) - view.addSubview(normalTextField) - view.addSubview(searchTextLabel) - view.addSubview(searchTextField) - } - - func setupConstraints() { - normalTagChip.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide).inset(16) - make.centerX.equalToSuperview() - } - - searchTagChip.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide).inset(16) - make.centerX.equalToSuperview() - } - - typeSegmentControl.snp.makeConstraints { make in - make.top.equalTo(normalTagChip.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - normalTextLabel.snp.makeConstraints { make in - make.top.equalTo(typeSegmentControl.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - normalTextField.snp.makeConstraints { make in - make.top.equalTo(normalTextLabel.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - searchTextLabel.snp.makeConstraints { make in - make.top.equalTo(normalTextField.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - - searchTextField.snp.makeConstraints { make in - make.top.equalTo(searchTextLabel.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - } - - func configureUI() { - view.backgroundColor = .systemBackground - } - - func bind() { - typeSegmentControl.rx.selectedSegmentIndex - .withUnretained(self) - .subscribe { owner, selectedIndex in - switch selectedIndex { - case 0: - owner.normalTagChip.isHidden = false - owner.searchTagChip.isHidden = true - default: - owner.normalTagChip.isHidden = true - owner.searchTagChip.isHidden = false - } - } - .disposed(by: disposeBag) - - normalTextField.rx.text.orEmpty - .withUnretained(self) - .subscribe { (owner, text) in - owner.normalTagChip.text = text - } - .disposed(by: disposeBag) - - searchTextField.rx.text.orEmpty - .withUnretained(self) - .subscribe { (owner, text) in - owner.searchTagChip.text = text - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/TapButtonTestViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/TapButtonTestViewController.swift deleted file mode 100644 index b3eb12e0..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/TapButtonTestViewController.swift +++ /dev/null @@ -1,68 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift - -final class TapButtonTestViewController: UIViewController { - - // MARK: - Properties - var disposeBag = DisposeBag() - private let tapButton = TapButton(text: "text") - - private let buttonStateToggle = ToggleBox(text: "isSelected") - - init() { - super.init(nibName: nil, bundle: nil) - self.title = "TapButton" - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -extension TapButtonTestViewController { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - bind() - } -} - -// MARK: - SetUp -private extension TapButtonTestViewController { - func addViews() { - view.addSubview(tapButton) - view.addSubview(buttonStateToggle) - } - - func setupConstraints() { - tapButton.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide).inset(16) - make.centerX.equalToSuperview() - } - - buttonStateToggle.snp.makeConstraints { make in - make.top.equalTo(tapButton.snp.bottom).offset(30) - make.horizontalEdges.equalToSuperview().inset(16) - } - } - - func configureUI() { - view.backgroundColor = .systemBackground - } - - func bind() { - buttonStateToggle.toggle.rx.isOn - .withUnretained(self) - .subscribe { (owner, isOn) in - owner.tapButton.isSelected = isOn - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/TextButtonTestViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/TextButtonTestViewController.swift deleted file mode 100644 index 4b430cb1..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/TextButtonTestViewController.swift +++ /dev/null @@ -1,47 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift -import SnapKit - -final class TextButtonTestViewController: UIViewController { - - // MARK: - Properties - var disposeBag = DisposeBag() - - let button = TextButton() - - init() { - super.init(nibName: nil, bundle: nil) - self.title = "TextButton" - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -extension TextButtonTestViewController { - override func viewDidLoad() { - super.viewDidLoad() - - view.backgroundColor = .whiteMLS - addViews() - setupConstraints() - } -} - -// MARK: - SetUp -private extension TextButtonTestViewController { - func addViews() { - view.addSubview(button) - } - - func setupConstraints() { - button.snp.makeConstraints { make in - make.center.equalToSuperview() - } - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/ToastMakerTestViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/ToastMakerTestViewController.swift deleted file mode 100644 index d94be686..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ComponentsTest/ToastMakerTestViewController.swift +++ /dev/null @@ -1,47 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift -import SnapKit - -final class ToastMakerTestViewController: UIViewController { - - // MARK: - Properties - var disposeBag = DisposeBag() - - let toast = Toast(message: "토스트 테스트") - - init() { - super.init(nibName: nil, bundle: nil) - self.title = "Toast" - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -extension ToastMakerTestViewController { - override func viewDidLoad() { - super.viewDidLoad() - - view.backgroundColor = .whiteMLS - addViews() - setupConstraints() - } -} - -// MARK: - SetUp -private extension ToastMakerTestViewController { - func addViews() { - view.addSubview(toast) - } - - func setupConstraints() { - toast.snp.makeConstraints { make in - make.center.equalToSuperview() - } - } -} diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/Info.plist b/MLS/Presentation/DesignSystem/DesignSystemDemo/Info.plist deleted file mode 100644 index 0eb786dc..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/Info.plist +++ /dev/null @@ -1,23 +0,0 @@ - - - - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - - - - - - diff --git a/MLS/Presentation/DesignSystem/DesignSystemDemo/ViewController.swift b/MLS/Presentation/DesignSystem/DesignSystemDemo/ViewController.swift deleted file mode 100644 index 14d37034..00000000 --- a/MLS/Presentation/DesignSystem/DesignSystemDemo/ViewController.swift +++ /dev/null @@ -1,112 +0,0 @@ -import UIKit - -import Core -import DesignSystem - -import RxCocoa -import RxSwift -import SnapKit - -class ViewController: UIViewController { - let tableView: UITableView = { - let view = UITableView(frame: .zero, style: .plain) - return view - }() - - let bottomTabBarViewController = BottomTabBarController(viewControllers: [ - CheckBoxButtonTestViewController(), - NavigationBarTestViewController(), - CommonButtonTestViewController(), - InputBoxTextViewController() - ], initialIndex: 1) - - lazy var componentViews: [UIViewController] = [ - CheckBoxButtonTestViewController(), - NavigationBarTestViewController(), - CommonButtonTestViewController(), - InputBoxTextViewController(), - DropDownBoxTextViewController(), - ToastMakerTestViewController(), - ErrorMessageTextViewController(), - StepIndicatorTestViewController(), - HeaderTestViewController(), - TapButtonTestViewController(), - TagChipTestViewController(), - GuideAlertTestViewController(), - CardListTestViewController(), - bottomTabBarViewController, - SearchBarTestViewController(), - CollectionListTestViewController(), - SnackBarTestViewController(), - BadgeTestController(), - DictionaryDetailViewTestController(), - TextButtonTestViewController() - ] - - override func viewDidLoad() { - super.viewDidLoad() - self.view.backgroundColor = .systemBackground - tableView.dataSource = self - tableView.delegate = self - navigationItem.title = "MLS Design System" - bottomTabBarViewController.title = "BottomTabBar" - - view.addSubview(tableView) - tableView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } -} - -extension ViewController: UITableViewDataSource, UITableViewDelegate { - func numberOfSections(in tableView: UITableView) -> Int { - return 2 - } - - func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? { - switch section { - case 0: - return "Components" - default: - return nil - } - } - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - switch section { - case 0: - return componentViews.count - default: - return 0 - } - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = UITableViewCell() - let viewController: UIViewController - - switch indexPath.section { - case 0: - viewController = componentViews[indexPath.row] - default: - return cell - } - - cell.textLabel?.text = viewController.title - cell.selectionStyle = .none - return cell - } - - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let nextController: UIViewController - - switch indexPath.section { - case 0: - nextController = componentViews[indexPath.row] - default: - return - } - - navigationController?.pushViewController(nextController, animated: true) - } -} diff --git a/MLS/Presentation/DictionaryFeature/.DS_Store b/MLS/Presentation/DictionaryFeature/.DS_Store deleted file mode 100644 index 69668d56..00000000 Binary files a/MLS/Presentation/DictionaryFeature/.DS_Store and /dev/null differ diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature.xcodeproj/project.pbxproj b/MLS/Presentation/DictionaryFeature/DictionaryFeature.xcodeproj/project.pbxproj deleted file mode 100644 index cd987481..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature.xcodeproj/project.pbxproj +++ /dev/null @@ -1,1048 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 77; - objects = { - -/* Begin PBXBuildFile section */ - 081D9DC12DF80DF6004F850D /* BaseFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9DC02DF80DF6004F850D /* BaseFeature.framework */; }; - 081D9DC52DF80E15004F850D /* DomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9DC42DF80E15004F850D /* DomainInterface.framework */; }; - 081D9DC82DF80E1A004F850D /* DesignSystem.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9DC72DF80E1A004F850D /* DesignSystem.framework */; }; - 081D9DCA2DF80E27004F850D /* DictionaryFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9D762DF80CB1004F850D /* DictionaryFeatureInterface.framework */; }; - 081D9DD02DF80E5C004F850D /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 081D9DCF2DF80E5C004F850D /* RxCocoa */; }; - 081D9DD22DF80E5C004F850D /* RxRelay in Frameworks */ = {isa = PBXBuildFile; productRef = 081D9DD12DF80E5C004F850D /* RxRelay */; }; - 081D9DD42DF80E5C004F850D /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 081D9DD32DF80E5C004F850D /* RxSwift */; }; - 081D9DD72DF80E69004F850D /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 081D9DD62DF80E69004F850D /* SnapKit */; }; - 081D9DDA2DF80E7E004F850D /* ReactorKit in Frameworks */ = {isa = PBXBuildFile; productRef = 081D9DD92DF80E7E004F850D /* ReactorKit */; }; - 081D9DDC2DF80EBB004F850D /* BaseFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9DDB2DF80EBB004F850D /* BaseFeature.framework */; }; - 081D9DE02DF80EC2004F850D /* DomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9DDF2DF80EC2004F850D /* DomainInterface.framework */; }; - 081D9DE22DF80F1D004F850D /* DictionaryFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9D762DF80CB1004F850D /* DictionaryFeatureInterface.framework */; }; - 081D9DE32DF80F1D004F850D /* DictionaryFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9D762DF80CB1004F850D /* DictionaryFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 081D9DE72DF80F20004F850D /* DictionaryFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9C192DF80854004F850D /* DictionaryFeature.framework */; }; - 081D9DE82DF80F20004F850D /* DictionaryFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9C192DF80854004F850D /* DictionaryFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 081D9DEC2DF80F23004F850D /* BaseFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9DEB2DF80F23004F850D /* BaseFeature.framework */; }; - 081D9DED2DF80F23004F850D /* BaseFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9DEB2DF80F23004F850D /* BaseFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 081D9DEF2DF80F2B004F850D /* Core.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9DEE2DF80F2B004F850D /* Core.framework */; }; - 081D9DF02DF80F2B004F850D /* Core.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9DEE2DF80F2B004F850D /* Core.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 081D9DF22DF80F30004F850D /* Data.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9DF12DF80F30004F850D /* Data.framework */; }; - 081D9DF32DF80F30004F850D /* Data.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9DF12DF80F30004F850D /* Data.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 081D9DF52DF80F34004F850D /* DataMock.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9DF42DF80F34004F850D /* DataMock.framework */; }; - 081D9DF62DF80F34004F850D /* DataMock.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9DF42DF80F34004F850D /* DataMock.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 081D9DF82DF80F3C004F850D /* DesignSystem.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9DF72DF80F3C004F850D /* DesignSystem.framework */; }; - 081D9DF92DF80F3C004F850D /* DesignSystem.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9DF72DF80F3C004F850D /* DesignSystem.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 081D9DFB2DF80F44004F850D /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 081D9DFA2DF80F44004F850D /* RxCocoa */; }; - 081D9DFD2DF80F47004F850D /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 081D9DFC2DF80F47004F850D /* RxSwift */; }; - 081D9DFF2DF80F4B004F850D /* RxRelay in Frameworks */ = {isa = PBXBuildFile; productRef = 081D9DFE2DF80F4B004F850D /* RxRelay */; }; - 081D9E012DF80F53004F850D /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 081D9E002DF80F53004F850D /* SnapKit */; }; - 081D9E032DF80F58004F850D /* ReactorKit in Frameworks */ = {isa = PBXBuildFile; productRef = 081D9E022DF80F58004F850D /* ReactorKit */; }; - 081D9E052DF80F63004F850D /* DomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9E042DF80F63004F850D /* DomainInterface.framework */; }; - 081D9E062DF80F63004F850D /* DomainInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9E042DF80F63004F850D /* DomainInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 081D9E082DF80F68004F850D /* Domain.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9E072DF80F68004F850D /* Domain.framework */; }; - 081D9E092DF80F68004F850D /* Domain.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 081D9E072DF80F68004F850D /* Domain.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 772DC9972E55CA93005F92E3 /* RxKeyboard in Frameworks */ = {isa = PBXBuildFile; productRef = 772DC9962E55CA93005F92E3 /* RxKeyboard */; }; - 773E8D462E7AF4A70094714D /* MyPageFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 773E8D452E7AF4A70094714D /* MyPageFeatureInterface.framework */; }; - 773E8D4A2E7AF4D30094714D /* MyPageFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 773E8D492E7AF4D30094714D /* MyPageFeature.framework */; }; - 773E8D4B2E7AF4D30094714D /* MyPageFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 773E8D492E7AF4D30094714D /* MyPageFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 773E8D4D2E7AF4F00094714D /* MyPageFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 773E8D4C2E7AF4F00094714D /* MyPageFeature.framework */; }; - 773E8D4E2E7AF4F00094714D /* MyPageFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 773E8D4C2E7AF4F00094714D /* MyPageFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 773E8D502E7AF4F60094714D /* MyPageFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 773E8D4F2E7AF4F60094714D /* MyPageFeatureInterface.framework */; }; - 773E8D512E7AF4F60094714D /* MyPageFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 773E8D4F2E7AF4F60094714D /* MyPageFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 779A49132E1AD4BC00ABDE4F /* BookmarkFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 779A49122E1AD4BC00ABDE4F /* BookmarkFeature.framework */; }; - 779A49142E1AD4BC00ABDE4F /* BookmarkFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 779A49122E1AD4BC00ABDE4F /* BookmarkFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77C755B82E4B70C30081D80F /* AuthFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C755B62E4B70C30081D80F /* AuthFeature.framework */; }; - 77C755B92E4B70C30081D80F /* AuthFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77C755B62E4B70C30081D80F /* AuthFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77C755BA2E4B70C30081D80F /* AuthFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C755B72E4B70C30081D80F /* AuthFeatureInterface.framework */; }; - 77C755BB2E4B70C30081D80F /* AuthFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77C755B72E4B70C30081D80F /* AuthFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77C755C12E4B917F0081D80F /* RxKeyboard in Frameworks */ = {isa = PBXBuildFile; productRef = 77C755C02E4B917F0081D80F /* RxKeyboard */; }; - 77C7F4E52ED88D14009559E1 /* RxGesture in Frameworks */ = {isa = PBXBuildFile; productRef = 77C7F4E42ED88D14009559E1 /* RxGesture */; }; - 77C974732E376124007198DA /* BookmarkFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C974722E376124007198DA /* BookmarkFeatureInterface.framework */; }; - 77C97DAB2E37D4AC007198DA /* AuthFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77C97DAA2E37D4AC007198DA /* AuthFeature.framework */; }; - 77DBD8BF2E1AD0C600529428 /* BookmarkFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77DBD8BE2E1AD0C600529428 /* BookmarkFeatureInterface.framework */; }; - 77DBD8C02E1AD0C600529428 /* BookmarkFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77DBD8BE2E1AD0C600529428 /* BookmarkFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77FEEF1D2EC5B0870023197A /* AuthFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77FEEF1C2EC5B0870023197A /* AuthFeatureInterface.framework */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 081D9DCC2DF80E27004F850D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 081D9C102DF80854004F850D /* Project object */; - proxyType = 1; - remoteGlobalIDString = 081D9D752DF80CB1004F850D; - remoteInfo = DictionaryFeatureInterface; - }; - 081D9DE42DF80F1D004F850D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 081D9C102DF80854004F850D /* Project object */; - proxyType = 1; - remoteGlobalIDString = 081D9D752DF80CB1004F850D; - remoteInfo = DictionaryFeatureInterface; - }; - 081D9DE92DF80F20004F850D /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 081D9C102DF80854004F850D /* Project object */; - proxyType = 1; - remoteGlobalIDString = 081D9C182DF80854004F850D; - remoteInfo = DictionaryFeature; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 081D9DE62DF80F1D004F850D /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 779A49142E1AD4BC00ABDE4F /* BookmarkFeature.framework in Embed Frameworks */, - 081D9DF92DF80F3C004F850D /* DesignSystem.framework in Embed Frameworks */, - 081D9DE32DF80F1D004F850D /* DictionaryFeatureInterface.framework in Embed Frameworks */, - 773E8D4E2E7AF4F00094714D /* MyPageFeature.framework in Embed Frameworks */, - 081D9DED2DF80F23004F850D /* BaseFeature.framework in Embed Frameworks */, - 081D9E092DF80F68004F850D /* Domain.framework in Embed Frameworks */, - 081D9DE82DF80F20004F850D /* DictionaryFeature.framework in Embed Frameworks */, - 773E8D4B2E7AF4D30094714D /* MyPageFeature.framework in Embed Frameworks */, - 773E8D512E7AF4F60094714D /* MyPageFeatureInterface.framework in Embed Frameworks */, - 77DBD8C02E1AD0C600529428 /* BookmarkFeatureInterface.framework in Embed Frameworks */, - 081D9DF32DF80F30004F850D /* Data.framework in Embed Frameworks */, - 081D9DF62DF80F34004F850D /* DataMock.framework in Embed Frameworks */, - 77C755BB2E4B70C30081D80F /* AuthFeatureInterface.framework in Embed Frameworks */, - 081D9E062DF80F63004F850D /* DomainInterface.framework in Embed Frameworks */, - 081D9DF02DF80F2B004F850D /* Core.framework in Embed Frameworks */, - 77C755B92E4B70C30081D80F /* AuthFeature.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 081D9C192DF80854004F850D /* DictionaryFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DictionaryFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 081D9D762DF80CB1004F850D /* DictionaryFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = DictionaryFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 081D9DAA2DF80DBD004F850D /* DictionaryFeatureDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = DictionaryFeatureDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 081D9DC02DF80DF6004F850D /* BaseFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BaseFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 081D9DC42DF80E15004F850D /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 081D9DC72DF80E1A004F850D /* DesignSystem.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DesignSystem.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 081D9DDB2DF80EBB004F850D /* BaseFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BaseFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 081D9DDF2DF80EC2004F850D /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 081D9DEB2DF80F23004F850D /* BaseFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BaseFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 081D9DEE2DF80F2B004F850D /* Core.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Core.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 081D9DF12DF80F30004F850D /* Data.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Data.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 081D9DF42DF80F34004F850D /* DataMock.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DataMock.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 081D9DF72DF80F3C004F850D /* DesignSystem.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DesignSystem.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 081D9E042DF80F63004F850D /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 081D9E072DF80F68004F850D /* Domain.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Domain.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 773E8D452E7AF4A70094714D /* MyPageFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MyPageFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 773E8D492E7AF4D30094714D /* MyPageFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MyPageFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 773E8D4C2E7AF4F00094714D /* MyPageFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MyPageFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 773E8D4F2E7AF4F60094714D /* MyPageFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = MyPageFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 775D68052DFD638900DDAD2F /* DataMock.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DataMock.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 775D68092DFD641E00DDAD2F /* Domain.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Domain.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 779A49122E1AD4BC00ABDE4F /* BookmarkFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BookmarkFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C755B62E4B70C30081D80F /* AuthFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AuthFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C755B72E4B70C30081D80F /* AuthFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AuthFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C974722E376124007198DA /* BookmarkFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BookmarkFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77C97DAA2E37D4AC007198DA /* AuthFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AuthFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77DBD8BE2E1AD0C600529428 /* BookmarkFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BookmarkFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77FEEF1C2EC5B0870023197A /* AuthFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AuthFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ - 081D9DBB2DF80DBE004F850D /* Exceptions for "DictionaryFeatureDemo" folder in "DictionaryFeatureDemo" target */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - membershipExceptions = ( - Info.plist, - ); - target = 081D9DA92DF80DBD004F850D /* DictionaryFeatureDemo */; - }; -/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ - -/* Begin PBXFileSystemSynchronizedRootGroup section */ - 081D9C1B2DF80854004F850D /* DictionaryFeature */ = { - isa = PBXFileSystemSynchronizedRootGroup; - path = DictionaryFeature; - sourceTree = ""; - }; - 081D9D772DF80CB1004F850D /* DictionaryFeatureInterface */ = { - isa = PBXFileSystemSynchronizedRootGroup; - path = DictionaryFeatureInterface; - sourceTree = ""; - }; - 081D9DAB2DF80DBD004F850D /* DictionaryFeatureDemo */ = { - isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - 081D9DBB2DF80DBE004F850D /* Exceptions for "DictionaryFeatureDemo" folder in "DictionaryFeatureDemo" target */, - ); - path = DictionaryFeatureDemo; - sourceTree = ""; - }; -/* End PBXFileSystemSynchronizedRootGroup section */ - -/* Begin PBXFrameworksBuildPhase section */ - 081D9C162DF80854004F850D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 081D9DD22DF80E5C004F850D /* RxRelay in Frameworks */, - 772DC9972E55CA93005F92E3 /* RxKeyboard in Frameworks */, - 081D9DD72DF80E69004F850D /* SnapKit in Frameworks */, - 081D9DC82DF80E1A004F850D /* DesignSystem.framework in Frameworks */, - 081D9DC52DF80E15004F850D /* DomainInterface.framework in Frameworks */, - 081D9DDA2DF80E7E004F850D /* ReactorKit in Frameworks */, - 77C974732E376124007198DA /* BookmarkFeatureInterface.framework in Frameworks */, - 77C7F4E52ED88D14009559E1 /* RxGesture in Frameworks */, - 77FEEF1D2EC5B0870023197A /* AuthFeatureInterface.framework in Frameworks */, - 081D9DD02DF80E5C004F850D /* RxCocoa in Frameworks */, - 77C97DAB2E37D4AC007198DA /* AuthFeature.framework in Frameworks */, - 081D9DC12DF80DF6004F850D /* BaseFeature.framework in Frameworks */, - 081D9DCA2DF80E27004F850D /* DictionaryFeatureInterface.framework in Frameworks */, - 773E8D462E7AF4A70094714D /* MyPageFeatureInterface.framework in Frameworks */, - 081D9DD42DF80E5C004F850D /* RxSwift in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 081D9D732DF80CB1004F850D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 081D9DE02DF80EC2004F850D /* DomainInterface.framework in Frameworks */, - 081D9DDC2DF80EBB004F850D /* BaseFeature.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 081D9DA72DF80DBD004F850D /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 081D9DFF2DF80F4B004F850D /* RxRelay in Frameworks */, - 081D9DFD2DF80F47004F850D /* RxSwift in Frameworks */, - 081D9DF82DF80F3C004F850D /* DesignSystem.framework in Frameworks */, - 081D9DE22DF80F1D004F850D /* DictionaryFeatureInterface.framework in Frameworks */, - 77C755B82E4B70C30081D80F /* AuthFeature.framework in Frameworks */, - 081D9DEC2DF80F23004F850D /* BaseFeature.framework in Frameworks */, - 773E8D502E7AF4F60094714D /* MyPageFeatureInterface.framework in Frameworks */, - 773E8D4D2E7AF4F00094714D /* MyPageFeature.framework in Frameworks */, - 77DBD8BF2E1AD0C600529428 /* BookmarkFeatureInterface.framework in Frameworks */, - 081D9DE72DF80F20004F850D /* DictionaryFeature.framework in Frameworks */, - 779A49132E1AD4BC00ABDE4F /* BookmarkFeature.framework in Frameworks */, - 081D9E082DF80F68004F850D /* Domain.framework in Frameworks */, - 081D9DF22DF80F30004F850D /* Data.framework in Frameworks */, - 77C755C12E4B917F0081D80F /* RxKeyboard in Frameworks */, - 081D9E052DF80F63004F850D /* DomainInterface.framework in Frameworks */, - 081D9DF52DF80F34004F850D /* DataMock.framework in Frameworks */, - 081D9DFB2DF80F44004F850D /* RxCocoa in Frameworks */, - 081D9DEF2DF80F2B004F850D /* Core.framework in Frameworks */, - 77C755BA2E4B70C30081D80F /* AuthFeatureInterface.framework in Frameworks */, - 081D9E032DF80F58004F850D /* ReactorKit in Frameworks */, - 773E8D4A2E7AF4D30094714D /* MyPageFeature.framework in Frameworks */, - 081D9E012DF80F53004F850D /* SnapKit in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 081D9C0F2DF80854004F850D = { - isa = PBXGroup; - children = ( - 081D9C1B2DF80854004F850D /* DictionaryFeature */, - 081D9D772DF80CB1004F850D /* DictionaryFeatureInterface */, - 081D9DAB2DF80DBD004F850D /* DictionaryFeatureDemo */, - 081D9DBF2DF80DF6004F850D /* Frameworks */, - 081D9C1A2DF80854004F850D /* Products */, - ); - sourceTree = ""; - }; - 081D9C1A2DF80854004F850D /* Products */ = { - isa = PBXGroup; - children = ( - 081D9C192DF80854004F850D /* DictionaryFeature.framework */, - 081D9D762DF80CB1004F850D /* DictionaryFeatureInterface.framework */, - 081D9DAA2DF80DBD004F850D /* DictionaryFeatureDemo.app */, - ); - name = Products; - sourceTree = ""; - }; - 081D9DBF2DF80DF6004F850D /* Frameworks */ = { - isa = PBXGroup; - children = ( - 77FEEF1C2EC5B0870023197A /* AuthFeatureInterface.framework */, - 773E8D4F2E7AF4F60094714D /* MyPageFeatureInterface.framework */, - 773E8D4C2E7AF4F00094714D /* MyPageFeature.framework */, - 773E8D492E7AF4D30094714D /* MyPageFeature.framework */, - 773E8D452E7AF4A70094714D /* MyPageFeatureInterface.framework */, - 77C755B62E4B70C30081D80F /* AuthFeature.framework */, - 77C755B72E4B70C30081D80F /* AuthFeatureInterface.framework */, - 77C97DAA2E37D4AC007198DA /* AuthFeature.framework */, - 77C974722E376124007198DA /* BookmarkFeatureInterface.framework */, - 779A49122E1AD4BC00ABDE4F /* BookmarkFeature.framework */, - 77DBD8BE2E1AD0C600529428 /* BookmarkFeatureInterface.framework */, - 775D68092DFD641E00DDAD2F /* Domain.framework */, - 775D68052DFD638900DDAD2F /* DataMock.framework */, - 081D9E072DF80F68004F850D /* Domain.framework */, - 081D9E042DF80F63004F850D /* DomainInterface.framework */, - 081D9DF72DF80F3C004F850D /* DesignSystem.framework */, - 081D9DF42DF80F34004F850D /* DataMock.framework */, - 081D9DF12DF80F30004F850D /* Data.framework */, - 081D9DEE2DF80F2B004F850D /* Core.framework */, - 081D9DEB2DF80F23004F850D /* BaseFeature.framework */, - 081D9DDF2DF80EC2004F850D /* DomainInterface.framework */, - 081D9DDB2DF80EBB004F850D /* BaseFeature.framework */, - 081D9DC72DF80E1A004F850D /* DesignSystem.framework */, - 081D9DC42DF80E15004F850D /* DomainInterface.framework */, - 081D9DC02DF80DF6004F850D /* BaseFeature.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 081D9C142DF80854004F850D /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 081D9D712DF80CB1004F850D /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 081D9C182DF80854004F850D /* DictionaryFeature */ = { - isa = PBXNativeTarget; - buildConfigurationList = 081D9C1F2DF80854004F850D /* Build configuration list for PBXNativeTarget "DictionaryFeature" */; - buildPhases = ( - 081D9C142DF80854004F850D /* Headers */, - 081D9C152DF80854004F850D /* Sources */, - 081D9C162DF80854004F850D /* Frameworks */, - 081D9C172DF80854004F850D /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 081D9DCD2DF80E27004F850D /* PBXTargetDependency */, - ); - fileSystemSynchronizedGroups = ( - 081D9C1B2DF80854004F850D /* DictionaryFeature */, - ); - name = DictionaryFeature; - packageProductDependencies = ( - 081D9DCF2DF80E5C004F850D /* RxCocoa */, - 081D9DD12DF80E5C004F850D /* RxRelay */, - 081D9DD32DF80E5C004F850D /* RxSwift */, - 081D9DD62DF80E69004F850D /* SnapKit */, - 081D9DD92DF80E7E004F850D /* ReactorKit */, - 772DC9962E55CA93005F92E3 /* RxKeyboard */, - 77C7F4E42ED88D14009559E1 /* RxGesture */, - ); - productName = DictionaryFeature; - productReference = 081D9C192DF80854004F850D /* DictionaryFeature.framework */; - productType = "com.apple.product-type.framework"; - }; - 081D9D752DF80CB1004F850D /* DictionaryFeatureInterface */ = { - isa = PBXNativeTarget; - buildConfigurationList = 081D9D7D2DF80CB1004F850D /* Build configuration list for PBXNativeTarget "DictionaryFeatureInterface" */; - buildPhases = ( - 081D9D712DF80CB1004F850D /* Headers */, - 081D9D722DF80CB1004F850D /* Sources */, - 081D9D732DF80CB1004F850D /* Frameworks */, - 081D9D742DF80CB1004F850D /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - fileSystemSynchronizedGroups = ( - 081D9D772DF80CB1004F850D /* DictionaryFeatureInterface */, - ); - name = DictionaryFeatureInterface; - packageProductDependencies = ( - ); - productName = DictionaryFeatureInterface; - productReference = 081D9D762DF80CB1004F850D /* DictionaryFeatureInterface.framework */; - productType = "com.apple.product-type.framework"; - }; - 081D9DA92DF80DBD004F850D /* DictionaryFeatureDemo */ = { - isa = PBXNativeTarget; - buildConfigurationList = 081D9DBC2DF80DBE004F850D /* Build configuration list for PBXNativeTarget "DictionaryFeatureDemo" */; - buildPhases = ( - 081D9DA62DF80DBD004F850D /* Sources */, - 081D9DA72DF80DBD004F850D /* Frameworks */, - 081D9DA82DF80DBD004F850D /* Resources */, - 081D9DE62DF80F1D004F850D /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 081D9DE52DF80F1D004F850D /* PBXTargetDependency */, - 081D9DEA2DF80F20004F850D /* PBXTargetDependency */, - ); - fileSystemSynchronizedGroups = ( - 081D9DAB2DF80DBD004F850D /* DictionaryFeatureDemo */, - ); - name = DictionaryFeatureDemo; - packageProductDependencies = ( - 081D9DFA2DF80F44004F850D /* RxCocoa */, - 081D9DFC2DF80F47004F850D /* RxSwift */, - 081D9DFE2DF80F4B004F850D /* RxRelay */, - 081D9E002DF80F53004F850D /* SnapKit */, - 081D9E022DF80F58004F850D /* ReactorKit */, - 77C755C02E4B917F0081D80F /* RxKeyboard */, - ); - productName = DictionaryFeatureDemo; - productReference = 081D9DAA2DF80DBD004F850D /* DictionaryFeatureDemo.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 081D9C102DF80854004F850D /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1620; - LastUpgradeCheck = 1620; - TargetAttributes = { - 081D9C182DF80854004F850D = { - CreatedOnToolsVersion = 16.2; - LastSwiftMigration = 1620; - }; - 081D9D752DF80CB1004F850D = { - CreatedOnToolsVersion = 16.2; - LastSwiftMigration = 1620; - }; - 081D9DA92DF80DBD004F850D = { - CreatedOnToolsVersion = 16.2; - }; - }; - }; - buildConfigurationList = 081D9C132DF80854004F850D /* Build configuration list for PBXProject "DictionaryFeature" */; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 081D9C0F2DF80854004F850D; - minimizedProjectReferenceProxies = 1; - packageReferences = ( - 081D9DCE2DF80E5C004F850D /* XCRemoteSwiftPackageReference "RxSwift" */, - 081D9DD52DF80E69004F850D /* XCRemoteSwiftPackageReference "SnapKit" */, - 081D9DD82DF80E7E004F850D /* XCRemoteSwiftPackageReference "ReactorKit" */, - 77C755BF2E4B917F0081D80F /* XCRemoteSwiftPackageReference "RxKeyboard" */, - 77C7F4E32ED88D14009559E1 /* XCRemoteSwiftPackageReference "RxGesture" */, - ); - preferredProjectObjectVersion = 77; - productRefGroup = 081D9C1A2DF80854004F850D /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 081D9C182DF80854004F850D /* DictionaryFeature */, - 081D9D752DF80CB1004F850D /* DictionaryFeatureInterface */, - 081D9DA92DF80DBD004F850D /* DictionaryFeatureDemo */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 081D9C172DF80854004F850D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 081D9D742DF80CB1004F850D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 081D9DA82DF80DBD004F850D /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 081D9C152DF80854004F850D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 081D9D722DF80CB1004F850D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 081D9DA62DF80DBD004F850D /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 081D9DCD2DF80E27004F850D /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 081D9D752DF80CB1004F850D /* DictionaryFeatureInterface */; - targetProxy = 081D9DCC2DF80E27004F850D /* PBXContainerItemProxy */; - }; - 081D9DE52DF80F1D004F850D /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 081D9D752DF80CB1004F850D /* DictionaryFeatureInterface */; - targetProxy = 081D9DE42DF80F1D004F850D /* PBXContainerItemProxy */; - }; - 081D9DEA2DF80F20004F850D /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 081D9C182DF80854004F850D /* DictionaryFeature */; - targetProxy = 081D9DE92DF80F20004F850D /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 081D9C202DF80854004F850D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.DictionaryFeature; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 081D9C212DF80854004F850D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.DictionaryFeature; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; - 081D9C222DF80854004F850D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.2; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 081D9C232DF80854004F850D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.2; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 081D9D7A2DF80CB1004F850D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = ( - "@executable_path/../Frameworks", - "@loader_path/Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 15.2; - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.DictionaryFeatureInterface; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = auto; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - XROS_DEPLOYMENT_TARGET = 2.2; - }; - name = Debug; - }; - 081D9D7B2DF80CB1004F850D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALLOW_TARGET_PLATFORM_SPECIALIZATION = YES; - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - "LD_RUNPATH_SEARCH_PATHS[sdk=macosx*]" = ( - "@executable_path/../Frameworks", - "@loader_path/Frameworks", - ); - MACOSX_DEPLOYMENT_TARGET = 15.2; - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.DictionaryFeatureInterface; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SDKROOT = auto; - SKIP_INSTALL = YES; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - XROS_DEPLOYMENT_TARGET = 2.2; - }; - name = Release; - }; - 081D9DBD2DF80DBE004F850D /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5QTRMS954; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = DictionaryFeatureDemo/Info.plist; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.MLS.DictionaryFeatureDemo; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = MLSDictionaryFeatureProvisioningProfileDev; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Debug; - }; - 081D9DBE2DF80DBE004F850D /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5QTRMS954; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = DictionaryFeatureDemo/Info.plist; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.MLS.DictionaryFeatureDemo; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = MLSDictionaryFeatureProvisioningProfile; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = 1; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 081D9C132DF80854004F850D /* Build configuration list for PBXProject "DictionaryFeature" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 081D9C222DF80854004F850D /* Debug */, - 081D9C232DF80854004F850D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 081D9C1F2DF80854004F850D /* Build configuration list for PBXNativeTarget "DictionaryFeature" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 081D9C202DF80854004F850D /* Debug */, - 081D9C212DF80854004F850D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 081D9D7D2DF80CB1004F850D /* Build configuration list for PBXNativeTarget "DictionaryFeatureInterface" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 081D9D7A2DF80CB1004F850D /* Debug */, - 081D9D7B2DF80CB1004F850D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 081D9DBC2DF80DBE004F850D /* Build configuration list for PBXNativeTarget "DictionaryFeatureDemo" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 081D9DBD2DF80DBE004F850D /* Debug */, - 081D9DBE2DF80DBE004F850D /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - 081D9DCE2DF80E5C004F850D /* XCRemoteSwiftPackageReference "RxSwift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ReactiveX/RxSwift"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 6.9.0; - }; - }; - 081D9DD52DF80E69004F850D /* XCRemoteSwiftPackageReference "SnapKit" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/SnapKit/SnapKit.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 5.7.1; - }; - }; - 081D9DD82DF80E7E004F850D /* XCRemoteSwiftPackageReference "ReactorKit" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ReactorKit/ReactorKit"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 3.2.0; - }; - }; - 77C755BF2E4B917F0081D80F /* XCRemoteSwiftPackageReference "RxKeyboard" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/RxSwiftCommunity/RxKeyboard"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.0.1; - }; - }; - 77C7F4E32ED88D14009559E1 /* XCRemoteSwiftPackageReference "RxGesture" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/RxSwiftCommunity/RxGesture.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 4.0.4; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 081D9DCF2DF80E5C004F850D /* RxCocoa */ = { - isa = XCSwiftPackageProductDependency; - package = 081D9DCE2DF80E5C004F850D /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxCocoa; - }; - 081D9DD12DF80E5C004F850D /* RxRelay */ = { - isa = XCSwiftPackageProductDependency; - package = 081D9DCE2DF80E5C004F850D /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxRelay; - }; - 081D9DD32DF80E5C004F850D /* RxSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 081D9DCE2DF80E5C004F850D /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxSwift; - }; - 081D9DD62DF80E69004F850D /* SnapKit */ = { - isa = XCSwiftPackageProductDependency; - package = 081D9DD52DF80E69004F850D /* XCRemoteSwiftPackageReference "SnapKit" */; - productName = SnapKit; - }; - 081D9DD92DF80E7E004F850D /* ReactorKit */ = { - isa = XCSwiftPackageProductDependency; - package = 081D9DD82DF80E7E004F850D /* XCRemoteSwiftPackageReference "ReactorKit" */; - productName = ReactorKit; - }; - 081D9DFA2DF80F44004F850D /* RxCocoa */ = { - isa = XCSwiftPackageProductDependency; - package = 081D9DCE2DF80E5C004F850D /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxCocoa; - }; - 081D9DFC2DF80F47004F850D /* RxSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 081D9DCE2DF80E5C004F850D /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxSwift; - }; - 081D9DFE2DF80F4B004F850D /* RxRelay */ = { - isa = XCSwiftPackageProductDependency; - package = 081D9DCE2DF80E5C004F850D /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxRelay; - }; - 081D9E002DF80F53004F850D /* SnapKit */ = { - isa = XCSwiftPackageProductDependency; - package = 081D9DD52DF80E69004F850D /* XCRemoteSwiftPackageReference "SnapKit" */; - productName = SnapKit; - }; - 081D9E022DF80F58004F850D /* ReactorKit */ = { - isa = XCSwiftPackageProductDependency; - package = 081D9DD82DF80E7E004F850D /* XCRemoteSwiftPackageReference "ReactorKit" */; - productName = ReactorKit; - }; - 772DC9962E55CA93005F92E3 /* RxKeyboard */ = { - isa = XCSwiftPackageProductDependency; - package = 77C755BF2E4B917F0081D80F /* XCRemoteSwiftPackageReference "RxKeyboard" */; - productName = RxKeyboard; - }; - 77C755C02E4B917F0081D80F /* RxKeyboard */ = { - isa = XCSwiftPackageProductDependency; - package = 77C755BF2E4B917F0081D80F /* XCRemoteSwiftPackageReference "RxKeyboard" */; - productName = RxKeyboard; - }; - 77C7F4E42ED88D14009559E1 /* RxGesture */ = { - isa = XCSwiftPackageProductDependency; - package = 77C7F4E32ED88D14009559E1 /* XCRemoteSwiftPackageReference "RxGesture" */; - productName = RxGesture; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 081D9C102DF80854004F850D /* Project object */; -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/MLS/Presentation/DictionaryFeature/DictionaryFeature.xcodeproj/project.xcworkspace/contents.xcworkspacedata deleted file mode 100644 index 919434a6..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature.xcodeproj/project.xcworkspace/contents.xcworkspacedata +++ /dev/null @@ -1,7 +0,0 @@ - - - - - diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature.xcodeproj/xcshareddata/xcschemes/DictionaryFeatureDemo.xcscheme b/MLS/Presentation/DictionaryFeature/DictionaryFeature.xcodeproj/xcshareddata/xcschemes/DictionaryFeatureDemo.xcscheme deleted file mode 100644 index 4c48101b..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature.xcodeproj/xcshareddata/xcschemes/DictionaryFeatureDemo.xcscheme +++ /dev/null @@ -1,78 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/.DS_Store b/MLS/Presentation/DictionaryFeature/DictionaryFeature/.DS_Store deleted file mode 100644 index 3c58da99..00000000 Binary files a/MLS/Presentation/DictionaryFeature/DictionaryFeature/.DS_Store and /dev/null differ diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/.DS_Store b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/.DS_Store deleted file mode 100644 index 9c35ab72..00000000 Binary files a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/.DS_Store and /dev/null differ diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseView.swift deleted file mode 100644 index eb3e4c90..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseView.swift +++ /dev/null @@ -1,488 +0,0 @@ -import UIKit - -import DesignSystem -import DomainInterface - -import SnapKit - -class DictionaryDetailBaseView: UIView { - // MARK: - Type - public enum Constant { - static let iconInset: CGFloat = 10 - static let navHeight: CGFloat = 44 - static let buttonSize: CGFloat = 44 - static let imageRadius: CGFloat = 24 - static let imageContentViewSize: CGFloat = 160 - static let imageSize: CGFloat = 112 - static let imageBottomMargin: CGFloat = 12 - static let horizontalInset: CGFloat = 16 - static let bookmarkViewSize: CGFloat = 44 - static let bookmarkViewMargin: CGFloat = 6 - static let bookmarkViewInset: CGFloat = 10 - static let textMargin: CGFloat = 4 - static let stickyHeight: CGFloat = 56 - static let dividerHeight: CGFloat = 1 - static let tagsBottomMargin: CGFloat = 30 - static let tabBarHeight: CGFloat = 40 - static let tabBarTopMargin: CGFloat = 30 - static let imageContentTopMargin: CGFloat = 20 - static let tagVerticalSpacing: CGFloat = 10 - static let tabBarSpacing: CGFloat = 20 - static let badgeHeight: CGFloat = 24 - static let numberOfLines: Int = 0 - static let tabBarStackViewInset: UIEdgeInsets = .init(top: 30, left: 16, bottom: 0, right: 16) - static let tagStackViewInset: UIEdgeInsets = .init(top: 10, left: 0, bottom: 10, right: 0) - static let secondSectionStackViewInset: UIEdgeInsets = .init(top: 0, left: 0, bottom: 20, right: 0) - static let stackViewInset: UIEdgeInsets = .init(top: 20, left: 0, bottom: 0, right: 0) - - static let menuTabBarButtonInset: NSDirectionalEdgeInsets = .init(top: 9, leading: 4, bottom: 9, trailing: 4) - static let underLineHeight: CGFloat = 2 - static let underTag: Int = 999999 - } - - // MARK: - Components - /// header에 들어가 컴포넌트들 담을 컨테이너 뷰 - public let headerView: UIView = { - let view = UIView() - return view - }() - - public let backButton: UIButton = { - let button = UIButton() - button - .setImage( - DesignSystemAsset - .image(named: "arrowBack")? - .withRenderingMode(.alwaysTemplate) - .resizableImage( - withCapInsets: UIEdgeInsets( - top: Constant.iconInset, - left: Constant.iconInset, - bottom: Constant.iconInset, - right: Constant.iconInset - ) - ), - for: .normal - ) - button.tintColor = .textColor - - return button - }() - - public var titleLabel = UILabel() - - public let dictButton: UIButton = { - let button = UIButton() - button - .setImage( - DesignSystemAsset - .image(named: "dictionary")? - .withRenderingMode(.alwaysTemplate) - .resizableImage( - withCapInsets: UIEdgeInsets( - top: Constant.iconInset, - left: Constant.iconInset, - bottom: Constant.iconInset, - right: Constant.iconInset - ) - ), - for: .normal - ) - button.tintColor = .textColor - - return button - }() - - public let reportButton: UIButton = { - let button = UIButton() - button - .setImage( - DesignSystemAsset - .image(named: "errorBlack")? - .withRenderingMode(.alwaysTemplate) - .resizableImage( - withCapInsets: UIEdgeInsets( - top: Constant.iconInset, - left: Constant.iconInset, - bottom: Constant.iconInset, - right: Constant.iconInset - ) - ), - for: .normal - ) - button.tintColor = .textColor - - return button - }() - - public let scrollView: UIScrollView = { - let scrollView = UIScrollView() - scrollView.backgroundColor = .neutral100 - return scrollView - }() - - /// 스크롤 뷰에 들어갈 컴포넌트들을 담을 스택 뷰 - /// 각 컴포너트들의 간격이 다 다름 - public let stackView: UIStackView = { - let stackView = UIStackView() - // 수직 스택 뷰 - stackView.axis = .vertical - stackView.backgroundColor = .whiteMLS - // 아이템 기본 중앙배치 - stackView.alignment = .center - stackView.isLayoutMarginsRelativeArrangement = true - stackView.layoutMargins = Constant.stackViewInset - return stackView - }() - - public let imageContentView: UIView = { - let view = UIView() - view.layer.cornerRadius = Constant.imageRadius - return view - }() - - // 이미지 뷰 - public let imageView: UIImageView = { - let view = UIImageView() - view.clipsToBounds = true - view.contentMode = .scaleAspectFit - return view - }() - - public let bookmarkContentView: UIView = { - let view = UIView() - return view - }() - - // 북마크 버튼 - public let bookmarkButton = UIButton() - - // 이름 - public let nameLabel: UILabel = { - let label = UILabel() - // 줄 수 제한 없음 - label.numberOfLines = 0 - // 단어 단위로 줄 바꿈 - label.lineBreakMode = .byWordWrapping - // 가운데 정렬 - label.textAlignment = .center - return label - }() - - // SubText - level, 지역 등 - public let subTextLabel: UILabel = { - let label = UILabel() - - label.numberOfLines = 0 - label.lineBreakMode = .byWordWrapping - label.textAlignment = .center - - return label - }() - - // tagView들을 담는 가로 stackView들을 담을 세로 stackView -> 말이 너무 어려운데.. - // 충분히 이해 하시겠죠...?ㅠㅠ - public let tagsVerticalStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .vertical - // 각 가로 태그줄의 간격 10 - stackView.spacing = Constant.tagVerticalSpacing - // horizontal tag들이 중앙정렬 되도록 - stackView.alignment = .center - stackView.isLayoutMarginsRelativeArrangement = true - stackView.layoutMargins = Constant.tagStackViewInset - - return stackView - }() - - // tabBar StackView - public let tabBarStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .horizontal - stackView.backgroundColor = .whiteMLS - stackView.distribution = .fill - stackView.spacing = Constant.tabBarSpacing - stackView.alignment = .leading - // layoutMargins을 사용하여 inset 설정 - stackView.isLayoutMarginsRelativeArrangement = true - stackView.layoutMargins = Constant.tabBarStackViewInset - - return stackView - }() - - // tabBar Sticky StackView - public let tabBarStickyStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .horizontal - stackView.backgroundColor = .whiteMLS - stackView.distribution = .fill - stackView.spacing = Constant.tabBarSpacing - stackView.alignment = .bottom - // layoutMargins을 사용하여 inset 설정 - stackView.isLayoutMarginsRelativeArrangement = true - stackView.layoutMargins = Constant.tabBarStackViewInset - stackView.isHidden = true - - return stackView - }() - - // tabBar 하단 구분선 - public let tabBarDividerView: UIView = { - let view = UIView() - view.backgroundColor = .neutral300 - - return view - }() - - // sticky tab Bar 하단 구분선 - public let stickyTabBarDividerView: UIView = { - let view = UIView() - view.backgroundColor = .neutral300 - view.isHidden = true - return view - }() - - // 두번째 섹션 스택 뷰 (배경색 바뀌는 부분) - public let secondSectionStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .vertical - stackView.alignment = .center - stackView.backgroundColor = .neutral100 - stackView.isLayoutMarginsRelativeArrangement = true - stackView.layoutMargins = Constant.secondSectionStackViewInset - - return stackView - }() - - // MARK: - Init - init() { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension DictionaryDetailBaseView { - func addViews() { - // forEach 활용하여 중복코드 제거 - [backButton, titleLabel, dictButton, reportButton].forEach { headerView.addSubview($0) } - - [headerView, scrollView].forEach { - addSubview($0) - } - // stackView를 scrollView안에 넣어줘야 함 - scrollView.addSubview(stackView) - - [imageContentView, nameLabel, subTextLabel, tagsVerticalStackView].forEach { - // 스택뷰에 subView 추가 - stackView.addArrangedSubview($0) - } - - scrollView.addSubview(secondSectionStackView) - scrollView.addSubview(tabBarStackView) - scrollView.addSubview(tabBarDividerView) - scrollView.addSubview(tabBarStickyStackView) - scrollView.addSubview(stickyTabBarDividerView) - - imageContentView.addSubview(imageView) - imageContentView.addSubview(bookmarkContentView) - bookmarkContentView.addSubview(bookmarkButton) - } - - func setupConstraints() { - headerView.snp.makeConstraints { make in - make.top.equalTo(self.safeAreaLayoutGuide.snp.top) - make.horizontalEdges.equalToSuperview() - make.height.equalTo(Constant.buttonSize) - } - backButton.snp.makeConstraints { make in - make.leading.centerY.equalToSuperview() - make.size.equalTo(Constant.buttonSize) - } - - titleLabel.snp.makeConstraints { make in - make.center.equalToSuperview() - } - - dictButton.snp.makeConstraints { make in - make.trailing.equalTo(reportButton.snp.leading) - make.centerY.equalToSuperview() - make.size.equalTo(Constant.buttonSize) - } - - reportButton.snp.makeConstraints { make in - make.trailing.centerY.equalToSuperview() - make.size.equalTo(Constant.buttonSize) - } - - scrollView.snp.makeConstraints { make in - make.top.equalTo(headerView.snp.bottom) - make.bottom.equalToSuperview() - make.leading.equalToSuperview() - make.trailing.equalToSuperview() - } - - stackView.snp.makeConstraints { make in - make.top.equalTo(scrollView.snp.top) - make.centerX.equalToSuperview() - make.horizontalEdges.equalToSuperview() - } - - imageContentView.snp.makeConstraints { make in - make.centerX.equalToSuperview() - make.size.equalTo(Constant.imageContentViewSize) - } - - imageView.snp.makeConstraints { make in - make.center.equalToSuperview() - make.width.equalTo(imageContentView.snp.width).multipliedBy(0.42) - } - - bookmarkContentView.snp.makeConstraints { make in - make.top.trailing.equalToSuperview().inset(Constant.bookmarkViewMargin) - make.size.equalTo(Constant.bookmarkViewSize) - } - - bookmarkButton.snp.makeConstraints { make in - make.center.equalToSuperview().inset(Constant.bookmarkViewInset) - } - - // 스택뷰 속 간격 커스텀 -> imageContentView와 다음 스택뷰 셀의 간격 imageBottomMargin 만큼 - stackView.setCustomSpacing(Constant.imageBottomMargin, after: imageContentView) - - nameLabel.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - } - - // nameLabel과 그 아래에 들어올 subText간 간격 조정 - stackView.setCustomSpacing(Constant.textMargin, after: nameLabel) - - subTextLabel.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - } - - stackView.setCustomSpacing(Constant.textMargin, after: subTextLabel) - - tabBarStackView.snp.makeConstraints { make in - // make.height.equalTo(Constant.tabBarHeight) - make.width.equalToSuperview() - make.top.equalTo(stackView.snp.bottom) - } - - tabBarDividerView.snp.makeConstraints { make in - make.height.equalTo(Constant.dividerHeight) - make.top.equalTo(tabBarStackView.snp.bottom) - make.horizontalEdges.equalToSuperview() - } - - // centerX와 horizontal을 각각 잡은이유 - secondSectionStackView.snp.makeConstraints { make in - make.top.equalTo(tabBarStackView.snp.bottom) - make.centerX.equalToSuperview() - make.horizontalEdges.equalToSuperview() - make.bottom.equalTo(scrollView.snp.bottom) - } - - tabBarStickyStackView.snp.makeConstraints { make in - // make.height.equalTo(Constant.stickyHeight) - make.width.equalToSuperview() - make.top.equalTo(headerView.snp.bottom) - } - - stickyTabBarDividerView.snp.makeConstraints { make in - make.top.equalTo(tabBarStickyStackView.snp.bottom) - make.horizontalEdges.equalToSuperview() - make.height.equalTo(Constant.dividerHeight) - } - } - - func configureUI() { - backgroundColor = .whiteMLS - } -} - -extension DictionaryDetailBaseView { - func createHorizontalStackView() -> UIStackView { - let stackView = UIStackView() - stackView.axis = .horizontal - stackView.alignment = .center - stackView.spacing = DictionaryDetailBaseView.Constant.tagVerticalSpacing - stackView.distribution = .fill - return stackView - } - - // 메뉴 탭바 버튼 생성하기 - func createMenuButton(title: String, tag: Int) -> UIButton { - let config = setupConfig() - let button = UIButton(configuration: config) - button.setAttributedTitle(.makeStyledString(font: .b_m_r, text: title), for: .normal) - button.setTitleColor(.neutral600, for: .normal) - button.titleLabel?.font = UIFont.b_m_r - button.tag = tag - - let underline = UIView() - underline.backgroundColor = .textColor - underline.isHidden = true - underline.tag = Constant.underTag - - button.addSubview(underline) - underline.snp.makeConstraints { make in - make.height.equalTo(Constant.underLineHeight) - make.leading.trailing.bottom.equalToSuperview() - } - - return button - } - - func setupConfig() -> UIButton.Configuration { - var config = UIButton.Configuration.plain() - config.contentInsets = Constant.menuTabBarButtonInset - return config - } - - // 태그 뱃지 제약사항 설정 - func setBadgeConstraints(_ badge: Badge, width: CGFloat) { - badge.snp.makeConstraints { make in - make.width.equalTo(width) - make.height.equalTo(DictionaryDetailBaseView.Constant.badgeHeight) - } - - } - - func setTabView(index: Int, contentViews: [UIView]) { - // 기존 뷰 제거 - for view in secondSectionStackView.arrangedSubviews { - secondSectionStackView.removeArrangedSubview(view) - view.removeFromSuperview() - } - // 새 뷰 추가 - let newView = contentViews[index] - secondSectionStackView.addArrangedSubview(newView) - - // constraint 유지 - newView.snp.makeConstraints { make in - make.width.equalToSuperview() - } - } - - func setupSpacerView() { - let spacerView = UIView() - let stickySpacerView = UIView() - spacerView.setContentHuggingPriority(.defaultLow, for: .horizontal) - stickySpacerView.setContentHuggingPriority(.defaultLow, for: .horizontal) - tabBarStackView.addArrangedSubview(spacerView) - tabBarStickyStackView.addArrangedSubview(stickySpacerView) - } - - func setBookmark(isBookmarked: Bool) { - bookmarkButton.isSelected = isBookmarked - bookmarkButton.setImage(DesignSystemAsset.image(named: isBookmarked ? "bookmark" : "bookmarkGrayBorder"), for: .normal) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift deleted file mode 100644 index 84d5dfcb..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailBaseViewController.swift +++ /dev/null @@ -1,424 +0,0 @@ -import UIKit - -import AuthFeatureInterface -import BaseFeature -import BookmarkFeatureInterface -import DesignSystem -import DictionaryFeatureInterface -import DomainInterface - -import RxCocoa -import RxSwift - -class DictionaryDetailBaseViewController: BaseViewController { - // MARK: - Properties - public var disposeBag = DisposeBag() - - private var didSelectInitialTab = false - var selectedIndex = 0 - var bookmarkRelay: PublishRelay<(id: Int, newBookmarkId: Int?)>? - var loginRelay: PublishRelay? - - /// 각 탭에 해당하는 콘텐츠 뷰들을 담는 배열 - public var contentViews: [UIView] = [] { - didSet { - let index = currentTabIndex ?? 0 - guard index < contentViews.count else { return } - mainView.setTabView(index: index, contentViews: contentViews) - } - } - - /// 현재 보여지고 있는 뷰의 인덱스 - private var currentTabIndex: Int? - - let bookmarkModalFactory: BookmarkModalFactory - let loginFactory: LoginFactory - public let dictionaryDetailFactory: DictionaryDetailFactory - private let detailOnBoardingFactory: DetailOnBoardingFactory - private let appCoordinator: AppCoordinatorProtocol - - private let fetchVisitDictionaryDetailUseCase: FetchVisitDictionaryDetailUseCase - - // MARK: - Components - public var mainView = DictionaryDetailBaseView() - - // 타입설정 - public var type: DictionaryItemType - - public init( - type: DictionaryItemType, - bookmarkModalFactory: BookmarkModalFactory, - loginFactory: LoginFactory, - dictionaryDetailFactory: DictionaryDetailFactory, - detailOnBoardingFactory: DetailOnBoardingFactory, - appCoordinator: AppCoordinatorProtocol, - fetchVisitDictionaryDetailUseCase: FetchVisitDictionaryDetailUseCase, - bookmarkRelay: PublishRelay<(id: Int, newBookmarkId: Int?)>?, - loginRelay: PublishRelay? - ) { - self.type = type - self.bookmarkModalFactory = bookmarkModalFactory - self.loginFactory = loginFactory - self.appCoordinator = appCoordinator - self.dictionaryDetailFactory = dictionaryDetailFactory - self.detailOnBoardingFactory = detailOnBoardingFactory - self.fetchVisitDictionaryDetailUseCase = fetchVisitDictionaryDetailUseCase - mainView.titleLabel.attributedText = .makeStyledString(font: .sub_m_b, text: type.detailTitle) - self.bookmarkRelay = bookmarkRelay - self.loginRelay = loginRelay - super.init() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - bind() // 액션 바인딩 - setupMenu(type.detailTypes) - } - - override func viewDidLayoutSubviews() { - super.viewDidLayoutSubviews() - - // 처음 진입 및 뷰가 추가 되었는지 확인 - if !didSelectInitialTab { - didSelectMenuTab(index: 0) - didSelectInitialTab = true - } - } - - open func toggleBookmark() { - assertionFailure("Subclass should override toggleBookmark()") - } - - open func checkLogin() -> Bool? { - return nil - } - - open func undoBookmark() { - assertionFailure("Subclass should override undoBookmark()") - } -} - -// MARK: - SetUp -private extension DictionaryDetailBaseViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide) - make.horizontalEdges.bottom.equalToSuperview() - } - } - - func configureUI() { - mainView.scrollView.delegate = self - checkVisited() - } -} - -/// 스티키 헤더 만들기 위한 델리게이트 -extension DictionaryDetailBaseViewController: UIScrollViewDelegate { - func scrollViewDidScroll(_ scrollView: UIScrollView) { - // 탭바의 frame을 self.view 기준으로 변환 - let tabBarY = mainView.tabBarStackView.convert(mainView.tabBarStackView.bounds, to: view) - - if tabBarY.origin.y <= view.safeAreaInsets.top + DictionaryDetailBaseView.Constant.buttonSize + DictionaryDetailBaseView.Constant.horizontalInset - DictionaryDetailBaseView.Constant.tabBarStackViewInset.top { - // safearea + 헤더뷰 + 헤더뷰와의 간격 16 = 122 - mainView.tabBarStickyStackView.isHidden = false - mainView.stickyTabBarDividerView.isHidden = false - } else { - mainView.tabBarStickyStackView.isHidden = true - mainView.stickyTabBarDividerView.isHidden = true - } - - let nameY = mainView.nameLabel.convert(mainView.nameLabel.bounds, to: view) - - if nameY.origin.y <= view.safeAreaInsets.top + DictionaryDetailBaseView.Constant.buttonSize + DictionaryDetailBaseView.Constant.horizontalInset { - // 메랜에서 이름이 가장 긴 몬스터의 경우 '다크 주니어 예티와 페페'로 알고 있는데, 따로 텍스트 길이에 대한 제약사항을 안줘도 다크 주니어 예티와 페페가 잘 표시가 됨. 제약사항 필요한가? - mainView.titleLabel.attributedText = .makeStyledString(font: .sub_m_b, text: mainView.nameLabel.text) - } else { - mainView.titleLabel.attributedText = .makeStyledString(font: .sub_m_b, text: type.detailTitle) - } - } -} - -extension DictionaryDetailBaseViewController { - /// image: 메인 이미지 - /// backgroundColor: dictionaryItemType에 따른 배경 색 - /// name: 해당 dict의 이름 - /// subText: level, 지역 등 다양한 서브 텍스트 - struct Input { - let imageUrl: String? - let backgroundColor: UIColor - let name: String - let subText: String? // 없는 경우도 있는듯 - } - - func inject(input: Input) { - // Load image if URL exists - if let imageUrlString = input.imageUrl { - ImageLoader.shared.loadImage(stringURL: imageUrlString) { [weak self] image in - guard let self = self, let image = image else { return } - self.mainView.imageView.image = image - } - } else { - mainView.imageView.image = nil - } - mainView.imageContentView.backgroundColor = input.backgroundColor - mainView.nameLabel.attributedText = .makeStyledString(font: .sub_l_m, text: input.name, color: .textColor) - mainView.subTextLabel.attributedText = .makeStyledString(font: .b_s_r, text: input.subText, color: .neutral500) - } - - func makeTagsRow(_ tags: Effectiveness) { - mainView.tagsVerticalStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } - - let maxWidth = UIScreen.main.bounds.width - DictionaryDetailBaseView.Constant.horizontalInset // 좌우 여백 고려 (16 * 2) - let tagSpacing: CGFloat = DictionaryDetailBaseView.Constant.tagVerticalSpacing - - var tagsRowStackView = mainView.createHorizontalStackView() - mainView.tagsVerticalStackView.addArrangedSubview(tagsRowStackView) - - var currentRowWidth: CGFloat = 0 - for (element, value) in tags.nonNilElements() { - let badge = Badge(style: .element("\(element.rawValue) \(value)")) - let fittingSize = badge.systemLayoutSizeFitting(UIView.layoutFittingCompressedSize) - let badgeWidth = fittingSize.width - - if currentRowWidth + badgeWidth + tagSpacing > maxWidth { - tagsRowStackView = mainView.createHorizontalStackView() - mainView.tagsVerticalStackView.addArrangedSubview(tagsRowStackView) - currentRowWidth = 0 - } - - tagsRowStackView.addArrangedSubview(badge) - currentRowWidth += badgeWidth + tagSpacing - mainView.setBadgeConstraints(badge, width: badgeWidth) - } - } - - // 탭바 메뉴 버튼 구성하기(스티키 쪽도 똑같이 구현) - func setupMenu(_ menus: [DetailType]) { - var firstIndexButton: UIButton? // 처음 화면 나올때 첫번째 버튼 클릭되게 하기 위해 첫번째 버튼 저장할 변수 - var firstStickyIndexButton: UIButton? - // 버튼 configuration 설정 -> inset 설정 - for (index, menu) in menus.enumerated() { - let button = mainView.createMenuButton(title: menu.description, tag: index) - button.rx.tap.bind { [weak self] _ in - self?.menuTabTapped(button) - } - .disposed(by: disposeBag) - - let stickyButton = mainView.createMenuButton(title: menu.description, tag: index) - stickyButton.rx.tap.bind { [weak self] _ in - self?.menuTabTapped(stickyButton) - } - .disposed(by: disposeBag) - - mainView.tabBarStackView.addArrangedSubview(button) - mainView.tabBarStickyStackView.addArrangedSubview(stickyButton) // 스티키 역할을 할 스택뷰에다가도 똑같은 버튼 추가 - - if index == 0 { - firstIndexButton = button - firstStickyIndexButton = button - } - } - mainView.setupSpacerView() - // 화면에 버튼 다 생성 한 이후에 첫번째 버튼 클릭 이벤트 유발 - if let firstIndexButton = firstIndexButton, let firstStickyIndexButton = firstStickyIndexButton { - menuTabTapped(firstIndexButton) - menuTabTapped(firstStickyIndexButton) - } - } - - private func menuTabTapped(_ sender: UIButton) { - let selectedTag = sender.tag - - updateButtonStates(in: mainView.tabBarStackView, selectedTag: selectedTag) - // 스티키 탭 버튼 상태 변경 - updateButtonStates(in: mainView.tabBarStickyStackView, selectedTag: selectedTag) - - // 자식 디테일 뷰컨에서 오버라이드 해서 사용하기? - didSelectMenuTab(index: sender.tag) - } - - // 버튼 상태 변경 함수 - private func updateButtonStates(in stackView: UIStackView, selectedTag: Int) { - for (index, subview) in stackView.arrangedSubviews.enumerated() { - guard let button = subview as? UIButton else { continue } - let title = button.titleLabel?.text ?? "" - - let underline = button.subviews.first { $0.tag == DictionaryDetailBaseView.Constant.underTag } - - if index == selectedTag { - button.setAttributedTitle(.makeStyledString(font: .sub_m_b, text: title, color: .black), for: .normal) - underline?.isHidden = false - } else { - button.setAttributedTitle(.makeStyledString(font: .b_m_r, text: title, color: .neutral600), for: .normal) - underline?.isHidden = true - } - } - } - - func didSelectMenuTab(index: Int) { - // 인덱스 유효성 검사 - guard index < contentViews.count else { return } - - // 현재 뷰가 같다면 변경 안함 - if currentTabIndex == index { return } - // 각 탭에 맞는 뷰 설정 - mainView.setTabView(index: index, contentViews: contentViews) - currentTabIndex = index - } - - func checkVisited() { - fetchVisitDictionaryDetailUseCase.execute() - .withUnretained(self) - .subscribe { owner, isVisit in - if !isVisit { - let viewController = owner.detailOnBoardingFactory.make() - viewController.modalPresentationStyle = .overFullScreen - viewController.modalTransitionStyle = .crossDissolve - owner.present(viewController, animated: true) - } - } - .disposed(by: disposeBag) - } -} - -private extension DictionaryDetailBaseViewController { - func bind() { - // 뒤로가기 버튼 액션 바인드 - bindBackButton() - } - - func bindBackButton() { - mainView.backButton.rx.tap - .observe(on: MainScheduler.instance) - .withUnretained(self) - .bind { owner, _ in - owner.navigationController?.popViewController(animated: true) - } - .disposed(by: disposeBag) - - mainView.dictButton.rx.tap - .observe(on: MainScheduler.instance) - .withUnretained(self) - .bind { owner, _ in - owner.appCoordinator.showMainTab() - } - .disposed(by: disposeBag) - - mainView.bookmarkButton.rx.tap - .withUnretained(self) - .subscribe(onNext: { owner, _ in - owner.handleBookmarkTapped() - }) - .disposed(by: disposeBag) - } -} - -extension DictionaryDetailBaseViewController { - public func bindReportButton(providerId: Observable, itemName: Observable) { - mainView.reportButton.rx.tap - .withLatestFrom(Observable.combineLatest(providerId, itemName)) - .bind { [weak self] id, name in - guard let self = self else { return } - let urlString = "https://forms.fillout.com/t/1JR9wiyv1Uus?providerId=\(id)&item=\(name)" - GuideAlertFactory.show( - mainText: "잘못된 정보를 발견하셨나요?\n운영진에게 알려주세요!", - ctaText: "건의하기", - cancelText: "취소", - ctaAction: { [weak self] in - guard self != nil else { return } - if let url = URL(string: urlString) { - UIApplication.shared.open(url) - } - }, - cancelAction: { GuideAlertFactory.dismiss() } - ) - } - .disposed(by: disposeBag) - } -} - -extension DictionaryDetailBaseViewController { - func handleBookmarkTapped() { - guard let isLogin = checkLogin() else { return } - - if !isLogin { - presentLoginGuide() - loginRelay?.accept(()) - return - } - - toggleBookmark() - } -} - -extension DictionaryDetailBaseViewController { - func presentAddSnackBar(bookmarkId: Int?, imageUrl: String?, background: UIColor) { - guard let bookmarkId else { return } - SnackBarFactory.createSnackBar( - type: .normal, - imageUrl: imageUrl, - imageBackgroundColor: background, - text: "아이템을 북마크에 추가했어요.", - buttonText: "컬렉션 추가", - buttonAction: { [weak self] in - self?.presentCollectionModal(bookmarkId: bookmarkId) - } - ) - } - - func presentDeleteSnackBar(imageUrl: String?, background: UIColor) { - SnackBarFactory.createSnackBar( - type: .delete, - imageUrl: imageUrl, - imageBackgroundColor: background, - text: "아이템을 북마크에서 삭제했어요.", - buttonText: "되돌리기", - buttonAction: { [weak self] in - self?.undoBookmark() - } - ) - } - - private func presentCollectionModal(bookmarkId: Int) { - let viewController = bookmarkModalFactory.make(bookmarkIds: [bookmarkId]) { isAdd in - if isAdd { - ToastFactory.createToast(message: "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요.") - } - } - viewController.modalPresentationStyle = .pageSheet - if let sheet = viewController.sheetPresentationController { - sheet.detents = [.medium(), .large()] - sheet.prefersGrabberVisible = true - sheet.preferredCornerRadius = 16 - } - self.present(viewController, animated: true) - } - - func presentLoginGuide() { - GuideAlertFactory.show( - mainText: "북마크를 하려면 로그인이 필요해요.", - ctaText: "로그인 하기", - cancelText: "취소", - ctaAction: { [weak self] in - guard let self else { return } - let vc = self.loginFactory.make(exitRoute: .pop) - self.navigationController?.pushViewController(vc, animated: true) - }, - cancelAction: nil - ) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift deleted file mode 100644 index c0f1a578..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/DictionaryDetailFactoryImpl.swift +++ /dev/null @@ -1,201 +0,0 @@ -import AuthFeatureInterface -import BaseFeature -import BookmarkFeatureInterface -import DictionaryFeatureInterface -import DomainInterface - -import RxCocoa - -public final class DictionaryDetailFactoryImpl: DictionaryDetailFactory { - private let loginFactory: () -> LoginFactory - private let bookmarkModalFactory: BookmarkModalFactory - private let dictionaryDetailFactory: () -> DictionaryDetailFactory - private let detailOnBoardingFactory: DetailOnBoardingFactory - private let appCoordinator: () -> AppCoordinatorProtocol - - private let dictionaryDetailMapUseCase: FetchDictionaryDetailMapUseCase - private let dictionaryDetailMapSpawnMonsterUseCase: FetchDictionaryDetailMapSpawnMonsterUseCase - private let dictionaryDetailMapNpcUseCase: FetchDictionaryDetailMapNpcUseCase - private let dictionaryDetailQuestLinkedQuestsUseCase: FetchDictionaryDetailQuestLinkedQuestsUseCase - private let dictionaryDetailQuestUseCase: FetchDictionaryDetailQuestUseCase - private let dictionaryDetailItemDropMonsterUseCase: FetchDictionaryDetailItemDropMonsterUseCase - private let dictionaryDetailItemUseCase: FetchDictionaryDetailItemUseCase - private let dictionaryDetailNpcUseCase: FetchDictionaryDetailNpcUseCase - private let dictionaryDetailNpcQuestUseCase: FetchDictionaryDetailNpcQuestUseCase - private let dictionaryDetailNpcMapUseCase: - FetchDictionaryDetailNpcMapUseCase - private let dictionaryDetailMonsterUseCase: FetchDictionaryDetailMonsterUseCase - private let dictionaryDetailMonsterDropItemUseCase: FetchDictionaryDetailMonsterItemsUseCase - private let dictionaryDetailMonsterMapUseCase: FetchDictionaryDetailMonsterMapUseCase - private let checkLoginUseCase: CheckLoginUseCase - private let setBookmarkUseCase: SetBookmarkUseCase - private let fetchVisitDictionaryDetailUseCase: FetchVisitDictionaryDetailUseCase - - public init( - loginFactory: @escaping () -> LoginFactory, - bookmarkModalFactory: BookmarkModalFactory, - dictionaryDetailFactory: @escaping () -> DictionaryDetailFactory, - detailOnBoardingFactory: DetailOnBoardingFactory, - appCoordinator: @escaping () -> AppCoordinatorProtocol, - dictionaryDetailMapUseCase: FetchDictionaryDetailMapUseCase, - dictionaryDetailMapSpawnMonsterUseCase: FetchDictionaryDetailMapSpawnMonsterUseCase, - dictionaryDetailMapNpcUseCase: FetchDictionaryDetailMapNpcUseCase, - dictionaryDetailQuestLinkedQuestsUseCase: FetchDictionaryDetailQuestLinkedQuestsUseCase, - dictionaryDetailQuestUseCase: FetchDictionaryDetailQuestUseCase, - dictionaryDetailItemDropMonsterUseCase: FetchDictionaryDetailItemDropMonsterUseCase, - dictionaryDetailItemUseCase: FetchDictionaryDetailItemUseCase, - dictionaryDetailNpcUseCase: FetchDictionaryDetailNpcUseCase, - dictionaryDetailNpcQuestUseCase: FetchDictionaryDetailNpcQuestUseCase, - dictionaryDetailNpcMapUseCase: FetchDictionaryDetailNpcMapUseCase, - dictionaryDetailMonsterUseCase: FetchDictionaryDetailMonsterUseCase, - dictionaryDetailMonsterDropItemUseCase: FetchDictionaryDetailMonsterItemsUseCase, - dictionaryDetailMonsterMapUseCase: FetchDictionaryDetailMonsterMapUseCase, - checkLoginUseCase: CheckLoginUseCase, - setBookmarkUseCase: SetBookmarkUseCase, - fetchVisitDictionaryDetailUseCase: FetchVisitDictionaryDetailUseCase - ) { - self.loginFactory = loginFactory - self.bookmarkModalFactory = bookmarkModalFactory - self.detailOnBoardingFactory = detailOnBoardingFactory - self.dictionaryDetailMapUseCase = dictionaryDetailMapUseCase - self.dictionaryDetailMapSpawnMonsterUseCase = dictionaryDetailMapSpawnMonsterUseCase - self.dictionaryDetailMapNpcUseCase = dictionaryDetailMapNpcUseCase - self.dictionaryDetailQuestLinkedQuestsUseCase = dictionaryDetailQuestLinkedQuestsUseCase - self.dictionaryDetailQuestUseCase = dictionaryDetailQuestUseCase - self.dictionaryDetailItemDropMonsterUseCase = dictionaryDetailItemDropMonsterUseCase - self.dictionaryDetailItemUseCase = dictionaryDetailItemUseCase - self.dictionaryDetailNpcUseCase = dictionaryDetailNpcUseCase - self.dictionaryDetailNpcQuestUseCase = dictionaryDetailNpcQuestUseCase - self.dictionaryDetailNpcMapUseCase = dictionaryDetailNpcMapUseCase - self.dictionaryDetailMonsterUseCase = dictionaryDetailMonsterUseCase - self.dictionaryDetailMonsterDropItemUseCase = dictionaryDetailMonsterDropItemUseCase - self.dictionaryDetailMonsterMapUseCase = dictionaryDetailMonsterMapUseCase - self.checkLoginUseCase = checkLoginUseCase - self.setBookmarkUseCase = setBookmarkUseCase - self.appCoordinator = appCoordinator - self.dictionaryDetailFactory = dictionaryDetailFactory - self.fetchVisitDictionaryDetailUseCase = fetchVisitDictionaryDetailUseCase - } - - public func make(type: DictionaryType, id: Int, bookmarkRelay: PublishRelay<(id: Int, newBookmarkId: Int?)>?, loginRelay: PublishRelay?) -> BaseViewController { - var viewController = BaseViewController() - switch type { - case .total: - break - case .collection: - break - case .item: - viewController = ItemDictionaryDetailViewController( - type: .item, - bookmarkModalFactory: bookmarkModalFactory, - loginFactory: loginFactory(), - dictionaryDetailFactory: dictionaryDetailFactory(), - detailOnBoardingFactory: detailOnBoardingFactory, - appCoordinator: appCoordinator(), fetchVisitDictionaryDetailUseCase: fetchVisitDictionaryDetailUseCase, - bookmarkRelay: bookmarkRelay, - loginRelay: loginRelay - ) - let reactor = ItemDictionaryDetailReactor( - dictionaryDetailItemUseCase: dictionaryDetailItemUseCase, - dictionaryDetailItemDropMonsterUseCase: dictionaryDetailItemDropMonsterUseCase, - checkLoginUseCase: checkLoginUseCase, - setBookmarkUseCase: setBookmarkUseCase, - id: id - ) - if let viewController = viewController as? ItemDictionaryDetailViewController { - viewController.reactor = reactor - } - case .monster: - viewController = MonsterDictionaryDetailViewController( - type: .monster, - bookmarkModalFactory: bookmarkModalFactory, - loginFactory: loginFactory(), - dictionaryDetailFactory: dictionaryDetailFactory(), - detailOnBoardingFactory: detailOnBoardingFactory, - appCoordinator: appCoordinator(), fetchVisitDictionaryDetailUseCase: fetchVisitDictionaryDetailUseCase, - bookmarkRelay: bookmarkRelay, - loginRelay: loginRelay - ) - let reactor = MonsterDictionaryDetailReactor( - dictionaryDetailMonsterUseCase: dictionaryDetailMonsterUseCase, - dictionaryDetailMonsterDropItemUseCase: dictionaryDetailMonsterDropItemUseCase, - dictionaryDetailMonsterMapUseCase: dictionaryDetailMonsterMapUseCase, - checkLoginUseCase: checkLoginUseCase, - setBookmarkUseCase: setBookmarkUseCase, - id: id - ) - if let viewController = viewController as? MonsterDictionaryDetailViewController { - viewController.reactor = reactor - } - case .map: - viewController = MapDictionaryDetailViewController( - type: .map, - bookmarkModalFactory: bookmarkModalFactory, - loginFactory: loginFactory(), - dictionaryDetailFactory: dictionaryDetailFactory(), - detailOnBoardingFactory: detailOnBoardingFactory, - appCoordinator: appCoordinator(), fetchVisitDictionaryDetailUseCase: fetchVisitDictionaryDetailUseCase, - bookmarkRelay: bookmarkRelay, - loginRelay: loginRelay - ) - let reactor = MapDictionaryDetailReactor( - dictionaryDetailMapUseCase: dictionaryDetailMapUseCase, - dictionaryDetailMapSpawnMonsterUseCase: dictionaryDetailMapSpawnMonsterUseCase, - dictionaryDetailMapNpcUseCase: dictionaryDetailMapNpcUseCase, - checkLoginUseCase: checkLoginUseCase, - setBookmarkUseCase: setBookmarkUseCase, - id: id - ) - if let viewController = viewController as? MapDictionaryDetailViewController { - viewController.reactor = reactor - } - case .npc: - viewController = NpcDictionaryDetailViewController( - type: .npc, - bookmarkModalFactory: bookmarkModalFactory, - loginFactory: loginFactory(), - dictionaryDetailFactory: dictionaryDetailFactory(), - detailOnBoardingFactory: detailOnBoardingFactory, - appCoordinator: appCoordinator(), fetchVisitDictionaryDetailUseCase: fetchVisitDictionaryDetailUseCase, - bookmarkRelay: bookmarkRelay, - loginRelay: loginRelay - ) - let reactor = NpcDictionaryDetailReactor( - dictionaryDetailNpcUseCase: dictionaryDetailNpcUseCase, - dictionaryDetailNpcQuestUseCase: dictionaryDetailNpcQuestUseCase, - dictionaryDetailNpcMapUseCase: dictionaryDetailNpcMapUseCase, - checkLoginUseCase: checkLoginUseCase, - setBookmarkUseCase: setBookmarkUseCase, - id: id - ) - if let viewController = viewController as? NpcDictionaryDetailViewController { - viewController.reactor = reactor - } - case .quest: - viewController = QuestDictionaryDetailViewController( - type: .quest, - bookmarkModalFactory: bookmarkModalFactory, - loginFactory: loginFactory(), - dictionaryDetailFactory: dictionaryDetailFactory(), - detailOnBoardingFactory: detailOnBoardingFactory, - appCoordinator: appCoordinator(), fetchVisitDictionaryDetailUseCase: fetchVisitDictionaryDetailUseCase, - bookmarkRelay: bookmarkRelay, - loginRelay: loginRelay - ) - let reactor = QuestDictionaryDetailReactor( - dictionaryDetailQuestUseCase: dictionaryDetailQuestUseCase, - dictionaryDetailQuestLinkedQuestUseCase: dictionaryDetailQuestLinkedQuestsUseCase, - checkLoginUseCase: checkLoginUseCase, - setBookmarkUseCase: setBookmarkUseCase, - id: id - ) - if let viewController = viewController as? QuestDictionaryDetailViewController { - viewController.reactor = reactor - } - } - - // 하단 탭바 히든 - viewController.isBottomTabbarHidden = true - return viewController - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift deleted file mode 100644 index b9e31a13..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailReactor.swift +++ /dev/null @@ -1,179 +0,0 @@ -import DomainInterface - -import ReactorKit - -// MARK: - Reactor -public final class ItemDictionaryDetailReactor: Reactor { - // MARK: Type - public enum Route { - case none - case filter(DictionaryType) - case detail(Int) - case bookmarkError - } - - public enum UIEvent { - case none - case add(DictionaryDetailItemResponse) - case delete(DictionaryDetailItemResponse) - case undo - } - - // MARK: Action - public enum Action { - case filterButtonTapped - case viewWillAppear - case selectFilter(SortType) - case toggleBookmark - case undoLastDeletedBookmark - case dataTapped(index: Int) - } - - // MARK: Mutation - public enum Mutation { - case navigatTo(Route) - case setDetailData(DictionaryDetailItemResponse) - case setDetailDropMonsterData([DictionaryDetailItemDropMonsterResponse]) - case setLoginState(Bool) - case setEvent(UIEvent) - } - - // MARK: State - public struct State { - @Pulse var event: UIEvent = .none - @Pulse var route: Route = .none - var itemDetailInfo: DictionaryDetailItemResponse - var type: DictionaryType = .item - var monsters: [DictionaryDetailItemDropMonsterResponse] - var id: Int - var isLogin = false - } - - public var initialState: State - private let disposeBag = DisposeBag() - - private let dictionaryDetailItemUseCase: FetchDictionaryDetailItemUseCase - private let dictionaryDetailItemDropMonsterUseCase: FetchDictionaryDetailItemDropMonsterUseCase - private let checkLoginUseCase: CheckLoginUseCase - private let setBookmarkUseCase: SetBookmarkUseCase - - // MARK: Init - public init( - dictionaryDetailItemUseCase: FetchDictionaryDetailItemUseCase, - dictionaryDetailItemDropMonsterUseCase: FetchDictionaryDetailItemDropMonsterUseCase, - checkLoginUseCase: CheckLoginUseCase, - setBookmarkUseCase: SetBookmarkUseCase, - id: Int - ) { - self.dictionaryDetailItemUseCase = dictionaryDetailItemUseCase - self.dictionaryDetailItemDropMonsterUseCase = dictionaryDetailItemDropMonsterUseCase - self.checkLoginUseCase = checkLoginUseCase - self.setBookmarkUseCase = setBookmarkUseCase - self.initialState = .init( - itemDetailInfo: DictionaryDetailItemResponse( - itemId: 0, nameKr: nil, nameEn: nil, descriptionText: nil, - imgUrl: nil, npcPrice: nil, itemType: nil, categoryHierachy: nil, - availableJobs: nil, requiredStats: nil, equipmentStats: nil, - scrollDetail: nil, bookmarkId: nil - ), - type: .item, - monsters: [], - id: id - ) - } - - // MARK: Mutate - public func mutate(action: Action) -> Observable { - switch action { - case .filterButtonTapped: - return .just(.navigatTo(.filter(currentState.type))) - case .viewWillAppear: - return .merge([ - checkLoginUseCase.execute().map { .setLoginState($0) }, - dictionaryDetailItemUseCase.execute(id: currentState.id).map { .setDetailData($0) }, - dictionaryDetailItemDropMonsterUseCase.execute(id: currentState.id, sort: nil).map { .setDetailDropMonsterData($0) } - ]) - case let .selectFilter(type): - return dictionaryDetailItemDropMonsterUseCase.execute(id: currentState.id, sort: type.sortParameter).map { .setDetailDropMonsterData($0) } - - case .toggleBookmark: - return handleToggleBookmark() - - case .undoLastDeletedBookmark: - return handleUndoLastDeletedBookmark() - - case .dataTapped(let index): - guard let id = currentState.monsters[index].monsterId else { return .empty() } - return .just(.navigatTo(.detail(id))) - } - } - - // MARK: Reduce - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - switch mutation { - case let .setDetailData(data): - newState.itemDetailInfo = data - case let .setDetailDropMonsterData(data): - newState.monsters = data - case let .setLoginState(isLogin): - newState.isLogin = isLogin - case .navigatTo(let route): - newState.route = route - case let .setEvent(event): - newState.event = event - } - return newState - } -} - -private extension ItemDictionaryDetailReactor { - func handleToggleBookmark() -> Observable { - var item = currentState.itemDetailInfo - let isSelected = item.bookmarkId != nil - guard let type = currentState.type.toItemType else { return .empty() } - - return setBookmarkUseCase.execute( - bookmarkId: isSelected ? item.bookmarkId ?? item.itemId : item.itemId, - isBookmark: isSelected ? .delete : .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } - - item.bookmarkId = newBookmarkId - let event: UIEvent = isSelected ? .delete(item) : .add(item) - let eventMutation = Observable.just(Mutation.setEvent(event)) - - let refresh = self.dictionaryDetailItemUseCase.execute(id: self.currentState.id) - .map { Mutation.setDetailData($0) } - - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigatTo(.bookmarkError)) - } - } - - func handleUndoLastDeletedBookmark() -> Observable { - var item = currentState.itemDetailInfo - guard let type = currentState.type.toItemType else { return .empty() } - - return setBookmarkUseCase.execute( - bookmarkId: item.itemId, - isBookmark: .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } - - item.bookmarkId = newBookmarkId - let eventMutation = Observable.just(Mutation.setEvent(.add(item))) - let refresh = self.dictionaryDetailItemUseCase.execute(id: self.currentState.id) - .map { Mutation.setDetailData($0) } - - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigatTo(.bookmarkError)) - } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift deleted file mode 100644 index c4efe2c5..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Item/ItemDictionaryDetailViewController.swift +++ /dev/null @@ -1,278 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem -import DictionaryFeatureInterface -import DomainInterface - -import ReactorKit - -final class ItemDictionaryDetailViewController: DictionaryDetailBaseViewController, View { - public typealias Reactor = ItemDictionaryDetailReactor - - // MARK: - Components - private let detailInfoView = DetailStackInfoView(type: .item) - private let monsterCardView = DetailStackCardView() - private let sortedFactory: SortedBottomSheetFactory = SortedBottomSheetFactoryImpl() - - override func toggleBookmark() { - reactor?.action.onNext(.toggleBookmark) - } - - override func checkLogin() -> Bool { - guard let reactor = reactor else { return false } - return reactor.currentState.isLogin - } - - override func undoBookmark() { - reactor?.action.onNext(.undoLastDeletedBookmark) - } -} - -// MARK: - Populate Data -private extension ItemDictionaryDetailViewController { - func setupMainInfo() { - // 상세 정보(메인?) - inject(input: DictionaryDetailBaseViewController.Input( - imageUrl: reactor?.currentState.itemDetailInfo.imgUrl, - backgroundColor: type.backgroundColor, - name: reactor?.currentState.itemDetailInfo.nameKr ?? "이름 없음", - subText: reactor?.currentState.itemDetailInfo.requiredStats?.level.map { "Lv. \($0)" } ?? "" // 착용 레벨이 존재하는 아이템일 경우 레벨 보여주기 - )) - } - - func setUpInfoStackView() { - guard let reactor = reactor else { return } - let infos = reactor.currentState.itemDetailInfo - - contentViews.append(detailInfoView) - // descriptionText - detailInfoView.descriptionLabel.text = infos.descriptionText ?? "" - - detailInfoView.reset() - if let npcPrice = infos.npcPrice { - detailInfoView.addInfo(mainText: "상점판매가", subText: "\(npcPrice.formatted()) 메소") - } - - if let availableJobs = infos.availableJobs { - let jobNames = availableJobs.compactMap { $0.jobName }.joined(separator: ", ") - if !jobNames.isEmpty { - detailInfoView.addInfo(mainText: "직업", subText: jobNames) - } - } - - if let requiredStats = infos.requiredStats { - if let level = requiredStats.level { - detailInfoView.addInfo(mainText: "착용레벨", subText: "Lv. \(level)") - } - if let str = requiredStats.str { - detailInfoView.addInfo(mainText: "필요 STR", subText: "\(str)") - } - if let dex = requiredStats.dex { - detailInfoView.addInfo(mainText: "필요 DEX", subText: "\(dex)") - } - if let int = requiredStats.intelligence { - detailInfoView.addInfo(mainText: "필요 INT", subText: "\(int)") - } - if let luk = requiredStats.luk { - detailInfoView.addInfo(mainText: "필요 LUK", subText: "\(luk)") - } - if let pop = requiredStats.pop { - detailInfoView.addInfo(mainText: "필요 POP", subText: "\(pop)") - } - } - // 해당 스트링들을 상수 추출 하는게 좋을지.. - if let equipmentStats = infos.equipmentStats { - let statMappings: [(title: String, stat: Stats?)] = [ - ("STR 증가", equipmentStats.str), - ("DEX 증가", equipmentStats.dex), - ("INT 증가", equipmentStats.intelligence), - ("LUK 증가", equipmentStats.luk), - ("HP 증가", equipmentStats.hp), - ("MP 증가", equipmentStats.mp), - ("물리공격력 증가", equipmentStats.weaponAttack), - ("마법공격력 증가", equipmentStats.magicAttack), - ("물리방어력 증가", equipmentStats.physicalDefense), - ("마법방어력 증가", equipmentStats.magicDefense), - ("명중률 증가", equipmentStats.accuracy), - ("회피율 증가", equipmentStats.evasion), - ("이동속도 증가", equipmentStats.speed), - ("점프력 증가", equipmentStats.jump) - ] - - for (title, stat) in statMappings { - if let base = stat?.base { - let subText = formatStatText(base: base, min: stat?.min, max: stat?.max) - detailInfoView.addInfo(mainText: title, subText: subText) - } - } - - if let attackSpeed = equipmentStats.attackSpeed, let attackSpeedDetails = equipmentStats.attackSpeedDetails { - detailInfoView.addInfo(mainText: "공격속도", subText: "\(attackSpeed.formatted()) (\(attackSpeedDetails))") - } - } - - if let scrollDetail = infos.scrollDetail { - let scrollMappings: [(title: String, value: Int?)] = [ - ("STR 증가", scrollDetail.strChange), - ("DEX 증가", scrollDetail.dexChange), - ("INT 증가", scrollDetail.intelligenceChange), - ("LUK 증가", scrollDetail.lukChange), - ("HP 증가", scrollDetail.hpChange), - ("MP 증가", scrollDetail.mpChange), - ("물리공격력 증가", scrollDetail.weaponAttackChange), - ("마법공격력 증가", scrollDetail.magicAttackChange), - ("물리방어력 증가", scrollDetail.physicalDefenseChange), - ("마법방어력 증가", scrollDetail.magicDefenseChange), - ("명중률 증가", scrollDetail.accuracyChange), - ("회피율 증가", scrollDetail.evasionChange), - ("이동속도 증가", scrollDetail.speedChange), - ("점프력 증가", scrollDetail.jumpChange) - ] - - if let successRate = scrollDetail.successRatePercent { - detailInfoView.addInfo(mainText: "성공 확률", subText: "\(successRate)%") - } - - if let targetItem = scrollDetail.targetItemTypeText { - detailInfoView.addInfo(mainText: "사용 가능 장비", subText: targetItem) - } - - for (title, value) in scrollMappings { - if let value = value { - let sign = value >= 0 ? "+" : "" - detailInfoView.addInfo(mainText: title, subText: "\(sign)\(value.formatted())") - } - } - } - } - - func setUpMonsterView() { - guard let reactor = reactor, - let detailType = reactor.currentState.type.detailTypes.first, - let filter = detailType.sortFilter.first else { return } - monsterCardView.initFilter(firstFilter: filter) - let monsters = reactor.currentState.monsters - monsterCardView.reset() - - contentViews.append(monsterCardView) - if monsters.isEmpty { - contentViews[1] = DetailEmptyView(type: .dropMonsterWithText) - } else { - contentViews[1] = monsterCardView - for monster in monsters { - monsterCardView.inject(input: DetailStackCardView.Input(type: .dropMonsterWithText, imageUrl: monster.imageUrl ?? "", mainText: monster.monsterName, additionalText: "\(monster.dropRate ?? 0)%") - ) - } - } - } -} - -// MARK: - Bind -extension ItemDictionaryDetailViewController { - public func bind(reactor: Reactor) { - bindUserAction(reactor: reactor) - bindViewState(reactor: reactor) - bindReportButton( - providerId: reactor.state.map { $0.itemDetailInfo.itemId }, - itemName: reactor.state.map { $0.itemDetailInfo.nameKr ?? "" } - ) - } - - private func bindUserAction(reactor: Reactor) { - rx.viewWillAppear - .map { Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - monsterCardView.filterButton.rx.tap - .map { Reactor.Action.filterButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - monsterCardView.tap - .map { Reactor.Action.dataTapped(index: $0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - private func bindViewState(reactor: Reactor) { - reactor.state.map(\.itemDetailInfo) - .distinctUntilChanged() - .observe(on: MainScheduler.instance) - .withUnretained(self) - .bind(onNext: { owner, item in - owner.setupMainInfo() - owner.setUpInfoStackView() - owner.mainView.setBookmark(isBookmarked: item.bookmarkId != nil) - }) - .disposed(by: disposeBag) - - reactor.state.map(\.monsters) - .distinctUntilChanged() - .observe(on: MainScheduler.instance) - .withUnretained(self) - .bind(onNext: { owner, _ in - owner.setUpMonsterView() - }) - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } // 값이 바뀔때만 이벤트 받음 - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, route in - switch route { - case let .filter(type): - guard let option = type.detailTypes.first else { return } - let viewController = owner.sortedFactory.make(sortedOptions: option.sortFilter, selectedIndex: owner.selectedIndex) { index in - owner.selectedIndex = index - let selectedFilter = option.sortFilter[index] - owner.monsterCardView.selectFilter(selectedType: selectedFilter) - reactor.action.onNext(.selectFilter(selectedFilter)) - } - owner.tabBarController?.presentModal(viewController, hideTabBar: true) - case let .detail(id): - let viewController = owner.dictionaryDetailFactory.make(type: .monster, id: id, bookmarkRelay: owner.bookmarkRelay, loginRelay: owner.loginRelay) - owner.navigationController?.pushViewController(viewController, animated: true) - case .bookmarkError: - ToastFactory.createToast(message: "북마크 요청에 실패했어요. 다시 시도해주세요.") - default: - break - } - } - .disposed(by: disposeBag) - - reactor.pulse(\.$event) - .bind(onNext: { [weak self] event in - switch event { - case let .add(item): - self?.presentAddSnackBar( - bookmarkId: item.bookmarkId, - imageUrl: item.imgUrl, - background: DictionaryItemType.item.backgroundColor - ) - self?.bookmarkRelay?.accept((item.itemId, item.bookmarkId)) - case let .delete(item): - self?.presentDeleteSnackBar( - imageUrl: item.imgUrl, - background: DictionaryItemType.item.backgroundColor - ) - self?.bookmarkRelay?.accept((item.itemId, item.bookmarkId)) - default: break - } - }) - .disposed(by: disposeBag) - } -} - -private extension ItemDictionaryDetailViewController { - func formatStatText(base: Int, min: Int?, max: Int?) -> String { - if let min = min, let max = max { - return "\(base.formatted()) [\(min.formatted())-\(max.formatted())]" - } else { - return "\(base)" - } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift deleted file mode 100644 index 8ed34e3c..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailReactor.swift +++ /dev/null @@ -1,203 +0,0 @@ -import DomainInterface - -import ReactorKit - -public final class MapDictionaryDetailReactor: Reactor { - // MARK: - Reactor - public enum Route { - case none - case filter([SortType]) - case detail(type: DictionaryType, id: Int) - case bookmarkError - } - - public enum UIEvent { - case none - case add(DictionaryDetailMapResponse) - case delete(DictionaryDetailMapResponse) - case undo - } - - public enum Action { - case monsterFilterButtonTapped - case viewWillAppear - case toggleBookmark - case undoLastDeletedBookmark - case monsterTapped(index: Int) - case npcTapped(index: Int) - case selectFilter(SortType) - } - - public enum Mutation { - case navigatTo(Route) - case setDetailData(DictionaryDetailMapResponse) - case setDetailSpawnMonsters([DictionaryDetailMapSpawnMonsterResponse]) - case setDetailNpc([DictionaryDetailMapNpcResponse]) - case setBookmark(DictionaryDetailMapResponse) - case setLastDeletedBookmark(DictionaryDetailMapResponse?) - case setLoginState(Bool) - case setEvent(UIEvent) - } - - public let dictionaryDetailMapUseCase: FetchDictionaryDetailMapUseCase - public let dictionaryDetailMapSpawnMonsterUseCase: FetchDictionaryDetailMapSpawnMonsterUseCase - public let dictionaryDetailMapNpcUseCase: FetchDictionaryDetailMapNpcUseCase - private let checkLoginUseCase: CheckLoginUseCase - private let setBookmarkUseCase: SetBookmarkUseCase - - public struct State { - @Pulse var event: UIEvent = .none - @Pulse var route: Route = .none - var mapDetailInfo: DictionaryDetailMapResponse - var spawnMonsters: [DictionaryDetailMapSpawnMonsterResponse] - var npcs: [DictionaryDetailMapNpcResponse] - var type: DictionaryType = .map - var monsterFilter: [SortType] { - type.detailTypes[0].sortFilter - } - var id = 0 - var isLogin = false - var lastDeletedBookmark: DictionaryDetailMapResponse? - } - - public var initialState: State - private let disposBag = DisposeBag() - - public init( - dictionaryDetailMapUseCase: FetchDictionaryDetailMapUseCase, - dictionaryDetailMapSpawnMonsterUseCase: FetchDictionaryDetailMapSpawnMonsterUseCase, - dictionaryDetailMapNpcUseCase: FetchDictionaryDetailMapNpcUseCase, - checkLoginUseCase: CheckLoginUseCase, - setBookmarkUseCase: SetBookmarkUseCase, - id: Int - ) { - initialState = State( - mapDetailInfo: DictionaryDetailMapResponse( - mapId: 0, - nameKr: nil, - nameEn: nil, - regionName: nil, - detailName: nil, - topRegionName: nil, - mapUrl: nil, - iconUrl: nil, - bookmarkId: nil - ), - spawnMonsters: [], - npcs: [], - type: .map, - id: id - ) - - self.dictionaryDetailMapUseCase = dictionaryDetailMapUseCase - self.dictionaryDetailMapSpawnMonsterUseCase = dictionaryDetailMapSpawnMonsterUseCase - self.dictionaryDetailMapNpcUseCase = dictionaryDetailMapNpcUseCase - self.checkLoginUseCase = checkLoginUseCase - self.setBookmarkUseCase = setBookmarkUseCase - } - - public func mutate(action: Action) -> Observable { - switch action { - case .monsterFilterButtonTapped: - return Observable.just(.navigatTo(.filter(currentState.monsterFilter))) - case .viewWillAppear: - return .merge([ - checkLoginUseCase.execute().map { .setLoginState($0) }, - dictionaryDetailMapUseCase.execute(id: currentState.id).map {.setDetailData($0)}, - dictionaryDetailMapSpawnMonsterUseCase.execute(id: currentState.id, sort: nil).map {.setDetailSpawnMonsters($0)}, - dictionaryDetailMapNpcUseCase.execute(id: currentState.id).map {.setDetailNpc($0)} - ]) - case .toggleBookmark: - return handleToggleBookmark() - - case .undoLastDeletedBookmark: - return handleUndoLastDeletedBookmark() - - case let .selectFilter(type): - return dictionaryDetailMapSpawnMonsterUseCase.execute(id: currentState.id, sort: type.sortParameter).map { .setDetailSpawnMonsters($0) } - - case .monsterTapped(index: let index): - guard let id = currentState.spawnMonsters[index].monsterId else { return .empty() } - - return .just(.navigatTo(.detail(type: .monster, id: id))) - case .npcTapped(index: let index): - guard let id = currentState.npcs[index].npcId else { return .empty() } - return .just(.navigatTo(.detail(type: .npc, id: id))) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .navigatTo(let route): - newState.route = route - case let .setDetailData(data): - newState.mapDetailInfo = data - case let .setDetailSpawnMonsters(data): - newState.spawnMonsters = data - case let .setDetailNpc(data): - newState.npcs = data - case let .setBookmark(map): - newState.mapDetailInfo = map - case let .setLastDeletedBookmark(map): - newState.lastDeletedBookmark = map - case let .setLoginState(isLogin): - newState.isLogin = isLogin - case let .setEvent(event): - newState.event = event - } - return newState - } -} - -private extension MapDictionaryDetailReactor { - func handleToggleBookmark() -> Observable { - var map = currentState.mapDetailInfo - let isSelected = map.bookmarkId != nil - guard let type = currentState.type.toItemType else { return .empty() } - - return setBookmarkUseCase.execute( - bookmarkId: isSelected ? map.bookmarkId ?? map.mapId : map.mapId, - isBookmark: isSelected ? .delete : .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } - - map.bookmarkId = newBookmarkId - let event: UIEvent = isSelected ? .delete(map) : .add(map) - let eventMutation = Observable.just(Mutation.setEvent(event)) - - let refresh = self.dictionaryDetailMapUseCase.execute(id: self.currentState.id) - .map { Mutation.setDetailData($0) } - - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigatTo(.bookmarkError)) - } - } - - func handleUndoLastDeletedBookmark() -> Observable { - var map = currentState.mapDetailInfo - guard let type = currentState.type.toItemType else { return .empty() } - - return setBookmarkUseCase.execute( - bookmarkId: map.mapId, - isBookmark: .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } - - map.bookmarkId = newBookmarkId - let eventMutation = Observable.just(Mutation.setEvent(.add(map))) - let refresh = self.dictionaryDetailMapUseCase.execute(id: self.currentState.id) - .map { Mutation.setDetailData($0) } - - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigatTo(.bookmarkError)) - } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift deleted file mode 100644 index 62ab5cc7..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Map/MapDictionaryDetailViewController.swift +++ /dev/null @@ -1,234 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem -import DictionaryFeatureInterface -import DomainInterface - -import ReactorKit -import RxCocoa -import RxSwift - -final class MapDictionaryDetailViewController: DictionaryDetailBaseViewController, View { - public typealias Reactor = MapDictionaryDetailReactor - - // MARK: - Componenets - private var mapInfoView = DetailStackMapView(imageUrl: "") - private var appearMonsterView = DetailStackCardView() - private var appearNpcView = DetailStackCardView() - private let sortedFactory: SortedBottomSheetFactory = SortedBottomSheetFactoryImpl() - - override func viewDidLoad() { - super.viewDidLoad() - bindImageView() - } - - override func toggleBookmark() { - reactor?.action.onNext(.toggleBookmark) - } - - override func checkLogin() -> Bool { - guard let reactor = reactor else { return false } - return reactor.currentState.isLogin - } - - override func undoBookmark() { - reactor?.action.onNext(.undoLastDeletedBookmark) - } -} - -// MARK: - SetUp -private extension MapDictionaryDetailViewController { - func setUpMainInfo() { - guard let reactor = reactor else { return } - let info = reactor.currentState.mapDetailInfo - inject( - input: DictionaryDetailBaseViewController - .Input( - imageUrl: info.iconUrl, - backgroundColor: type.backgroundColor, - name: info.nameKr ?? "이름 없음", - subText: info.detailName ?? "" - ) - ) - } - - func setUpMapView() { - guard let reactor = reactor else { return } - - contentViews.append(mapInfoView) - if let mapUrl = reactor.currentState.mapDetailInfo.mapUrl, !mapUrl.isEmpty { - mapInfoView.setUpMapView(imageUrl: reactor.currentState.mapDetailInfo.mapUrl) - contentViews[0] = mapInfoView - } else { - contentViews[0] = DetailEmptyView(type: .mapInfo) - } - } - - func setUpMonsterView() { - guard let reactor = reactor, - let filter = reactor.currentState.monsterFilter.first else { return } - appearMonsterView.initFilter(firstFilter: filter) - - appearMonsterView.reset() - let monsters = reactor.currentState.spawnMonsters - contentViews.append(appearMonsterView) - if monsters.isEmpty { - contentViews[1] = DetailEmptyView(type: .appearMonsterWithText) - } else { - contentViews[1] = appearMonsterView - for monster in monsters { - appearMonsterView.inject(input: DetailStackCardView.Input(type: .appearMonsterWithText, imageUrl: monster.imageUrl ?? "", mainText: monster.monsterName, subText: "Lv.\(monster.level ?? 0)", additionalText: { - if let count = monster.maxSpawnCount { - return "\(count)마리" - } else { - return "??마리" - } - }())) - } - } - } - - func setUpNpcView() { - guard let reactor = reactor else { return } - - let npcs = reactor.currentState.npcs - appearNpcView.reset() - contentViews.append(appearNpcView) - if npcs.isEmpty { - contentViews[2] = DetailEmptyView(type: .appearNPC) - } else { - contentViews[2] = appearNpcView - for npc in npcs { - appearNpcView.inject(input: DetailStackCardView.Input(type: .appearNPC, imageUrl: npc.iconUrl ?? "", mainText: npc.npcName)) - } - } - } - - func bindImageView() { - let tapGesture = UITapGestureRecognizer() - mapInfoView.mapImageView.isUserInteractionEnabled = true - mapInfoView.mapImageView.addGestureRecognizer(tapGesture) - - tapGesture.rx.event - .withUnretained(self) - .bind(onNext: { owner, _ in - guard let reactor = owner.reactor, - let url = reactor.currentState.mapDetailInfo.mapUrl else { return } - let viewController = PinchMapViewController(imageUrl: url) - viewController.modalPresentationStyle = .overFullScreen - owner.isBottomTabbarHidden = true - self.present(viewController, animated: true) - }) - .disposed(by: disposeBag) - } -} - -// MARK: - Bind -extension MapDictionaryDetailViewController { - func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - bindReportButton(providerId: reactor.state.map { $0.mapDetailInfo.mapId }, itemName: reactor.state.map { $0.mapDetailInfo.nameKr ?? "" }) - } - - private func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .map { Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - appearMonsterView.filterButton.rx.tap - .map { Reactor.Action.monsterFilterButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - appearMonsterView.tap - .map { Reactor.Action.monsterTapped(index: $0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - appearNpcView.tap - .map { Reactor.Action.npcTapped(index: $0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - private func bindViewState(reactor: Reactor) { - reactor.state.map(\.mapDetailInfo) - .distinctUntilChanged() - .observe(on: MainScheduler.instance) - .withUnretained(self) - .bind(onNext: { owner, item in - owner.setUpMainInfo() - owner.setUpMapView() - owner.mainView.setBookmark(isBookmarked: item.bookmarkId != nil) - }) - .disposed(by: disposeBag) - - reactor.state.map(\.spawnMonsters) - .distinctUntilChanged() - .observe(on: MainScheduler.instance) - .withUnretained(self) - .bind(onNext: { owner, _ in - owner.setUpMonsterView() - }) - .disposed(by: disposeBag) - - reactor.state.map(\.npcs) - .distinctUntilChanged() - .observe(on: MainScheduler.instance) - .withUnretained(self) - .bind(onNext: { owner, _ in - owner.setUpNpcView() - }) - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } // 값이 바뀔때만 이벤트 받음 - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, route in - switch route { - case .filter(let sort): - let viewController = owner.sortedFactory.make(sortedOptions: sort, selectedIndex: owner.selectedIndex) { index in - owner.selectedIndex = index - let selectedFilter = reactor.currentState.monsterFilter[index] - owner.appearMonsterView.selectFilter(selectedType: selectedFilter) - reactor.action.onNext(.selectFilter(selectedFilter)) - } - owner.tabBarController?.presentModal(viewController, hideTabBar: true) - case .detail(let type, let id): - let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, loginRelay: owner.loginRelay) - owner.navigationController?.pushViewController(viewController, animated: true) - case .bookmarkError: - ToastFactory.createToast(message: "북마크 요청에 실패했어요. 다시 시도해주세요.") - default: - break - } - } - .disposed(by: disposeBag) - - reactor.pulse(\.$event) - .bind(onNext: { [weak self] event in - switch event { - case let .add(item): - self?.presentAddSnackBar( - bookmarkId: item.bookmarkId, - imageUrl: item.iconUrl, - background: DictionaryItemType.item.backgroundColor - ) - self?.bookmarkRelay?.accept((item.mapId, item.bookmarkId)) - case let .delete(item): - self?.presentDeleteSnackBar( - imageUrl: item.iconUrl, - background: DictionaryItemType.item.backgroundColor - ) - self?.bookmarkRelay?.accept((item.mapId, item.bookmarkId)) - default: break - } - }) - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift deleted file mode 100644 index 0f798445..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailReactor.swift +++ /dev/null @@ -1,225 +0,0 @@ -import DomainInterface - -import ReactorKit - -public final class MonsterDictionaryDetailReactor: Reactor { - // MARK: - Type - public enum Route { - case none - case filter(type: DictionaryType, sort: [SortType]) - case detail(type: DictionaryType, id: Int) - case bookmarkError - } - - public struct Info: Equatable { - var name: String - var desc: String - } - - public enum UIEvent { - case none - case add(DictionaryDetailMonsterResponse) - case delete(DictionaryDetailMonsterResponse) - case undo - } - - // MARK: - Action - public enum Action { - case filterButtonTapped(DictionaryType) - case viewWillAppear - case selectFilter(SortType) - case toggleBookmark - case undoLastDeletedBookmark - case itemTapped(index: Int) - case mapTapped(index: Int) - } - - // MARK: - Mutation - public enum Mutation { - case navigatTo(Route) - case setDetailData(DictionaryDetailMonsterResponse) - case setDetailDropItemData([DictionaryDetailMonsterDropItemResponse]) - case setDetailMapData([DictionaryDetailMonsterMapResponse]) - case setBookmark(DictionaryDetailMonsterResponse) - case setLastDeletedBookmark(DictionaryDetailMonsterResponse?) - case setLoginState(Bool) - case setEvent(UIEvent) - } - - // MARK: - State - public struct State { - @Pulse var event: UIEvent = .none - @Pulse var route: Route = .none - var type: DictionaryType = .monster - var id = 0 - var monsterDetailInfo = DictionaryDetailMonsterResponse( - monsterId: 0, nameKr: "", nameEn: "", imageUrl: "", - level: 0, exp: 0, hp: 0, mp: 0, - physicalDefense: 0, magicDefense: 0, - requiredAccuracy: 0, bonusAccuracyPerLevelLower: 0, - evasionRate: 0, mesoDropAmount: nil, mesoDropRate: nil, - typeEffectiveness: nil, bookmarkId: nil - ) - var spawnMaps = [DictionaryDetailMonsterMapResponse]() - var dropItems = [DictionaryDetailMonsterDropItemResponse]() - var mapFilter: [SortType] { - type.detailTypes[0].sortFilter - } - - var itemFilter: [SortType] { - type.detailTypes[1].sortFilter - } - var infos = [Info]() - var isLogin = false - var lastDeletedBookmark: DictionaryDetailMonsterResponse? - } - - // MARK: - Properties - private let disposeBag = DisposeBag() - private let dictionaryDetailMonsterUseCase: FetchDictionaryDetailMonsterUseCase - private let dictionaryDetailMonsterDropItemUseCase: FetchDictionaryDetailMonsterItemsUseCase - private let dictionaryDetailMonsterMapUseCase: FetchDictionaryDetailMonsterMapUseCase - private let checkLoginUseCase: CheckLoginUseCase - private let setBookmarkUseCase: SetBookmarkUseCase - - public var initialState: State - - // MARK: - Init - public init( - dictionaryDetailMonsterUseCase: FetchDictionaryDetailMonsterUseCase, - dictionaryDetailMonsterDropItemUseCase: FetchDictionaryDetailMonsterItemsUseCase, - dictionaryDetailMonsterMapUseCase: FetchDictionaryDetailMonsterMapUseCase, - checkLoginUseCase: CheckLoginUseCase, - setBookmarkUseCase: SetBookmarkUseCase, - id: Int - ) { - self.initialState = State(type: .monster, id: id) - self.dictionaryDetailMonsterUseCase = dictionaryDetailMonsterUseCase - self.dictionaryDetailMonsterDropItemUseCase = dictionaryDetailMonsterDropItemUseCase - self.dictionaryDetailMonsterMapUseCase = dictionaryDetailMonsterMapUseCase - self.checkLoginUseCase = checkLoginUseCase - self.setBookmarkUseCase = setBookmarkUseCase - } - - // MARK: - Mutate - public func mutate(action: Action) -> Observable { - switch action { - case let .filterButtonTapped(type): - return .just(.navigatTo(.filter(type: type, sort: type == .map ? currentState.mapFilter : currentState.itemFilter))) - - case .viewWillAppear: - return .merge([ - checkLoginUseCase.execute().map { .setLoginState($0) }, - dictionaryDetailMonsterUseCase.execute(id: currentState.id).map { .setDetailData($0) }, - dictionaryDetailMonsterDropItemUseCase.execute(id: currentState.id, sort: nil).map { .setDetailDropItemData($0) }, - dictionaryDetailMonsterMapUseCase.execute(id: currentState.id).map { .setDetailMapData($0) } - ]) - - case let .selectFilter(type): - return dictionaryDetailMonsterDropItemUseCase.execute(id: currentState.id, sort: type.sortParameter).map { .setDetailDropItemData($0) } - - case .toggleBookmark: - return handleToggleBookmark() - - case .undoLastDeletedBookmark: - return handleUndoLastDeletedBookmark() - - case .itemTapped(index: let index): - return .just(.navigatTo(.detail(type: .item, id: currentState.dropItems[index].itemId))) - - case .mapTapped(index: let index): - return .just(.navigatTo(.detail(type: .map, id: currentState.spawnMaps[index].mapId))) - } - } - - // MARK: - Reduce - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case let .navigatTo(route): - newState.route = route - - case let .setDetailData(data): - newState.monsterDetailInfo = data - - var infos: [Info] = [] - infos.append(.init(name: "HP", desc: "\(data.hp.formatted())")) - infos.append(.init(name: "MP", desc: "\(data.mp.formatted())")) - infos.append(.init(name: "EXP", desc: "\(data.exp.formatted())")) - infos.append(.init(name: "물리방어력", desc: "\(data.physicalDefense.formatted())")) - infos.append(.init(name: "마법방어력", desc: "\(data.magicDefense.formatted())")) - newState.infos = infos - - case let .setDetailDropItemData(data): - newState.dropItems = data - - case let .setDetailMapData(data): - newState.spawnMaps = data - - case let .setBookmark(monster): - newState.monsterDetailInfo = monster - - case let .setLastDeletedBookmark(monster): - newState.lastDeletedBookmark = monster - - case let .setLoginState(isLogin): - newState.isLogin = isLogin - case let .setEvent(event): - newState.event = event - } - - return newState - } -} - -private extension MonsterDictionaryDetailReactor { - func handleToggleBookmark() -> Observable { - var monster = currentState.monsterDetailInfo - let isSelected = monster.bookmarkId != nil - guard let type = currentState.type.toItemType else { return .empty() } - - return setBookmarkUseCase.execute( - bookmarkId: isSelected ? monster.bookmarkId ?? monster.monsterId : monster.monsterId, - isBookmark: isSelected ? .delete : .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } - - monster.bookmarkId = newBookmarkId - let event: UIEvent = isSelected ? .delete(monster) : .add(monster) - let eventMutation = Observable.just(Mutation.setEvent(event)) - - let refresh = self.dictionaryDetailMonsterUseCase.execute(id: self.currentState.id) - .map { Mutation.setDetailData($0) } - - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigatTo(.bookmarkError)) - } - } - - func handleUndoLastDeletedBookmark() -> Observable { - var monster = currentState.monsterDetailInfo - guard let type = currentState.type.toItemType else { return .empty() } - - return setBookmarkUseCase.execute( - bookmarkId: monster.monsterId, - isBookmark: .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } - - monster.bookmarkId = newBookmarkId - let eventMutation = Observable.just(Mutation.setEvent(.add(monster))) - let refresh = self.dictionaryDetailMonsterUseCase.execute(id: self.currentState.id) - .map { Mutation.setDetailData($0) } - - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigatTo(.bookmarkError)) - } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift deleted file mode 100644 index 2e4e7ca7..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Monster/MonsterDictionaryDetailViewController.swift +++ /dev/null @@ -1,255 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem -import DictionaryFeatureInterface -import DomainInterface - -import ReactorKit -import RxCocoa -import RxSwift - -class MonsterDictionaryDetailViewController: DictionaryDetailBaseViewController, View { - public typealias Reactor = MonsterDictionaryDetailReactor - - // MARK: - Properties - private var dropItemSelectedIndex = 0 - private var mapSelectedIntdex = 0 - - // MARK: - Componenets - private var detailView = DetailStackInfoView(type: .monster) - private var appearMapView = DetailStackCardView() - private var dropItemView = DetailStackCardView() - private let sortedFactory: SortedBottomSheetFactory = SortedBottomSheetFactoryImpl() - - override func toggleBookmark() { - reactor?.action.onNext(.toggleBookmark) - } - - override func checkLogin() -> Bool { - guard let reactor = reactor else { return false } - return reactor.currentState.isLogin - } - - override func undoBookmark() { - reactor?.action.onNext(.undoLastDeletedBookmark) - } -} - -// MARK: - Populate Data -private extension MonsterDictionaryDetailViewController { - func setUpMainInfo(name: String, subText: String, imageUrl: String?) { - // 상세정보 - inject( - input: DictionaryDetailBaseViewController - .Input( - imageUrl: imageUrl, - backgroundColor: type.backgroundColor, - name: name, - subText: subText - ) - ) - } - - func setUpInfoStackView() { - guard let reactor = reactor else { return } - let infos = reactor.currentState.infos - - contentViews.append(detailView) - - for info in infos { - detailView.addInfo(mainText: info.name, subText: info.desc) - } - } - - func setUpMapView() { - guard let reactor = reactor, - let filter = reactor.currentState.mapFilter.first else { return } - - appearMapView.initFilter(firstFilter: filter) - - let maps = reactor.currentState.spawnMaps - appearMapView.reset() - contentViews.append(appearMapView) - if maps.isEmpty { - contentViews[1] = DetailEmptyView(type: .appearMap) - } else { - contentViews[1] = appearMapView - - for map in maps { - appearMapView.inject(input: DetailStackCardView - .Input( - type: .appearMapWithText, - imageUrl: map.iconUrl, - mainText: map.mapName, - subText: map.regionName, - additionalText: { - if let count = map.maxSpawnCount { - return "\(count)마리" - } else { - return "??마리" - } - }() - ) - ) - } - } - } - - func setUpDropItemView() { - guard let reactor = reactor, - let filter = reactor.currentState.itemFilter.first else { return } - - dropItemView.initFilter(firstFilter: filter) - let items = reactor.currentState.dropItems - - dropItemView.reset() - contentViews.append(dropItemView) - // 드롭아이템 - if items.isEmpty { - // 드롭 아이템 - contentViews[2] = DetailEmptyView(type: .dropItemWithText) - } else { - contentViews[2] = dropItemView - for item in items { - dropItemView - .inject( - input: DetailStackCardView - .Input( - type: .dropItemWithText, - imageUrl: item.imageUrl, - mainText: item.itemName, - subText: "Lv.\(item.itemLevel)", - additionalText: "\(item.dropRate)%" - ) - ) - } - } - } -} - -// MARK: - Bind -extension MonsterDictionaryDetailViewController { - public func bind(reactor: Reactor) { - bindcUserActions(reactor: reactor) - bindViewState(reactor: reactor) - bindReportButton(providerId: reactor.state.map { $0.id }, itemName: reactor.state.map { $0.monsterDetailInfo.nameKr }) - } - - private func bindcUserActions(reactor: Reactor) { - rx.viewWillAppear - .map { Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - dropItemView.filterButton.rx.tap - .map { Reactor.Action.filterButtonTapped(.item) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - appearMapView.filterButton.rx.tap - .map { Reactor.Action.filterButtonTapped(.map) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - dropItemView.tap - .map { Reactor.Action.itemTapped(index: $0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - appearMapView.tap - .map { Reactor.Action.mapTapped(index: $0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - private func bindViewState(reactor: Reactor) { - reactor.state.map(\.monsterDetailInfo) - .distinctUntilChanged() - .observe(on: MainScheduler.instance) - .withUnretained(self) - .bind(onNext: { owner, monster in - if let tags = monster.typeEffectiveness { - owner.makeTagsRow(tags) - } - owner.setUpMainInfo(name: reactor.currentState.monsterDetailInfo.nameKr, subText: "Lv. \(reactor.currentState.monsterDetailInfo.level)", imageUrl: reactor.currentState.monsterDetailInfo.imageUrl) - owner.mainView.setBookmark(isBookmarked: monster.bookmarkId != nil) - owner.setUpInfoStackView() - }) - .disposed(by: disposeBag) - - reactor.state.map(\.spawnMaps) - .distinctUntilChanged() - .observe(on: MainScheduler.instance) - .withUnretained(self) - .bind(onNext: { owner, _ in - owner.setUpMapView() - }) - .disposed(by: disposeBag) - - reactor.state.map(\.dropItems) - .distinctUntilChanged() - .observe(on: MainScheduler.instance) - .withUnretained(self) - .bind(onNext: { owner, _ in - owner.setUpDropItemView() - }) - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } // 값이 바뀔때만 이벤트 받음 - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, route in - switch route { - case .filter(let type, let sort): - let selectedIndex = (type == .item) ? owner.dropItemSelectedIndex : owner.mapSelectedIntdex - - let viewController = owner.sortedFactory.make(sortedOptions: sort, selectedIndex: selectedIndex) { index in - if type == .item { - owner.dropItemSelectedIndex = index - let selectedFilter = sort[index] - owner.dropItemView.selectFilter(selectedType: selectedFilter) - reactor.action.onNext(.selectFilter(selectedFilter)) - } else if type == .map { - owner.mapSelectedIntdex = index - let selectedFilter = sort[index] - owner.appearMapView.selectFilter(selectedType: selectedFilter) - reactor.action.onNext(.selectFilter(selectedFilter)) - } - } - owner.tabBarController?.presentModal(viewController, hideTabBar: true) - case let .detail(type: type, id: id): - let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, loginRelay: owner.loginRelay) - owner.navigationController?.pushViewController(viewController, animated: true) - case .bookmarkError: - ToastFactory.createToast(message: "북마크 요청에 실패했어요. 다시 시도해주세요.") - default: - break - } - } - .disposed(by: disposeBag) - - reactor.pulse(\.$event) - .bind(onNext: { [weak self] event in - switch event { - case let .add(item): - self?.presentAddSnackBar( - bookmarkId: item.bookmarkId, - imageUrl: item.imageUrl, - background: DictionaryItemType.item.backgroundColor - ) - self?.bookmarkRelay?.accept((item.monsterId, item.bookmarkId)) - case let .delete(item): - self?.presentDeleteSnackBar( - imageUrl: item.imageUrl, - background: DictionaryItemType.item.backgroundColor - ) - self?.bookmarkRelay?.accept((item.monsterId, item.bookmarkId)) - default: break - } - }) - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift deleted file mode 100644 index 1857182c..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailReactor.swift +++ /dev/null @@ -1,194 +0,0 @@ -import DomainInterface - -import ReactorKit - -public final class NpcDictionaryDetailReactor: Reactor { - // MARK: - Route - public enum Route { - case none - case filter([SortType]) - case detail(type: DictionaryType, id: Int) - case bookmarkError - } - - public enum UIEvent { - case none - case add(DictionaryDetailNpcResponse) - case delete(DictionaryDetailNpcResponse) - case undo - } - - // MARK: - Action - public enum Action { - case filterButtonTapped - case viewWillAppear - case selectFilter(SortType) - case toggleBookmark - case undoLastDeletedBookmark - case mapTapped(index: Int) - case questTapped(index: Int) - } - - // MARK: - Mutation - public enum Mutation { - case navigatTo(Route) - case setDetailData(DictionaryDetailNpcResponse) - case setDetailMaps([DictionaryDetailMonsterMapResponse]) - case setDetailQuests([DictionaryDetailNpcQuestResponse]) - case setLoginState(Bool) - case setLastDeletedBookmark(DictionaryDetailNpcResponse?) - case setEvent(UIEvent) - } - - // MARK: - State - public struct State { - @Pulse var event: UIEvent = .none - @Pulse var route: Route = .none - var npcDetailInfo: DictionaryDetailNpcResponse - var type: DictionaryType = .npc - var maps: [DictionaryDetailMonsterMapResponse] - var quests: [DictionaryDetailNpcQuestResponse] - var questFilter: [SortType] { - type.detailTypes[0].sortFilter - } - var id: Int - var isLogin = false - var lastDeletedBookmark: DictionaryDetailNpcResponse? - } - - // MARK: - UseCases - private let dictionaryDetailNpcUseCase: FetchDictionaryDetailNpcUseCase - private let dictionaryDetailNpcQuestUseCase: FetchDictionaryDetailNpcQuestUseCase - private let dictionaryDetailNpcMapUseCase: FetchDictionaryDetailNpcMapUseCase - private let checkLoginUseCase: CheckLoginUseCase - private let setBookmarkUseCase: SetBookmarkUseCase - - public var initialState: State - private let disposeBag = DisposeBag() - - // MARK: - Init - public init( - dictionaryDetailNpcUseCase: FetchDictionaryDetailNpcUseCase, - dictionaryDetailNpcQuestUseCase: FetchDictionaryDetailNpcQuestUseCase, - dictionaryDetailNpcMapUseCase: FetchDictionaryDetailNpcMapUseCase, - checkLoginUseCase: CheckLoginUseCase, - setBookmarkUseCase: SetBookmarkUseCase, - id: Int - ) { - self.dictionaryDetailNpcUseCase = dictionaryDetailNpcUseCase - self.dictionaryDetailNpcQuestUseCase = dictionaryDetailNpcQuestUseCase - self.dictionaryDetailNpcMapUseCase = dictionaryDetailNpcMapUseCase - self.checkLoginUseCase = checkLoginUseCase - self.setBookmarkUseCase = setBookmarkUseCase - self.initialState = State( - npcDetailInfo: DictionaryDetailNpcResponse( - npcId: 0, nameKr: "", nameEn: "", iconUrlDetail: nil, bookmarkId: nil - ), - maps: [], - quests: [], - id: id - ) - } - - // MARK: - Mutate - public func mutate(action: Action) -> Observable { - switch action { - case .filterButtonTapped: - return .just(.navigatTo(.filter(currentState.questFilter))) - case .viewWillAppear: - return .merge([ - checkLoginUseCase.execute().map { .setLoginState($0) }, - dictionaryDetailNpcUseCase.execute(id: currentState.id).map { .setDetailData($0) }, - dictionaryDetailNpcMapUseCase.execute(id: currentState.id).map { .setDetailMaps($0) }, - dictionaryDetailNpcQuestUseCase.execute(id: currentState.id, sort: nil).map { .setDetailQuests($0) } - ]) - case let .selectFilter(type): - return dictionaryDetailNpcQuestUseCase.execute(id: currentState.id, sort: type.sortParameter).map { .setDetailQuests($0) } - - case .toggleBookmark: - return handleToggleBookmark() - - case .undoLastDeletedBookmark: - return handleUndoLastDeletedBookmark() - - case .mapTapped(index: let index): - return .just(.navigatTo(.detail(type: .map, id: currentState.maps[index].mapId))) - - case .questTapped(index: let index): - return .just(.navigatTo(.detail(type: .quest, id: currentState.quests[index].questId))) - } - } - - // MARK: - Reduce - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - switch mutation { - case .navigatTo(let route): - newState.route = route - case let .setDetailData(data): - newState.npcDetailInfo = data - case let .setDetailMaps(data): - newState.maps = data - case let .setDetailQuests(data): - newState.quests = data - case let .setLoginState(isLogin): - newState.isLogin = isLogin - case let .setLastDeletedBookmark(map): - newState.lastDeletedBookmark = map - case let .setEvent(event): - newState.event = event - } - return newState - } -} - -private extension NpcDictionaryDetailReactor { - func handleToggleBookmark() -> Observable { - var npc = currentState.npcDetailInfo - let isSelected = npc.bookmarkId != nil - guard let type = currentState.type.toItemType else { return .empty() } - - return setBookmarkUseCase.execute( - bookmarkId: isSelected ? npc.bookmarkId ?? npc.npcId : npc.npcId, - isBookmark: isSelected ? .delete : .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } - - npc.bookmarkId = newBookmarkId - let event: UIEvent = isSelected ? .delete(npc) : .add(npc) - let eventMutation = Observable.just(Mutation.setEvent(event)) - - let refresh = self.dictionaryDetailNpcUseCase.execute(id: self.currentState.id) - .map { Mutation.setDetailData($0) } - - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigatTo(.bookmarkError)) - } - } - - func handleUndoLastDeletedBookmark() -> Observable { - var npc = currentState.npcDetailInfo - guard let type = currentState.type.toItemType else { return .empty() } - - return setBookmarkUseCase.execute( - bookmarkId: npc.npcId, - isBookmark: .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } - - npc.bookmarkId = newBookmarkId - let eventMutation = Observable.just(Mutation.setEvent(.add(npc))) - let refresh = self.dictionaryDetailNpcUseCase.execute(id: self.currentState.id) - .map { Mutation.setDetailData($0) } - - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigatTo(.bookmarkError)) - } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift deleted file mode 100644 index 04d448ef..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/NPC/NpcDictionaryDetailViewController.swift +++ /dev/null @@ -1,204 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem -import DictionaryFeatureInterface -import DomainInterface - -import ReactorKit -import RxCocoa -import RxSwift - -final class NpcDictionaryDetailViewController: DictionaryDetailBaseViewController, View { - public typealias Reactor = NpcDictionaryDetailReactor - - // MARK: - Componenets - private var appearMapView = DetailStackCardView() - private var questView = DetailStackCardView() - private let sortedFactory: SortedBottomSheetFactory = SortedBottomSheetFactoryImpl() - - override func toggleBookmark() { - reactor?.action.onNext(.toggleBookmark) - } - - override func checkLogin() -> Bool { - guard let reactor = reactor else { return false } - return reactor.currentState.isLogin - } - - override func undoBookmark() { - reactor?.action.onNext(.undoLastDeletedBookmark) - } -} - -// MARK: - SetUp -private extension NpcDictionaryDetailViewController { - // 매개변수로 넘겨주는 것과 - func setUpMainInfo(name: String, imageUrl: String?) { - // 상세정보(메인) - inject( - input: DictionaryDetailBaseViewController - .Input( - imageUrl: imageUrl, - backgroundColor: type.backgroundColor, - name: name, - subText: "" - ) - ) - } - - // 내부에서 리액터 사용해서 하는 것 - func setUpMapView() { - guard let reactor = reactor else { return } - let maps = reactor.currentState.maps - - appearMapView.reset() - contentViews.append(appearMapView) - if maps.isEmpty { - // 출현맵 - contentViews[0] = DetailEmptyView(type: .appearMap) - } else { - contentViews[0] = appearMapView - for map in maps { - appearMapView.inject(input: DetailStackCardView.Input( - type: .appearMap, - imageUrl: map.iconUrl, - mainText: map.mapName, - subText: map.detailName - )) - } - } - } - - func setUpQuestView() { - guard let reactor = reactor, - let filter = reactor.currentState.questFilter.first else { return } - - questView.initFilter(firstFilter: filter) - - let quests = reactor.currentState.quests - questView.reset() - contentViews.append(questView) - if quests.isEmpty { - // 퀘스트 - contentViews[1] = DetailEmptyView(type: .quest) - } else { - contentViews[1] = questView - for quest in quests { - questView.inject(input: DetailStackCardView.Input( - type: .quest, - imageUrl: quest.questIconUrl, - mainText: quest.questNameKr - )) - } - } - } -} - -// MARK: - Bind -extension NpcDictionaryDetailViewController { - func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - bindReportButton(providerId: reactor.state.map { $0.id }, itemName: reactor.state.map { $0.npcDetailInfo.nameKr }) - } - - private func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .map { Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - questView.filterButton.rx.tap - .map { Reactor.Action.filterButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - questView.tap - .map { Reactor.Action.questTapped(index: $0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - appearMapView.tap - .map { Reactor.Action.mapTapped(index: $0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - private func bindViewState(reactor: Reactor) { - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } // 값이 바뀔때만 이벤트 받음 - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, route in - switch route { - case .filter(let type): - let viewController = owner.sortedFactory.make(sortedOptions: type, selectedIndex: owner.selectedIndex) { index in - owner.selectedIndex = index - let selectedFilter = type[index] - owner.questView.selectFilter(selectedType: selectedFilter) - reactor.action.onNext(.selectFilter(selectedFilter)) - } - owner.tabBarController?.presentModal(viewController, hideTabBar: true) - case .detail(type: let type, id: let id): - let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, loginRelay: owner.loginRelay) - owner.navigationController?.pushViewController(viewController, animated: true) - case .bookmarkError: - ToastFactory.createToast(message: "북마크 요청에 실패했어요. 다시 시도해주세요.") - default: - break - } - } - .disposed(by: disposeBag) - - reactor.state.map(\.npcDetailInfo) - .distinctUntilChanged() - .observe(on: MainScheduler.instance) - .withUnretained(self) - .bind(onNext: { owner, map in - owner.setUpMainInfo(name: map.nameKr, imageUrl: map.iconUrlDetail) - owner.mainView.setBookmark(isBookmarked: map.bookmarkId != nil) - }) - .disposed(by: disposeBag) - - reactor.state.map(\.maps) - .distinctUntilChanged() - .observe(on: MainScheduler.instance) - .withUnretained(self) - .bind(onNext: { owner, _ in - owner.setUpMapView() - }) - .disposed(by: disposeBag) - - reactor.state.map(\.quests) - .distinctUntilChanged() - .observe(on: MainScheduler.instance) - .withUnretained(self) - .bind(onNext: { owner, _ in - owner.setUpQuestView() - }) - .disposed(by: disposeBag) - - reactor.pulse(\.$event) - .bind(onNext: { [weak self] event in - switch event { - case let .add(item): - self?.presentAddSnackBar( - bookmarkId: item.bookmarkId, - imageUrl: item.iconUrlDetail, - background: DictionaryItemType.item.backgroundColor - ) - self?.bookmarkRelay?.accept((item.npcId, item.bookmarkId)) - case let .delete(item): - self?.presentDeleteSnackBar( - imageUrl: item.iconUrlDetail, - background: DictionaryItemType.item.backgroundColor - ) - self?.bookmarkRelay?.accept((item.npcId, item.bookmarkId)) - default: break - } - }) - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/OnBoarding/DetailOnBoardingFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/OnBoarding/DetailOnBoardingFactoryImpl.swift deleted file mode 100644 index 6c0482f5..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/OnBoarding/DetailOnBoardingFactoryImpl.swift +++ /dev/null @@ -1,14 +0,0 @@ -import BaseFeature -import DictionaryFeatureInterface - -public final class DetailOnBoardingFactoryImpl: DetailOnBoardingFactory { - public init() {} - - public func make() -> BaseViewController { - let reactor = DetailOnBoardingReactor() - let viewController = DetailOnBoardingViewController() - viewController.reactor = reactor - viewController.isBottomTabbarHidden = true - return viewController - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/OnBoarding/DetailOnBoardingReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/OnBoarding/DetailOnBoardingReactor.swift deleted file mode 100644 index c473e635..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/OnBoarding/DetailOnBoardingReactor.swift +++ /dev/null @@ -1,52 +0,0 @@ -import DomainInterface - -import ReactorKit - -public final class DetailOnBoardingReactor: Reactor { - // MARK: - Route - public enum Route { - case none - case dismiss - } - - // MARK: - Action - public enum Action { - case closeButtonTapped - } - - // MARK: - Mutation - public enum Mutation { - case toNavigate(Route) - } - - // MARK: - State - public struct State { - @Pulse var route: Route = .none - } - - public var initialState: State - private let disposeBag = DisposeBag() - - // MARK: - Init - public init() { - self.initialState = State(route: .none) - } - - // MARK: - Mutate - public func mutate(action: Action) -> Observable { - switch action { - case .closeButtonTapped: - .just(.toNavigate(.dismiss)) - } - } - - // MARK: - Reduce - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - switch mutation { - case let .toNavigate(route): - newState.route = route - } - return newState - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/OnBoarding/DetailOnBoardingView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/OnBoarding/DetailOnBoardingView.swift deleted file mode 100644 index 798bcbc8..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/OnBoarding/DetailOnBoardingView.swift +++ /dev/null @@ -1,192 +0,0 @@ -import UIKit - -import DesignSystem -import DomainInterface - -import SnapKit - -class DetailOnBoardingView: UIView { - // MARK: - Type - public enum Constant { - static let margin: CGFloat = 48 - static let trailingMargin: CGFloat = 8 - static let iconSize: CGFloat = 36 - static let contentViewSize: CGFloat = 44 - static let arrowSize: CGFloat = 48 - static let arrowTrailing: CGFloat = 28 - static let arrowMargin: CGFloat = 6 - static let alertHeight: CGFloat = 220 - static let alertWidth: CGFloat = 328 - static let buttonWitdh: CGFloat = 96 - static let radius: CGFloat = 8 - } - - // MARK: - Components - private lazy var iconContentView: UIView = { - let view = UIView() - view.backgroundColor = .whiteMLS - view.layer.cornerRadius = Constant.radius - - view.addSubview(iconView) - - iconView.snp.makeConstraints { make in - make.center.equalToSuperview() - make.size.equalTo(Constant.iconSize) - } - - return view - }() - - private let iconView: UIImageView = { - let view = UIImageView(image: DesignSystemAsset.image(named: "guideIcon")) - return view - }() - - private let firstArrow: UIImageView = { - let view = UIImageView(image: DesignSystemAsset.image(named: "guideArrow1")) - return view - }() - - private let secondArrow: UIImageView = { - let view = UIImageView(image: DesignSystemAsset.image(named: "guideArrow2")) - return view - }() - - private let firstLabel: UILabel = { - let label = UILabel() - label.numberOfLines = 0 - - let text = "해당 내용에 잘못된 정보가 있다면\n아이콘을 눌러 제보할 수 있어요." - guard let font = UIFont.korFont(style: .bold, size: 16) else { return UILabel() } - let attributedString = NSMutableAttributedString( - string: text, - attributes: [ - .foregroundColor: UIColor.whiteMLS, - .font: font - ] - ) - - let highlights = ["잘못된 정보", "아이콘을 눌러 제보"] - - highlights.forEach { keyword in - if let range = text.range(of: keyword) { - attributedString.addAttribute( - .foregroundColor, - value: UIColor.secondary, - range: NSRange(range, in: text) - ) - } - } - - label.attributedText = attributedString - return label - }() - - private let secondLabel: UILabel = { - let label = UILabel() - label.numberOfLines = 0 - - let text = "제보해주시면 빠르게 반영 할게요!" - guard let font = UIFont.korFont(style: .bold, size: 16) else { return UILabel() } - let attributedString = NSMutableAttributedString( - string: text, - attributes: [ - .foregroundColor: UIColor.whiteMLS, - .font: font - ] - ) - - if let range = text.range(of: "빠르게 반영") { - let nsRange = NSRange(range, in: text) - attributedString.addAttribute(.foregroundColor, value: UIColor.secondary, range: nsRange) - } - - label.attributedText = attributedString - return label - }() - - private let alertView: UIImageView = { - let view = UIImageView(image: DesignSystemAsset.image(named: "guideAlert")) - return view - }() - - public let closeButton: CommonButton = { - let button = CommonButton(style: .border, title: "닫기", disabledTitle: nil) - button.updateTitleColor(color: .whiteMLS) - return button - }() - - // MARK: - Init - init() { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension DetailOnBoardingView { - func addViews() { - addSubview(iconContentView) - addSubview(firstArrow) - addSubview(secondArrow) - addSubview(firstLabel) - addSubview(secondLabel) - addSubview(alertView) - addSubview(closeButton) - } - - func setupConstraints() { - iconContentView.snp.makeConstraints { make in - make.top.equalToSuperview() - make.leading.equalTo(firstArrow.snp.trailing) - make.trailing.equalToSuperview().inset(Constant.trailingMargin) - make.size.equalTo(Constant.contentViewSize) - } - - firstArrow.snp.makeConstraints { make in - make.top.equalTo(iconContentView.snp.centerY) - make.size.equalTo(Constant.arrowSize) - } - - firstLabel.snp.makeConstraints { make in - make.top.equalTo(firstArrow.snp.bottom) - make.trailing.equalToSuperview().inset(Constant.trailingMargin) - } - - alertView.snp.makeConstraints { make in - make.center.equalToSuperview() - make.width.equalTo(Constant.alertWidth) - make.height.equalTo(Constant.alertHeight) - } - - secondArrow.snp.makeConstraints { make in - make.top.equalTo(alertView.snp.bottom).offset(Constant.arrowMargin) - make.centerX.equalTo(firstLabel) - make.size.equalTo(Constant.arrowSize) - } - - secondLabel.snp.makeConstraints { make in - make.top.equalTo(secondArrow.snp.bottom).offset(Constant.arrowMargin) - make.trailing.equalTo(secondArrow.snp.trailing).offset(Constant.arrowTrailing) - } - - closeButton.snp.makeConstraints { make in - make.centerX.equalToSuperview() - make.bottom.equalToSuperview().inset(Constant.margin) - make.width.equalTo(Constant.buttonWitdh) - } - } - - func configureUI() { - backgroundColor = .clearMLS - } -} - -extension DetailOnBoardingView {} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/OnBoarding/DetailOnBoardingViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/OnBoarding/DetailOnBoardingViewController.swift deleted file mode 100644 index 1f1f1552..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/OnBoarding/DetailOnBoardingViewController.swift +++ /dev/null @@ -1,83 +0,0 @@ -import UIKit - -import BaseFeature -import DictionaryFeatureInterface - -import ReactorKit -import RxCocoa -import RxSwift - -class DetailOnBoardingViewController: BaseViewController, View { - public typealias Reactor = DetailOnBoardingReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - // MARK: - Components - public var mainView = DetailOnBoardingView() - - public override init() { - super.init() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension DetailOnBoardingViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide) - make.horizontalEdges.bottom.equalToSuperview() - } - } - - func configureUI() { - view.backgroundColor = .textColor.withAlphaComponent(0.9) - } -} - -extension DetailOnBoardingViewController { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - mainView.closeButton.rx.tap - .map { Reactor.Action.closeButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - rx.viewDidLoad - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .subscribe { owner, route in - switch route { - case .dismiss: - owner.dismiss(animated: true) - default: - break - } - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift deleted file mode 100644 index 8e35deb5..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailReactor.swift +++ /dev/null @@ -1,238 +0,0 @@ -import DomainInterface - -import ReactorKit - -public final class QuestDictionaryDetailReactor: Reactor { - enum QuestType { - case previous - case current - case next - } - - struct QuestInfo: Equatable { - let quest: Quest - let type: QuestType - } - - public enum Route { - case none - case filter(DictionaryType) - case detail(type: DictionaryType, id: Int) - case bookmarkError - } - - public enum UIEvent { - case none - case add(DictionaryDetailQuestResponse) - case delete(DictionaryDetailQuestResponse) - case undo - } - - public enum Action { - case viewWillAppear - case toggleBookmark - case undoLastDeletedBookmark - case questTapped(index: Int) - case infoTapped(type: DictionaryType, id: Int) - } - - public enum Mutation { - case navigatTo(Route) - case setDetailData(DictionaryDetailQuestResponse) - case setLinkedQuests(DictionaryDetailQuestLinkedQuestsResponse) - case setLoginState(Bool) - case setLastDeletedBookmark(DictionaryDetailQuestResponse?) - case setEvent(UIEvent) - } - - public struct State { - @Pulse var event: UIEvent = .none - @Pulse var route: Route = .none - var type: DictionaryType = .quest - var id: Int - var detailInfo: DictionaryDetailQuestResponse - var linkedQuestInfo: DictionaryDetailQuestLinkedQuestsResponse - var totalQuest: [QuestInfo] - var isLogin = false - var lastDeletedBookmark: DictionaryDetailQuestResponse? - } - - private let dictionaryDetailQuestUseCase: FetchDictionaryDetailQuestUseCase - private let dictionaryDetailQuestLinkedQuestUseCase: FetchDictionaryDetailQuestLinkedQuestsUseCase - private let checkLoginUseCase: CheckLoginUseCase - private let setBookmarkUseCase: SetBookmarkUseCase - - public var initialState: State - private let disposeBag = DisposeBag() - - public init( - dictionaryDetailQuestUseCase: FetchDictionaryDetailQuestUseCase, - dictionaryDetailQuestLinkedQuestUseCase: FetchDictionaryDetailQuestLinkedQuestsUseCase, - checkLoginUseCase: CheckLoginUseCase, - setBookmarkUseCase: SetBookmarkUseCase, - id: Int - ) { - self.dictionaryDetailQuestUseCase = dictionaryDetailQuestUseCase - self.dictionaryDetailQuestLinkedQuestUseCase = dictionaryDetailQuestLinkedQuestUseCase - self.checkLoginUseCase = checkLoginUseCase - self.setBookmarkUseCase = setBookmarkUseCase - self.initialState = .init( - id: id, - detailInfo: .init( - questId: 0, - titlePrefix: nil, - nameKr: nil, - nameEn: nil, - iconUrl: nil, - questType: nil, - minLevel: nil, - maxLevel: nil, - requiredMesoStart: nil, - startNpcId: nil, - startNpcName: nil, - endNpcId: nil, - endNpcName: nil, - reward: nil, - rewardItems: nil, - requirements: nil, - allowedJobs: nil, - bookmarkId: nil - ), - linkedQuestInfo: .init(previousQuests: nil, nextQuests: nil), totalQuest: [] - ) - } - - public func mutate(action: Action) -> Observable { - switch action { - case .viewWillAppear: - return .merge([ - checkLoginUseCase.execute().map { .setLoginState($0) }, - dictionaryDetailQuestUseCase.execute(id: currentState.id).map { .setDetailData($0) }, - dictionaryDetailQuestLinkedQuestUseCase.execute(id: currentState.id).map { .setLinkedQuests($0) } - ]) - - case .toggleBookmark: - return handleToggleBookmark() - - case .undoLastDeletedBookmark: - return handleUndoLastDeletedBookmark() - - case let .questTapped(index): - let tappedQuestInfo = currentState.totalQuest[index] - guard let id = tappedQuestInfo.quest.questId, - tappedQuestInfo.type != .current else { return .empty() } - return .just(.navigatTo(.detail(type: .quest, id: id))) - - case let .infoTapped(type: type, id: id): - return .just(.navigatTo(.detail(type: type, id: id))) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - switch mutation { - case let .setDetailData(data): - newState.detailInfo = data - newState.totalQuest = mergeTotalQuests( - detailInfo: data, - linkedInfo: state.linkedQuestInfo - ) - case let .setLinkedQuests(data): - newState.linkedQuestInfo = data - newState.totalQuest = mergeTotalQuests( - detailInfo: state.detailInfo, - linkedInfo: data - ) - case let .setLoginState(isLogin): - newState.isLogin = isLogin - case let .setLastDeletedBookmark(data): - newState.lastDeletedBookmark = data - case let .navigatTo(route): - newState.route = route - case let .setEvent(event): - newState.event = event - } - return newState - } -} - -extension QuestDictionaryDetailReactor { - private func mergeTotalQuests( - detailInfo: DictionaryDetailQuestResponse, - linkedInfo: DictionaryDetailQuestLinkedQuestsResponse - ) -> [QuestInfo] { - var quests: [QuestInfo] = [] - - if let previous = linkedInfo.previousQuests { - let mapped = previous.map { QuestInfo(quest: $0, type: .previous) } - quests.append(contentsOf: mapped) - } - - let currentQuest = Quest( - questId: detailInfo.questId, - name: detailInfo.nameKr ?? "", - minLevel: detailInfo.minLevel, - maxLevel: detailInfo.maxLevel, - iconUrl: detailInfo.iconUrl - ) - quests.append(QuestInfo(quest: currentQuest, type: .current)) - - if let next = linkedInfo.nextQuests { - let mapped = next.map { QuestInfo(quest: $0, type: .next) } - quests.append(contentsOf: mapped) - } - - return quests - } -} - -private extension QuestDictionaryDetailReactor { - func handleToggleBookmark() -> Observable { - var quest = currentState.detailInfo - let isSelected = quest.bookmarkId != nil - guard let type = currentState.type.toItemType else { return .empty() } - - return setBookmarkUseCase.execute( - bookmarkId: isSelected ? quest.bookmarkId ?? quest.questId : quest.questId, - isBookmark: isSelected ? .delete : .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } - - quest.bookmarkId = newBookmarkId - let event: UIEvent = isSelected ? .delete(quest) : .add(quest) - let eventMutation = Observable.just(Mutation.setEvent(event)) - - let refresh = self.dictionaryDetailQuestUseCase.execute(id: self.currentState.id) - .map { Mutation.setDetailData($0) } - - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigatTo(.bookmarkError)) - } - } - - func handleUndoLastDeletedBookmark() -> Observable { - var quest = currentState.detailInfo - guard let type = currentState.type.toItemType else { return .empty() } - - return setBookmarkUseCase.execute( - bookmarkId: quest.questId, - isBookmark: .set(type) - ) - .flatMap { [weak self] newBookmarkId -> Observable in - guard let self else { return .empty() } - - quest.bookmarkId = newBookmarkId - let eventMutation = Observable.just(Mutation.setEvent(.add(quest))) - let refresh = self.dictionaryDetailQuestUseCase.execute(id: self.currentState.id) - .map { Mutation.setDetailData($0) } - - return .concat([eventMutation, refresh]) - } - .catch { _ in - .just(.navigatTo(.bookmarkError)) - } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift deleted file mode 100644 index 25e88982..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/Quest/QuestDictionaryDetailViewController.swift +++ /dev/null @@ -1,234 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem -import DomainInterface - -import ReactorKit -import RxCocoa -import RxSwift - -final class QuestDictionaryDetailViewController: DictionaryDetailBaseViewController, View { - public typealias Reactor = QuestDictionaryDetailReactor - // MARK: - Components - private var detailInfoView = DetailStackInfoView(type: .quest) - private var linkedQuestView = DetailStackCardView() - - override func toggleBookmark() { - reactor?.action.onNext(.toggleBookmark) - } - - override func checkLogin() -> Bool { - guard let reactor = reactor else { return false } - return reactor.currentState.isLogin - } - - override func undoBookmark() { - reactor?.action.onNext(.undoLastDeletedBookmark) - } -} - -// MARK: - Populate Data -private extension QuestDictionaryDetailViewController { - func setUpMainInfo() { - // 상세 정보(메인?) - inject(input: DictionaryDetailBaseViewController.Input( - imageUrl: reactor?.currentState.detailInfo.iconUrl, - backgroundColor: type.backgroundColor, - name: reactor?.currentState.detailInfo.nameKr ?? "이름 없음", - subText: "수락 Lv.\(reactor?.currentState.detailInfo.minLevel ?? 0)" - )) - } - - func setUpInfoStackView() { - guard let reactor = reactor else { return } - let detailInfos = reactor.currentState.detailInfo - - let rewardInfos = reactor.currentState.detailInfo.reward - let rewardItemInfos = reactor.currentState.detailInfo.rewardItems - - contentViews.append(detailInfoView) - // 뭘로 빈페이지 보여줄지 정하지.. - detailInfoView.reset() - if !(detailInfos.startNpcName == nil) { - contentViews.append(detailInfoView) - // 완료조건 추가 - if let requirements = detailInfos.requirements { - for requirement in requirements { - if let quantity = requirement.quantity { - if let name = requirement.itemName ?? requirement.monsterName, - let type = DictionaryType(rawValue: requirement.requirementType ?? "") { - - if let id = type == .item ? requirement.itemId : requirement.monsterId { - detailInfoView.addCondition( - mainText: name, - subText: "\(quantity)", - clickable: true, - onTap: { [weak reactor] in - reactor?.action.onNext(.infoTapped(type: type, id: id)) - } - ) - } else { - detailInfoView.addCondition( - mainText: name, - subText: "\(quantity)", - clickable: false, - onTap: {} - ) - } - } - } - } - } - - if let minLevel = detailInfos.minLevel { - detailInfoView.addDetailInfo(mainText: DictionaryDetailText.minLevel, subText: "\(minLevel)") - } - if let maxLevel = detailInfos.maxLevel { - detailInfoView.addDetailInfo(mainText: DictionaryDetailText.maxLevel, subText: "\(maxLevel)") - } - if let startNpc = detailInfos.startNpcName { - detailInfoView.addDetailInfo(mainText: DictionaryDetailText.startNpc, subText: startNpc) - } - if let endNpc = detailInfos.endNpcName { - detailInfoView.addDetailInfo(mainText: DictionaryDetailText.endNpc, subText: endNpc) - } - if let jobs = detailInfos.allowedJobs { - let jobNames = jobs.compactMap { $0.jobName } // nil 제거 + jobName만 추출 - let jobText = jobNames.joined(separator: ", ") - if !jobText.isEmpty { - detailInfoView.addDetailInfo(mainText: DictionaryDetailText.job, subText: jobText) - } - } - - // 보상 추가 - 메소,경험치, 인기도 - if let meso = rewardInfos?.meso { - detailInfoView.addReward(mainText: DictionaryDetailText.meso, subText: "\(meso.formatted())") - } - if let exp = rewardInfos?.exp { - detailInfoView.addReward(mainText: DictionaryDetailText.exp, subText: "\(exp.formatted())") - } - if let pop = rewardInfos?.popularity { - detailInfoView.addReward(mainText: DictionaryDetailText.pop, subText: "\(pop.formatted())") - } - if let rewardItems = rewardItemInfos { - for info in rewardItems { - guard let name = info.itemName else { continue } - guard let quantity = info.quantity else { continue } - detailInfoView.addReward(mainText: name, subText: "\(quantity)") - } - } - - } else { - contentViews.append(DetailEmptyView(type: .normal)) - } - } - - func setUpQuestView() { - guard let reactor = reactor else { return } - let quests = reactor.currentState.totalQuest - - linkedQuestView.reset() - contentViews.append(linkedQuestView) - - if quests.isEmpty { - contentViews[1] = DetailEmptyView(type: .quest) - } else { - contentViews[1] = linkedQuestView - - for data in quests { - linkedQuestView.inject( - input: DetailStackCardView.Input( - type: .linkedQuest, - imageUrl: data.quest.iconUrl ?? "", - mainText: data.quest.name, - subText: "수락 Lv.\(data.quest.minLevel ?? 0)", - questType: data.type - ) - ) - } - } - } -} - -// MARK: - Bind -extension QuestDictionaryDetailViewController { - public func bind(reactor: Reactor) { - bindUserAction(reactor: reactor) - bindViewState(reactor: reactor) - bindReportButton(providerId: reactor.state.map { $0.detailInfo.questId }, itemName: reactor.state.map { $0.detailInfo.nameKr ?? "" }) - } - - private func bindUserAction(reactor: Reactor) { - rx.viewWillAppear - .map { Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - linkedQuestView.tap - .map { Reactor.Action.questTapped(index: $0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - private func bindViewState(reactor: Reactor) { - reactor.state.map(\.detailInfo) - .distinctUntilChanged() - .observe(on: MainScheduler.instance) - .withUnretained(self) - .bind(onNext: { owner, map in - owner.setUpMainInfo() - owner.setUpInfoStackView() - owner.mainView.setBookmark(isBookmarked: map.bookmarkId != nil) - }) - .disposed(by: disposeBag) - - reactor.state.map(\.totalQuest) - .distinctUntilChanged() - .observe(on: MainScheduler.instance) - .withUnretained(self) - .bind(onNext: { owner, _ in - owner.setUpQuestView() - }) - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, route in - switch route { - case let .detail(type, id): - let viewController = owner.dictionaryDetailFactory.make(type: type, id: id, bookmarkRelay: owner.bookmarkRelay, loginRelay: owner.loginRelay) - owner.navigationController?.pushViewController(viewController, animated: true) - case .bookmarkError: - ToastFactory.createToast(message: "북마크 요청에 실패했어요. 다시 시도해주세요.") - default: - break - } - } - .disposed(by: disposeBag) - - reactor.pulse(\.$event) - .bind(onNext: { [weak self] event in - switch event { - case let .add(item): - self?.presentAddSnackBar( - bookmarkId: item.bookmarkId, - imageUrl: item.iconUrl, - background: DictionaryItemType.item.backgroundColor - ) - self?.bookmarkRelay?.accept((item.questId, item.bookmarkId)) - case let .delete(item): - self?.presentDeleteSnackBar( - imageUrl: item.iconUrl, - background: DictionaryItemType.item.backgroundColor - ) - self?.bookmarkRelay?.accept((item.questId, item.bookmarkId)) - default: break - } - }) - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailEmptyView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailEmptyView.swift deleted file mode 100644 index 20d4cee5..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailEmptyView.swift +++ /dev/null @@ -1,53 +0,0 @@ -import DomainInterface -import UIKit - -import DesignSystem - -import SnapKit - -final class DetailEmptyView: UIView { - // MARK: - Type - private enum Constant { - static let topSpacing: CGFloat = 20 - static let filterSpacing: CGFloat = 12 - static let cardHorizontalInset: CGFloat = 16 - static let filterContainerHeight: CGFloat = 28 - static let filterContainerTopMargin: CGFloat = 12 - static let filterButtonTrailing: CGFloat = 8 - static let viewSpacing: CGFloat = 10 - } - - // MARK: - Components - let textLabel = UILabel() - - // MARK: - Init - init(type: DetailType) { - super.init(frame: .zero) - addViews() - setUpConstraints() - setTextLabel(type: type) - } - - @available(*, unavailable) - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension DetailEmptyView { - func addViews() { - addSubview(textLabel) - } - - func setUpConstraints() { - textLabel.snp.makeConstraints { make in - make.top.equalToSuperview().inset(36) - make.horizontalEdges.equalToSuperview().inset(16) - } - } - - func setTextLabel(type: DetailType) { - textLabel.attributedText = .makeStyledString(font: .b_s_r, text: "\(type.description) 정보가 존재하지 않습니다.", color: .neutral600) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailStackCardView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailStackCardView.swift deleted file mode 100644 index 3d567b67..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailStackCardView.swift +++ /dev/null @@ -1,268 +0,0 @@ -import BaseFeature -import DesignSystem -import DomainInterface -import RxCocoa -import RxGesture -import RxSwift -import SnapKit -import UIKit - -final class DetailStackCardView: UIStackView { - // MARK: - Type - private enum Constant { - static let topSpacing: CGFloat = 20 - static let filterSpacing: CGFloat = 12 - static let cardHorizontalInset: CGFloat = 16 - static let filterContainerHeight: CGFloat = 28 - static let filterContainerTopMargin: CGFloat = 12 - static let filterButtonTrailing: CGFloat = 8 - static let viewSpacing: CGFloat = 10 - static let stackViewInset: UIEdgeInsets = .init( - top: 12, - left: 16, - bottom: 0, - right: 16 - ) - } - - // MARK: - Properties - private let disposeBag = DisposeBag() - - private let tapSubject = PublishSubject() - var tap: Observable { tapSubject.asObservable() } - - // MARK: - Components - private var cardViews: [CardList] = [] - - private let filterContainerView = UIView() - // 몬스터 순서 필터 버튼 - public let filterButton: UIButton = { - let button = UIButton() - button.setAttributedTitle( - .makeStyledString( - font: .b_s_r, - text: "드롭률 높은 순", - color: .textColor - ), - for: .normal - ) - button.setImage( - DesignSystemAsset.image(named: "dropDown")?.withRenderingMode( - .alwaysTemplate - ), - for: .normal - ) - - button.tintColor = .textColor - button.semanticContentAttribute = .forceRightToLeft - return button - }() - - private let spacer = UIView() - - // MARK: - Init - init() { - super.init(frame: .zero) - self.isLayoutMarginsRelativeArrangement = true - self.layoutMargins = Constant.stackViewInset - - addViews() - setUpConstraints() - configureUI() - } - - @available(*, unavailable) - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -extension DetailStackCardView { - fileprivate func addViews() { - addArrangedSubview(filterContainerView) - filterContainerView.addSubview(filterButton) - addArrangedSubview(spacer) - } - - fileprivate func setUpConstraints() { - filterContainerView.snp.makeConstraints { make in - make.height.equalTo(Constant.filterContainerHeight) - } - - filterButton.snp.makeConstraints { make in - make.centerY.equalToSuperview() - make.trailing.equalToSuperview().inset( - Constant.filterButtonTrailing - ) - } - - spacer.snp.makeConstraints { make in - make.height.equalTo(Constant.filterSpacing) - } - } - - fileprivate func configureUI() { - axis = .vertical - alignment = .fill - distribution = .fill - } -} - -// MARK: - Methods -extension DetailStackCardView { - struct Input { - let type: DetailType - let imageUrl: String - // 왼쪽 텍스트 - let mainText: String? - var subText: String? - // 오른쪽 텍스트 - var additionalText: String? - var questType: QuestDictionaryDetailReactor.QuestType? - - init( - type: DetailType, - imageUrl: String, - mainText: String?, - subText: String? = nil, - additionalText: String? = nil, - questType: QuestDictionaryDetailReactor.QuestType? = nil - ) { - self.type = type - self.imageUrl = imageUrl - self.mainText = mainText - self.subText = subText - self.additionalText = additionalText - self.questType = questType - } - } - - func inject(input: Input) { - // type별 필터 유무 - setFilter(isHidden: input.type.sortFilter.isEmpty) - let cardView = CardList() - cardViews.append(cardView) - let spacer = UIView() - - addArrangedSubview(cardView) - addArrangedSubview(spacer) - - spacer.snp.makeConstraints { make in - make.height.equalTo(Constant.viewSpacing) - } - - cardView.setType(type: .detailStackText) - ImageLoader.shared.loadImage(stringURL: input.imageUrl) { image in - guard let image = image else { return } - if input.type == .appearMap || input.type == .appearMapWithText { - cardView.setMapImage( - image: image, - backgroundColor: input.type.backgroundColor - ) - } else { - cardView.setImage( - image: image, - backgroundColor: input.type.backgroundColor - ) - } - } - cardView.mainText = input.mainText - cardView.subText = input.subText - - switch input.type { - case .dropItemWithText, .dropMonsterWithText: - cardView.setType(type: .detailStackText) - cardView.setDropInfoText(title: "드롭률", value: input.additionalText) - case .appearMonsterWithText, .appearMapWithText: - cardView.setType(type: .detailStackText) - cardView.setDropInfoText(title: "출현수", value: input.additionalText) - case .appearMap, .appearNPC, .quest: - cardView.setType(type: .detailStack) - case .linkedQuest: - switch input.questType { - case .previous: - cardView.setType(type: .detailStackBadge(.preQuest)) - case .current: - cardView.setType(type: .detailStackBadge(.currentQuest)) - default: - cardView.setType(type: .detailStackBadge(.nextQuest)) - } - default: - break - } - - cardView.rx.tapGesture() - .when(.recognized) - .map { [weak self] _ -> Int in - guard let self = self else { return 0 } - return self.cardViews.firstIndex(of: cardView) ?? 0 - } - .bind(to: tapSubject) - .disposed(by: disposeBag) - } - - func setFilter(isHidden: Bool) { - filterContainerView.isHidden = isHidden - - spacer.snp.remakeConstraints { make in - make.height.equalTo( - isHidden ? Constant.topSpacing : Constant.filterSpacing - ) - } - } - - func selectFilter(selectedType: SortType) { - filterButton.setAttributedTitle( - .makeStyledString( - font: .b_s_r, - text: selectedType.rawValue, - color: .primary700 - ), - for: .normal - ) - filterButton.tintColor = .primary700 - } - - func initFilter(firstFilter: SortType) { - filterButton.setAttributedTitle( - .makeStyledString( - font: .b_s_r, - text: firstFilter.rawValue, - color: .textColor - ), - for: .normal - ) - } - - func reset() { - cardViews.removeAll() - // 필터 뷰를 제외한 arrangedSubview만 제거 - for subview in arrangedSubviews { - if subview == filterContainerView { continue } - if subview == spacer { continue } - - removeArrangedSubview(subview) - subview.removeFromSuperview() - } - } -} - -extension DetailType { - var backgroundColor: UIColor { - switch self { - case .appearMap, .appearMapWithText: - .listMap - case .appearMonsterWithText, .dropMonsterWithText: - .listMonster - case .appearNPC: - .listNPC - case .dropItemWithText: - .listItem - case .linkedQuest, .quest: - .listQuest - case .normal, .mapInfo: - .clearMLS - } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailStackInfoView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailStackInfoView.swift deleted file mode 100644 index 00670a7f..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailStackInfoView.swift +++ /dev/null @@ -1,296 +0,0 @@ -import UIKit - -import DesignSystem -import DomainInterface - -import RxGesture -import RxSwift -import SnapKit - -final class DetailStackInfoView: UIStackView { - // MARK: - Type - private enum Constant { - static let descriptionCornerRadius: CGFloat = 16 - static let descriptionStackViewInset: UIEdgeInsets = .init(top: 14, left: 16, bottom: 14, right: 16) - static let detailStackViewInset: UIEdgeInsets = .init(top: 20, left: 16, bottom: 20, right: 16) - static let detailInfoStackViewInset: UIEdgeInsets = .init(top: 10, left: 0, bottom: 10, right: 0) - static let height: CGFloat = 50 - static let dividerHeight: CGFloat = 1 - static let horizontalInset: CGFloat = 10 - static let detailInfoStackViewSpacing: CGFloat = 20 - static let titleLeadingInset: CGFloat = 16 - } - - // MARK: - Properties - private let disposeBag = DisposeBag() - - // MARK: - Components - // 상세정보 스택 뷰 속 설명 글 - var descriptionLabel: UILabel = { - let label = UILabel() - label.numberOfLines = 0 - label.attributedText = .makeStyledString(font: .b_s_r, text: "강철로 만든 수리검이다. 여러개가 들어있으며 모두 사용했다면 다시 충전해야 한다.강철로 만든 수리검이다. 여러개가 들어있으며 모두 사용했다면 다시 충전해야 한다.강철로 만든 수리검이다. 여러개가 들어있으며 모두 사용했다면 다시 충전해야 한다.", color: .neutral700) - label.textAlignment = .left - return label - }() - - // 상세정보 스택 뷰 속 아이템 정보 보여주는 스택뷰(물공 - 2, 판매가 - 1메소) - private let infoStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .vertical - stackView.alignment = .center - stackView.backgroundColor = .whiteMLS - stackView.distribution = .fill - stackView.layer.cornerRadius = Constant.descriptionCornerRadius - return stackView - }() - - // 퀘스트 상세정보 스택뷰 속 상세정보 스택뷰 - private let detailInfoStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .vertical - stackView.alignment = .center - stackView.backgroundColor = .whiteMLS - stackView.distribution = .fill - stackView.layer.cornerRadius = Constant.descriptionCornerRadius - stackView.isLayoutMarginsRelativeArrangement = true - stackView.layoutMargins = Constant.detailInfoStackViewInset - return stackView - }() - - // 타이틀 뷰 - private let detailInfoTitleLabelView = UIView() - // 타이틀 라벨 - private let detailInfoTitleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .sub_m_b, text: "상세 정보", color: .textColor) - return label - }() - - // 퀘스트 완료조건 스택뷰 - private let completeConditionStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .vertical - stackView.alignment = .center - stackView.backgroundColor = .whiteMLS - stackView.distribution = .fill - stackView.layer.cornerRadius = Constant.descriptionCornerRadius - stackView.isLayoutMarginsRelativeArrangement = true - stackView.layoutMargins = Constant.detailInfoStackViewInset - return stackView - }() - - private let completeConditionTitleLabelView = UIView() - private let completeConditionTitleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .sub_m_b, text: "완료 조건", color: .textColor) - return label - }() - - // 퀘스트 보상 스택뷰 - private let rewardStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .vertical - stackView.alignment = .center - stackView.backgroundColor = .whiteMLS - stackView.distribution = .fill - stackView.layer.cornerRadius = Constant.descriptionCornerRadius - stackView.isLayoutMarginsRelativeArrangement = true - stackView.layoutMargins = Constant.detailInfoStackViewInset - return stackView - }() - - private let rewardTitleLabelView = UIView() - private let rewardTitleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .sub_m_b, text: "보상", color: .textColor) - return label - }() - - // 어떤뷰 타입의 상세정보인지 구분하기 위한 변수 - private let type: DictionaryItemType - - // MARK: - Init - init(type: DictionaryItemType) { - self.type = type - super.init(frame: .zero) - configureUI() - addViews() - // 퀘스트일때만 제약 잡아줌 - if type == .quest { - setConstraints() - } - } - - @available(*, unavailable) - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension DetailStackInfoView { - func addViews() { - // DetailStackInfoView는 3가지(item, monster, quest)에서만 사용할 듯? - if type == .item { - // 아이템 타입일 경우만 설명라벨추가 - addArrangedSubview(descriptionLabel) - addArrangedSubview(infoStackView) - } else if type == .monster { - addArrangedSubview(infoStackView) - } else if type == .quest { - addArrangedSubview(detailInfoStackView) - detailInfoStackView.addArrangedSubview(detailInfoTitleLabelView) - detailInfoTitleLabelView.addSubview(detailInfoTitleLabel) - - addArrangedSubview(completeConditionStackView) - completeConditionStackView.addArrangedSubview(completeConditionTitleLabelView) - completeConditionTitleLabelView.addSubview(completeConditionTitleLabel) - - addArrangedSubview(rewardStackView) - rewardStackView.addArrangedSubview(rewardTitleLabelView) - rewardTitleLabelView.addSubview(rewardTitleLabel) - } - } - - func setConstraints() { - detailInfoTitleLabelView.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.height.equalTo(Constant.height) - } - detailInfoTitleLabel.snp.makeConstraints { make in - make.leading.equalTo(Constant.titleLeadingInset) - make.centerY.equalToSuperview() - } - completeConditionTitleLabelView.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.height.equalTo(Constant.height) - } - completeConditionTitleLabel.snp.makeConstraints { make in - make.leading.equalTo(Constant.titleLeadingInset) - make.centerY.equalToSuperview() - } - rewardTitleLabelView.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.height.equalTo(Constant.height) - } - rewardTitleLabel.snp.makeConstraints { make in - make.leading.equalTo(Constant.titleLeadingInset) - make.centerY.equalToSuperview() - } - } - - func configureUI() { - axis = .vertical - alignment = .fill - distribution = .fill - spacing = Constant.detailInfoStackViewSpacing - isLayoutMarginsRelativeArrangement = true - layoutMargins = Constant.detailStackViewInset - } -} - -// MARK: - Methods -extension DetailStackInfoView { - /// 퀘스트 상세정보 한 줄 추가 - func addDetailInfo(mainText: String, subText: String) { - addInfoRow(to: detailInfoStackView, mainText: mainText, subText: subText) - } - - /// 완료조건 상세정보 한 줄 추가 - func addCondition(mainText: String, subText: String, clickable: Bool, onTap: (() -> Void)? = nil) { - addInfoRow(to: completeConditionStackView, mainText: mainText, subText: subText, clickable: true, onTap: onTap) - } - - /// 보상 상세정보 한 줄 추가 - func addReward(mainText: String, subText: String) { - addInfoRow(to: rewardStackView, mainText: mainText, subText: subText) - } - - /// 아이템 상세정보 한 줄 추가 - func addInfo(mainText: String, subText: String) { - addInfoRow(to: infoStackView, mainText: mainText, subText: subText) - } - - /// 현재 표시 중인 모든 스택뷰 내용을 초기화 - func reset() { - infoStackView.arrangedSubviews.forEach { $0.removeFromSuperview() } - - detailInfoStackView.arrangedSubviews - .filter { $0 !== detailInfoTitleLabelView } - .forEach { $0.removeFromSuperview() } - - completeConditionStackView.arrangedSubviews - .filter { $0 !== completeConditionTitleLabelView } - .forEach { $0.removeFromSuperview() } - - rewardStackView.arrangedSubviews - .filter { $0 !== rewardTitleLabelView } - .forEach { $0.removeFromSuperview() } - } - - private func addInfoRow( - to stackView: UIStackView, - mainText: String, - subText: String, - clickable: Bool = false, - onTap: (() -> Void)? = nil - ) { - let rowStackView = UIStackView() - let dividerView = DividerView() - - rowStackView.axis = .horizontal - rowStackView.distribution = .equalSpacing - rowStackView.alignment = .center - rowStackView.isLayoutMarginsRelativeArrangement = true - rowStackView.layoutMargins = Constant.descriptionStackViewInset - - let mainLabel = UILabel() - let subLabel = UILabel() - subLabel.attributedText = .makeStyledString(font: .b_s_r, text: subText) - - if clickable { - let imageView = UIImageView(image: DesignSystemAsset.image(named: "rightArrow")) - let clickableStack = UIStackView(arrangedSubviews: [mainLabel, imageView]) - clickableStack.axis = .horizontal - clickableStack.spacing = 4 - clickableStack.alignment = .center - - mainLabel.attributedText = .makeStyledUnderlinedString(font: .sub_m_sb, text: mainText) - mainLabel.isUserInteractionEnabled = true - - mainLabel.rx.tapGesture() - .when(.recognized) - .bind { _ in - onTap?() - } - .disposed(by: disposeBag) - - rowStackView.addArrangedSubview(clickableStack) - } else { - mainLabel.attributedText = .makeStyledString(font: .sub_m_sb, text: mainText) - rowStackView.addArrangedSubview(mainLabel) - } - - rowStackView.addArrangedSubview(subLabel) - - if let lastDivider = stackView.arrangedSubviews.last as? DividerView { - lastDivider.isHidden = false - } - - stackView.addArrangedSubview(rowStackView) - stackView.addArrangedSubview(dividerView) - - dividerView.isHidden = true - - rowStackView.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.height.equalTo(Constant.height) - } - - dividerView.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.height.equalTo(Constant.dividerHeight) - } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailStackMapView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailStackMapView.swift deleted file mode 100644 index 3fd3b0f6..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/DetailStackMapView.swift +++ /dev/null @@ -1,69 +0,0 @@ -import BaseFeature -import DesignSystem -import UIKit - -final class DetailStackMapView: UIStackView { - // MARK: - Type - private enum Constant { - static let mapCornerRadius: CGFloat = 16 - static let mapLayoutMargin: UIEdgeInsets = .init(top: 20, left: 16, bottom: 0, right: 16) - } - - /// 상세설명 메뉴에서 보여줄 상세 설명 스택 뷰 3가지 - public let mapImageView: UIImageView = { - let view = UIImageView() - view.backgroundColor = .whiteMLS - view.layer.cornerRadius = Constant.mapCornerRadius - view.contentMode = .scaleAspectFit - view.clipsToBounds = true - return view - }() - - init(imageUrl: String) { - super.init(frame: .zero) - addViews() - setUpConstraints() - configureUI() - setUpMapView(imageUrl: imageUrl) - } - - @available(*, unavailable) - required init(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension DetailStackMapView { - func addViews() { - addArrangedSubview(mapImageView) - } - - func setUpConstraints() { - mapImageView.snp.makeConstraints { make in - make.height.equalTo(mapImageView.snp.width) - } - } - - func configureUI() { - isLayoutMarginsRelativeArrangement = true - layoutMargins = Constant.mapLayoutMargin - } -} - -extension DetailStackMapView { - func setUpMapView(imageUrl: String?) { - ImageLoader.shared.loadImage(stringURL: imageUrl) { [weak self] image in - if image == DesignSystemAsset.image(named: "connectionError") { - self?.mapImageView.snp.remakeConstraints { make in - make.size.equalTo(165) - } - } else { - self?.mapImageView.snp.remakeConstraints { make in - make.height.equalTo(self?.mapImageView.snp.width ?? 0) - } - } - self?.mapImageView.image = image - } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/PinchMapView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/PinchMapView.swift deleted file mode 100644 index 4ffa6d00..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/PinchMapView.swift +++ /dev/null @@ -1,94 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem - -final class PinchMapView: UIView { - // MARK: - Type - private enum Constant { - static let iconInset: CGFloat = 10 - static let navHeight: CGFloat = 44 - static let buttonSize: CGFloat = 44 - } - - // MARK: - Components - public let scrollView: UIScrollView = { - let scrollView = UIScrollView() - scrollView.minimumZoomScale = 1.0 - scrollView.maximumZoomScale = 4.0 - scrollView.showsVerticalScrollIndicator = false - scrollView.showsHorizontalScrollIndicator = false - scrollView.bouncesZoom = true - scrollView.backgroundColor = .clearMLS - return scrollView - }() - - public let imageView: UIImageView = { - let view = UIImageView() - view.clipsToBounds = true - view.contentMode = .scaleAspectFit - view.backgroundColor = .clearMLS - view.layer.opacity = 0.9 - return view - }() - - let backButton: UIButton = { - let button = UIButton() - button.setImage(DesignSystemAsset.image(named: "largeX")?.withRenderingMode(.alwaysTemplate), for: .normal) - button.tintColor = .whiteMLS - return button - }() - - // MARK: - Init - init() { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension PinchMapView { - func addViews() { - addSubview(scrollView) - scrollView.addSubview(imageView) - addSubview(backButton) - } - - func setupConstraints() { - scrollView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - - imageView.snp.makeConstraints { make in - make.edges.equalToSuperview() - make.width.equalToSuperview() - make.height.equalToSuperview() - } - - backButton.snp.makeConstraints { make in - make.top.equalToSuperview().inset(54) - make.leading.equalToSuperview().inset(16) - make.size.equalTo(24) - } - } - - func configureUI() { - backgroundColor = .textColor.withAlphaComponent(0.9) - } -} - -// MARK: - Methods -extension PinchMapView { - func setImage(imageUrl: String) { - ImageLoader.shared.loadImage(stringURL: imageUrl) { [weak self] image in - self?.imageView.image = image - } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/PinchMapViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/PinchMapViewController.swift deleted file mode 100644 index 745e6893..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryDetail/SectionStackView/PinchMapViewController.swift +++ /dev/null @@ -1,64 +0,0 @@ -import UIKit - -import BaseFeature - -import RxCocoa -import RxSwift - -class PinchMapViewController: BaseViewController { - // MARK: - Properties - public var disposeBag = DisposeBag() - - // MARK: - Components - private var mainView = PinchMapView() - - public init(imageUrl: String) { - super.init() - mainView.setImage(imageUrl: imageUrl) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension PinchMapViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } - - func configureUI() { - view.backgroundColor = .clearMLS - - mainView.scrollView.delegate = self - - mainView.backButton.rx.tap - .withUnretained(self) - .subscribe { owner, _ in - owner.dismiss(animated: true) - } - .disposed(by: disposeBag) - } -} - -extension PinchMapViewController: UIScrollViewDelegate { - public func viewForZooming(in scrollView: UIScrollView) -> UIView? { - return mainView.imageView - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListFactoryImpl.swift deleted file mode 100644 index 02884710..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListFactoryImpl.swift +++ /dev/null @@ -1,87 +0,0 @@ -import AuthFeatureInterface -import BaseFeature -import BookmarkFeatureInterface -import DictionaryFeatureInterface -import DomainInterface - -public final class DictionaryListFactoryImpl: DictionaryMainListFactory { - private let checkLoginUseCase: CheckLoginUseCase - private let dictionaryAllListItemUseCase: FetchDictionaryAllListUseCase - private let dictionaryMapListItemUseCase: FetchDictionaryMapListUseCase - private let dictionaryItemListItemUseCase: FetchDictionaryItemListUseCase - private let dictionaryQuestListItemUseCase: FetchDictionaryQuestListUseCase - private let dictionaryNpcListItemUseCase: FetchDictionaryNpcListUseCase - private let dictionaryListItemUseCase: FetchDictionaryMonsterListUseCase - private let parseItemFilterResultUseCase: ParseItemFilterResultUseCase - private let setBookmarkUseCase: SetBookmarkUseCase - - private let itemFilterFactory: ItemFilterBottomSheetFactory - private let monsterFilterFactory: MonsterFilterBottomSheetFactory - private let sortedFactory: SortedBottomSheetFactory - private let bookmarkModalFactory: BookmarkModalFactory - private let detailFactory: DictionaryDetailFactory - private let loginFactory: () -> LoginFactory - - public init( - checkLoginUseCase: CheckLoginUseCase, - dictionaryAllListItemUseCase: FetchDictionaryAllListUseCase, - dictionaryMapListItemUseCase: FetchDictionaryMapListUseCase, - dictionaryItemListItemUseCase: FetchDictionaryItemListUseCase, - dictionaryQuestListItemUseCase: FetchDictionaryQuestListUseCase, - dictionaryNpcListItemUseCase: FetchDictionaryNpcListUseCase, - dictionaryListItemUseCase: FetchDictionaryMonsterListUseCase, - setBookmarkUseCase: SetBookmarkUseCase, - parseItemFilterResultUseCase: ParseItemFilterResultUseCase, - itemFilterFactory: ItemFilterBottomSheetFactory, - monsterFilterFactory: MonsterFilterBottomSheetFactory, - sortedFactory: SortedBottomSheetFactory, - bookmarkModalFactory: BookmarkModalFactory, - detailFactory: DictionaryDetailFactory, - loginFactory: @escaping () -> LoginFactory - ) { - self.checkLoginUseCase = checkLoginUseCase - self.dictionaryAllListItemUseCase = dictionaryAllListItemUseCase - self.dictionaryMapListItemUseCase = dictionaryMapListItemUseCase - self.dictionaryItemListItemUseCase = dictionaryItemListItemUseCase - self.dictionaryQuestListItemUseCase = dictionaryQuestListItemUseCase - self.dictionaryNpcListItemUseCase = dictionaryNpcListItemUseCase - self.dictionaryListItemUseCase = dictionaryListItemUseCase - self.setBookmarkUseCase = setBookmarkUseCase - self.parseItemFilterResultUseCase = parseItemFilterResultUseCase - self.itemFilterFactory = itemFilterFactory - self.monsterFilterFactory = monsterFilterFactory - self.sortedFactory = sortedFactory - self.bookmarkModalFactory = bookmarkModalFactory - self.detailFactory = detailFactory - self.loginFactory = loginFactory - } - - public func make(type: DictionaryType, listType: DictionaryMainViewType, keyword: String? = "") -> BaseViewController { - let reactor = DictionaryListReactor( - type: type, - keyword: keyword, - checkLoginUseCase: checkLoginUseCase, - dictionaryAllListUseCase: dictionaryAllListItemUseCase, - dictionaryMapListUseCase: dictionaryMapListItemUseCase, - dictionaryItemListUseCase: dictionaryItemListItemUseCase, - dictionaryQuestListUseCase: dictionaryQuestListItemUseCase, - dictionaryNpcListUseCase: dictionaryNpcListItemUseCase, - dictionaryListUseCase: dictionaryListItemUseCase, - setBookmarkUseCase: setBookmarkUseCase, - parseItemFilterResultUseCase: parseItemFilterResultUseCase - ) - let viewController = DictionaryListViewController( - reactor: reactor, - itemFilterFactory: itemFilterFactory, - monsterFilterFactory: monsterFilterFactory, - sortedFactory: sortedFactory, - bookmarkModalFactory: bookmarkModalFactory, - detailFactory: detailFactory, - loginFactory: loginFactory() - ) - if listType == .search { - viewController.isBottomTabbarHidden = true - } - return viewController - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift deleted file mode 100644 index 7be1f4a9..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListReactor.swift +++ /dev/null @@ -1,389 +0,0 @@ -import BaseFeature -import DomainInterface - -import ReactorKit -import RxSwift - -public final class DictionaryListReactor: Reactor { - // MARK: - Type - public enum Route { - case none - case sort(DictionaryType) - case filter(DictionaryType) - case bookmarkError - } - - public enum UIEvent { - case none - case add(DictionaryMainItemResponse) - case delete(DictionaryMainItemResponse) - case undo - case login - } - - // MARK: - Action - public enum Action { - case viewWillAppear - case sortButtonTapped - case filterButtonTapped - case sortOptionSelected(SortType) - case filterOptionSelected(startLevel: Int, endLevel: Int) - case itemFilterOptionSelected([(String, String)]) - case setCurrentPage - case fetchList - case undoLastDeletedBookmark - case toggleBookmark(id: Int) - case showLogin - case updateBookmark(id: Int, newBookmarkId: Int?) - } - - // MARK: - Mutation - public enum Mutation { - case navigatTo(Route) - case setListItem(DictionaryMainResponse, updateBookmarkOnly: Bool = false) - case setSort(String) - case setFilter(start: Int?, end: Int?) - case setCurrentPage - case initPage - case setLoginState(Bool) - case setLastDeletedBookmark(DictionaryMainItemResponse?) - case setJobId([Int]) - case setCategoryId([Int]) - case updateBookmarkId(id: Int, newBookmarkId: Int?) - case setFirstFetch(Bool) - case setEvent(UIEvent) - } - - // MARK: - State - public struct State { - @Pulse var uiEvent: UIEvent = .none - @Pulse var route: Route - public var listItems: [DictionaryMainItemResponse] = [] - public var type: DictionaryType - - public var keyword: String? - public var jobId: [Int]? - public var categoryIds: [Int]? - public var sort: String? - public var startLevel: Int? - public var endLevel: Int? - - public var currentPage = 0 - public var totalCounts = 0 - - var isLogin: Bool - var lastDeletedBookmark: DictionaryMainItemResponse? - var isBookmarkUpdateOnly = false - var isFirstFetch = true - } - - public var initialState: State - - // MARK: - UseCases - private let checkLoginUseCase: CheckLoginUseCase - private let dictionaryAllListUseCase: FetchDictionaryAllListUseCase - private let dictionaryMapListUseCase: FetchDictionaryMapListUseCase - private let dictionaryItemListUseCase: FetchDictionaryItemListUseCase - private let dictionaryQuestListUseCase: FetchDictionaryQuestListUseCase - private let dictionaryNpcListUseCase: FetchDictionaryNpcListUseCase - private let dictionaryListUseCase: FetchDictionaryMonsterListUseCase - private let setBookmarkUseCase: SetBookmarkUseCase - private let parseItemFilterResultUseCase: ParseItemFilterResultUseCase - - private let disposeBag = DisposeBag() - - // MARK: - Init - public init( - type: DictionaryType, - keyword: String?, - checkLoginUseCase: CheckLoginUseCase, - dictionaryAllListUseCase: FetchDictionaryAllListUseCase, - dictionaryMapListUseCase: FetchDictionaryMapListUseCase, - dictionaryItemListUseCase: FetchDictionaryItemListUseCase, - dictionaryQuestListUseCase: FetchDictionaryQuestListUseCase, - dictionaryNpcListUseCase: FetchDictionaryNpcListUseCase, - dictionaryListUseCase: FetchDictionaryMonsterListUseCase, - setBookmarkUseCase: SetBookmarkUseCase, - parseItemFilterResultUseCase: ParseItemFilterResultUseCase - ) { - self.initialState = State(route: .none, type: type, keyword: keyword, isLogin: false) - self.checkLoginUseCase = checkLoginUseCase - self.dictionaryAllListUseCase = dictionaryAllListUseCase - self.dictionaryMapListUseCase = dictionaryMapListUseCase - self.dictionaryItemListUseCase = dictionaryItemListUseCase - self.dictionaryQuestListUseCase = dictionaryQuestListUseCase - self.dictionaryNpcListUseCase = dictionaryNpcListUseCase - self.dictionaryListUseCase = dictionaryListUseCase - self.setBookmarkUseCase = setBookmarkUseCase - self.parseItemFilterResultUseCase = parseItemFilterResultUseCase - } - - // MARK: - Mutate - public func mutate(action: Action) -> Observable { - switch action { - case .viewWillAppear: - return handleViewWillAppear() - case .sortButtonTapped: - return .just(.navigatTo(.sort(currentState.type))) - case .filterButtonTapped: - return .just(.navigatTo(.filter(currentState.type))) - case let .sortOptionSelected(sort): - return handleSortOptionSelected(sort: sort) - case let .filterOptionSelected(startLevel, endLevel): - return handleFilterOptionSelected(startLevel: startLevel, endLevel: endLevel) - case .setCurrentPage: - return .just(.setCurrentPage) - case .fetchList: - return fetchList(sort: currentState.sort, startLevel: currentState.startLevel, endLevel: currentState.endLevel) - case .undoLastDeletedBookmark: - return handleUndoLastDeletedBookmark() - case let .toggleBookmark(id): - return handleToggleBookmark(id: id) - case let .itemFilterOptionSelected(results): - return handleItemFilterOptionSelected(results: results) - case .showLogin: - return .just(.setEvent(.login)) - case let .updateBookmark(id, newBookmarkId): - return handleUpdateBookmark(id: id, newBookmarkId: newBookmarkId) - } - } - - // MARK: - Reduce - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - switch mutation { - case let .navigatTo(route): - newState.route = route - case let .setListItem(items, updateBookmarkOnly): - newState.isBookmarkUpdateOnly = updateBookmarkOnly - newState.totalCounts = items.totalElements - if updateBookmarkOnly { - newState.listItems = newState.listItems.map { item in - if let updated = items.contents.first(where: { $0.id == item.id }) { - var copy = item - copy.bookmarkId = updated.bookmarkId - return copy - } else { return item } - } - } else { - if newState.currentPage == 0 { - newState.listItems = items.contents - } else { - let existingIds = Set(newState.listItems.map { $0.id }) - let newItems = items.contents.filter { !existingIds.contains($0.id) } - newState.listItems.append(contentsOf: newItems) - } - } - case let .setSort(sort): - newState.sort = sort - case let .setFilter(startLevel, endLevel): - newState.startLevel = startLevel - newState.endLevel = endLevel - case .setCurrentPage: - newState.currentPage += 1 - case .initPage: - newState.currentPage = 0 - case let .setLastDeletedBookmark(item): - newState.lastDeletedBookmark = item - case let .setLoginState(isLogin): - newState.isLogin = isLogin - case let .setJobId(id): - newState.jobId = id - case let .setCategoryId(id): - newState.categoryIds = id - case let .setFirstFetch(isFirstFetch): - newState.isFirstFetch = isFirstFetch - case let .updateBookmarkId(id, newBookmarkId): - if let index = newState.listItems.firstIndex(where: { $0.id == id }) { - newState.listItems[index].bookmarkId = newBookmarkId - } - case let .setEvent(event): - newState.uiEvent = event - } - return newState - } -} - -// MARK: - Methods -private extension DictionaryListReactor { - func fetchList(sort: String?, startLevel: Int?, endLevel: Int?, updateBookmarkOnly: Bool = false) -> Observable { - let response: Observable - - switch currentState.type { - case .monster: - response = dictionaryListUseCase.execute( - type: .monster, - query: DictionaryListQuery( - keyword: currentState.keyword ?? "", - page: currentState.currentPage, - size: 20, - sort: sort, - minLevel: startLevel, - maxLevel: endLevel - ) - ) - case .item: - response = dictionaryItemListUseCase.execute( - keyword: currentState.keyword ?? "", - jobId: currentState.jobId, - minLevel: currentState.startLevel, - maxLevel: currentState.endLevel, - categoryIds: currentState.categoryIds, - page: currentState.currentPage, - size: 20, - sort: sort - ) - case .map: - response = dictionaryMapListUseCase.execute( - keyword: currentState.keyword ?? "", - page: currentState.currentPage, - size: 20, - sort: sort ?? "ASC" - ) - case .npc: - response = dictionaryNpcListUseCase.execute( - keyword: currentState.keyword ?? "", - page: currentState.currentPage, - size: 20, - sort: sort ?? "ASC" - ) - case .quest: - response = dictionaryQuestListUseCase.execute( - keyword: currentState.keyword ?? "", - page: currentState.currentPage, - size: 20, - sort: sort ?? "ASC" - ) - case .total: - response = dictionaryAllListUseCase.execute( - keyword: currentState.keyword ?? "", - page: currentState.currentPage - ) - default: - return .empty() - } - - return response.map { .setListItem($0, updateBookmarkOnly: updateBookmarkOnly) } - } - - func handleViewWillAppear() -> Observable { - let loginState = checkLoginUseCase.execute() - .map { Mutation.setLoginState($0) } - - let fetchMutation: Observable - - if currentState.isFirstFetch { - let firstFetch = Observable.just(Mutation.setFirstFetch(false)) - let fetch = fetchList( - sort: currentState.sort, - startLevel: currentState.startLevel, - endLevel: currentState.endLevel - ) - fetchMutation = .concat([firstFetch, fetch]) - } else { - fetchMutation = fetchList( - sort: currentState.sort, - startLevel: currentState.startLevel, - endLevel: currentState.endLevel, - updateBookmarkOnly: true - ) - } - - return .merge([loginState, fetchMutation]) - } - - func handleToggleBookmark(id: Int) -> Observable { - guard let index = currentState.listItems.firstIndex(where: { $0.id == id }) else { - return .empty() - } - - let targetItem = currentState.listItems[index] - let isSelected = targetItem.bookmarkId != nil - - return setBookmarkUseCase.execute( - bookmarkId: isSelected ? targetItem.bookmarkId ?? targetItem.id : targetItem.id, - isBookmark: isSelected ? .delete : .set(targetItem.type) - ) - .flatMap { newBookmarkId -> Observable in - let lastItem = Mutation.setLastDeletedBookmark(targetItem) - - let event: UIEvent = isSelected ? .delete(targetItem) : .add(targetItem) - let eventMutation = Mutation.setEvent(event) - - let updateMutation = Mutation.updateBookmarkId(id: id, newBookmarkId: newBookmarkId) - return .from([lastItem, updateMutation, eventMutation]) - } - .catch { _ in - .just(.navigatTo(.bookmarkError)) - } - } - - func handleUpdateBookmark(id: Int, newBookmarkId: Int?) -> Observable { - guard let index = currentState.listItems.firstIndex(where: { $0.id == id }) else { - return .empty() - } - - guard currentState.listItems[index].bookmarkId != newBookmarkId else { - return .empty() - } - - return .just(.updateBookmarkId(id: id, newBookmarkId: newBookmarkId)) - } - - func handleSortOptionSelected(sort: SortType) -> Observable { - return .concat([ - .just(.setSort(sort.sortParameter)), - .just(.initPage) - ]) - .concat(Observable.deferred { [weak self] in - guard let self = self else { return .empty() } - return self.fetchList(sort: self.currentState.sort, startLevel: currentState.startLevel, endLevel: currentState.endLevel) - }) - } - - func handleFilterOptionSelected(startLevel: Int?, endLevel: Int?) -> Observable { - return .concat([ - .just(.setFilter(start: startLevel, end: endLevel)), - .just(.initPage) - ]) - .concat(Observable.deferred { [weak self] in - guard let self = self else { return .empty() } - return self.fetchList(sort: self.currentState.sort, startLevel: startLevel, endLevel: endLevel) - }) - } - - func handleUndoLastDeletedBookmark() -> Observable { - guard let lastDeleted = currentState.lastDeletedBookmark else { return .empty() } - - return setBookmarkUseCase.execute( - bookmarkId: lastDeleted.id, - isBookmark: .set(lastDeleted.type) - ) - .flatMap { newBookmarkId -> Observable in - let lastItem = Mutation.setLastDeletedBookmark(nil) - - let event: UIEvent = .add(lastDeleted) - let eventMutation = Mutation.setEvent(event) - - let updateMutation = Mutation.updateBookmarkId(id: lastDeleted.id, newBookmarkId: newBookmarkId) - return .from([lastItem, updateMutation, eventMutation]) - } - .catch { _ in - .just(.navigatTo(.bookmarkError)) - } - } - - func handleItemFilterOptionSelected(results: [(String, String)]) -> Observable { - let criteria = parseItemFilterResultUseCase.execute(results: results) - return .concat([ - .just(.setJobId(criteria.jobIds)), - .just(.setFilter(start: criteria.startLevel, end: criteria.endLevel)), - .just(.setCategoryId(criteria.categoryIds)), - .just(.initPage) - ]) - .concat(Observable.deferred { [weak self] in - guard let self = self else { return .empty() } - return self.fetchList(sort: self.currentState.sort, startLevel: self.currentState.startLevel, endLevel: self.currentState.endLevel) - }) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListView.swift deleted file mode 100644 index d32a7174..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListView.swift +++ /dev/null @@ -1,24 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem - -final class DictionaryListView: BaseListView { - // MARK: - Init - init(isFilterHidden: Bool) { - let sortButton = BaseListView.makeSortButton(title: "가나다 순", tintColor: .neutral900) - let filterButton = BaseListView.makeFilterButton(title: "필터", tintColor: .neutral900) - let emptyView = DataEmptyView(type: .dictionary) - - super.init( - editButton: nil, - sortButton: sortButton, - filterButton: filterButton, - emptyView: emptyView, - isFilterHidden: isFilterHidden - ) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { fatalError() } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift deleted file mode 100644 index c89a9695..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryList/DictionaryListViewController.swift +++ /dev/null @@ -1,420 +0,0 @@ -import AuthFeatureInterface -import BaseFeature -import BookmarkFeatureInterface -import DictionaryFeatureInterface -import DomainInterface -import ReactorKit -import RxCocoa -import RxSwift -import UIKit - -public final class DictionaryListViewController: BaseViewController, View { - public typealias Reactor = DictionaryListReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - private let itemFilterFactory: ItemFilterBottomSheetFactory - private let monsterFilterFactory: MonsterFilterBottomSheetFactory - private let bookmarkModalFactory: BookmarkModalFactory - private let sortedFactory: SortedBottomSheetFactory - private let detailFactory: DictionaryDetailFactory - private let loginFactory: LoginFactory - - private var selectedSortIndex = 0 - public let itemCountRelay = PublishRelay() - private let bookmarkChangeRelay = PublishRelay<(id: Int, newBookmarkId: Int?)>() - private var loginRelay = PublishRelay() - private var lastPagingTime: Date = .distantPast - - // MARK: - Components - private var mainView: DictionaryListView - - public init( - reactor: DictionaryListReactor, - itemFilterFactory: ItemFilterBottomSheetFactory, - monsterFilterFactory: MonsterFilterBottomSheetFactory, - sortedFactory: SortedBottomSheetFactory, - bookmarkModalFactory: BookmarkModalFactory, - detailFactory: DictionaryDetailFactory, loginFactory: LoginFactory - ) { - self.itemFilterFactory = itemFilterFactory - self.monsterFilterFactory = monsterFilterFactory - self.sortedFactory = sortedFactory - self.bookmarkModalFactory = bookmarkModalFactory - self.detailFactory = detailFactory - self.loginFactory = loginFactory - self.mainView = DictionaryListView(isFilterHidden: reactor.currentState.type.isSortHidden) - super.init() - self.reactor = reactor - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override public func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension DictionaryListViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide) - make.horizontalEdges.bottom.equalToSuperview() - } - } - - func configureUI() { - mainView.listCollectionView.collectionViewLayout = createListLayout() - mainView.listCollectionView.delegate = self - mainView.listCollectionView.dataSource = self - mainView.listCollectionView.register( - DictionaryListCell.self, - forCellWithReuseIdentifier: DictionaryListCell.identifier - ) - } - - func createListLayout() -> UICollectionViewLayout { - guard let isHidden = reactor?.currentState.type.isSortHidden else { return UICollectionViewLayout() } - let layoutFactory = LayoutFactory() - let layout = CompositionalLayoutBuilder() - .section { _ in layoutFactory.getDictionaryListLayout(isFilterHidden: isHidden) } - .build() - layout.register( - Neutral300DividerView.self, - forDecorationViewOfKind: Neutral300DividerView.identifier - ) - return layout - } -} - -// MARK: - Bind -extension DictionaryListViewController { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - mainView.sortButton.rx.tap - .map { Reactor.Action.sortButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.filterButton.rx.tap - .map { Reactor.Action.filterButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - bindItemCount(reactor: reactor) - bindLifecycle(reactor: reactor) - bindRoute(reactor: reactor) - bindTypeChanges(reactor: reactor) - bindBookmarkChange() - bindListItems() - bindUIEvents(reactor: reactor) - } - - // MARK: - Sub-binds - - private func bindItemCount(reactor: Reactor) { - reactor.state - .map { $0.totalCounts } - .distinctUntilChanged() - .bind(to: itemCountRelay) - .disposed(by: disposeBag) - } - - private func bindLifecycle(reactor: Reactor) { - rx.viewWillAppear - .map { _ in Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - private func bindRoute(reactor: Reactor) { - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe(onNext: { owner, route in - switch route { - case .sort(let type): - let viewController = owner.sortedFactory.make( - sortedOptions: type.bookmarkSortedFilter, - selectedIndex: owner.selectedSortIndex - ) { [weak self, weak reactor] index in - guard let self, let reactor else { return } - self.selectedSortIndex = index - let selectedFilter = reactor.currentState.type.bookmarkSortedFilter[index] - reactor.action.onNext(.sortOptionSelected(selectedFilter)) - self.mainView.selectSort(selectedType: selectedFilter) - } - owner.tabBarController?.presentModal(viewController) - case .filter(let type): - switch type { - case .item: - let viewController = owner.itemFilterFactory.make { [weak self, weak reactor] results in - guard let self, let reactor else { return } - reactor.action.onNext(.itemFilterOptionSelected(results)) - - if results.isEmpty { - self.mainView.resetFilter() - } else { - self.mainView.selectFilter() - } - } - owner.present(viewController, animated: true) - case .monster: - let viewController = owner.monsterFilterFactory.make( - startLevel: reactor.currentState.startLevel ?? 0, - endLevel: reactor.currentState.endLevel ?? 200 - ) { [weak self, weak reactor] startLevel, endLevel in - self?.mainView.selectFilter() - reactor?.action.onNext(.filterOptionSelected(startLevel: startLevel, endLevel: endLevel)) - } - owner.tabBarController?.presentModal(viewController) - default: - break - } - case .bookmarkError: - ToastFactory.createToast(message: "북마크 요청에 실패했어요. 다시 시도해주세요.") - default: - break - } - }) - .disposed(by: disposeBag) - } - - private func bindTypeChanges(reactor: Reactor) { - reactor.state - .map(\.type) - .distinctUntilChanged() - .withUnretained(self) - .bind(onNext: { owner, type in - owner.mainView.updateFilter(sortType: type.sortedFilter.first) - }) - .disposed(by: disposeBag) - } - - private func bindBookmarkChange() { - bookmarkChangeRelay - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind(onNext: { owner, bookmarkResult in - let (id, newBookmarkId) = bookmarkResult - owner.reactor?.action.onNext(.updateBookmark(id: id, newBookmarkId: newBookmarkId)) - }) - .disposed(by: disposeBag) - } - - private func bindListItems() { - reactor?.state.map(\.listItems) - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind { owner, items in - owner.updateCollectionView(items: items) - } - .disposed(by: disposeBag) - } - - private func bindUIEvents(reactor: Reactor) { - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$uiEvent) } - .withUnretained(self) - .subscribe(onNext: { owner, event in - switch event { - case .add(let item): - owner.presentAddSnackBar(item: item) - case .delete(let item): - owner.presentDeleteSnackBar(item: item) - case .login: - owner.presentLoginGuide() - default: - break - } - }) - .disposed(by: disposeBag) - } - - private func presentAddSnackBar(item: DictionaryMainItemResponse) { - SnackBarFactory.createSnackBar( - type: .normal, - imageUrl: item.imageUrl, - imageBackgroundColor: item.type.backgroundColor, - text: "아이템을 북마크에 추가했어요.", - buttonText: "컬렉션 추가", - buttonAction: { [weak self] in - self?.reactor?.state.map(\.listItems) - .compactMap { list in - list.first(where: { $0.id == item.id })?.bookmarkId - } - .take(1) - .observe(on: MainScheduler.instance) - .subscribe(onNext: { [weak self] bookmarkId in - guard let self else { return } - let vc = self.bookmarkModalFactory.make(bookmarkIds: [bookmarkId]) { isAdd in - if isAdd { - ToastFactory.createToast( - message: "컬렉션에 추가되었어요. 북마크 탭에서 확인 할 수 있어요." - ) - } - } - vc.modalPresentationStyle = .pageSheet - if let sheet = vc.sheetPresentationController { - sheet.detents = [.medium(), .large()] - sheet.prefersGrabberVisible = true - sheet.preferredCornerRadius = 16 - } - self.present(vc, animated: true) - }) - .disposed(by: self?.disposeBag ?? DisposeBag()) - } - ) - } - - private func presentDeleteSnackBar(item: DictionaryMainItemResponse) { - SnackBarFactory.createSnackBar( - type: .delete, - imageUrl: item.imageUrl, - imageBackgroundColor: item.type.backgroundColor, - text: "아이템을 북마크에서 삭제했어요.", - buttonText: "되돌리기", - buttonAction: { [weak self] in - self?.reactor?.action.onNext(.undoLastDeletedBookmark) - } - ) - } - - private func presentLoginGuide() { - GuideAlertFactory.show( - mainText: "북마크를 하려면 로그인이 필요해요.", - ctaText: "로그인 하기", - cancelText: "취소", - ctaAction: { [weak self] in - guard let self else { return } - let vc = self.loginFactory.make(exitRoute: .pop) - self.navigationController?.pushViewController(vc, animated: true) - }, - cancelAction: nil - ) - } - - private func updateCollectionView(items: [DictionaryMainItemResponse]) { - let collectionView = mainView.listCollectionView - mainView.checkEmptyData(isEmpty: items.isEmpty) - - guard let reactor = reactor else { return } - if reactor.currentState.currentPage == 0, !reactor.currentState.isBookmarkUpdateOnly { - collectionView.reloadData() - } else { - let startIndex = collectionView.numberOfItems(inSection: 0) - let endIndex = items.count - if endIndex > startIndex { - let indexPaths = (startIndex ..< endIndex).map { IndexPath(item: $0, section: 0) } - collectionView.performBatchUpdates { - collectionView.insertItems(at: indexPaths) - } - } - - for cell in collectionView.visibleCells { - if let indexPath = collectionView.indexPath(for: cell), - indexPath.item < items.count, - let cell = cell as? DictionaryListCell { - let item = items[indexPath.item] - cell.updateBookmarkState(isBookmarked: item.bookmarkId != nil) - } - } - } - } -} - -// MARK: - Delegate -extension DictionaryListViewController: UICollectionViewDelegate, UICollectionViewDataSource { - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - guard let state = reactor?.currentState else { return 0 } - return state.listItems.count - } - - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let state = reactor?.currentState, - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: DictionaryListCell.identifier, for: indexPath) as? DictionaryListCell else { return UICollectionViewCell() } - let item = state.listItems[indexPath.row] - let subText: String? = [.item, .monster, .quest].contains(item.type) ? item.level.map { "Lv. \($0)" } : nil - - cell.inject( - type: .bookmark, - input: DictionaryListCell.Input( - type: item.type, - mainText: item.name, - subText: subText, - imageUrl: item.imageUrl ?? "", - isBookmarked: item.bookmarkId != nil - ), - indexPath: indexPath, - collectionView: collectionView, - isMap: item.type == .map, - onBookmarkTapped: { [weak self] in - guard let self else { return } - guard self.reactor?.currentState.isLogin == true else { - self.reactor?.action.onNext(.showLogin) - return - } - self.reactor?.action.onNext(.toggleBookmark(id: item.id)) - } - ) - - return cell - } - - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - guard let reactor = reactor else { return } - let item: DictionaryMainItemResponse - - item = reactor.currentState.listItems[indexPath.item] - let viewController: UIViewController - - switch reactor.currentState.type { - case .total: - guard let type = item.type.toDictionaryType else { return } - viewController = detailFactory.make(type: type, id: item.id, bookmarkRelay: bookmarkChangeRelay, loginRelay: loginRelay) - default: - // 단일 타입일 경우 리액터 타입에 따라 처리 - viewController = detailFactory.make( - type: reactor.currentState.type, id: item.id, bookmarkRelay: bookmarkChangeRelay, loginRelay: loginRelay - ) - } - navigationController?.pushViewController(viewController, animated: true) - } - - public func scrollViewDidScroll(_ scrollView: UIScrollView) { - let now = Date() - guard now.timeIntervalSince(lastPagingTime) > 0.5 else { return } - - let offsetY = scrollView.contentOffset.y - let contentHeight = scrollView.contentSize.height - let height = scrollView.frame.size.height - - if offsetY > contentHeight - height - 100 { - lastPagingTime = now - reactor?.action.onNext(.setCurrentPage) - reactor?.action.onNext(.fetchList) - } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainReactor.swift deleted file mode 100644 index 49a8a7fa..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainReactor.swift +++ /dev/null @@ -1,82 +0,0 @@ -import ReactorKit - -import DomainInterface - -public final class DictionaryMainReactor: Reactor { - // MARK: - Reactor - public enum Route { - case none - case search - case notification - case login - } - - public enum Action { - case viewWillAppear - case searchButtonTapped - case notificationButtonTapped - case changeTab(Int) - } - - public enum Mutation { - case navigateTo(Route) - case setLogin(Bool) - case setCurrentTab(oldIndex: Int, newIndex: Int) - } - - public struct State { - @Pulse var route: Route = .none - let type = DictionaryMainViewType.main - var sections: [String] { - return type.pageTabList.map { $0.title } - } - var isLogin = false - var currentPageIndex = 0 - var oldPageIndex = 0 - } - - // MARK: - properties - public var initialState: State - var disposeBag = DisposeBag() - - private let fetchProfileUseCase: FetchProfileUseCase - - // MARK: - init - public init(fetchProfileUseCase: FetchProfileUseCase) { - self.initialState = State() - self.fetchProfileUseCase = fetchProfileUseCase - } - - // MARK: - Reactor Methods - public func mutate(action: Action) -> Observable { - switch action { - case .viewWillAppear: - return fetchProfileUseCase.execute() - .map { .setLogin($0 != nil) } - .catchAndReturn(.setLogin(false)) - case .searchButtonTapped: - return .just(.navigateTo(.search)) - case .notificationButtonTapped: - return .just(.navigateTo(currentState.isLogin ? .notification : .login)) - case let .changeTab(index): - let oldIndex = currentState.currentPageIndex - return .just(.setCurrentTab(oldIndex: oldIndex, newIndex: index)) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .navigateTo(let route): - newState.route = route - case let .setLogin(isLogin): - newState.isLogin = isLogin - case let .setCurrentTab(oldIndex, newIndex): - newState.oldPageIndex = oldIndex - newState.currentPageIndex = newIndex - } - - return newState - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainView.swift deleted file mode 100644 index f7feb203..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainView.swift +++ /dev/null @@ -1,97 +0,0 @@ -import UIKit - -import DesignSystem -import DictionaryFeatureInterface -import DomainInterface - -import SnapKit - -final class DictionaryMainView: UIView { - - enum Constant { - static let topMargin: CGFloat = 20 - static let pageTabHeight: CGFloat = 40 - static let bottomTabHeight: CGFloat = 64 - } - - // MARK: - Components - public let headerView = Header(style: .main, title: "도감") - - public let searchBar = SearchBar() - - public let tabCollectionView: UICollectionView = { - let layout = UICollectionViewLayout() - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) - collectionView.isScrollEnabled = false - return collectionView - }() - - public let pageViewController = UIPageViewController( - transitionStyle: .scroll, - navigationOrientation: .horizontal - ) - - // MARK: - Init - public init(type: DictionaryMainViewType) { - super.init(frame: .zero) - addViews(type: type) - setupConstraints(type: type) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension DictionaryMainView { - func addViews(type: DictionaryMainViewType) { - switch type { - case .search: - addSubview(searchBar) - default: - addSubview(headerView) - } - addSubview(tabCollectionView) - addSubview(pageViewController.view) - } - - func setupConstraints(type: DictionaryMainViewType) { - switch type { - case .search: - searchBar.snp.makeConstraints { make in - make.top.equalTo(safeAreaLayoutGuide) - make.horizontalEdges.equalToSuperview() - } - - tabCollectionView.snp.makeConstraints { make in - make.top.equalTo(searchBar.snp.bottom).offset(Constant.topMargin) - make.horizontalEdges.equalToSuperview() - make.height.equalTo(Constant.pageTabHeight) - } - - pageViewController.view.snp.makeConstraints { make in - make.top.equalTo(tabCollectionView.snp.bottom) - make.horizontalEdges.equalTo(safeAreaLayoutGuide) - make.bottom.equalToSuperview() - } - default: - headerView.snp.makeConstraints { make in - make.top.equalTo(safeAreaLayoutGuide) - make.horizontalEdges.equalToSuperview() - } - - tabCollectionView.snp.makeConstraints { make in - make.top.equalTo(headerView.snp.bottom).offset(Constant.topMargin) - make.horizontalEdges.equalToSuperview() - make.height.equalTo(Constant.pageTabHeight) - } - - pageViewController.view.snp.makeConstraints { make in - make.top.equalTo(tabCollectionView.snp.bottom) - make.horizontalEdges.equalTo(safeAreaLayoutGuide) - make.bottom.equalToSuperview().inset(Constant.bottomTabHeight) - } - } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainViewController.swift deleted file mode 100644 index c7abe68b..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainViewController.swift +++ /dev/null @@ -1,252 +0,0 @@ -import UIKit - -import AuthFeatureInterface -import BaseFeature -import DesignSystem -import DictionaryFeatureInterface -import DomainInterface - -import ReactorKit -import RxCocoa -import RxSwift - -public final class DictionaryMainViewController: BaseViewController, View, DictionaryTabControllable { - public typealias Reactor = DictionaryMainReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - private let initialIndex: Int - - private let searchFactory: DictionarySearchFactory - private let notificationFactory: DictionaryNotificationFactory - private let loginFactory: LoginFactory - - private var viewControllers: [UIViewController] - - private var mainView: DictionaryMainView - let underLineController = TabBarUnderlineController() - - public init( - initialIndex: Int = 0, - dictionaryMainListFactory: DictionaryMainListFactory, - searchFactory: DictionarySearchFactory, - notificationFactory: DictionaryNotificationFactory, - loginFactory: LoginFactory, - reactor: DictionaryMainReactor - ) { - let type = reactor.currentState.type - self.mainView = DictionaryMainView(type: type) - self.viewControllers = type.pageTabList.map { dictionaryMainListFactory.make(type: $0, listType: type, keyword: "") } - self.searchFactory = searchFactory - self.notificationFactory = notificationFactory - self.loginFactory = loginFactory - self.initialIndex = initialIndex - super.init() - self.reactor = reactor - } - - @available(*, unavailable) - @MainActor required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -public extension DictionaryMainViewController { - override func viewDidLoad() { - super.viewDidLoad() - addViews() - setupConstraints() - configureUI() - setInitialIndex() - DictionaryTabRegistry.register(controller: self) - } -} - -// MARK: - SetUp -private extension DictionaryMainViewController { - func addViews() { - addChild(mainView.pageViewController) - mainView.pageViewController.didMove(toParent: self) - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } - - func configureUI() { - mainView.pageViewController.delegate = self - mainView.pageViewController.dataSource = self - configureTabCollectionView() - } - - func configureTabCollectionView() { - mainView.tabCollectionView.collectionViewLayout = createTabLayout() - mainView.tabCollectionView.delegate = self - mainView.tabCollectionView.dataSource = self - mainView.tabCollectionView.register(PageTabbarCell.self, forCellWithReuseIdentifier: PageTabbarCell.identifier) - underLineController.configure(with: mainView.tabCollectionView) - } - - func createTabLayout() -> UICollectionViewLayout { - let layout = CompositionalLayoutBuilder() - .section { _ in LayoutFactory.getPageTabbarLayout(underLineController: underLineController) } - .build() - return layout - } - - func setInitialIndex() { - let indexPath = IndexPath(item: initialIndex, section: 0) - - mainView.pageViewController.setViewControllers( - [viewControllers[initialIndex]], - direction: .forward, - animated: false, - completion: nil - ) - - mainView.tabCollectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredHorizontally) - DispatchQueue.main.async { [weak self] in - self?.underLineController.setInitialIndicator() - } - } - - func moveToTab(oldIndex: Int, newIndex: Int) { - guard newIndex < viewControllers.count else { return } - let direction: UIPageViewController.NavigationDirection = newIndex > oldIndex ? .forward : .reverse - - mainView.pageViewController.setViewControllers( - [viewControllers[newIndex]], - direction: direction, - animated: true, - completion: nil - ) - - mainView.tabCollectionView.selectItem( - at: IndexPath(item: newIndex, section: 0), - animated: true, - scrollPosition: .centeredHorizontally - ) - - underLineController.animateIndicatorToSelectedItem() - } -} - -// MARK: - Bind -public extension DictionaryMainViewController { - func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .map { .viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.headerView.firstIconButton.rx.tap - .map { Reactor.Action.searchButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.headerView.secondIconButton.rx.tap - .map { Reactor.Action.notificationButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .observe(on: MainScheduler.instance) - .withUnretained(self) - .subscribe { owner, route in - switch route { - case .search: - let controller = owner.searchFactory.make() - owner.navigationController?.pushViewController(controller, animated: true) - case .notification: - let controller = owner.notificationFactory.make() - owner.navigationController?.pushViewController(controller, animated: true) - case .login: - let controller = owner.loginFactory.make(exitRoute: .pop, onLoginCompleted: nil) - owner.navigationController?.pushViewController(controller, animated: true) - default: - break - } - } - .disposed(by: disposeBag) - - reactor.state - .map(\.currentPageIndex) - .distinctUntilChanged() - .skip(1) - .withUnretained(self) - .subscribe(onNext: { owner, newIndex in - let oldIndex = reactor.currentState.oldPageIndex - owner.moveToTab(oldIndex: oldIndex, newIndex: newIndex) - }) - .disposed(by: disposeBag) - } -} - -public extension DictionaryMainViewController { - func changeTab(index: Int) { - reactor?.action.onNext(.changeTab(index)) - } -} - -// MARK: - UIPageViewController DataSource & Delegate -extension DictionaryMainViewController: UIPageViewControllerDataSource, UIPageViewControllerDelegate { - public func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { - guard let index = viewControllers.firstIndex(of: viewController) else { return nil } - let previousIndex = index - 1 - return previousIndex >= 0 ? viewControllers[previousIndex] : nil - } - - public func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { - guard let index = viewControllers.firstIndex(of: viewController) else { return nil } - let nextIndex = index + 1 - return nextIndex < viewControllers.count ? viewControllers[nextIndex] : nil - } - - public func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { - if completed, let visibleViewController = pageViewController.viewControllers?.first, - let newIndex = viewControllers.firstIndex(of: visibleViewController) { - reactor?.action.onNext(.changeTab(newIndex)) - } - } -} - -// MARK: - UICollectionView DataSource & Delegate -extension DictionaryMainViewController: UICollectionViewDataSource, UICollectionViewDelegate { - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - guard let reactor = reactor else { return 0 } - return reactor.currentState.sections.count - } - - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let reactor = reactor else { return UICollectionViewCell() } - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PageTabbarCell.identifier, for: indexPath) as? PageTabbarCell else { - return UICollectionViewCell() - } - let title = reactor.currentState.sections[indexPath.row] - cell.inject(title: title) - cell.isSelected = indexPath.row == reactor.currentState.currentPageIndex - return cell - } - - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - let newIndex = indexPath.row - guard let oldIndex = reactor?.currentState.currentPageIndex else { return } - guard newIndex != oldIndex else { return } - - reactor?.action.onNext(.changeTab(newIndex)) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainViewFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainViewFactoryImpl.swift deleted file mode 100644 index 798c5e6f..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryMain/DictionaryMainViewFactoryImpl.swift +++ /dev/null @@ -1,28 +0,0 @@ -import AuthFeatureInterface -import BaseFeature -import DictionaryFeatureInterface -import DomainInterface - -public final class DictionaryMainViewFactoryImpl: DictionaryMainViewFactory { - private let dictionaryMainListFactory: DictionaryMainListFactory - private let searchFactory: DictionarySearchFactory - private let notificationFactory: DictionaryNotificationFactory - private let loginFactory: LoginFactory - private let fetchProfileUseCase: FetchProfileUseCase - - public init(dictionaryMainListFactory: DictionaryMainListFactory, searchFactory: DictionarySearchFactory, notificationFactory: DictionaryNotificationFactory, loginFactory: LoginFactory, fetchProfileUseCase: FetchProfileUseCase) { - self.dictionaryMainListFactory = dictionaryMainListFactory - self.searchFactory = searchFactory - self.notificationFactory = notificationFactory - self.loginFactory = loginFactory - self.fetchProfileUseCase = fetchProfileUseCase - } - - public func make() -> BaseViewController { - let reactor = DictionaryMainReactor(fetchProfileUseCase: fetchProfileUseCase) - let viewController = DictionaryMainViewController(dictionaryMainListFactory: dictionaryMainListFactory, searchFactory: searchFactory, notificationFactory: notificationFactory, loginFactory: loginFactory, reactor: reactor, ) - viewController.isBottomTabbarHidden = false - viewController.reactor = reactor - return viewController - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationFactoryImpl.swift deleted file mode 100644 index 2543eac8..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationFactoryImpl.swift +++ /dev/null @@ -1,34 +0,0 @@ -import BaseFeature -import DictionaryFeatureInterface -import DomainInterface -import MyPageFeatureInterface - -public final class DictionaryNotificationFactoryImpl: DictionaryNotificationFactory { - private let notificationSettingFactory: NotificationSettingFactory - - private let fetchAllAlarmUseCase: FetchAllAlarmUseCase - private let fetchProfileUseCase: FetchProfileUseCase - private let checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase - private let setReadUseCase: SetReadUseCase - - public init( - notificationSettingFactory: NotificationSettingFactory, - fetchAllAlarmUseCase: FetchAllAlarmUseCase, - fetchProfileUseCase: FetchProfileUseCase, - checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase, - setReadUseCase: SetReadUseCase - ) { - self.notificationSettingFactory = notificationSettingFactory - self.fetchAllAlarmUseCase = fetchAllAlarmUseCase - self.fetchProfileUseCase = fetchProfileUseCase - self.checkNotificationPermissionUseCase = checkNotificationPermissionUseCase - self.setReadUseCase = setReadUseCase - } - - public func make() -> BaseViewController { - let reactor = DictionaryNotificationReactor(fetchAllAlarmUseCase: fetchAllAlarmUseCase, fetchProfileUseCase: fetchProfileUseCase, checkNotificationPermissionUseCase: checkNotificationPermissionUseCase, setReadUseCase: setReadUseCase) - let viewController = DictionaryNotificationViewController(notificationSettingFactory: notificationSettingFactory) - viewController.reactor = reactor - return viewController - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift deleted file mode 100644 index 20e8e42c..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationReactor.swift +++ /dev/null @@ -1,143 +0,0 @@ -import DomainInterface -import ReactorKit -import RxSwift - -public final class DictionaryNotificationReactor: Reactor { - // MARK: - Reactor - public enum Route { - case none - case dismiss - case setting - case notification(url: String) - } - - public enum Action { - case viewWillAppear - case loadMore - case backButtonTapped - case settingButtonTapped - case notificationTapped(index: Int) - } - - public enum Mutation { - case setNotifications([AllAlarmResponse], hasMore: Bool, reset: Bool) - case setLoading(Bool) - case setProfile(MyPageResponse?) - case navigateTo(Route) - case setPermission(Bool) - case checkAlarm(link: String) - } - - public struct State { - @Pulse var route: Route = .none - var notifications: [AllAlarmResponse] = [] - var profile: MyPageResponse? - var hasMore: Bool = false - var isLoading: Bool = false - var permission = false - } - - // MARK: - Properties - public var initialState: State - private let disposeBag = DisposeBag() - private let fetchAllAlarmUseCase: FetchAllAlarmUseCase - private let fetchProfileUseCase: FetchProfileUseCase - private let checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase - private let setReadUseCase: SetReadUseCase - - // MARK: - Init - public init(fetchAllAlarmUseCase: FetchAllAlarmUseCase, fetchProfileUseCase: FetchProfileUseCase, checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase, setReadUseCase: SetReadUseCase) { - self.initialState = State() - self.fetchAllAlarmUseCase = fetchAllAlarmUseCase - self.fetchProfileUseCase = fetchProfileUseCase - self.checkNotificationPermissionUseCase = checkNotificationPermissionUseCase - self.setReadUseCase = setReadUseCase - } - - // MARK: - Mutate - public func mutate(action: Action) -> Observable { - switch action { - case .viewWillAppear: - let profileStream: Observable = fetchProfileUseCase.execute() - .map { Mutation.setProfile($0) } - - let notificationStream: Observable = Observable.concat([ - Observable.just(.setLoading(true)), - fetchAllAlarmUseCase.execute(id: nil, pageSize: 20) - .map { paged in - Mutation.setNotifications(paged.items, hasMore: paged.hasMore, reset: true) - }, - Observable.just(.setLoading(false)) - ]) - - let permissionStream: Observable = checkNotificationPermissionUseCase.execute() - .asObservable() - .map { Mutation.setPermission($0) } - - return Observable.merge(profileStream, notificationStream, permissionStream) - - case .loadMore: - guard currentState.hasMore, !currentState.isLoading else { return .empty() } - let cursor = currentState.notifications.last?.id - - return Observable.concat([ - Observable.just(.setLoading(true)), - fetchAllAlarmUseCase.execute(id: cursor, pageSize: 20) - .map { paged in - Mutation.setNotifications(paged.items, hasMore: paged.hasMore, reset: false) - }, - Observable.just(.setLoading(false)) - ]) - - case .backButtonTapped: - return .just(.navigateTo(.dismiss)) - - case .settingButtonTapped: - return .just(.navigateTo(.setting)) - - case let .notificationTapped(index): - let notification = currentState.notifications[index] - - return setReadUseCase.execute(alarmLink: notification.link) - .andThen( - Observable.concat([ - .just(.checkAlarm(link: notification.link)), - .just(.navigateTo(.notification(url: notification.link))) - ]) - ) - } - } - - // MARK: - Reduce - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case let .setNotifications(newItems, hasMore, reset): - if reset { - newState.notifications = newItems - } else { - newState.notifications.append(contentsOf: newItems) - } - newState.hasMore = hasMore - - case let .setLoading(isLoading): - newState.isLoading = isLoading - - case let .setProfile(profile): - newState.profile = profile - - case let .navigateTo(route): - newState.route = route - - case let .setPermission(granted): - newState.permission = granted - case let .checkAlarm(link): - if let index = newState.notifications.firstIndex(where: { $0.link == link }) { - newState.notifications[index].alreadyRead = true - } - } - - return newState - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationView.swift deleted file mode 100644 index 49602afe..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationView.swift +++ /dev/null @@ -1,91 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -public final class DictionaryNotificationView: UIView { - // MARK: - Type - enum Constant { - static let emptyViewTopMargin: CGFloat = 40 - static let titleTopMargin: CGFloat = 20 - static let titleBottomMargin: CGFloat = 18 - static let titleHorizontalInset: CGFloat = 16 - static let titleHeight: CGFloat = 34 - static let titleWidth: CGFloat = 42 - } - - // MARK: - Components - private let emptyView = NotificationEmptyView() - public let header = NavigationBar(type: .withString("설정")) - public let titleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .h_xxxl_sb, text: "알림", alignment: .left) - return label - }() - - public let notificationCollectionView: UICollectionView = { - let layout = UICollectionViewLayout() - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) - return collectionView - }() - - // MARK: - Init - init() { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension DictionaryNotificationView { - func addViews() { - addSubview(emptyView) - - addSubview(header) - addSubview(titleLabel) - addSubview(notificationCollectionView) - } - - func setupConstraints() { - header.snp.makeConstraints { make in - make.top.equalToSuperview() - make.horizontalEdges.equalToSuperview() - } - - emptyView.snp.makeConstraints { make in - make.centerY.equalToSuperview().multipliedBy(0.315) - make.horizontalEdges.equalToSuperview() - } - - titleLabel.snp.makeConstraints { make in - make.top.equalTo(header.snp.bottom).offset(Constant.titleTopMargin) - make.horizontalEdges.equalToSuperview().inset(Constant.titleHorizontalInset) - } - - notificationCollectionView.snp.makeConstraints { make in - make.top.equalTo(titleLabel.snp.bottom).offset(Constant.titleBottomMargin) - make.horizontalEdges.bottom.equalToSuperview() - } - } - - func configureUI() { - backgroundColor = .clearMLS - header.rightButton.isHidden = true - } -} - -public extension DictionaryNotificationView { - func setEmpty(hasPermission: Bool) { - emptyView.isHidden = hasPermission - titleLabel.isHidden = !hasPermission - notificationCollectionView.isHidden = !hasPermission - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationViewController.swift deleted file mode 100644 index 0e1538d7..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/DictionaryNotificationViewController.swift +++ /dev/null @@ -1,180 +0,0 @@ -import MyPageFeatureInterface -import UIKit - -import BaseFeature -import DictionaryFeatureInterface - -import ReactorKit -import RxCocoa -import RxSwift -import SnapKit - -public final class DictionaryNotificationViewController: BaseViewController, View { - public typealias Reactor = DictionaryNotificationReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - private var lastPagingTime: Date = .distantPast - - private var notificationSettingFactory: NotificationSettingFactory - - // MARK: - Components - private let mainView = DictionaryNotificationView() - - public init(notificationSettingFactory: NotificationSettingFactory) { - self.notificationSettingFactory = notificationSettingFactory - super.init() - } - - @available(*, unavailable) - @MainActor required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -public extension DictionaryNotificationViewController { - override func viewDidLoad() { - super.viewDidLoad() - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension DictionaryNotificationViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.top.horizontalEdges.equalTo(view.safeAreaLayoutGuide) - make.bottom.equalToSuperview() - } - } - - func configureUI() { - isBottomTabbarHidden = true - - mainView.notificationCollectionView.delegate = self - mainView.notificationCollectionView.dataSource = self - mainView.notificationCollectionView.register(DictionaryNotificationCell.self, forCellWithReuseIdentifier: DictionaryNotificationCell.identifier) - mainView.notificationCollectionView.collectionViewLayout = createTabLayout() - } - - func createTabLayout() -> UICollectionViewLayout { - let layout = CompositionalLayoutBuilder() - .section { _ in LayoutFactory.getNotificationLayout() } - .build() - return layout - } -} - -// MARK: - Bind -public extension DictionaryNotificationViewController { - func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .map { _ in Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.header.leftButton.rx.tap - .map { Reactor.Action.backButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.header.boldTextButton.rx.tap - .map { Reactor.Action.settingButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, route in - switch route { - case .dismiss: - owner.navigationController?.popViewController(animated: true) - case .setting: - guard let reactor = owner.reactor, - let profile = reactor.currentState.profile else { return } - let viewController = owner.notificationSettingFactory.make(isAgreeEventNotification: profile.eventAgreement, isAgreeNoticeNotification: profile.noticeAgreement, isAgreePatchNoteNotification: profile.patchNoteAgreement) - owner.navigationController?.pushViewController(viewController, animated: true) - case let .notification(url): - if let webViewController = WebViewController.make(urlString: url) { - owner.present(webViewController, animated: true) - } - default: - break - } - } - .disposed(by: disposeBag) - - reactor.state.map { $0.notifications } - .distinctUntilChanged() - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, _ in - owner.mainView.notificationCollectionView.reloadData() - } - .disposed(by: disposeBag) - - reactor.state - .map { $0.permission } - .distinctUntilChanged() - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, permission in - owner.mainView.setEmpty(hasPermission: permission) - } - .disposed(by: disposeBag) - } -} - -// MARK: - Delegate -extension DictionaryNotificationViewController: UICollectionViewDelegate, UICollectionViewDataSource { - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - guard let reactor = reactor else { return 0 } - return reactor.currentState.notifications.count - } - - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let reactor = reactor else { return UICollectionViewCell() } - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: DictionaryNotificationCell.identifier, for: indexPath) as? DictionaryNotificationCell else { return UICollectionViewCell() } - let item = reactor.currentState.notifications[indexPath.row] - cell.inject(input: DictionaryNotificationCell.Input(title: item.title, subTitle: item.date.toDisplayDateString(), isChecked: item.alreadyRead)) - return cell - } - - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - guard let reactor = reactor else { return } - reactor.action.onNext(.notificationTapped(index: indexPath.row)) - } - - public func scrollViewDidScroll(_ scrollView: UIScrollView) { - let now = Date() - guard now.timeIntervalSince(lastPagingTime) > 0.5 else { return } - - guard let reactor = reactor else { return } - - let offsetY = scrollView.contentOffset.y - let contentHeight = scrollView.contentSize.height - let frameHeight = scrollView.frame.size.height - - if offsetY > contentHeight - frameHeight - 100 { - reactor.action.onNext(.loadMore) - } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/NotificationEmptyView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/NotificationEmptyView.swift deleted file mode 100644 index 660383eb..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionaryNotification/NotificationEmptyView.swift +++ /dev/null @@ -1,104 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -final class NotificationEmptyView: UIView { - // MARK: - Type - enum Constant { - static let imageViewSize: CGFloat = 220 - static let spacing: CGFloat = 12 - } - - // MARK: - Components - private let imageView: UIImageView = { - let view = UIImageView() - view.image = DesignSystemAsset.image(named: "settingsHint") - return view - }() - - private let titleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .h_xl_b, text: "알림이 꺼져있어요", alignment: .center) - return label - }() - - private let subLabel: UILabel = { - let label = UILabel() - - let fullText = "오른쪽 상단 설정을 눌러 알림을 켜면\n업데이트, 이벤트 소식을 바로 받아볼 수 있어요!" - let keyword = "설정" - - guard let baseFont = UIFont.cp_s_r, - let specialFont = UIFont.cp_s_r else { return UILabel() } - let specialColor = UIColor.textColor - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.alignment = .center - paragraphStyle.maximumLineHeight = (baseFont.lineHeight) * 1.17 - - let attributedText = NSMutableAttributedString( - string: fullText, - attributes: [ - .font: baseFont, - .foregroundColor: UIColor.neutral600, - .paragraphStyle: paragraphStyle - ] - ) - - if let range = fullText.range(of: keyword) { - let nsRange = NSRange(range, in: fullText) - attributedText.addAttributes([ -// .font: specialFont, - .foregroundColor: specialColor - ], range: nsRange) - } - - label.attributedText = attributedText - label.numberOfLines = 0 - return label - }() - - // MARK: - Init - init() { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension NotificationEmptyView { - func addViews() { - addSubview(imageView) - addSubview(titleLabel) - addSubview(subLabel) - } - - func setupConstraints() { - imageView.snp.makeConstraints { make in - make.top.centerX.equalToSuperview() - make.size.equalTo(Constant.imageViewSize) - } - - titleLabel.snp.makeConstraints { make in - make.top.equalTo(imageView.snp.bottom).offset(Constant.spacing) - make.centerX.equalToSuperview() - } - - subLabel.snp.makeConstraints { make in - make.top.equalTo(titleLabel.snp.bottom).offset(Constant.spacing) - make.centerX.equalToSuperview() - } - } - - func configureUI() { - backgroundColor = .clearMLS - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchFactoryImpl.swift deleted file mode 100644 index 10857c85..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchFactoryImpl.swift +++ /dev/null @@ -1,24 +0,0 @@ -import BaseFeature -import DictionaryFeatureInterface -import DomainInterface - -public final class DictionarySearchFactoryImpl: DictionarySearchFactory { - private let recentSearchRemoveUseCase: RecentSearchRemoveUseCase - private let recentSearchAddUseCase: RecentSearchAddUseCase - private let recentSearchFetchUseCase: RecentSearchFetchUseCase - private let searchResultFactory: DictionarySearchResultFactory - - public init(recentSearchRemoveUseCase: RecentSearchRemoveUseCase, recentSearchAddUseCase: RecentSearchAddUseCase, searchResultFactory: DictionarySearchResultFactory, recentSearchFetchUseCase: RecentSearchFetchUseCase) { - self.recentSearchRemoveUseCase = recentSearchRemoveUseCase - self.recentSearchAddUseCase = recentSearchAddUseCase - self.recentSearchFetchUseCase = recentSearchFetchUseCase - self.searchResultFactory = searchResultFactory - } - - public func make() -> BaseViewController { - let reactor = DictionarySearchReactor(recentSearchAddUseCase: recentSearchAddUseCase, recentSearchRemoveUseCase: recentSearchRemoveUseCase, recentSearchFetchUseCase: recentSearchFetchUseCase) - let viewController = DictionarySearchViewController(searchResultFactory: searchResultFactory) - viewController.reactor = reactor - return viewController - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchReactor.swift deleted file mode 100644 index 98e3b950..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchReactor.swift +++ /dev/null @@ -1,135 +0,0 @@ -import DomainInterface -import Foundation -import ReactorKit - -struct PopularItem { - let rank: Int - let name: String -} - -public final class DictionarySearchReactor: Reactor { - // MARK: - Reactor - public enum Route { - case none - case dismiss - case search(String) - } - - public enum Action { - case viewWillAppear - case backButtonTapped - case searchButtonTapped(String) - case cancelRecentButtonTapped(String) - case deleteAllButtonTapped - case recentButtonTapped(String) - } - - public enum Mutation { - case navigateTo(Route) - case deleteItem(String) - case deleteAllItems - case addRecentItem(String) - case setRecentList([String]) - } - - public struct State { - @Pulse var route: Route - var recentResult: [String] - let popularResult: [PopularItem] - } - - public let recentSearchAddUseCase: RecentSearchAddUseCase - public let recentSearchRemoveUseCase: RecentSearchRemoveUseCase - public let recentSearchFetchUseCase: RecentSearchFetchUseCase - - // MARK: - properties - public var initialState: State - var disposeBag = DisposeBag() - - // MARK: - init - public init(recentSearchAddUseCase: RecentSearchAddUseCase, recentSearchRemoveUseCase: RecentSearchRemoveUseCase, recentSearchFetchUseCase: RecentSearchFetchUseCase) { - // TODO: 인기 검색어 추후 개발 - let items = [ - PopularItem(rank: 1, name: "주니어 예티"), - PopularItem(rank: 2, name: "주니어 페페"), - PopularItem(rank: 3, name: "주니어 네키"), - PopularItem(rank: 4, name: "주니어 버섯"), - PopularItem(rank: 5, name: "주니어 달팽이"), - PopularItem(rank: 6, name: "주니어 유림"), - PopularItem(rank: 7, name: "주니어 채령"), - PopularItem(rank: 8, name: "주니어 진훈"), - PopularItem(rank: 9, name: "주니어 여송"), - PopularItem(rank: 10, name: "주니어 명범"), - PopularItem(rank: 11, name: "주니어 재혁") - ] - let numberOfRows = Int(ceil(Double(items.count) / Double(2))) - var grid = [[PopularItem?]](repeating: [PopularItem?](repeating: nil, count: 2), count: numberOfRows) - - for (index, item) in items.enumerated() { - let row = index % numberOfRows - let column = index / numberOfRows - grid[row][column] = item - } - - let newItems = grid.flatMap { $0.compactMap { $0 } } - - self.recentSearchAddUseCase = recentSearchAddUseCase - self.recentSearchRemoveUseCase = recentSearchRemoveUseCase - self.recentSearchFetchUseCase = recentSearchFetchUseCase - - let savedRecentResult: [String] = [] - - self.initialState = State( - route: .none, - recentResult: savedRecentResult, - popularResult: newItems - ) - } - - // MARK: - Reactor Methods - public func mutate(action: Action) -> Observable { - switch action { - case .viewWillAppear: - return recentSearchFetchUseCase.fetch().map { Mutation.setRecentList($0) } - case .backButtonTapped: - return Observable.just(.navigateTo(.dismiss)) - case .searchButtonTapped(let keyword): - return recentSearchAddUseCase.add(keyword: keyword) - .andThen( - currentState.recentResult.contains(keyword) - ? .just(.navigateTo(.search(keyword))) - : .concat([ - .just(.addRecentItem(keyword)), - .just(.navigateTo(.search(keyword))) - ]) - ) - case .cancelRecentButtonTapped(let keyword): - return recentSearchRemoveUseCase.remove(keyword: keyword) - .andThen(.just(.deleteItem(keyword))) - case .recentButtonTapped(let keyword): - return Observable.just(.navigateTo(.search(keyword))) - case .deleteAllButtonTapped: - return recentSearchRemoveUseCase.removeAll() - .andThen(.just(.deleteAllItems)) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .setRecentList(let list): - newState.recentResult = list - case .navigateTo(let route): - newState.route = route - case .addRecentItem(let name): - newState.recentResult.insert(name, at: 0) // 맨 앞에 최근 검색어 추가 - case .deleteItem(let name): - newState.recentResult = state.recentResult.filter { $0 != name } - case .deleteAllItems: - newState.recentResult = [] - } - - return newState - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchView.swift deleted file mode 100644 index 2e2f3f29..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchView.swift +++ /dev/null @@ -1,78 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift -import SnapKit - -final class DictionarySearchView: UIView { - // MARK: - Type - enum Constant { - static let searchBarTopMargin: CGFloat = 12 - static let collectionViewTopMargin: CGFloat = 20 - static let horizontalMargin: CGFloat = 16 - static let collectionViewSpacing: CGFloat = 10 - } - - // MARK: - Properties - private let disposeBag = DisposeBag() - - // MARK: - Components - public let searchBar = SearchBar() - - public let searchCollectionView: UICollectionView = { - let layout = UICollectionViewLayout() - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) - return collectionView - }() - - // MARK: - Init - init() { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - setupKeyboard() - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -} - -// MARK: - SetUp -private extension DictionarySearchView { - func addViews() { - addSubview(searchBar) - addSubview(searchCollectionView) - } - - func setupConstraints() { - searchBar.snp.makeConstraints { make in - make.top.equalToSuperview().inset(Constant.searchBarTopMargin) - make.horizontalEdges.equalToSuperview() - } - - searchCollectionView.snp.makeConstraints { make in - make.top.equalTo(searchBar.snp.bottom).offset(Constant.collectionViewTopMargin) - make.horizontalEdges.bottom.equalToSuperview() - } - } - - func configureUI() { - backgroundColor = .clearMLS - } - - func setupKeyboard() { - let tapGesture = UITapGestureRecognizer() - tapGesture.cancelsTouchesInView = false - addGestureRecognizer(tapGesture) - - tapGesture.rx.event - .bind(onNext: { [weak self] _ in - self?.endEditing(true) - }) - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift deleted file mode 100644 index 9d826ca9..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/DictionarySearchViewController.swift +++ /dev/null @@ -1,278 +0,0 @@ -import DictionaryFeatureInterface -import UIKit - -import BaseFeature -import DesignSystem -import DomainInterface - -import ReactorKit -import RxCocoa -import RxSwift - -public final class DictionarySearchViewController: BaseViewController, View { - public typealias Reactor = DictionarySearchReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - private var searchResultFactory: DictionarySearchResultFactory - - private let chipTapRelay = PublishRelay() - private let chipCancelRelay = PublishRelay() - - // MARK: - Components - private let mainView = DictionarySearchView() - - public init(searchResultFactory: DictionarySearchResultFactory) { - self.searchResultFactory = searchResultFactory - super.init() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override public func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension DictionarySearchViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } - - func configureUI() { - isBottomTabbarHidden = true - - mainView.searchBar.searchDelegate = self - mainView.searchBar.textField.becomeFirstResponder() - - mainView.searchCollectionView.collectionViewLayout = createLayout() - mainView.searchCollectionView.delegate = self - mainView.searchCollectionView.dataSource = self - mainView.searchCollectionView.register(EmptyRecentCell.self, forCellWithReuseIdentifier: EmptyRecentCell.identifier) - mainView.searchCollectionView.register(TagChipCell.self, forCellWithReuseIdentifier: TagChipCell.identifier) - mainView.searchCollectionView.register(PopularResultCell.self, forCellWithReuseIdentifier: PopularResultCell.identifier) - mainView.searchCollectionView.register( - RecentSearchHeaderView.self, - forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, - withReuseIdentifier: RecentSearchHeaderView.identifier - ) - mainView.searchCollectionView.register( - PopularSearchHeaderView.self, - forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, - withReuseIdentifier: PopularSearchHeaderView.identifier - ) - } - - func createLayout() -> UICollectionViewLayout { - let layoutFactory = LayoutFactory() - - let layout = UICollectionViewCompositionalLayout { [weak self] sectionIndex, _ in - guard self != nil else { - return NSCollectionLayoutSection( - group: NSCollectionLayoutGroup.vertical( - layoutSize: .init(widthDimension: .fractionalWidth(1), heightDimension: .absolute(1)), - subitems: [] - ) - ) - } - - switch sectionIndex { - case 0: - return layoutFactory.getTagChipLayout().build() - case 1: - return layoutFactory.getDecorationSection().build() - case 2: - return layoutFactory.getPopularResultLayout().build() - default: - return nil - } - } - - layout.register(SearchDividerView.self, forDecorationViewOfKind: SearchDividerView.identifier) - return layout - } -} - -// MARK: - Bind -extension DictionarySearchViewController { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .map { Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.searchBar.backButton.rx.tap - .map { Reactor.Action.backButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.searchBar.searchButton.rx.tap - .withUnretained(self) - .map { $0.0.mainView.searchBar.textField.text ?? "" } - .map(Reactor.Action.searchButtonTapped) - .bind(to: reactor.action) - .disposed(by: disposeBag) - - chipTapRelay - .map { Reactor.Action.recentButtonTapped($0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - chipCancelRelay - .map { Reactor.Action.cancelRecentButtonTapped($0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - reactor.state.map { $0.recentResult } - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe(onNext: { owner, _ in - owner.mainView.searchCollectionView.reloadData() - }) - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .subscribe { owner, route in - switch route { - case .dismiss: - owner.navigationController?.popViewController(animated: true) - case .search(let keyword): - if !keyword.isOnlyKorean() { - GuideAlertFactory.show(mainText: "초성은 검색할 수 없습니다.", ctaText: "확인", ctaAction: {}) - } else { - owner.mainView.searchBar.textField.text = "" - let viewController = owner.searchResultFactory.make(keyword: keyword) - owner.navigationController?.pushViewController(viewController, animated: true) - } - default: - break - } - } - .disposed(by: disposeBag) - } -} - -// MARK: - Delegate -extension DictionarySearchViewController: UICollectionViewDelegate, UICollectionViewDataSource { - public func numberOfSections(in collectionView: UICollectionView) -> Int { - return 3 - } - - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - guard let reactor = reactor else { return 0 } - - switch section { - case 0: - let recentResult = reactor.currentState.recentResult - return recentResult.count == 0 ? 1 : recentResult.count - case 2: - return true ? 0 : reactor.currentState.popularResult.count // TODO: 인기검색어는 추후에 - default: - return 0 - } - } - - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let reactor = reactor else { return UICollectionViewCell() } - - let section = indexPath.section - - switch section { - case 0: - if reactor.currentState.recentResult.isEmpty { - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: EmptyRecentCell.identifier, for: indexPath) as? EmptyRecentCell else { return UICollectionViewCell() } - return cell - } else { - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TagChipCell.identifier, for: indexPath) as? TagChipCell else { return UICollectionViewCell() } - let item = reactor.currentState.recentResult[indexPath.row] - cell.inject(title: item, style: .search) - - cell.buttonTapSubject - .map { item } - .bind(to: chipTapRelay) - .disposed(by: cell.disposeBag) - - cell.cancelButtonTapSubject - .map { item } - .bind(to: chipCancelRelay) - .disposed(by: cell.disposeBag) - - return cell - } - case 2: - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PopularResultCell.identifier, for: indexPath) as! PopularResultCell - let item = reactor.currentState.popularResult[indexPath.item] - cell.inject(input: .init(text: item.name, rank: item.rank)) - return cell - - default: - return UICollectionViewCell() - } - } - - public func collectionView( - _ collectionView: UICollectionView, - viewForSupplementaryElementOfKind kind: String, - at indexPath: IndexPath - ) -> UICollectionReusableView { - switch indexPath.section { - case 0: - guard let view = collectionView.dequeueReusableSupplementaryView( - ofKind: kind, - withReuseIdentifier: RecentSearchHeaderView.identifier, - for: indexPath - ) as? RecentSearchHeaderView else { return UICollectionViewCell() } - - guard let reactor = reactor else { return UICollectionViewCell() } - - view.deleteButton.rx.tap - .map { Reactor.Action.deleteAllButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - return view - - case 2: - let view = collectionView.dequeueReusableSupplementaryView( - ofKind: kind, - withReuseIdentifier: PopularSearchHeaderView.identifier, - for: indexPath - ) as! PopularSearchHeaderView - // TODO: 인기검색어 추후에 - return view - default: - return UICollectionReusableView() - } - } -} - -extension DictionarySearchViewController: SearchBarDelegate { - public func searchBarDidReturn(_ searchBar: SearchBar, text: String) { - reactor?.action.onNext(.searchButtonTapped(text)) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/EmptyRecentCell.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/EmptyRecentCell.swift deleted file mode 100644 index cfc2ab71..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/EmptyRecentCell.swift +++ /dev/null @@ -1,35 +0,0 @@ -import UIKit - -import SnapKit - -final class EmptyRecentCell: UICollectionViewCell { - private let label: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .b_s_r, text: "최근 검색어 내역이 없습니다", color: .neutral600) - return label - }() - - override init(frame: CGRect) { - super.init(frame: frame) - addViews() - setUpConstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { fatalError() } -} - -// MARK: SetUp -private extension EmptyRecentCell { - func addViews() { - contentView.addSubview(label) - } - - func setUpConstraints() { - label.snp.makeConstraints { - $0.edges.equalToSuperview() - $0.height.equalTo(32) - } - - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/PopularResultCell.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/PopularResultCell.swift deleted file mode 100644 index af6a3155..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/PopularResultCell.swift +++ /dev/null @@ -1,64 +0,0 @@ -import UIKit - -import DesignSystem -import DomainInterface - -final class PopularResultCell: UICollectionViewCell { - // MARK: - Type - private enum Constant { - static let verticalInset: CGFloat = 8 - static let spacing: CGFloat = 8 - static let indexLabelWidth: CGFloat = 18 - } - - // MARK: - Components - public let indexLabel = UILabel() - public let textLabel = UILabel() - - // MARK: - init - override init(frame: CGRect) { - super.init(frame: frame) - - addViews() - setupContstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension PopularResultCell { - func addViews() { - contentView.addSubview(indexLabel) - contentView.addSubview(textLabel) - } - - func setupContstraints() { - indexLabel.snp.makeConstraints { make in - make.verticalEdges.equalToSuperview().inset(Constant.verticalInset) - make.leading.equalToSuperview() - make.width.equalTo(Constant.indexLabelWidth) - } - - textLabel.snp.makeConstraints { make in - make.verticalEdges.equalToSuperview().inset(Constant.verticalInset) - make.leading.equalTo(indexLabel.snp.trailing).offset(Constant.spacing).priority(.high) - make.trailing.equalToSuperview().priority(.low) - } - } -} - -extension PopularResultCell { - struct Input { - let text: String - let rank: Int - } - - func inject(input: Input) { - indexLabel.attributedText = .makeStyledString(font: input.rank < 4 ? .cp_s_m : .cp_s_r, text: "\(input.rank)", color: input.rank < 4 ? .primary700 : .neutral700, alignment: .center) - textLabel.attributedText = .makeStyledString(font: input.rank < 4 ? .cp_s_m : .cp_s_r, text: input.text, color: input.rank < 4 ? .primary700 : .neutral700, alignment: .left) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/TagChipCell.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/TagChipCell.swift deleted file mode 100644 index 66129c71..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearch/TagChipCell.swift +++ /dev/null @@ -1,68 +0,0 @@ -import UIKit - -import DesignSystem - -import RxSwift -import SnapKit - -public final class TagChipCell: UICollectionViewCell { - // MARK: - Properties - public let buttonTapSubject = PublishSubject() - public let cancelButtonTapSubject = PublishSubject() - - // MARK: - Components - public let button: TagChip = { - let button = TagChip(style: .normal, text: "") - return button - }() - - override init(frame: CGRect) { - super.init(frame: frame) - addViews() - setupConstraints() - } - - public var disposeBag = DisposeBag() - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override public func prepareForReuse() { - super.prepareForReuse() - disposeBag = DisposeBag() - } -} - -// MARK: - SetUp -private extension TagChipCell { - func addViews() { - contentView.addSubview(button) - } - - func setupConstraints() { - button.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } - - func bind() { - button.rx.tap - .bind(to: buttonTapSubject) - .disposed(by: disposeBag) - - button.cancelButton.rx.tap - .bind(to: cancelButtonTapSubject) - .disposed(by: disposeBag) - } -} - -public extension TagChipCell { - func inject(title: String?, style: TagChip.TagChipStyle) { - bind() - button.style = style - button.text = title ?? "" - button.titleLabel?.numberOfLines = 1 - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultFactoryImpl.swift deleted file mode 100644 index eb07655e..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultFactoryImpl.swift +++ /dev/null @@ -1,23 +0,0 @@ -import BaseFeature -import DictionaryFeatureInterface -import DomainInterface - -public final class DictionarySearchResultFactoryImpl: DictionarySearchResultFactory { - private let dictionaryListCountUseCase: FetchDictionaryListCountUseCase - private let dictionaryMainListFactory: DictionaryMainListFactory - private let dictionarySearchListUseCase: FetchDictionarySearchListUseCase - private let recentSearchAddUseCase: RecentSearchAddUseCase - - public init(dictionaryListCountUseCase: FetchDictionaryListCountUseCase, dictionaryMainListFactory: DictionaryMainListFactory, dictionarySearchListUseCase: FetchDictionarySearchListUseCase, recentSearchAddUseCase: RecentSearchAddUseCase) { - self.dictionaryListCountUseCase = dictionaryListCountUseCase - self.dictionaryMainListFactory = dictionaryMainListFactory - self.dictionarySearchListUseCase = dictionarySearchListUseCase - self.recentSearchAddUseCase = recentSearchAddUseCase - } - - public func make(keyword: String?) -> BaseViewController { - let reactor = DictionarySearchResultReactor(keyword: keyword, dictionarySearchUseCase: dictionarySearchListUseCase, dictionarySearchCountUseCase: dictionaryListCountUseCase, recentSearchAddUseCase: recentSearchAddUseCase) - let viewController = DictionarySearchResultViewController(dictionaryListFactory: dictionaryMainListFactory, reactor: reactor) - return viewController - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultReactor.swift deleted file mode 100644 index 70019158..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultReactor.swift +++ /dev/null @@ -1,114 +0,0 @@ -import ReactorKit - -import DomainInterface - -public final class DictionarySearchResultReactor: Reactor { - // MARK: - Reactor - public enum Route { - case none - case dismiss - } - - public enum Action { - case backbuttonTapped - case updateKeyword(String) - case viewWillAppear - case searchButtonTapped(String?) - } - - public enum Mutation { - case navigateTo(Route) - case setKeyword(String) - case setCounts([Int]) - } - - public struct State { - @Pulse var route: Route = .none - let type = DictionaryMainViewType.search - var sections: [String] { - return type.pageTabList.map { $0.title } - } - - var keyword: String? - - var counts: [Int] = [0, 0, 0, 0, 0, 0] - } - - // MARK: - properties - public var initialState: State - var disposeBag = DisposeBag() - - // MARK: - UseCases - private let dictionarySearchUseCase: FetchDictionarySearchListUseCase - private let dictionarySearchCountUseCase: FetchDictionaryListCountUseCase - private let recentSearchAddUseCase: RecentSearchAddUseCase - - // MARK: - init - public init(keyword: String?, dictionarySearchUseCase: FetchDictionarySearchListUseCase, dictionarySearchCountUseCase: FetchDictionaryListCountUseCase, recentSearchAddUseCase: RecentSearchAddUseCase) { - self.initialState = State(keyword: keyword) - self.dictionarySearchUseCase = dictionarySearchUseCase - self.dictionarySearchCountUseCase = dictionarySearchCountUseCase - self.recentSearchAddUseCase = recentSearchAddUseCase - } - - // MARK: - Reactor Methods - public func mutate(action: Action) -> Observable { - switch action { - case .backbuttonTapped: - return Observable.just(.navigateTo(.dismiss)) - case .updateKeyword(let keyword): - return Observable.just(.setKeyword(keyword)) - case .viewWillAppear: - // 초기 검색 시, state.keyword를 그대로 사용 - // transform에서 keyword 변화 감지 후 호출됨 - if let keyword = currentState.keyword { - return Observable.just(.setKeyword(keyword)) - } else { - return .empty() - } - // 검색 결과 화면에서 재검색 시 - case .searchButtonTapped(let keyword): - let keyword = keyword ?? "" - return recentSearchAddUseCase.add(keyword: keyword) - .andThen(.just(.setKeyword(keyword))) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .navigateTo(let route): - newState.route = route - case .setKeyword(let keyword): - newState.keyword = keyword - case .setCounts(let counts): - newState.counts = counts - } - - return newState - } - - public func transform(mutation: Observable) -> Observable { - let keywordChanges = mutation - .compactMap { mutation -> String? in - if case .setKeyword(let keyword) = mutation { return keyword } - return nil - } - .distinctUntilChanged() // 중복 keyword 방지 - .flatMap { [weak self] keyword -> Observable in - guard let self = self else { return .empty() } - let types = ["search", "monsters", "items", "maps", "npcs", "quests"] - let countObservables = types.map { type in - self.dictionarySearchCountUseCase.execute(type: type, keyword: keyword) - .map { $0.count ?? 0 } - } - return Observable.zip(countObservables) - .map { counts in - Mutation.setCounts(counts) - } - } - - return Observable.merge(mutation, keywordChanges) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift deleted file mode 100644 index b9bfe4ba..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/DictionarySearchResult/DictionarySearchResultViewController.swift +++ /dev/null @@ -1,301 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem -import DictionaryFeatureInterface -import DomainInterface - -import ReactorKit -import RxCocoa -import RxSwift -import SnapKit - -public final class DictionarySearchResultViewController: BaseViewController, View { - public typealias Reactor = DictionarySearchResultReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - private let initialIndex: Int - private lazy var currentPageIndex = BehaviorRelay(value: initialIndex) - - private var viewControllers: [UIViewController] - - private var mainView: DictionaryMainView - private let underLineController = TabBarUnderlineController() - private let dictionaryListFactory: DictionaryMainListFactory - - private var didSetInitialIndex = false - - public init( - dictionaryListFactory: DictionaryMainListFactory, - initialIndex: Int = 0, - reactor: DictionarySearchResultReactor - ) { - let type = reactor.currentState.type - self.mainView = DictionaryMainView(type: type) - self.viewControllers = type.pageTabList.map { dictionaryListFactory.make(type: $0, listType: type, keyword: reactor.currentState.keyword) } - self.initialIndex = initialIndex - self.dictionaryListFactory = dictionaryListFactory - super.init() - self.reactor = reactor - } - - @available(*, unavailable) - @MainActor required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -public extension DictionarySearchResultViewController { - override func viewDidLoad() { - super.viewDidLoad() - addViews() - setupConstraints() - configureUI() - } - - override func viewDidAppear(_ animated: Bool) { - guard !didSetInitialIndex else { return } - didSetInitialIndex = true - setInitialIndex() - } - - private func updateViewControllers(keyword: String) { - guard let reactor = reactor else { return } - let type = reactor.currentState.type - - // 기존 viewControllers 제거 - for viewController in viewControllers { - viewController.removeFromParent() - viewController.view.removeFromSuperview() - } - - // 새로운 viewControllers 생성 - viewControllers = type.pageTabList.map { dictionaryListFactory.make(type: $0, listType: type, keyword: keyword) } - - // PageViewController에 첫 번째 뷰컨트롤러 설정 - if !viewControllers.isEmpty { - mainView.pageViewController.setViewControllers( - [viewControllers[0]], - direction: .forward, - animated: false, - completion: nil - ) - } - - // TabCollectionView 갱신 - mainView.tabCollectionView.reloadData() - - // Tab 선택 초기화 - DispatchQueue.main.async { [weak self] in - guard let self = self else { return } - let indexPath = IndexPath(item: 0, section: 0) - if self.mainView.tabCollectionView.numberOfItems(inSection: 0) > 0 { - self.mainView.tabCollectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredHorizontally) - self.currentPageIndex.accept(0) - self.underLineController.setInitialIndicator() - } - } - } -} - -// MARK: - SetUp -private extension DictionarySearchResultViewController { - func addViews() { - addChild(mainView.pageViewController) - mainView.pageViewController.didMove(toParent: self) - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.top.horizontalEdges.equalTo(view.safeAreaLayoutGuide) - make.bottom.equalToSuperview() - } - } - - func configureUI() { - mainView.searchBar.searchDelegate = self - mainView.searchBar.textField.becomeFirstResponder() - - mainView.pageViewController.delegate = self - mainView.pageViewController.dataSource = self - configureTabCollectionView() - isBottomTabbarHidden = true - mainView.searchBar.textField.resignFirstResponder() - } - - func configureTabCollectionView() { - mainView.tabCollectionView.collectionViewLayout = createTabLayout() - mainView.tabCollectionView.delegate = self - mainView.tabCollectionView.dataSource = self - mainView.tabCollectionView.register(PageTabbarCell.self, forCellWithReuseIdentifier: PageTabbarCell.identifier) - underLineController.configure(with: mainView.tabCollectionView) - } - - func createTabLayout() -> UICollectionViewLayout { - let layout = CompositionalLayoutBuilder() - .section { _ in LayoutFactory.getPageTabbarLayout(underLineController: underLineController) } - .build() - return layout - } - - func setInitialIndex() { - let indexPath = IndexPath(item: initialIndex, section: 0) - - mainView.pageViewController.setViewControllers( - [viewControllers[initialIndex]], - direction: .forward, - animated: false, - completion: nil - ) - - mainView.tabCollectionView.selectItem(at: indexPath, animated: false, scrollPosition: .centeredHorizontally) - - // 전체 레이아웃 강제 갱신 - mainView.tabCollectionView.collectionViewLayout.invalidateLayout() - mainView.tabCollectionView.layoutIfNeeded() - - DispatchQueue.main.async { [weak self] in - self?.underLineController.setInitialIndicator() - } - } -} - -// MARK: - Bind -public extension DictionarySearchResultViewController { - func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - mainView.searchBar.backButton.rx.tap - .map { Reactor.Action.backbuttonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.searchBar.searchButton.rx.tap - .withLatestFrom(mainView.searchBar.textField.rx.text.orEmpty) - .map { text in Reactor.Action.searchButtonTapped(text) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .subscribe { owner, route in - switch route { - case .dismiss: - owner.navigationController?.popViewController(animated: true) - default: - break - } - } - .disposed(by: disposeBag) - - reactor.state - .map(\.keyword) - .filter { $0 != nil } - .map { $0! } - .distinctUntilChanged() - .skip(1) - .observe(on: MainScheduler.instance) - .bind(with: self) { owner, newKeyword in - if !newKeyword.isOnlyKorean() { - GuideAlertFactory.show(mainText: "초성은 검색할 수 없습니다.", ctaText: "확인", ctaAction: {}) - } else { - owner.updateViewControllers(keyword: newKeyword) - } - } - .disposed(by: disposeBag) - - rx.viewWillAppear - .map { _ in Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - reactor.state - .map(\.counts) - .distinctUntilChanged() - .observe(on: MainScheduler.instance) - .bind(with: self) { owner, _ in - owner.mainView.tabCollectionView.reloadData() - } - .disposed(by: disposeBag) - } -} - -// MARK: - UIPageViewController DataSource & Delegate -extension DictionarySearchResultViewController: UIPageViewControllerDataSource, UIPageViewControllerDelegate { - public func pageViewController(_ pageViewController: UIPageViewController, viewControllerBefore viewController: UIViewController) -> UIViewController? { - guard let index = viewControllers.firstIndex(of: viewController) else { return nil } - let previousIndex = index - 1 - return previousIndex >= 0 ? viewControllers[previousIndex] : nil - } - - public func pageViewController(_ pageViewController: UIPageViewController, viewControllerAfter viewController: UIViewController) -> UIViewController? { - guard let index = viewControllers.firstIndex(of: viewController) else { return nil } - let nextIndex = index + 1 - return nextIndex < viewControllers.count ? viewControllers[nextIndex] : nil - } - - public func pageViewController(_ pageViewController: UIPageViewController, didFinishAnimating finished: Bool, previousViewControllers: [UIViewController], transitionCompleted completed: Bool) { - if completed, let visibleViewController = pageViewController.viewControllers?.first, - let newIndex = viewControllers.firstIndex(of: visibleViewController) { - currentPageIndex.accept(newIndex) - mainView.tabCollectionView.selectItem(at: IndexPath(item: newIndex, section: 0), animated: true, scrollPosition: .centeredHorizontally) - underLineController.animateIndicatorToSelectedItem() - } - } -} - -// MARK: - UICollectionView DataSource & Delegate -extension DictionarySearchResultViewController: UICollectionViewDataSource, UICollectionViewDelegate { - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - guard let reactor = reactor else { return 0 } - return reactor.currentState.sections.count - } - - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let reactor = reactor else { return UICollectionViewCell() } - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PageTabbarCell.identifier, for: indexPath) as? PageTabbarCell else { - return UICollectionViewCell() - } - let title = reactor.currentState.sections[indexPath.row] - let count = reactor.currentState.counts[indexPath.row] - cell.inject(title: "\(title)(\(count))") - cell.isSelected = indexPath.row == currentPageIndex.value - return cell - } - - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - let newIndex = indexPath.row - let oldIndex = currentPageIndex.value - - guard newIndex != oldIndex else { return } - - let direction: UIPageViewController.NavigationDirection = newIndex > oldIndex ? .forward : .reverse - - mainView.pageViewController.setViewControllers( - [viewControllers[newIndex]], - direction: direction, - animated: true, - completion: nil - ) - - currentPageIndex.accept(newIndex) - underLineController.animateIndicatorToSelectedItem() - } -} - -extension DictionarySearchResultViewController: SearchBarDelegate { - public func searchBarDidReturn(_ searchBar: SearchBar, text: String) { - reactor?.action.onNext(.searchButtonTapped(text)) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/ItemFilterBottomSheetFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/ItemFilterBottomSheetFactoryImpl.swift deleted file mode 100644 index e4a85934..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/ItemFilterBottomSheetFactoryImpl.swift +++ /dev/null @@ -1,15 +0,0 @@ -import BaseFeature -import DictionaryFeatureInterface - -public struct ItemFilterBottomSheetFactoryImpl: ItemFilterBottomSheetFactory { - private let sharedReactor = ItemFilterBottomSheetReactor() - public init() {} - - public func make(onFilterSelected: @escaping ([(String, String)]) -> Void) -> BaseViewController { - // let reactor = ItemFilterBottomSheetReactor() // 매번 새로 리액터를 생성하기 때문에 초기화 - let viewController = ItemFilterBottomSheetViewController() - viewController.reactor = sharedReactor - viewController.onFilterSelected = onFilterSelected - return viewController - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/ItemFilterBottomSheetReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/ItemFilterBottomSheetReactor.swift deleted file mode 100644 index 7882922b..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/ItemFilterBottomSheetReactor.swift +++ /dev/null @@ -1,162 +0,0 @@ -import Foundation - -import ReactorKit -import RxSwift - -public final class ItemFilterBottomSheetReactor: Reactor { - public enum Route { - case none - case dismiss - case dismissWithSelection([(String, String)]) - case resetFilters - } - - // MARK: - Reactor - public enum Action { - case closeButtonTapped - case filterSelected(indexPath: IndexPath) - case filterDeselected(indexPath: IndexPath) - case changeLevelRange(low: Int?, high: Int?) - case applyButtonTapped([(String, String)]) - case resetFilters - } - - public enum Mutation { - case navigateTo(route: Route) - case setScrolls(selectedIndex: Int?) - case appendSelectedItem(indexPath: IndexPath) - case removeSelectedItem(indexPath: IndexPath) - case setLevelRange(low: Int?, high: Int?) - case resetFilters - } - - public struct State { - var sections: [String] = ["직업/레벨", "무기", "발사체", "방어구", "장신구", "주문서", "기타"] - var jobs: [String] = ["없음", "공용", "마법사", "전사", "궁수", "도적"] - var weapons: [String] = ["한손검", "한손도끼", "한손둔기", "창", "단검", "두손검", "두손도끼", "두손둔기", "폴암", "활", "석궁", "완드", "스태프", "아대"] - var projectiles: [String] = ["화살", "표창"] // 불렛은 제거 - var armors: [String] = ["모자", "상의", "하의", "장갑", "신발", "방패", "전신갑옷"] // 전신 = 전신갑옷? - var accessories: [String] = ["귀고리", "망토", "훈장", "눈장식", "얼굴장식", "팬던트", "벨트", "반지", "어깨장식"] // 귀장식 데이터 안줌 -> 귀장식 = 귀고리, 훈장은 서버에서 데이터 안줌. - @Pulse var scrollCategories: [String] = ["무기 주문서", "방어구 주문서", "기타 주문서"] - var originWeaponScrolls: [String] = ["한손검", "한손도끼", "한손둔기", "단검", "완드", "스태프", "두손검", "두손도끼", "두손둔기", "창", "폴암", "활", "석궁", "아대"] - var originArmorScrolls: [String] = ["투구", "상의", "하의", "전신갑옷", "신발", "장갑", "망토", "방패", "귀장식"] - var originEtcScrolls: [String] = ["펫장비", "연성서", "귀환주문서"] - @Pulse var weaponScrolls: [String] = [] - @Pulse var armorScrolls: [String] = [] - @Pulse var etcScrolls: [String] = [] - var etcItems: [String] = ["마스터리북", "스킬북", "소비", "설치", "이동수단"] - var selectedScrollIndexes: Int? - var selectedItemIndexes: [IndexPath] = [] - var levelRange: (low: Int?, high: Int?) = (nil, nil) - @Pulse var route: Route = .none - } - - // MARK: - properties - public var initialState: State - var disposeBag = DisposeBag() - - // MARK: - init - public init() { - self.initialState = State() - } - - // MARK: - Reactor Methods - public func mutate(action: Action) -> Observable { - switch action { - case .closeButtonTapped: - // 닫기버튼 누르면 선택했던 필터 초기화 해줘야함 - return .concat([Observable.just(.navigateTo(route: .dismiss)), Observable.just(.resetFilters)]) - case .filterSelected(let indexPath): - let section = ItemFilterBottomSheetViewController.FilterSection(rawValue: indexPath.section) - switch section { - case .scrollCategories: - return Observable.just(.setScrolls(selectedIndex: indexPath.row)) - default: - return Observable.just(.appendSelectedItem(indexPath: indexPath)) - } - case .filterDeselected(let indexPath): - let section = ItemFilterBottomSheetViewController.FilterSection(rawValue: indexPath.section) - switch section { - case .scrollCategories: - return Observable.just(.setScrolls(selectedIndex: nil)) - default: - return Observable.just(.removeSelectedItem(indexPath: indexPath)) - } - case .changeLevelRange(low: let low, high: let high): - return Observable.just(.setLevelRange(low: low, high: high)) - case .applyButtonTapped(let selectedItems): - return .just(.navigateTo(route: .dismissWithSelection(selectedItems))) - case .resetFilters: - return Observable.just(.resetFilters) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .navigateTo(let route): - newState.route = route - case .appendSelectedItem(let indexPath): - newState.selectedItemIndexes.insert(indexPath, at: 0) - let selectedWeaponScrollCount = newState.selectedItemIndexes.filter { ItemFilterBottomSheetViewController.FilterSection(rawValue: $0.section) == .weaponScrolls }.count - let selectedArmorScrollCount = newState.selectedItemIndexes.filter { ItemFilterBottomSheetViewController.FilterSection(rawValue: $0.section) == .armorsScrolls }.count - let selectedEtcScrollCount = newState.selectedItemIndexes.filter { ItemFilterBottomSheetViewController.FilterSection(rawValue: $0.section) == .etcScrolls }.count - newState.scrollCategories = [ - "무기 주문서\(selectedWeaponScrollCount == 0 ? "" : " \(selectedWeaponScrollCount)")", - "방어구 주문서\(selectedArmorScrollCount == 0 ? "" : " \(selectedArmorScrollCount)")", - "기타 주문서\(selectedEtcScrollCount == 0 ? "" : " \(selectedEtcScrollCount)")" - ] - case .removeSelectedItem(let indexPath): - if let removeIndex = newState.selectedItemIndexes.firstIndex(of: indexPath) { - newState.selectedItemIndexes.remove(at: removeIndex) - } - let selectedWeaponScrollCount = newState.selectedItemIndexes.filter { ItemFilterBottomSheetViewController.FilterSection(rawValue: $0.section) == .weaponScrolls }.count - let selectedArmorScrollCount = newState.selectedItemIndexes.filter { ItemFilterBottomSheetViewController.FilterSection(rawValue: $0.section) == .armorsScrolls }.count - let selectedEtcScrollCount = newState.selectedItemIndexes.filter { ItemFilterBottomSheetViewController.FilterSection(rawValue: $0.section) == .etcScrolls }.count - newState.scrollCategories = [ - "무기 주문서\(selectedWeaponScrollCount == 0 ? "" : " \(selectedWeaponScrollCount)")", - "방어구 주문서\(selectedArmorScrollCount == 0 ? "" : " \(selectedArmorScrollCount)")", - "기타 주문서\(selectedEtcScrollCount == 0 ? "" : " \(selectedEtcScrollCount)")" - ] - case .setScrolls(let selectedIndex): - newState.selectedScrollIndexes = selectedIndex - switch selectedIndex { - case 0: - newState.weaponScrolls = newState.originWeaponScrolls - newState.armorScrolls = [] - newState.etcScrolls = [] - case 1: - newState.weaponScrolls = [] - newState.armorScrolls = newState.originArmorScrolls - newState.etcScrolls = [] - - case 2: - newState.weaponScrolls = [] - newState.armorScrolls = [] - newState.etcScrolls = newState.originEtcScrolls - default: - newState.weaponScrolls = [] - newState.armorScrolls = [] - newState.etcScrolls = [] - } - case .setLevelRange(low: let low, high: let high): - let levelSection: IndexPath = .init(row: 0, section: ItemFilterBottomSheetViewController.FilterSection.level.rawValue) - if low == 0 && high == 200 { - if let removeIndex = newState.selectedItemIndexes.firstIndex(of: levelSection) { newState.selectedItemIndexes.remove(at: removeIndex) } - } else { - if !newState.selectedItemIndexes.contains(levelSection) { newState.selectedItemIndexes.insert(levelSection, at: 0) } - } - newState.levelRange = (low, high) - case .resetFilters: - newState.selectedItemIndexes = [] - newState.levelRange = (nil, nil) - newState.scrollCategories = ["무기 주문서", "방어구 주문서", "기타 주문서"] - newState.weaponScrolls = [] - newState.armorScrolls = [] - newState.etcScrolls = [] - newState.selectedScrollIndexes = nil - } - return newState - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/ItemFilterBottomSheetViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/ItemFilterBottomSheetViewController.swift deleted file mode 100644 index 4adbcbe5..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/ItemFilterBottomSheetViewController.swift +++ /dev/null @@ -1,619 +0,0 @@ -// swiftlint:disable all - -import UIKit - -import BaseFeature - -import ReactorKit -import RxCocoa -import RxSwift -import SnapKit - -public final class ItemFilterBottomSheetViewController: BaseViewController, View { - public typealias Reactor = ItemFilterBottomSheetReactor - - enum FilterSection: Int, CaseIterable { - case job - case level - case weapons - case projectiles - case armors - case accessories - case scrollCategories - case weaponScrolls - case armorsScrolls - case etcScrolls - case etcItems - - var headerTitle: String? { - switch self { - case .job: return "직업" - case .level: return "레벨" - case .weapons: return "무기" - case .projectiles: return "발사체" - case .armors: return "방어구" - case .accessories: return "장신구" - case .scrollCategories: return "주문서" - case .etcItems: return "기타" - default: return nil - } - } - - var layout: CompositionalSectionBuilder { - switch self { - case .level: return LayoutFactory.getLevelRangeSection() - case .weaponScrolls, .armorsScrolls, .etcScrolls: - return CompositionalSectionBuilder() - .item(width: .fractionalWidth(0.5), height: .absolute(32)) - .group(.horizontal, width: .fractionalWidth(1), height: .estimated(300)) - .interItemSpacing(.fixed(3)) - .buildSection() - .interGroupSpacing(16) - .contentInsets(.init(top: 0, leading: 16, bottom: 32, trailing: 16)) - default: - return LayoutFactory.getItemTagListSection() - } - } - } - - enum FilterItem: Hashable { - case job(String) - case level(low: Int?, upper: Int?) - case weapons(String) - case projectiles(String) - case armors(String) - case accessories(String) - case scrollCategories(String) - case weaponScrolls(String) - case armorScrolls(String) - case etcScrolls(String) - case etcItems(String) - } - - // Diffable Data Source 타입 정의 - typealias DataSource = UICollectionViewDiffableDataSource - typealias Snapshot = NSDiffableDataSourceSnapshot - - // MARK: - Properties - public var disposeBag = DisposeBag() - private var isUserScrollDragging: Bool = false - private var dataSource: DataSource! = nil - private var mainView = ItemFilterBottomSheetView() - private let underLineController = TabBarUnderlineController() - - public var onFilterSelected: (([(String, String)]) -> Void)? - - override public init() { - super.init() - } - - @available(*, unavailable) - @MainActor required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Life Cycle -public extension ItemFilterBottomSheetViewController { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - } - - override func viewDidAppear(_ animated: Bool) { - super.viewDidAppear(animated) - - // Modal Gesture 제거 - navigationController?.presentationController?.presentedView?.gestureRecognizers?.forEach { $0.isEnabled = false } - presentationController?.presentedView?.gestureRecognizers?.forEach { $0.isEnabled = false } - } - - override func viewWillAppear(_ animated: Bool) { - super.viewWillAppear(animated) - guard let reactor = reactor else { return } - - reactor.currentState.selectedItemIndexes.forEach { indexPath in - let sectionCount = mainView.contentCollectionView.numberOfItems(inSection: indexPath.section) - if indexPath.row < sectionCount { - mainView.contentCollectionView.selectItem(at: indexPath, animated: false, scrollPosition: []) - } - - } - guard let selectedIndex = reactor.currentState.selectedScrollIndexes else { return } - // 스크롤 탭(무기/방어구/기타 주문서) UI 선택 상태 복원 - let scrollCategoryIndexPath = IndexPath(row: selectedIndex, section: FilterSection.scrollCategories.rawValue) - mainView.contentCollectionView.selectItem(at: scrollCategoryIndexPath, animated: false, scrollPosition: .centeredHorizontally) - - } -} - -// MARK: - SetUp -private extension ItemFilterBottomSheetViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } - - func configureUI() { - configureCategoryCollectionView() - configureContentCollectionView() - configureSelectedItemCollectionView() - configureDataSource() - applyInitialSnapshot() - } - - func configureCategoryCollectionView() { - mainView.categoryCollectionView.collectionViewLayout = createCategoryLayout() - mainView.categoryCollectionView.dataSource = self - mainView.categoryCollectionView.register(PageTabbarCell.self, forCellWithReuseIdentifier: PageTabbarCell.identifier) - underLineController.configure(with: mainView.categoryCollectionView) - } - - func configureContentCollectionView() { - mainView.contentCollectionView.collectionViewLayout = createContentLayout() - mainView.contentCollectionView.register(TapButtonCell.self, forCellWithReuseIdentifier: TapButtonCell.identifier) - mainView.contentCollectionView.register(FilterLevelSectionCell.self, forCellWithReuseIdentifier: FilterLevelSectionCell.identifier) - mainView.contentCollectionView.register(CheckBoxButtonListSmallCell.self, forCellWithReuseIdentifier: CheckBoxButtonListSmallCell.identifier) - mainView.contentCollectionView.register( - SubTitleBoldHeaderView.self, - forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, - withReuseIdentifier: SubTitleBoldHeaderView.identifier - ) - } - - func configureSelectedItemCollectionView() { - mainView.selectedItemCollectionView.collectionViewLayout = createSelectedItemLayout() - mainView.selectedItemCollectionView.dataSource = self - mainView.selectedItemCollectionView.register(TagChipCell.self, forCellWithReuseIdentifier: TagChipCell.identifier) - } - - func createCategoryLayout() -> UICollectionViewLayout { - let layout = CompositionalLayoutBuilder() - .section { _ in LayoutFactory.getPageTabbarLayout(underLineController: underLineController) } - .build() - return layout - } - - func createContentLayout() -> UICollectionViewLayout { - let layoutAry = FilterSection.allCases.compactMap { $0.layout.build() } - let layout = CompositionalLayoutBuilder() - .setSections(layoutAry) - .build() - layout.register(Neutral200DividerView.self, forDecorationViewOfKind: Neutral200DividerView.identifier) - return layout - } - - func createSelectedItemLayout() -> UICollectionViewLayout { - let layout = CompositionalLayoutBuilder() - .section { builder in - builder - .item(width: .estimated(100), height: .absolute(32)) - .group(.horizontal, width: .estimated(100), height: .absolute(32)) - .buildSection() - .interGroupSpacing(8) - .contentInsets(.init(top: 12, leading: 16, bottom: 12, trailing: 16)) - .orthogonalScrolling(.continuous) - } - .build() - return layout - } - - func configureDataSource() { - dataSource = DataSource(collectionView: mainView.contentCollectionView) { collectionView, indexPath, item in - switch item { - case .job(let title), .weapons(let title), .projectiles(let title), .armors(let title), - .accessories(let title), .scrollCategories(let title), .etcItems(let title): - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TapButtonCell.identifier, for: indexPath) as! TapButtonCell - cell.inject(title: title) - return cell - case .weaponScrolls(let title), .armorScrolls(let title), .etcScrolls(let title): - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: CheckBoxButtonListSmallCell.identifier, for: indexPath) as! CheckBoxButtonListSmallCell - cell.inject(title: title) - return cell - case .level(let low, let upper): - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: FilterLevelSectionCell.identifier, for: indexPath) as! FilterLevelSectionCell - cell.inject(input: .init(lowValue: low, highValue: upper)) - guard let reactor = self.reactor else { return UICollectionViewCell() } - let lowValue = cell.levelSectionView.slider.lowerValueObservable - let highValue = cell.levelSectionView.slider.upperValueObservable - Observable.combineLatest(lowValue, highValue) - .map { low, high in - return Reactor.Action.changeLevelRange(low: low.map { Int($0)}, high: high.map { Int($0)}) - } - .bind(to: reactor.action) - .disposed(by: cell.disposeBag) - - // Slider Thumb 동작 시 Scroll 비활성화 - cell.levelSectionView.slider.isThumbTracking - .distinctUntilChanged() - .withUnretained(self) - .subscribe { owner, isTracking in - owner.mainView.contentCollectionView.isScrollEnabled = !isTracking - } - .disposed(by: cell.disposeBag) - return cell - } - } - - dataSource.supplementaryViewProvider = { collectionView, _, indexPath in - let header = collectionView.dequeueReusableSupplementaryView( - ofKind: UICollectionView.elementKindSectionHeader, - withReuseIdentifier: SubTitleBoldHeaderView.identifier, - for: indexPath - ) as? SubTitleBoldHeaderView - - let section = FilterSection.allCases[indexPath.section] - header?.inject(title: section.headerTitle) - return header - } - } - - private func applyInitialSnapshot() { - var snapshot = Snapshot() - - guard let reactor = reactor else { return } - // 모든 섹션 추가 - snapshot.appendSections(FilterSection.allCases) - - // 섹션별 아이템 추가 - snapshot.appendItems(reactor.currentState.jobs.map { .job($0) }, toSection: .job) - snapshot.appendItems( - [.level( - low: reactor.currentState.levelRange.low, - upper: reactor.currentState.levelRange.high - )], - toSection: .level - ) - snapshot.appendItems(reactor.currentState.weapons.map { .weapons($0) }, toSection: .weapons) - snapshot.appendItems(reactor.currentState.projectiles.map { .projectiles($0) }, toSection: .projectiles) - snapshot.appendItems(reactor.currentState.armors.map { .armors($0) }, toSection: .armors) - snapshot.appendItems(reactor.currentState.accessories.map { .accessories($0) }, toSection: .accessories) - snapshot.appendItems(reactor.currentState.scrollCategories.map { .scrollCategories($0) }, toSection: .scrollCategories) - snapshot.appendItems(reactor.currentState.weaponScrolls.map { .weaponScrolls($0) }, toSection: .weaponScrolls) - snapshot.appendItems(reactor.currentState.armorScrolls.map { .armorScrolls($0) }, toSection: .armorsScrolls) - snapshot.appendItems(reactor.currentState.etcScrolls.map { .etcScrolls($0) }, toSection: .etcScrolls) - snapshot.appendItems(reactor.currentState.etcItems.map { .etcItems($0) }, toSection: .etcItems) - - dataSource.apply(snapshot, animatingDifferences: true) { [weak self] in - self?.mainView.categoryCollectionView.selectItem(at: .init(row: 0, section: 0), animated: false, scrollPosition: .centeredHorizontally) - self?.underLineController.setInitialIndicator() - } - } -} - -// MARK: - Methods -private extension ItemFilterBottomSheetViewController { - func getSelectedScrollCategoryIndexPath() -> IndexPath? { - let selectedScrollCategoryIndexPaths = getSelectedScrollCategoryIndexPaths() - guard let selectedScrollCategoryIndexPath = selectedScrollCategoryIndexPaths.first else { return nil } - return selectedScrollCategoryIndexPath - } - - func getSelectedScrollCategoryIndexPaths() -> [IndexPath] { - let indexPathsForSelectedItems = mainView.contentCollectionView.indexPathsForSelectedItems ?? [] - let selectedScrollCategoryIndexPaths = indexPathsForSelectedItems.filter { $0.section == FilterSection.scrollCategories.rawValue } - return selectedScrollCategoryIndexPaths - } -} - -extension ItemFilterBottomSheetViewController { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - mainView.headerView.firstIconButton.rx.tap - .map { Reactor.Action.closeButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.contentCollectionView.rx.itemSelected - .withUnretained(self) - .subscribe { owner, indexPath in - guard let section = FilterSection(rawValue: indexPath.section) else { return } - owner.mainView.contentCollectionView.isScrollEnabled = true - switch section { - case .scrollCategories: - let selectedItems = owner.getSelectedScrollCategoryIndexPaths() - for selectedIndexPath in selectedItems { - if indexPath != selectedIndexPath { owner.mainView.contentCollectionView.deselectItem(at: selectedIndexPath, animated: true) } - } - owner.reactor?.action.onNext(.filterSelected(indexPath: indexPath)) - case .weaponScrolls, .armorsScrolls, .etcScrolls: - let selectedItem = owner.getSelectedScrollCategoryIndexPath() - owner.reactor?.action.onNext(.filterSelected(indexPath: indexPath)) - owner.mainView.contentCollectionView.selectItem(at: selectedItem, animated: false, scrollPosition: .left) - case .level: - owner.mainView.contentCollectionView.deselectItem(at: indexPath, animated: true) - default: - owner.reactor?.action.onNext(.filterSelected(indexPath: indexPath)) - } - owner.view.endEditing(true) - } - .disposed(by: disposeBag) - - mainView.contentCollectionView.rx.itemDeselected - .withUnretained(self) - .subscribe(onNext: { owner, indexPath in - guard let section = FilterSection(rawValue: indexPath.section) else { return } - switch section { - case .weaponScrolls, .armorsScrolls, .etcScrolls: - let selectedItem = owner.getSelectedScrollCategoryIndexPath() - owner.reactor?.action.onNext(.filterDeselected(indexPath: indexPath)) - owner.mainView.contentCollectionView.selectItem(at: selectedItem, animated: false, scrollPosition: .left) - default: - reactor.action.onNext(.filterDeselected(indexPath: indexPath)) - } - }) - .disposed(by: disposeBag) - - mainView.contentCollectionView.rx.didScroll - .withUnretained(self) - .subscribe { owner, _ in - guard owner.isUserScrollDragging else { return } - let visibleIndexPaths = owner.mainView.contentCollectionView.indexPathsForVisibleItems - guard let topIndexPath = visibleIndexPaths.sorted(by: { $0.section < $1.section }).first, - let sectionMaxCount = owner.reactor?.currentState.sections.count else { return } - var currentSection: Int = sectionMaxCount - 1 - if topIndexPath.section < sectionMaxCount { currentSection = topIndexPath.section == 0 ? 0 : topIndexPath.section - 1 } - owner.mainView.categoryCollectionView.selectItem( - at: .init(row: currentSection, section: 0), - animated: true, - scrollPosition: .centeredHorizontally - ) - owner.underLineController.animateIndicatorToSelectedItem() - } - .disposed(by: disposeBag) - - mainView.contentCollectionView.rx.willBeginDragging - .withUnretained(self) - .subscribe { owner, _ in - owner.isUserScrollDragging = true - } - .disposed(by: disposeBag) - - mainView.contentCollectionView.rx.didEndDecelerating - .withUnretained(self) - .subscribe { owner, _ in - owner.isUserScrollDragging = false - } - .disposed(by: disposeBag) - - mainView.categoryCollectionView.rx.itemSelected - .withUnretained(self) - .subscribe { owner, indexPath in - owner.mainView.categoryCollectionView.scrollToItem(at: indexPath, at: .centeredHorizontally, animated: true) - let section = indexPath.row == 6 ? 10 : indexPath.row == 0 ? 0 : indexPath.row + 1 - owner.underLineController.animateIndicatorToSelectedItem() - owner.mainView.contentCollectionView.scrollToItem(at: .init(row: 0, section: section), at: .top, animated: true) - } - .disposed(by: disposeBag) - - let tapGesture = UITapGestureRecognizer() - tapGesture.cancelsTouchesInView = false - mainView.contentCollectionView.addGestureRecognizer(tapGesture) - - tapGesture.rx.event - .bind { [weak self] _ in - self?.view.endEditing(true) - } - .disposed(by: disposeBag) - - mainView.clearButton.rx.tap - .withUnretained(self) - .subscribe(onNext: { owner, _ in - // Reactor에 액션 전달 - owner.reactor?.action.onNext(.resetFilters) - - if let cell = owner.mainView.contentCollectionView.cellForItem(at: IndexPath(row: 0, section: 1)) as? FilterLevelSectionCell { - cell.levelSectionView.slider.lowerValue = 0 - cell.levelSectionView.slider.upperValue = 200 - } - // UI에서 직접 deselect - owner.mainView.contentCollectionView.indexPathsForSelectedItems?.forEach { - owner.mainView.contentCollectionView.deselectItem(at: $0, animated: false) - } - }) - .disposed(by: disposeBag) - - mainView.headerView.firstIconButton.rx.tap - .map { Reactor.Action.closeButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.applyButton.rx.tap - .withUnretained(self) - .compactMap { _, _ in - - let state = reactor.currentState - - var selectedItems: [(String, String)] = [] - - for indexPath in state.selectedItemIndexes { - guard let section = ItemFilterBottomSheetViewController.FilterSection(rawValue: indexPath.section) else { continue } - - switch section { - case .level: - selectedItems.append(("레벨", "레벨 \(state.levelRange.low) ~ \(state.levelRange.high)")) - case .job: - selectedItems.append(("직업", state.jobs[indexPath.row])) - case .weapons: - selectedItems.append(("무기", state.weapons[indexPath.row])) - case .projectiles: - selectedItems.append(("발사체", state.projectiles[indexPath.row])) - case .armors: - selectedItems.append(("방어구", state.armors[indexPath.row])) - case .accessories: - selectedItems.append(("장신구", state.accessories[indexPath.row])) - case .scrollCategories: - selectedItems.append(("주문서", state.scrollCategories[indexPath.row])) - case .weaponScrolls: - // 기존 방식대로 하게 되면 주문서 탭 변경시 각 scrolls가 빈배열 처리되서 오류 - selectedItems.append(("무기주문서", state.originWeaponScrolls[indexPath.row])) - case .armorsScrolls: - selectedItems.append(("방어구주문서", state.originArmorScrolls[indexPath.row])) - case .etcScrolls: - selectedItems.append(("기타주문서", state.originEtcScrolls[indexPath.row])) - case .etcItems: - selectedItems.append(("기타아이템", state.etcItems[indexPath.row])) - } - } - return Reactor.Action.applyButtonTapped(selectedItems) - } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - reactor.state - .map { (scrollTypes: $0.scrollCategories, weaponScrolls: $0.weaponScrolls, armorScrolls: $0.armorScrolls, etcScrolls: $0.etcScrolls) } - .distinctUntilChanged { $0 == $1 } - .skip(1) - .withUnretained(self) - .subscribe { owner, scrolls in - guard let dataSource = owner.dataSource else { return } - var snapshot = dataSource.snapshot() - snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .scrollCategories)) - snapshot.appendItems(scrolls.scrollTypes.map { .scrollCategories($0) }, toSection: .scrollCategories) - snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .weaponScrolls)) - snapshot.appendItems(scrolls.weaponScrolls.map { .weaponScrolls($0) }, toSection: .weaponScrolls) - snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .armorsScrolls)) - snapshot.appendItems(scrolls.armorScrolls.map { .armorScrolls($0) }, toSection: .armorsScrolls) - snapshot.deleteItems(snapshot.itemIdentifiers(inSection: .etcScrolls)) - snapshot.appendItems(scrolls.etcScrolls.map { .etcScrolls($0) }, toSection: .etcScrolls) - owner.dataSource.apply(snapshot, animatingDifferences: false) { - - guard let selectedItem = owner.getSelectedScrollCategoryIndexPath() else { return } - var targetIndexPath: [IndexPath] = [] - switch selectedItem.row { - case 0: - targetIndexPath = owner.reactor?.currentState.selectedItemIndexes.filter { FilterSection(rawValue: $0.section) == .weaponScrolls } ?? [] - case 1: - targetIndexPath = owner.reactor?.currentState.selectedItemIndexes.filter { FilterSection(rawValue: $0.section) == .armorsScrolls } ?? [] - case 2: - targetIndexPath = owner.reactor?.currentState.selectedItemIndexes.filter { FilterSection(rawValue: $0.section) == .etcScrolls } ?? [] - default: - break - } - for target in targetIndexPath { - let count = owner.mainView.contentCollectionView.numberOfItems(inSection: target.section) - if count > target.row { - owner.mainView.contentCollectionView.selectItem(at: target, animated: true, scrollPosition: .left) - } - } - - } - } - .disposed(by: disposeBag) - - reactor.state - .map { $0.selectedItemIndexes } - .withUnretained(self) - .subscribe { owner, indexPaths in - owner.mainView.selectedItemCollectionView.isHidden = indexPaths.isEmpty - owner.mainView.selectedItemCollectionView.reloadData() - } - .disposed(by: disposeBag) - rx.viewDidLoad - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .subscribe { [weak self] route in - guard let self = self else { return } - switch route { - case .dismiss: - self.dismiss(animated: true) - case .dismissWithSelection(let selectedItems): - self.onFilterSelected?(selectedItems) - self.dismiss(animated: true) - default: - break - } - } - .disposed(by: disposeBag) - } -} - -extension ItemFilterBottomSheetViewController: UICollectionViewDataSource { - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - guard let reactor = reactor else { return 0 } - if collectionView == mainView.categoryCollectionView { - return reactor.currentState.sections.count - } else { - return reactor.currentState.selectedItemIndexes.count - } - } - - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let reactor = reactor else { return UICollectionViewCell() } - if collectionView == mainView.categoryCollectionView { - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: PageTabbarCell.identifier, for: indexPath) as! PageTabbarCell - let title = reactor.currentState.sections[indexPath.row] - cell.inject(title: title) - return cell - } else { - let cell = collectionView.dequeueReusableCell(withReuseIdentifier: TagChipCell.identifier, for: indexPath) as! TagChipCell - let titles = reactor.currentState.selectedItemIndexes.map { indexPath -> String in - guard let section = ItemFilterBottomSheetViewController.FilterSection(rawValue: indexPath.section) else { return "" } - switch section { - case .job: - return reactor.currentState.jobs[indexPath.row] - case .weapons: - return reactor.currentState.weapons[indexPath.row] - case .projectiles: - return reactor.currentState.projectiles[indexPath.row] - case .armors: - return reactor.currentState.armors[indexPath.row] - case .accessories: - return reactor.currentState.accessories[indexPath.row] - case .weaponScrolls: - return reactor.currentState.originWeaponScrolls[indexPath.row] - case .armorsScrolls: - return reactor.currentState.originArmorScrolls[indexPath.row] - case .etcScrolls: - return reactor.currentState.originEtcScrolls[indexPath.row] - case .etcItems: - return reactor.currentState.etcItems[indexPath.row] - case .level: - let range = reactor.currentState.levelRange - return "\(range.low ?? 0) ~ \(range.high ?? 200)" - default: - return "" - } - } - cell.inject(title: titles[indexPath.row], style: .normal) - cell.button.cancelButton.rx.tap - .withUnretained(self) - .subscribe { owner, _ in - let deselectedIndex = reactor.currentState.selectedItemIndexes[indexPath.row] - let section = FilterSection(rawValue: deselectedIndex.section) - switch section { - case .level: - if let cell = owner.mainView.contentCollectionView.cellForItem(at: deselectedIndex) as? FilterLevelSectionCell { - cell.levelSectionView.slider.lowerValue = 0 - cell.levelSectionView.slider.upperValue = 200 - } - owner.reactor?.action.onNext(.filterDeselected(indexPath: deselectedIndex)) - case .weaponScrolls, .armorsScrolls, .etcScrolls: - let selectedItem = owner.getSelectedScrollCategoryIndexPath() - owner.reactor?.action.onNext(.filterDeselected(indexPath: deselectedIndex)) - owner.mainView.contentCollectionView.deselectItem(at: deselectedIndex, animated: false) - owner.mainView.contentCollectionView.selectItem(at: selectedItem, animated: false, scrollPosition: .left) - default: - owner.mainView.contentCollectionView.deselectItem(at: deselectedIndex, animated: true) - owner.reactor?.action.onNext(.filterDeselected(indexPath: deselectedIndex)) - } - } - .disposed(by: cell.disposeBag) - return cell - } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/Views/FilterLevelSectionCell.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/Views/FilterLevelSectionCell.swift deleted file mode 100644 index ae04c6ee..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/Views/FilterLevelSectionCell.swift +++ /dev/null @@ -1,59 +0,0 @@ -import UIKit - -import DesignSystem - -import RxCocoa -import RxSwift -import SnapKit - -public class FilterLevelSectionCell: UICollectionViewCell { - public let levelSectionView: FilterLevelSectionView = { - let view = FilterLevelSectionView() - return view - }() - - public var disposeBag = DisposeBag() - - override init(frame: CGRect) { - super.init(frame: frame) - addViews() - setupConstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override public func prepareForReuse() { - super.prepareForReuse() - disposeBag = DisposeBag() - levelSectionView.disposeBag = DisposeBag() - levelSectionView.bind() - } -} - -// MARK: - SetUp -private extension FilterLevelSectionCell { - func addViews() { - contentView.addSubview(levelSectionView) - } - - func setupConstraints() { - levelSectionView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } -} - -extension FilterLevelSectionCell { - struct Input { - let lowValue: Int? - let highValue: Int? - } - - func inject(input: Input) { - levelSectionView.slider.lowerValue = input.lowValue.map { CGFloat($0) } - levelSectionView.slider.upperValue = input.highValue.map { CGFloat($0) } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/Views/FilterLevelSectionView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/Views/FilterLevelSectionView.swift deleted file mode 100644 index 800bfe57..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/Views/FilterLevelSectionView.swift +++ /dev/null @@ -1,193 +0,0 @@ -import UIKit - -import DesignSystem - -import RxCocoa -import RxSwift -import SnapKit - -public class FilterLevelSectionView: UIView { - private enum Constant { - static let inputBoxWidth: CGFloat = (UIScreen.main.bounds.width - (16 * 2) - dashWidth - (stackViewSpacing * 2)) / 2 - static let dashWidth: CGFloat = 7 - static let stackViewSpacing: CGFloat = 6 - static let sliderTopOffSet: CGFloat = 20 - static let sliderBottomMargin: CGFloat = 12 - static let sliderHeight: CGFloat = 26 - } - - private var isEdit = false - - let leftInputBox: InputBox = { - let box = InputBox(label: "범위", placeHodler: "0") - box.textField.keyboardType = .numberPad - return box - }() - - private let dashLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .b_m_r, text: "-") - return label - }() - - let rightInputBox: InputBox = { - let box = InputBox(placeHodler: "200") - box.textField.keyboardType = .numberPad - return box - }() - - private let stackView: UIStackView = { - let view = UIStackView() - view.axis = .horizontal - view.alignment = .bottom - view.spacing = Constant.stackViewSpacing - return view - }() - - public let slider: FilterSlider - - private let lowerLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .b_s_r, text: "0", color: .neutral500) - return label - }() - - private let middleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .b_s_r, text: "100", color: .neutral500) - return label - }() - - private let upperLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .b_s_r, text: "200", color: .neutral500) - return label - }() - - public var disposeBag = DisposeBag() - - public init(initialLowerValue: CGFloat = 0, initialUpperValue: CGFloat = 200) { - self.slider = FilterSlider(minimumValue: 0, maximumValue: 200, initialLowerValue: initialLowerValue, initialUpperValue: initialUpperValue) - super.init(frame: .zero) - addViews() - setupConstraints() - bind() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension FilterLevelSectionView { - func addViews() { - addSubview(stackView) - - stackView.addArrangedSubview(leftInputBox) - stackView.addArrangedSubview(dashLabel) - stackView.addArrangedSubview(rightInputBox) - addSubview(slider) - addSubview(lowerLabel) - addSubview(middleLabel) - addSubview(upperLabel) - } - - func setupConstraints() { - stackView.snp.makeConstraints { make in - make.top.horizontalEdges.equalToSuperview() - } - leftInputBox.snp.makeConstraints { make in - make.width.equalTo(Constant.inputBoxWidth) - } - rightInputBox.snp.makeConstraints { make in - make.width.equalTo(Constant.inputBoxWidth) - } - dashLabel.snp.makeConstraints { make in - make.height.equalTo(rightInputBox.snp.height) - make.width.equalTo(Constant.dashWidth) - } - slider.snp.makeConstraints { make in - make.top.equalTo(stackView.snp.bottom).offset(Constant.sliderTopOffSet) - make.height.equalTo(Constant.sliderHeight) - make.horizontalEdges.equalToSuperview() - } - lowerLabel.snp.makeConstraints { make in - make.top.equalTo(slider.snp.bottom).offset(Constant.sliderBottomMargin) - make.bottom.leading.equalToSuperview() - } - middleLabel.snp.makeConstraints { make in - make.top.equalTo(slider.snp.bottom).offset(Constant.sliderBottomMargin) - make.bottom.centerX.equalToSuperview() - } - upperLabel.snp.makeConstraints { make in - make.top.equalTo(slider.snp.bottom).offset(Constant.sliderBottomMargin) - make.bottom.trailing.equalToSuperview() - } - } -} - -public extension FilterLevelSectionView { - func bind() { - slider.lowerValueObservable - .withUnretained(self) - .subscribe { owner, value in - guard !owner.isEdit else { return } - let lowValue = Int(value ?? 0) - owner.leftInputBox.textField.text = value == owner.slider.minimumValue ? nil : "\(lowValue)" - } - .disposed(by: disposeBag) - - slider.upperValueObservable - .withUnretained(self) - .subscribe { owner, value in - guard !owner.isEdit else { return } - let upperValue = Int(value ?? 200) - owner.rightInputBox.textField.text = value == owner.slider.maximumValue ? nil : "\(upperValue)" - } - .disposed(by: disposeBag) - - leftInputBox.textField.rx.text.orEmpty - .debounce(.milliseconds(100), scheduler: MainScheduler.instance) - .withUnretained(self) - .subscribe { owner, text in - guard !owner.isEdit, !text.isEmpty else { return } - if let value = Double(text) { - owner.slider.lowerValue = value - } - } - .disposed(by: disposeBag) - - rightInputBox.textField.rx.text.orEmpty - .debounce(.milliseconds(100), scheduler: MainScheduler.instance) - .withUnretained(self) - .subscribe { owner, text in - guard !owner.isEdit, !text.isEmpty else { return } - if let value = Double(text) { - owner.slider.upperValue = value - } - } - .disposed(by: disposeBag) - - let leftBoxDidEnd = leftInputBox.textField.rx.controlEvent(.editingDidEnd).asObservable() - let rightBoxDidEnd = rightInputBox.textField.rx.controlEvent(.editingDidEnd).asObservable() - - Observable.merge([leftBoxDidEnd, rightBoxDidEnd]) - .withUnretained(self) - .debounce(.seconds(1), scheduler: MainScheduler.instance) - .subscribe { owner, _ in - if let leftValue = Double(owner.leftInputBox.textField.text ?? "1"), let rightValue = Double(owner.rightInputBox.textField.text ?? "200") { - if leftValue > rightValue { - owner.isEdit = true - owner.leftInputBox.textField.text = "\(Int(rightValue))" - owner.slider.lowerValue = rightValue - owner.rightInputBox.textField.text = "\(Int(leftValue))" - owner.slider.upperValue = leftValue - owner.isEdit = false - } - } - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/Views/FilterSlider.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/Views/FilterSlider.swift deleted file mode 100644 index c43bac3d..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/Views/FilterSlider.swift +++ /dev/null @@ -1,293 +0,0 @@ -import UIKit - -import RxCocoa -import RxSwift -import SnapKit - -public class FilterSlider: UIControl { - // MARK: - Constants - private enum Constant { - static let thumbSize: CGFloat = 26 - static let trackHeight: CGFloat = 8 - static let trackCornerRadius: CGFloat = 4 - static let thumbCornerRadius: CGFloat = thumbSize / 2 - static let thumbBorderWidth: CGFloat = 1 - static let thumbShadowOpacity: Float = 1 - static let thumbShadowRadius: CGFloat = 10 - static let thumbShadowOffset = CGSize(width: 4, height: 4) - static let expandedTouchInset: CGFloat = -10 - static let animationDuration: TimeInterval = 0.25 - } - - // MARK: - Value Relays - private let minimumValueRelay = BehaviorRelay(value: 0) - private let maximumValueRelay = BehaviorRelay(value: 200) - private let lowerValueRelay = BehaviorRelay(value: nil) - private let upperValueRelay = BehaviorRelay(value: nil) - - // MARK: - Public properties - public var minimumValue: CGFloat { - get { minimumValueRelay.value } - set { minimumValueRelay.accept(newValue) } - } - - public var maximumValue: CGFloat { - get { maximumValueRelay.value } - set { maximumValueRelay.accept(newValue) } - } - - public var lowerValue: CGFloat? { - get { lowerValueRelay.value } - set { lowerValueRelay.accept(boundValue(newValue ?? minimumValue, lower: minimumValue, upper: maximumValue)) } - } - - public var upperValue: CGFloat? { - get { upperValueRelay.value } - set { upperValueRelay.accept(boundValue(newValue ?? maximumValue, lower: minimumValue, upper: maximumValue)) } - } - - public let isThumbTracking: BehaviorRelay = .init(value: false) - - // MARK: - Observables - public var minimumValueObservable: Observable { minimumValueRelay.asObservable() } - public var maximumValueObservable: Observable { maximumValueRelay.asObservable() } - public var lowerValueObservable: Observable { lowerValueRelay.asObservable() } - public var upperValueObservable: Observable { upperValueRelay.asObservable() } - - // MARK: - UI Elements - private let trackView = UIView() - private let selectedTrackView = UIView() - private let lowerThumb = UIView() - private let upperThumb = UIView() - - private var previousLocation = CGPoint.zero - - private var selectedTrackLeadingConstraint: Constraint? - private var selectedTrackTrailingConstraint: Constraint? - private var lowerThumbCenterX: Constraint? - private var upperThumbCenterX: Constraint? - - private enum Thumb { - case lower, upper, none - } - - private var activeThumb: Thumb = .none - - private let disposeBag = DisposeBag() - - // MARK: - Init - public init( - minimumValue: CGFloat, - maximumValue: CGFloat, - initialLowerValue: CGFloat, - initialUpperValue: CGFloat - ) { - super.init(frame: .zero) - - minimumValueRelay.accept(minimumValue) - maximumValueRelay.accept(maximumValue) - - lowerValueRelay.accept(boundValue(initialLowerValue, lower: minimumValue, upper: maximumValue)) - upperValueRelay.accept(boundValue(initialUpperValue, lower: minimumValue, upper: maximumValue)) - - setup() - bindValues() - } - - public required init?(coder: NSCoder) { - super.init(coder: coder) - setup() - bindValues() - } - - // MARK: - Setup UI - private func setup() { - trackView.backgroundColor = .neutral200 - trackView.layer.cornerRadius = Constant.trackCornerRadius - addSubview(trackView) - trackView.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview() - make.centerY.equalToSuperview() - make.height.equalTo(Constant.trackHeight) - } - - selectedTrackView.backgroundColor = .primary700 - selectedTrackView.layer.cornerRadius = Constant.trackCornerRadius - addSubview(selectedTrackView) - selectedTrackView.snp.makeConstraints { make in - make.centerY.equalTo(trackView) - make.height.equalTo(Constant.trackHeight) - selectedTrackLeadingConstraint = make.leading.equalToSuperview().constraint - selectedTrackTrailingConstraint = make.trailing.equalToSuperview().constraint - } - - [lowerThumb, upperThumb].forEach { - $0.backgroundColor = .whiteMLS - $0.layer.borderColor = UIColor.neutral200.cgColor - $0.layer.borderWidth = Constant.thumbBorderWidth - $0.layer.cornerRadius = Constant.thumbCornerRadius - $0.isUserInteractionEnabled = false - $0.layer.shadowColor = UIColor.black.withAlphaComponent(0.12).cgColor - $0.layer.shadowOpacity = Constant.thumbShadowOpacity - $0.layer.shadowRadius = Constant.thumbShadowRadius - $0.layer.shadowOffset = Constant.thumbShadowOffset - addSubview($0) - $0.snp.makeConstraints { make in - make.width.height.equalTo(Constant.thumbSize) - make.centerY.equalTo(trackView) - } - } - - lowerThumb.snp.makeConstraints { make in - lowerThumbCenterX = make.centerX.equalToSuperview().constraint - } - upperThumb.snp.makeConstraints { make in - upperThumbCenterX = make.centerX.equalToSuperview().constraint - } - } - - // MARK: - Bindings - private func bindValues() { - Observable.combineLatest(minimumValueRelay, maximumValueRelay) - .subscribe(onNext: { [weak self] minVal, maxVal in - guard let self = self else { return } - let clampedLower = self.boundValue(self.lowerValueRelay.value ?? self.minimumValue, lower: minVal, upper: maxVal) - let clampedUpper = self.boundValue(self.upperValueRelay.value ?? self.maximumValue, lower: minVal, upper: maxVal) - if clampedLower != self.lowerValueRelay.value { - self.lowerValueRelay.accept(clampedLower) - } - if clampedUpper != self.upperValueRelay.value { - self.upperValueRelay.accept(clampedUpper) - } - self.animateUpdate() - }) - .disposed(by: disposeBag) - - Observable.merge(lowerValueRelay.asObservable(), upperValueRelay.asObservable()) - .subscribe(onNext: { [weak self] _ in - self?.animateUpdate() - self?.sendActions(for: .valueChanged) - }) - .disposed(by: disposeBag) - } - - // MARK: - Layout - override public func layoutSubviews() { - super.layoutSubviews() - updateTrackAndThumb(animated: false) - lowerThumb.frame = lowerThumb.frame.integral - upperThumb.frame = upperThumb.frame.integral - } - - private func position(for value: CGFloat) -> CGFloat { - guard maximumValue != minimumValue else { return Constant.thumbSize / 2 } - let availableWidth = bounds.width - Constant.thumbSize - return (value - minimumValue) / (maximumValue - minimumValue) * availableWidth + Constant.thumbSize / 2 - } - - private func updateTrackAndThumb(animated: Bool) { - let lowerX = position(for: lowerValueRelay.value ?? minimumValue) - let upperX = position(for: upperValueRelay.value ?? maximumValue) - - lowerThumbCenterX?.update(offset: lowerX - bounds.midX) - upperThumbCenterX?.update(offset: upperX - bounds.midX) - - let minX = min(lowerX, upperX) - let maxX = max(lowerX, upperX) - - selectedTrackLeadingConstraint?.update(offset: minX) - selectedTrackTrailingConstraint?.update(offset: -(bounds.width - maxX)) - - if animated { - UIView.animate(withDuration: Constant.animationDuration, delay: 0, options: [.curveEaseInOut]) { - self.layoutIfNeeded() - } - } else { - layoutIfNeeded() - } - } - - private func animateUpdate() { - updateTrackAndThumb(animated: true) - } - - private func boundValue(_ value: CGFloat, lower: CGFloat, upper: CGFloat) -> CGFloat { - return min(max(value, lower), upper) - } - - // MARK: - Touch Handling - override public func beginTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { - isThumbTracking.accept(true) - previousLocation = touch.location(in: self) - - if lowerThumb.frame.insetBy(dx: Constant.expandedTouchInset, dy: Constant.expandedTouchInset).contains(previousLocation) { - activeThumb = .lower - } else if upperThumb.frame.insetBy(dx: Constant.expandedTouchInset, dy: Constant.expandedTouchInset).contains(previousLocation) { - activeThumb = .upper - } else { - activeThumb = .none - } - - return activeThumb != .none - } - - override public func continueTracking(_ touch: UITouch, with event: UIEvent?) -> Bool { - isThumbTracking.accept(true) - let location = touch.location(in: self) - let deltaLocation = location.x - previousLocation.x - let deltaValue = (maximumValue - minimumValue) * deltaLocation / (bounds.width - Constant.thumbSize) - previousLocation = location - - var newLower = lowerValueRelay.value ?? minimumValue - var newUpper = upperValueRelay.value ?? maximumValue - - switch activeThumb { - case .lower: - newLower += deltaValue - case .upper: - newUpper += deltaValue - case .none: - break - } - - newLower = boundValue(newLower, lower: minimumValue, upper: maximumValue) - newUpper = boundValue(newUpper, lower: minimumValue, upper: maximumValue) - - if newLower > newUpper { - lowerValueRelay.accept(newUpper) - upperValueRelay.accept(newLower) - activeThumb = (activeThumb == .lower) ? .upper : .lower - } else { - lowerValueRelay.accept(newLower) - upperValueRelay.accept(newUpper) - } - - return true - } - - override public func endTracking(_ touch: UITouch?, with event: UIEvent?) { - isThumbTracking.accept(false) - activeThumb = .none - } - - // MARK: - Touch Hit Test - override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? { - if lowerThumb.frame.insetBy(dx: Constant.expandedTouchInset, dy: Constant.expandedTouchInset).contains(point) { - return self - } - - if upperThumb.frame.insetBy(dx: Constant.expandedTouchInset, dy: Constant.expandedTouchInset).contains(point) { - return self - } - - return super.hitTest(point, with: event) - } -} - -public extension FilterSlider { - func reset(lower: CGFloat, upper: CGFloat) { - lowerValueRelay.accept(boundValue(lower, lower: minimumValue, upper: maximumValue)) - upperValueRelay.accept(boundValue(upper, lower: minimumValue, upper: maximumValue)) - animateUpdate() - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/Views/ItemFilterBottomSheetView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/Views/ItemFilterBottomSheetView.swift deleted file mode 100644 index 1e45758b..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/ItemFilterBottomSheet/Views/ItemFilterBottomSheetView.swift +++ /dev/null @@ -1,154 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -final class ItemFilterBottomSheetView: UIView { - private enum Constant { - static let horizontalInset: CGFloat = 16 - static let buttonSpacing: CGFloat = 8 - static let buttonSuperViewSize = UIScreen.main.bounds.width - (Constant.horizontalInset * 2) - buttonSpacing - static let buttonStackViewTopMargin: CGFloat = 12 - static let buttonStackViewBottomMargin: CGFloat = 16 - static let collectionViewTopOffset = 8 - static let categoryCollectionViewHeight = 40 - static let dividerHeight = 1 - static let selectedItemCollectionViewHeight = 56 - static let contentCollectionViewTopMargin = 32 - } - - // MARK: - Properties - let headerView: Header = .init(style: .filter, title: "필터") - - private let toolBarStackView: UIStackView = { - let view = UIStackView() - view.spacing = 0 - view.axis = .vertical - return view - }() - - private let buttonStackView: UIStackView = { - let view = UIStackView() - view.axis = .horizontal - view.spacing = 8 - view.isLayoutMarginsRelativeArrangement = true - view.layoutMargins = .init( - top: Constant.buttonStackViewTopMargin, - left: Constant.horizontalInset, - bottom: Constant.buttonStackViewBottomMargin, - right: Constant.horizontalInset - ) - - return view - }() - - public let clearButton: CommonButton = { - let button = CommonButton(style: .border, title: "초기화", disabledTitle: nil) - return button - }() - - public let applyButton: CommonButton = { - let button = CommonButton(style: .normal, title: "적용하기", disabledTitle: nil) - return button - }() - - private let buttonStackViewDividerView: UIView = { - let view = UIView() - view.backgroundColor = .neutral200 - return view - }() - - public let categoryCollectionView: UICollectionView = { - let view = UICollectionView(frame: .zero, collectionViewLayout: .init()) - view.isScrollEnabled = false - return view - }() - - public let contentCollectionView: UICollectionView = { - let view = UICollectionView(frame: .zero, collectionViewLayout: .init()) - view.contentInset = .init(top: 0, left: 0, bottom: 40, right: 0) - view.allowsMultipleSelection = true - return view - }() - - public let selectedItemCollectionView: UICollectionView = { - let view = UICollectionView(frame: .zero, collectionViewLayout: .init()) - view.alwaysBounceVertical = false - view.isHidden = true - return view - }() - - private let selectedItemDividerView: UIView = { - let view = UIView() - view.backgroundColor = .neutral200 - return view - }() - - // MARK: - init - init() { - super.init(frame: .zero) - - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension ItemFilterBottomSheetView { - func addViews() { - addSubview(headerView) - addSubview(toolBarStackView) - addSubview(categoryCollectionView) - addSubview(contentCollectionView) - toolBarStackView.addArrangedSubview(selectedItemCollectionView) - toolBarStackView.addArrangedSubview(buttonStackView) - buttonStackView.addArrangedSubview(clearButton) - buttonStackView.addArrangedSubview(applyButton) - buttonStackView.addSubview(buttonStackViewDividerView) - toolBarStackView.addSubview(selectedItemDividerView) - } - - func setupConstraints() { - headerView.snp.makeConstraints { make in - make.top.equalToSuperview().inset(Constant.horizontalInset) - make.horizontalEdges.equalToSuperview() - } - toolBarStackView.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview() - make.bottom.equalToSuperview() - } - clearButton.snp.makeConstraints { make in - make.width.equalTo(Constant.buttonSuperViewSize * 0.3) - } - categoryCollectionView.snp.makeConstraints { make in - make.top.equalTo(headerView.snp.bottom).offset(Constant.collectionViewTopOffset) - make.horizontalEdges.equalToSuperview() - make.height.equalTo(Constant.categoryCollectionViewHeight) - } - contentCollectionView.snp.makeConstraints { make in - make.top.equalTo(categoryCollectionView.snp.bottom).offset(Constant.contentCollectionViewTopMargin) - make.horizontalEdges.equalToSuperview() - make.bottom.equalTo(toolBarStackView.snp.top) - } - buttonStackViewDividerView.snp.makeConstraints { make in - make.top.horizontalEdges.equalToSuperview() - make.height.equalTo(Constant.dividerHeight) - } - selectedItemCollectionView.snp.makeConstraints { make in - make.height.equalTo(Constant.selectedItemCollectionViewHeight) - } - selectedItemDividerView.snp.makeConstraints { make in - make.top.horizontalEdges.equalToSuperview() - make.height.equalTo(Constant.dividerHeight) - } - } - - func configureUI() {} -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/MonsterFilterBottomSheet/MonsterFilterBottomSheetFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/MonsterFilterBottomSheet/MonsterFilterBottomSheetFactoryImpl.swift deleted file mode 100644 index 40e900bd..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/MonsterFilterBottomSheet/MonsterFilterBottomSheetFactoryImpl.swift +++ /dev/null @@ -1,18 +0,0 @@ -import Foundation - -import BaseFeature -import DictionaryFeatureInterface - -public struct MonsterFilterBottomSheetFactoryImpl: MonsterFilterBottomSheetFactory { - public init() {} - - public func make(startLevel: Int, endLevel: Int, onFilterSelected: @escaping (Int, Int) -> Void) -> BaseViewController & ModalPresentable { - let viewController = MonsterFilterBottomSheetViewController() - viewController.startLevel = CGFloat(startLevel) - viewController.endLevel = CGFloat(endLevel) - viewController.reactor = MonsterFilterBottomSheetReactor(startLevel: startLevel, endLevel: endLevel) - viewController.onFilterSelected = onFilterSelected - - return viewController - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/MonsterFilterBottomSheet/MonsterFilterBottomSheetReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/MonsterFilterBottomSheet/MonsterFilterBottomSheetReactor.swift deleted file mode 100644 index a3d63887..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/MonsterFilterBottomSheet/MonsterFilterBottomSheetReactor.swift +++ /dev/null @@ -1,69 +0,0 @@ -import ReactorKit -import RxSwift - -public final class MonsterFilterBottomSheetReactor: Reactor { - public enum Route { - case none - case dismiss - case dismissWithLevelRange(start: Int, end: Int) - case clear - } - - // MARK: - Reactor - public enum Action { - case cancelButtonTapped - case applyButtonTapped(start: Int, end: Int) - case clearButtonTapped - } - - public enum Mutation { - case navigateTo(route: Route) - } - - public struct State { - @Pulse var route: Route = .none - } - - // MARK: - properties - public var initialState: State - var disposeBag = DisposeBag() - - // MARK: - init - public init(startLevel: Int = 1, endLevel: Int = 200) { - self.initialState = State() - } - - // MARK: - Reactor Methods - public func mutate(action: Action) -> Observable { - switch action { - case .cancelButtonTapped: - return Observable.just(.navigateTo(route: .dismiss)) - case let .applyButtonTapped(start, end): - guard start <= end else { - return .empty() - } - - return .just(.navigateTo(route: .dismissWithLevelRange(start: start, end: end))) - case .clearButtonTapped: - return .just(.navigateTo(route: .clear)) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .navigateTo(let route): - switch route { - case .dismiss: - newState.route = route - case .dismissWithLevelRange: - newState.route = route - default: - newState.route = route - } - } - - return newState - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/MonsterFilterBottomSheet/MonsterFilterBottomSheetView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/MonsterFilterBottomSheet/MonsterFilterBottomSheetView.swift deleted file mode 100644 index e8e5e901..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/MonsterFilterBottomSheet/MonsterFilterBottomSheetView.swift +++ /dev/null @@ -1,121 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -public class MonsterFilterBottomSheetView: UIView { - private enum Constant { - static let horizontalInset: CGFloat = 16 - static let buttonSpacing: CGFloat = 8 - static let buttonSuperViewSize = UIScreen.main.bounds.width - (Constant.horizontalInset * 2) - buttonSpacing - static let buttonStackViewTopMargin: CGFloat = 12 - static let buttonStackViewBottomMargin: CGFloat = 16 - static let dividerHeight = 1 - static let itemBottomSpacing = 31 - } - - // MARK: - Properties - let tapGesture = UITapGestureRecognizer() - var lowerLevel: CGFloat - var upperLevel: CGFloat - - // MARK: - Components - let header: Header = { - let header = Header(style: .filter, title: "필터") - return header - }() - - private let sectionTitleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .sub_m_b, text: "레벨", alignment: .left) - return label - }() - - let levelRangeView: FilterLevelSectionView - - private let dividerView: UIView = { - let view = UIView() - view.backgroundColor = .neutral200 - return view - }() - - private let buttonStackView: UIStackView = { - let view = UIStackView() - view.axis = .horizontal - view.spacing = 8 - return view - }() - - public let clearButton: CommonButton = { - let button = CommonButton(style: .border, title: "초기화", disabledTitle: nil) - return button - }() - - public let applyButton: CommonButton = { - let button = CommonButton(style: .normal, title: "적용하기", disabledTitle: nil) - return button - }() - - // MARK: - init - init(lowerLevel: CGFloat, upperLevel: CGFloat) { - self.lowerLevel = lowerLevel - self.upperLevel = upperLevel - self.levelRangeView = FilterLevelSectionView(initialLowerValue: lowerLevel, initialUpperValue: upperLevel) - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension MonsterFilterBottomSheetView { - func addViews() { - addSubview(header) - addSubview(sectionTitleLabel) - addSubview(levelRangeView) - addSubview(dividerView) - addSubview(buttonStackView) - buttonStackView.addArrangedSubview(clearButton) - buttonStackView.addArrangedSubview(applyButton) - } - - func setupConstraints() { - header.snp.makeConstraints { make in - make.top.equalToSuperview().inset(16) - make.horizontalEdges.equalToSuperview() - } - sectionTitleLabel.snp.makeConstraints { make in - make.top.equalTo(header.snp.bottom).offset(Constant.itemBottomSpacing) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - } - levelRangeView.snp.makeConstraints { make in - make.top.equalTo(sectionTitleLabel.snp.bottom).offset(10) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - } - dividerView.snp.makeConstraints { make in - make.top.equalTo(levelRangeView.snp.bottom).offset(Constant.itemBottomSpacing) - make.height.equalTo(Constant.dividerHeight) - make.horizontalEdges.equalToSuperview() - } - buttonStackView.snp.makeConstraints { make in - make.top.equalTo(dividerView.snp.top).offset(Constant.buttonStackViewTopMargin) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.bottom.equalToSuperview().inset(Constant.buttonStackViewBottomMargin) - } - clearButton.snp.makeConstraints { make in - make.width.equalTo(Constant.buttonSuperViewSize * 0.3) - } - } - - func configureUI() { - tapGesture.cancelsTouchesInView = false - addGestureRecognizer(tapGesture) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/MonsterFilterBottomSheet/MonsterFilterBottomSheetViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/MonsterFilterBottomSheet/MonsterFilterBottomSheetViewController.swift deleted file mode 100644 index b94640af..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/MonsterFilterBottomSheet/MonsterFilterBottomSheetViewController.swift +++ /dev/null @@ -1,133 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem - -import ReactorKit -import RxKeyboard -import RxSwift -import SnapKit - -public final class MonsterFilterBottomSheetViewController: BaseViewController, ModalPresentable, View { - public var modalHeight: CGFloat? - - public typealias Reactor = MonsterFilterBottomSheetReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - var startLevel: CGFloat = 1 - var endLevel: CGFloat = 200 - - public lazy var mainView = MonsterFilterBottomSheetView(lowerLevel: startLevel, upperLevel: endLevel) - - public var onFilterSelected: ((Int, Int) -> Void)? -} - -// MARK: - Life Cycle -public extension MonsterFilterBottomSheetViewController { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - setupKeyboard() - } -} - -// MARK: - SetUp -private extension MonsterFilterBottomSheetViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } - - func configureUI() {} - - func setupKeyboard() { - setupKeyboard { [weak self] height in - self?.mainView.snp.remakeConstraints { make in - make.top.horizontalEdges.equalToSuperview() - make.bottom.equalToSuperview().inset(height) - } - } - } -} - -extension MonsterFilterBottomSheetViewController { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - mainView.header.firstIconButton.rx.tap - .map { Reactor.Action.cancelButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.clearButton.rx.tap - .map { Reactor.Action.clearButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.applyButton.rx.tap - .withUnretained(self) - .compactMap { _, _ in - let startText = (self.mainView.levelRangeView.leftInputBox.textField.text?.isEmpty == false) - ? self.mainView.levelRangeView.leftInputBox.textField.text! - : "1" - - let endText = (self.mainView.levelRangeView.rightInputBox.textField.text?.isEmpty == false) - ? self.mainView.levelRangeView.rightInputBox.textField.text! - : "200" - guard let start = Int(startText), - let end = Int(endText) - else { - return nil - } - return Reactor.Action.applyButtonTapped(start: start, end: end) - } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .subscribe { owner, route in - switch route { - case .dismiss: - owner.dismissCurrentModal() - case .dismissWithLevelRange(let start, let end): - owner.onFilterSelected?(start, end) - owner.dismissCurrentModal() - case .clear: - owner.mainView.levelRangeView.slider.reset(lower: 1, upper: 200) - default: - break - } - } - .disposed(by: disposeBag) - - mainView.tapGesture.rx.event - .withUnretained(self) - .bind { owner, gesture in - let location = gesture.location(in: owner.mainView) - - if !owner.mainView.levelRangeView.leftInputBox.frame.contains(location), - !owner.mainView.levelRangeView.rightInputBox.frame.contains(location) { - owner.mainView.endEditing(true) - } - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/SortedBottomSheet/SortedBottomSheetFactoryImpl.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/SortedBottomSheet/SortedBottomSheetFactoryImpl.swift deleted file mode 100644 index 54a686ce..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/SortedBottomSheet/SortedBottomSheetFactoryImpl.swift +++ /dev/null @@ -1,14 +0,0 @@ -import BaseFeature -import DictionaryFeatureInterface -import DomainInterface - -public struct SortedBottomSheetFactoryImpl: SortedBottomSheetFactory { - public init() {} - - public func make(sortedOptions: [SortType], selectedIndex: Int, onSelectedIndex: @escaping (Int) -> Void) -> BaseViewController & ModalPresentable { - let viewController = SortedBottomSheetViewController() - viewController.reactor = SortedBottomSheetReactor(sortTypes: sortedOptions, selectedIndex: selectedIndex) - viewController.onSelectedIndex = onSelectedIndex - return viewController - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/SortedBottomSheet/SortedBottomSheetReactor.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/SortedBottomSheet/SortedBottomSheetReactor.swift deleted file mode 100644 index 17b528d4..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/SortedBottomSheet/SortedBottomSheetReactor.swift +++ /dev/null @@ -1,66 +0,0 @@ -import DomainInterface - -import ReactorKit -import RxCocoa -import RxSwift - -public final class SortedBottomSheetReactor: Reactor { - public enum Route { - case none - case dismiss - case dismissWithSave - } - - // MARK: - Reactor - public enum Action { - case cancelButtonTapped - case sortedButtonTapped(index: Int) - case applyButtonTapped - } - - public enum Mutation { - case navigateTo(route: Route) - case setSelectedIndex(index: Int) - } - - public struct State { - var sortTypes: [SortType] - var selectedIndex: Int - var isTabbarHidden: Bool - @Pulse var route: Route = .none - } - - // MARK: - properties - public var initialState: State - var disposeBag = DisposeBag() - - // MARK: - init - public init(sortTypes: [SortType], selectedIndex: Int, isTabbarHidden: Bool = false) { - self.initialState = State(sortTypes: sortTypes, selectedIndex: selectedIndex, isTabbarHidden: isTabbarHidden) - } - - // MARK: - Reactor Methods - public func mutate(action: Action) -> Observable { - switch action { - case .cancelButtonTapped: - return Observable.just(.navigateTo(route: .dismiss)) - case .sortedButtonTapped(let index): - return Observable.just(.setSelectedIndex(index: index)) - case .applyButtonTapped: - return Observable.just(.navigateTo(route: .dismissWithSave)) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .navigateTo(let route): - newState.route = route - case .setSelectedIndex(let index): - newState.selectedIndex = index - } - - return newState - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/SortedBottomSheet/SortedBottomSheetView.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/SortedBottomSheet/SortedBottomSheetView.swift deleted file mode 100644 index 07188061..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/SortedBottomSheet/SortedBottomSheetView.swift +++ /dev/null @@ -1,68 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -final class SortedBottomSheetView: UIView { - private enum Constant { - static let defaultInset: CGFloat = 16 - static let stackViewTopInset = 14 - } - - // MARK: - Properties - let header: Header = { - let header = Header(style: .filter, title: "정렬") - return header - }() - - let sortedStackView: UIStackView = { - let view = UIStackView() - view.axis = .vertical - return view - }() - - let applyButton: CommonButton = { - let button = CommonButton(style: .normal, title: "적용", disabledTitle: nil) - return button - }() - - var sortedButtons: [CheckBoxButton] = [] - - // MARK: - init - init() { - super.init(frame: .zero) - - addViews() - setupConstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension SortedBottomSheetView { - func addViews() { - addSubview(header) - addSubview(sortedStackView) - addSubview(applyButton) - } - - func setupConstraints() { - header.snp.makeConstraints { make in - make.top.equalToSuperview().inset(Constant.defaultInset) - make.horizontalEdges.equalToSuperview() - } - sortedStackView.snp.makeConstraints { make in - make.top.equalTo(header.snp.bottom).offset(Constant.stackViewTopInset) - make.horizontalEdges.equalToSuperview() - } - applyButton.snp.makeConstraints { make in - make.top.equalTo(sortedStackView.snp.bottom).offset(Constant.defaultInset) - make.horizontalEdges.bottom.equalToSuperview().inset(Constant.defaultInset) - } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeature/SortedBottomSheet/SortedBottomSheetViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeature/SortedBottomSheet/SortedBottomSheetViewController.swift deleted file mode 100644 index a5e5ae06..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeature/SortedBottomSheet/SortedBottomSheetViewController.swift +++ /dev/null @@ -1,128 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem -import DomainInterface - -import ReactorKit -import RxCocoa -import RxSwift -import SnapKit - -public final class SortedBottomSheetViewController: BaseViewController, ModalPresentable, View { - public var modalHeight: CGFloat? - - public typealias Reactor = SortedBottomSheetReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - public var onSelectedIndex: ((Int) -> Void)? - - // MARK: - Components - - private var mainView = SortedBottomSheetView() -} - -// MARK: - Life Cycle -public extension SortedBottomSheetViewController { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - } -} - -// MARK: - SetUp -private extension SortedBottomSheetViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } - - private func updateSortedButtons(types: [SortType]) { - mainView.sortedStackView.arrangedSubviews.forEach { - mainView.sortedStackView.removeArrangedSubview($0) - $0.removeFromSuperview() - } - - guard let reactor = reactor else { return } - mainView.sortedButtons = types.enumerated().map { index, type in - let button = CheckBoxButton(style: .listLarge, mainTitle: type.rawValue, subTitle: nil) - - button.rx.tap - .map { Reactor.Action.sortedButtonTapped(index: index) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.sortedStackView.addArrangedSubview(button) - return button - } - } -} - -extension SortedBottomSheetViewController { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - mainView.header.firstIconButton.rx.tap - .map { Reactor.Action.cancelButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.applyButton.rx.tap - .map { Reactor.Action.applyButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - reactor.state - .map { $0.sortTypes } - .distinctUntilChanged() - .withUnretained(self) - .subscribe { owner, type in - owner.updateSortedButtons(types: type) - } - .disposed(by: disposeBag) - - reactor.state - .map { $0.selectedIndex } - .distinctUntilChanged() - .withUnretained(self) - .subscribe { owner, selectedIndex in - owner.mainView.sortedButtons.enumerated().forEach { index, button in - button.isSelected = selectedIndex == index ? true : false - } - } - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .subscribe { owner, route in - switch route { - case .dismiss: - owner.isBottomTabbarHidden = reactor.currentState.isTabbarHidden - owner.dismissCurrentModal() - case .dismissWithSave: - owner.isBottomTabbarHidden = reactor.currentState.isTabbarHidden - owner.onSelectedIndex?(reactor.currentState.selectedIndex) - owner.dismissCurrentModal() - default: - break - } - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/AppDelegate.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/AppDelegate.swift deleted file mode 100644 index 1f04fe03..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/AppDelegate.swift +++ /dev/null @@ -1,416 +0,0 @@ -// swiftlint:disable function_body_length -// swiftlint:disable line_length - -import UIKit - -import AuthFeature -import AuthFeatureInterface -import BaseFeature -import BookmarkFeature -import BookmarkFeatureInterface -import Core -import Data -import DataMock -import DesignSystem -import DictionaryFeature -import DictionaryFeatureInterface -import Domain -import DomainInterface -import MyPageFeature -import MyPageFeatureInterface - -import KakaoSDKCommon - -@main -class AppDelegate: UIResponder, UIApplicationDelegate { - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - ImageLoader.shared.configure.diskCacheCountLimit = 10 - FontManager.registerFonts() - registerDependencies() - return true - } - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {} -} - -private extension AppDelegate { - func registerDependencies() { - registerProvider() - registerRepository() - registerUseCase() - registerFactory() - } - - func registerProvider() { - DIContainer.register(type: NetworkProvider.self) { - NetworkProviderImpl() - } - DIContainer.register(type: SocialAuthenticatableProvider.self, name: "kakao") { - KakaoLoginProviderMock() - } - DIContainer.register(type: SocialAuthenticatableProvider.self, name: "apple") { - AppleLoginProviderMock() - } - } - - func registerRepository() { - DIContainer.register(type: AuthAPIRepository.self) { - AuthAPIRepositoryMock(provider: DIContainer.resolve(type: NetworkProvider.self)) - } - DIContainer.register(type: TokenRepository.self) { - KeyChainRepositoryImpl() - } - DIContainer.register(type: DictionaryListAPIRepository.self) { - DictionaryListAPIRepositoryImpl(provider: DIContainer.resolve(type: NetworkProvider.self), tokenInterceptor: TokenInterceptor(fetchTokenUseCase: DIContainer.resolve(type: FetchTokenFromLocalUseCase.self))) - } - DIContainer.register(type: DictionaryDetailAPIRepository.self) { - DictionaryDetailAPIRepositoryImpl(provider: DIContainer.resolve(type: NetworkProvider.self), tokenInterceptor: TokenInterceptor(fetchTokenUseCase: DIContainer.resolve(type: FetchTokenFromLocalUseCase.self))) - } - DIContainer.register(type: BookmarkRepository.self) { - BookmarkRepositoryImpl(provider: DIContainer.resolve(type: NetworkProvider.self), interceptor: TokenInterceptor(fetchTokenUseCase: DIContainer.resolve(type: FetchTokenFromLocalUseCase.self))) - } - DIContainer.register(type: UserDefaultsRepository.self) { - UserDefaultsRepositoryImpl() - } - DIContainer.register(type: AlarmAPIRepository.self) { - AlarmAPIRepositoryImpl(provider: DIContainer.resolve(type: NetworkProvider.self), interceptor: TokenInterceptor(fetchTokenUseCase: DIContainer.resolve(type: FetchTokenFromLocalUseCase.self))) - } - } - - func registerUseCase() { - DIContainer.register(type: FetchSocialCredentialUseCase.self, name: "kakao") { - let provider = DIContainer.resolve(type: SocialAuthenticatableProvider.self, name: "kakao") - return SocialLoginUseCaseImpl(provider: provider) - } - DIContainer.register(type: FetchSocialCredentialUseCase.self, name: "apple") { - let provider = DIContainer.resolve(type: SocialAuthenticatableProvider.self, name: "apple") - return SocialLoginUseCaseImpl(provider: provider) - } - DIContainer.register(type: CheckEmptyLevelAndRoleUseCase.self) { - CheckEmptyLevelAndRoleUseCaseImpl() - } - DIContainer.register(type: CheckValidLevelUseCase.self) { - CheckValidLevelUseCaseImpl() - } - DIContainer.register(type: FetchJobListUseCase.self) { - FetchJobListUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: LoginWithAppleUseCase.self) { - LoginWithAppleUseCaseImpl(authRepository: DIContainer.resolve(type: AuthAPIRepository.self), tokenRepository: DIContainer.resolve(type: TokenRepository.self), userDefaultsRepository: DIContainer.resolve(type: UserDefaultsRepository.self)) - } - DIContainer.register(type: LoginWithKakaoUseCase.self) { - LoginWithKakaoUseCaseImpl(authRepository: DIContainer.resolve(type: AuthAPIRepository.self), tokenRepository: DIContainer.resolve(type: TokenRepository.self), userDefaultsRepository: DIContainer.resolve(type: UserDefaultsRepository.self)) - } - DIContainer.register(type: SignUpWithAppleUseCase.self) { - SignUpWithAppleUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: SignUpWithKakaoUseCase.self) { - SignUpWithKakaoUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: UpdateUserInfoUseCase.self) { - UpdateUserInfoUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: FetchTokenFromLocalUseCase.self) { - FetchTokenFromLocalUseCaseImpl(repository: DIContainer.resolve(type: TokenRepository.self)) - } - DIContainer.register(type: SaveTokenToLocalUseCase.self) { - SaveTokenToLocalUseCaseImpl(repository: DIContainer.resolve(type: TokenRepository.self)) - } - DIContainer.register(type: DeleteTokenFromLocalUseCase.self) { - DeleteTokenFromLocalUseCaseImpl(repository: DIContainer.resolve(type: TokenRepository.self)) - } - DIContainer.register(type: FetchDictionaryAllListUseCase.self) { - FetchDictionaryAllListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryMapListUseCase.self) { - FetchDictionaryMapListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryItemListUseCase.self) { - FetchDictionaryItemListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryQuestListUseCase.self) { - FetchDictionaryQuestListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryNpcListUseCase.self) { - FetchDictionaryNpcListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryMonsterListUseCase.self) { - FetchDictionaryMonsterListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMonsterUseCase.self) { - FetchDictionaryDetailMonsterUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMonsterItemsUseCase.self) { - FetchDictionaryDetailMonsterDropItemUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMonsterMapUseCase.self) { - FetchDictionaryDetailMonsterMapUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailNpcUseCase.self) { - FetchDictionaryDetailNpcUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailNpcQuestUseCase.self) { - FetchDictionaryDetailNpcQuestUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailNpcMapUseCase.self) { - FetchDictionaryDetailNpcMapUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailItemUseCase.self) { - FetchDictionaryDetailItemUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailItemDropMonsterUseCase.self) { - FetchDictionaryDetailItemDropMonsterUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailQuestUseCase.self) { - FetchDictionaryDetailQuestUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailQuestLinkedQuestsUseCase.self) { - FetchDictionaryDetailQuestLinkedQuestsUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMapUseCase.self) { - FetchDictionaryDetailMapUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMapSpawnMonsterUseCase.self) { - FetchDictionaryDetailMapSpawnMonsterUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryDetailMapNpcUseCase.self) { - FetchDictionaryDetailMapNpcUseCaseImpl(repository: DIContainer.resolve(type: DictionaryDetailAPIRepository.self)) - } - DIContainer.register(type: CheckLoginUseCase.self) { - CheckLoginUseCaseImpl(authRepository: DIContainer.resolve(type: AuthAPIRepository.self), tokenRepository: DIContainer.resolve(type: TokenRepository.self)) - } - DIContainer.register(type: UpdateMarketingAgreementUseCase.self) { - UpdateMarketingAgreementUseCaseImpl(authRepository: DIContainer.resolve(type: AuthAPIRepository.self), tokenRepository: DIContainer.resolve(type: TokenRepository.self)) - } - DIContainer.register(type: CheckNotificationPermissionUseCase.self) { - CheckNotificationPermissionUseCaseImpl() - } - DIContainer.register(type: OpenNotificationSettingUseCase.self) { - OpenNotificationSettingUseCaseImpl() - } - DIContainer.register(type: UpdateNotificationAgreementUseCase.self) { - UpdateNotificationAgreementUseCaseImpl(authRepository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: SetBookmarkUseCase.self) { - SetBookmarkUseCaseImpl(repository: DIContainer.resolve(type: BookmarkRepository.self)) - } - DIContainer.register(type: FetchMonsterBookmarkUseCase.self) { - FetchMonsterBookmarkUseCaseImpl(repository: DIContainer.resolve(type: BookmarkRepository.self)) - } - DIContainer.register(type: FetchItemBookmarkUseCase.self) { - FetchItemBookmarkUseCaseImpl(repository: DIContainer.resolve(type: BookmarkRepository.self)) - } - DIContainer.register(type: FetchMapBookmarkUseCase.self) { - FetchMapBookmarkUseCaseImpl(repository: DIContainer.resolve(type: BookmarkRepository.self)) - } - DIContainer.register(type: FetchQuestBookmarkUseCase.self) { - FetchQuestBookmarkUseCaseImpl(repository: DIContainer.resolve(type: BookmarkRepository.self)) - } - DIContainer.register(type: FetchNPCBookmarkUseCase.self) { - FetchNPCBookmarkUseCaseImpl(repository: DIContainer.resolve(type: BookmarkRepository.self)) - } - DIContainer.register(type: FetchBookmarkUseCase.self) { - FetchBookmarkUseCaseImpl(repository: DIContainer.resolve(type: BookmarkRepository.self)) - } - DIContainer.register(type: FetchDictionarySearchListUseCase.self) { - FetchDictionarySearchListUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: FetchDictionaryListCountUseCase.self) { - FetchDictionaryListCountUseCaseImpl(repository: DIContainer.resolve(type: DictionaryListAPIRepository.self)) - } - DIContainer.register(type: RecentSearchAddUseCase.self) { - RecentSearchAddUseCaseImpl(repository: DIContainer.resolve(type: UserDefaultsRepository.self)) - } - DIContainer.register(type: RecentSearchRemoveUseCase.self) { - RecentSearchRemoveUseCaseImpl(repository: DIContainer.resolve(type: UserDefaultsRepository.self)) - } - DIContainer.register(type: RecentSearchFetchUseCase.self) { - RecentSearchFetchUseCaseImpl(repository: DIContainer.resolve(type: UserDefaultsRepository.self)) - } - DIContainer.register(type: ParseItemFilterResultUseCase.self) { - ParseItemFilterResultUseCaseImpl() - } - DIContainer.register(type: FetchPlatformUseCase.self) { - FetchPlatformUseCaseImpl(repository: DIContainer.resolve(type: UserDefaultsRepository.self)) - } - DIContainer.register(type: FetchProfileUseCase.self) { - FetchProfileUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self), fetchJobUseCase: DIContainer.resolve(type: FetchJobUseCase.self)) - } - DIContainer.register(type: FetchJobUseCase.self) { - FetchJobUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: FetchAllAlarmUseCase.self) { - FetchAllAlarmUseCaseImpl(repository: DIContainer.resolve(type: AlarmAPIRepository.self)) - } - } - func registerFactory() { - DIContainer.register(type: ItemFilterBottomSheetFactory.self) { - ItemFilterBottomSheetFactoryImpl() - } - DIContainer.register(type: MonsterFilterBottomSheetFactory.self) { - MonsterFilterBottomSheetFactoryImpl() - } - DIContainer.register(type: SortedBottomSheetFactory.self) { - SortedBottomSheetFactoryImpl() - } - DIContainer.register(type: BookmarkModalFactory.self) { - BookmarkModalFactoryImpl(addCollectionFactory: DIContainer.resolve(type: AddCollectionFactory.self)) - } - DIContainer.register(type: DictionaryDetailFactory.self) { - DictionaryDetailFactoryImpl(loginFactory: { DIContainer.resolve(type: LoginFactory.self) }, bookmarkModalFactory: DIContainer.resolve(type: BookmarkModalFactory.self), dictionaryDetailMapUseCase: DIContainer.resolve(type: FetchDictionaryDetailMapUseCase.self), dictionaryDetailMapSpawnMonsterUseCase: DIContainer.resolve(type: FetchDictionaryDetailMapSpawnMonsterUseCase.self), dictionaryDetailMapNpcUseCase: DIContainer.resolve(type: FetchDictionaryDetailMapNpcUseCase.self), dictionaryDetailQuestLinkedQuestsUseCase: DIContainer.resolve(type: FetchDictionaryDetailQuestLinkedQuestsUseCase.self), dictionaryDetailQuestUseCase: DIContainer.resolve(type: FetchDictionaryDetailQuestUseCase.self), dictionaryDetailItemDropMonsterUseCase: DIContainer.resolve(type: FetchDictionaryDetailItemDropMonsterUseCase.self), dictionaryDetailItemUseCase: DIContainer.resolve(type: FetchDictionaryDetailItemUseCase.self), dictionaryDetailNpcUseCase: DIContainer.resolve(type: FetchDictionaryDetailNpcUseCase.self), dictionaryDetailNpcQuestUseCase: DIContainer.resolve(type: FetchDictionaryDetailNpcQuestUseCase.self), dictionaryDetailNpcMapUseCase: DIContainer.resolve(type: FetchDictionaryDetailNpcMapUseCase.self), dictionaryDetailMonsterUseCase: DIContainer.resolve(type: FetchDictionaryDetailMonsterUseCase.self), dictionaryDetailMonsterDropItemUseCase: DIContainer.resolve(type: FetchDictionaryDetailMonsterItemsUseCase.self), dictionaryDetailMonsterMapUseCase: DIContainer.resolve(type: FetchDictionaryDetailMonsterMapUseCase.self), checkLoginUseCase: DIContainer.resolve(type: CheckLoginUseCase.self), setBookmarkUseCase: DIContainer.resolve(type: SetBookmarkUseCase.self)) - } - DIContainer.register(type: DictionaryMainListFactory.self) { - DictionaryListFactoryImpl( - checkLoginUseCase: DIContainer.resolve(type: CheckLoginUseCase.self), - dictionaryAllListItemUseCase: DIContainer.resolve(type: FetchDictionaryAllListUseCase.self), - dictionaryMapListItemUseCase: DIContainer.resolve(type: FetchDictionaryMapListUseCase.self), - dictionaryItemListItemUseCase: DIContainer.resolve(type: FetchDictionaryItemListUseCase.self), - dictionaryQuestListItemUseCase: DIContainer.resolve(type: FetchDictionaryQuestListUseCase.self), - dictionaryNpcListItemUseCase: DIContainer.resolve(type: FetchDictionaryNpcListUseCase.self), - dictionaryListItemUseCase: DIContainer.resolve(type: FetchDictionaryMonsterListUseCase.self), - setBookmarkUseCase: DIContainer.resolve(type: SetBookmarkUseCase.self), - parseItemFilterResultUseCase: DIContainer.resolve(type: ParseItemFilterResultUseCase.self), - itemFilterFactory: DIContainer.resolve(type: ItemFilterBottomSheetFactory.self), - monsterFilterFactory: DIContainer.resolve(type: MonsterFilterBottomSheetFactory.self), - sortedFactory: DIContainer.resolve(type: SortedBottomSheetFactory.self), - bookmarkModalFactory: DIContainer.resolve(type: BookmarkModalFactory.self), - detailFactory: DIContainer.resolve(type: DictionaryDetailFactory.self), loginFactory: { DIContainer.resolve(type: LoginFactory.self) } - ) - } - DIContainer.register(type: DictionarySearchResultFactory.self) { - DictionarySearchResultFactoryImpl( - dictionaryListCountUseCase: DIContainer.resolve(type: FetchDictionaryListCountUseCase.self), - dictionaryMainListFactory: DIContainer - .resolve(type: DictionaryMainListFactory.self), - dictionarySearchListUseCase: DIContainer.resolve(type: FetchDictionarySearchListUseCase.self) - ) - } - DIContainer.register(type: DictionarySearchFactory.self) { - DictionarySearchFactoryImpl(recentSearchRemoveUseCase: DIContainer.resolve(type: RecentSearchRemoveUseCase.self), - recentSearchAddUseCase: DIContainer.resolve(type: RecentSearchAddUseCase.self), - searchResultFactory: DIContainer - .resolve(type: DictionarySearchResultFactory.self), recentSearchFetchUseCase: DIContainer.resolve(type: RecentSearchFetchUseCase.self) - ) - } - DIContainer.register(type: NotificationSettingFactory.self) { - NotificationSettingFactoryImpl(checkNotificationPermissionUseCase: DIContainer.resolve(type: CheckNotificationPermissionUseCase.self), updateNotificationAgreementUseCase: DIContainer.resolve(type: UpdateNotificationAgreementUseCase.self)) - } - DIContainer.register(type: DictionaryNotificationFactory.self) { - DictionaryNotificationFactoryImpl(notificationSettingFactory: DIContainer.resolve(type: NotificationSettingFactory.self), fetchAllAlarmUseCase: DIContainer.resolve(type: FetchAllAlarmUseCase.self), fetchProfileUseCase: DIContainer.resolve(type: FetchProfileUseCase.self)) - } - DIContainer.register(type: DictionaryMainViewFactory.self) { - DictionaryMainViewFactoryImpl( - dictionaryMainListFactory: DIContainer - .resolve(type: DictionaryMainListFactory.self), - searchFactory: DIContainer.resolve(type: DictionarySearchFactory.self), - notificationFactory: DIContainer - .resolve(type: DictionaryNotificationFactory.self), checkLoginUseCase: DIContainer.resolve(type: CheckLoginUseCase.self)) - } - DIContainer.register(type: BookmarkOnBoardingFactory.self) { - BookmarkOnBoardingFactoryImpl() - } - DIContainer.register(type: OnBoardingNotificationSheetFactory.self) { - OnBoardingNotificationSheetFactoryImpl(checkNotificationPermissionUseCase: DIContainer.resolve(type: CheckNotificationPermissionUseCase.self), openNotificationSettingUseCase: DIContainer.resolve(type: OpenNotificationSettingUseCase.self), updateNotificationAgreementUseCase: DIContainer.resolve(type: UpdateNotificationAgreementUseCase.self), updateUserInfoUseCase: DIContainer.resolve(type: UpdateUserInfoUseCase.self), dictionaryMainViewFactory: DIContainer.resolve(type: DictionaryMainViewFactory.self)) - } - DIContainer.register(type: OnBoardingNotificationFactory.self) { - OnBoardingNotificationFactoryImpl(onBoardingNotificationSheetFactory: DIContainer.resolve(type: OnBoardingNotificationSheetFactory.self)) - } - DIContainer.register(type: OnBoardingInputFactory.self) { - OnBoardingInputFactoryImpl( - checkEmptyUseCase: DIContainer - .resolve(type: CheckEmptyLevelAndRoleUseCase.self), - checkValidLevelUseCase: DIContainer - .resolve(type: CheckValidLevelUseCase.self), - fetchJobListUseCase: DIContainer - .resolve(type: FetchJobListUseCase.self), updateUserInfoUseCase: DIContainer.resolve(type: UpdateUserInfoUseCase.self), - onBoardingNotificationFactory: DIContainer - .resolve(type: OnBoardingNotificationFactory.self) - ) - } - DIContainer.register(type: OnBoardingQuestionFactory.self) { - OnBoardingQuestionFactoryImpl(onBoardingInputFactory: DIContainer.resolve(type: OnBoardingInputFactory.self)) - } - DIContainer.register(type: TermsAgreementFactory.self) { - TermsAgreementFactoryImpl( - onBoardingQuestionFactory: DIContainer - .resolve(type: OnBoardingQuestionFactory.self), - signUpWithKakaoUseCase: DIContainer - .resolve(type: SignUpWithKakaoUseCase.self), - signUpWithAppleUseCase: DIContainer - .resolve(type: SignUpWithAppleUseCase.self), - saveTokenUseCase: DIContainer - .resolve(type: SaveTokenToLocalUseCase.self), - fetchTokenUseCase: DIContainer - .resolve(type: FetchTokenFromLocalUseCase.self), updateMarketingAgreementUseCase: DIContainer.resolve(type: UpdateMarketingAgreementUseCase.self) - ) - } - DIContainer.register(type: PutFCMTokenUseCase.self) { - PutFCMTokenUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) - } - DIContainer.register(type: LoginFactory.self) { - LoginFactoryImpl( - termsAgreementsFactory: DIContainer - .resolve(type: TermsAgreementFactory.self), - appleLoginUseCase: DIContainer - .resolve(type: FetchSocialCredentialUseCase.self, name: "apple"), - kakaoLoginUseCase: DIContainer - .resolve(type: FetchSocialCredentialUseCase.self, name: "kakao"), - loginWithAppleUseCase: DIContainer - .resolve(type: LoginWithAppleUseCase.self), - loginWithKakaoUseCase: DIContainer - .resolve(type: LoginWithKakaoUseCase.self), - fetchTokenUseCase: DIContainer.resolve(type: FetchTokenFromLocalUseCase.self), - putFCMTokenUseCase: DIContainer.resolve(type: PutFCMTokenUseCase.self), fetchPlatformUseCase: DIContainer.resolve(type: FetchPlatformUseCase.self) - ) - } - DIContainer.register(type: AddCollectionFactory.self) { - AddCollectionFactoryImpl() - } - DIContainer.register(type: BookmarkListFactory.self) { - BookmarkListFactoryImpl(itemFilterFactory: DIContainer.resolve(type: ItemFilterBottomSheetFactory.self), monsterFilterFactory: DIContainer.resolve(type: MonsterFilterBottomSheetFactory.self), sortedFactory: DIContainer.resolve(type: SortedBottomSheetFactory.self), bookmarkModalFactory: DIContainer.resolve(type: BookmarkModalFactory.self), loginFactory: DIContainer.resolve(type: LoginFactory.self), dictionaryDetailFactory: DIContainer.resolve(type: DictionaryDetailFactory.self), setBookmarkUseCase: DIContainer.resolve(type: SetBookmarkUseCase.self), checkLoginUseCase: DIContainer.resolve(type: CheckLoginUseCase.self), fetchBookmarkUseCase: DIContainer.resolve(type: FetchBookmarkUseCase.self), fetchMonsterBookmarkUseCase: DIContainer.resolve(type: FetchMonsterBookmarkUseCase.self), fetchItemBookmarkUseCase: DIContainer.resolve(type: FetchItemBookmarkUseCase.self), fetchNPCBookmarkUseCase: DIContainer.resolve(type: FetchNPCBookmarkUseCase.self), fetchQuestBookmarkUseCase: DIContainer.resolve(type: FetchQuestBookmarkUseCase.self), fetchMapBookmarkUseCase: DIContainer.resolve(type: FetchMapBookmarkUseCase.self), collectionEditFactory: DIContainer.resolve(type: CollectionEditFactory.self)) - } - DIContainer.register(type: CollectionSettingFactory.self) { - CollectionSettingFactoryImpl() - } - DIContainer.register(type: CollectionEditFactory.self) { - CollectionEditFactoryImpl(setBookmarkUseCase: DIContainer.resolve(type: SetBookmarkUseCase.self), bookmarkModalFactory: DIContainer.resolve(type: BookmarkModalFactory.self)) - } - DIContainer.register(type: CollectionDetailFactory.self) { - CollectionDetailFactoryImpl( - setBookmarkUseCase: DIContainer.resolve(type: SetBookmarkUseCase.self), - bookmarkModalFactory: DIContainer - .resolve(type: BookmarkModalFactory.self), - collectionSettingFactory: DIContainer - .resolve(type: CollectionSettingFactory.self), - addCollectionFactory: DIContainer - .resolve(type: AddCollectionFactory.self), - collectionEditFactory: DIContainer - .resolve(type: CollectionEditFactory.self), dictionaryDetailFactory: DIContainer.resolve(type: DictionaryDetailFactory.self) - ) - } - DIContainer.register(type: CollectionListFactory.self) { - CollectionListFactoryImpl(addCollectionFactory: DIContainer.resolve(type: AddCollectionFactory.self), bookmarkDetailFactory: DIContainer.resolve(type: CollectionDetailFactory.self)) - } - DIContainer.register(type: BookmarkMainFactory.self) { - BookmarkMainFactoryImpl( - setBookmarkUseCase: DIContainer - .resolve(type: SetBookmarkUseCase.self), - onBoardingFactory: DIContainer - .resolve(type: BookmarkOnBoardingFactory.self), - bookmarkListFactory: DIContainer - .resolve(type: BookmarkListFactory.self), - collectionListFactory: DIContainer - .resolve(type: CollectionListFactory.self), - searchFactory: DIContainer - .resolve(type: DictionarySearchFactory.self), - notificationFactory: DIContainer.resolve( - type: DictionaryNotificationFactory.self - ) - ) - } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/AccentColor.colorset/Contents.json b/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index eb878970..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/AppIcon.appiconset/Contents.json b/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index 5aca7cac..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "images" : [ - { - "filename" : "appIcon.png", - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "tinted" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/AppIcon.appiconset/appIcon.png b/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/AppIcon.appiconset/appIcon.png deleted file mode 100644 index b759ed9c..00000000 Binary files a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/AppIcon.appiconset/appIcon.png and /dev/null differ diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/Contents.json b/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/image.imageset/Contents.json b/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/image.imageset/Contents.json deleted file mode 100644 index 8f75fcb4..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/image.imageset/Contents.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "images" : [ - { - "filename" : "image.svg", - "idiom" : "universal", - "scale" : "1x" - }, - { - "idiom" : "universal", - "scale" : "2x" - }, - { - "idiom" : "universal", - "scale" : "3x" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/image.imageset/image.svg b/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/image.imageset/image.svg deleted file mode 100644 index 7b8caba9..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Assets.xcassets/image.imageset/image.svg +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Base.lproj/LaunchScreen.storyboard b/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 865e9329..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Info.plist b/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Info.plist deleted file mode 100644 index 7c5f0be1..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/Info.plist +++ /dev/null @@ -1,25 +0,0 @@ - - - - - ITSAppUsesNonExemptEncryption - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - - - - - - diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/SceneDelegate.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/SceneDelegate.swift deleted file mode 100644 index 93fa62bb..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/SceneDelegate.swift +++ /dev/null @@ -1,26 +0,0 @@ -import UIKit - -import DesignSystem -import DictionaryFeature - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - var window: UIWindow? - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - guard let windowScene = (scene as? UIWindowScene) else { return } - window = UIWindow(windowScene: windowScene) - let startVC = ViewController() - window?.rootViewController = UINavigationController(rootViewController: startVC) - window?.makeKeyAndVisible() - } - - func sceneDidDisconnect(_ scene: UIScene) {} - - func sceneDidBecomeActive(_ scene: UIScene) {} - - func sceneWillResignActive(_ scene: UIScene) {} - - func sceneWillEnterForeground(_ scene: UIScene) {} - - func sceneDidEnterBackground(_ scene: UIScene) {} -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/ViewController.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/ViewController.swift deleted file mode 100644 index 28d2d119..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureDemo/ViewController.swift +++ /dev/null @@ -1,100 +0,0 @@ -import UIKit - -import BaseFeature -import BookmarkFeatureInterface -import Core -import DesignSystem -import DictionaryFeatureInterface -import Domain -import DomainInterface - -import RxCocoa -import RxSwift -import SnapKit - -class ViewController: UIViewController { - let tableView: UITableView = { - let view = UITableView(frame: .zero, style: .plain) - return view - }() - - lazy var views: [[UIViewController]] = { - let itemFilterBottomSheetVC = DIContainer.resolve(type: ItemFilterBottomSheetFactory.self).make { _ in } - itemFilterBottomSheetVC.title = "아이템 필터 바텀시트" - - let monsterBottomSheetVC = DIContainer.resolve(type: MonsterFilterBottomSheetFactory.self).make(startLevel: 0, endLevel: 200) { _, _ in } - monsterBottomSheetVC.title = "몬스터 필터 바텀시트" - - let sortedBottomSheetVC = DIContainer.resolve(type: SortedBottomSheetFactory.self).make(sortedOptions: [ - .korean - ], selectedIndex: 0, onSelectedIndex: {_ in }) - sortedBottomSheetVC.title = "정렬 바텀시트" - - let modalVC = [itemFilterBottomSheetVC, monsterBottomSheetVC, sortedBottomSheetVC] - - let dictionaryMainVC = DIContainer.resolve(type: DictionaryMainViewFactory.self).make() - - let bookmarkMainVC = DIContainer.resolve(type: BookmarkMainFactory.self).make() - - let dictView = BottomTabBarController(viewControllers: [ - dictionaryMainVC, - bookmarkMainVC, - BaseViewController() - ]) - dictView.title = "도감 메인" - - return [ - modalVC, - [dictView] - ] - }() - - override func viewDidLoad() { - super.viewDidLoad() - view.backgroundColor = .systemBackground - tableView.dataSource = self - tableView.delegate = self - navigationItem.title = "MLS Feature System" - - view.addSubview(tableView) - - tableView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } -} - -extension ViewController: UITableViewDataSource, UITableViewDelegate { - func numberOfSections(in tableView: UITableView) -> Int { - return views.count - } - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return views[section].count - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = UITableViewCell() - cell.textLabel?.text = views[indexPath.section][indexPath.row].title - cell.selectionStyle = .none - return cell - } - - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let nextController = views[indexPath.section][indexPath.row] - if indexPath.section == 0 { - if nextController.title == "몬스터 필터 바텀시트" || nextController.title == "정렬 바텀시트" { - if let nextVC = nextController as? (UIViewController & ModalPresentable) { - presentModal(nextVC) - } - } else { - navigationController?.present(nextController, animated: true) - } - } else if indexPath.section == 1 { - nextController.modalPresentationStyle = .fullScreen - navigationController?.present(nextController, animated: true) - } else { - navigationController?.pushViewController(nextController, animated: true) - } - } -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DetailOnBoardingFactory.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DetailOnBoardingFactory.swift deleted file mode 100644 index 4a3cb3e6..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DetailOnBoardingFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol DetailOnBoardingFactory { - func make() -> BaseViewController -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryDetailFactory.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryDetailFactory.swift deleted file mode 100644 index 562bfe32..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryDetailFactory.swift +++ /dev/null @@ -1,8 +0,0 @@ -import BaseFeature -import DomainInterface - -import RxCocoa - -public protocol DictionaryDetailFactory { - func make(type: DictionaryType, id: Int, bookmarkRelay: PublishRelay<(id: Int, newBookmarkId: Int?)>?, loginRelay: PublishRelay?) -> BaseViewController -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryMainListFactory.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryMainListFactory.swift deleted file mode 100644 index e3ccf330..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryMainListFactory.swift +++ /dev/null @@ -1,6 +0,0 @@ -import BaseFeature -import DomainInterface - -public protocol DictionaryMainListFactory { - func make(type: DictionaryType, listType: DictionaryMainViewType, keyword: String?) -> BaseViewController -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryMainViewFactory.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryMainViewFactory.swift deleted file mode 100644 index 1bce179e..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryMainViewFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol DictionaryMainViewFactory { - func make() -> BaseViewController -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryNotificationFactory.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryNotificationFactory.swift deleted file mode 100644 index f7eeefbd..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionaryNotificationFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol DictionaryNotificationFactory { - func make() -> BaseViewController -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionarySearchFactory.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionarySearchFactory.swift deleted file mode 100644 index 5d5f2cb0..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionarySearchFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol DictionarySearchFactory { - func make() -> BaseViewController -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionarySearchResultFactory.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionarySearchResultFactory.swift deleted file mode 100644 index 3eaf2a8e..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/DictionarySearchResultFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol DictionarySearchResultFactory { - func make(keyword: String?) -> BaseViewController -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/ItemFilterBottomSheetFactory.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/ItemFilterBottomSheetFactory.swift deleted file mode 100644 index 37257544..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/ItemFilterBottomSheetFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol ItemFilterBottomSheetFactory { - func make(onFilterSelected: @escaping ([(String, String)]) -> Void) -> BaseViewController -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/MonsterFilterBottomSheetFactory.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/MonsterFilterBottomSheetFactory.swift deleted file mode 100644 index aff5d2db..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/MonsterFilterBottomSheetFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol MonsterFilterBottomSheetFactory { - func make(startLevel: Int, endLevel: Int, onFilterSelected: @escaping ((Int, Int) -> Void)) -> BaseViewController & ModalPresentable -} diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/NotificationSettingFactory.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/NotificationSettingFactory.swift deleted file mode 100644 index 87a43ec9..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/NotificationSettingFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -// public protocol NotificationSettingFactory { -// func make() -> BaseViewController -// } diff --git a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/SortedBottomSheetFactory.swift b/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/SortedBottomSheetFactory.swift deleted file mode 100644 index a4ea31bc..00000000 --- a/MLS/Presentation/DictionaryFeature/DictionaryFeatureInterface/SortedBottomSheetFactory.swift +++ /dev/null @@ -1,6 +0,0 @@ -import BaseFeature -import DomainInterface - -public protocol SortedBottomSheetFactory { - func make(sortedOptions: [SortType], selectedIndex: Int, onSelectedIndex: @escaping (Int) -> Void) -> BaseViewController & ModalPresentable -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature.xcodeproj/project.pbxproj b/MLS/Presentation/MyPageFeature/MyPageFeature.xcodeproj/project.pbxproj deleted file mode 100644 index dae3ecdd..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature.xcodeproj/project.pbxproj +++ /dev/null @@ -1,958 +0,0 @@ -// !$*UTF8*$! -{ - archiveVersion = 1; - classes = { - }; - objectVersion = 77; - objects = { - -/* Begin PBXBuildFile section */ - 773A3BEB2E716FD800F75B30 /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 773A3BEA2E716FD800F75B30 /* SnapKit */; }; - 773A3BEE2E716FEF00F75B30 /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 773A3BED2E716FEF00F75B30 /* RxCocoa */; }; - 773A3BF02E716FEF00F75B30 /* RxRelay in Frameworks */ = {isa = PBXBuildFile; productRef = 773A3BEF2E716FEF00F75B30 /* RxRelay */; }; - 773A3BF22E716FEF00F75B30 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 773A3BF12E716FEF00F75B30 /* RxSwift */; }; - 773A3BF52E716FFD00F75B30 /* ReactorKit in Frameworks */ = {isa = PBXBuildFile; productRef = 773A3BF42E716FFD00F75B30 /* ReactorKit */; }; - 773A3BF82E71701D00F75B30 /* RxCocoa in Frameworks */ = {isa = PBXBuildFile; productRef = 773A3BF72E71701D00F75B30 /* RxCocoa */; }; - 773A3BFA2E71701D00F75B30 /* RxRelay in Frameworks */ = {isa = PBXBuildFile; productRef = 773A3BF92E71701D00F75B30 /* RxRelay */; }; - 773A3BFC2E71701D00F75B30 /* RxSwift in Frameworks */ = {isa = PBXBuildFile; productRef = 773A3BFB2E71701D00F75B30 /* RxSwift */; }; - 773A3BFE2E71702300F75B30 /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 773A3BFD2E71702300F75B30 /* SnapKit */; }; - 773A3BFF2E7170A700F75B30 /* MyPageFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 773A38202E71591B00F75B30 /* MyPageFeatureInterface.framework */; }; - 773A3C002E7170A700F75B30 /* MyPageFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 773A38202E71591B00F75B30 /* MyPageFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 773A3C092E71712300F75B30 /* MyPageFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 773A38202E71591B00F75B30 /* MyPageFeatureInterface.framework */; }; - 773A3F662E71731700F75B30 /* MyPageFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 773A38062E7158B400F75B30 /* MyPageFeature.framework */; }; - 773A3F672E71731700F75B30 /* MyPageFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 773A38062E7158B400F75B30 /* MyPageFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 773A3F6B2E71734600F75B30 /* DesignSystem.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 773A3F6A2E71734600F75B30 /* DesignSystem.framework */; }; - 773A3F6C2E71734600F75B30 /* DesignSystem.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 773A3F6A2E71734600F75B30 /* DesignSystem.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 773A3F6E2E71736300F75B30 /* BaseFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 773A3F6D2E71736300F75B30 /* BaseFeature.framework */; }; - 773A3F6F2E71736300F75B30 /* BaseFeature.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 773A3F6D2E71736300F75B30 /* BaseFeature.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 773A3F712E71736A00F75B30 /* BaseFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 773A3F702E71736A00F75B30 /* BaseFeature.framework */; }; - 773A42D02E717B8900F75B30 /* BaseFeature.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 773A42CF2E717B8900F75B30 /* BaseFeature.framework */; }; - 7746ABAA2E84225A0046F603 /* Core.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7746ABA92E84225A0046F603 /* Core.framework */; }; - 7746ABAB2E84225A0046F603 /* Core.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 7746ABA92E84225A0046F603 /* Core.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 7746ABAD2E84227A0046F603 /* DomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7746ABAC2E84227A0046F603 /* DomainInterface.framework */; }; - 7746ABB12E84245D0046F603 /* RxGesture in Frameworks */ = {isa = PBXBuildFile; productRef = 7746ABB02E84245D0046F603 /* RxGesture */; }; - 7746ABB32E8425E00046F603 /* DesignSystem.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7746ABB22E8425E00046F603 /* DesignSystem.framework */; }; - 7746ABB72E8427F80046F603 /* RxKeyboard in Frameworks */ = {isa = PBXBuildFile; productRef = 7746ABB62E8427F80046F603 /* RxKeyboard */; }; - 775966F32EC30B3A00CC389B /* AuthFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 775966F22EC30B3A00CC389B /* AuthFeatureInterface.framework */; }; - 777C28142E7D87B8000765F2 /* RxKeyboard in Frameworks */ = {isa = PBXBuildFile; productRef = 777C28132E7D87B8000765F2 /* RxKeyboard */; }; - 77BE55BC2E78596900522216 /* DomainInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77BE55B92E78596900522216 /* DomainInterface.framework */; }; - 77BE55BD2E78596900522216 /* DomainInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77BE55B92E78596900522216 /* DomainInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - 77D0AD422F97DA78008B0C57 /* AuthFeatureInterface.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 77D0AD412F97DA78008B0C57 /* AuthFeatureInterface.framework */; }; - 77D0AD432F97DA78008B0C57 /* AuthFeatureInterface.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 77D0AD412F97DA78008B0C57 /* AuthFeatureInterface.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; - D22195C52E83FA81001203D4 /* RxGesture in Frameworks */ = {isa = PBXBuildFile; productRef = D22195C42E83FA81001203D4 /* RxGesture */; }; - D2DA8C322E798917009C53BA /* ReactorKit in Frameworks */ = {isa = PBXBuildFile; productRef = D2227A7C2E76A84A0095343A /* ReactorKit */; }; -/* End PBXBuildFile section */ - -/* Begin PBXContainerItemProxy section */ - 773A3C012E7170A700F75B30 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 773A37FD2E7158B400F75B30 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 773A381F2E71591B00F75B30; - remoteInfo = MyPageFeatureInterface; - }; - 773A3C0B2E71712300F75B30 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 773A37FD2E7158B400F75B30 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 773A381F2E71591B00F75B30; - remoteInfo = MyPageFeatureInterface; - }; - 773A3F682E71731700F75B30 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 773A37FD2E7158B400F75B30 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 773A38052E7158B400F75B30; - remoteInfo = MyPageFeature; - }; -/* End PBXContainerItemProxy section */ - -/* Begin PBXCopyFilesBuildPhase section */ - 773A3C032E7170A700F75B30 /* Embed Frameworks */ = { - isa = PBXCopyFilesBuildPhase; - buildActionMask = 2147483647; - dstPath = ""; - dstSubfolderSpec = 10; - files = ( - 77D0AD432F97DA78008B0C57 /* AuthFeatureInterface.framework in Embed Frameworks */, - 77BE55BD2E78596900522216 /* DomainInterface.framework in Embed Frameworks */, - 773A3F6F2E71736300F75B30 /* BaseFeature.framework in Embed Frameworks */, - 773A3F6C2E71734600F75B30 /* DesignSystem.framework in Embed Frameworks */, - 773A3F672E71731700F75B30 /* MyPageFeature.framework in Embed Frameworks */, - 7746ABAB2E84225A0046F603 /* Core.framework in Embed Frameworks */, - 773A3C002E7170A700F75B30 /* MyPageFeatureInterface.framework in Embed Frameworks */, - ); - name = "Embed Frameworks"; - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXCopyFilesBuildPhase section */ - -/* Begin PBXFileReference section */ - 773A38062E7158B400F75B30 /* MyPageFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MyPageFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 773A38202E71591B00F75B30 /* MyPageFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = MyPageFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 773A38772E7159CA00F75B30 /* MyPageFeatureDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MyPageFeatureDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; - 773A3F6A2E71734600F75B30 /* DesignSystem.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DesignSystem.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 773A3F6D2E71736300F75B30 /* BaseFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BaseFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 773A3F702E71736A00F75B30 /* BaseFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BaseFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 773A42CF2E717B8900F75B30 /* BaseFeature.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = BaseFeature.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 7746A7EE2E841C9C0046F603 /* Data.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Data.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 7746A7F12E841CEA0046F603 /* DataMock.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DataMock.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 7746ABA92E84225A0046F603 /* Core.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Core.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 7746ABAC2E84227A0046F603 /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 7746ABB22E8425E00046F603 /* DesignSystem.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DesignSystem.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 775966F22EC30B3A00CC389B /* AuthFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AuthFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 776FEA332EA4D29B0039ACE2 /* AuthFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AuthFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77BE55B82E78596900522216 /* Domain.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Domain.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77BE55B92E78596900522216 /* DomainInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = DomainInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 77D0AD412F97DA78008B0C57 /* AuthFeatureInterface.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = AuthFeatureInterface.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - D2227A762E76A7E70095343A /* Core.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Core.framework; sourceTree = BUILT_PRODUCTS_DIR; }; -/* End PBXFileReference section */ - -/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ - 773A38882E7159CB00F75B30 /* Exceptions for "MyPageFeatureDemo" folder in "MyPageFeatureDemo" target */ = { - isa = PBXFileSystemSynchronizedBuildFileExceptionSet; - membershipExceptions = ( - Info.plist, - ); - target = 773A38762E7159CA00F75B30 /* MyPageFeatureDemo */; - }; -/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ - -/* Begin PBXFileSystemSynchronizedRootGroup section */ - 773A38082E7158B400F75B30 /* MyPageFeature */ = { - isa = PBXFileSystemSynchronizedRootGroup; - path = MyPageFeature; - sourceTree = ""; - }; - 773A38212E71591B00F75B30 /* MyPageFeatureInterface */ = { - isa = PBXFileSystemSynchronizedRootGroup; - path = MyPageFeatureInterface; - sourceTree = ""; - }; - 773A38782E7159CA00F75B30 /* MyPageFeatureDemo */ = { - isa = PBXFileSystemSynchronizedRootGroup; - exceptions = ( - 773A38882E7159CB00F75B30 /* Exceptions for "MyPageFeatureDemo" folder in "MyPageFeatureDemo" target */, - ); - path = MyPageFeatureDemo; - sourceTree = ""; - }; -/* End PBXFileSystemSynchronizedRootGroup section */ - -/* Begin PBXFrameworksBuildPhase section */ - 773A38032E7158B400F75B30 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 7746ABAD2E84227A0046F603 /* DomainInterface.framework in Frameworks */, - 773A3BF02E716FEF00F75B30 /* RxRelay in Frameworks */, - D22195C52E83FA81001203D4 /* RxGesture in Frameworks */, - 773A3BEE2E716FEF00F75B30 /* RxCocoa in Frameworks */, - 773A3BF22E716FEF00F75B30 /* RxSwift in Frameworks */, - 773A3BF52E716FFD00F75B30 /* ReactorKit in Frameworks */, - 7746ABB32E8425E00046F603 /* DesignSystem.framework in Frameworks */, - 773A3C092E71712300F75B30 /* MyPageFeatureInterface.framework in Frameworks */, - 777C28142E7D87B8000765F2 /* RxKeyboard in Frameworks */, - 775966F32EC30B3A00CC389B /* AuthFeatureInterface.framework in Frameworks */, - 773A3BEB2E716FD800F75B30 /* SnapKit in Frameworks */, - 773A3F712E71736A00F75B30 /* BaseFeature.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 773A381D2E71591B00F75B30 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - 773A42D02E717B8900F75B30 /* BaseFeature.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 773A38742E7159CA00F75B30 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - D2DA8C322E798917009C53BA /* ReactorKit in Frameworks */, - 77BE55BC2E78596900522216 /* DomainInterface.framework in Frameworks */, - 773A3F6E2E71736300F75B30 /* BaseFeature.framework in Frameworks */, - 773A3F6B2E71734600F75B30 /* DesignSystem.framework in Frameworks */, - 7746ABB72E8427F80046F603 /* RxKeyboard in Frameworks */, - 773A3F662E71731700F75B30 /* MyPageFeature.framework in Frameworks */, - 7746ABB12E84245D0046F603 /* RxGesture in Frameworks */, - 77D0AD422F97DA78008B0C57 /* AuthFeatureInterface.framework in Frameworks */, - 7746ABAA2E84225A0046F603 /* Core.framework in Frameworks */, - 773A3BFC2E71701D00F75B30 /* RxSwift in Frameworks */, - 773A3BFE2E71702300F75B30 /* SnapKit in Frameworks */, - 773A3BFA2E71701D00F75B30 /* RxRelay in Frameworks */, - 773A3BF82E71701D00F75B30 /* RxCocoa in Frameworks */, - 773A3BFF2E7170A700F75B30 /* MyPageFeatureInterface.framework in Frameworks */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXFrameworksBuildPhase section */ - -/* Begin PBXGroup section */ - 773A37FC2E7158B400F75B30 = { - isa = PBXGroup; - children = ( - 773A38082E7158B400F75B30 /* MyPageFeature */, - 773A38212E71591B00F75B30 /* MyPageFeatureInterface */, - 773A38782E7159CA00F75B30 /* MyPageFeatureDemo */, - 773A3BF62E71701D00F75B30 /* Frameworks */, - 773A38072E7158B400F75B30 /* Products */, - ); - sourceTree = ""; - }; - 773A38072E7158B400F75B30 /* Products */ = { - isa = PBXGroup; - children = ( - 773A38062E7158B400F75B30 /* MyPageFeature.framework */, - 773A38202E71591B00F75B30 /* MyPageFeatureInterface.framework */, - 773A38772E7159CA00F75B30 /* MyPageFeatureDemo.app */, - ); - name = Products; - sourceTree = ""; - }; - 773A3BF62E71701D00F75B30 /* Frameworks */ = { - isa = PBXGroup; - children = ( - 77D0AD412F97DA78008B0C57 /* AuthFeatureInterface.framework */, - 775966F22EC30B3A00CC389B /* AuthFeatureInterface.framework */, - 776FEA332EA4D29B0039ACE2 /* AuthFeatureInterface.framework */, - 7746ABB22E8425E00046F603 /* DesignSystem.framework */, - 7746ABAC2E84227A0046F603 /* DomainInterface.framework */, - 7746ABA92E84225A0046F603 /* Core.framework */, - 7746A7F12E841CEA0046F603 /* DataMock.framework */, - 7746A7EE2E841C9C0046F603 /* Data.framework */, - 77BE55B82E78596900522216 /* Domain.framework */, - 77BE55B92E78596900522216 /* DomainInterface.framework */, - D2227A762E76A7E70095343A /* Core.framework */, - 773A42CF2E717B8900F75B30 /* BaseFeature.framework */, - 773A3F702E71736A00F75B30 /* BaseFeature.framework */, - 773A3F6D2E71736300F75B30 /* BaseFeature.framework */, - 773A3F6A2E71734600F75B30 /* DesignSystem.framework */, - ); - name = Frameworks; - sourceTree = ""; - }; -/* End PBXGroup section */ - -/* Begin PBXHeadersBuildPhase section */ - 773A38012E7158B400F75B30 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 773A381B2E71591B00F75B30 /* Headers */ = { - isa = PBXHeadersBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXHeadersBuildPhase section */ - -/* Begin PBXNativeTarget section */ - 773A38052E7158B400F75B30 /* MyPageFeature */ = { - isa = PBXNativeTarget; - buildConfigurationList = 773A380E2E7158B400F75B30 /* Build configuration list for PBXNativeTarget "MyPageFeature" */; - buildPhases = ( - 773A38012E7158B400F75B30 /* Headers */, - 773A38022E7158B400F75B30 /* Sources */, - 773A38032E7158B400F75B30 /* Frameworks */, - 773A38042E7158B400F75B30 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 773A3C0C2E71712300F75B30 /* PBXTargetDependency */, - ); - fileSystemSynchronizedGroups = ( - 773A38082E7158B400F75B30 /* MyPageFeature */, - ); - name = MyPageFeature; - packageProductDependencies = ( - 773A3BEA2E716FD800F75B30 /* SnapKit */, - 773A3BED2E716FEF00F75B30 /* RxCocoa */, - 773A3BEF2E716FEF00F75B30 /* RxRelay */, - 773A3BF12E716FEF00F75B30 /* RxSwift */, - 773A3BF42E716FFD00F75B30 /* ReactorKit */, - 777C28132E7D87B8000765F2 /* RxKeyboard */, - D22195C42E83FA81001203D4 /* RxGesture */, - ); - productName = MyPageFeature; - productReference = 773A38062E7158B400F75B30 /* MyPageFeature.framework */; - productType = "com.apple.product-type.framework"; - }; - 773A381F2E71591B00F75B30 /* MyPageFeatureInterface */ = { - isa = PBXNativeTarget; - buildConfigurationList = 773A38272E71591B00F75B30 /* Build configuration list for PBXNativeTarget "MyPageFeatureInterface" */; - buildPhases = ( - 773A381B2E71591B00F75B30 /* Headers */, - 773A381C2E71591B00F75B30 /* Sources */, - 773A381D2E71591B00F75B30 /* Frameworks */, - 773A381E2E71591B00F75B30 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - ); - fileSystemSynchronizedGroups = ( - 773A38212E71591B00F75B30 /* MyPageFeatureInterface */, - ); - name = MyPageFeatureInterface; - packageProductDependencies = ( - ); - productName = MyPageFeatureInterface; - productReference = 773A38202E71591B00F75B30 /* MyPageFeatureInterface.framework */; - productType = "com.apple.product-type.framework"; - }; - 773A38762E7159CA00F75B30 /* MyPageFeatureDemo */ = { - isa = PBXNativeTarget; - buildConfigurationList = 773A38892E7159CB00F75B30 /* Build configuration list for PBXNativeTarget "MyPageFeatureDemo" */; - buildPhases = ( - 773A38732E7159CA00F75B30 /* Sources */, - 773A38742E7159CA00F75B30 /* Frameworks */, - 773A38752E7159CA00F75B30 /* Resources */, - 773A3C032E7170A700F75B30 /* Embed Frameworks */, - ); - buildRules = ( - ); - dependencies = ( - 773A3C022E7170A700F75B30 /* PBXTargetDependency */, - 773A3F692E71731700F75B30 /* PBXTargetDependency */, - ); - fileSystemSynchronizedGroups = ( - 773A38782E7159CA00F75B30 /* MyPageFeatureDemo */, - ); - name = MyPageFeatureDemo; - packageProductDependencies = ( - 773A3BF72E71701D00F75B30 /* RxCocoa */, - 773A3BF92E71701D00F75B30 /* RxRelay */, - 773A3BFB2E71701D00F75B30 /* RxSwift */, - 773A3BFD2E71702300F75B30 /* SnapKit */, - D2227A7C2E76A84A0095343A /* ReactorKit */, - 7746ABB02E84245D0046F603 /* RxGesture */, - 7746ABB62E8427F80046F603 /* RxKeyboard */, - ); - productName = MyPageFeatureDemo; - productReference = 773A38772E7159CA00F75B30 /* MyPageFeatureDemo.app */; - productType = "com.apple.product-type.application"; - }; -/* End PBXNativeTarget section */ - -/* Begin PBXProject section */ - 773A37FD2E7158B400F75B30 /* Project object */ = { - isa = PBXProject; - attributes = { - BuildIndependentTargetsInParallel = 1; - LastSwiftUpdateCheck = 1620; - LastUpgradeCheck = 1620; - TargetAttributes = { - 773A38052E7158B400F75B30 = { - CreatedOnToolsVersion = 16.2; - LastSwiftMigration = 1620; - }; - 773A381F2E71591B00F75B30 = { - CreatedOnToolsVersion = 16.2; - LastSwiftMigration = 1620; - }; - 773A38762E7159CA00F75B30 = { - CreatedOnToolsVersion = 16.2; - }; - }; - }; - buildConfigurationList = 773A38002E7158B400F75B30 /* Build configuration list for PBXProject "MyPageFeature" */; - developmentRegion = en; - hasScannedForEncodings = 0; - knownRegions = ( - en, - Base, - ); - mainGroup = 773A37FC2E7158B400F75B30; - minimizedProjectReferenceProxies = 1; - packageReferences = ( - 773A3BE92E716FD800F75B30 /* XCRemoteSwiftPackageReference "SnapKit" */, - 773A3BEC2E716FEF00F75B30 /* XCRemoteSwiftPackageReference "RxSwift" */, - 773A3BF32E716FFD00F75B30 /* XCRemoteSwiftPackageReference "ReactorKit" */, - 777C28122E7D87B8000765F2 /* XCRemoteSwiftPackageReference "RxKeyboard" */, - D22195C32E83FA81001203D4 /* XCRemoteSwiftPackageReference "RxGesture" */, - ); - preferredProjectObjectVersion = 77; - productRefGroup = 773A38072E7158B400F75B30 /* Products */; - projectDirPath = ""; - projectRoot = ""; - targets = ( - 773A38052E7158B400F75B30 /* MyPageFeature */, - 773A381F2E71591B00F75B30 /* MyPageFeatureInterface */, - 773A38762E7159CA00F75B30 /* MyPageFeatureDemo */, - ); - }; -/* End PBXProject section */ - -/* Begin PBXResourcesBuildPhase section */ - 773A38042E7158B400F75B30 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 773A381E2E71591B00F75B30 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 773A38752E7159CA00F75B30 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXResourcesBuildPhase section */ - -/* Begin PBXSourcesBuildPhase section */ - 773A38022E7158B400F75B30 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 773A381C2E71591B00F75B30 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; - 773A38732E7159CA00F75B30 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; -/* End PBXSourcesBuildPhase section */ - -/* Begin PBXTargetDependency section */ - 773A3C022E7170A700F75B30 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 773A381F2E71591B00F75B30 /* MyPageFeatureInterface */; - targetProxy = 773A3C012E7170A700F75B30 /* PBXContainerItemProxy */; - }; - 773A3C0C2E71712300F75B30 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 773A381F2E71591B00F75B30 /* MyPageFeatureInterface */; - targetProxy = 773A3C0B2E71712300F75B30 /* PBXContainerItemProxy */; - }; - 773A3F692E71731700F75B30 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 773A38052E7158B400F75B30 /* MyPageFeature */; - targetProxy = 773A3F682E71731700F75B30 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - -/* Begin XCBuildConfiguration section */ - 773A380F2E7158B400F75B30 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.MyPageFeature; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 773A38102E7158B400F75B30 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_IDENTITY = "Apple Development"; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DEVELOPMENT_TEAM = ""; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.MyPageFeature; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 773A38112E7158B400F75B30 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = dwarf; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_TESTABILITY = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_DYNAMIC_NO_PIC = NO; - GCC_NO_COMMON_BLOCKS = YES; - GCC_OPTIMIZATION_LEVEL = 0; - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.2; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; - MTL_FAST_MATH = YES; - ONLY_ACTIVE_ARCH = YES; - SDKROOT = iphoneos; - SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)"; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Debug; - }; - 773A38122E7158B400F75B30 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ALWAYS_SEARCH_USER_PATHS = NO; - ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES; - CLANG_ANALYZER_NONNULL = YES; - CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; - CLANG_CXX_LANGUAGE_STANDARD = "gnu++20"; - CLANG_ENABLE_MODULES = YES; - CLANG_ENABLE_OBJC_ARC = YES; - CLANG_ENABLE_OBJC_WEAK = YES; - CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; - CLANG_WARN_BOOL_CONVERSION = YES; - CLANG_WARN_COMMA = YES; - CLANG_WARN_CONSTANT_CONVERSION = YES; - CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; - CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; - CLANG_WARN_DOCUMENTATION_COMMENTS = YES; - CLANG_WARN_EMPTY_BODY = YES; - CLANG_WARN_ENUM_CONVERSION = YES; - CLANG_WARN_INFINITE_RECURSION = YES; - CLANG_WARN_INT_CONVERSION = YES; - CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; - CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; - CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; - CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; - CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; - CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; - CLANG_WARN_STRICT_PROTOTYPES = YES; - CLANG_WARN_SUSPICIOUS_MOVE = YES; - CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; - CLANG_WARN_UNREACHABLE_CODE = YES; - CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; - COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 1; - DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; - ENABLE_NS_ASSERTIONS = NO; - ENABLE_STRICT_OBJC_MSGSEND = YES; - ENABLE_USER_SCRIPT_SANDBOXING = YES; - GCC_C_LANGUAGE_STANDARD = gnu17; - GCC_NO_COMMON_BLOCKS = YES; - GCC_WARN_64_TO_32_BIT_CONVERSION = YES; - GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; - GCC_WARN_UNDECLARED_SELECTOR = YES; - GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; - GCC_WARN_UNUSED_FUNCTION = YES; - GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 18.2; - LOCALIZATION_PREFERS_STRING_CATALOGS = YES; - MTL_ENABLE_DEBUG_INFO = NO; - MTL_FAST_MATH = YES; - SDKROOT = iphoneos; - SWIFT_COMPILATION_MODE = wholemodule; - VALIDATE_PRODUCT = YES; - VERSIONING_SYSTEM = "apple-generic"; - VERSION_INFO_PREFIX = ""; - }; - name = Release; - }; - 773A38282E71591B00F75B30 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.MyPageFeatureInterface; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 773A38292E71591B00F75B30 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUILD_LIBRARY_FOR_DISTRIBUTION = NO; - CLANG_ENABLE_MODULES = YES; - CODE_SIGN_STYLE = Automatic; - CURRENT_PROJECT_VERSION = 1; - DEFINES_MODULE = NO; - DYLIB_COMPATIBILITY_VERSION = 1; - DYLIB_CURRENT_VERSION = 1; - DYLIB_INSTALL_NAME_BASE = "@rpath"; - ENABLE_MODULE_VERIFIER = YES; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_KEY_NSHumanReadableCopyright = ""; - INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; - IPHONEOS_DEPLOYMENT_TARGET = 15.6; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - "@loader_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++"; - MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20"; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.MyPageFeatureInterface; - PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)"; - SKIP_INSTALL = YES; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_INSTALL_OBJC_HEADER = NO; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; - 773A388A2E7159CB00F75B30 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5QTRMS954; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = MyPageFeatureDemo/Info.plist; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.MLS.MyPageFeatureDemo2; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = MLSMyPageFeatureProvisioningProfileDev; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Debug; - }; - 773A388B2E7159CB00F75B30 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; - ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor; - "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution"; - CODE_SIGN_STYLE = Manual; - CURRENT_PROJECT_VERSION = 1; - DEVELOPMENT_TEAM = ""; - "DEVELOPMENT_TEAM[sdk=iphoneos*]" = W5QTRMS954; - GENERATE_INFOPLIST_FILE = YES; - INFOPLIST_FILE = MyPageFeatureDemo/Info.plist; - INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES; - INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - INFOPLIST_KEY_UISupportedInterfaceOrientations_iPhone = "UIInterfaceOrientationPortrait UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight"; - LD_RUNPATH_SEARCH_PATHS = ( - "$(inherited)", - "@executable_path/Frameworks", - ); - MARKETING_VERSION = 1.0; - PRODUCT_BUNDLE_IDENTIFIER = com.donggle.MLS.MyPageFeatureDemo2; - PRODUCT_NAME = "$(TARGET_NAME)"; - PROVISIONING_PROFILE_SPECIFIER = ""; - "PROVISIONING_PROFILE_SPECIFIER[sdk=iphoneos*]" = MLSMyPageFeatureProvisioningProfile; - SUPPORTED_PLATFORMS = "iphoneos iphonesimulator"; - SUPPORTS_MACCATALYST = NO; - SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = NO; - SUPPORTS_XR_DESIGNED_FOR_IPHONE_IPAD = NO; - SWIFT_EMIT_LOC_STRINGS = YES; - SWIFT_VERSION = 5.0; - TARGETED_DEVICE_FAMILY = "1,2"; - }; - name = Release; - }; -/* End XCBuildConfiguration section */ - -/* Begin XCConfigurationList section */ - 773A38002E7158B400F75B30 /* Build configuration list for PBXProject "MyPageFeature" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 773A38112E7158B400F75B30 /* Debug */, - 773A38122E7158B400F75B30 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 773A380E2E7158B400F75B30 /* Build configuration list for PBXNativeTarget "MyPageFeature" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 773A380F2E7158B400F75B30 /* Debug */, - 773A38102E7158B400F75B30 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 773A38272E71591B00F75B30 /* Build configuration list for PBXNativeTarget "MyPageFeatureInterface" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 773A38282E71591B00F75B30 /* Debug */, - 773A38292E71591B00F75B30 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; - 773A38892E7159CB00F75B30 /* Build configuration list for PBXNativeTarget "MyPageFeatureDemo" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 773A388A2E7159CB00F75B30 /* Debug */, - 773A388B2E7159CB00F75B30 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; -/* End XCConfigurationList section */ - -/* Begin XCRemoteSwiftPackageReference section */ - 773A3BE92E716FD800F75B30 /* XCRemoteSwiftPackageReference "SnapKit" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/SnapKit/SnapKit"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 5.7.1; - }; - }; - 773A3BEC2E716FEF00F75B30 /* XCRemoteSwiftPackageReference "RxSwift" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ReactiveX/RxSwift"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 6.9.0; - }; - }; - 773A3BF32E716FFD00F75B30 /* XCRemoteSwiftPackageReference "ReactorKit" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/ReactorKit/ReactorKit.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 3.2.0; - }; - }; - 777C28122E7D87B8000765F2 /* XCRemoteSwiftPackageReference "RxKeyboard" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/RxSwiftCommunity/RxKeyboard"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 2.0.1; - }; - }; - D22195C32E83FA81001203D4 /* XCRemoteSwiftPackageReference "RxGesture" */ = { - isa = XCRemoteSwiftPackageReference; - repositoryURL = "https://github.com/RxSwiftCommunity/RxGesture.git"; - requirement = { - kind = upToNextMajorVersion; - minimumVersion = 4.0.4; - }; - }; -/* End XCRemoteSwiftPackageReference section */ - -/* Begin XCSwiftPackageProductDependency section */ - 773A3BEA2E716FD800F75B30 /* SnapKit */ = { - isa = XCSwiftPackageProductDependency; - package = 773A3BE92E716FD800F75B30 /* XCRemoteSwiftPackageReference "SnapKit" */; - productName = SnapKit; - }; - 773A3BED2E716FEF00F75B30 /* RxCocoa */ = { - isa = XCSwiftPackageProductDependency; - package = 773A3BEC2E716FEF00F75B30 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxCocoa; - }; - 773A3BEF2E716FEF00F75B30 /* RxRelay */ = { - isa = XCSwiftPackageProductDependency; - package = 773A3BEC2E716FEF00F75B30 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxRelay; - }; - 773A3BF12E716FEF00F75B30 /* RxSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 773A3BEC2E716FEF00F75B30 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxSwift; - }; - 773A3BF42E716FFD00F75B30 /* ReactorKit */ = { - isa = XCSwiftPackageProductDependency; - package = 773A3BF32E716FFD00F75B30 /* XCRemoteSwiftPackageReference "ReactorKit" */; - productName = ReactorKit; - }; - 773A3BF72E71701D00F75B30 /* RxCocoa */ = { - isa = XCSwiftPackageProductDependency; - package = 773A3BEC2E716FEF00F75B30 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxCocoa; - }; - 773A3BF92E71701D00F75B30 /* RxRelay */ = { - isa = XCSwiftPackageProductDependency; - package = 773A3BEC2E716FEF00F75B30 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxRelay; - }; - 773A3BFB2E71701D00F75B30 /* RxSwift */ = { - isa = XCSwiftPackageProductDependency; - package = 773A3BEC2E716FEF00F75B30 /* XCRemoteSwiftPackageReference "RxSwift" */; - productName = RxSwift; - }; - 773A3BFD2E71702300F75B30 /* SnapKit */ = { - isa = XCSwiftPackageProductDependency; - package = 773A3BE92E716FD800F75B30 /* XCRemoteSwiftPackageReference "SnapKit" */; - productName = SnapKit; - }; - 7746ABB02E84245D0046F603 /* RxGesture */ = { - isa = XCSwiftPackageProductDependency; - package = D22195C32E83FA81001203D4 /* XCRemoteSwiftPackageReference "RxGesture" */; - productName = RxGesture; - }; - 7746ABB62E8427F80046F603 /* RxKeyboard */ = { - isa = XCSwiftPackageProductDependency; - package = 777C28122E7D87B8000765F2 /* XCRemoteSwiftPackageReference "RxKeyboard" */; - productName = RxKeyboard; - }; - 777C28132E7D87B8000765F2 /* RxKeyboard */ = { - isa = XCSwiftPackageProductDependency; - package = 777C28122E7D87B8000765F2 /* XCRemoteSwiftPackageReference "RxKeyboard" */; - productName = RxKeyboard; - }; - D22195C42E83FA81001203D4 /* RxGesture */ = { - isa = XCSwiftPackageProductDependency; - package = D22195C32E83FA81001203D4 /* XCRemoteSwiftPackageReference "RxGesture" */; - productName = RxGesture; - }; - D2227A7C2E76A84A0095343A /* ReactorKit */ = { - isa = XCSwiftPackageProductDependency; - package = 773A3BF32E716FFD00F75B30 /* XCRemoteSwiftPackageReference "ReactorKit" */; - productName = ReactorKit; - }; -/* End XCSwiftPackageProductDependency section */ - }; - rootObject = 773A37FD2E7158B400F75B30 /* Project object */; -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Announcement/AnnouncementReactor.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Announcement/AnnouncementReactor.swift deleted file mode 100644 index ff7ee125..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Announcement/AnnouncementReactor.swift +++ /dev/null @@ -1,86 +0,0 @@ -import ReactorKit - -import DomainInterface - -public final class AnnouncementReactor: Reactor { - // MARK: - Reactor - public enum Route { - case none - } - - public enum Action { - case viewWillAppear - case loadMore - case itemTapped(Int) - } - - public enum Mutation { - case setAlarms([AlarmResponse], hasMore: Bool, reset: Bool) - case setLoading(Bool) - } - - public struct State { - var alarms = [AlarmResponse]() - var hasMore = false - var isLoading = false - } - - // MARK: - Properties - public var initialState: State - private let disposeBag = DisposeBag() - private let fetchNoticesUseCase: FetchNoticesUseCase - private let setReadUseCase: SetReadUseCase - - public init(fetchNoticesUseCase: FetchNoticesUseCase, setReadUseCase: SetReadUseCase) { - self.initialState = .init() - self.fetchNoticesUseCase = fetchNoticesUseCase - self.setReadUseCase = setReadUseCase - } - - public func mutate(action: Action) -> Observable { - switch action { - case .viewWillAppear: - return .concat([ - .just(.setLoading(true)), - fetchNoticesUseCase.execute(id: nil, pageSize: 20) - .map { paged in - .setAlarms(paged.items, hasMore: paged.hasMore, reset: true) - }, - .just(.setLoading(false)) - ]) - case .loadMore: - guard currentState.hasMore, !currentState.isLoading else { return .empty() } - let lastCursor = currentState.alarms.last?.id - return .concat([ - .just(.setLoading(true)), - fetchNoticesUseCase.execute(id: lastCursor, pageSize: 20) - .map { paged in - .setAlarms(paged.items, hasMore: paged.hasMore, reset: false) - }, - .just(.setLoading(false)) - ]) - case .itemTapped(let index): - return setReadUseCase.execute(alarmLink: currentState.alarms[index].link) - .andThen(.empty()) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case let .setAlarms(newAlarms, hasMore, reset): - if reset { - newState.alarms = newAlarms - } else { - newState.alarms.append(contentsOf: newAlarms) - } - newState.hasMore = hasMore - - case let .setLoading(isLoading): - newState.isLoading = isLoading - } - - return newState - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Announcement/AnnouncementViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Announcement/AnnouncementViewController.swift deleted file mode 100644 index d7f8a2fd..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Announcement/AnnouncementViewController.swift +++ /dev/null @@ -1,62 +0,0 @@ -import UIKit - -import DomainInterface - -import ReactorKit - -final class AnnouncementViewController: CustomerSupportBaseViewController, View { - typealias Reactor = AnnouncementReactor - - // MARK: - Init - override init(type: CustomerSupportType) { - super.init(type: type) - } - - override func viewDidLoad() { - super.viewDidLoad() - - // 타입을 나눠서 베이스에서 다 처리하는게 나을려나?? - mainView.setMenuHidden(true) - mainView.changeSetupConstraints() - - onItemTapped = { [weak self] itemIndex in - self?.reactor?.action.onNext(.itemTapped(itemIndex)) - } - - onLoadMore = { [weak self] in - self?.reactor?.action.onNext(.loadMore) - } - } -} - -// MARK: - Bind -extension AnnouncementViewController { - func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .take(1) - .map { _ in Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - reactor.state - .map(\.alarms) - .distinctUntilChanged() - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind(onNext: { owner, items in - owner.mainView.detailItemStackView.arrangedSubviews.forEach { - owner.mainView.detailItemStackView.removeArrangedSubview($0) - $0.removeFromSuperview() - } - owner.createDetailItem(items: items) - }) - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseView.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseView.swift deleted file mode 100644 index 9ba80e06..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseView.swift +++ /dev/null @@ -1,286 +0,0 @@ -import UIKit - -import DesignSystem -/* - **고객지원 공통뷰가 될 것 같음** - */ -final class CustomerSupportBaseView: UIView { - // MARK: - Type - public enum Constant { - static let iconInset: CGFloat = 10 - static let buttonSize: CGFloat = 44 - static let horizontalInset: CGFloat = 16 - static let topMargin: CGFloat = 20 - static let menuStackViewHeight: CGFloat = 40 - static let underlineHeight: CGFloat = 2 - static let spacerHeight: CGFloat = 1 - static let imageSize: CGFloat = 20 - static let textWidth: CGFloat = 300 - static let viewHeight: CGFloat = 86 - static let dateTopMargin: CGFloat = 4 - static let emptyLabelHeight: CGFloat = 86 - static let emptyLabelInset: CGFloat = 16 - - static let menuTabBarButtonInset: NSDirectionalEdgeInsets = .init(top: 9, leading: 4, bottom: 9, trailing: 4) - static let menuTabBarHorizontalInset: UIEdgeInsets = .init(top: 0, left: 16, bottom: 0, right: 16) - } - - // MARK: - Components - // 헤더 뷰 - public let headerView = UIView() - - public let backButton: UIButton = { - let button = UIButton() - button - .setImage( - DesignSystemAsset - .image(named: "arrowBack")? - .withRenderingMode(.alwaysTemplate) - .resizableImage( - withCapInsets: UIEdgeInsets( - top: Constant.iconInset, - left: Constant.iconInset, - bottom: Constant.iconInset, - right: Constant.iconInset - ) - ), - for: .normal - ) - button.tintColor = .textColor - return button - }() - - public let titleLabel = UILabel() - - let menuContainerView = UIView() - - // 이벤트 메뉴(진행중, 종료) 스택 뷰 - let menuStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .horizontal - stackView.distribution = .fill - stackView.spacing = 20 - stackView.alignment = .leading - stackView.isLayoutMarginsRelativeArrangement = true - stackView.layoutMargins = Constant.menuTabBarHorizontalInset - return stackView - }() - - let bottomLineView: UIView = { - let view = UIView() - view.backgroundColor = .neutral300 - return view - }() - - // 메뉴 스택뷰 왼쪽 정렬을 위해서 - let emptyView = UIView() - - /// 아이템 스 택뷰 담을 스크롤 뷰 - public let scrollView: UIScrollView = { - let scrollView = UIScrollView() - return scrollView - }() - - // 아이템 담을 스택 뷰 - let detailItemStackView: UIStackView = { - let stackView = UIStackView() - stackView.axis = .vertical - stackView.distribution = .fill - stackView.alignment = .fill - stackView.isLayoutMarginsRelativeArrangement = true - stackView.layoutMargins = Constant.menuTabBarHorizontalInset - return stackView - }() - - // MARK: - Init - init() { - super.init(frame: .zero) - addViews() - setupConstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension CustomerSupportBaseView { - func addViews() { - [backButton, titleLabel].forEach { headerView.addSubview($0) } - [headerView, menuContainerView, scrollView].forEach { addSubview($0) } - scrollView.addSubview(detailItemStackView) - menuContainerView.addSubview(menuStackView) - menuContainerView.addSubview(bottomLineView) - } - - func setupConstraints() { - headerView.snp.makeConstraints { make in - make.top.equalTo(self.safeAreaLayoutGuide.snp.top) - make.horizontalEdges.equalToSuperview() - make.height.equalTo(Constant.buttonSize) - } - - backButton.snp.makeConstraints { make in - make.leading.centerY.equalToSuperview() - make.size.equalTo(Constant.buttonSize) - make.centerY.equalToSuperview() - } - - titleLabel.snp.makeConstraints { make in - make.leading.equalTo(backButton.snp.trailing) - make.centerY.equalToSuperview() - } - - menuContainerView.snp.makeConstraints { make in - make.top.equalTo(headerView.snp.bottom).offset(Constant.topMargin) - make.width.equalToSuperview() - make.height.equalTo(Constant.menuStackViewHeight) - } - menuStackView.snp.makeConstraints { make in - make.width.equalToSuperview() - make.height.equalTo(Constant.menuStackViewHeight) - make.edges.equalToSuperview() - } - - bottomLineView.snp.makeConstraints { make in - make.bottom.equalToSuperview() - make.width.equalToSuperview() - make.height.equalTo(Constant.spacerHeight) - } - - scrollView.snp.makeConstraints { make in - make.top.equalTo(menuContainerView.snp.bottom) - make.width.equalToSuperview() - make.horizontalEdges.equalToSuperview() - make.bottom.equalToSuperview() - } - - detailItemStackView.snp.makeConstraints { make in - make.top.equalToSuperview() - make.width.equalToSuperview() - make.bottom.equalToSuperview() - } - } -} - -extension CustomerSupportBaseView { - func createMenuButton(title: String, tag: Int) -> UIButton { - let config = setupConfig() - let button = UIButton(configuration: config) - button.setAttributedTitle(.makeStyledString(font: .b_m_r, text: title), for: .normal) - button.setTitleColor(.neutral600, for: .normal) - button.titleLabel?.font = UIFont.b_m_r - button.tag = tag - - let underline = UIView() - underline.backgroundColor = .textColor - underline.isHidden = true - underline.tag = 999999 - - button.addSubview(underline) - underline.snp.makeConstraints { make in - make.height.equalTo(Constant.underlineHeight) - make.leading.trailing.bottom.equalToSuperview() - } - return button - } - - func setupConfig() -> UIButton.Configuration { - var config = UIButton.Configuration.plain() - config.contentInsets = Constant.menuTabBarButtonInset - return config - } - - func createDetailItem(titleText: String, dateText: String?) -> UIView { // 제목, 날짜 데이터 필요 - let view = UIView() - let title = UILabel() - let date = UILabel() - let spacer = UIView() - let imageView = UIImageView() - imageView.image = DesignSystemAsset.image(named: "arrowForwardSmall") - - title.attributedText = .makeStyledString(font: .sub_m_sb, text: titleText) - title.textAlignment = .left - - date.attributedText = .makeStyledString(font: .b_s_r, text: dateText, color: .neutral700) - - view.addSubview(title) - view.addSubview(date) - view.addSubview(imageView) - - spacer.backgroundColor = UIColor.neutral200 - - view.snp.makeConstraints { make in - make.height.equalTo(Constant.viewHeight) - } - if dateText != nil { - title.snp.makeConstraints { make in - make.top.equalToSuperview().inset(Constant.topMargin) - // 임의 너비 설정 - make.width.equalTo(Constant.textWidth) - } - date.snp.makeConstraints { make in - make.top.equalTo(title.snp.bottom).offset(Constant.dateTopMargin) - } - } else { - title.snp.makeConstraints { make in - make.centerY.equalToSuperview() - make.width.equalTo(Constant.textWidth) - } - } - imageView.snp.makeConstraints { make in - make.size.equalTo(Constant.imageSize) - make.centerY.equalToSuperview() - make.trailing.equalToSuperview() - } - spacer.snp.makeConstraints { make in - make.height.equalTo(Constant.spacerHeight) - } - - detailItemStackView.addArrangedSubview(view) - detailItemStackView.addArrangedSubview(spacer) - - return view - } - - func setupSpacerView() { - let spacerView = UIView() - spacerView.setContentHuggingPriority(.defaultLow, for: .horizontal) - menuStackView.addArrangedSubview(spacerView) - } - - // 이벤트 뷰가 아닐 경우 메뉴 태그 필요없음 -> 제약사항 변경 되어야 함 - func changeSetupConstraints() { - scrollView.snp.remakeConstraints { make in - make.top.equalTo(headerView.snp.bottom).offset(Constant.topMargin) - make.width.equalToSuperview() - make.horizontalEdges.equalToSuperview() - make.bottom.equalToSuperview() - } - setMenuHidden(true) // menuContainer뷰 숨기기 - } - - // menuContainerView Encapsulation - func setMenuHidden(_ hidden: Bool) { - menuContainerView.isHidden = hidden - } - - func setEmpty(text: String) { - let label = UILabel() - label.attributedText = .makeStyledString(font: .b_m_r, text: text, color: .neutral700, alignment: .left) - let view = UIView() - - view.addSubview(label) - - view.snp.makeConstraints { make in - make.height.equalTo(Constant.emptyLabelHeight) - } - label.snp.makeConstraints { make in - make.horizontalEdges.equalToSuperview().inset(Constant.emptyLabelInset) - make.centerY.equalToSuperview() - } - detailItemStackView.addArrangedSubview(view) - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewController.swift deleted file mode 100644 index bf643f53..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewController.swift +++ /dev/null @@ -1,161 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem -import DomainInterface -import MyPageFeatureInterface - -import RxCocoa -import RxGesture -import RxSwift -/* - **부모 뷰컨이 될 것 같음** - */ -class CustomerSupportBaseViewController: BaseViewController { - // MARK: - Properties - public var disposeBag = DisposeBag() - - /// 현재 보여지고 있는 뷰의 인덱스 - public var currentTabIndex: Int? - public var urlStrings: [String] = [] - var onItemTapped: ((Int) -> Void)? - var onLoadMore: (() -> Void)? - - private let policyFactory: PolicyFactory? - - // MARK: - Components - public var mainView = CustomerSupportBaseView() - public var type: CustomerSupportType - - public init(type: CustomerSupportType) { - self.type = type - self.policyFactory = nil - super.init() - mainView.titleLabel.attributedText = .makeStyledString(font: .sub_m_b, text: type.detailTitle) - } - - public init(type: CustomerSupportType, policyFactory: PolicyFactory) { - self.type = type - mainView.titleLabel.attributedText = .makeStyledString(font: .sub_m_b, text: type.detailTitle) - self.policyFactory = policyFactory - super.init() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - isBottomTabbarHidden = true - addViews() - setupConstaraints() - bindBackButton() - bindScrollPagination() - } - - func createDetailItem(items: [AlarmResponse]) { - for (index, item) in items.enumerated() { - let view = mainView.createDetailItem(titleText: item.title, dateText: item.date.toDisplayDateString()) - view.tag = index - urlStrings.append(item.link) - - view.isUserInteractionEnabled = true // 꼭 필요! - - view.rx.tapGesture() - .when(.recognized) - .subscribe(onNext: { [weak self] _ in - self?.handleItemTap(index: index) - }) - .disposed(by: disposeBag) - } - } - - func createTermsDetailItem(items: [String]) { - for (index, item) in items.enumerated() { - let view = mainView.createDetailItem(titleText: item, dateText: nil) - view.tag = index // 뷰에 index 태그 부여 (URL 매핑용) - - view.isUserInteractionEnabled = true - - view.rx.tapGesture() - .when(.recognized) - .subscribe(onNext: { [weak self] _ in - self?.handleItemTap(index: index) - }) - .disposed(by: disposeBag) - } - } -} - -// MARK: - SetUp -extension CustomerSupportBaseViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstaraints() { - mainView.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide) - make.horizontalEdges.bottom.equalToSuperview() - } - } -} - -extension CustomerSupportBaseViewController { - func handleItemTap(index: Int) { - // 원하는 URL 열기 또는 네비게이션 처리 - switch type { - case .announcement, .event, .patchNote: - onItemTapped?(index) - guard index < urlStrings.count else { return } - let url = urlStrings[index] - if let webViewController = WebViewController.make(urlString: url) { - present(webViewController, animated: true) - } - case .terms: - switch index { - case 0: - guard let viewController = policyFactory?.make(type: .service) else { return } - navigationController?.pushViewController(viewController, animated: true) - case 1: - guard let viewController = policyFactory?.make(type: .service) else { return } - navigationController?.pushViewController(viewController, animated: true) - case 2: - guard let url = URL(string: UIApplication.openSettingsURLString) else { return } - if UIApplication.shared.canOpenURL(url) { - UIApplication.shared.open(url, options: [:], completionHandler: nil) - } - default: - break - } - } - } - - func bindBackButton() { - mainView.backButton.rx.tap - .bind { [weak self] in - self?.navigationController?.popViewController(animated: true) - } - .disposed(by: disposeBag) - } - - func bindScrollPagination() { - mainView.scrollView.rx.contentOffset - .throttle(.milliseconds(300), scheduler: MainScheduler.instance) - .map { [weak self] offset -> Bool in - guard let self = self else { return false } - let contentHeight = self.mainView.scrollView.contentSize.height - let height = self.mainView.scrollView.frame.size.height - let offsetY = offset.y - return offsetY > contentHeight - height - 100 - } - .distinctUntilChanged() - .filter { $0 } - .bind { [weak self] _ in - self?.onLoadMore?() - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewFactoryImpl.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewFactoryImpl.swift deleted file mode 100644 index 3507e671..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/CustomerSupportBaseViewFactoryImpl.swift +++ /dev/null @@ -1,56 +0,0 @@ -import BaseFeature -import DomainInterface -import MyPageFeatureInterface - -public final class CustomerSupportBaseViewFactoryImpl: CustomerSupportFactory { - private let policyFactory: PolicyFactory - - private let fetchNoticesUseCase: FetchNoticesUseCase - private let fetchOngoingEventsUseCase: FetchOngoingEventsUseCase - private let fetchOutdatedEventsUseCase: FetchOutdatedEventsUseCase - private let fetchPatchNotesUseCase: FetchPatchNotesUseCase - private let setReadUseCase: SetReadUseCase - - public init( - policyFactory: PolicyFactory, - fetchNoticesUseCase: FetchNoticesUseCase, - fetchOngoingEventsUseCase: FetchOngoingEventsUseCase, - fetchOutdatedEventsUseCase: FetchOutdatedEventsUseCase, - fetchPatchNotesUseCase: FetchPatchNotesUseCase, - setReadUseCase: SetReadUseCase - ) { - self.policyFactory = policyFactory - self.fetchNoticesUseCase = fetchNoticesUseCase - self.fetchOngoingEventsUseCase = fetchOngoingEventsUseCase - self.fetchOutdatedEventsUseCase = fetchOutdatedEventsUseCase - self.fetchPatchNotesUseCase = fetchPatchNotesUseCase - self.setReadUseCase = setReadUseCase - } - - public func make(type: CustomerSupportType) -> BaseViewController { - var viewController = BaseViewController() - - switch type { - case .event: - viewController = EventViewController(type: .event) - if let viewController = viewController as? EventViewController { - viewController.reactor = EventReactor(fetchOngoingEventsUseCase: fetchOngoingEventsUseCase, fetchOutdatedEventsUseCase: fetchOutdatedEventsUseCase, setReadUseCase: setReadUseCase) - } - case .announcement: - viewController = AnnouncementViewController(type: .announcement) - if let viewController = viewController as? AnnouncementViewController { - viewController.reactor = AnnouncementReactor(fetchNoticesUseCase: fetchNoticesUseCase, setReadUseCase: setReadUseCase) - } - case .patchNote: - viewController = PatchNoteViewController(type: .patchNote) - if let viewController = viewController as? PatchNoteViewController { - viewController.reactor = PatchNoteReactor(fetchPatchNotesUseCase: fetchPatchNotesUseCase, setReadUseCase: setReadUseCase) - } - case .terms: - viewController = TermsViewController(type: .terms, policyFactory: policyFactory) - } - - viewController.isBottomTabbarHidden = true - return viewController - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventReactor.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventReactor.swift deleted file mode 100644 index 92b9ebce..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventReactor.swift +++ /dev/null @@ -1,103 +0,0 @@ -import ReactorKit - -import DomainInterface - -public final class EventReactor: Reactor { - // MARK: - Reactor - public enum Route { - case none - } - - public enum Action { - case loadMore - case selectTab(Int) - case itemTapped(Int) - } - - public enum Mutation { - case setAlarms([AlarmResponse], hasMore: Bool, reset: Bool) - case setLoading(Bool) - case setIndex(Int) - } - - public struct State { - var alarms = [AlarmResponse]() - var selectedIndex = 0 - var hasMore = false - var isLoading = false - } - - // MARK: - Properties - public var initialState: State - private let disposeBag = DisposeBag() - private let fetchOngoingEventsUseCase: FetchOngoingEventsUseCase - private let fetchOutdatedEventsUseCase: FetchOutdatedEventsUseCase - private let setReadUseCase: SetReadUseCase - - public init(fetchOngoingEventsUseCase: FetchOngoingEventsUseCase, fetchOutdatedEventsUseCase: FetchOutdatedEventsUseCase, setReadUseCase: SetReadUseCase) { - self.initialState = .init() - self.fetchOngoingEventsUseCase = fetchOngoingEventsUseCase - self.fetchOutdatedEventsUseCase = fetchOutdatedEventsUseCase - self.setReadUseCase = setReadUseCase - } - - public func mutate(action: Action) -> Observable { - switch action { - case let .selectTab(index): - let fetchObservable = (index == 0 - ? fetchOngoingEventsUseCase.execute(id: nil, pageSize: 20) - : fetchOutdatedEventsUseCase.execute(id: nil, pageSize: 20)) - .map { paged -> Mutation in - .setAlarms(paged.items, hasMore: paged.hasMore, reset: true) - } - .catch { error -> Observable in - print("Fetch error: \(error)") - return .just(.setLoading(false)) - } - - return .concat([ - .just(.setIndex(index)), - .just(.setLoading(true)), - fetchObservable, - .just(.setLoading(false)) - ]) - - case .loadMore: - guard currentState.hasMore, !currentState.isLoading else { return .empty() } - let lastCursor = currentState.alarms.last?.id - - return .concat([ - .just(.setLoading(true)), - (currentState.selectedIndex == 0 ? fetchOngoingEventsUseCase.execute(id: lastCursor, pageSize: 20) : fetchOutdatedEventsUseCase.execute(id: lastCursor, pageSize: 20)) - .map { paged in - .setAlarms(paged.items, hasMore: paged.hasMore, reset: false) - }, - .just(.setLoading(false)) - ]) - case let .itemTapped(index): - return setReadUseCase.execute(alarmLink: currentState.alarms[index].link) - .andThen(.empty()) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case let .setIndex(index): - newState.selectedIndex = index - case let .setAlarms(newAlarms, hasMore, reset): - if reset { - newState.alarms = newAlarms - } else { - newState.alarms.append(contentsOf: newAlarms) - } - newState.hasMore = hasMore - - case let .setLoading(isLoading): - newState.isLoading = isLoading - } - - return newState - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventViewController.swift deleted file mode 100644 index 146c91c1..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Event/EventViewController.swift +++ /dev/null @@ -1,100 +0,0 @@ -import DomainInterface -import ReactorKit -import UIKit - -final class EventViewController: CustomerSupportBaseViewController, View { - typealias Reactor = EventReactor - - // MARK: - Init - override init(type: CustomerSupportType) { - super.init(type: type) - } - - override func viewDidLoad() { - super.viewDidLoad() - setupMenu() - - onItemTapped = { [weak self] itemIndex in - self?.reactor?.action.onNext(.itemTapped(itemIndex)) - } - - onLoadMore = { [weak self] in - self?.reactor?.action.onNext(.loadMore) - } - } - - // MARK: - Setup - private func setupMenu() { - let ongoingButton = mainView.createMenuButton(title: "진행중인 이벤트", tag: 0) - let endedButton = mainView.createMenuButton(title: "종료된 이벤트", tag: 1) - - mainView.menuStackView.addArrangedSubview(ongoingButton) - mainView.menuStackView.addArrangedSubview(endedButton) - mainView.setupSpacerView() - - guard let reactor = reactor else { return } - mainView.menuStackView.arrangedSubviews - .compactMap { $0 as? UIButton } - .forEach { button in - button.rx.tap - .map { Reactor.Action.selectTab(button.tag) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - } -} - -// MARK: - Bind -extension EventViewController { - func bind(reactor: Reactor) { - reactor.action.onNext(.selectTab(0)) - bindViewState(reactor: reactor) - } - - private func bindViewState(reactor: Reactor) { - reactor.state.map(\.selectedIndex) - .observe(on: MainScheduler.instance) - .bind { [weak self] selectedIndex in - guard let self else { return } - self.updateButtonStates(in: self.mainView.menuStackView, selectedTag: selectedIndex) - } - .disposed(by: disposeBag) - - reactor.state.map(\.alarms) - .distinctUntilChanged() - .observe(on: MainScheduler.instance) - .bind { [weak self] items in - guard let self else { return } - self.mainView.detailItemStackView.arrangedSubviews.forEach { subview in - self.mainView.detailItemStackView.removeArrangedSubview(subview) - subview.removeFromSuperview() - } - let eventType = reactor.currentState.selectedIndex == 0 ? "진행중인" : "종료된" - if items.isEmpty { - self.mainView.setEmpty(text: "\(eventType) 이벤트가 없습니다.") - } else { - self.createDetailItem(items: items) - } - } - .disposed(by: disposeBag) - } -} - -// MARK: - Methods -private extension EventViewController { - private func updateButtonStates(in stackView: UIStackView, selectedTag: Int) { - for (index, subview) in stackView.arrangedSubviews.enumerated() { - guard let button = subview as? UIButton else { continue } - let title = button.titleLabel?.text ?? "" - let underline = button.subviews.first { $0.tag == 999999 } - - if index == selectedTag { - button.setAttributedTitle(.makeStyledString(font: .sub_m_b, text: title, color: .black), for: .normal) - underline?.isHidden = false - } else { - button.setAttributedTitle(.makeStyledString(font: .b_m_r, text: title, color: .neutral600), for: .normal) - underline?.isHidden = true - } - } - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/PatchNote/PatchNoteReactor.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/PatchNote/PatchNoteReactor.swift deleted file mode 100644 index 8aaa10c0..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/PatchNote/PatchNoteReactor.swift +++ /dev/null @@ -1,86 +0,0 @@ -import ReactorKit - -import DomainInterface - -public final class PatchNoteReactor: Reactor { - // MARK: - Reactor - public enum Route { - case none - } - - public enum Action { - case viewWillAppear - case loadMore - case itemTapped(Int) - } - - public enum Mutation { - case setAlarms([AlarmResponse], hasMore: Bool, reset: Bool) - case setLoading(Bool) - } - - public struct State { - var alarms = [AlarmResponse]() - var hasMore = false - var isLoading = false - } - - // MARK: - Properties - public var initialState: State - private let disposeBag = DisposeBag() - private let fetchPatchNotesUseCase: FetchPatchNotesUseCase - private let setReadUseCase: SetReadUseCase - - public init(fetchPatchNotesUseCase: FetchPatchNotesUseCase, setReadUseCase: SetReadUseCase) { - self.initialState = .init() - self.fetchPatchNotesUseCase = fetchPatchNotesUseCase - self.setReadUseCase = setReadUseCase - } - - public func mutate(action: Action) -> Observable { - switch action { - case .viewWillAppear: - return .concat([ - .just(.setLoading(true)), - fetchPatchNotesUseCase.execute(id: nil, pageSize: 20) - .map { paged in - .setAlarms(paged.items, hasMore: paged.hasMore, reset: true) - }, - .just(.setLoading(false)) - ]) - case .loadMore: - guard currentState.hasMore, !currentState.isLoading else { return .empty() } - let lastCursor = currentState.alarms.last?.id - return .concat([ - .just(.setLoading(true)), - fetchPatchNotesUseCase.execute(id: lastCursor, pageSize: 20) - .map { paged in - .setAlarms(paged.items, hasMore: paged.hasMore, reset: false) - }, - .just(.setLoading(false)) - ]) - case .itemTapped(let index): - return setReadUseCase.execute(alarmLink: currentState.alarms[index].link) - .andThen(.empty()) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case let .setAlarms(newAlarms, hasMore, reset): - if reset { - newState.alarms = newAlarms - } else { - newState.alarms.append(contentsOf: newAlarms) - } - newState.hasMore = hasMore - - case let .setLoading(isLoading): - newState.isLoading = isLoading - } - - return newState - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/PatchNote/PatchNoteViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/PatchNote/PatchNoteViewController.swift deleted file mode 100644 index 3935c851..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/PatchNote/PatchNoteViewController.swift +++ /dev/null @@ -1,62 +0,0 @@ -import UIKit - -import DomainInterface - -import ReactorKit - -final class PatchNoteViewController: CustomerSupportBaseViewController, View { - typealias Reactor = PatchNoteReactor - - // MARK: - Init - override init(type: CustomerSupportType) { - super.init(type: type) - } - - override func viewDidLoad() { - super.viewDidLoad() - - // 타입을 나눠서 베이스에서 다 처리하는게 나을려나?? - mainView.setMenuHidden(true) - mainView.changeSetupConstraints() - - onItemTapped = { [weak self] itemIndex in - self?.reactor?.action.onNext(.itemTapped(itemIndex)) - } - - onLoadMore = { [weak self] in - self?.reactor?.action.onNext(.loadMore) - } - } -} - -// MARK: - Bind -extension PatchNoteViewController { - func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) {} - - func bindViewState(reactor: Reactor) { - rx.viewWillAppear - .take(1) - .map { _ in Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - reactor.state - .map { $0.alarms } - .distinctUntilChanged() - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind(onNext: { owner, alarms in - owner.mainView.detailItemStackView.arrangedSubviews.forEach { - owner.mainView.detailItemStackView.removeArrangedSubview($0) - $0.removeFromSuperview() - } - owner.createDetailItem(items: alarms) - }) - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Policy/PolicyFactoryImpl.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Policy/PolicyFactoryImpl.swift deleted file mode 100644 index dcadf10a..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Policy/PolicyFactoryImpl.swift +++ /dev/null @@ -1,12 +0,0 @@ -import BaseFeature -import MyPageFeatureInterface - -public final class PolicyFactoryImpl: PolicyFactory { - public init() {} - - public func make(type: PolicyType) -> BaseViewController { - let viewController = PolicyViewController(type: type) - viewController.isBottomTabbarHidden = true - return viewController - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Policy/PolicyView.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Policy/PolicyView.swift deleted file mode 100644 index df7f7fba..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Policy/PolicyView.swift +++ /dev/null @@ -1,86 +0,0 @@ -import UIKit - -import DesignSystem -import MyPageFeatureInterface - -final class PolicyView: UIView { - // MARK: - Type - public enum Constant { - static let verticalMargin: CGFloat = 20 - static let horizontalMargin: CGFloat = 16 - } - - // MARK: - Components - public let headerView = NavigationBar(type: .collection("약관 및 정책")) - - private let titleLabel = UILabel() - - private let contentTextView: UITextView = { - let view = UITextView() - view.isScrollEnabled = true - view.isEditable = false - view.isSelectable = false - return view - }() - - // MARK: - Init - init(type: PolicyType) { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI(type: type) - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension PolicyView { - func addViews() { - addSubview(headerView) - addSubview(titleLabel) - addSubview(contentTextView) - } - - func setupConstraints() { - headerView.snp.makeConstraints { make in - make.top.horizontalEdges.equalToSuperview() - } - - titleLabel.snp.makeConstraints { make in - make.top.equalTo(headerView.snp.bottom).offset(Constant.verticalMargin) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalMargin) - } - - contentTextView.snp.makeConstraints { make in - make.top.equalTo(titleLabel.snp.bottom).offset(Constant.verticalMargin) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalMargin) - make.bottom.equalToSuperview().inset(Constant.verticalMargin) - } - } - - func configureUI(type: PolicyType) { - headerView.editButton.isHidden = true - headerView.addButton.isHidden = true - headerView.setTitle(title: type.title) - titleLabel.attributedText = .makeStyledString(font: .h_xxxl_sb, text: "메랜사 \(type.title)", alignment: .left) - - let paragraphStyle = NSMutableParagraphStyle() - paragraphStyle.lineBreakMode = .byWordWrapping - paragraphStyle.alignment = .left - - let attrString = NSAttributedString( - string: type.content, - attributes: [ - .font: UIFont.b_s_r ?? .systemFont(ofSize: 12), - .foregroundColor: UIColor.textColor, - .paragraphStyle: paragraphStyle - ] - ) - - contentTextView.attributedText = attrString - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Policy/PolicyViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Policy/PolicyViewController.swift deleted file mode 100644 index bd108f2c..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Policy/PolicyViewController.swift +++ /dev/null @@ -1,61 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem -import DomainInterface -import MyPageFeatureInterface - -import RxCocoa -import RxGesture -import RxSwift -/* -**부모 뷰컨이 될 것 같음** - */ -class PolicyViewController: BaseViewController { - // MARK: - Properties - public var disposeBag = DisposeBag() - - // MARK: - Components - public var mainView: PolicyView - - public init(type: PolicyType) { - self.mainView = PolicyView(type: type) - super.init() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - override func viewDidLoad() { - super.viewDidLoad() - addViews() - setupConstaraints() - bind() - } -} - -// MARK: - SetUp -extension PolicyViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstaraints() { - mainView.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide) - make.horizontalEdges.bottom.equalToSuperview() - } - } - - func bind() { - mainView.headerView.leftButton.rx.tap - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, _ in - owner.navigationController?.popViewController(animated: true) - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Policy/TermsViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Policy/TermsViewController.swift deleted file mode 100644 index bf93585c..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/CustomerSupport/Policy/TermsViewController.swift +++ /dev/null @@ -1,16 +0,0 @@ -import UIKit - -import MyPageFeatureInterface - -final class TermsViewController: CustomerSupportBaseViewController { - - override func viewDidLoad() { - super.viewDidLoad() - - let items = PolicyType.allCases - - mainView.setMenuHidden(true) - mainView.changeSetupConstraints() - createTermsDetailItem(items: items.map { $0.title }) - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageListCell.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageListCell.swift deleted file mode 100644 index 7ecb2f75..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageListCell.swift +++ /dev/null @@ -1,88 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -public final class MyPageListCell: UICollectionViewCell { - // MARK: - Type - enum Constant { - static let inset: CGFloat = 10 - static let badgeMargin: CGFloat = 12 - } - - // MARK: - Components - private let titleLabel = UILabel() - - private let iconView: UIImageView = { - let view = UIImageView() - view.image = DesignSystemAsset.image(named: "arrowForwardSmall") - return view - }() - - var levelBadge: Badge? - - // MARK: - init - override init(frame: CGRect) { - super.init(frame: frame) - - addViews() - setupContstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension MyPageListCell { - func addViews() { - addSubview(titleLabel) - addSubview(iconView) - } - - func setupContstraints() { - titleLabel.snp.makeConstraints { make in - make.leading.equalToSuperview().inset(Constant.inset) - make.centerY.equalToSuperview() - } - - iconView.snp.makeConstraints { make in - make.trailing.equalToSuperview().inset(Constant.inset) - make.centerY.equalToSuperview() - } - } -} - -public extension MyPageListCell { - struct Input { - let title: String - var isHeader: Bool - var addLevel: Int? - - init(title: String, isHeader: Bool = false, addLevel: Int? = nil) { - self.title = title - self.isHeader = isHeader - self.addLevel = addLevel - } - } - - func inject(input: Input) { - titleLabel.attributedText = .makeStyledString(font: input.isHeader ? .sub_m_b : .b_m_r, text: input.title, alignment: .left) - iconView.isHidden = input.isHeader - levelBadge?.removeFromSuperview() - if let level = input.addLevel { - let levelBadge = Badge(style: .element("Lv.\(level)")) - - addSubview(levelBadge) - - levelBadge.snp.makeConstraints { make in - make.leading.equalTo(titleLabel.snp.trailing).offset(Constant.badgeMargin) - make.centerY.equalToSuperview() - } - self.levelBadge = levelBadge - } - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageMainCell.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageMainCell.swift deleted file mode 100644 index a02d2651..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageMainCell.swift +++ /dev/null @@ -1,131 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem - -import RxCocoa -import RxSwift -import SnapKit - -public final class MyPageMainCell: UICollectionViewCell { - // MARK: - Type - enum Constant { - static let imageSize: CGFloat = 104 - static let spacingBetweenImageAndLabel: CGFloat = 12 - static let spacingBetweenLabelAndButton: CGFloat = 16 - static let buttonHeight: CGFloat = 44 - static let horizontalInset: CGFloat = 16 - static let verticalInset: CGFloat = 20 - static let radius: CGFloat = 42 - } - - // MARK: - Properties - private let disposeBag = DisposeBag() - public var onSetProfileTap: (() -> Void)? - - // MARK: - Components - private let imageView: UIImageView = { - let imageView = UIImageView() - imageView.contentMode = .scaleAspectFill - imageView.clipsToBounds = true - imageView.layer.cornerRadius = Constant.radius - return imageView - }() - - private let nameLabel: UILabel = { - let label = UILabel() - label.numberOfLines = 2 - label.textAlignment = .center - return label - }() - - public let setProfileButton = CommonButton(style: .normal, title: "프로필 설정", disabledTitle: nil) - - private lazy var contentStackView: UIStackView = { - let stack = UIStackView(arrangedSubviews: [imageView, nameLabel, setProfileButton]) - stack.axis = .vertical - stack.alignment = .center - stack.spacing = Constant.spacingBetweenImageAndLabel - return stack - }() - - // MARK: - Init - override init(frame: CGRect) { - super.init(frame: frame) - addViews() - setupConstraints() - configureUI() - bindButton() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - Setup -private extension MyPageMainCell { - func addViews() { - addSubview(contentStackView) - } - - func setupConstraints() { - contentStackView.snp.makeConstraints { make in - make.top.bottom.equalToSuperview().inset(Constant.verticalInset) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - } - - imageView.snp.makeConstraints { make in - make.size.equalTo(Constant.imageSize) - } - - setProfileButton.snp.remakeConstraints { make in - make.height.equalTo(Constant.buttonHeight) - make.horizontalEdges.equalToSuperview() - } - } - - func configureUI() { - backgroundColor = .whiteMLS - } - - func bindButton() { - setProfileButton.rx.tap - .withUnretained(self) - .subscribe { owner, _ in - owner.onSetProfileTap?() - } - .disposed(by: disposeBag) - } -} - -// MARK: - Public -public extension MyPageMainCell { - struct Input { - let imageUrl: String - let name: String - let isLogin: Bool - } - - func inject(input: Input) { - if input.isLogin { - imageView.isHidden = false - ImageLoader.shared.loadImage(stringURL: input.imageUrl) { [weak self] image in - self?.imageView.image = image - } - nameLabel.attributedText = .makeStyledString(font: .sub_l_b, text: input.name) - contentStackView.spacing = Constant.spacingBetweenImageAndLabel - setProfileButton.updateTitle(title: "프로필 설정") - } else { - imageView.isHidden = true - nameLabel.attributedText = .makeStyledString( - font: .b_s_m, - text: "로그인 후 이벤트 실시간 알림과 북마크\n그리고 최적화된 검색 서비스를 이용해보세요", - color: .neutral500 - ) - contentStackView.spacing = Constant.spacingBetweenLabelAndButton - setProfileButton.updateTitle(title: "로그인 하기") - } - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageMainFactoryImpl.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageMainFactoryImpl.swift deleted file mode 100644 index 6c45c1f2..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageMainFactoryImpl.swift +++ /dev/null @@ -1,41 +0,0 @@ -import AuthFeatureInterface -import BaseFeature -import DomainInterface -import MyPageFeatureInterface - -public final class MyPageMainFactoryImpl: MyPageMainFactory { - private let loginFactory: LoginFactory - private let setProfileFactory: SetProfileFactory - private let customerSupportFactory: CustomerSupportFactory - private let notificationSettingFactory: NotificationSettingFactory - private let setCharacterFactory: SetCharacterFactory - private let fetchProfileUseCase: FetchProfileUseCase - - public init( - loginFactory: LoginFactory, - setProfileFactory: SetProfileFactory, - customerSupportFactory: CustomerSupportFactory, - notificationSettingFactory: NotificationSettingFactory, - setCharacterFactory: SetCharacterFactory, - fetchProfileUseCase: FetchProfileUseCase - ) { - self.loginFactory = loginFactory - self.setProfileFactory = setProfileFactory - self.customerSupportFactory = customerSupportFactory - self.notificationSettingFactory = notificationSettingFactory - self.setCharacterFactory = setCharacterFactory - self.fetchProfileUseCase = fetchProfileUseCase - } - - public func make() -> BaseViewController { - let viewController = MyPageMainViewController( - setProfileFactory: setProfileFactory, - customerSupportFactory: customerSupportFactory, - notificationSettingFactory: notificationSettingFactory, - setCharacterFactory: setCharacterFactory, - loginFactory: loginFactory - ) - viewController.reactor = MyPageMainReactor(fetchProfileUseCase: fetchProfileUseCase) - return viewController - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageMainReactor.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageMainReactor.swift deleted file mode 100644 index 514303ad..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageMainReactor.swift +++ /dev/null @@ -1,150 +0,0 @@ -import DomainInterface - -import ReactorKit - -public final class MyPageMainReactor: Reactor { - // MARK: - Type - public enum MyPageMenu { - case setAlarm - case setCharacterInfo(MyPageResponse?) - case showEvent - case showNotice - case showPatchNode - case showPolicy - - var route: Route { - switch self { - case .setAlarm: - .notificationSetting - case .showEvent: - .event - case .showNotice: - .notice - case .showPatchNode: - .patchNode - case .showPolicy: - .policy - case .setCharacterInfo: - .characterInfoSetting - } - } - - var description: String { - switch self { - case .setAlarm: - "알림 설정" - case .setCharacterInfo: - "캐릭터 정보 설정" - case .showEvent: - "메이플랜드 이벤트" - case .showNotice: - "메이플랜드 공지사항" - case .showPatchNode: - "메이플랜드 패치노트" - case .showPolicy: - "약관 및 정책" - } - } - - var requiresLogin: Bool { - switch self { - case .setAlarm, .setCharacterInfo: - return true - default: - return false - } - } - } - - // MARK: - Route - public enum Route { - case edit - case notificationSetting - case characterInfoSetting - case event - case notice - case patchNode - case policy - case login - } - - // MARK: - Action - public enum Action { - case viewWillAppear - case profileButtonTapped - case menuItemTapped(MyPageMenu) - } - - // MARK: - Mutation - public enum Mutation { - case toNavigate(Route) - case setProfile(MyPageResponse?) - } - - // MARK: - State - public struct State { - @Pulse var route: Route? - var menus: [[MyPageMenu]] = [ - [ - .setAlarm, - .setCharacterInfo(nil) - ], [ - .showEvent, - .showNotice, - .showPatchNode, - .showPolicy - ] - ] - var profile: MyPageResponse? - } - - // MARK: - Properties - public var initialState = State() - - private let fetchProfileUseCase: FetchProfileUseCase - - // MARK: - Init - public init(fetchProfileUseCase: FetchProfileUseCase) { - self.fetchProfileUseCase = fetchProfileUseCase - } - - // MARK: - Mutate - public func mutate(action: Action) -> Observable { - switch action { - case .profileButtonTapped: - if currentState.profile != nil { - return .just(.toNavigate(.edit)) - } else { - return .just(.toNavigate(.login)) - } - case .menuItemTapped(let menu): - if currentState.profile == nil, menu.requiresLogin { - return .just(.toNavigate(.login)) - } else { - return .just(.toNavigate(menu.route)) - } - case .viewWillAppear: - return fetchProfileUseCase.execute() - .map { .setProfile($0) } - .catch { error in - print(error) - return .just(.setProfile(nil)) - } - } - } - - // MARK: - Reduce - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .toNavigate(let route): - newState.route = route - case .setProfile(let profile): - newState.profile = profile - newState.menus[0][1] = .setCharacterInfo(profile) - } - - return newState - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageMainView.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageMainView.swift deleted file mode 100644 index 19ac70ed..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageMainView.swift +++ /dev/null @@ -1,68 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -public final class MyPageMainView: UIView { - // MARK: - Type - enum Constant { - static let titleLabelHeight: CGFloat = 44 - static let colletionViewTopMargin: CGFloat = 20 - static let horizontalInset: CGFloat = 16 - } - - // MARK: - Properties - - // MARK: - Components - private let titleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .h_xxxl_b, text: "마이페이지", alignment: .left) - return label - }() - - public let mainCollectionView: UICollectionView = { - let layout = UICollectionViewLayout() - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) - collectionView.backgroundColor = .neutral100 - return collectionView - }() - - // MARK: - init - public init() { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - SetUp -private extension MyPageMainView { - func addViews() { - addSubview(titleLabel) - addSubview(mainCollectionView) - } - - func setupConstraints() { - titleLabel.snp.makeConstraints { make in - make.top.equalTo(self.layoutMarginsGuide) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.height.equalTo(Constant.titleLabelHeight) - } - - mainCollectionView.snp.makeConstraints { make in - make.top.equalTo(titleLabel.snp.bottom).offset(Constant.colletionViewTopMargin) - make.horizontalEdges.bottom.equalToSuperview() - } - } - - func configureUI() { - backgroundColor = .whiteMLS - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageMainViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageMainViewController.swift deleted file mode 100644 index aa9bc141..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/Main/MyPageMainViewController.swift +++ /dev/null @@ -1,265 +0,0 @@ -import UIKit - -import AuthFeatureInterface -import BaseFeature -import MyPageFeatureInterface - -import ReactorKit -import RxSwift -import SnapKit - -public final class MyPageMainViewController: BaseViewController, View { - // MARK: - Type - enum Constant { - static let bottomHeight: CGFloat = 64 - } - - public typealias Reactor = MyPageMainReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - private let setProfileFactory: SetProfileFactory - private let customerSupportFactory: CustomerSupportFactory - private let notificationSettingFactory: NotificationSettingFactory - private let setCharacterFactory: SetCharacterFactory - private let loginFactory: LoginFactory - - // MARK: - Components - private let mainView = MyPageMainView() - - // MARK: - Init - public init(setProfileFactory: SetProfileFactory, customerSupportFactory: CustomerSupportFactory, notificationSettingFactory: NotificationSettingFactory, setCharacterFactory: SetCharacterFactory, loginFactory: LoginFactory) { - self.setProfileFactory = setProfileFactory - self.customerSupportFactory = customerSupportFactory - self.notificationSettingFactory = notificationSettingFactory - self.setCharacterFactory = setCharacterFactory - self.loginFactory = loginFactory - super.init() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // MARK: - Lifecycle - override public func viewDidLoad() { - super.viewDidLoad() - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - Setup -private extension MyPageMainViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.top.horizontalEdges.equalToSuperview() - make.bottom.equalTo(view.safeAreaLayoutGuide).inset(Constant.bottomHeight) - } - } - - func configureUI() { - mainView.mainCollectionView.collectionViewLayout = createLayout() - mainView.mainCollectionView.delegate = self - mainView.mainCollectionView.dataSource = self - mainView.mainCollectionView.register(MyPageMainCell.self, forCellWithReuseIdentifier: MyPageMainCell.identifier) - mainView.mainCollectionView.register(MyPageListCell.self, forCellWithReuseIdentifier: MyPageListCell.identifier) - } - - func createLayout() -> UICollectionViewLayout { - let layoutFactory = LayoutFactory() - - let layout = UICollectionViewCompositionalLayout { sectionIndex, _ in - switch sectionIndex { - case 0: - return layoutFactory.getMyPageMainLayout().build() - case 1: - return layoutFactory.getMyPageSettingLayout().build() - default: - return layoutFactory.getMyPageSupportLayout().build() - } - } - layout.register(SettingBackgroundView.self, forDecorationViewOfKind: SettingBackgroundView.identifier) - layout.register(SupportBackgroundView.self, forDecorationViewOfKind: SupportBackgroundView.identifier) - return layout - } -} - -// MARK: - Bind -extension MyPageMainViewController { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindState(reactor: reactor) - } - - private func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .map { _ in Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - private func bindState(reactor: Reactor) { - reactor.state - .map { $0.profile } - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind { owner, _ in - owner.mainView.mainCollectionView.reloadData() - } - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .observe(on: MainScheduler.instance) - .withUnretained(self) - .subscribe { owner, route in - switch route { - case .edit: - let viewController = owner.setProfileFactory.make() - if let viewController = viewController as? SetProfileViewController { - viewController.didReturn - .withUnretained(self) - .subscribe(onNext: { _, isUpdate in - if isUpdate { - ToastFactory.createToast(message: "프로필이 업데이트 되었어요.") - } - }) - .disposed(by: owner.disposeBag) - } - owner.navigationController?.pushViewController(viewController, animated: true) - case .characterInfoSetting: - let viewController = owner.setCharacterFactory.make() - owner.navigationController?.pushViewController(viewController, animated: true) - case .event: - let viewController = owner.customerSupportFactory.make(type: .event) - owner.navigationController?.pushViewController(viewController, animated: true) - case .notice: - let viewController = owner.customerSupportFactory.make(type: .announcement) - owner.navigationController?.pushViewController(viewController, animated: true) - case .patchNode: - let viewController = owner.customerSupportFactory.make(type: .patchNote) - owner.navigationController?.pushViewController(viewController, animated: true) - case .policy: - let viewController = owner.customerSupportFactory.make(type: .terms) - owner.navigationController?.pushViewController(viewController, animated: true) - case .notificationSetting: - guard let reactor = owner.reactor, - let profile = reactor.currentState.profile else { return } - let viewController = owner.notificationSettingFactory.make(isAgreeEventNotification: profile.eventAgreement, isAgreeNoticeNotification: profile.noticeAgreement, isAgreePatchNoteNotification: profile.patchNoteAgreement) - owner.navigationController?.pushViewController(viewController, animated: true) - case .login: - let viewController = owner.loginFactory.make(exitRoute: .pop) - owner.navigationController?.pushViewController(viewController, animated: true) - case .none: - break - } - } - .disposed(by: disposeBag) - } -} - -// MARK: - Delegate -extension MyPageMainViewController: UICollectionViewDelegate, UICollectionViewDataSource { - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - guard let reactor = reactor else { return 0 } - switch section { - case 0: - return 1 - case 1: - return reactor.currentState.menus[0].count + 1 - default: - return reactor.currentState.menus[1].count + 1 - } - } - - public func numberOfSections(in collectionView: UICollectionView) -> Int { - return 3 - } - - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - switch indexPath.section { - case 0: - guard let cell = collectionView.dequeueReusableCell( - withReuseIdentifier: MyPageMainCell.identifier, - for: indexPath - ) as? MyPageMainCell, - let reactor = reactor else { return UICollectionViewCell() } - - let profile = reactor.currentState.profile - cell.inject( - input: MyPageMainCell.Input( - imageUrl: profile?.profileUrl ?? "", - name: profile?.nickname ?? "", - isLogin: profile != nil - ) - ) - cell.onSetProfileTap = { [weak self] in - self?.reactor?.action.onNext(.profileButtonTapped) - } - return cell - - case 1, 2: - guard let cell = collectionView.dequeueReusableCell( - withReuseIdentifier: MyPageListCell.identifier, - for: indexPath - ) as? MyPageListCell, - let reactor = reactor else { return UICollectionViewCell() } - - let headerTitle: String - switch indexPath.section { - case 1: headerTitle = "설정" - default: headerTitle = "고객 지원" - } - - if indexPath.row == 0 { - cell.inject(input: MyPageListCell.Input(title: headerTitle, isHeader: true)) - } else { - // index.row == 0은 제목 - let item = reactor.currentState.menus[indexPath.section - 1][indexPath.row - 1] - switch item { - case .setCharacterInfo(let .some(profile)): - if let level = profile.level { - cell.inject(input: MyPageListCell.Input(title: profile.jobName, isHeader: false, addLevel: profile.level)) - } else { - cell.inject(input: MyPageListCell.Input(title: item.description, isHeader: false)) - } - default: - cell.inject(input: MyPageListCell.Input(title: item.description, isHeader: false)) - } - } - - return cell - - default: - return UICollectionViewCell() - } - } - - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - guard indexPath.section > 0 else { return } // section 0은 프로필 셀 - - let row = indexPath.row - guard row > 0 else { return } // row 0은 header - - // 메뉴 항목 가져오기 - guard let menu = reactor?.currentState.menus[indexPath.section - 1][row - 1] else { return } - // 액션 발생 - reactor?.action.onNext(.menuItemTapped(menu)) - } - - public func scrollViewDidScroll(_ scrollView: UIScrollView) { - // 디자이너 문의 필요 - if scrollView.contentOffset.y < 0 { - scrollView.contentOffset.y = 0 - } - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/NotificationSetting/NotificationSettingFactoryImpl.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/NotificationSetting/NotificationSettingFactoryImpl.swift deleted file mode 100644 index 10548ef8..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/NotificationSetting/NotificationSettingFactoryImpl.swift +++ /dev/null @@ -1,26 +0,0 @@ -import BaseFeature -import DomainInterface -import MyPageFeatureInterface - -public final class NotificationSettingFactoryImpl: NotificationSettingFactory { - private let checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase - private let updateNotificationAgreementUseCase: UpdateNotificationAgreementUseCase - - public init(checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase, updateNotificationAgreementUseCase: UpdateNotificationAgreementUseCase) { - self.checkNotificationPermissionUseCase = checkNotificationPermissionUseCase - self.updateNotificationAgreementUseCase = updateNotificationAgreementUseCase - } - - public func make(isAgreeEventNotification: Bool, isAgreeNoticeNotification: Bool, isAgreePatchNoteNotification: Bool) -> BaseViewController { - let viewController = NotificationSettingViewController( - reactor: NotificationSettingReactor( - checkNotificationPermissionUseCase: checkNotificationPermissionUseCase, - updateNotificationAgreementUseCase: updateNotificationAgreementUseCase, - isAgreeEventNotification: isAgreeEventNotification, - isAgreeNoticeNotification: isAgreeNoticeNotification, - isAgreePatchNoteNotification: isAgreePatchNoteNotification - ) - ) - return viewController - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/NotificationSetting/NotificationSettingItemView.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/NotificationSetting/NotificationSettingItemView.swift deleted file mode 100644 index a4d11545..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/NotificationSetting/NotificationSettingItemView.swift +++ /dev/null @@ -1,107 +0,0 @@ -import UIKit - -import DesignSystem - -import RxCocoa -import RxSwift -import SnapKit - -final class NotificationItemView: UIView { - // MARK: - Constants - enum Constant { - static let iconInset: CGFloat = 10 - static let buttonSize: CGFloat = 44 - static let topMargin: CGFloat = 20 - static let viewHeight: CGFloat = 100 - static let subTextViewWidth: CGFloat = 220 - static let horizontalMargin: CGFloat = 16 - static let subTextTopMargin: CGFloat = 8 - static let spacerHeight: CGFloat = 10 - } - - // MARK: - Components - private let titleLabel = UILabel() - private let subTextLabel = UILabel() - public let switchButton = UISwitch() - public let changeButton = UIButton() - private let spacer = UIView() - - // MARK: - Properties - private let disposeBag = DisposeBag() - - // MARK: - Init - init(title: String, subtitle: String, isAuth: Bool) { - super.init(frame: .zero) - setupUI(title: title, subtitle: subtitle, isAuth: isAuth) - } - - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // MARK: - UI Setup - private func setupUI(title: String, subtitle: String, isAuth: Bool) { - // 기본 속성 설정 - titleLabel.attributedText = .makeStyledString(font: .sub_m_sb, text: title, color: .textColor) - titleLabel.textAlignment = .left - - subTextLabel.attributedText = .makeStyledString(font: .cp_s_r, text: subtitle, color: .neutral500) - subTextLabel.numberOfLines = 0 - subTextLabel.textAlignment = .left - - switchButton.onTintColor = .primary700 - - changeButton.setAttributedTitle( - .makeStyledString(font: .cp_xs_r, text: "변경하기", color: .primary700), - for: .normal - ) - changeButton.semanticContentAttribute = .forceRightToLeft - changeButton.setImage(DesignSystemAsset.image(named: "arrowForwardSmall")?.withRenderingMode(.alwaysTemplate), for: .normal) - changeButton.tintColor = .primary700 - - // addSubviews - addSubview(titleLabel) - addSubview(subTextLabel) - addSubview(spacer) - spacer.backgroundColor = .neutral100 - - if isAuth { - addSubview(switchButton) - } else { - addSubview(changeButton) - } - - // Layout - self.snp.makeConstraints { make in - make.height.equalTo(Constant.viewHeight) - } - - titleLabel.snp.makeConstraints { make in - make.top.equalToSuperview() - make.leading.equalToSuperview().inset(Constant.horizontalMargin) - } - - subTextLabel.snp.makeConstraints { make in - make.top.equalTo(titleLabel.snp.bottom).offset(Constant.subTextTopMargin) - make.leading.equalToSuperview().inset(Constant.horizontalMargin) - make.width.equalTo(Constant.subTextViewWidth) - } - - if isAuth { - switchButton.snp.makeConstraints { make in - make.trailing.equalToSuperview().inset(Constant.horizontalMargin) - make.top.equalToSuperview().offset(Constant.topMargin) - } - } else { - changeButton.snp.makeConstraints { make in - make.trailing.equalToSuperview().inset(Constant.horizontalMargin) - make.top.equalToSuperview().offset(Constant.topMargin) - } - } - spacer.snp.makeConstraints { make in - make.height.equalTo(Constant.spacerHeight) - make.bottom.equalToSuperview() - make.width.equalToSuperview() - } - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/NotificationSetting/NotificationSettingReactor.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/NotificationSetting/NotificationSettingReactor.swift deleted file mode 100644 index b36a593d..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/NotificationSetting/NotificationSettingReactor.swift +++ /dev/null @@ -1,96 +0,0 @@ -import DomainInterface -import ReactorKit - -public final class NotificationSettingReactor: Reactor { - // MARK: - Reactor - public enum Route { - case none - case dismiss - case setting - } - - public enum Action { - case viewWillAppear - case appWillEnterForeground - case backButtonTapped - case eventViewSwitch(Bool) - case noticeViewSwitch(Bool) - case patchNoteViewSwitch(Bool) - case pushGuideViewTapped - case updateAuthorization(Bool) - } - - public enum Mutation { - case setAuthorized(Bool) - case toNavigate(Route) - case setEventNotification(Bool) - case setNoticeNotification(Bool) - case setPatchNoteNotification(Bool) - } - - public struct State { - @Pulse var route = Route.none - var authorized = false - var isAgreeEventNotification: Bool - var isAgreeNoticeNotification: Bool - var isAgreePatchNoteNotification: Bool - } - - public var initialState: State - private let disposeBag = DisposeBag() - - private let checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase - private let updateNotificationAgreementUseCase: UpdateNotificationAgreementUseCase - - init(checkNotificationPermissionUseCase: CheckNotificationPermissionUseCase, updateNotificationAgreementUseCase: UpdateNotificationAgreementUseCase, - isAgreeEventNotification: Bool, - isAgreeNoticeNotification: Bool, - isAgreePatchNoteNotification: Bool) { - self.initialState = .init(isAgreeEventNotification: isAgreeEventNotification, isAgreeNoticeNotification: isAgreeNoticeNotification, isAgreePatchNoteNotification: isAgreePatchNoteNotification) - self.checkNotificationPermissionUseCase = checkNotificationPermissionUseCase - self.updateNotificationAgreementUseCase = updateNotificationAgreementUseCase - } - - public func mutate(action: Action) -> Observable { - switch action { - case .viewWillAppear, .appWillEnterForeground: - return checkNotificationPermissionUseCase.execute() - .asObservable() - .map { Mutation.setAuthorized($0) } - case .backButtonTapped: - return .just(.toNavigate(.dismiss)) - case .eventViewSwitch(let isAgree): - return updateNotificationAgreementUseCase.execute(noticeAgreement: currentState.isAgreeNoticeNotification, patchNoteAgreement: currentState.isAgreePatchNoteNotification, eventAgreement: isAgree) - .andThen(.just(.setEventNotification(isAgree))) - case .noticeViewSwitch(let isAgree): - return updateNotificationAgreementUseCase.execute(noticeAgreement: isAgree, patchNoteAgreement: currentState.isAgreePatchNoteNotification, eventAgreement: currentState.isAgreeEventNotification) - .andThen(.just(.setNoticeNotification(isAgree))) - case .patchNoteViewSwitch(let isAgree): - return updateNotificationAgreementUseCase.execute(noticeAgreement: currentState.isAgreeNoticeNotification, patchNoteAgreement: isAgree, eventAgreement: currentState.isAgreeEventNotification) - .andThen(.just(.setPatchNoteNotification(isAgree))) - case .pushGuideViewTapped: - return .just(.toNavigate(.setting)) - case .updateAuthorization(let authorized): - return .just(.setAuthorized(authorized)) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .setAuthorized(let authorized): - newState.authorized = authorized - case .toNavigate(let route): - newState.route = route - case .setEventNotification(let isAgree): - newState.isAgreeEventNotification = isAgree - case .setNoticeNotification(let isAgree): - newState.isAgreeNoticeNotification = isAgree - case .setPatchNoteNotification(let isAgree): - newState.isAgreePatchNoteNotification = isAgree - } - - return newState - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/NotificationSetting/NotificationSettingView.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/NotificationSetting/NotificationSettingView.swift deleted file mode 100644 index 7c0612bc..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/NotificationSetting/NotificationSettingView.swift +++ /dev/null @@ -1,121 +0,0 @@ -import UIKit - -import DesignSystem - -import RxCocoa -import RxSwift - -final class NotificationSettingView: UIView { - // MARK: - Properties - public var disposeBag = DisposeBag() - - // MARK: - Constants - public enum Constant { - static let iconInset: CGFloat = 10 - static let buttonSize: CGFloat = 44 - static let topMargin: CGFloat = 20 - } - - // MARK: - Components - // 헤더 뷰 - public let headerView = UIView() - public let backButton: UIButton = { - let button = UIButton() - button - .setImage( - DesignSystemAsset - .image(named: "arrowBack")? - .withRenderingMode(.alwaysTemplate) - .resizableImage( - withCapInsets: UIEdgeInsets( - top: Constant.iconInset, - left: Constant.iconInset, - bottom: Constant.iconInset, - right: Constant.iconInset - ) - ), - for: .normal - ) - button.tintColor = .textColor - return button - }() - public let titleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .sub_m_b, text: "알림 설정") - return label - }() - - // 알림 설정 셀들을 담는 스택뷰 - private lazy var stackView: UIStackView = { - let stackView = UIStackView(arrangedSubviews: [eventView, noticeView, patchNoteView, pushGuideView]) - stackView.axis = .vertical - stackView.distribution = .fill - stackView.spacing = 36 - return stackView - }() - - public let eventView = NotificationItemView(title: "신규 이벤트 알림 설정", subtitle: "메이플랜드 신규 이벤트를 푸시 알림으로 빠르게 받을 수 있어요.", isAuth: true) - - public let noticeView = NotificationItemView(title: "공지사항 알림 설정", subtitle: "메이플랜드 공지사항을 푸시 알림으로 빠르게 받을 수 있어요.", isAuth: true) - - public let patchNoteView = NotificationItemView(title: "패치노트 알림 설정", subtitle: "메이플랜드 패치노트를 푸시 알림으로 빠르게 받을 수 있어요.", isAuth: true) - - public let pushGuideView = NotificationItemView(title: "푸시 알림 설정", subtitle: "기기 설정을 변경해야 알림을 받을 수 있어요.", isAuth: false) - - // MARK: - Init - init() { - super.init(frame: .zero) - addViews() - setupConstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } -} - -// MARK: - Setup -private extension NotificationSettingView { - func addViews() { - addSubview(headerView) - addSubview(stackView) - - headerView.addSubview(backButton) - headerView.addSubview(titleLabel) - } - - func setupConstraints() { - headerView.snp.makeConstraints { make in - make.top.equalTo(safeAreaLayoutGuide.snp.top) - make.horizontalEdges.equalToSuperview() - make.height.equalTo(Constant.buttonSize) - } - - backButton.snp.makeConstraints { make in - make.leading.centerY.equalToSuperview() - make.size.equalTo(Constant.buttonSize) - } - - titleLabel.snp.makeConstraints { make in - make.leading.equalTo(backButton.snp.trailing) - make.centerY.equalToSuperview() - } - - stackView.snp.makeConstraints { make in - make.top.equalTo(headerView.snp.bottom).offset(Constant.topMargin) - make.horizontalEdges.equalToSuperview() - make.bottom.lessThanOrEqualToSuperview() - } - } -} - -// MARK: - Update -extension NotificationSettingView { - func setViews(authorized: Bool) { - eventView.isHidden = !authorized - noticeView.isHidden = !authorized - patchNoteView.isHidden = !authorized - pushGuideView.isHidden = authorized - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/NotificationSetting/NotificationSettingViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/NotificationSetting/NotificationSettingViewController.swift deleted file mode 100644 index 6a0d9b4a..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/NotificationSetting/NotificationSettingViewController.swift +++ /dev/null @@ -1,166 +0,0 @@ -import UIKit - -import BaseFeature -import DomainInterface - -import ReactorKit -import RxSwift - -final class NotificationSettingViewController: BaseViewController, View, UNUserNotificationCenterDelegate { - typealias Reactor = NotificationSettingReactor - - public var disposeBag = DisposeBag() - - // MARK: - Properties - - // MARK: - UI Components - private let mainView = NotificationSettingView() - - // MARK: - Init - init(reactor: NotificationSettingReactor) { - super.init() - self.reactor = reactor - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // MARK: - LifeCycle - override func viewDidLoad() { - super.viewDidLoad() - setupUI() - } -} - -// MARK: - Setup -private extension NotificationSettingViewController { - func setupUI() { - isBottomTabbarHidden = true - view.addSubview(mainView) - mainView.snp.makeConstraints { make in - make.top.equalTo(view.safeAreaLayoutGuide) - make.horizontalEdges.bottom.equalToSuperview() - } - } -} - -// MARK: - Notification Authorization -private extension NotificationSettingViewController { - func checkNotificationAuthorization() { - guard let reactor = reactor else { return } - - NotificationPermissionManager.shared.getStatus { status in - switch status { - case .authorized, .provisional: - reactor.action.onNext(.updateAuthorization(true)) - case .denied: - reactor.action.onNext(.updateAuthorization(false)) - case .notDetermined: - NotificationPermissionManager.shared.requestIfNeeded { granted in - reactor.action.onNext(.updateAuthorization(granted)) - } - default: - reactor.action.onNext(.updateAuthorization(false)) - } - } - } -} - -// MARK: - Reactor Binding -extension NotificationSettingViewController { - func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - private func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .take(1) - .do(onNext: { [weak self] _ in - self?.checkNotificationAuthorization() - }) - .map { _ in Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - NotificationCenter.default.rx.notification(UIApplication.willEnterForegroundNotification) - .map { _ in Reactor.Action.appWillEnterForeground } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.backButton.rx.tap - .map { Reactor.Action.backButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.eventView.switchButton.rx.isOn - .skip(1) - .map { Reactor.Action.eventViewSwitch($0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.noticeView.switchButton.rx.isOn - .skip(1) - .map { Reactor.Action.noticeViewSwitch($0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.patchNoteView.switchButton.rx.isOn - .skip(1) - .map { Reactor.Action.patchNoteViewSwitch($0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.pushGuideView.changeButton.rx.tap - .map { Reactor.Action.pushGuideViewTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - private func bindViewState(reactor: Reactor) { - reactor.state - .observe(on: MainScheduler.instance) - .map { $0.authorized } - .withUnretained(self) - .subscribe { owner, authorized in - owner.mainView.setViews(authorized: authorized) - } - .disposed(by: disposeBag) - - reactor.state.map { $0.isAgreeEventNotification } - .distinctUntilChanged() - .bind(to: mainView.eventView.switchButton.rx.isOn) - .disposed(by: disposeBag) - - reactor.state.map { $0.isAgreeNoticeNotification } - .distinctUntilChanged() - .bind(to: mainView.noticeView.switchButton.rx.isOn) - .disposed(by: disposeBag) - - reactor.state.map { $0.isAgreePatchNoteNotification } - .distinctUntilChanged() - .bind(to: mainView.patchNoteView.switchButton.rx.isOn) - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .subscribe(onNext: { owner, route in - switch route { - case .dismiss: - owner.navigationController?.popViewController(animated: true) - case .setting: - guard let url = URL(string: UIApplication.openSettingsURLString) else { return } - if UIApplication.shared.canOpenURL(url) { - UIApplication.shared.open(url, options: [:], completionHandler: nil) - } - default: - break - } - }) - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/SelectImage/SelectImageCell.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/SelectImage/SelectImageCell.swift deleted file mode 100644 index 74019a5a..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/SelectImage/SelectImageCell.swift +++ /dev/null @@ -1,117 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem - -import SnapKit - -public final class SelectImageCell: UICollectionViewCell { - // MARK: - Type - enum Constant { - static let inset: CGFloat = 28 - } - - // MARK: - Properties - private var type: MapleIllustration? - - override public var isSelected: Bool { - didSet { - updateImage() - } - } - - // MARK: - Components - private let imageView: UIImageView = { - let view = UIImageView() - view.clipsToBounds = true - return view - }() - - private lazy var checkMarkContainerView: UIView = { - let view = UIView() - view.backgroundColor = .primary100.withAlphaComponent(0.5) - - view.addSubview(checkMarkView) - - checkMarkView.snp.makeConstraints { make in - make.edges.equalToSuperview().inset(3) - } - - return view - }() - - private lazy var checkMarkView: UIView = { - let view = UIView() - view.backgroundColor = UIColor(hexCode: "72412C", alpha: 0.5) - view.clipsToBounds = true - - view.addSubview(checkIcon) - - checkIcon.snp.makeConstraints { make in - make.edges.equalToSuperview().inset(Constant.inset) - } - return view - }() - - private let checkIcon: UIImageView = { - let view = UIImageView(image: DesignSystemAsset.image(named: "checkMark")?.withRenderingMode(.alwaysTemplate)) - view.tintColor = .whiteMLS - return view - }() - - // MARK: - init - override init(frame: CGRect) { - super.init(frame: frame) - - addViews() - setupContstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } - - public override func layoutSubviews() { - super.layoutSubviews() - imageView.layer.cornerRadius = imageView.bounds.width * 0.4 - checkMarkView.layer.cornerRadius = checkMarkView.bounds.width * 0.4 - } -} - -// MARK: - SetUp -private extension SelectImageCell { - func addViews() { - addSubview(imageView) - imageView.addSubview(checkMarkContainerView) - } - - func setupContstraints() { - imageView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - - checkMarkContainerView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } - - func updateImage() { - guard let type = type else { return } - ImageLoader.shared.loadImage(stringURL: type.url) { [weak self] image in - self?.imageView.image = image - } - checkMarkContainerView.isHidden = !isSelected - } -} - -public extension SelectImageCell { - struct Input { - let type: MapleIllustration - } - - func inject(input: Input) { - type = input.type - updateImage() - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/SelectImage/SelectImageFactoryImpl.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/SelectImage/SelectImageFactoryImpl.swift deleted file mode 100644 index 63540822..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/SelectImage/SelectImageFactoryImpl.swift +++ /dev/null @@ -1,18 +0,0 @@ -import BaseFeature -import DomainInterface -import MyPageFeatureInterface - -public struct SelectImageFactoryImpl: SelectImageFactory { - private let updateProfileImageUseCase: UpdateProfileImageUseCase - - public init(updateProfileImageUseCase: UpdateProfileImageUseCase) { - self.updateProfileImageUseCase = updateProfileImageUseCase - } - - public func make() -> BaseViewController & ModalPresentable { - let viewController = SelectImageViewContoller() - viewController.reactor = SelectImageReactor(updateProfileImageUseCase: updateProfileImageUseCase) - viewController.isBottomTabbarHidden = true - return viewController - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/SelectImage/SelectImageReactor.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/SelectImage/SelectImageReactor.swift deleted file mode 100644 index 49be8575..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/SelectImage/SelectImageReactor.swift +++ /dev/null @@ -1,82 +0,0 @@ -import DesignSystem -import DomainInterface - -import ReactorKit -import RxCocoa -import RxSwift - -public final class SelectImageReactor: Reactor { - public enum Route { - case none - case dismiss - case dismissWithSave - } - - // MARK: - Reactor - public enum Action { - case cancelButtonTapped - case applyButtonTapped - case imageTapped(Int) - } - - public enum Mutation { - case navigateTo(route: Route) - case selectImage(MapleIllustration) - } - - public struct State { - @Pulse var route: Route = .none - var images: [MapleIllustration] = [ - .mushroom, - .slime, - .blueSnail, - .juniorYeti, - .yeti, - .pepe, - .wraith, - .starPixie, - .rash - ] - var selectedImage: MapleIllustration? - } - - // MARK: - properties - public var initialState: State - var disposeBag = DisposeBag() - - private let updateProfileImageUseCase: UpdateProfileImageUseCase - - // MARK: - init - public init(updateProfileImageUseCase: UpdateProfileImageUseCase) { - self.initialState = State() - self.updateProfileImageUseCase = updateProfileImageUseCase - } - - // MARK: - Reactor Methods - public func mutate(action: Action) -> Observable { - switch action { - case .cancelButtonTapped: - return .just(.navigateTo(route: .dismiss)) - case .applyButtonTapped: - guard let url = currentState.selectedImage?.url else { return .empty() } - return updateProfileImageUseCase.execute(url: url) - .andThen(.just(.navigateTo(route: .dismissWithSave))) - case .imageTapped(let index): - let image = currentState.images[index] - return .just(.selectImage(image)) - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .navigateTo(let route): - newState.route = route - case .selectImage(let image): - newState.selectedImage = image - } - - return newState - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/SelectImage/SelectImageView.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/SelectImage/SelectImageView.swift deleted file mode 100644 index ff65a882..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/SelectImage/SelectImageView.swift +++ /dev/null @@ -1,68 +0,0 @@ -import UIKit - -import DesignSystem - -import SnapKit - -final class SelectImageView: UIView { - private enum Constant { - static let imageSize: CGFloat = 104 - static let topMargin: CGFloat = 16 - static let headerHeight: CGFloat = 32 - static let bottomMargin: CGFloat = 24 - static let buttonBottomMargin: CGFloat = 4 - static let horizontalInset: CGFloat = 16 - } - - // MARK: - Components - public let header = Header(style: .filter, title: "프로필 이미지를 선택해주세요.") - - public let imageCollectionView: UICollectionView = { - let layout = UICollectionViewLayout() - let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) - return collectionView - }() - - public let applyButton = CommonButton(style: .normal, title: "적용", disabledTitle: nil) - - // MARK: - init - init() { - super.init(frame: .zero) - - addViews() - setupConstraints() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension SelectImageView { - func addViews() { - addSubview(header) - addSubview(imageCollectionView) - addSubview(applyButton) - } - - func setupConstraints() { - header.snp.makeConstraints { make in - make.top.equalToSuperview().inset(Constant.topMargin) - make.horizontalEdges.equalToSuperview() - make.height.equalTo(Constant.headerHeight) - } - - imageCollectionView.snp.makeConstraints { make in - make.top.equalTo(header.snp.bottom) - make.horizontalEdges.equalToSuperview() - } - - applyButton.snp.makeConstraints { make in - make.top.equalTo(imageCollectionView.snp.bottom).offset(Constant.bottomMargin) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - make.bottom.equalToSuperview().inset(Constant.buttonBottomMargin) - } - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/SelectImage/SelectImageViewContoller.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/SelectImage/SelectImageViewContoller.swift deleted file mode 100644 index 23938438..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/SelectImage/SelectImageViewContoller.swift +++ /dev/null @@ -1,120 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem -import DomainInterface - -import ReactorKit -import RxCocoa -import RxKeyboard -import RxSwift -import SnapKit - -public final class SelectImageViewContoller: BaseViewController, ModalPresentable, View { - // 수정필요 - public var modalHeight: CGFloat? = 16 + 32 + UIScreen.main.bounds.size.width + 4 + 24 + 54 + 4 - - public typealias Reactor = SelectImageReactor - - public var disposeBag = DisposeBag() - - // MARK: - Components - - private var mainView = SelectImageView() -} - -// MARK: - Life Cycle -public extension SelectImageViewContoller { - override func viewDidLoad() { - super.viewDidLoad() - - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension SelectImageViewContoller { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalToSuperview() - } - } - - func configureUI() { - mainView.imageCollectionView.collectionViewLayout = createLayout() - mainView.imageCollectionView.delegate = self - mainView.imageCollectionView.dataSource = self - mainView.imageCollectionView.register(SelectImageCell.self, forCellWithReuseIdentifier: SelectImageCell.identifier) - } - - func createLayout() -> UICollectionViewLayout { - let layoutFactory = LayoutFactory() - let layout = CompositionalLayoutBuilder() - .section { _ in layoutFactory.getSelectImageLayout() } - .build() - return layout - } -} - -extension SelectImageViewContoller { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - mainView.header.firstIconButton.rx.tap - .map { Reactor.Action.cancelButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.applyButton.rx.tap - .map { Reactor.Action.applyButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, route in - switch route { - case .dismiss: - owner.dismissCurrentModal() - case .dismissWithSave: - owner.dismissCurrentModal() - default: - break - } - } - .disposed(by: disposeBag) - } -} - -extension SelectImageViewContoller: UICollectionViewDelegate, UICollectionViewDataSource { - public func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { - guard let reactor = reactor else { return 0 } - return reactor.currentState.images.count - } - - public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { - guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: SelectImageCell.identifier, for: indexPath) as? SelectImageCell, - let reactor = reactor else { return UICollectionViewCell() } - cell.inject(input: SelectImageCell.Input(type: reactor.currentState.images[indexPath.row])) - return cell - } - - public func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { - guard let reactor = reactor else { return } - reactor.action.onNext(.imageTapped(indexPath.row)) - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/SetCharacter/SetCharacterFactoryImpl.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/SetCharacter/SetCharacterFactoryImpl.swift deleted file mode 100644 index a7a0f4ba..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/SetCharacter/SetCharacterFactoryImpl.swift +++ /dev/null @@ -1,34 +0,0 @@ -import BaseFeature -import DomainInterface -import MyPageFeatureInterface - -public struct SetCharacterFactoryImpl: SetCharacterFactory { - private let checkEmptyUseCase: CheckEmptyLevelAndRoleUseCase - private let checkValidLevelUseCase: CheckValidLevelUseCase - private let fetchJobListUseCase: FetchJobListUseCase - private let updateUserInfoUseCase: UpdateUserInfoUseCase - - public init( - checkEmptyUseCase: CheckEmptyLevelAndRoleUseCase, - checkValidLevelUseCase: CheckValidLevelUseCase, - fetchJobListUseCase: FetchJobListUseCase, - updateUserInfoUseCase: UpdateUserInfoUseCase - ) { - self.checkEmptyUseCase = checkEmptyUseCase - self.checkValidLevelUseCase = checkValidLevelUseCase - self.fetchJobListUseCase = fetchJobListUseCase - self.updateUserInfoUseCase = updateUserInfoUseCase - } - - public func make() -> BaseViewController { - let viewController = SetCharacterViewController() - viewController.reactor = SetCharacterReactor( - checkEmptyUseCase: checkEmptyUseCase, - checkValidLevelUseCase: checkValidLevelUseCase, - fetchJobListUseCase: fetchJobListUseCase, - updateUserInfoUseCase: updateUserInfoUseCase - ) - viewController.isBottomTabbarHidden = true - return viewController - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/SetCharacter/SetCharacterReactor.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/SetCharacter/SetCharacterReactor.swift deleted file mode 100644 index 9d2a37ec..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/SetCharacter/SetCharacterReactor.swift +++ /dev/null @@ -1,117 +0,0 @@ -import DomainInterface - -import ReactorKit -import RxSwift - -public final class SetCharacterReactor: Reactor { - // MARK: - Reactor - public enum Route { - case none - case dismiss - case dismissWithSave - case error - } - - public enum Action { - case viewWillAppear - case backButtonTapped - case applyButtonTapped - case inputLevel(Int?) - case inputRole(Job?) - } - - public enum Mutation { - case setJobList(jobList: [Job]) - case setButtonEnabled(Bool) - case setLevelValid(Bool?) - case setLevel(Int?) - case setRole(Job?) - case navigateTo(route: Route) - } - - public struct State { - @Pulse var route: Route = .none - - var level: Int? - var job: Job? - var isButtonEnabled: Bool = false - var isLevelValid: Bool? - var jobList: [Job] = [] - } - - // MARK: - properties - public var initialState: State - private let checkEmptyUseCase: CheckEmptyLevelAndRoleUseCase - private let checkValidLevelUseCase: CheckValidLevelUseCase - private let fetchJobListUseCase: FetchJobListUseCase - private let updateUserInfoUseCase: UpdateUserInfoUseCase - var disposeBag = DisposeBag() - - // MARK: - init - public init( - checkEmptyUseCase: CheckEmptyLevelAndRoleUseCase, - checkValidLevelUseCase: CheckValidLevelUseCase, - fetchJobListUseCase: FetchJobListUseCase, - updateUserInfoUseCase: UpdateUserInfoUseCase - ) { - self.checkEmptyUseCase = checkEmptyUseCase - self.checkValidLevelUseCase = checkValidLevelUseCase - self.fetchJobListUseCase = fetchJobListUseCase - self.updateUserInfoUseCase = updateUserInfoUseCase - self.initialState = State() - } - - // MARK: - Reactor Methods - public func mutate(action: Action) -> Observable { - switch action { - case .viewWillAppear: - return fetchJobListUseCase.execute() - .map { response in - .setJobList(jobList: response.jobList) - } - .catchAndReturn(.navigateTo(route: .error)) - case .backButtonTapped: - return Observable.just(.navigateTo(route: .dismiss)) - case .applyButtonTapped: - guard let level = currentState.level, - let job = currentState.job else { return Observable.just(.navigateTo(route: .error)) } - return updateUserInfoUseCase.execute(level: level, selectedJobID: job.id) - .andThen(Observable.just(.navigateTo(route: .dismissWithSave))) - .catchAndReturn(.navigateTo(route: .error)) - case .inputLevel(let level): - let changeLevel = Observable.just(Mutation.setLevel(level)) - let validateButton = checkEmptyUseCase.execute(level: level, job: currentState.job?.name) - .map(Mutation.setButtonEnabled) - let validateLevel = checkValidLevelUseCase.execute(level: level) - .map(Mutation.setLevelValid) - return .merge(changeLevel, validateButton, validateLevel) - case .inputRole(let job): - return checkEmptyUseCase.execute(level: currentState.level, job: job?.name) - .map { isValid in - [.setRole(job), .setButtonEnabled(isValid)] - } - .flatMap { Observable.from($0) } - } - } - - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .setJobList(let jobList): - newState.jobList = jobList - case .setButtonEnabled(let isEnabled): - newState.isButtonEnabled = isEnabled - case .setLevelValid(let isValid): - newState.isLevelValid = isValid - case .setLevel(let level): - newState.level = level - case .setRole(let job): - newState.job = job - case .navigateTo(let route): - newState.route = route - } - - return newState - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/SetCharacter/SetCharacterView.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/SetCharacter/SetCharacterView.swift deleted file mode 100644 index cdb60720..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/SetCharacter/SetCharacterView.swift +++ /dev/null @@ -1,56 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem - -import RxCocoa -import RxSwift -import SnapKit - -public final class SetCharacterView: CharacterInputView { - // MARK: - Type - - // MARK: - Properties - - // MARK: - Components - public let headerView: NavigationBar = { - let view = NavigationBar(type: .arrowLeft) - return view - }() - - // MARK: - init - override init() { - super.init() - addViews() - setupConstraints() - configureUI() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("\(#file), \(#function) Error") - } -} - -// MARK: - SetUp -private extension SetCharacterView { - func addViews() { - addSubview(headerView) - } - - func setupConstraints() { - headerView.snp.makeConstraints { make in - make.top.horizontalEdges.equalToSuperview() - } - - descriptionLabel.snp.makeConstraints { make in - make.top.equalTo(headerView.snp.bottom).offset(Constant.verticalInset) - make.horizontalEdges.equalToSuperview().inset(Constant.horizontalInset) - } - } - - func configureUI() { - backgroundColor = .clearMLS - nextButton.updateTitle(title: "완료", disabledTitle: "완료") - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/SetCharacter/SetCharacterViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/SetCharacter/SetCharacterViewController.swift deleted file mode 100644 index f9f22874..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/SetCharacter/SetCharacterViewController.swift +++ /dev/null @@ -1,140 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem - -import ReactorKit -import RxCocoa -import RxKeyboard -import RxSwift -import SnapKit - -public class SetCharacterViewController: BaseViewController, View { - // MARK: - Properties - public typealias Reactor = SetCharacterReactor - - public var disposeBag = DisposeBag() - - // MARK: - Components - - private var mainView = SetCharacterView() -} - -// MARK: - Life Cycle -public extension SetCharacterViewController { - override func viewDidLoad() { - super.viewDidLoad() - addViews() - setupConstraints() - configureUI() - } -} - -// MARK: - SetUp -private extension SetCharacterViewController { - func addViews() { - view.addSubview(mainView) - } - - func setupConstraints() { - mainView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } - - func configureUI() { - setupKeyboard() - } - - func setupKeyboard() { - setupKeyboard(inset: CharacterInputView.Constant.bottomInset) { [weak self] height in - self?.mainView.nextButtonBottomConstraint?.update(inset: height) - } - } -} - -// MARK: - Bind -public extension SetCharacterViewController { - func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindViewState(reactor: reactor) - } - - func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .map { Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.nextButton.rx.tap - .map { Reactor.Action.applyButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.inputBox.textField.rx.text.orEmpty - .map { text -> Int? in - Int(text) - } - .map { Reactor.Action.inputLevel($0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.dropDownBox.onItemSelected = { [weak self] job in - guard let self = self else { return } - self.reactor?.action.onNext(.inputRole(.init(name: job.name, id: job.id))) - } - - mainView.headerView.leftButton.rx.tap - .map { Reactor.Action.backButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - func bindViewState(reactor: Reactor) { - reactor.state - .map { $0.jobList } - .observe(on: MainScheduler.instance) - .distinctUntilChanged() - .withUnretained(self) - .subscribe { owner, list in - owner.mainView.dropDownBox.items = list.map { .init(name: $0.name, id: $0.id) } - } - .disposed(by: disposeBag) - - reactor.state - .map { $0.isLevelValid } - .distinctUntilChanged() - .withUnretained(self) - .subscribe { owner, isLevelValid in - guard let isLevelValid = isLevelValid else { return } - owner.mainView.inputBox.setType(type: isLevelValid ? InputBoxType.edit : InputBoxType.error) - owner.mainView.errorMessage.isHidden = isLevelValid - } - .disposed(by: disposeBag) - - reactor.state - .map { $0.isButtonEnabled } - .bind(to: mainView.nextButton.rx.isEnabled) - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .observe(on: MainScheduler.instance) - .withUnretained(self) - .subscribe(onNext: { owner, route in - switch route { - case .dismiss: - owner.navigationController?.popViewController(animated: true) - case .dismissWithSave: - owner.navigationController?.popViewController(animated: true) - case .error: - let errorViewController = BaseErrorViewController() - owner.present(errorViewController, animated: true) - default: - break - } - }) - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileFactoryImpl.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileFactoryImpl.swift deleted file mode 100644 index 59352520..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileFactoryImpl.swift +++ /dev/null @@ -1,35 +0,0 @@ -import BaseFeature -import DomainInterface -import MyPageFeatureInterface - -public final class SetProfileFactoryImpl: SetProfileFactory { - private let selectImageFactory: SelectImageFactory - private let checkNickNameUseCase: CheckNickNameUseCase - private let updateNickNameUseCase: UpdateNickNameUseCase - private let logoutUseCase: LogoutUseCase - private let withdrawUseCase: WithdrawUseCase - private let fetchProfileUseCase: FetchProfileUseCase - - public init( - selectImageFactory: SelectImageFactory, - checkNickNameUseCase: CheckNickNameUseCase, - updateNickNameUseCase: UpdateNickNameUseCase, - logoutUseCase: LogoutUseCase, - withdrawUseCase: WithdrawUseCase, - fetchProfileUseCase: FetchProfileUseCase - ) { - self.selectImageFactory = selectImageFactory - self.checkNickNameUseCase = checkNickNameUseCase - self.updateNickNameUseCase = updateNickNameUseCase - self.logoutUseCase = logoutUseCase - self.withdrawUseCase = withdrawUseCase - self.fetchProfileUseCase = fetchProfileUseCase - } - - public func make() -> BaseViewController { - let viewController = SetProfileViewController(selectImageFactory: selectImageFactory) - viewController.reactor = SetProfileReactor(checkNickNameUseCase: checkNickNameUseCase, updateNickNameUseCase: updateNickNameUseCase, logoutUseCase: logoutUseCase, withdrawUseCase: withdrawUseCase, fetchProfileUseCase: fetchProfileUseCase) - viewController.isBottomTabbarHidden = true - return viewController - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileReactor.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileReactor.swift deleted file mode 100644 index 4e10af60..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileReactor.swift +++ /dev/null @@ -1,149 +0,0 @@ -import DomainInterface - -import ReactorKit - -public final class SetProfileReactor: Reactor { - // MARK: - Route - public enum Route: Equatable { - case none - case dismiss - case dismissWithUpdate - case imageBottomSheet - case logoutAlert - case withdrawAlert - } - - // MARK: - Action - public enum Action { - case viewWillAppear - case backButtonTapped - case editButtonTapped - case logoutButtonTapped - case withdrawButtonTapped - case showBottomSheet - case inputNickName(String) - case beginEditingNickName - case logout - case withdraw - } - - // MARK: - Mutation - public enum Mutation: Equatable { - case toNavigate(Route) - case setNickName(String) - case setProfile(MyPageResponse?) - case showError(Bool) - case beginSetText(Bool) - case beginEditting - case cancelEditting - case completeEditting - } - - // MARK: - State - public struct State { - @Pulse var route: Route = .none - var setProfileState: SetProfileView.SetProfileState - var isShowError = false - var isEditingNickName = false - var profile: MyPageResponse? - var nickName = "" - } - - // MARK: - Properties - public var initialState = State(setProfileState: .normal) - - private let checkNickNameUseCase: CheckNickNameUseCase - private let updateNickNameUseCase: UpdateNickNameUseCase - private let logoutUseCase: LogoutUseCase - private let withdrawUseCase: WithdrawUseCase - private let fetchProfileUseCase: FetchProfileUseCase - - // MARK: - Init - public init(checkNickNameUseCase: CheckNickNameUseCase, updateNickNameUseCase: UpdateNickNameUseCase, logoutUseCase: LogoutUseCase, withdrawUseCase: WithdrawUseCase, fetchProfileUseCase: FetchProfileUseCase) { - self.checkNickNameUseCase = checkNickNameUseCase - self.updateNickNameUseCase = updateNickNameUseCase - self.logoutUseCase = logoutUseCase - self.withdrawUseCase = withdrawUseCase - self.fetchProfileUseCase = fetchProfileUseCase - } - - // MARK: - Mutate - public func mutate(action: Action) -> Observable { - switch action { - case .showBottomSheet: - return .just(.toNavigate(.imageBottomSheet)) - case .inputNickName(let nickName): - return checkNickNameUseCase.execute(nickName: nickName) - .map { isValid in - [.setNickName(nickName), .showError(!isValid)] - } - .flatMap { Observable.from($0) } - case .beginEditingNickName: - return .just(.beginSetText(true)) - case .backButtonTapped: - switch currentState.setProfileState { - case .edit: - return .just(.cancelEditting) - case .normal: - return .just(.toNavigate(.dismiss)) - } - case .editButtonTapped: - switch currentState.setProfileState { - case .edit: - if currentState.isShowError { - return .empty() - } else { - return updateNickNameUseCase.execute(nickName: currentState.nickName) - .flatMap { profile in - Observable.concat([ - .just(.setProfile(profile)), - .just(.completeEditting) - ]) - } - } - case .normal: - return .just(.beginEditting) - } - case .logoutButtonTapped: - return Observable.just(.toNavigate(.logoutAlert)) - case .withdrawButtonTapped: - return Observable.just(.toNavigate(.withdrawAlert)) - case .logout: - return logoutUseCase.execute() - .andThen(.just(.toNavigate(.dismiss))) - case .withdraw: - return withdrawUseCase.execute() - .andThen(.just(.toNavigate(.dismiss))) - case .viewWillAppear: - return fetchProfileUseCase.execute() - .map { Mutation.setProfile($0)} - } - } - - // MARK: - Reduce - public func reduce(state: State, mutation: Mutation) -> State { - var newState = state - - switch mutation { - case .toNavigate(let route): - newState.route = route - case .showError(let error): - newState.isShowError = error - case .beginSetText(let isEditing): - newState.isEditingNickName = isEditing - case .cancelEditting: - newState.setProfileState = .normal - case .beginEditting: - newState.setProfileState = .edit - case .completeEditting: - newState.route = .dismissWithUpdate - case .setProfile(let profile): - newState.profile = profile - newState.nickName = profile?.nickname ?? "" - case .setNickName(let nickname): - newState.nickName = nickname - } - - return newState - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileView.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileView.swift deleted file mode 100644 index 07655712..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileView.swift +++ /dev/null @@ -1,437 +0,0 @@ -import UIKit - -import BaseFeature -import DesignSystem -import DomainInterface - -import RxCocoa -import RxSwift -import SnapKit - -public final class SetProfileView: UIView { - // MARK: - Type - enum Constant { - static let buttonSize: CGFloat = 44 - static let headerViewHeight: CGFloat = 44 - static let imageViewTopMargin: CGFloat = 20 - static let imageSize: CGFloat = 104 - static let setImageIconSize: CGFloat = 28 - static let nameTopMargin: CGFloat = 12 - static let nameBottomMargin: CGFloat = 64 - static let backgroudViewTopInset: CGFloat = 20 - static let backgroudViewHorizontalInset: CGFloat = 16 - static let cancelTextViewBottomMargin: CGFloat = 10 - static let contentViewInset: CGFloat = 20 - static let textSpacing: CGFloat = 28 - static let platformSpacing: CGFloat = 5 - static let platformIconSize: CGFloat = 26 - static let logoutBottomMargin: CGFloat = 11 - static let nickNameTopMargin: CGFloat = 40 - static let nickNameHorizontalMargin: CGFloat = 33 - static let errorMessageBottomMargin: CGFloat = 12 - static let countLabelTopMargin: CGFloat = 3 - static let radius: CGFloat = 16 - } - - // MARK: - Properties - private let disposeBag = DisposeBag() - - var onCancelTap = PublishRelay() - public let imageTap = PublishRelay() - - // MARK: - Components - // shared - private lazy var headerView: UIView = { - let view = UIView() - - view.addSubview(backButton) - view.addSubview(titleLabel) - view.addSubview(editButton) - - backButton.snp.makeConstraints { make in - make.leading.equalToSuperview() - make.centerY.equalToSuperview() - make.size.equalTo(Constant.buttonSize) - } - - titleLabel.snp.makeConstraints { make in - make.center.equalToSuperview() - } - - editButton.snp.makeConstraints { make in - make.trailing.equalToSuperview() - make.centerY.equalToSuperview() - make.size.equalTo(Constant.buttonSize) - } - - return view - }() - - public let backButton: UIButton = { - let button = UIButton() - button.setImage(DesignSystemAsset.image(named: "arrowBack"), for: .normal) - return button - }() - - private let titleLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .sub_m_b, text: "프로필 설정") - return label - }() - - public let editButton = UIButton() - - private lazy var imageView: UIImageView = { - let view = UIImageView() - view.clipsToBounds = true - - view.addSubview(setImageButton) - - setImageButton.snp.makeConstraints { make in - make.trailing.bottom.equalToSuperview() - make.size.equalTo(Constant.setImageIconSize) - } - - return view - }() - - private let setImageButton: UIButton = { - let button = UIButton() - var config = UIButton.Configuration.plain() - config.baseBackgroundColor = .clear - config.background.backgroundColor = .clear - config.image = DesignSystemAsset.image(named: "plusIcon") - button.configuration = config - return button - }() - - private let nameLabel = UILabel() - - public let logoutButton: UIButton = { - let button = UIButton() - button.setAttributedTitle(.makeStyledUnderlinedString(font: .b_s_r, text: "로그아웃", color: .neutral600), for: .normal) - return button - }() - - private let cancelTextView: UITextView = { - let textView = UITextView() - textView.isEditable = false - textView.isScrollEnabled = false - textView.isUserInteractionEnabled = true - textView.backgroundColor = .clear - textView.textContainerInset = .zero - textView.textContainer.lineFragmentPadding = 0 - - let text = "메이플랜드사전을 탈퇴하려면 여기를 눌러주세요" - let attributed = NSMutableAttributedString(string: text) - - let fullRange = NSRange(text.startIndex ..< text.endIndex, in: text) - attributed.addAttribute(.font, value: UIFont.korFont(style: .regular, size: 12)!, range: fullRange) - attributed.addAttribute(.foregroundColor, value: UIColor.neutral500, range: fullRange) - - if let range = text.range(of: "여기") { - let nsRange = NSRange(range, in: text) - attributed.addAttribute(.link, value: "cancel", range: nsRange) - attributed.addAttribute(.underlineStyle, value: NSUnderlineStyle.single.rawValue, range: nsRange) - } - - textView.attributedText = attributed - - textView.linkTextAttributes = [ - .foregroundColor: UIColor.neutral500, - .underlineStyle: NSUnderlineStyle.single.rawValue - ] - - return textView - }() - - // normal - private lazy var backgroudView: UIView = { - let view = UIView() - view.backgroundColor = .neutral100 - - view.addSubview(contentView) - - contentView.snp.makeConstraints { make in - make.top.equalToSuperview().inset(Constant.backgroudViewTopInset) - make.horizontalEdges.equalToSuperview().inset(Constant.backgroudViewHorizontalInset) - } - - return view - }() - - private lazy var contentView: UIView = { - let view = UIView() - view.backgroundColor = .whiteMLS - view.layer.cornerRadius = Constant.radius - - view.addSubview(infoLabel) - view.addSubview(accountLabel) - view.addSubview(platformIconView) - view.addSubview(platformLabel) - - infoLabel.snp.makeConstraints { make in - make.top.leading.equalToSuperview().inset(Constant.contentViewInset) - } - - accountLabel.snp.makeConstraints { make in - make.top.equalTo(infoLabel.snp.bottom).offset(Constant.textSpacing) - make.leading.bottom.equalToSuperview().inset(Constant.contentViewInset) - } - - platformIconView.snp.makeConstraints { make in - make.leading.equalTo(accountLabel.snp.trailing) - make.centerY.equalTo(accountLabel) - make.size.equalTo(Constant.platformIconSize) - } - - platformLabel.snp.makeConstraints { make in - make.leading.equalTo(platformIconView.snp.trailing).offset(Constant.platformSpacing) - make.trailing.equalToSuperview().inset(Constant.contentViewInset) - make.centerY.equalTo(accountLabel) - } - - return view - }() - - private let infoLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .sub_m_b, text: "가입 정보") - return label - }() - - private let accountLabel: UILabel = { - let label = UILabel() - label.attributedText = .makeStyledString(font: .b_m_r, text: "가입 계정", alignment: .left) - return label - }() - - private let platformIconView = UIImageView() - private let platformLabel = UILabel() - - // setEdit - public let nickNameInputBox: InputBox = { - let box = InputBox(label: "닉네임", placeHodler: "한글 2~15자 입력해주세요.") - box.label.attributedText = .makeStyledString(font: .cp_s_r, text: "닉네임", color: .textColor) - return box - }() - - private lazy var errorMessageContentView: UIView = { - let view = UIView() - - view.addSubview(errorMessage) - - errorMessage.snp.makeConstraints { make in - make.centerX.equalToSuperview() - make.bottom.equalToSuperview().inset(Constant.errorMessageBottomMargin) - } - - return view - }() - - private let errorMessage = ErrorMessage(message: "닉네임은 15자 이하로 입력해주세요.") - - private let countLabel = UILabel() - - // MARK: - init - public init() { - super.init(frame: .zero) - addViews() - setupConstraints() - configureUI() - bindImageGesture() - bindTextFieldGesture() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - -// public override var inputAccessoryView: UIView? { -// return errorMessageContentView -// } - - public override var canBecomeFirstResponder: Bool { - return true - } -} - -// MARK: - SetUp -private extension SetProfileView { - func addViews() { - addSubview(headerView) - addSubview(imageView) - addSubview(nameLabel) - addSubview(backgroudView) - addSubview(nickNameInputBox) - addSubview(countLabel) - addSubview(logoutButton) - addSubview(cancelTextView) - } - - func setupConstraints() { - headerView.snp.makeConstraints { make in - make.top.leading.trailing.equalToSuperview() - make.height.equalTo(Constant.headerViewHeight) - } - - imageView.snp.makeConstraints { make in - make.top.equalTo(headerView.snp.bottom).offset(Constant.imageViewTopMargin) - make.centerX.equalToSuperview() - make.size.equalTo(Constant.imageSize) - } - - nameLabel.snp.makeConstraints { make in - make.top.equalTo(imageView.snp.bottom).offset(Constant.nameTopMargin) - make.centerX.equalToSuperview() - } - - backgroudView.snp.makeConstraints { make in - make.top.equalTo(nameLabel.snp.bottom).offset(Constant.nameBottomMargin) - make.horizontalEdges.bottom.equalToSuperview() - } - - nickNameInputBox.snp.makeConstraints { make in - make.top.equalTo(imageView.snp.bottom).offset(Constant.nickNameTopMargin) - make.horizontalEdges.equalToSuperview().inset(Constant.nickNameHorizontalMargin) - } - - countLabel.snp.makeConstraints { make in - make.top.equalTo(nickNameInputBox.snp.bottom).offset(Constant.countLabelTopMargin) - make.trailing.equalTo(nickNameInputBox) - } - - logoutButton.snp.makeConstraints { make in - make.centerX.equalToSuperview() - } - - cancelTextView.snp.makeConstraints { make in - make.top.equalTo(logoutButton.snp.bottom).offset(Constant.logoutBottomMargin) - make.centerX.equalToSuperview() - make.bottom.equalToSuperview().inset(Constant.cancelTextViewBottomMargin) - } - } - - func configureUI() { - backgroundColor = .whiteMLS - cancelTextView.delegate = self - nickNameInputBox.textField.inputAccessoryView = errorMessageContentView - } - - func bindImageGesture() { - imageView.isUserInteractionEnabled = true - - let tapGesture = UITapGestureRecognizer() - imageView.addGestureRecognizer(tapGesture) - - tapGesture.rx.event - .map { _ in } - .bind(to: imageTap) - .disposed(by: disposeBag) - - setImageButton.rx.tap - .bind(to: imageTap) - .disposed(by: disposeBag) - } - - func bindTextFieldGesture() { - let tapGesture = UITapGestureRecognizer() - tapGesture.cancelsTouchesInView = false - addGestureRecognizer(tapGesture) - - tapGesture.rx.event - .subscribe(onNext: { [weak self] _ in - self?.endEditing(true) - }) - .disposed(by: disposeBag) - } -} - -extension SetProfileView: UITextViewDelegate { - public func textView(_ textView: UITextView, shouldInteractWith URL: URL, in characterRange: NSRange, interaction: UITextItemInteraction) -> Bool { - if URL.absoluteString == "cancel" { - onCancelTap.accept(()) - return false - } - return true - } -} - -public extension SetProfileView { - enum SetProfileState { - case normal - case edit - } - - func setState(state: SetProfileState) { - switch state { - case .normal: - editButton.setAttributedTitle(.makeStyledString(font: .btn_m_r, text: "수정"), for: .normal) - nameLabel.isHidden = false - backgroudView.isHidden = false - nickNameInputBox.isHidden = true - setImageButton.isHidden = true - imageView.isUserInteractionEnabled = false - case .edit: - editButton.setAttributedTitle(.makeStyledString(font: .btn_m_r, text: "완료"), for: .normal) - nameLabel.isHidden = true - backgroudView.isHidden = true - nickNameInputBox.isHidden = false - setImageButton.isHidden = false - imageView.isUserInteractionEnabled = true - } - } - - func setImage(imageUrl: String) { - ImageLoader.shared.loadImage(stringURL: imageUrl) { [weak self] image in - self?.imageView.image = image - } - } - - func setName(name: String) { - nameLabel.attributedText = .makeStyledString(font: .sub_l_b, text: name) - } - - func setPlatform(platform: LoginPlatform) { - switch platform { - case .kakao: - platformLabel.attributedText = .makeStyledString(font: .b_m_r, text: "카카오") - platformIconView.image = DesignSystemAsset.image(named: "kakaoImage") - case .apple: - platformLabel.attributedText = .makeStyledString(font: .b_m_r, text: "애플") - platformIconView.image = DesignSystemAsset.image(named: "appleImage") - } - } - - func setCount(count: Int) { - countLabel.isHidden = count < 0 - let text = "\(count)/15" - - let attributed = NSMutableAttributedString(string: text) - - if count == 0 { - let fullRange = NSRange(location: 0, length: attributed.length) - attributed.addAttribute(.font, value: UIFont.korFont(style: .regular, size: 12)!, range: fullRange) - attributed.addAttribute(.foregroundColor, value: UIColor.neutral600, range: fullRange) - } else { - let countRange = (text as NSString).range(of: "\(count)") - attributed.addAttribute(.font, value: UIFont.korFont(style: .semiBold, size: 12)!, range: countRange) - attributed.addAttribute(.foregroundColor, value: UIColor.textColor, range: countRange) - - let suffixRange = (text as NSString).range(of: "/15") - attributed.addAttribute(.font, value: UIFont.korFont(style: .regular, size: 12)!, range: suffixRange) - attributed.addAttribute(.foregroundColor, value: UIColor.neutral600, range: suffixRange) - } - - countLabel.attributedText = attributed - } - - func setError(isError: Bool) { - errorMessage.isHidden = !isError - } - - func setCountHidden(state: SetProfileState) { - countLabel.isHidden = state != .edit - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileViewController.swift deleted file mode 100644 index fd8264d2..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeature/SetProfile/SetProfileViewController.swift +++ /dev/null @@ -1,216 +0,0 @@ -import UIKit - -import BaseFeature -import MyPageFeatureInterface - -import ReactorKit -import RxCocoa -import RxSwift -import SnapKit - -public final class SetProfileViewController: BaseViewController, View { - // MARK: - Type - enum Constant { - static let bottomHeight: CGFloat = 64 - } - - public typealias Reactor = SetProfileReactor - - // MARK: - Properties - public var disposeBag = DisposeBag() - - var didReturn = PublishRelay() - private var selectImageFactory: SelectImageFactory - - // MARK: - Components - private let mainView = SetProfileView() - private let topBackgroundView: UIView = { - let view = UIView() - view.backgroundColor = .whiteMLS - return view - }() - - // MARK: - Init - public init(selectImageFactory: SelectImageFactory) { - self.selectImageFactory = selectImageFactory - super.init() - } - - @available(*, unavailable) - required init?(coder: NSCoder) { - fatalError("init(coder:) has not been implemented") - } - - // MARK: - Lifecycle - override public func viewDidLoad() { - super.viewDidLoad() - addViews() - setupConstraints() - } -} - -// MARK: - Setup -private extension SetProfileViewController { - func addViews() { - view.addSubview(topBackgroundView) - view.addSubview(mainView) - } - - func setupConstraints() { - topBackgroundView.snp.makeConstraints { make in - make.top.horizontalEdges.equalToSuperview() - make.bottom.equalTo(view.safeAreaLayoutGuide.snp.top) - } - - mainView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } -} - -// MARK: - Bind -extension SetProfileViewController { - public func bind(reactor: Reactor) { - bindUserActions(reactor: reactor) - bindState(reactor: reactor) - } - - private func bindUserActions(reactor: Reactor) { - rx.viewWillAppear - .map { Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.backButton.rx.tap - .map { Reactor.Action.backButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.editButton.rx.tap - .map { Reactor.Action.editButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.imageTap - .map { Reactor.Action.showBottomSheet } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.nickNameInputBox.textField.rx.text.orEmpty - .map { Reactor.Action.inputNickName($0) } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.nickNameInputBox.textField.rx.controlEvent(.editingDidBegin) - .map { Reactor.Action.beginEditingNickName } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.logoutButton.rx.tap - .map { Reactor.Action.logoutButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - - mainView.onCancelTap - .map { Reactor.Action.withdrawButtonTapped } - .bind(to: reactor.action) - .disposed(by: disposeBag) - } - - private func bindState(reactor: Reactor) { - reactor.state - .map(\.setProfileState) - .distinctUntilChanged() - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind(onNext: { owner, state in - owner.view.backgroundColor = state == .edit ? .whiteMLS : .neutral100 - owner.mainView.setCountHidden(state: state) - owner.mainView.setState(state: state) - }) - .disposed(by: disposeBag) - - reactor.state - .compactMap(\.profile) - .distinctUntilChanged() - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind(onNext: { owner, profile in - owner.mainView.setImage(imageUrl: profile.profileUrl) - owner.mainView.setPlatform(platform: profile.platform) - owner.mainView.nickNameInputBox.textField.text = profile.nickname - }) - .disposed(by: disposeBag) - - reactor.state - .compactMap(\.nickName) - .distinctUntilChanged() - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind(onNext: { owner, nickname in - owner.mainView.setName(name: nickname) - }) - .disposed(by: disposeBag) - - reactor.state - .filter(\.isEditingNickName) - .compactMap(\.nickName) - .distinctUntilChanged() - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind(onNext: { owner, nickname in - owner.mainView.setCount(count: nickname.count) - }) - .disposed(by: disposeBag) - - reactor.state - .map(\.isShowError) - .distinctUntilChanged() - .withUnretained(self) - .observe(on: MainScheduler.instance) - .bind(onNext: { owner, isShowError in - owner.mainView.setError(isError: isShowError) - }) - .disposed(by: disposeBag) - - rx.viewDidAppear - .take(1) - .flatMapLatest { _ in reactor.pulse(\.$route) } - .withUnretained(self) - .observe(on: MainScheduler.instance) - .subscribe { owner, route in - switch route { - case .imageBottomSheet: - let viewController = owner.selectImageFactory.make() - - if let viewController = viewController as? UIViewController { - viewController.rx - .methodInvoked(#selector(UIViewController.viewDidDisappear)) - .take(1) - .map { _ in Reactor.Action.viewWillAppear } - .bind(to: reactor.action) - .disposed(by: owner.disposeBag) - } - - owner.presentModal(viewController) - case .dismiss: - owner.didReturn.accept(false) - owner.navigationController?.popViewController(animated: true) - case .dismissWithUpdate: - owner.didReturn.accept(true) - owner.navigationController?.popViewController(animated: true) - case .logoutAlert: - GuideAlertFactory.showAuthAlert(type: .logout, ctaAction: { - reactor.action.onNext(.logout) - }) - case .withdrawAlert: - GuideAlertFactory.showAuthAlert(type: .withdraw, ctaAction: { - reactor.action.onNext(.withdraw) - }) - default: - break - } - } - .disposed(by: disposeBag) - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/AppDelegate.swift b/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/AppDelegate.swift deleted file mode 100644 index d71869df..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/AppDelegate.swift +++ /dev/null @@ -1,166 +0,0 @@ -// swiftlint:disable line_length - -import UIKit - -import AuthFeatureInterface -import BaseFeature -import Core -import DesignSystem -import DomainInterface -import MyPageFeature -import MyPageFeatureInterface - -@main -class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate { - func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - ImageLoader.shared.configure.diskCacheCountLimit = 10 - FontManager.registerFonts() - registerDependencies() - - let center = UNUserNotificationCenter.current() - center.delegate = self - - center.getNotificationSettings { settings in - switch settings.authorizationStatus { - case .notDetermined: - center.requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in - if let error = error { - print("알림 권한 요청 실패: \(error)") - } else { - print("알림 권한 허용 여부: \(granted)") - } - } - case .denied: - print("사용자가 알림 권한 거부") - case .authorized, .provisional, .ephemeral: - print("알림 권한 이미 허용됨") - @unknown default: - break - } - } - - return true - } - - func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration { - return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role) - } - - func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set) {} -} - -private extension AppDelegate { - func registerDependencies() { - registerUseCase() - registerFactory() - } - - func registerUseCase() { - /// 테스트 코드에 맞게 등록 -// DIContainer.register(type: CheckNickNameUseCase.self) { -// CheckNickNameUseCaseImpl() -// } -// DIContainer.register(type: CheckEmptyLevelAndRoleUseCase.self) { -// CheckEmptyLevelAndRoleUseCaseImpl() -// } -// DIContainer.register(type: CheckValidLevelUseCase.self) { -// CheckValidLevelUseCaseImpl() -// } -// DIContainer.register(type: FetchJobListUseCase.self) { -// FetchJobListUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) -// } -// DIContainer.register(type: UpdateUserInfoUseCase.self) { -// UpdateUserInfoUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) -// } -// DIContainer.register(type: UpdateNickNameUseCase.self) { -// UpdateNickNameUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) -// } -// DIContainer.register(type: LogoutUseCase.self) { -// LogoutUseCaseImpl(repository: DIContainer.resolve(type: TokenRepository.self)) -// } -// DIContainer.register(type: WithdrawUseCase.self) { -// WithdrawUseCaseImpl(authRepository: DIContainer.resolve(type: AuthAPIRepository.self), tokenRepository: DIContainer.resolve(type: TokenRepository.self)) -// } -// DIContainer.register(type: FetchTokenFromLocalUseCase.self) { -// FetchTokenFromLocalUseCaseImpl(repository: DIContainer.resolve(type: TokenRepository.self)) -// } -// DIContainer.register(type: FetchNoticesUseCase.self) { -// FetchNoticesUseCaseImpl(repository: DIContainer.resolve(type: AlarmAPIRepository.self)) -// } -// DIContainer.register(type: FetchOngoingEventsUseCase.self) { -// FetchOngoingEventsUseCaseImpl(repository: DIContainer.resolve(type: AlarmAPIRepository.self)) -// } -// DIContainer.register(type: FetchOutdatedEventsUseCase.self) { -// FetchOutdatedEventsUseCaseImpl(repository: DIContainer.resolve(type: AlarmAPIRepository.self)) -// } -// DIContainer.register(type: FetchPatchNotesUseCase.self) { -// FetchPatchNotesUseCaseImpl(repository: DIContainer.resolve(type: AlarmAPIRepository.self)) -// } -// DIContainer.register(type: SetReadUseCase.self) { -// SetReadUseCaseImpl(repository: DIContainer.resolve(type: AlarmAPIRepository.self)) -// } -// DIContainer.register(type: CheckNotificationPermissionUseCase.self) { -// CheckNotificationPermissionUseCaseImpl() -// } -// DIContainer.register(type: UpdateNotificationAgreementUseCase.self) { -// UpdateNotificationAgreementUseCaseImpl(authRepository: DIContainer.resolve(type: AuthAPIRepository.self)) -// } -// DIContainer.register(type: UpdateProfileImageUseCase.self) { -// UpdateProfileImageUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) -// } -// DIContainer.register(type: FetchJobUseCase.self) { -// FetchJobUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self)) -// } -// DIContainer.register(type: FetchProfileUseCase.self) { -// FetchProfileUseCaseImpl(repository: DIContainer.resolve(type: AuthAPIRepository.self), fetchJobUseCase: DIContainer.resolve(type: FetchJobUseCase.self)) -// } - } - - func registerFactory() { - DIContainer.register(type: SelectImageFactory.self) { - SelectImageFactoryImpl(updateProfileImageUseCase: DIContainer.resolve(type: UpdateProfileImageUseCase.self)) - } - - DIContainer.register(type: SetProfileFactory.self) { - SetProfileFactoryImpl(selectImageFactory: DIContainer.resolve(type: SelectImageFactory.self), checkNickNameUseCase: DIContainer.resolve(type: CheckNickNameUseCase.self), updateNickNameUseCase: DIContainer.resolve(type: UpdateNickNameUseCase.self), logoutUseCase: DIContainer.resolve(type: LogoutUseCase.self), withdrawUseCase: DIContainer.resolve(type: WithdrawUseCase.self), fetchProfileUseCase: DIContainer.resolve(type: FetchProfileUseCase.self)) - } - - DIContainer.register(type: SetCharacterFactory.self) { - SetCharacterFactoryImpl( - checkEmptyUseCase: DIContainer - .resolve(type: CheckEmptyLevelAndRoleUseCase.self), - checkValidLevelUseCase: DIContainer - .resolve(type: CheckValidLevelUseCase.self), - fetchJobListUseCase: DIContainer - .resolve(type: FetchJobListUseCase.self), - updateUserInfoUseCase: DIContainer - .resolve(type: UpdateUserInfoUseCase.self) - ) - } - - DIContainer.register(type: MyPageMainFactory.self) { - MyPageMainFactoryImpl( - loginFactory: DIContainer.resolve(type: LoginFactory.self), setProfileFactory: DIContainer - .resolve(type: SetProfileFactory.self), - customerSupportFactory: DIContainer - .resolve(type: CustomerSupportFactory.self), - notificationSettingFactory: DIContainer - .resolve(type: NotificationSettingFactory.self), - setCharacterFactory: DIContainer - .resolve(type: SetCharacterFactory.self), fetchProfileUseCase: DIContainer.resolve(type: FetchProfileUseCase.self) - ) - } - - DIContainer.register(type: CustomerSupportFactory.self) { - CustomerSupportBaseViewFactoryImpl(policyFactory: DIContainer.resolve(type: PolicyFactory.self), fetchNoticesUseCase: DIContainer.resolve(type: FetchNoticesUseCase.self), fetchOngoingEventsUseCase: DIContainer.resolve(type: FetchOngoingEventsUseCase.self), fetchOutdatedEventsUseCase: DIContainer.resolve(type: FetchOutdatedEventsUseCase.self), fetchPatchNotesUseCase: DIContainer.resolve(type: FetchPatchNotesUseCase.self), setReadUseCase: DIContainer.resolve(type: SetReadUseCase.self)) - } - - DIContainer.register(type: NotificationSettingFactory.self) { - NotificationSettingFactoryImpl(checkNotificationPermissionUseCase: DIContainer.resolve(type: CheckNotificationPermissionUseCase.self), updateNotificationAgreementUseCase: DIContainer.resolve(type: UpdateNotificationAgreementUseCase.self)) - } - - DIContainer.register(type: LoginFactory.self) { - MockLoginFactory() - } - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Assets.xcassets/AccentColor.colorset/Contents.json b/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Assets.xcassets/AccentColor.colorset/Contents.json deleted file mode 100644 index eb878970..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Assets.xcassets/AccentColor.colorset/Contents.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "colors" : [ - { - "idiom" : "universal" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Assets.xcassets/AppIcon.appiconset/AppIcon.png b/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Assets.xcassets/AppIcon.appiconset/AppIcon.png deleted file mode 100644 index 58815bf5..00000000 Binary files a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Assets.xcassets/AppIcon.appiconset/AppIcon.png and /dev/null differ diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Assets.xcassets/AppIcon.appiconset/Contents.json b/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Assets.xcassets/AppIcon.appiconset/Contents.json deleted file mode 100644 index ce8e776e..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Assets.xcassets/AppIcon.appiconset/Contents.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "images" : [ - { - "filename" : "AppIcon.png", - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "dark" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - }, - { - "appearances" : [ - { - "appearance" : "luminosity", - "value" : "tinted" - } - ], - "idiom" : "universal", - "platform" : "ios", - "size" : "1024x1024" - } - ], - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Assets.xcassets/Contents.json b/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Assets.xcassets/Contents.json deleted file mode 100644 index 73c00596..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Assets.xcassets/Contents.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "info" : { - "author" : "xcode", - "version" : 1 - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Base.lproj/LaunchScreen.storyboard b/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Base.lproj/LaunchScreen.storyboard deleted file mode 100644 index 865e9329..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Base.lproj/LaunchScreen.storyboard +++ /dev/null @@ -1,25 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Info.plist b/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Info.plist deleted file mode 100644 index 7c5f0be1..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Info.plist +++ /dev/null @@ -1,25 +0,0 @@ - - - - - ITSAppUsesNonExemptEncryption - - UIApplicationSceneManifest - - UIApplicationSupportsMultipleScenes - - UISceneConfigurations - - UIWindowSceneSessionRoleApplication - - - UISceneConfigurationName - Default Configuration - UISceneDelegateClassName - $(PRODUCT_MODULE_NAME).SceneDelegate - - - - - - diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Mock/MockLoginFactory.swift b/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Mock/MockLoginFactory.swift deleted file mode 100644 index ff98072c..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/Mock/MockLoginFactory.swift +++ /dev/null @@ -1,10 +0,0 @@ -import AuthFeatureInterface -import BaseFeature - -public final class MockLoginFactory: LoginFactory { - public func make(exitRoute: LoginExitRoute, onLoginCompleted: (() -> Void)?) -> BaseViewController { - let viewcontroller = BaseViewController() - viewcontroller.view.backgroundColor = .redMLS - return viewcontroller - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/SceneDelegate.swift b/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/SceneDelegate.swift deleted file mode 100644 index 2e5908b1..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/SceneDelegate.swift +++ /dev/null @@ -1,23 +0,0 @@ -import UIKit - -class SceneDelegate: UIResponder, UIWindowSceneDelegate { - var window: UIWindow? - - func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { - guard let windowScene = (scene as? UIWindowScene) else { return } - window = UIWindow(windowScene: windowScene) - let startVC = ViewController() - window?.rootViewController = UINavigationController(rootViewController: startVC) - window?.makeKeyAndVisible() - } - - func sceneDidDisconnect(_ scene: UIScene) {} - - func sceneDidBecomeActive(_ scene: UIScene) {} - - func sceneWillResignActive(_ scene: UIScene) {} - - func sceneWillEnterForeground(_ scene: UIScene) {} - - func sceneDidEnterBackground(_ scene: UIScene) {} -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/ViewController.swift b/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/ViewController.swift deleted file mode 100644 index d1f3a414..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeatureDemo/ViewController.swift +++ /dev/null @@ -1,85 +0,0 @@ -import UIKit - -import Core -import DesignSystem -import MyPageFeatureInterface - -import SnapKit - -class ViewController: UIViewController { - let tableView: UITableView = { - let view = UITableView(frame: .zero, style: .plain) - return view - }() - - lazy var views: [[UIViewController]] = { - let mainView = BottomTabBarController(viewControllers: [ - DIContainer.resolve(type: MyPageMainFactory.self).make() - ]) - let announceView = BottomTabBarController(viewControllers: [ - DIContainer.resolve(type: CustomerSupportFactory.self).make(type: .announcement) - ]) - - let eventView = BottomTabBarController(viewControllers: [ - DIContainer.resolve(type: CustomerSupportFactory.self).make(type: .event) - ]) - - let patchView = BottomTabBarController(viewControllers: [ - DIContainer.resolve(type: CustomerSupportFactory.self).make(type: .patchNote) - ]) - - let termsView = BottomTabBarController(viewControllers: [ - DIContainer.resolve(type: CustomerSupportFactory.self).make(type: .terms) - ]) - - let notiView = BottomTabBarController(viewControllers: [ - DIContainer.resolve(type: NotificationSettingFactory.self).make(isAgreeEventNotification: false, isAgreeNoticeNotification: false, isAgreePatchNoteNotification: false) - ]) - - mainView.title = "마이페이지 메인" - announceView.title = "공지사항" - eventView.title = "이벤트" - patchView.title = "패치 노트" - termsView.title = "약관" - notiView.title = "알림설정" - - return [ - [mainView, announceView, eventView, patchView, termsView, notiView] - ] - }() - - override func viewDidLoad() { - super.viewDidLoad() - view.backgroundColor = .systemBackground - tableView.dataSource = self - tableView.delegate = self - navigationItem.title = "MLS Feature System" - view.addSubview(tableView) - - tableView.snp.makeConstraints { make in - make.edges.equalTo(view.safeAreaLayoutGuide) - } - } -} - -extension ViewController: UITableViewDataSource, UITableViewDelegate { - func numberOfSections(in tableView: UITableView) -> Int { - return views.count - } - - func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { - return views[section].count - } - - func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { - let cell = UITableViewCell() - cell.textLabel?.text = views[indexPath.section][indexPath.row].title - cell.selectionStyle = .none - return cell - } - - func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { - let nextController = views[indexPath.section][indexPath.row] - navigationController?.pushViewController(nextController, animated: true) - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/CustomerSupportFactory.swift b/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/CustomerSupportFactory.swift deleted file mode 100644 index fe54602e..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/CustomerSupportFactory.swift +++ /dev/null @@ -1,6 +0,0 @@ -import BaseFeature -import DomainInterface - -public protocol CustomerSupportFactory { - func make(type: CustomerSupportType) -> BaseViewController -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/MyPageMainFactory.swift b/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/MyPageMainFactory.swift deleted file mode 100644 index 4bd89971..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/MyPageMainFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol MyPageMainFactory { - func make() -> BaseViewController -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/NotificationSettingFactory.swift b/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/NotificationSettingFactory.swift deleted file mode 100644 index 45a4e762..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/NotificationSettingFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol NotificationSettingFactory { - func make(isAgreeEventNotification: Bool, isAgreeNoticeNotification: Bool, isAgreePatchNoteNotification: Bool) -> BaseViewController -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/PolicyFactory.swift b/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/PolicyFactory.swift deleted file mode 100644 index c97ad2ea..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/PolicyFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol PolicyFactory { - func make(type: PolicyType) -> BaseViewController -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/PolicyType.swift b/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/PolicyType.swift deleted file mode 100644 index aa334654..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/PolicyType.swift +++ /dev/null @@ -1,40 +0,0 @@ -import Foundation - -public enum PolicyType: CaseIterable { - case service - case privacy - case openSource - - public var title: String { - switch self { - case .service: - "서비스 이용약관" - case .privacy: - "개인정보 처리방침" - case .openSource: - "오픈소스 라이선스" - } - } - - public var fileName: String { - switch self { - case .service: - "TermsOfService.txt" - case .privacy: - "PrivacyPolicy.txt" - case .openSource: - "" - } - } - - public var content: String { - var result = "" - guard let pahts = Bundle.main.path(forResource: fileName, ofType: nil) else { return "" } - do { - result = try String(contentsOfFile: pahts, encoding: .utf8) - return result - } catch { - return "Error: file read failed - \(error.localizedDescription)" - } - } -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/SelectImageFactory.swift b/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/SelectImageFactory.swift deleted file mode 100644 index a71dcd7c..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/SelectImageFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol SelectImageFactory { - func make() -> BaseViewController & ModalPresentable -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/SetCharacterFactory.swift b/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/SetCharacterFactory.swift deleted file mode 100644 index 0ad4a20b..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/SetCharacterFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol SetCharacterFactory { - func make() -> BaseViewController -} diff --git a/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/SetProfileFactory.swift b/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/SetProfileFactory.swift deleted file mode 100644 index c1f9367d..00000000 --- a/MLS/Presentation/MyPageFeature/MyPageFeatureInterface/SetProfileFactory.swift +++ /dev/null @@ -1,5 +0,0 @@ -import BaseFeature - -public protocol SetProfileFactory { - func make() -> BaseViewController -}