Merge pull request 'main' (#8) from seonkyu.kim/AcaMate_iOS:main into main

Reviewed-on: https://git.ipstein.myds.me/AcaMate/AcaMate_iOS/pulls/8
This commit is contained in:
김선규 2025-02-04 15:46:53 +00:00
commit eef7d01d8c
106 changed files with 1347 additions and 200 deletions

3
.gitignore vendored
View File

@ -1,7 +1,8 @@
# 특정 환경에 따라 추가 # 특정 환경에 따라 추가
./private/ ./private/
# 인텔리제이꺼
*.idea
# Xcode 관련 # Xcode 관련
# 사용자별 설정 파일 # 사용자별 설정 파일

View File

@ -7,6 +7,9 @@
objects = { objects = {
/* Begin PBXBuildFile section */ /* Begin PBXBuildFile section */
A73892212D526A9D00659A62 /* FirebaseAnalytics in Frameworks */ = {isa = PBXBuildFile; productRef = A73892202D526A9D00659A62 /* FirebaseAnalytics */; };
A73892232D526A9D00659A62 /* FirebaseAppCheck in Frameworks */ = {isa = PBXBuildFile; productRef = A73892222D526A9D00659A62 /* FirebaseAppCheck */; };
A73892252D526A9D00659A62 /* FirebaseCrashlytics in Frameworks */ = {isa = PBXBuildFile; productRef = A73892242D526A9D00659A62 /* FirebaseCrashlytics */; };
A771FFF22CFB70D100367DA6 /* KakaoSDK in Frameworks */ = {isa = PBXBuildFile; productRef = A771FFF12CFB70D100367DA6 /* KakaoSDK */; }; A771FFF22CFB70D100367DA6 /* KakaoSDK in Frameworks */ = {isa = PBXBuildFile; productRef = A771FFF12CFB70D100367DA6 /* KakaoSDK */; };
A78774722CF586AF002FE2EE /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = A78774712CF586AF002FE2EE /* Alamofire */; }; A78774722CF586AF002FE2EE /* Alamofire in Frameworks */ = {isa = PBXBuildFile; productRef = A78774712CF586AF002FE2EE /* Alamofire */; };
A7A518CF2CF555E200822D0D /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = A7A518CE2CF555E200822D0D /* README.md */; }; A7A518CF2CF555E200822D0D /* README.md in Resources */ = {isa = PBXBuildFile; fileRef = A7A518CE2CF555E200822D0D /* README.md */; };
@ -45,8 +48,11 @@
isa = PBXFrameworksBuildPhase; isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
A73892232D526A9D00659A62 /* FirebaseAppCheck in Frameworks */,
A78774722CF586AF002FE2EE /* Alamofire in Frameworks */, A78774722CF586AF002FE2EE /* Alamofire in Frameworks */,
A73892252D526A9D00659A62 /* FirebaseCrashlytics in Frameworks */,
A771FFF22CFB70D100367DA6 /* KakaoSDK in Frameworks */, A771FFF22CFB70D100367DA6 /* KakaoSDK in Frameworks */,
A73892212D526A9D00659A62 /* FirebaseAnalytics in Frameworks */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
@ -93,6 +99,9 @@
packageProductDependencies = ( packageProductDependencies = (
A78774712CF586AF002FE2EE /* Alamofire */, A78774712CF586AF002FE2EE /* Alamofire */,
A771FFF12CFB70D100367DA6 /* KakaoSDK */, A771FFF12CFB70D100367DA6 /* KakaoSDK */,
A73892202D526A9D00659A62 /* FirebaseAnalytics */,
A73892222D526A9D00659A62 /* FirebaseAppCheck */,
A73892242D526A9D00659A62 /* FirebaseCrashlytics */,
); );
productName = AcaMate; productName = AcaMate;
productReference = A7A518BB2CF5558B00822D0D /* AcaMate.app */; productReference = A7A518BB2CF5558B00822D0D /* AcaMate.app */;
@ -125,6 +134,7 @@
packageReferences = ( packageReferences = (
A78774702CF586AF002FE2EE /* XCRemoteSwiftPackageReference "Alamofire" */, A78774702CF586AF002FE2EE /* XCRemoteSwiftPackageReference "Alamofire" */,
A771FFF02CFB70D100367DA6 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */, A771FFF02CFB70D100367DA6 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */,
A738921F2D526A9D00659A62 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */,
); );
preferredProjectObjectVersion = 77; preferredProjectObjectVersion = 77;
productRefGroup = A7A518BC2CF5558B00822D0D /* Products */; productRefGroup = A7A518BC2CF5558B00822D0D /* Products */;
@ -378,6 +388,14 @@
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */ /* Begin XCRemoteSwiftPackageReference section */
A738921F2D526A9D00659A62 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/firebase/firebase-ios-sdk";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 11.8.0;
};
};
A771FFF02CFB70D100367DA6 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */ = { A771FFF02CFB70D100367DA6 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */ = {
isa = XCRemoteSwiftPackageReference; isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/kakao/kakao-ios-sdk"; repositoryURL = "https://github.com/kakao/kakao-ios-sdk";
@ -397,6 +415,21 @@
/* End XCRemoteSwiftPackageReference section */ /* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */ /* Begin XCSwiftPackageProductDependency section */
A73892202D526A9D00659A62 /* FirebaseAnalytics */ = {
isa = XCSwiftPackageProductDependency;
package = A738921F2D526A9D00659A62 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
productName = FirebaseAnalytics;
};
A73892222D526A9D00659A62 /* FirebaseAppCheck */ = {
isa = XCSwiftPackageProductDependency;
package = A738921F2D526A9D00659A62 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
productName = FirebaseAppCheck;
};
A73892242D526A9D00659A62 /* FirebaseCrashlytics */ = {
isa = XCSwiftPackageProductDependency;
package = A738921F2D526A9D00659A62 /* XCRemoteSwiftPackageReference "firebase-ios-sdk" */;
productName = FirebaseCrashlytics;
};
A771FFF12CFB70D100367DA6 /* KakaoSDK */ = { A771FFF12CFB70D100367DA6 /* KakaoSDK */ = {
isa = XCSwiftPackageProductDependency; isa = XCSwiftPackageProductDependency;
package = A771FFF02CFB70D100367DA6 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */; package = A771FFF02CFB70D100367DA6 /* XCRemoteSwiftPackageReference "kakao-ios-sdk" */;

View File

@ -1,6 +1,15 @@
{ {
"originHash" : "48d44fe9560aaa48bc97ae34cdb596f62fa2d739be3dafd4261b95db8f8c86ab", "originHash" : "3b609245b8d633048f6670834279f82d0601cc0879a2d8c9c86fa0dd25734ea3",
"pins" : [ "pins" : [
{
"identity" : "abseil-cpp-binary",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/abseil-cpp-binary.git",
"state" : {
"revision" : "194a6706acbd25e4ef639bcaddea16e8758a3e27",
"version" : "1.2024011602.0"
}
},
{ {
"identity" : "alamofire", "identity" : "alamofire",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
@ -10,6 +19,78 @@
"version" : "5.10.2" "version" : "5.10.2"
} }
}, },
{
"identity" : "app-check",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/app-check.git",
"state" : {
"revision" : "61b85103a1aeed8218f17c794687781505fbbef5",
"version" : "11.2.0"
}
},
{
"identity" : "firebase-ios-sdk",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/firebase-ios-sdk",
"state" : {
"revision" : "075679d6b25b28f4cb167f1d7769b58fb556fb30",
"version" : "11.8.0"
}
},
{
"identity" : "googleappmeasurement",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleAppMeasurement.git",
"state" : {
"revision" : "be0881ff728eca210ccb628092af400c086abda3",
"version" : "11.7.0"
}
},
{
"identity" : "googledatatransport",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleDataTransport.git",
"state" : {
"revision" : "617af071af9aa1d6a091d59a202910ac482128f9",
"version" : "10.1.0"
}
},
{
"identity" : "googleutilities",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleUtilities.git",
"state" : {
"revision" : "53156c7ec267db846e6b64c9f4c4e31ba4cf75eb",
"version" : "8.0.2"
}
},
{
"identity" : "grpc-binary",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/grpc-binary.git",
"state" : {
"revision" : "f56d8fc3162de9a498377c7b6cea43431f4f5083",
"version" : "1.65.1"
}
},
{
"identity" : "gtm-session-fetcher",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/gtm-session-fetcher.git",
"state" : {
"revision" : "3cdb78efb79b4a5383c3911488d8025bfc545b5e",
"version" : "4.3.0"
}
},
{
"identity" : "interop-ios-for-google-sdks",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/interop-ios-for-google-sdks.git",
"state" : {
"revision" : "2d12673670417654f08f5f90fdd62926dc3a2648",
"version" : "100.0.0"
}
},
{ {
"identity" : "kakao-ios-sdk", "identity" : "kakao-ios-sdk",
"kind" : "remoteSourceControl", "kind" : "remoteSourceControl",
@ -18,6 +99,42 @@
"branch" : "master", "branch" : "master",
"revision" : "ab4309c1950550add307046ad1e08024c7514603" "revision" : "ab4309c1950550add307046ad1e08024c7514603"
} }
},
{
"identity" : "leveldb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/leveldb.git",
"state" : {
"revision" : "a0bc79961d7be727d258d33d5a6b2f1023270ba1",
"version" : "1.22.5"
}
},
{
"identity" : "nanopb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/nanopb.git",
"state" : {
"revision" : "b7e1104502eca3a213b46303391ca4d3bc8ddec1",
"version" : "2.30910.0"
}
},
{
"identity" : "promises",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/promises.git",
"state" : {
"revision" : "540318ecedd63d883069ae7f1ed811a2df00b6ac",
"version" : "2.4.0"
}
},
{
"identity" : "swift-protobuf",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-protobuf.git",
"state" : {
"revision" : "ebc7251dd5b37f627c93698e4374084d98409633",
"version" : "1.28.2"
}
} }
], ],
"version" : 3 "version" : 3

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid = "800DD51A-C089-4DC4-AE55-7F5ABD5C0AE7"
type = "1"
version = "2.0">
</Bucket>

View File

@ -12,10 +12,11 @@ import UserNotifications
import KakaoSDKCommon import KakaoSDKCommon
import KakaoSDKAuth import KakaoSDKAuth
import FirebaseCore
class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDelegate { class AppDelegate: NSObject, UIApplicationDelegate {
@ -28,6 +29,7 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
} }
//MARK: - Set Notification //MARK: - Set Notification
let center = UNUserNotificationCenter.current() let center = UNUserNotificationCenter.current()
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound] let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
center.requestAuthorization(options: authOptions) { granted, error in center.requestAuthorization(options: authOptions) { granted, error in
@ -47,6 +49,9 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
//MARK: - //MARK: -
_ = NetworkMonitor.shared _ = NetworkMonitor.shared
//MARK: - FIREBASE
FirebaseApp.configure()
printLog("End Set AppDelegate") printLog("End Set AppDelegate")
return true return true
} }
@ -60,6 +65,12 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
} }
}
extension AppDelegate: UNUserNotificationCenterDelegate {
//
func registerForRemoteNotifications() { func registerForRemoteNotifications() {
UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound, .badge]) { granted, error in
print("Permission granted: \(granted)") print("Permission granted: \(granted)")
@ -86,7 +97,7 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
printLog("APNs 등록 실패: \(error)") printLog("APNs 등록 실패: \(error)")
} }
// ( ) //
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions { func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions {
let userInfo = notification.request.content.userInfo let userInfo = notification.request.content.userInfo
@ -107,7 +118,7 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
} }
} }
// Notification // Noti ( )
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) { func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse, withCompletionHandler completionHandler: @escaping () -> Void) {
let userInfo = response.notification.request.content.userInfo let userInfo = response.notification.request.content.userInfo
if let apsData = userInfo["aps"] as? [AnyHashable: Any] { if let apsData = userInfo["aps"] as? [AnyHashable: Any] {
@ -117,9 +128,7 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
if let param = alert["parameter"] { if let param = alert["parameter"] {
printLog(param as? String) printLog(param as? String)
} }
// viewModel.setBadge()
} }
} }
} }
} }

View File

@ -6,7 +6,10 @@
// //
import SwiftUI import SwiftUI
// MARK: - ACAMATE // MARK: - ACAMATE
#if DEV // APPSTORE_URL : https://apps.apple.com/us/app/%EC%95%84%EC%B9%B4%EB%8D%B0%EB%AF%B8%EB%A9%94%EC%9D%B4%ED%8A%B8/id6739448113
#if DEV && LOCAL
public let API_URL: String = "http://localhost:5144"
#elseif DEV
public let API_URL: String = "https://devacamate.ipstein.myds.me" public let API_URL: String = "https://devacamate.ipstein.myds.me"
#else #else
public let API_URL: String = "https://acamate.ipstein.myds.me" public let API_URL: String = "https://acamate.ipstein.myds.me"
@ -122,6 +125,19 @@ public func jsonToDict(_ input: String) -> [String: Any] {
return [:] return [:]
} }
/// JSON Swift .
public func jsonToSwift<T: Decodable>(_ input: String) -> T? {
if let data = input.data(using: .utf8) {
do {
let jsonObject = try JSONDecoder().decode(T.self, from: data)
return jsonObject
} catch let error {
printLog("JSON ERROR: \(error))")
}
}
return nil
}
func versionChange(ver: String) -> [Int] { func versionChange(ver: String) -> [Int] {
return ver.components(separatedBy: ["."]).map {Int($0) ?? 0} return ver.components(separatedBy: ["."]).map {Int($0) ?? 0}
} }

View File

@ -1,57 +0,0 @@
//
// LoginView.swift
// AcaMate
//
// Created by Sean Kim on 12/1/24.
//
import SwiftUI
struct LoginView: View {
@EnvironmentObject var alertController: AlertController
@Binding var naviState : NaviState
var body: some View {
VStack(spacing: 0) {
Image("Team_Icon")
.resizable()
.frame(width: 200, height: 200)
.background(.white)
.border(.black)
.padding(.bottom, 84)
Button {
} label: {
HStack(spacing: 12) {
Image("Kakao_Icon")
.resizable()
.frame(width: 32, height: 32)
Text("카카오 계정으로 시작하기")
.font(.nps(font: .regular, size: 16))
.foregroundStyle(Color(.Text.black))
}
.padding(12)
.background {
RoundedRectangle(cornerRadius: 12)
.foregroundStyle(Color(.Other.yellow))
}
}
Button {
alertController.alertData = SetAlertData().setTest()
alertController.showAlert.toggle()
// naviState.set(act: .MOVE,path: .Intro)
} label: {
Text("111111111")
}
.padding()
}
.fullView(.Normal.normal)
}
}
//#Preview {
// LoginView()
//}

View File

@ -9,8 +9,10 @@ import SwiftUI
import Combine import Combine
///
struct NavigationView: View { struct NavigationView: View {
@EnvironmentObject var appVM: AppViewModel
@State private var naviState : NaviState = .init(act: .NONE, path: .Intro) @State private var naviState : NaviState = .init(act: .NONE, path: .Intro)
@State private var history: [PathName] = [.Intro] @State private var history: [PathName] = [.Intro]
@ -25,7 +27,7 @@ struct NavigationView: View {
case .Login : case .Login :
LoginView(naviState: $naviState) LoginView(naviState: $naviState)
case .Main: case .Main:
EmptyView() MainView(naviState: $naviState)
} }
} }
.onChange(of: naviState) { old, new in .onChange(of: naviState) { old, new in
@ -41,30 +43,37 @@ struct NavigationView: View {
case .MOVE: case .MOVE:
moveHistory(path: new.path) moveHistory(path: new.path)
} }
// LOG // LOG
printLog("\(old.path) => \(new.path)") printLog("\(old.path) => \(new.path)")
showHistory() showHistory()
} }
.fullView(.Normal.normal) .onTapGesture {
endTextEditing()
}
.fullDrawView(.Normal.normal)
.setAlert() .setAlert()
.setNetwork() .setNetwork()
.loadingView(isLoading: $appVM.isLoading)
} }
///
private func addHistory(path: PathName) { private func addHistory(path: PathName) {
history.append(path) history.append(path)
} }
///
private func popHistory() { private func popHistory() {
history.removeLast() history.removeLast()
naviState.set(act: .NONE, path: history.last ?? .NONE) naviState.set(act: .NONE, path: history.last ?? .NONE)
} }
///
private func resetHistory(path: PathName) { private func resetHistory(path: PathName) {
history.removeAll() history.removeAll()
addHistory(path: path) addHistory(path: path)
} }
/// ,
private func moveHistory(path: PathName) { private func moveHistory(path: PathName) {
if path == .NONE { if path == .NONE {
naviState.set(act: .RESET, path: history.first ?? .Main) naviState.set(act: .RESET, path: history.first ?? .Main)

View File

@ -0,0 +1,117 @@
//
// AccountLoginView.swift
// AcaMate
//
// Created by Sean Kim on 12/14/24.
//
import SwiftUI
struct AccountLoginView: View {
@ObservedObject var viewModel: LoginViewModel
@Binding var userId: String
@Binding var password: String
@Binding var isSecure: Bool
@Binding var isSave: Bool
var body: some View {
VStack(spacing: 0) {
ZStack(alignment: .leading) {
if userId.isEmpty {
Text("아이디를 입력하세요.")
.font(.nps(font: .regular, size: 16))
.foregroundStyle(Color(.Text.border))
.padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 24))
}
CustomTextField(placeholder: "", text: $userId)
.frame(maxWidth: .infinity,maxHeight: 24)
.padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 24))
}
.background {
RoundedRectangle(cornerRadius: 24)
.foregroundStyle(.white)
}
.padding(EdgeInsets(top: 0, leading: 12, bottom: 8, trailing: 12))
ZStack(alignment: .leading) {
if password.isEmpty {
Text("비밀번호를 입력하세요.")
.font(.nps(font: .regular, size: 16))
.foregroundStyle(Color(.Text.border))
.padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 24))
}
CustomTextField(placeholder: "", text: $password, isSecure: $isSecure)
.frame(maxWidth: .infinity,maxHeight: 24)
.padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 24))
HStack {
Spacer()
Button {
isSecure.toggle()
} label: {
if password.isEmpty {
Rectangle()
.frame(width: 16, height: 2)
.foregroundStyle(Color(.Text.border))
.padding(.trailing,24)
}
else {
if isSecure {
Image(systemName: "eye")
.frame(width: 16, height: 16)
.foregroundStyle(Color(.Text.detail))
.padding(.trailing,24)
}
else {
Image(systemName: "eye.slash")
.frame(width: 16, height: 16)
.foregroundStyle(Color(.Text.detail))
.padding(.trailing,24)
}
}
}
}
}
.background {
RoundedRectangle(cornerRadius: 24)
.foregroundStyle(.white)
}
.padding(EdgeInsets(top: 0, leading: 12, bottom: 8, trailing: 12))
Button {
isSave.toggle()
} label: {
HStack(alignment: .center, spacing: 4) {
Spacer(minLength: 1)
if isSave {
Image(systemName: "checkmark.square")
.foregroundStyle(Color(.Second.normal))
.frame(width: 24, height: 24)
} else {
Image(systemName: "square")
.foregroundStyle(Color(.Second.normal))
.frame(width: 24, height: 24)
}
Text("로그인 정보 저장")
.font(.nps(font: .regular, size: 16))
.foregroundStyle(Color(.Text.detail))
}
}
.padding(EdgeInsets(top: 0, leading: 0, bottom: 24, trailing: 12))
Button {
viewModel.loginAction.send(true)
} label: {
Text("로그인")
.font(.nps(font: .bold, size: 24))
.foregroundStyle(Color(.Text.white))
.padding(EdgeInsets(top: 8, leading: 48, bottom: 8, trailing: 48))
.background{
RoundedRectangle(cornerRadius: 12)
.foregroundStyle(Color(.Second.normal))
}
}
}
}
}

View File

@ -9,7 +9,8 @@ import SwiftUI
import Combine import Combine
struct IntroView: View { struct IntroView: View {
@EnvironmentObject var alertController: AlertController @EnvironmentObject var appVM: AppViewModel
@State var cancellables: Set<AnyCancellable> = [] @State var cancellables: Set<AnyCancellable> = []
@Binding var naviState : NaviState @Binding var naviState : NaviState
@ -17,15 +18,12 @@ struct IntroView: View {
VStack(spacing: 0) { VStack(spacing: 0) {
Spacer() Spacer()
.frame(height: 100) .frame(height: 100)
Image("Team_Icon") Image(.Icon.appIcon)
.resizable() .resizable()
.frame(width: 200, height: 200) .frame(width: 200, height: 200)
.background(.white)
.border(.black)
.padding()
Spacer() Spacer()
HStack(spacing: 4) { HStack(spacing: 4) {
Image("Team_Icon") Image(.Icon.teamIcon)
.resizable() .resizable()
.frame(width: 24, height: 24) .frame(width: 24, height: 24)
Text("STEIN") Text("STEIN")
@ -52,16 +50,17 @@ struct IntroView: View {
} receiveValue: { version in } receiveValue: { version in
let compareForce = compareVersion(version.force_ver, currentVersion()) let compareForce = compareVersion(version.force_ver, currentVersion())
let compareChoice = compareVersion(version.final_ver, currentVersion()) let compareChoice = compareVersion(version.final_ver, currentVersion())
if compareForce == .bigger { if compareForce == .bigger {
alertController.alertData = SetAlertData().setForceUpdate( appVM.alertData = SetAlertData().setForceUpdate(
action: alertController.alertAction action: appVM.alertAction
) )
alertController.showAlert.toggle() appVM.showAlert.toggle()
} else if compareChoice == .bigger && version.choice_update_yn { } else if compareChoice == .bigger && version.choice_update_yn {
alertController.alertData = SetAlertData().setSelectUpdate( appVM.alertData = SetAlertData().setSelectUpdate(
action: alertController.alertAction action: appVM.alertAction
) )
alertController.showAlert.toggle() appVM.showAlert.toggle()
} else { } else {
naviState.set(act: .RESET, path: .Login) naviState.set(act: .RESET, path: .Login)
} }
@ -73,7 +72,7 @@ struct IntroView: View {
} }
private func subscribeAlertAction() { private func subscribeAlertAction() {
alertController.alertAction appVM.alertAction
.compactMap { $0 } .compactMap { $0 }
.sink { action in .sink { action in
if action == "updateNow" { if action == "updateNow" {

View File

@ -0,0 +1,183 @@
//
// LoginView.swift
// AcaMate
//
// Created by Sean Kim on 12/1/24.
//
import SwiftUI
import Combine
struct LoginView: View {
@EnvironmentObject var appVM: AppViewModel
@StateObject private var loginVM = LoginViewModel()
@State var cancellables: Set<AnyCancellable> = []
@Binding var naviState : NaviState
@State var selectIdLogin: Bool = false
@State var userId: String = ""
@State var password: String = ""
@State var isSecure: Bool = true
@State var isSave: Bool = false
var body: some View {
VStack(spacing: 0) {
Image(.Icon.appIcon)
.resizable()
.frame(width: 200, height: 200)
.padding(.top, 80)
///
VStack(spacing: 16) {
Button {
// MARK: - TODO,
appVM.isLoading.toggle()
loginAction(type: .Kakao)
} label: {
makeButton(image: Image(.Icon.kakaoIcon),color: Color(.Other.yellow), "카카오 계정으로 시작하기")
}
Button {
// MARK: - TODO,
naviState.set(act: .MOVE, path: .Main)
} label: {
makeButton(image: Image(.Icon.appleIcon), color: Color(.Text.black), "애플 계정으로 시작하기")
}
}
/*
VStack(spacing: 16) {
Button {
// MARK: TO-DO
//
naviState.set(act: .MOVE, path: .Main)
} label: {
HStack(spacing: 24) {
Image("Kakao_Icon")
.resizable()
.frame(width: 32, height: 32)
Text("카카오 계정으로 시작하기")
.font(.nps(font: .regular, size: 16))
.foregroundStyle(Color(.Text.black))
}
.frame(maxWidth: .infinity)
.padding(12)
.background {
RoundedRectangle(cornerRadius: 12)
.foregroundStyle(Color(.Other.yellow))
}
}
.frame(maxWidth: .infinity)
/// KAKAO
Button {
// MARK: TO-DO
//
} label: {
HStack(spacing: 24) {
Image(systemName: "apple.logo")
.resizable()
.accentColor(Color(.Text.white))
.frame(width: 32, height: 32)
Text("애플 계정으로 시작하기")
.font(.nps(font: .regular, size: 16))
.foregroundStyle(Color(.Text.white))
}
.frame(maxWidth: .infinity)
.padding(12)
.background {
RoundedRectangle(cornerRadius: 12)
.foregroundStyle(Color(.Text.black))
}
}
.frame(maxWidth: .infinity)
/// APPLE
}
*/
.padding([.leading,.trailing], 28)
}
.onAppear {
subscribeLoginAction()
}
.frame(maxWidth: .infinity,maxHeight: .infinity)
.fullDrawView(.Normal.normal)
}
func makeButton(image: Image, color: Color? = nil, _ body: String) -> some View {
return HStack {
image
.resizable()
.frame(width: 32, height: 32)
Spacer(minLength: 12)
Text("\(body)")
.font(.nps(font: .regular, size: 16))
.foregroundStyle(color == Color(.Text.black) ? Color(.Text.white) : Color(.Text.black))
Spacer(minLength: 12)
}
.padding(12)
.background {
if let color = color {
RoundedRectangle(cornerRadius: 12)
.foregroundStyle(color)
}
}
}
private func subscribeLoginAction() {
loginVM.loginAction
.sink { isTapped in
if isTapped {
if userId.isEmpty || password.isEmpty {
appVM.alertData = SetAlertData().setErrorLogin()
appVM.showAlert.toggle()
}
else {
}
printLog("로그인")
}
}
.store(in: &cancellables)
}
private func loginAction(type: SNSLoginType) {
LoginController().login(type)
.flatMap{ snsId in
loadAPIData(url: "\(API_URL)",
path: "/api/v1/in/user/login",
parameters: [
"sns_id": "\(snsId.snsId)",
"acctype": "\(type == .Apple ? "ST00": "ST01")"
],
decodingType: APIResponse<User_Academy>.self)
}
.sink { completion in
switch completion {
case .failure(let error):
printLog("\(error)")
appVM.isLoading.toggle()
case .finished:
appVM.isLoading.toggle()
}
} receiveValue: { response in
guard let ua = response as? APIResponse<User_Academy> else {return}
if let bids = ua.data.toStringDict()["bid"] {
printLog(bids)
if let bidArray: [String] = jsonToSwift(bids) {
printLog(bidArray[0])
} else {
printLog("JSON 변환 실패")
}
}
}
.store(in: &cancellables)
}
}
//#Preview {
// LoginView()
//}

View File

@ -0,0 +1,39 @@
//
// BoxBtnView.swift
// AcaMate
//
// Created by TAnine on 2/4/25.
//
import SwiftUI
struct BoxBtnView<Content: View>: View {
let width: CGFloat
let height: CGFloat
let action: VOID_TO_VOID?
@ViewBuilder let content: Content
var body: some View {
Button{
guard let action = action else { return }
action()
} label: {
content
// if let image = image {
// image
// .resizable()
// .frame(width: width, height: height)
// }
}
}
}
#Preview {
BoxBtnView(width: 40, height: 40, action: nil){
VStack {
Text("Test1")
Text("Test2")
}
}
}

View File

@ -0,0 +1,56 @@
//
// ButtonView.swift
// AcaMate
//
// Created by TAnine on 2/4/25.
//
import SwiftUI
struct CircleBtnView: View {
let title: String?
let image: Image
@Binding var isSelected: Bool
let isReverse: Bool
let action: VOID_TO_VOID?
var backColor: Color {isReverse ? Color(.Second.light) : Color(.Normal.normal)}
var tintColor: Color {isSelected ? Color(.Second.normal) : Color(.Disable.normal)}
var body: some View {
Button{
guard let action = action else {return}
action()
} label: {
VStack(alignment: .center, spacing: 0) {
self.image
.resizable()
.renderingMode(.template)
.foregroundStyle(self.tintColor)
.frame(width: 24, height: 24)
if let title = self.title {
Text("\(title)")
.font(.nps(font: .bold, size: 6))
.tint(self.tintColor)
}
}
.padding()
.background {
if isReverse {
Circle()
.accentColor(self.backColor)
.frame(width: 48, height: 48)
.innerShadow(shape: Circle(), color: Color(.Text.black).opacity(0.75), blur: 8, x: 0, y: 4)
} else {
Circle()
.accentColor(self.backColor)
.frame(width: 48, height: 48)
.shadow(color: Color(.Text.black).opacity(0.75), radius: 8, x: 4, y: 8)
}
}
}
}
}

View File

@ -0,0 +1,45 @@
//
// SimpleBtnView.swift
// AcaMate
//
// Created by TAnine on 2/4/25.
//
import SwiftUI
struct SimpleBtnView: View {
let title: String?
let image: Image?
let font: Font?
let width: CGFloat
let height: CGFloat
let action: VOID_TO_VOID?
var body: some View {
Button{
guard let action = action else { return }
action()
} label: {
if let title = title, let font = font {
Text("\(title)")
.font(font)
.tint(Color(.Second.dark))
.frame(width: width, height: height)
}
else if let image = image {
image
.resizable()
.frame(width: width, height: height)
}
}
}
}
#Preview {
SimpleBtnView(title: "체크 합니다", image: Image(.BottomBar.home),
font: .nps(font: .bold, size: 12),
width: 40, height: 40,
action: nil)
}

View File

@ -0,0 +1,79 @@
//
// BottomView.swift
// AcaMate
//
// Created by TAnine on 2/4/25.
//
import SwiftUI
struct BottomView: View {
@State private var isHomeSelected: Bool = true
@State private var isManagementSelected: Bool = false
@State private var isChattingSelected: Bool = false
@State private var isCalendarSelected: Bool = false
@State private var isEtcSelected: Bool = false
var body: some View {
HStack(spacing: 0){
Spacer(minLength: 1)
CircleBtnView(title: "", image: Image(.BottomBar.home),
isSelected: $isHomeSelected, isReverse: false,
action: {
btnAllFalse()
isHomeSelected.toggle()
})
Spacer(minLength: 1)
CircleBtnView(title: "학습 관리", image: Image(.BottomBar.management),
isSelected: $isManagementSelected, isReverse: false,
action: {
btnAllFalse()
isManagementSelected.toggle()
})
Spacer(minLength: 1)
CircleBtnView(title: "채팅", image: Image(.BottomBar.chatting),
isSelected: $isChattingSelected, isReverse: false,
action: {
btnAllFalse()
isChattingSelected.toggle()
})
Spacer(minLength: 1)
CircleBtnView(title: "일정", image: Image(.BottomBar.calendar),
isSelected: $isCalendarSelected, isReverse: false,
action: {
btnAllFalse()
isCalendarSelected.toggle()
})
Spacer(minLength: 1)
CircleBtnView(title: "더보기", image: Image(.BottomBar.etc),
isSelected: $isEtcSelected, isReverse: false,
action: {
btnAllFalse()
isEtcSelected.toggle()
})
Spacer(minLength: 1)
}
.padding([.top],12)
.background {
Rectangle()
.foregroundStyle(Color(.Normal.dark))
.ignoresSafeArea(edges: .bottom)
}
.frame(maxWidth: .infinity)
}
private func btnAllFalse() {
isHomeSelected = false
isManagementSelected = false
isChattingSelected = false
isCalendarSelected = false
isEtcSelected = false
}
}
#Preview {
BottomView()
}

View File

@ -0,0 +1,34 @@
//
// MainView.swift
// AcaMate
//
// Created by TAnine on 2/4/25.
//
import SwiftUI
import Combine
struct MainView: View {
@EnvironmentObject var alertController: AlertController
@State var cancellables: Set<AnyCancellable> = []
@Binding var naviState : NaviState
var body: some View {
VStack(spacing: 0) {
TopView(titleName: "Name")
Spacer()
BottomView()
.frame(maxWidth: .infinity)
// .backgroundStyle(Color(.Normal.dark))
// .safeAreaInset(edge: .bottom, spacing: 0) {
// Color(.Normal.dark)
//// .frame(height: 0)
// }
}
// .fullDrawView(Color(.Normal.dark))
}
}

View File

@ -0,0 +1,43 @@
//
// TopView.swift
// AcaMate
//
// Created by TAnine on 2/4/25.
//
import SwiftUI
struct TopView: View {
@State var titleName: String = ""
var body: some View {
HStack(alignment: .center, spacing: 0) {
SimpleBtnView(title: nil, image: Image(.TopBar.face), font: nil, width: 40, height: 40, action: {
})
.padding(EdgeInsets(top: 12, leading: 24, bottom: 12, trailing: 12))
Text("\(titleName)")
.tint(Color(.Text.disabled))
.font(.nps(font: .bold, size: 20))
Spacer()
SimpleBtnView(title: nil, image: Image(.TopBar.face), font: nil, width: 40, height: 40, action: {
})
.hidden()
}
.background {
Rectangle()
.foregroundStyle(Color(.Other.cell))
.ignoresSafeArea(edges: .top)
}
.frame(maxWidth: .infinity)
}
}
#Preview {
TopView(titleName: "Name")
}

View File

@ -25,5 +25,11 @@ class VersionData: Codable {
} }
// ----------------
class User_Academy: Codable {
let uid: String
let bid: [String]
}

View File

@ -82,5 +82,16 @@ struct SetAlertData {
]) ])
} }
///
func setErrorLogin() -> AlertData {
return AlertData(title: "로그인",
body: """
ID .
.
""",
button: [
ButtonType(name: "확인", role: .cancel, function: nil)
])
}
} }

View File

@ -0,0 +1,19 @@
//
// AlertController.swift
// AcaMate
//
// Created by Sean Kim on 12/13/24.
//
import SwiftUI
import Combine
class AlertViewModel2: ObservableObject {
@Published var showAlert: Bool = false
var alertData: AlertData = .init(body: "")
let alertAction = CurrentValueSubject<String?, Never>(nil)
}

View File

@ -0,0 +1,19 @@
//
// AppViewModel.swift
// AcaMate
//
// Created by Sean Kim on 12/16/24.
//
import SwiftUI
import Combine
class AppViewModel: ObservableObject {
@Published var isLoading: Bool = false
@Published var showAlert: Bool = false
var alertData: AlertData = .init(body: "")
let alertAction = CurrentValueSubject<String?, Never>(nil)
}

View File

@ -0,0 +1,13 @@
//
// LoginViewModel.swift
// AcaMate
//
// Created by Sean Kim on 12/14/24.
//
import SwiftUI
import Combine
class LoginViewModel: ObservableObject {
let loginAction = CurrentValueSubject<Bool, Never>(false)
}

View File

@ -12,28 +12,31 @@ import KakaoSDKAuth
import KakaoSDKUser import KakaoSDKUser
import Alamofire import Alamofire
import Foundation
class SNSLogin { class LoginController {
private var cancellables = Set<AnyCancellable>() private var cancellables = Set<AnyCancellable>()
func login(type: SNSLoginType){ func login(_ type: SNSLoginType) -> AnyPublisher<SNSID,Error> {
switch type { switch type {
case .Kakao: case .Kakao:
self.checkKakaoToken() return self.checkKakaoToken()
.sink { completion in .handleEvents(receiveCompletion: { completion in
switch completion { switch completion {
case .failure(let error): case .failure(let error) :
printLog("KAKAO LOGIN ERROR: \(error)") printLog("KAKAO LOGIN ERROR: \(error)")
case .finished: break case .finished: break
} }
} receiveValue: { snsId in })
printLog("로그인 완료 \(snsId)") .eraseToAnyPublisher()
} //
.store(in: &cancellables)
case .Apple: break case .Apple:
return Fail(error: NSError(domain: "Apple login not implemented", code: 1, userInfo: nil))
.eraseToAnyPublisher()
} }
} }
func logout(type: SNSLoginType) { func logout(type: SNSLoginType) {
@ -54,7 +57,7 @@ class SNSLogin {
//MARK: - KAKAO LOGIN //MARK: - KAKAO LOGIN
extension SNSLogin { extension LoginController {
/// ///
private func checkKakaoToken() -> Future<SNSID, Error> { private func checkKakaoToken() -> Future<SNSID, Error> {
return Future { promise in return Future { promise in

View File

@ -0,0 +1,65 @@
//
// UIView.swift
// AcaMate
//
// Created by Sean Kim on 12/14/24.
//
import SwiftUI
import UIKit
struct CustomTextField: UIViewRepresentable {
var placeholder: String
@Binding var text: String
var isSecure: Binding<Bool> = .constant(false)
var textColor = UIColor(Color(.Text.detail))
var font = UIFont(name: "NPS-font-Regular", size: 16)
// [] UIView
func makeUIView(context: Context) -> UITextField {
let txf = UITextField()
txf.placeholder = placeholder
txf.isSecureTextEntry = isSecure.wrappedValue
txf.textColor = textColor
txf.font = font
txf.translatesAutoresizingMaskIntoConstraints = false
let height = (font?.lineHeight ?? 10) + 8
txf.frame.size.height = height
txf.autocorrectionType = .no
txf.autocapitalizationType = .none
txf.smartInsertDeleteType = .no
txf.textContentType = .oneTimeCode
txf.delegate = context.coordinator
return txf
}
// [] UIView
func updateUIView(_ uiView: UITextField, context: Context) {
uiView.text = text
uiView.isSecureTextEntry = isSecure.wrappedValue
}
func makeCoordinator() -> Coordinator {
Coordinator(self)
}
class Coordinator: NSObject, UITextFieldDelegate {
var parent: CustomTextField
init(_ parent: CustomTextField) {
self.parent = parent
}
func textFieldDidChangeSelection(_ textField: UITextField) {
parent.text = textField.text ?? ""
}
}
}

View File

@ -8,28 +8,29 @@
import SwiftUI import SwiftUI
import Combine import Combine
struct NetworkModifier: ViewModifier { struct NetworkModifier: ViewModifier {
@ObservedObject private var networkMonitor = NetworkMonitor.shared @ObservedObject private var networkMonitor = NetworkMonitor.shared
@EnvironmentObject var alertController: AlertController @EnvironmentObject var appVM: AppViewModel
func body(content: Content) -> some View { func body(content: Content) -> some View {
content content
.onChange(of: networkMonitor.isConnected) { _ , new in .onChange(of: networkMonitor.isConnected) { _ , new in
if !new { if !new {
alertController.alertData = SetAlertData().setErrorNetwork() appVM.alertData = SetAlertData().setErrorNetwork()
alertController.showAlert.toggle() appVM.showAlert.toggle()
} }
} }
} }
} }
struct AlertModifier: ViewModifier { struct AlertModifier: ViewModifier {
@EnvironmentObject var controller: AlertController @EnvironmentObject var appVM: AppViewModel
func body(content: Content) -> some View { func body(content: Content) -> some View {
content content
.alert(controller.alertData.title, .alert(appVM.alertData.title,
isPresented: $controller.showAlert, isPresented: $appVM.showAlert,
presenting: $controller.alertData) { data in presenting: $appVM.alertData) { data in
let btnCount = data.button.count let btnCount = data.button.count
ForEach(0 ..< btnCount, id: \.self) { index in ForEach(0 ..< btnCount, id: \.self) { index in
let btn = data.wrappedValue.button[index] let btn = data.wrappedValue.button[index]
@ -45,8 +46,35 @@ struct AlertModifier: ViewModifier {
} }
} }
struct LoadingModifier: ViewModifier {
@Binding var isLoading: Bool
func body(content: Content) -> some View {
ZStack {
content
.disabled(isLoading)
.blur(radius: isLoading ? 3:0)
if isLoading {
Color.Text.detail.opacity(0.6)
// Color.Second.normal.opacity(0.3)
.ignoresSafeArea()
ProgressView("Loading...")
// .tint(Color.Text.black)
.tint(Color.Normal.normal)
.scaleEffect(1.5)
.foregroundStyle(Color.Normal.normal)
.font(.nps(font: .bold, size: 16))
.padding()
}
}
}
}
extension View { extension View {
func fullView(_ backColor: Color) -> some View { /// View
func fullDrawView(_ backColor: Color) -> some View {
return self return self
.frame(maxWidth: .infinity, maxHeight: .infinity) .frame(maxWidth: .infinity, maxHeight: .infinity)
.background(backColor) .background(backColor)
@ -63,9 +91,17 @@ extension View {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil) UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
} }
func setNavigaion() -> some View { func loadingView(isLoading: Binding<Bool>) -> some View {
self self.modifier(LoadingModifier(isLoading: isLoading))
.navigationBarBackButtonHidden(true) }
.toolbar(.hidden, for: .navigationBar)
func innerShadow<S: Shape> (shape: S, color: Color, lineWidth: CGFloat = 6, blur: CGFloat, x: CGFloat, y: CGFloat) -> some View {
return self.overlay {
shape
.stroke(color, lineWidth: lineWidth)
.offset(x: x, y: y)
.blur(radius: blur)
.mask(shape.fill(LinearGradient(gradient: Gradient(colors: [.black, .clear]), startPoint: .topLeading, endPoint: .bottomTrailing)))
}
} }
} }

View File

@ -1,6 +1,7 @@
{ {
"images" : [ "images" : [
{ {
"filename" : "LOGO.png",
"idiom" : "universal", "idiom" : "universal",
"platform" : "ios", "platform" : "ios",
"size" : "1024x1024" "size" : "1024x1024"
@ -12,6 +13,7 @@
"value" : "dark" "value" : "dark"
} }
], ],
"filename" : "LOGO 1.png",
"idiom" : "universal", "idiom" : "universal",
"platform" : "ios", "platform" : "ios",
"size" : "1024x1024" "size" : "1024x1024"
@ -23,6 +25,7 @@
"value" : "tinted" "value" : "tinted"
} }
], ],
"filename" : "LOGO 2.png",
"idiom" : "universal", "idiom" : "universal",
"platform" : "ios", "platform" : "ios",
"size" : "1024x1024" "size" : "1024x1024"

Binary file not shown.

After

Width:  |  Height:  |  Size: 811 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 811 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 811 KiB

View File

@ -0,0 +1,20 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0.776",
"green" : "0.776",
"red" : "0.776"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Calendar.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Chatting.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,9 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"provides-namespace" : true
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Etc.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Home.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Management.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "appIcon.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "APPLE.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,9 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"provides-namespace" : true
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "KAKAO.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "MI.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "PageIcon.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "TeamIcon.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -1,21 +0,0 @@
{
"images" : [
{
"filename" : "KakaoIcon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

View File

@ -1,21 +0,0 @@
{
"images" : [
{
"filename" : "MI.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -1,21 +0,0 @@
{
"images" : [
{
"filename" : "1024.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Back.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,9 @@
{
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"provides-namespace" : true
}
}

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Edit.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Face.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Market.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Person.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Plus.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 261 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Save.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 844 B

View File

@ -0,0 +1,12 @@
{
"images" : [
{
"filename" : "Setting.png",
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 636 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 604 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 577 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 811 KiB

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

View File

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 587 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 535 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Some files were not shown because too many files have changed in this diff Show More