diff --git a/Kream.xcodeproj/project.pbxproj b/Kream.xcodeproj/project.pbxproj index 9d4d6c4..ba82637 100644 --- a/Kream.xcodeproj/project.pbxproj +++ b/Kream.xcodeproj/project.pbxproj @@ -8,15 +8,45 @@ /* Begin PBXBuildFile section */ 5239955B2CAEF016005A358A /* SnapKit in Frameworks */ = {isa = PBXBuildFile; productRef = 5239955A2CAEF016005A358A /* SnapKit */; }; + + 52C6308B2CE1FF740098C775 /* KakaoSDK in Frameworks */ = {isa = PBXBuildFile; productRef = 52C6308A2CE1FF740098C775 /* KakaoSDK */; }; + 52C6308D2CE1FF740098C775 /* KakaoSDKAuth in Frameworks */ = {isa = PBXBuildFile; productRef = 52C6308C2CE1FF740098C775 /* KakaoSDKAuth */; }; + 52C6308F2CE1FF740098C775 /* KakaoSDKCert in Frameworks */ = {isa = PBXBuildFile; productRef = 52C6308E2CE1FF740098C775 /* KakaoSDKCert */; }; + 52C630912CE1FF740098C775 /* KakaoSDKCertCore in Frameworks */ = {isa = PBXBuildFile; productRef = 52C630902CE1FF740098C775 /* KakaoSDKCertCore */; }; + 52C630932CE1FF740098C775 /* KakaoSDKCommon in Frameworks */ = {isa = PBXBuildFile; productRef = 52C630922CE1FF740098C775 /* KakaoSDKCommon */; }; + 52C630952CE1FF740098C775 /* KakaoSDKFriend in Frameworks */ = {isa = PBXBuildFile; productRef = 52C630942CE1FF740098C775 /* KakaoSDKFriend */; }; + 52C630972CE1FF740098C775 /* KakaoSDKFriendCore in Frameworks */ = {isa = PBXBuildFile; productRef = 52C630962CE1FF740098C775 /* KakaoSDKFriendCore */; }; + 52C630992CE1FF740098C775 /* KakaoSDKNavi in Frameworks */ = {isa = PBXBuildFile; productRef = 52C630982CE1FF740098C775 /* KakaoSDKNavi */; }; + 52C6309B2CE1FF740098C775 /* KakaoSDKShare in Frameworks */ = {isa = PBXBuildFile; productRef = 52C6309A2CE1FF740098C775 /* KakaoSDKShare */; }; + 52C6309D2CE1FF740098C775 /* KakaoSDKTalk in Frameworks */ = {isa = PBXBuildFile; productRef = 52C6309C2CE1FF740098C775 /* KakaoSDKTalk */; }; + 52C6309F2CE1FF740098C775 /* KakaoSDKTemplate in Frameworks */ = {isa = PBXBuildFile; productRef = 52C6309E2CE1FF740098C775 /* KakaoSDKTemplate */; }; + 52C630A12CE1FF740098C775 /* KakaoSDKUser in Frameworks */ = {isa = PBXBuildFile; productRef = 52C630A02CE1FF740098C775 /* KakaoSDKUser */; }; + 52C630E02CE4320C0098C775 /* KeychainAccess in Frameworks */ = {isa = PBXBuildFile; productRef = 52C630DF2CE4320C0098C775 /* KeychainAccess */; }; + /* End PBXBuildFile section */ /* Begin PBXFileReference section */ 52C34CF12CA47B3E00DB8986 /* Kream.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Kream.app; sourceTree = BUILT_PRODUCTS_DIR; }; /* End PBXFileReference section */ + +/* Begin PBXFileSystemSynchronizedBuildFileExceptionSet section */ + 52C34D032CA47B4000DB8986 /* Exceptions for "Kream" folder in "Kream" target */ = { + isa = PBXFileSystemSynchronizedBuildFileExceptionSet; + membershipExceptions = ( + Info.plist, + ); + target = 52C34CF02CA47B3E00DB8986 /* Kream */; + }; +/* End PBXFileSystemSynchronizedBuildFileExceptionSet section */ + /* Begin PBXFileSystemSynchronizedRootGroup section */ 52C34CF32CA47B3E00DB8986 /* Kream */ = { isa = PBXFileSystemSynchronizedRootGroup; + exceptions = ( + 52C34D032CA47B4000DB8986 /* Exceptions for "Kream" folder in "Kream" target */, + ); + path = Kream; sourceTree = ""; }; @@ -28,6 +58,21 @@ buildActionMask = 2147483647; files = ( 5239955B2CAEF016005A358A /* SnapKit in Frameworks */, + + 52C630952CE1FF740098C775 /* KakaoSDKFriend in Frameworks */, + 52C630E02CE4320C0098C775 /* KeychainAccess in Frameworks */, + 52C6308B2CE1FF740098C775 /* KakaoSDK in Frameworks */, + 52C630992CE1FF740098C775 /* KakaoSDKNavi in Frameworks */, + 52C630912CE1FF740098C775 /* KakaoSDKCertCore in Frameworks */, + 52C6309F2CE1FF740098C775 /* KakaoSDKTemplate in Frameworks */, + 52C630972CE1FF740098C775 /* KakaoSDKFriendCore in Frameworks */, + 52C6308D2CE1FF740098C775 /* KakaoSDKAuth in Frameworks */, + 52C630A12CE1FF740098C775 /* KakaoSDKUser in Frameworks */, + 52C6309D2CE1FF740098C775 /* KakaoSDKTalk in Frameworks */, + 52C6309B2CE1FF740098C775 /* KakaoSDKShare in Frameworks */, + 52C630932CE1FF740098C775 /* KakaoSDKCommon in Frameworks */, + 52C6308F2CE1FF740098C775 /* KakaoSDKCert in Frameworks */, + ); runOnlyForDeploymentPostprocessing = 0; }; @@ -71,6 +116,21 @@ name = Kream; packageProductDependencies = ( 5239955A2CAEF016005A358A /* SnapKit */, + + 52C6308A2CE1FF740098C775 /* KakaoSDK */, + 52C6308C2CE1FF740098C775 /* KakaoSDKAuth */, + 52C6308E2CE1FF740098C775 /* KakaoSDKCert */, + 52C630902CE1FF740098C775 /* KakaoSDKCertCore */, + 52C630922CE1FF740098C775 /* KakaoSDKCommon */, + 52C630942CE1FF740098C775 /* KakaoSDKFriend */, + 52C630962CE1FF740098C775 /* KakaoSDKFriendCore */, + 52C630982CE1FF740098C775 /* KakaoSDKNavi */, + 52C6309A2CE1FF740098C775 /* KakaoSDKShare */, + 52C6309C2CE1FF740098C775 /* KakaoSDKTalk */, + 52C6309E2CE1FF740098C775 /* KakaoSDKTemplate */, + 52C630A02CE1FF740098C775 /* KakaoSDKUser */, + 52C630DF2CE4320C0098C775 /* KeychainAccess */, + ); productName = Kream; productReference = 52C34CF12CA47B3E00DB8986 /* Kream.app */; @@ -102,6 +162,10 @@ minimizedProjectReferenceProxies = 1; packageReferences = ( 523995592CAEF016005A358A /* XCRemoteSwiftPackageReference "SnapKit" */, + + 52C630892CE1FF740098C775 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */, + 52C630DE2CE4320C0098C775 /* XCRemoteSwiftPackageReference "KeychainAccess" */, + ); preferredProjectObjectVersion = 77; productRefGroup = 52C34CF22CA47B3E00DB8986 /* Products */; @@ -337,6 +401,24 @@ minimumVersion = 5.7.1; }; }; + + 52C630892CE1FF740098C775 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/kakao/kakao-ios-sdk"; + requirement = { + kind = upToNextMajorVersion; + minimumVersion = 2.23.0; + }; + }; + 52C630DE2CE4320C0098C775 /* XCRemoteSwiftPackageReference "KeychainAccess" */ = { + isa = XCRemoteSwiftPackageReference; + repositoryURL = "https://github.com/kishikawakatsumi/KeychainAccess"; + requirement = { + branch = master; + kind = branch; + }; + }; + /* End XCRemoteSwiftPackageReference section */ /* Begin XCSwiftPackageProductDependency section */ @@ -345,6 +427,73 @@ package = 523995592CAEF016005A358A /* XCRemoteSwiftPackageReference "SnapKit" */; productName = SnapKit; }; + + 52C6308A2CE1FF740098C775 /* KakaoSDK */ = { + isa = XCSwiftPackageProductDependency; + package = 52C630892CE1FF740098C775 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; + productName = KakaoSDK; + }; + 52C6308C2CE1FF740098C775 /* KakaoSDKAuth */ = { + isa = XCSwiftPackageProductDependency; + package = 52C630892CE1FF740098C775 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; + productName = KakaoSDKAuth; + }; + 52C6308E2CE1FF740098C775 /* KakaoSDKCert */ = { + isa = XCSwiftPackageProductDependency; + package = 52C630892CE1FF740098C775 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; + productName = KakaoSDKCert; + }; + 52C630902CE1FF740098C775 /* KakaoSDKCertCore */ = { + isa = XCSwiftPackageProductDependency; + package = 52C630892CE1FF740098C775 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; + productName = KakaoSDKCertCore; + }; + 52C630922CE1FF740098C775 /* KakaoSDKCommon */ = { + isa = XCSwiftPackageProductDependency; + package = 52C630892CE1FF740098C775 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; + productName = KakaoSDKCommon; + }; + 52C630942CE1FF740098C775 /* KakaoSDKFriend */ = { + isa = XCSwiftPackageProductDependency; + package = 52C630892CE1FF740098C775 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; + productName = KakaoSDKFriend; + }; + 52C630962CE1FF740098C775 /* KakaoSDKFriendCore */ = { + isa = XCSwiftPackageProductDependency; + package = 52C630892CE1FF740098C775 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; + productName = KakaoSDKFriendCore; + }; + 52C630982CE1FF740098C775 /* KakaoSDKNavi */ = { + isa = XCSwiftPackageProductDependency; + package = 52C630892CE1FF740098C775 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; + productName = KakaoSDKNavi; + }; + 52C6309A2CE1FF740098C775 /* KakaoSDKShare */ = { + isa = XCSwiftPackageProductDependency; + package = 52C630892CE1FF740098C775 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; + productName = KakaoSDKShare; + }; + 52C6309C2CE1FF740098C775 /* KakaoSDKTalk */ = { + isa = XCSwiftPackageProductDependency; + package = 52C630892CE1FF740098C775 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; + productName = KakaoSDKTalk; + }; + 52C6309E2CE1FF740098C775 /* KakaoSDKTemplate */ = { + isa = XCSwiftPackageProductDependency; + package = 52C630892CE1FF740098C775 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; + productName = KakaoSDKTemplate; + }; + 52C630A02CE1FF740098C775 /* KakaoSDKUser */ = { + isa = XCSwiftPackageProductDependency; + package = 52C630892CE1FF740098C775 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; + productName = KakaoSDKUser; + }; + 52C630DF2CE4320C0098C775 /* KeychainAccess */ = { + isa = XCSwiftPackageProductDependency; + package = 52C630DE2CE4320C0098C775 /* XCRemoteSwiftPackageReference "KeychainAccess" */; + productName = KeychainAccess; + }; + /* End XCSwiftPackageProductDependency section */ }; rootObject = 52C34CE92CA47B3E00DB8986 /* Project object */; diff --git a/Kream/AppDelegate.swift b/Kream/AppDelegate.swift index 1e422bb..4777d2d 100644 --- a/Kream/AppDelegate.swift +++ b/Kream/AppDelegate.swift @@ -1,18 +1,26 @@ import UIKit +import KakaoSDKCommon + + @main class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { - + + // Kakao SDK 초기화 + KakaoSDK.initSDK(appKey: "2c8ab94e144d90c1bb9598fb2443dea1") + // 윈도우 생성 및 설정 window = UIWindow(frame: UIScreen.main.bounds) - - // 로그인 화면을 루트 뷰 컨트롤러로 설정 + + // ProductDetailViewController를 루트 뷰 컨트롤러로 설정 let loginViewController = LoginViewController() - window?.rootViewController = loginViewController + let navigationController = UINavigationController(rootViewController: loginViewController) + window?.rootViewController = navigationController + window?.makeKeyAndVisible() return true diff --git a/Kream/Assets.xcassets/productDetail/Contents.json b/Kream/Assets.xcassets/productDetail/Contents.json new file mode 100644 index 0000000..73c0059 --- /dev/null +++ b/Kream/Assets.xcassets/productDetail/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Kream/Assets.xcassets/productDetail/color_1.imageset/Contents.json b/Kream/Assets.xcassets/productDetail/color_1.imageset/Contents.json new file mode 100644 index 0000000..48d4161 --- /dev/null +++ b/Kream/Assets.xcassets/productDetail/color_1.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Rectangle 9653.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Kream/Assets.xcassets/productDetail/color_1.imageset/Rectangle 9653.png b/Kream/Assets.xcassets/productDetail/color_1.imageset/Rectangle 9653.png new file mode 100644 index 0000000..4b47f3b Binary files /dev/null and b/Kream/Assets.xcassets/productDetail/color_1.imageset/Rectangle 9653.png differ diff --git a/Kream/Assets.xcassets/productDetail/color_2.imageset/Contents.json b/Kream/Assets.xcassets/productDetail/color_2.imageset/Contents.json new file mode 100644 index 0000000..bbd68b3 --- /dev/null +++ b/Kream/Assets.xcassets/productDetail/color_2.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Rectangle 9652.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Kream/Assets.xcassets/productDetail/color_2.imageset/Rectangle 9652.png b/Kream/Assets.xcassets/productDetail/color_2.imageset/Rectangle 9652.png new file mode 100644 index 0000000..c2c22f0 Binary files /dev/null and b/Kream/Assets.xcassets/productDetail/color_2.imageset/Rectangle 9652.png differ diff --git a/Kream/Assets.xcassets/productDetail/color_3.imageset/Contents.json b/Kream/Assets.xcassets/productDetail/color_3.imageset/Contents.json new file mode 100644 index 0000000..a2e20c2 --- /dev/null +++ b/Kream/Assets.xcassets/productDetail/color_3.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Rectangle 9654.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Kream/Assets.xcassets/productDetail/color_3.imageset/Rectangle 9654.png b/Kream/Assets.xcassets/productDetail/color_3.imageset/Rectangle 9654.png new file mode 100644 index 0000000..004e418 Binary files /dev/null and b/Kream/Assets.xcassets/productDetail/color_3.imageset/Rectangle 9654.png differ diff --git a/Kream/Assets.xcassets/productDetail/color_4.imageset/Contents.json b/Kream/Assets.xcassets/productDetail/color_4.imageset/Contents.json new file mode 100644 index 0000000..8971cbc --- /dev/null +++ b/Kream/Assets.xcassets/productDetail/color_4.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Rectangle 9655.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Kream/Assets.xcassets/productDetail/color_4.imageset/Rectangle 9655.png b/Kream/Assets.xcassets/productDetail/color_4.imageset/Rectangle 9655.png new file mode 100644 index 0000000..db5cd0a Binary files /dev/null and b/Kream/Assets.xcassets/productDetail/color_4.imageset/Rectangle 9655.png differ diff --git a/Kream/Assets.xcassets/productDetail/color_5.imageset/Contents.json b/Kream/Assets.xcassets/productDetail/color_5.imageset/Contents.json new file mode 100644 index 0000000..0bdfc99 --- /dev/null +++ b/Kream/Assets.xcassets/productDetail/color_5.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Rectangle 9656.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Kream/Assets.xcassets/productDetail/color_5.imageset/Rectangle 9656.png b/Kream/Assets.xcassets/productDetail/color_5.imageset/Rectangle 9656.png new file mode 100644 index 0000000..2c237df Binary files /dev/null and b/Kream/Assets.xcassets/productDetail/color_5.imageset/Rectangle 9656.png differ diff --git a/Kream/Assets.xcassets/productDetail/color_6.imageset/Contents.json b/Kream/Assets.xcassets/productDetail/color_6.imageset/Contents.json new file mode 100644 index 0000000..1b73053 --- /dev/null +++ b/Kream/Assets.xcassets/productDetail/color_6.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "Rectangle 9657.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Kream/Assets.xcassets/productDetail/color_6.imageset/Rectangle 9657.png b/Kream/Assets.xcassets/productDetail/color_6.imageset/Rectangle 9657.png new file mode 100644 index 0000000..c872a48 Binary files /dev/null and b/Kream/Assets.xcassets/productDetail/color_6.imageset/Rectangle 9657.png differ diff --git a/Kream/Assets.xcassets/productDetail/matinKim.imageset/Contents.json b/Kream/Assets.xcassets/productDetail/matinKim.imageset/Contents.json new file mode 100644 index 0000000..bd17fa8 --- /dev/null +++ b/Kream/Assets.xcassets/productDetail/matinKim.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "filename" : "matinKim.png", + "idiom" : "universal", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "author" : "xcode", + "version" : 1 + } +} diff --git a/Kream/Assets.xcassets/productDetail/matinKim.imageset/matinKim.png b/Kream/Assets.xcassets/productDetail/matinKim.imageset/matinKim.png new file mode 100644 index 0000000..6894dd8 Binary files /dev/null and b/Kream/Assets.xcassets/productDetail/matinKim.imageset/matinKim.png differ diff --git a/Kream/Assets.xcassets/tab_bar_icon/mypage_icon.imageset/Contents.json b/Kream/Assets.xcassets/tab_bar_icon/mypage_icon.imageset/Contents.json index 9ee1d24..363e9a9 100644 --- a/Kream/Assets.xcassets/tab_bar_icon/mypage_icon.imageset/Contents.json +++ b/Kream/Assets.xcassets/tab_bar_icon/mypage_icon.imageset/Contents.json @@ -1,17 +1,21 @@ { "images" : [ { - "filename" : "my_icon.png", + + "filename" : "mypage_icon.png", + "idiom" : "universal", "scale" : "1x" }, { - "filename" : "my_icon 1.png", + "idiom" : "universal", "scale" : "2x" }, { + "filename" : "my_icon 2.png", + "idiom" : "universal", "scale" : "3x" } diff --git a/Kream/Assets.xcassets/tab_bar_icon/mypage_icon.imageset/mypage_icon.png b/Kream/Assets.xcassets/tab_bar_icon/mypage_icon.imageset/mypage_icon.png new file mode 100644 index 0000000..bad3906 Binary files /dev/null and b/Kream/Assets.xcassets/tab_bar_icon/mypage_icon.imageset/mypage_icon.png differ diff --git a/Kream/Models/LoginModel.swift b/Kream/Models/LoginModel.swift index 9611037..08fd74c 100644 --- a/Kream/Models/LoginModel.swift +++ b/Kream/Models/LoginModel.swift @@ -1,5 +1,55 @@ import Foundation + +class LoginViewModel { + + // UserDefaults에 저장할 키 정의 + private let emailKey = "userEmail" + private let passwordKey = "userPassword" + + // 저장된 이메일과 비밀번호를 UserDefaults에서 불러와서 저장할 변수 + var email: String { + get { + return UserDefaults.standard.string(forKey: emailKey) ?? "" + } + set { + UserDefaults.standard.set(newValue, forKey: emailKey) + } + } + + var password: String { + get { + return UserDefaults.standard.string(forKey: passwordKey) ?? "" + } + set { + UserDefaults.standard.set(newValue, forKey: passwordKey) + } + } + + // 로그인 성공 여부를 반환하는 메서드 + func login(email: String, password: String) -> Bool { + // 간단한 예시: 이메일과 비밀번호가 일치하면 로그인 성공으로 간주 + if self.email == email && self.password == password { + return true + } else { + return false + } + } + + // UserDefaults에 이메일과 비밀번호 저장 메서드 + func saveCredentials(email: String, password: String) { + self.email = email + self.password = password + } + + // UserDefaults에서 이메일과 비밀번호 삭제 메서드 + func clearCredentials() { + UserDefaults.standard.removeObject(forKey: emailKey) + UserDefaults.standard.removeObject(forKey: passwordKey) + } +} + + // 이메일과 비밀번호를 처리하는 모델 struct LoginModel { var email: String = "" @@ -22,3 +72,4 @@ struct LoginModel { return isValidEmail() && isValidPassword() } } + diff --git a/Kream/SceneDelegate.swift b/Kream/SceneDelegate.swift index 479c3b7..0f3b9ec 100644 --- a/Kream/SceneDelegate.swift +++ b/Kream/SceneDelegate.swift @@ -14,11 +14,15 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate { func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) { guard let windowScene = (scene as? UIWindowScene) else { return } - - + window = UIWindow(frame: windowScene.coordinateSpace.bounds) window?.windowScene = windowScene - window?.rootViewController = LoginViewController() // LoginViewController로 변경 + + // ProductDetailViewController를 초기 루트 뷰 컨트롤러로 설정 + let loginViewController = LoginViewController() + + window?.rootViewController = UINavigationController(rootViewController: LoginViewController()) + window?.makeKeyAndVisible() } diff --git a/Kream/VIews/Cell/ColorCollectionViewCell.swift b/Kream/VIews/Cell/ColorCollectionViewCell.swift new file mode 100644 index 0000000..b46db57 --- /dev/null +++ b/Kream/VIews/Cell/ColorCollectionViewCell.swift @@ -0,0 +1,68 @@ +// ColorCollectionViewCell.swift +import UIKit +import SnapKit + +class ColorCollectionViewCell: UICollectionViewCell { + + let colorImageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFit + imageView.layer.cornerRadius = 8 // 이미지에 라운드를 추가 + imageView.layer.masksToBounds = true // 라운드 처리를 위해 클리핑 활성화 + return imageView + }() + + // 선택된 상태를 표시하기 위한 뷰 추가 (선택 효과) + let selectionOverlay: UIView = { + let view = UIView() + view.backgroundColor = UIColor.black.withAlphaComponent(0.3) // 반투명한 검은색 오버레이 + view.isHidden = true // 기본적으로 숨김 처리 + view.layer.cornerRadius = 8 // 동일하게 라운드 적용 + view.layer.masksToBounds = true + return view + }() + + override init(frame: CGRect) { + super.init(frame: frame) + contentView.addSubview(colorImageView) + contentView.addSubview(selectionOverlay) // 오버레이 추가 + + colorImageView.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + selectionOverlay.snp.makeConstraints { make in + make.edges.equalToSuperview() + } + + setupGesture() // 제스처 설정 추가 + } + + required init?(coder: NSCoder) { + fatalError("init(coder:) has not been implemented") + } + + // 이미지를 설정하는 메서드 + func configure(with image: UIImage?) { + colorImageView.image = image + } + + // 셀이 선택되었을 때 효과 추가 + override var isSelected: Bool { + didSet { + selectionOverlay.isHidden = !isSelected // 선택되었을 때만 오버레이를 보여줌 + } + } + + // 셀 클릭 이벤트 처리를 위한 제스처 설정 + private func setupGesture() { + let tapGesture = UITapGestureRecognizer(target: self, action: #selector(handleTap)) + self.addGestureRecognizer(tapGesture) + } + + @objc private func handleTap() { + // 선택 시 처리 로직 추가 (필요시 외부에서 호출할 수도 있음) + self.isSelected.toggle() + } +} + diff --git a/Kream/VIews/Cell/JustDroppedCollectionViewCell.swift b/Kream/VIews/Cell/JustDroppedCollectionViewCell.swift index 41e3434..370ef56 100644 --- a/Kream/VIews/Cell/JustDroppedCollectionViewCell.swift +++ b/Kream/VIews/Cell/JustDroppedCollectionViewCell.swift @@ -3,7 +3,6 @@ import SnapKit class JustDroppedCollectionViewCell: UICollectionViewCell { - let imageView: UIImageView = { let imageView = UIImageView() imageView.contentMode = .scaleAspectFill @@ -11,7 +10,31 @@ class JustDroppedCollectionViewCell: UICollectionViewCell { imageView.layer.cornerRadius = 10 return imageView }() + + + + let bookmarkButton: UIButton = { + var configuration = UIButton.Configuration.plain() + configuration.image = UIImage(systemName: "bookmark") + configuration.baseForegroundColor = .black + + let button = UIButton(configuration: configuration) + button.addTarget(self, action: #selector(bookmarkButtonTapped), for: .touchUpInside) + + // 클릭 시 하이라이트 효과 제거 + button.configurationUpdateHandler = { button in + var config = button.configuration + if button.isHighlighted { + config?.baseBackgroundColor = .clear // 하이라이트 시에도 배경색 변경 없이 유지 + button.alpha = 1.0 // 알파값 조정으로 시각적인 효과 제거 + } + button.configuration = config + } + + return button + }() + let titleLabel: UILabel = { let label = UILabel() label.font = UIFont.boldSystemFont(ofSize: 12) @@ -40,17 +63,20 @@ class JustDroppedCollectionViewCell: UICollectionViewCell { return label }() + override init(frame: CGRect) { super.init(frame: frame) setupLayout() + bookmarkButton.addTarget(self, action: #selector(toggleBookmark), for: .touchUpInside) } - + required init?(coder: NSCoder) { fatalError("init(coder:) has not been implemented") } func setupLayout() { contentView.addSubview(imageView) + contentView.addSubview(bookmarkButton) contentView.addSubview(titleLabel) contentView.addSubview(descriptionLabel) contentView.addSubview(priceLabel) @@ -58,16 +84,23 @@ class JustDroppedCollectionViewCell: UICollectionViewCell { imageView.snp.makeConstraints { make in make.top.leading.trailing.equalToSuperview() - make.height.equalTo(142) // 이미지 높이를 142로 설정 + make.height.equalTo(142) + } + + bookmarkButton.snp.makeConstraints { make in + make.bottom.equalTo(imageView.snp.bottom).offset(-8) + make.trailing.equalTo(imageView.snp.trailing).offset(-8) + make.width.height.equalTo(24) } + titleLabel.snp.makeConstraints { make in - make.top.equalTo(imageView.snp.bottom).offset(4) // 이미지와의 간격을 줄임 + make.top.equalTo(imageView.snp.bottom).offset(4) make.leading.trailing.equalToSuperview().inset(8) } descriptionLabel.snp.makeConstraints { make in - make.top.equalTo(titleLabel.snp.bottom).offset(2) // 타이틀과의 간격을 줄임 + make.top.equalTo(titleLabel.snp.bottom).offset(2) make.leading.trailing.equalToSuperview().inset(8) } @@ -82,8 +115,18 @@ class JustDroppedCollectionViewCell: UICollectionViewCell { make.bottom.equalToSuperview().offset(-8) } } - - + + @objc func bookmarkButtonTapped() { + bookmarkButton.isSelected.toggle() + let imageName = bookmarkButton.isSelected ? "bookmark.fill" : "bookmark" + let icon = UIImage(systemName: imageName)?.withTintColor(.black, renderingMode: .alwaysOriginal) + bookmarkButton.setImage(icon, for: .normal) // 아이콘 전체를 검은색으로 설정 + } + + @objc func toggleBookmark() { + bookmarkButton.isSelected.toggle() + } + func configure(with item: JustDroppedItem) { imageView.image = item.image diff --git a/Kream/VIews/LoginView.swift b/Kream/VIews/LoginView.swift index 5012801..69ab203 100644 --- a/Kream/VIews/LoginView.swift +++ b/Kream/VIews/LoginView.swift @@ -81,11 +81,11 @@ class LoginView: UIView { let kakaoLoginButton: UIButton = { let button = UIButton(type: .system) - // 'Inter-Bold' 폰트 사용 (프로젝트에 포함되어 있어야 함) + let customFont = UIFont(name: "Inter-Bold", size: 13) ?? UIFont.boldSystemFont(ofSize: 16) let title = NSAttributedString(string: "카카오로 로그인", attributes: [ - .font: customFont // Inter-Bold 폰트로 설정 + .font: customFont ]) button.setAttributedTitle(title, for: .normal) @@ -110,11 +110,11 @@ class LoginView: UIView { let appleLoginButton: UIButton = { let button = UIButton(type: .system) - // 'Inter-Bold' 폰트 사용 (프로젝트에 포함되어 있어야 함) + let customFont = UIFont(name: "Inter-Bold", size: 13) ?? UIFont.boldSystemFont(ofSize: 16) let title = NSAttributedString(string: "Apple로 로그인", attributes: [ - .font: customFont // Inter-Bold 폰트로 설정 + .font: customFont ]) button.setAttributedTitle(title, for: .normal) diff --git a/Kream/VIews/MainTabBarViewController.swift b/Kream/VIews/MainTabBarViewController.swift index ab1594a..25b4a03 100644 --- a/Kream/VIews/MainTabBarViewController.swift +++ b/Kream/VIews/MainTabBarViewController.swift @@ -12,10 +12,10 @@ class MainTabBarController: UITabBarController { super.viewDidLoad() - let homeViewController = createNavController(for: HomeViewController(), title: "HOME", image: UIImage(named: "home_icon")!) + let homeViewController = createNavController(for: MainViewController(), title: "HOME", image: UIImage(named: "home_icon")!) let styleViewController = createNavController(for: StyleViewController(), title: "STYLE", image: UIImage(named: "style_icon")!) let shopViewController = createNavController(for: ShopViewController(), title: "SHOP", image: UIImage(named: "shop_icon")!) - let savedViewController = createNavController(for: SavedViewController(), title: "SAVED", image: UIImage(named: "saved_icon")!) + let savedViewController = createNavController(for: SavedViewController(), title: "Saved", image: UIImage(named: "saved_icon")!) let myViewController = createNavController(for: MyViewController(), title: "My", image: UIImage(named: "mypage_icon")!) diff --git a/Kream/VIews/SavedViewController.swift b/Kream/VIews/SavedViewController.swift index 4818b54..9a6a502 100644 --- a/Kream/VIews/SavedViewController.swift +++ b/Kream/VIews/SavedViewController.swift @@ -1,29 +1,74 @@ -// -// SavedViewController.swift -// Kream -// -// Created by 임소은 on 10/4/24. -// - import UIKit class SavedViewController: UIViewController { - + + // SavedListView 인스턴스 생성 + let savedListView = SavedListView() + + // 더미 데이터 배열 + var savedItems: [SavedItem] = [ + SavedItem(image: UIImage(named: "cell_image_1"), title: "하얀 음료", description: "이 음료를 마시면 건강해져요. 그런데 어디가 건강해질까요? 한 번 마셔봐요....", price: "120,000원"), + SavedItem(image: UIImage(named: "cell_image_2"), title: "이어폰", description: "모닝 커피로 마시면 하루가 상쾌해져요!", price: "3,500원"), + SavedItem(image: UIImage(named: "cell_image_3"), title: "옷", description: "녹차는 몸을 맑게 해줘요. 따뜻하게 한 잔 어떠세요?", price: "5,000원"), + SavedItem(image: UIImage(named: "cell_image_4"), title: "신발", description: "홍차는 풍부한 향과 맛이 특징이에요.", price: "6,000원"), + SavedItem(image: UIImage(named: "cell_image_5"), title: "반지", description: "우유는 칼슘이 풍부하여 뼈 건강에 좋아요.", price: "1,500원"), + SavedItem(image: UIImage(named: "cell_image_6"), title: "긴목 신발", description: "초코 음료는 달콤한 맛이 일품이에요!", price: "4,500원"), + SavedItem(image: UIImage(named: "cell_image_7"), title: "밥", description: "더운 여름날 시원하게 한 잔 하세요.", price: "3,000원"), + SavedItem(image: UIImage(named: "cell_image_8"), title: "배고파", description: "상큼한 레몬 에이드로 피로를 풀어보세요.", price: "5,000원"), + SavedItem(image: UIImage(named: "cell_image_9"), title: "새벽3시", description: "신선한 딸기가 들어간 스무디입니다.", price: "7,000원"), + SavedItem(image: UIImage(named: "10"), title: "세상에", description: "달콤한 망고 주스를 즐겨보세요.", price: "6,500원") + ] + override func viewDidLoad() { super.viewDidLoad() + view.backgroundColor = .white + + // SavedListView를 뷰에 추가 + view.addSubview(savedListView) + savedListView.snp.makeConstraints { make in + make.edges.equalToSuperview() // 전체 화면에 맞춤 + } + + // 테이블 뷰 델리게이트 및 데이터 소스 설정 + savedListView.tableView.delegate = self + savedListView.tableView.dataSource = self + + // 더미데이터 갯수에 맞춰 동적으로 변하도록 설정 + savedListView.itemCountLabel.text = "전체 \(savedItems.count)개" + + savedListView.itemCountLabel.snp.remakeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide.snp.top).offset(50) // 아래로 50pt 이동 + make.leading.equalToSuperview().offset(16) + } + } +} - // Do any additional setup after loading the view. +// MARK: - UITableViewDelegate, UITableViewDataSource +extension SavedViewController: UITableViewDelegate, UITableViewDataSource { + + // 테이블 뷰의 셀 개수 + func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { + return savedItems.count // 더미 데이터 배열의 개수 반환 } - - /* - // MARK: - Navigation - - // In a storyboard-based application, you will often want to do a little preparation before navigation - override func prepare(for segue: UIStoryboardSegue, sender: Any?) { - // Get the new view controller using segue.destination. - // Pass the selected object to the new view controller. + // 테이블 뷰의 셀 구성 + func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { + guard let cell = tableView.dequeueReusableCell(withIdentifier: "SavedCell", for: indexPath) as? SavedTableViewCell else { + return UITableViewCell() + } + + // 배열에서 데이터 가져오기 + let item = savedItems[indexPath.row] + + // 셀에 데이터 설정 + cell.configure(image: item.image, title: item.title, description: item.description, price: item.price) + + return cell + } + + // 셀이 선택되었을 때 호출되는 메서드 + func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { + } - */ - } + diff --git a/Kream/VIews/SettingViewController.swift b/Kream/VIews/SettingViewController.swift index 5a062dd..2ceda74 100644 --- a/Kream/VIews/SettingViewController.swift +++ b/Kream/VIews/SettingViewController.swift @@ -1,6 +1,9 @@ import UIKit import SnapKit + + + class SettingViewController: UIViewController { // 뒤로가기 버튼 @@ -57,6 +60,7 @@ class SettingViewController: UIViewController { textField.layer.borderColor = UIColor.lightGray.cgColor textField.layer.cornerRadius = 5 textField.font = UIFont.systemFont(ofSize: 14) + textField.isUserInteractionEnabled = false return textField }() @@ -69,6 +73,7 @@ class SettingViewController: UIViewController { button.layer.borderWidth = 1 button.layer.borderColor = UIColor.black.cgColor button.layer.cornerRadius = 5 + return button }() @@ -91,6 +96,7 @@ class SettingViewController: UIViewController { textField.layer.borderColor = UIColor.lightGray.cgColor textField.layer.cornerRadius = 5 textField.font = UIFont.systemFont(ofSize: 14) + textField.isUserInteractionEnabled = false return textField }() @@ -105,8 +111,9 @@ class SettingViewController: UIViewController { button.layer.cornerRadius = 5 return button }() - - + //이메일 / 비밀번호 버튼 변경을 위한 플래그 변수 + var isEmailEditing: Bool = false + var isPasswordEditing: Bool = false override func viewDidLoad() { super.viewDidLoad() @@ -131,23 +138,75 @@ class SettingViewController: UIViewController { backButton.addTarget(self, action: #selector(handleBackButtonTapped), for: .touchUpInside) + // 이메일 변경 버튼과 비밀번호 변경 버튼에 액션 추가 changeEmailButton.addTarget(self, action: #selector(handleChangeEmailButtonTapped), for: .touchUpInside) changePasswordButton.addTarget(self, action: #selector(handleChangePasswordButtonTapped), for: .touchUpInside) + + // UserDefaults에서 저장된 이메일과 비밀번호 불러와서 텍스트 필드에 설정 + if let userEmail = UserDefaults.standard.string(forKey: "userEmail") { + emailTextField.text = userEmail + } + if let userPassword = UserDefaults.standard.string(forKey: "userPassword") { + passwordTextField.text = userPassword + } + } // 이메일 변경 버튼 클릭 시 호출되는 메서드 - @objc func handleChangeEmailButtonTapped() { - emailTextField.text = "" // 기존 텍스트 제거 - emailTextField.placeholder = "새로운 이메일을 입력해주세요 !" // 플레이스홀더 변경 - } - - // 비밀번호 변경 버튼 클릭 시 호출되는 메서드 - @objc func handleChangePasswordButtonTapped() { - passwordTextField.text = "" // 기존 텍스트 제거 - passwordTextField.placeholder = "새로운 비밀번호를 입력해주세요!" // 플레이스홀더 변경 - } - + @objc func handleChangeEmailButtonTapped() { + //변경 -> 확인 + changeEmailButton.setTitle("확인", for: .normal) + + // 이메일 텍스트 필드를 편집 가능하도록 설정 + emailTextField.isUserInteractionEnabled = true + emailTextField.becomeFirstResponder() + emailTextField.text = "" // 기존 텍스트 제거 + emailTextField.placeholder = "새로운 이메일을 입력해주세요 !" + + // 확인 버튼이 클릭되었을 때 UserDefaults에 새로운 이메일 저장 + changeEmailButton.removeTarget(self, action: #selector(handleChangeEmailButtonTapped), for: .touchUpInside) + changeEmailButton.addTarget(self, action: #selector(saveNewEmail), for: .touchUpInside) + } + + @objc func saveNewEmail() { + // 이메일을 UserDefaults에 저장하고, 텍스트 필드 편집 불가하도록 변경 + if let newEmail = emailTextField.text, !newEmail.isEmpty { + UserDefaults.standard.set(newEmail, forKey: "userEmail") + emailTextField.isUserInteractionEnabled = false + changeEmailButton.setTitle("변경", for: .normal) // 버튼 텍스트를 다시 "변경"으로 변경 + changeEmailButton.removeTarget(self, action: #selector(saveNewEmail), for: .touchUpInside) + changeEmailButton.addTarget(self, action: #selector(handleChangeEmailButtonTapped), for: .touchUpInside) + } + } + + // 비밀번호 변경 버튼 클릭 시 호출되는 메서드 + @objc func handleChangePasswordButtonTapped() { + //변경 -> 확인 + changePasswordButton.setTitle("확인", for: .normal) + + // 비밀번호 텍스트 필드를 편집 가능하도록 설정 + passwordTextField.isUserInteractionEnabled = true + passwordTextField.becomeFirstResponder() // 텍스트 필드에 포커스 설정 + passwordTextField.text = "" // 기존 텍스트 제거 + passwordTextField.placeholder = "새로운 비밀번호를 입력해주세요!" // 플레이스홀더 변경 + + // 확인 버튼이 클릭되었을 때 UserDefaults에 새로운 비밀번호 저장 + changePasswordButton.removeTarget(self, action: #selector(handleChangePasswordButtonTapped), for: .touchUpInside) + changePasswordButton.addTarget(self, action: #selector(saveNewPassword), for: .touchUpInside) + } + + @objc func saveNewPassword() { + // 비밀번호를 UserDefaults에 저장하고, 텍스트 필드 편집 불가하도록 변경 + if let newPassword = passwordTextField.text, !newPassword.isEmpty { + UserDefaults.standard.set(newPassword, forKey: "userPassword") + passwordTextField.isUserInteractionEnabled = false + changePasswordButton.setTitle("변경", for: .normal) // 버튼 텍스트를 다시 "변경"으로 변경 + changePasswordButton.removeTarget(self, action: #selector(saveNewPassword), for: .touchUpInside) + changePasswordButton.addTarget(self, action: #selector(handleChangePasswordButtonTapped), for: .touchUpInside) + } + } + //뒤로가기 매서드 @objc func handleBackButtonTapped() { navigationController?.popViewController(animated: true) } diff --git a/Kream/ViewControllers/LoginViewController.swift b/Kream/ViewControllers/LoginViewController.swift index de772aa..8dad63b 100644 --- a/Kream/ViewControllers/LoginViewController.swift +++ b/Kream/ViewControllers/LoginViewController.swift @@ -1,10 +1,15 @@ import UIKit +import Alamofire +import KakaoSDKAuth +import KakaoSDKUser +import KeychainAccess class LoginViewController: UIViewController { - let loginView = LoginView() - + let loginViewModel = LoginViewModel() // 뷰모델 인스턴스 생성 + let keychain = Keychain(service: "com.yourapp.kakaoLogin") // Keychain + override func viewDidLoad() { super.viewDidLoad() self.view.backgroundColor = .white @@ -23,13 +28,106 @@ class LoginViewController: UIViewController { // 로그인 버튼에 액션 추가 loginView.loginButton.addTarget(self, action: #selector(handleLoginButtonTapped), for: .touchUpInside) + loginView.kakaoLoginButton.addTarget(self, action: #selector(handleKakaoLoginButtonTapped), for: .touchUpInside) } // 로그인 버튼 클릭 시 호출되는 메서드 @objc func handleLoginButtonTapped() { + // LoginView의 이메일 및 비밀번호 텍스트 필드 값 가져오기 + guard let email = loginView.emailTextField.text, !email.isEmpty, + let password = loginView.passwordTextField.text, !password.isEmpty else { + // 이메일 또는 비밀번호가 비어 있을 경우 경고 메시지 표시 + showAlert(title: "로그인 오류", message: "이메일과 비밀번호를 모두 입력해주세요.") + return + } + + // 로그인 정보를 UserDefaults에 저장 + loginViewModel.saveCredentials(email: email, password: password) + + // 로그인 성공 여부 확인 (임시로 저장된 값과 일치하는지 확인) + if loginViewModel.login(email: email, password: password) { + // 로그인 성공 시 메인 탭 화면으로 전환 + let mainTabBarController = MainTabBarController() + mainTabBarController.modalPresentationStyle = .fullScreen // 전체 화면 모달 설정 + present(mainTabBarController, animated: true, completion: nil) // 모달 전환 + } else { + // 로그인 실패 시 경고 메시지 표시 + showAlert(title: "로그인 실패", message: "이메일 또는 비밀번호가 올바르지 않습니다.") + } + } + + // 카카오 로그인 버튼 클릭 시 호출되는 메서드 + @objc func handleKakaoLoginButtonTapped() { + // 카카오톡 설치 여부에 따라 로그인 진행 방식 결정 + if UserApi.isKakaoTalkLoginAvailable() { + UserApi.shared.loginWithKakaoTalk { (oauthToken, error) in + if let error = error { + print("카카오톡 로그인 에러: \(error.localizedDescription)") + self.showAlert(title: "로그인 오류", message: "카카오톡 로그인 중 오류가 발생했습니다.") + } else { + print("카카오톡 로그인 성공") + if let token = oauthToken?.accessToken { + self.saveTokenToKeychain(token: token) + } + self.fetchUserNickname() + self.navigateToMainTabBarController() + } + } + } else { + UserApi.shared.loginWithKakaoAccount { (oauthToken, error) in + if let error = error { + print("카카오 계정 로그인 에러: \(error.localizedDescription)") + self.showAlert(title: "로그인 오류", message: "카카오 계정 로그인 중 오류가 발생했습니다.") + } else { + print("카카오 계정 로그인 성공") + if let token = oauthToken?.accessToken { + self.saveTokenToKeychain(token: token) + } + self.fetchUserNickname() + self.navigateToMainTabBarController() + } + } + } + } + + // 토큰을 키체인에 저장하는 메서드 + private func saveTokenToKeychain(token: String) { + do { + try keychain.set(token, key: "kakaoAccessToken") + } catch { + print("키체인에 토큰 저장 실패: \(error.localizedDescription)") + } + } + + // 닉네임을 가져와 키체인에 저장하는 메서드 + private func fetchUserNickname() { + UserApi.shared.me { (user, error) in + if let error = error { + print("사용자 정보 요청 실패: \(error.localizedDescription)") + } else { + if let nickname = user?.kakaoAccount?.profile?.nickname { + do { + try self.keychain.set(nickname, key: "kakaoUserNickname") + } catch { + print("키체인에 닉네임 저장 실패: \(error.localizedDescription)") + } + } + } + } + } + + // 메인 탭 화면으로 전환하는 메서드 + private func navigateToMainTabBarController() { let mainTabBarController = MainTabBarController() mainTabBarController.modalPresentationStyle = .fullScreen // 전체 화면 모달 설정 present(mainTabBarController, animated: true, completion: nil) // 모달 전환 } + + // 경고 메시지 표시 메서드 + private func showAlert(title: String, message: String) { + let alert = UIAlertController(title: title, message: message, preferredStyle: .alert) + let okAction = UIAlertAction(title: "확인", style: .default, handler: nil) + alert.addAction(okAction) + present(alert, animated: true, completion: nil) + } } - diff --git a/Kream/ViewControllers/MainViewController.swift b/Kream/ViewControllers/MainViewController.swift index a83e64e..4916ff8 100644 --- a/Kream/ViewControllers/MainViewController.swift +++ b/Kream/ViewControllers/MainViewController.swift @@ -45,8 +45,10 @@ class MainViewController: UIViewController { segmentedControl.addTarget(self, action: #selector(segmentChanged), for: .valueChanged) return segmentedControl }() - // 밑줄 뷰 추가 + // 뭐 챌린지 .. let underlineView = UIHelpers.createSeparatorLine(color: .black, height: 2) + let mainLabel = UIHelpers.createLabel(text: "본격 한파 대비! 연말 필수템 모음", font: .boldSystemFont(ofSize: 16), textColor: .black) + let hashtagLabel = UIHelpers.createLabel(text: "#해피홀리록챌린지", font: .systemFont(ofSize: 14), textColor: .gray) // 메뉴 아이템 데이터 배열 let menuItems = [ @@ -96,6 +98,8 @@ class MainViewController: UIViewController { collectionView.backgroundColor = .white return collectionView }() + //밑에 구분선 하나 더 추가 + let newSeparatorLine = UIHelpers.createSeparatorLine() override func viewDidLoad() { super.viewDidLoad() @@ -122,6 +126,9 @@ class MainViewController: UIViewController { contentView.addSubview(justDroppedTitleLabel) contentView.addSubview(justDroppedSubtitleLabel) contentView.addSubview(justDroppedCollectionView) + contentView.addSubview(newSeparatorLine) + contentView.addSubview(mainLabel) + contentView.addSubview(hashtagLabel) setupCollectionView() setupLayout() @@ -200,14 +207,31 @@ class MainViewController: UIViewController { make.leading.equalTo(justDroppedTitleLabel) } - // Just Dropped 컬렉션 뷰 레이아웃 - justDroppedCollectionView.snp.remakeConstraints { make in - make.top.equalTo(justDroppedSubtitleLabel.snp.bottom).offset(16) - make.leading.trailing.equalToSuperview() - make.height.equalTo(250) - make.bottom.equalToSuperview().offset(-30) - } - + justDroppedCollectionView.snp.makeConstraints { make in + make.top.equalTo(justDroppedSubtitleLabel.snp.bottom).offset(16) + make.leading.trailing.equalToSuperview() + make.height.equalTo(200) + } + + // Just Dropped 섹션 아래 구분선 추가 + newSeparatorLine.snp.makeConstraints { make in + make.top.equalTo(justDroppedCollectionView.snp.bottom).offset(30) + make.leading.trailing.equalToSuperview() + make.height.equalTo(1) + } + + // 본문 레이블 설정 + mainLabel.snp.makeConstraints { make in + make.top.equalTo(newSeparatorLine.snp.bottom).offset(20) + make.leading.equalToSuperview().offset(16) + } + + // 해시태그 레이블 설정 + hashtagLabel.snp.makeConstraints { make in + make.top.equalTo(mainLabel.snp.bottom).offset(4) + make.leading.equalTo(mainLabel) + make.bottom.equalToSuperview().offset(-20) // 전체 콘텐츠 하단 간격 + } } // MARK: - UICollectionView 설정 메서드 @@ -288,6 +312,7 @@ class MainViewController: UIViewController { make.height.equalTo(200) make.bottom.equalToSuperview().offset(-20) } + default: let label = UILabel() label.textAlignment = .center @@ -322,11 +347,9 @@ func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { if collectionView == self.justDroppedCollectionView { - return CGSize(width: 150, height: 230) + return CGSize(width: 150, height: 230) } return CGSize(width: 61, height: 81) } } - - diff --git a/Kream/ViewControllers/MyViewController.swift b/Kream/ViewControllers/MyViewController.swift new file mode 100644 index 0000000..13d5c78 --- /dev/null +++ b/Kream/ViewControllers/MyViewController.swift @@ -0,0 +1,224 @@ +import UIKit +import SnapKit +import KeychainAccess + +protocol ProfileEditDelegate: AnyObject { + // 프로필 이미지가 변경되었을 때 호출될 메서드 + func didUpdateProfileImage(_ image: UIImage) +} + +class MyViewController: UIViewController { + + let settingsButton: UIButton = { + let button = UIButton() + button.setImage(UIImage(systemName: "gearshape"), for: .normal) + button.tintColor = .black + return button + }() + + let cameraButton: UIButton = { + let button = UIButton() + button.setImage(UIImage(systemName: "camera"), for: .normal) + button.tintColor = .black + return button + }() + + let profileImageView: UIImageView = { + let imageView = UIImageView() + imageView.image = UIImage(named: "profile_image") // 프로필 이미지 설정 + imageView.layer.cornerRadius = 45 // 원형 이미지로 만들기 위한 설정 (이미지 크기에 맞춤) + imageView.layer.masksToBounds = true + imageView.contentMode = .scaleAspectFill + return imageView + }() + + let usernameLabel: UILabel = { + let label = UILabel() + label.text = "Jeong_iOS" + label.font = UIFont.systemFont(ofSize: 16, weight: .bold) + label.textAlignment = .left // 왼쪽 정렬로 설정 + return label + }() + + let followersLabel: UILabel = { + let label = UILabel() + label.text = "팔로워 326 팔로잉 20" + label.font = UIFont.systemFont(ofSize: 14) + label.textColor = .black + label.textAlignment = .left // 왼쪽 정렬로 설정 + return label + }() + + // 사용자 이름과 팔로워/팔로잉 레이블을 수직으로 정렬할 StackView + let nameAndFollowersStackView: UIStackView = { + let stackView = UIStackView() + stackView.axis = .vertical + stackView.alignment = .leading + stackView.spacing = 4 + return stackView + }() + + + let profileInfoStackView: UIStackView = { + let stackView = UIStackView() + stackView.axis = .horizontal + stackView.alignment = .center + stackView.spacing = 16 + return stackView + }() + + let profileEditButton: UIButton = { + let button = UIButton() + button.setTitle("프로필 관리", for: .normal) + button.setTitleColor(.black, for: .normal) + button.layer.borderWidth = 1 + button.layer.borderColor = UIColor.gray.cgColor + button.titleLabel?.font = UIFont.systemFont(ofSize: 9, weight: .light) + button.layer.cornerRadius = 10 + return button + }() + + let profileShareButton: UIButton = { + let button = UIButton() + button.setTitle("프로필 공유", for: .normal) + button.setTitleColor(.black, for: .normal) + button.layer.borderWidth = 1 + button.layer.borderColor = UIColor.lightGray.cgColor + button.titleLabel?.font = UIFont.systemFont(ofSize: 9, weight: .light) + button.layer.cornerRadius = 10 + return button + }() + + // 하단의 빈 뷰 (구분선 대신 사용) + let bottomSpacingView: UIView = { + let view = UIView() + view.backgroundColor = .systemGray6 + return view + }() + + let keychain = Keychain(service: "com.yourapp.kakaoLogin") // Keychain 인스턴스 생성 + + override func viewDidLoad() { + super.viewDidLoad() + + view.backgroundColor = .white + + //네비게이션 타이틀 바 숨기기 + navigationItem.title = nil + navigationController?.setNavigationBarHidden(true, animated: false) + + + view.addSubview(settingsButton) + view.addSubview(cameraButton) + view.addSubview(profileInfoStackView) + view.addSubview(profileEditButton) + view.addSubview(profileShareButton) + view.addSubview(bottomSpacingView) + + + nameAndFollowersStackView.addArrangedSubview(usernameLabel) + nameAndFollowersStackView.addArrangedSubview(followersLabel) + + profileInfoStackView.addArrangedSubview(profileImageView) + profileInfoStackView.addArrangedSubview(nameAndFollowersStackView) + + //레이아웃설정 + setupLayout() + + //설정버튼 + settingsButton.addTarget(self, action: #selector(handleSettingsButtonTapped), for: .touchUpInside) + //프로필 관리 버튼 + profileEditButton.addTarget(self, action: #selector(handleProfileEditButtonTapped), for: .touchUpInside) + // UserDefaults에서 저장된 프로필 이미지 불러오기 + if let savedProfileImage = UserDefaults.standard.image(forKey: "profileImage") { + profileImageView.image = savedProfileImage + } else { + // 기본 프로필 이미지 설정 + profileImageView.image = UIImage(named: "profile_image") + } + + // UserDefaults에서 저장된 이메일 불러오기 + if let savedEmail = UserDefaults.standard.string(forKey: "userEmail") { + usernameLabel.text = savedEmail // usernameLabel에 저장된 이메일 출력 + } + + // Keychain에서 저장된 카카오 닉네임 불러오기 + if let kakaoNickname = try? keychain.get("kakaoUserNickname") { + usernameLabel.text = kakaoNickname + } + } + + //설정버튼 + @objc func handleSettingsButtonTapped() { + let settingVC = SettingViewController() + + + navigationController?.pushViewController(settingVC, animated: true) + } + //프로필 관리 버튼 액션 + @objc func handleProfileEditButtonTapped() { + let profileEditVC = SettingViewController() // SettingViewController로 이동하도록 설정 + navigationController?.pushViewController(profileEditVC, animated: true) + } + + + //레이아웃 설정 + func setupLayout() { + + settingsButton.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide).offset(16) + make.leading.equalToSuperview().offset(16) + make.width.equalTo(25) + make.height.equalTo(25) + } + + + cameraButton.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide).offset(16) + make.trailing.equalToSuperview().offset(-16) + make.width.height.equalTo(25) + } + + // 프로필 정보 StackView + profileInfoStackView.snp.makeConstraints { make in + make.top.equalTo(settingsButton.snp.bottom).offset(20) + make.leading.equalToSuperview().offset(30) // 왼쪽 여백 설정 + } + + // 프로필 + profileImageView.snp.makeConstraints { make in + make.width.height.equalTo(90) // 원형 이미지로 설정 + } + + // 프로필 관리 버튼 + profileEditButton.snp.makeConstraints { make in + make.top.equalTo(profileInfoStackView.snp.bottom).offset(20) + make.leading.equalToSuperview().offset(40) + make.trailing.equalTo(view.snp.centerX).offset(-10) + make.height.equalTo(26) + } + + // 프로필 공유 버튼 + profileShareButton.snp.makeConstraints { make in + make.top.equalTo(profileInfoStackView.snp.bottom).offset(20) + make.leading.equalTo(view.snp.centerX).offset(10) + make.trailing.equalToSuperview().offset(-40) + make.height.equalTo(26) + } + + // 하단 빈 뷰 (구분선 대체) 레이아웃 설정 + bottomSpacingView.snp.makeConstraints { make in + make.top.equalTo(profileEditButton.snp.bottom).offset(20) + make.leading.trailing.equalToSuperview() + make.height.equalTo(20) // 빈 뷰 높이 설정 + } + } +} +// MARK: - SettingViewController의 Delegate 메서드 구현 +extension MyViewController: ProfileEditDelegate { + func didUpdateProfileImage(_ image: UIImage) { + profileImageView.image = image + UserDefaults.standard.setImage(image, forKey: "profileImage") // 변경된 이미지를 UserDefaults에 저장 + } +} + diff --git a/Kream/ViewControllers/ProductDetailViewController.swift b/Kream/ViewControllers/ProductDetailViewController.swift new file mode 100644 index 0000000..ef09bfe --- /dev/null +++ b/Kream/ViewControllers/ProductDetailViewController.swift @@ -0,0 +1,243 @@ +import UIKit +import SnapKit + +class ProductDetailViewController: UIViewController { + + let backButton: UIButton = { + let button = UIButton(type: .system) + button.setImage(UIImage(systemName: "chevron.left"), for: .normal) + button.tintColor = .black + button.addTarget(self, action: #selector(backButtonTapped), for: .touchUpInside) + return button + }() + + let productImageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFit + imageView.image = UIImage(named: "matinKim") + imageView.layer.cornerRadius = 16 + imageView.clipsToBounds = true // 둥근 모서리 적용을 위해 추가 + return imageView + }() + + let colorCollectionView: UICollectionView = { + let layout = UICollectionViewFlowLayout() + layout.scrollDirection = .horizontal + layout.minimumLineSpacing = 8 + layout.itemSize = CGSize(width: 60, height: 60) + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: layout) + collectionView.backgroundColor = .clear + return collectionView + }() + + let priceLabel: UILabel = { + let label = UILabel() + label.text = "즉시 구매가" + label.font = UIFont.systemFont(ofSize: 12) + label.textColor = .gray + return label + }() + let priceLabel2: UILabel = { + let label = UILabel() + label.text = "228,000원" + label.font = UIFont.boldSystemFont(ofSize: 18) + label.textColor = .black + return label + }() + + let productTitleLabel: UILabel = { + let label = UILabel() + label.text = "Matin Kim Logo Coating Jumper" + label.font = UIFont.boldSystemFont(ofSize: 16) + label.textColor = .black + return label + }() + + let productSubtitleLabel: UILabel = { + let label = UILabel() + label.text = "마틴킴 로고 코팅 점퍼 블랙" + label.font = UIFont.systemFont(ofSize: 14) + label.textColor = .gray + return label + }() + let bookmarkButton: UIButton = { + var configuration = UIButton.Configuration.plain() + configuration.image = UIImage(systemName: "bookmark") + configuration.baseForegroundColor = .black + + let button = UIButton(configuration: configuration) + button.addTarget(self, action: #selector(bookmarkButtonTapped), for: .touchUpInside) + + // 클릭 시 하이라이트 효과 제거 + button.configurationUpdateHandler = { button in + var config = button.configuration + if button.isHighlighted { + config?.baseBackgroundColor = .clear // 하이라이트 시에도 배경색 변경 없이 유지 + button.alpha = 1.0 // 알파값 조정으로 시각적인 효과 제거 + } + button.configuration = config + } + + return button + }() + + + + + + let separatorLine: UIView = { + let view = UIView() + view.backgroundColor = .systemGray6 + return view + }() + + let purchaseButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle("구매", for: .normal) + button.backgroundColor = UIColor(red: 0xEF / 255.0, green: 0x62 / 255.0, blue: 0x54 / 255.0, alpha: 1.0) + button.setTitleColor(.white, for: .normal) + button.layer.cornerRadius = 8 + button.addTarget(self, action: #selector(purchaseButtonTapped), for: .touchUpInside) + return button + }() + + let sellButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle("판매", for: .normal) + button.backgroundColor = UIColor(red: 0x41 / 255.0, green: 0xB9 / 255.0, blue: 0x7A / 255.0, alpha: 1.0) + button.setTitleColor(.white, for: .normal) + button.layer.cornerRadius = 8 + return button + }() + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .white + + setupNavigationBar() + setupUI() + setupConstraints() + } + + func setupNavigationBar() { + // 뒤로가기 버튼 설정 + let backButton = UIBarButtonItem(image: UIImage(systemName: "arrow.backward"), + style: .plain, + target: self, + action: #selector(backButtonTapped)) + backButton.tintColor = .black // 버튼 색상 설정 + navigationItem.leftBarButtonItem = backButton + } + + func setupUI() { + view.addSubview(productImageView) + view.addSubview(colorCollectionView) + view.addSubview(priceLabel) + view.addSubview(priceLabel2) + view.addSubview(productTitleLabel) + view.addSubview(productSubtitleLabel) + view.addSubview(separatorLine) + view.addSubview(bookmarkButton) + view.addSubview(purchaseButton) + view.addSubview(sellButton) + + colorCollectionView.delegate = self + colorCollectionView.dataSource = self + colorCollectionView.register(ColorCollectionViewCell.self, forCellWithReuseIdentifier: "ColorCell") + } + + func setupConstraints() { + productImageView.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide).offset(16) + make.leading.trailing.equalToSuperview().inset(16) + make.height.equalTo(374) + } + + colorCollectionView.snp.makeConstraints { make in + make.top.equalTo(productImageView.snp.bottom).offset(16) + make.leading.trailing.equalToSuperview().inset(16) + make.height.equalTo(60) + } + + priceLabel.snp.makeConstraints { make in + make.top.equalTo(colorCollectionView.snp.bottom).offset(23) + make.leading.equalToSuperview().offset(16) + } + priceLabel2.snp.makeConstraints { make in + make.bottom.equalTo(priceLabel.snp.bottom).offset(4) + make.leading.equalToSuperview().offset(16) + } + + + productTitleLabel.snp.makeConstraints { make in + make.top.equalTo(priceLabel2.snp.bottom).offset(18) + make.leading.equalToSuperview().offset(16) + } + + productSubtitleLabel.snp.makeConstraints { make in + make.top.equalTo(productTitleLabel.snp.bottom).offset(2) + make.leading.equalToSuperview().offset(16) + } + + separatorLine.snp.makeConstraints { make in + make.top.equalTo(productSubtitleLabel.snp.bottom).offset(54) + make.leading.trailing.equalToSuperview().inset(16) + make.height.equalTo(1) + } + + bookmarkButton.snp.makeConstraints { make in + make.top.equalTo(separatorLine.snp.bottom).offset(16) + make.leading.equalToSuperview().offset(16) + make.bottom.equalTo(view.safeAreaLayoutGuide).offset(-16) + make.width.height.equalTo(40) + } + + purchaseButton.snp.makeConstraints { make in + make.centerY.equalTo(bookmarkButton.snp.centerY) + make.leading.equalTo(bookmarkButton.snp.trailing).offset(16) + make.height.equalTo(49) + make.width.equalTo(147) + } + + sellButton.snp.makeConstraints { make in + make.centerY.equalTo(purchaseButton.snp.centerY) + make.leading.equalTo(purchaseButton.snp.trailing).offset(16) + make.height.equalTo(49) + make.width.equalTo(147) + } + } + + @objc func backButtonTapped() { + navigationController?.popViewController(animated: true) + } + + @objc func purchaseButtonTapped() { + let purchaseSheet = PurchaseSheetViewController() + purchaseSheet.modalPresentationStyle = .pageSheet + present(purchaseSheet, animated: true, completion: nil) + } + + @objc func bookmarkButtonTapped() { + bookmarkButton.isSelected.toggle() + let imageName = bookmarkButton.isSelected ? "bookmark.fill" : "bookmark" + bookmarkButton.setImage(UIImage(systemName: imageName), for: .normal) + bookmarkButton.tintColor = .black // 버튼 색상은 검정색으로 설정 + } +} + +// MARK: - UICollectionViewDelegate, UICollectionViewDataSource +extension ProductDetailViewController: UICollectionViewDelegate, UICollectionViewDataSource { + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + return 6 // 이미지 수에 맞춰 수정 + } + + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { + guard let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "ColorCell", for: indexPath) as? ColorCollectionViewCell else { + fatalError("Could not dequeue ColorCollectionViewCell") + } + // 반복문을 이용하여 이미지 설정 + let imageName = "color_\(indexPath.item + 1)" + cell.configure(with: UIImage(named: imageName)) + return cell + } +} diff --git a/Kream/ViewControllers/PurchaseSheetViewController.swift b/Kream/ViewControllers/PurchaseSheetViewController.swift new file mode 100644 index 0000000..576e66c --- /dev/null +++ b/Kream/ViewControllers/PurchaseSheetViewController.swift @@ -0,0 +1,174 @@ +import UIKit +import SnapKit + +class PurchaseSheetViewController: UIViewController { + + let closeButton: UIButton = { + let button = UIButton(type: .system) + button.setTitle("X", for: .normal) + button.tintColor = .black + button.addTarget(self, action: #selector(closeSheet), for: .touchUpInside) + return button + }() + + let productImageView: UIImageView = { + let imageView = UIImageView() + imageView.contentMode = .scaleAspectFit + imageView.image = UIImage(named: "matinKim") + imageView.layer.cornerRadius = 8 + imageView.clipsToBounds = true + return imageView + }() + + let productTitleLabel: UILabel = { + let label = UILabel() + label.text = "Matin Kim Logo Coating Jumper" + label.font = UIFont.boldSystemFont(ofSize: 16) + label.textColor = .black + return label + }() + + let productSubtitleLabel: UILabel = { + let label = UILabel() + label.text = "마틴킴 로고 코팅 점퍼 블랙" + label.font = UIFont.systemFont(ofSize: 14) + label.textColor = .gray + return label + }() + + var sizeButtons: [UIButton] = [] + let sizes = ["S", "M", "L", "XL", "XXL"] + + override func viewDidLoad() { + super.viewDidLoad() + view.backgroundColor = .white + setupUI() + } + + func setupUI() { + view.addSubview(closeButton) + view.addSubview(productImageView) + view.addSubview(productTitleLabel) + view.addSubview(productSubtitleLabel) + + let titleLabel = UILabel() + titleLabel.text = "구매하기" + titleLabel.font = UIFont.boldSystemFont(ofSize: 18) + + let subtitleLabel = UILabel() + subtitleLabel.text = "(가격 단위: 원)" + subtitleLabel.font = UIFont.systemFont(ofSize: 14) + subtitleLabel.textColor = .gray + + view.addSubview(titleLabel) + view.addSubview(subtitleLabel) + + closeButton.snp.makeConstraints { make in + make.top.equalTo(view.safeAreaLayoutGuide).offset(16) + make.trailing.equalToSuperview().inset(16) + } + titleLabel.snp.makeConstraints { make in + make.top.equalTo(closeButton.snp.top) + make.centerX.equalToSuperview() + } + + subtitleLabel.snp.makeConstraints { make in + make.top.equalTo(titleLabel.snp.bottom).offset(4) + make.centerX.equalToSuperview() + } + + productImageView.snp.makeConstraints { make in + make.top.equalTo(subtitleLabel.snp.bottom).offset(16) + make.leading.equalToSuperview().offset(16) + make.width.height.equalTo(91) + } + + productTitleLabel.snp.makeConstraints { make in + make.top.equalTo(subtitleLabel.snp.bottom).offset(29) + make.leading.equalTo(productImageView.snp.trailing).offset(15) + make.trailing.equalToSuperview().inset(16) + } + + productSubtitleLabel.snp.makeConstraints { make in + make.top.equalTo(productTitleLabel.snp.bottom).offset(4) + make.leading.equalTo(productTitleLabel.snp.leading) + make.trailing.equalTo(productTitleLabel.snp.trailing) + } + + // 사이즈 버튼 생성 및 추가 + createSizeButtons() + } + + func createSizeButtons() { + let buttonContainerView = UIView() + var lastButton: UIButton? = nil + var rowCounter = 0 + + for size in sizes { + let button = UIButton(type: .system) + button.setTitle(size, for: .normal) + button.setTitleColor(.black, for: .normal) + button.layer.borderWidth = 1 + button.layer.borderColor = UIColor.lightGray.cgColor + button.layer.cornerRadius = 8 + button.backgroundColor = .white // 기본 배경색 + + button.snp.makeConstraints { make in + make.width.equalTo(110) + make.height.equalTo(47) + } + + + sizeButtons.append(button) + buttonContainerView.addSubview(button) + + button.snp.makeConstraints { make in + if let lastButton = lastButton { + if rowCounter < 3 { + // 같은 줄에 배치 + make.leading.equalTo(lastButton.snp.trailing).offset(8) + make.top.equalTo(lastButton.snp.top) + rowCounter += 1 + } else { + // 새 줄에 배치 + make.top.equalTo(lastButton.snp.bottom).offset(8) + make.leading.equalToSuperview() + rowCounter = 0 + } + } else { + // 첫 번째 버튼 배치 + make.top.leading.equalToSuperview() + rowCounter += 1 + } + } + + + lastButton = button + } + + view.addSubview(buttonContainerView) + buttonContainerView.snp.makeConstraints { make in + make.top.equalTo(productImageView.snp.bottom).offset(16) + make.leading.trailing.equalToSuperview().inset(16) + } + + } + + @objc func closeSheet() { + dismiss(animated: true, completion: nil) + } + @objc func sizeButtonTapped(_ sender: UIButton) { + // 모든 버튼을 초기 상태로 되돌림 + sizeButtons.forEach { button in + button.layer.borderWidth = 1 + button.layer.borderColor = UIColor.lightGray.cgColor + button.backgroundColor = .white + } + + // 선택된 버튼을 강조 + sender.layer.borderWidth = 2 + sender.layer.borderColor = UIColor.black.cgColor + } + +} +