[📝] GIT init

This commit is contained in:
김선규 2024-06-26 12:38:42 +09:00
commit 0872089c5d
64 changed files with 4799 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
.Pods/
Podfile
Podfile.lock
JJUNGTABLE/Common/KEY.swift

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,140 @@
{
"pins" : [
{
"identity" : "abseil-cpp-binary",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/abseil-cpp-binary.git",
"state" : {
"revision" : "bfc0b6f81adc06ce5121eb23f628473638d67c5c",
"version" : "1.2022062300.0"
}
},
{
"identity" : "alamofire",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Alamofire/Alamofire.git",
"state" : {
"revision" : "b2fa556e4e48cbf06cf8c63def138c98f4b811fa",
"version" : "5.8.0"
}
},
{
"identity" : "firebase-ios-sdk",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/firebase-ios-sdk",
"state" : {
"revision" : "837d4af6ead57cec1fc38007892500d3139c7556",
"version" : "10.16.0"
}
},
{
"identity" : "googleappmeasurement",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleAppMeasurement.git",
"state" : {
"revision" : "56f681586ff006a7982b53dc94082eea31971acf",
"version" : "10.16.0"
}
},
{
"identity" : "googledatatransport",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleDataTransport.git",
"state" : {
"revision" : "aae45a320fd0d11811820335b1eabc8753902a40",
"version" : "9.2.5"
}
},
{
"identity" : "googleutilities",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleUtilities.git",
"state" : {
"revision" : "c38ce365d77b04a9a300c31061c5227589e5597b",
"version" : "7.11.5"
}
},
{
"identity" : "grpc-binary",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/grpc-binary.git",
"state" : {
"revision" : "a673bc2937fbe886dd1f99c401b01b6d977a9c98",
"version" : "1.49.1"
}
},
{
"identity" : "gtm-session-fetcher",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/gtm-session-fetcher.git",
"state" : {
"revision" : "d415594121c9e8a4f9d79cecee0965cf35e74dbd",
"version" : "3.1.1"
}
},
{
"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",
"kind" : "remoteSourceControl",
"location" : "https://github.com/kakao/kakao-ios-sdk",
"state" : {
"revision" : "4747117b01d8b28efbfcb004dbd122b8e1626f79",
"version" : "2.18.1"
}
},
{
"identity" : "leveldb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/leveldb.git",
"state" : {
"revision" : "0706abcc6b0bd9cedfbb015ba840e4a780b5159b",
"version" : "1.22.2"
}
},
{
"identity" : "nanopb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/nanopb.git",
"state" : {
"revision" : "819d0a2173aff699fb8c364b6fb906f7cdb1a692",
"version" : "2.30909.0"
}
},
{
"identity" : "promises",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/promises.git",
"state" : {
"revision" : "e70e889c0196c76d22759eb50d6a0270ca9f1d9e",
"version" : "2.3.1"
}
},
{
"identity" : "snapkit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/SnapKit/SnapKit.git",
"state" : {
"revision" : "f222cbdf325885926566172f6f5f06af95473158",
"version" : "5.6.0"
}
},
{
"identity" : "swift-protobuf",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-protobuf.git",
"state" : {
"revision" : "3c54ab05249f59f2c6641dd2920b8358ea9ed127",
"version" : "1.24.0"
}
}
],
"version" : 2
}

View File

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1500"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A7C240A72AE9F60D001E0925"
BuildableName = "JJUNGTABLE.app"
BlueprintName = "JJUNGTABLE"
ReferencedContainer = "container:JJUNGTABLE.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A7C240A72AE9F60D001E0925"
BuildableName = "JJUNGTABLE.app"
BlueprintName = "JJUNGTABLE"
ReferencedContainer = "container:JJUNGTABLE.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "A7C240A72AE9F60D001E0925"
BuildableName = "JJUNGTABLE.app"
BlueprintName = "JJUNGTABLE"
ReferencedContainer = "container:JJUNGTABLE.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid = "E7C3BF9D-4509-4851-BCD9-5895856D2EBC"
type = "1"
version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "8BB130DE-9616-4745-B407-9F71AE773D50"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "JJUNGTABLE/Scene/HomeScene/TopViewAlert/FriendView/FriendView.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "20"
endingLineNumber = "20"
landmarkName = "initData(_:)"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>

View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>JJUNGTABLE.xcscheme_^#shared#^_</key>
<dict>
<key>orderHint</key>
<integer>4</integer>
</dict>
<key>Promises (Playground) 1.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>5</integer>
</dict>
<key>Promises (Playground) 2.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>6</integer>
</dict>
<key>Promises (Playground).xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>0</integer>
</dict>
<key>SnapKitPlayground (Playground) 1.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>2</integer>
</dict>
<key>SnapKitPlayground (Playground) 2.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>3</integer>
</dict>
<key>SnapKitPlayground (Playground) 3.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>7</integer>
</dict>
<key>SnapKitPlayground (Playground) 4.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>8</integer>
</dict>
<key>SnapKitPlayground (Playground) 5.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>9</integer>
</dict>
<key>SnapKitPlayground (Playground).xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>1</integer>
</dict>
</dict>
<key>SuppressBuildableAutocreation</key>
<dict>
<key>A7C240A72AE9F60D001E0925</key>
<dict>
<key>primary</key>
<true/>
</dict>
</dict>
</dict>
</plist>

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:JJUNGTABLE.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@ -0,0 +1,149 @@
{
"pins" : [
{
"identity" : "abseil-cpp-binary",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/abseil-cpp-binary.git",
"state" : {
"revision" : "bfc0b6f81adc06ce5121eb23f628473638d67c5c",
"version" : "1.2022062300.0"
}
},
{
"identity" : "alamofire",
"kind" : "remoteSourceControl",
"location" : "https://github.com/Alamofire/Alamofire.git",
"state" : {
"revision" : "3dc6a42c7727c49bf26508e29b0a0b35f9c7e1ad",
"version" : "5.8.1"
}
},
{
"identity" : "app-check",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/app-check.git",
"state" : {
"revision" : "5746b2d35c91c50581590ed97abe4c06b5037274",
"version" : "10.18.0"
}
},
{
"identity" : "firebase-ios-sdk",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/firebase-ios-sdk",
"state" : {
"revision" : "c60c958e707c50a9cf8bcb7cfd7d51c566d726c5",
"version" : "10.19.1"
}
},
{
"identity" : "googleappmeasurement",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleAppMeasurement.git",
"state" : {
"revision" : "6b332152355c372ace9966d8ee76ed191f97025e",
"version" : "10.17.0"
}
},
{
"identity" : "googledatatransport",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleDataTransport.git",
"state" : {
"revision" : "a732a4b47f59e4f725a2ea10f0c77e93a7131117",
"version" : "9.3.0"
}
},
{
"identity" : "googleutilities",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/GoogleUtilities.git",
"state" : {
"revision" : "bc27fad73504f3d4af235de451f02ee22586ebd3",
"version" : "7.12.1"
}
},
{
"identity" : "grpc-binary",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/grpc-binary.git",
"state" : {
"revision" : "a673bc2937fbe886dd1f99c401b01b6d977a9c98",
"version" : "1.49.1"
}
},
{
"identity" : "gtm-session-fetcher",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/gtm-session-fetcher.git",
"state" : {
"revision" : "115f75e43851774934d695449a4836123c3246e1",
"version" : "3.2.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",
"kind" : "remoteSourceControl",
"location" : "https://github.com/kakao/kakao-ios-sdk",
"state" : {
"revision" : "ae3c60cbd4e3b348775f8c766e5b908fa1e66c5a",
"version" : "2.20.0"
}
},
{
"identity" : "leveldb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/leveldb.git",
"state" : {
"revision" : "9d108e9112aa1d65ce508facf804674546116d9c",
"version" : "1.22.3"
}
},
{
"identity" : "nanopb",
"kind" : "remoteSourceControl",
"location" : "https://github.com/firebase/nanopb.git",
"state" : {
"revision" : "819d0a2173aff699fb8c364b6fb906f7cdb1a692",
"version" : "2.30909.0"
}
},
{
"identity" : "promises",
"kind" : "remoteSourceControl",
"location" : "https://github.com/google/promises.git",
"state" : {
"revision" : "e70e889c0196c76d22759eb50d6a0270ca9f1d9e",
"version" : "2.3.1"
}
},
{
"identity" : "snapkit",
"kind" : "remoteSourceControl",
"location" : "https://github.com/SnapKit/SnapKit.git",
"state" : {
"revision" : "f222cbdf325885926566172f6f5f06af95473158",
"version" : "5.6.0"
}
},
{
"identity" : "swift-protobuf",
"kind" : "remoteSourceControl",
"location" : "https://github.com/apple/swift-protobuf.git",
"state" : {
"revision" : "65e8f29b2d63c4e38e736b25c27b83e012159be8",
"version" : "1.25.2"
}
}
],
"version" : 2
}

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<Bucket
uuid = "821E3B5D-51C3-4FFC-B087-93F99A77899C"
type = "0"
version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "A46E5F1A-275E-4724-80DE-0B342715A93D"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "JJUNGTABLE/Scene/Common/IntroViewController.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "21"
endingLineNumber = "21"
landmarkName = "IntroViewController"
landmarkType = "3">
</BreakpointContent>
</BreakpointProxy>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
uuid = "24F20DB5-D9D5-46D5-87A4-73D88CBC9C7B"
shouldBeEnabled = "Yes"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "JJUNGTABLE/Scene/Common/IntroViewController.swift"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "79"
endingLineNumber = "79"
landmarkName = "gotoMainVC()"
landmarkType = "7">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket>

View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>SchemeUserState</key>
<dict>
<key>Promises (Playground) 1.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>5</integer>
</dict>
<key>Promises (Playground) 2.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>6</integer>
</dict>
<key>Promises (Playground) 3.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>12</integer>
</dict>
<key>Promises (Playground) 4.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>13</integer>
</dict>
<key>Promises (Playground) 5.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>14</integer>
</dict>
<key>Promises (Playground).xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>4</integer>
</dict>
<key>SnapKitPlayground (Playground) 1.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>8</integer>
</dict>
<key>SnapKitPlayground (Playground) 2.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>9</integer>
</dict>
<key>SnapKitPlayground (Playground) 3.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>3</integer>
</dict>
<key>SnapKitPlayground (Playground) 4.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>10</integer>
</dict>
<key>SnapKitPlayground (Playground) 5.xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>11</integer>
</dict>
<key>SnapKitPlayground (Playground).xcscheme</key>
<dict>
<key>isShown</key>
<false/>
<key>orderHint</key>
<integer>7</integer>
</dict>
</dict>
</dict>
</plist>

BIN
JJUNGTABLE/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,376 @@
//
// AppDelegate.swift
// JJUNGTABLE
//
// Created by Sean Kim on 10/26/23.
//
import UIKit
import SwiftUI
import Combine
import UserNotifications
import Firebase
import FirebaseMessaging
import KakaoSDKCommon
@main
class AppDelegate: UIResponder, UIApplicationDelegate, UNUserNotificationCenterDelegate, MessagingDelegate{
var viewModel = ViewModel()
private var cancellables = Set<AnyCancellable>()
private var version: [Version] = []
private let gcmMessageIDKey = "gcm.message_id"
// private var cancellables = Set<AnyCancellable>()
// private var versions: [Version] = []
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>) {
}
private func checkVersion() {
API.shared.readData(path: "/db/version/read",
queryItems: [URLQueryItem(name: "os_type", value: "I")])
.sink { completion in
switch completion {
case .finished:
printLog(self.version)
// OOO
switch compareVersion(currentVersion(), self.version[0].update_ver) {
case .bigger:
self.viewModel.isUpdate = "N"
case .smaller, .equal:
self.viewModel.isUpdate = "Y"
case .error:
self.viewModel.alertData = self.viewModel.systemErrorAlert()
self.viewModel.showAlert.toggle()
}
switch compareVersion(currentVersion(), self.version[0].final_ver) {
case .bigger, .equal:
// - x
break
case .smaller:
let choice = self.version[0].update_choice == "Y" ? true : false
switch compareVersion(currentVersion(), self.version[0].force_ver) {
case .bigger, .equal:
//
if !choice {
break //
}
else {
self.viewModel.alertData = .init(title: "업데이트 안내",
body: """
.
?
""",
button: [ButtonType(name: "지금 업데이트", role: .cancel ,
function: {exit(1)}),
ButtonType(name: "나중에", role: .none ,
function: nil),
])
self.viewModel.showAlert.toggle()
}
case .smaller:
// -> .
self.viewModel.alertData = .init(title: "업데이트 안내",
body: """
.
.
""",
button: [ButtonType(name: "지금 업데이트", role: .none,
function: {exit(1)})])
self.viewModel.showAlert.toggle()
case .error:
self.viewModel.alertData = self.viewModel.systemErrorAlert()
self.viewModel.showAlert.toggle()
}
case .error:
self.viewModel.alertData = self.viewModel.systemErrorAlert()
self.viewModel.showAlert.toggle()
}
//
case .failure(let error):
printLog(error)
self.viewModel.alertData = self.viewModel.systemErrorAlert()
self.viewModel.showAlert.toggle()
}
} receiveValue: { data in
do {
let decoder = JSONDecoder()
self.version = try decoder.decode([Version].self, from: data)
} catch {
printLog(error)
self.viewModel.alertData = self.viewModel.systemErrorAlert()
self.viewModel.showAlert.toggle()
}
}
.store(in: &cancellables)
}
}
// MARK: -
extension AppDelegate {
func application(_ application: UIApplication,didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
printLog("Start Set AppDelegate")
if isIllegalDevice() {
viewModel.alertData = .init(title:"경고",
body: """
OS('') .
""",
button: [ButtonType(name: "확인", role: .none ,
function: {exit(1)})])
viewModel.showAlert.toggle()
}
else {
checkVersion()
// Firebase
FirebaseApp.configure()
// App Check
// AppCheck.setAppCheckProviderFactory(AppCheckDebugProviderFactory())
// SDK
KakaoSDK.initSDK(appKey: KEY.kakaoAppKey)
#if FCM
// FCM
Messaging.messaging().delegate = self
#endif
// Noti
UNUserNotificationCenter.current().delegate = self
let authOptions: UNAuthorizationOptions = [.alert, .badge, .sound]
UNUserNotificationCenter.current().requestAuthorization(options: authOptions) { granted, error in
if let error = error {
printLog("Authorization error: \(error.localizedDescription)")
}
if granted {
DispatchQueue.main.async {
UIApplication.shared.registerForRemoteNotifications()
}
} else {
printLog("Notification permission denied.")
}
}
application.registerForRemoteNotifications()
UIApplication.shared.registerForRemoteNotifications()
//
_ = NetworkMonitor.shared
}
printLog("End Set AppDelegate")
return true
}
func application(_ application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: Error) {
}
}
extension AppDelegate {
// 24.05.30 () -
func application(_ application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data) {
// SMS
Auth.auth().setAPNSToken(deviceToken, type: .unknown)
printLog("원격 푸시 알림 등록 성공 ")
let deviceTokenString = deviceToken.reduce("", {$0 + String(format: "%02.2hX", $1)})
viewModel.deviceToken = deviceTokenString
// Firebase
Messaging.messaging().apnsToken = deviceToken
printLog("DeviceToken: \(viewModel.deviceToken)")
}
// 24.05.30 () - FCM
func messaging(_ messaging: Messaging, didReceiveRegistrationToken fcmToken: String?) {
@UserDefault (key: "isRegisterToken", defaultValue: "F") var isRegisterToken
printLog("토큰 등록 동작 시작")
guard let fcmToken = fcmToken else { return }
viewModel.pushFCMToken = fcmToken
Task {
if isRegisterToken == "F" {
// switch await FB_CRUD.shared.create("Token", doc: "\(viewModel.deviceToken)",
// data: ["fcmToken":"\(viewModel.pushFCMToken)"]) {
// case .success(_):
// viewModel.pushFCMToken = fcmToken
// isRegisterToken = "T"
// printLog(" ")
// case .failure(let error):
// isRegisterToken = "F"
// viewModel.alertData = .init(body:"""
// .
// .
// """,
// button: [ButtonType(name: "", role: .destructive ,function: {exit(1)})])
// viewModel.showAlert.toggle()
// printLog(" ")
// }
}
else {
// if viewModel.pushFCMToken != fcmToken {
// switch await FB_CRUD.shared.update("Token", doc: "\(viewModel.deviceToken)",
// data: ["fcmToken":"\(viewModel.pushFCMToken)"]) {
// case .success(_):
// viewModel.pushFCMToken = fcmToken
// isRegisterToken = "T"
// printLog(" ")
// case .failure(_):
// viewModel.alertData = .init(body:"""
// .
// .
// """,
// button: [ButtonType(name: "", role: .destructive ,function: {exit(1)})])
// viewModel.showAlert.toggle()
// printLog(" ")
// }
// }
}
printLog("FCM Token: \(viewModel.pushFCMToken)")
}
}
//
func userNotificationCenter(_ center: UNUserNotificationCenter, willPresent notification: UNNotification) async -> UNNotificationPresentationOptions {
let userInfo = notification.request.content.userInfo
// SMS
if Auth.auth().canHandleNotification(userInfo) {
return []
}
if let apsData = userInfo["aps"] as? [AnyHashable: Any],
let messageId = userInfo["gcm.message_id"] as? String,
let badge = apsData["badge"] as? Int {
// switch await FB_CRUD.shared.read("Users", doc: "\(viewModel.userId)") {
// case .success(let data):
// if var noReadList = data["noReadAlert"] as? [String] {
// noReadList.append(messageId)
// viewModel.noReadAlertList = noReadList
// switch await FB_CRUD.shared.update("Users", doc: "\(viewModel.userId)",
// data: ["noReadAlert":noReadList]) {
// case .success(let data):
// await viewModel.setBadge()
// case .failure(let gg):
// printLog(noReadList)
// }
// printLog(viewModel.noReadAlertList)
// printLog(viewModel.noReadAlertList.count)
//
// }
// case .failure(let failure):
// printLog(failure)
// }
}
Messaging.messaging().appDidReceiveMessage(userInfo)
if #available(iOS 14.0, *) {
return [[.list,.banner,.sound]]
} else {
return[[.alert,.sound]]
}
}
// Background Notification
func userNotificationCenter(_ center: UNUserNotificationCenter, didReceive response: UNNotificationResponse) {
printLog("ININININININi")
let userInfo = response.notification.request.content.userInfo
// SMS
if Auth.auth().canHandleNotification(userInfo) {
return
}
if let apsData = userInfo["aps"] as? [AnyHashable: Any] {
if let alert = apsData["alert"] as? [AnyHashable: Any],
let messageKey = apsData[gcmMessageIDKey] as? String {
printLog("apsData: \(apsData)")
printLog("alert: \(alert)")
printLog("key: \(messageKey)")
if let param = alert["parameter"] {
printLog(param as? String)
}
// viewModel.setBadge()
}
}
}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any], fetchCompletionHandler completionHandler: @escaping (UIBackgroundFetchResult) -> Void) {
// SMS
if Auth.auth().canHandleNotification(userInfo) {
completionHandler(.noData)
return
}
// printLog("Back = \(userInfo)")
// FB_CRUD.shared.sendPushNotification("", body: "")
// @UserDefault (key: "fcmToken", defaultValue: "") var pushFCMToken
// @UserDefault (key: "userId", defaultValue: "") var userId
// @UserDefault (key: "noReadAlertList", defaultValue: [""]) var noReadAlertList
//
// let userInfo = notification.request.content.userInfo
//
// if let apsData = userInfo["aps"] as? [AnyHashable: Any],
// let messageId = userInfo["gcm.message_id"] as? String,
// let badge = apsData["badge"] as? Int {
//
// switch await FB_CRUD.shared.read("Users", doc: "\(userId)") {
// case .success(let data):
// printLog(data)
// if var noReadList = data["noReadAlert"] as? [String] {
// noReadList.append(messageId)
// noReadAlertList = noReadList
// await FB_CRUD.shared.update("Users", doc: "\(userId)",
// data: ["noReadAlert":noReadList])
// printLog(noReadList)
// printLog(noReadAlertList)
// printLog(noReadAlertList.count)
// await viewModel.setBadge(badge: noReadAlertList.count)
// }
// case .failure(let failure):
// printLog(failure)
// }
//
// }
}
}

View File

@ -0,0 +1,88 @@
//
// SceneDelegate.swift
// JJUNGTABLE
//
// Created by Sean Kim on 10/26/23.
//
import UIKit
import SwiftUI
import KakaoSDKAuth
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
var window: UIWindow?
// private var appCoordinator: AppCordinator?
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
guard let appDelegate = UIApplication.shared.delegate as? AppDelegate else { return }
guard let windowScene = scene as? UIWindowScene else { return }
var contentView = ContentView().environmentObject(appDelegate.viewModel)
window = UIWindow(windowScene: windowScene)
window?.rootViewController = UIHostingController(rootView: contentView)
window?.makeKeyAndVisible()
// self.window = window
/*
let navigationController = UINavigationController()
navigationController.navigationBar.isHidden = true
navigationController.interactivePopGestureRecognizer?.isEnabled = false
self.appCoordinator = AppCordinator(navigationController: navigationController)
self.appCoordinator?.choiceVC(.intro, isPop: F)
window = UIWindow(windowScene: windowScene)
window?.windowScene = windowScene
window?.rootViewController = navigationController
window?.makeKeyAndVisible()
*/
}
func sceneDidDisconnect(_ scene: UIScene) {
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene) {
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene) {
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene) {
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene) {
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
//
if let url = URLContexts.first?.url {
if url.scheme == "특정스키마" {
//
}
else if AuthApi.isKakaoTalkLoginUrl(url) {
_ = AuthController.handleOpenUrl(url: url)
}
}
}
}

BIN
JJUNGTABLE/Assets.xcassets/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,14 @@
{
"images" : [
{
"filename" : "JJungTable_Icon.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 543 KiB

View File

@ -0,0 +1,41 @@
{
"colors" : [
{
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "68",
"green" : "83",
"red" : "230"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "0.267",
"green" : "0.325",
"red" : "0.902"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"localizable" : true
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

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

View File

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

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

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

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "0.699",
"green" : "0.699",
"red" : "0.699"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "0.699",
"green" : "0.699",
"red" : "0.699"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,23 @@
{
"colors" : [
{
"color" : {
"color-space" : "srgb",
"components" : {
"alpha" : "1.000",
"blue" : "0",
"green" : "102",
"red" : "255"
}
},
"idiom" : "iphone"
}
],
"info" : {
"author" : "xcode",
"version" : 1
},
"properties" : {
"localizable" : true
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

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

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "0.251",
"green" : "0.251",
"red" : "0.251"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "1.000",
"blue" : "0.251",
"green" : "0.251",
"red" : "0.251"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,38 @@
{
"colors" : [
{
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "0.200",
"blue" : "0.698",
"green" : "0.698",
"red" : "0.698"
}
},
"idiom" : "universal"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"color" : {
"color-space" : "display-p3",
"components" : {
"alpha" : "0.200",
"blue" : "0.698",
"green" : "0.698",
"red" : "0.698"
}
},
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="22505" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina6_12" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22504"/>
<capability name="Image references" minToolsVersion="12.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<customFonts key="customFonts">
<array key="NPSfont_regular.otf">
<string>NPS-font-Regular</string>
</array>
</customFonts>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="gTx-ol-ybK">
<rect key="frame" x="114.66666666666669" y="363.33333333333337" width="164" height="152.33333333333337"/>
<imageReference key="image" image="j.square.on.square" catalog="system" symbolScale="large" renderingMode="hierarchical">
<hierarchicalColors>
<color name="BrandColor"/>
<color name="BrandColor"/>
<color name="BrandColor"/>
</hierarchicalColors>
</imageReference>
<preferredSymbolConfiguration key="preferredSymbolConfiguration" configurationType="pointSize" pointSize="100" scale="large"/>
</imageView>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="© 2023. Sean.Kim" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="jwU-9l-Qnk">
<rect key="frame" x="144.33333333333334" y="790.33333333333337" width="104.66666666666666" height="17.666666666666629"/>
<fontDescription key="fontDescription" name="NPS-font-Regular" family="NPS font" pointSize="12"/>
<color key="textColor" white="0.66666666669999997" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
<color key="backgroundColor" systemColor="systemBackgroundColor"/>
<constraints>
<constraint firstItem="6Tk-OE-BBY" firstAttribute="bottom" secondItem="jwU-9l-Qnk" secondAttribute="bottom" constant="10" id="J8u-6m-q7i"/>
<constraint firstItem="jwU-9l-Qnk" firstAttribute="centerX" secondItem="6Tk-OE-BBY" secondAttribute="centerX" id="Ukm-3B-467"/>
<constraint firstItem="gTx-ol-ybK" firstAttribute="centerY" secondItem="6Tk-OE-BBY" secondAttribute="centerY" id="enm-4c-d2c"/>
<constraint firstItem="gTx-ol-ybK" firstAttribute="centerX" secondItem="6Tk-OE-BBY" secondAttribute="centerX" id="zE7-OK-N1V"/>
</constraints>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="52.671755725190835" y="374.64788732394368"/>
</scene>
</scenes>
<resources>
<image name="j.square.on.square" catalog="system" width="128" height="116"/>
<namedColor name="BrandColor">
<color red="0.90196079019999997" green="0.32549020649999999" blue="0.26666668059999998" alpha="1" colorSpace="custom" customColorSpace="displayP3"/>
</namedColor>
<systemColor name="systemBackgroundColor">
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</systemColor>
</resources>
</document>

View File

@ -0,0 +1,93 @@
//
// API.swift
// JJUNGTABLE
//
// Created by Sean Kim on 6/5/24.
//
import SwiftUI
import Combine
struct InfoKey {
static var httpURL: String {
return Bundle.main.object(forInfoDictionaryKey: "httpURL") as? String ?? ""
}
static var httpsURL: String {
return Bundle.main.object(forInfoDictionaryKey: "httpsURL") as? String ?? ""
}
static var apiPort: String {
return Bundle.main.object(forInfoDictionaryKey: "PORT") as? String ?? ""
}
}
class API {
static let shared = API()
private init() {}
private func makeURLComponents(path: String, queryItems: [URLQueryItem]? = nil) -> Result<URLComponents, Error> {
// let url = InfoKey.httpURL
// let port = InfoKey.apiPort
let url = "https://ipstein.myds.me"
let port = "5004"
let path = "/JJ\(path)"
printLog("\(url):\(port)\(path)?\(queryItems)")
if url == "" || port == "" {
return .failure(API_ERROR(caseType: .API_PLIST_WRONG, message: "저장된 API 주소 오류"))
}
guard var components = URLComponents(string: url) else {
return .failure(API_ERROR(caseType: .API_PATH_WRONG, message: "API 주소 오류"))
}
components.port = Int(port)
components.path = path
components.queryItems = queryItems
return .success(components)
}
func createUserInfo() -> AnyPublisher<[UserInfo], Error> {
// switch self.makeURLComponents() {
// case .success(let components):
// break
// case .failure(let error):
// return Fail(error: error)
// .eraseToAnyPublisher()
// }
return Fail(error: API_ERROR(caseType: .API_PATH_WRONG, message: "API 주소 오류"))
.eraseToAnyPublisher()
}
func readData(path: String, queryItems: [URLQueryItem]? = nil) -> AnyPublisher<Data, Error> {
switch self.makeURLComponents(path: path, queryItems: queryItems) {
case .success(let components):
guard let url = components.url else {
return Fail(error: API_ERROR(caseType: .API_PATH_WRONG, message: "API 주소 오류"))
.eraseToAnyPublisher()
}
return URLSession.shared.dataTaskPublisher(for: url)
.tryMap { result in
guard let httpResponse = result.response as? HTTPURLResponse, httpResponse.statusCode == 200 else {
throw API_ERROR(caseType: .API_CONNECT, message: "서버 접속 오류")
}
return result.data
}
.mapError { error in
return API_ERROR(caseType: .API_READ, message: "\(error.localizedDescription)")
}
.receive(on: DispatchQueue.main)
.eraseToAnyPublisher()
case .failure(let error):
return Fail(error: error)
.eraseToAnyPublisher()
}
}
}

View File

@ -0,0 +1,39 @@
//
// DataModel.swift
// JJUNGTABLE
//
// Created by Sean Kim on 6/10/24.
//
import Foundation
struct Version: Codable {
let os_type: String
let final_ver: String
let force_ver: String
let update_ver: String
let update_choice: String
}
struct UserInfo: Codable, Identifiable {
let id: String
let connect_type: String
let os_type: String
let table_id: String
let name: String
let birth: String
private enum CodingKeys: String, CodingKey {
case id = "user_cid"
case connect_type
case os_type
case table_id
case name
case birth
}
}
struct UserCID: Codable {
let user_cid: String
}

View File

@ -0,0 +1,97 @@
//
// HalfView.swift
// PersonalHealthDiary
//
// Created by Sean Kim on 3/6/24.
//
import SwiftUI
//struct HalfView: View {
// @State var showSheet: Bool = false
//
// var body: some View {
//// NavigationView {
// Button {
// showSheet.toggle()
// } label: {
// Text("Button Click2")
// }
// .halfSheet(showSheet: $showSheet) {
// Text("HELLO HALF")
// } onEnd: {
// print("?")
// }
// // }
// }
//}
extension View {
func halfSheet<SheetView: View>(showSheet: Binding<Bool>, @ViewBuilder sheetView: @escaping ()->SheetView, onEnd: @escaping ()->() ) -> some View {
return self
.background(
//
HalfSheetHelper(sheetView: sheetView(), showSheet: showSheet, onEnd: onEnd)
)
}
}
//UIKit
struct HalfSheetHelper<SheetView: View>: UIViewControllerRepresentable {
var sheetView: SheetView
@Binding var showSheet: Bool
var onEnd: ()->()
//
let vc = UIViewController()
func makeCoordinator() -> Coordinator {
return Coordinator(parent: self)
}
func makeUIViewController(context: Context) -> UIViewController {
vc.view.backgroundColor = .clear
return vc
}
func updateUIViewController(_ uiViewController: UIViewController, context: Context) {
if showSheet {
let sheetController = CustomHostingController(rootView: sheetView)
sheetController.presentationController?.delegate = context.coordinator
uiViewController.present(sheetController, animated: true)
}
else {
// showSheet view
// uiViewController.dismiss(animated: true)
uiViewController.presentedViewController?.dismiss(animated: true)
}
}
//
class Coordinator: NSObject, UISheetPresentationControllerDelegate {
var parent: HalfSheetHelper
init(parent: HalfSheetHelper) {
self.parent = parent
}
func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
parent.showSheet = false
parent.onEnd()
}
}
}
class CustomHostingController<Content: View>: UIHostingController<Content> {
override func viewDidLoad() {
// view.backgroundColor = .clear
//
if let presentationController = presentationController as? UISheetPresentationController {
presentationController.detents = [.medium()]
//
presentationController.prefersGrabberVisible = false
}
}
}

View File

@ -0,0 +1,103 @@
//
// ScorllView_Example.swift
// RememberbyAnything
//
// Created by Sean Kim on 5/14/24.
//
import SwiftUI
struct ScorllView_Example: View {
@StateObject private var scrollViewModel: ScrollViewModel = ScrollViewModel()
@State var isStartScroll: Bool = true
// scroll
private var scrollObservableView: some View {
GeometryReader { proxy in
let offsetY = proxy.frame(in: .global).origin.y
Color.clear
.preference(
key: ScrollOffsetKey.self,
value: offsetY
)
.onAppear {
scrollViewModel.setOriginOffset(offsetY)
}
}
.frame(height: 0)
}
var body: some View {
ScrollViewReader { scroll in
ScrollView(showsIndicators: false) {
scrollObservableView.id(-1)
}
.onPreferenceChange(ScrollOffsetKey.self) {
scrollViewModel.setOffset($0)
self.isStartScroll = scrollViewModel.isStartScroll
}
//
.overlay(alignment: .top) {
if isStartScroll {
GeometryReader { geo in
Button {
withAnimation {
scroll.scrollTo(-1, anchor: .center)
}
} label: {
Icon.up
.font(.nps(size: 30))
.foregroundStyle(.brandDeepBlue)
.frame(width: geo.size.width, height: isStartScroll ? 30 : 0,alignment: .center)
.padding(.init(top: 10, leading: 0, bottom: 20, trailing: 0))
.background(
LinearGradient(
colors: [.whiteSora, .whiteSora.opacity(0)],
startPoint: .top,
endPoint: .bottom)
)
}
}
}
}
}
}
}
// MARK: - modifier
struct HeightPreferenceKey: PreferenceKey {
static var defaultValue: CGFloat = 0
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value = nextValue()
}
}
// = PreferenceKey
struct ScrollOffsetKey: PreferenceKey {
static var defaultValue: CGFloat = .zero
static func reduce(value: inout CGFloat, nextValue: () -> CGFloat) {
value += nextValue()
}
}
final class ScrollViewModel: ObservableObject {
@Published var offset: CGFloat = 0
@Published var isStartScroll: Bool = false
var originOffset: CGFloat = 0
var isCheckedOriginOffset: Bool = false
func setOriginOffset(_ offset: CGFloat) {
guard !isCheckedOriginOffset else { return }
self.originOffset = offset - 30 //
self.offset = offset
isCheckedOriginOffset = true
}
func setOffset(_ offset: CGFloat) {
self.offset = offset
if self.offset < self.originOffset { isStartScroll = true }
else { isStartScroll = false }
}
}

View File

@ -0,0 +1,269 @@
//
// EDENON.swift
// JJUNGTABLE
//
// Created by Sean Kim on 6/13/24.
//
import Foundation
import Combine
/*
(5 )
)
: 12345678
: 20240612
0
1
.
- 1 0 .
)
1 2 3 4 5 6 7 8
2 0 2 4 0 6 1 2
: 03 02 05 08 05 12 08 10
2
1 (: n) 1 n번째를 2 n-1 3 n-2 .
)
03 02 05 08 05 12 08 10
: 0310 0208 0512 0805
3
2 .
1 ,
1~2 ,
1~3 .
1~4 .
)
0310 0208 0512 0805
: 0310 -> 0 -> : 310 -> = 3100
: 0208 -> 02 -> : 08 -> = 0802
: 0512 -> 051 -> : 2 -> = 2051
: 0805 -> 0805 -> : -> = 0805
: 3100 0802 2051 0805
4
3 .
)
3100 0802 2051 0805
[ ]
: 3 0 2 0
: 1 8 0 8
: 0 0 5 0
: 0 2 1 5
: 3020 1808 0050 0215
5
4 (isToggle: default = false) .
4 .
1 = A, 2 = B, 3 = C, 4 = D, 5 = E, 6 = F, 7 = G, 8 = H, 9 = I isToggle의 false면 true이면 .
0 isToggle의 Bool값을 0 1 9 (J~Z) .
0 2 0 . 4 .
)
3020 1808 0050 0215
- - isToggle
3 - C - F
0 - - T
2 - b - T
0 - - F
0000
0000 (J~Z)
1 - A - F
8 - H - F
0 - - T
8 - h - T
0000
0000 (J~Z)
0 - - F
0 - 2 - T - 0 2 2
5 - e - T
0 - - F
0000
0000 (J~Z)
0 - 2 - T - 0 0 2 2
2 - b - T
1 - a - T
5 - e - T
0000
0000 (J~Z)
: Cb AHh 2e 2bae
.
: 12345678
: 20240612
: Cb AHh 2e 2bae
*/
struct ENDC_ERROR:Error {
var caseType: CASE
var message: String
enum CASE: Error{
case EN_DIGIT
case DC_WRONG
}
}
func edon_E(value: String, key: String) -> Future<String, ENDC_ERROR> {
return Future { promise in
var result = ""
// 0:
if value.count != key.count { promise(.failure(ENDC_ERROR(caseType: .EN_DIGIT, message: "digit ERROR"))) }
/// 1: + +
/// <>
/// 1.
/// 2. 1 1 0 2
/// 3. 0 ~ index [index+1... end] .
/// 4. 3 .
/// 5. 4 String .
let sum = { () -> String in
var tempArray = ["","","",""]
let add = zip(value, key).map{
guard let first = Int(String($0)), let second = Int(String($1)) else { return ""}
return String(format: "%02d", first + second)
}
zip(add[...3],add[4...].reversed())
.map{"\($0)\($1)"}.enumerated()
.map { (index, value) in
let sumValue = value.map{$0}
return "\(String(sumValue[(index+1)...]))\(String(sumValue[...(index)]))"
}
.joined(separator: "")
.enumerated().map { (index, value) in
tempArray[index % 4] += "\(value)"
}
// print(tempArray)
// print(tempArray.joined(separator: ""))
return tempArray.joined(separator: "")
}()
// print(sum)
// print(String(Character(UnicodeScalar(73))))
//"I".unicodeScalars.first?.value
/// 2
/// [ : 65~73]
/// <>
/// 1.
var isToggle = false
var zCnt = 0
let ascii = { (value: Int) -> String in
if let scalar = UnicodeScalar(value) { return "\(scalar)" }
return ""
}
for value in sum {
if value == "0" {
isToggle.toggle()
zCnt += 1
if zCnt == 4 {
result += isToggle ? ascii(Int.random(in: 74...90)).lowercased() : ascii(Int.random(in: 74...90))
zCnt = 0
}
}
else {
if zCnt > 1 { result += "\(zCnt)" }
zCnt = 0
result += isToggle ? ascii(Int("\(value)")!+64).lowercased() : ascii(Int("\(value)")!+64)
}
}
promise(.success(result))
}
}
func edon_D(value: String, key: String) -> Future<String, ENDC_ERROR> {
return Future { promise in
var result = ""
var temp = ""
var isToggle = false
let ascii = { (value: String) -> Int in
if let scalar = value.unicodeScalars.first, let sInt = Int("\(scalar.value)") { return sInt }
return 0
}
// = 65~73, = 97~105
value.map {
if let codeNum = Int("\($0)") {
for _ in 0..<codeNum {
temp += "0"
isToggle.toggle()
}
}
else {
let code = ascii("\($0)")
if code > 64 && code < 74 {
if isToggle {
temp += "0\(code-64)"
isToggle.toggle()
}
else { temp += "\(code-64)" }
}
else if code > 96 && code < 106 {
if !isToggle {
temp += "0\(code-96)"
isToggle.toggle()
}
else { temp += "\(code-96)" }
}
else {
temp += "0000"
}
}
}
if temp.count % 4 > 0 { for _ in 0 ..< 4-(temp.count%4) { temp += "0" } }
var tempArray = ["","","",""]
temp.enumerated().map {(index,value) in tempArray[index%4] += "\(value)" }
var saveArray = [String].init(repeating: "", count: 8)
var saveTArray = [[String]]()
tempArray.enumerated().map {(index,value) in
let sepValue = value.map{$0}
saveTArray.append("\(String(sepValue[(3-index)...]))\(String(sepValue[...(3-index-1)]))".map{"\($0)"})
saveArray[index] = saveTArray[index][0...1].joined(separator: "")
saveArray[(7-index)] = saveTArray[index][2...3].joined(separator: "")
}
for (v,k) in zip(saveArray,key) {
if let value = Int(v), let key = Int("\(k)") {
if value-key > 0 { result += "\(value-key)" }
else { result += "\((value-key) * -1)" }
}
}
promise(.success(result))
}
}

View File

@ -0,0 +1,47 @@
//
// FB_Functions.swift
// CheckAnything
//
// Created by Sean Kim on 5/23/24.
//
import Foundation
import FirebaseMessaging
import FirebaseAuth
class FB_FUNC {
static var shared = FB_FUNC()
private init() {}
//CheckAnything.com
func sendPushNotification(_ title: String, body: String) {
@UserDefault (key: "fcmToken", defaultValue: "") var pushFCMToken
// let url = URL(string: "\(KEY.apiLink)send?&")!
// var request = URLRequest(url: url)
// request.httpMethod = "GET"
// let task = URLSession.shared.dataTask(with: request) { data, response, error in
// if let error = error {
// print("Error sending FCM token: \(error)")
// return
// }
// if let response = response as? HTTPURLResponse, response.statusCode == 200 {
// print("FCM token sent successfully")
// } else {
// print("Failed to send FCM token")
// }
// }
// task.resume()
}
func login(_ id: String, _ password: String, _ code: String) {
Auth.auth().signIn(withEmail: "\(id)@checkanythingemail.com", password: password) { authResult, error in
if let error = error {
printLog(error.localizedDescription)
return
}
}
}
}

View File

@ -0,0 +1,190 @@
//
// Login.swift
// JJUNGTABLE
//
// Created by Sean Kim on 6/11/24.
//
import SwiftUI
import Combine
import AuthenticationServices
import KakaoSDKCommon
import KakaoSDKAuth
import KakaoSDKUser
import Firebase
import FirebaseAuth
/*
2024-06-11 01:26:08184 [][Api.swift 136:41] -> response:
Optional({
"app_id" = 987284;
"expires_in" = 43199;
id = 3138117983;
})
__________ __________ __________ __________
* LOCATION : [ContentView.swift : 69] - body
| TIME : [2024/06/12 14:39:17:856]
> NOTE : 001273.49bfcb15b70d440a9666b4434336fc2c.0741
*/
class Login: NSObject, ObservableObject{
// let appId = "987284"
@State private var verificationCode: String = ""
@State private var verificationID: String?
private var cancellables = Set<AnyCancellable>()
private var currentPromise: Future<String, LOGIN_ERROR>.Promise?
func tryKakaoLogin() -> Future<String, LOGIN_ERROR> {
return Future { promise in
if UserApi.isKakaoTalkLoginAvailable() { //
UserApi.shared.loginWithKakaoTalk { (oauthToken, error) in
if let error = error {
promise(.failure(.init(caseType: .KAKAO_LOGIN,
message: "\(error.localizedDescription)")))
} else {
printLog("Login success.: \(oauthToken)")
self.kakaoAccessUserInfo().sink(
receiveCompletion: { completion in
if case .failure(let error) = completion {
promise(.failure(error))
}
},
receiveValue: { id in
promise(.success(id))
}
).store(in: &self.cancellables)
}
}
} else {
UserApi.shared.loginWithKakaoAccount { (oauthToken, error) in
if let error = error {
promise(.failure(.init(caseType: .KAKAO_LOGIN,
message: "\(error.localizedDescription)")))
} else {
print("Login success.")
// AccessToken
self.kakaoAccessUserInfo().sink(
receiveCompletion: { completion in
if case .failure(let error) = completion {
promise(.failure(error))
}
},
receiveValue: { id in
promise(.success(id))
}
).store(in: &self.cancellables)
}
}
}
}
}
func kakaoAccessUserInfo() -> Future<String, LOGIN_ERROR> {
return Future { promise in
UserApi.shared.me { user, error in
if let error = error {
printLog("[ERROR] Kakao me: \(error)")
promise(.failure(.init(caseType: .KAKAO_ACC_USER,
message: "\(error.localizedDescription)")))
}
else if let user = user, let id = user.id {
printLog("Access Kakao UserInfo")
promise(.success("\(id)"))
}
else {
promise(.failure(.init(caseType: .KAKAO_ACC_USER,
message: "undefined ERROR")))
}
}
}
}
}
extension Login: ASAuthorizationControllerDelegate {
func tryAppleLogin() -> Future<String, LOGIN_ERROR> {
return Future { promise in
let request = ASAuthorizationAppleIDProvider().createRequest()
// request.requestedScopes = [.fullName, .email]
let controller = ASAuthorizationController(authorizationRequests: [request])
controller.delegate = self
controller.presentationContextProvider = self
//
controller.performRequests()
self.currentPromise = promise
}
}
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
printLog("APPLE success")
if let credential = authorization.credential as? ASAuthorizationAppleIDCredential {
let userId = credential.user
currentPromise?(.success(userId))
} else {
currentPromise?(.failure(.init(caseType: .APPLE_LOGIN, message: "로그인 실패")))
}
currentPromise = nil
}
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: any Error) {
currentPromise?(.failure(.init(caseType: .APPLE_LOGIN, message: "\(error.localizedDescription)")))
currentPromise = nil
}
}
extension Login: ASAuthorizationControllerPresentationContextProviding{
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
guard let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene else {
return ASPresentationAnchor()
}
// Return the first window of the window scene
return windowScene.windows.first { $0.isKeyWindow } ?? ASPresentationAnchor()
}
}
extension Login {
func sendCodeToPhone() {
PhoneAuthProvider.provider().verifyPhoneNumber("+821034523551", uiDelegate: nil) { verificationID, error in
if let error = error {
print("Error: \(error.localizedDescription)")
return
}
// self.verificationID = verificationID
UserDefaults.standard.set(verificationID, forKey: "authVerifyID")
printLog(verificationID)
}
}
func verifyCode(code: String) {
printLog(code)
// let verificationID = UserDefaults.standard.string(forKey: "authVerifyID")
guard let verificationID = UserDefaults.standard.string(forKey: "authVerifyID") else {
printLog("Please request verification code first.")
return
}
let credential = PhoneAuthProvider.provider().credential(
withVerificationID: verificationID,
verificationCode: code
)
printLog(credential)
}
}

View File

@ -0,0 +1,55 @@
//
// BaseViewModifier.swift
// JJUNGTABLE
//
// Created by Sean Kim on 6/11/24.
//
import SwiftUI
import Combine
struct BaseViewModifier: ViewModifier {
@ObservedObject private var networkMonitor = NetworkMonitor.shared
@EnvironmentObject var viewModel: ViewModel
func body(content: Content) -> some View {
content
//
.onChange(of: networkMonitor.isConnected) { isConnectd in
if !isConnectd {
viewModel.alertData = .init(body: """
.
.
""",
button: [ButtonType(name: "확인", role: .none ,
function: {exit(1)})])
viewModel.showAlert.toggle()
}
}
//
.alert(viewModel.alertData.title,
isPresented: $viewModel.showAlert,
presenting: $viewModel.alertData) { data in
let count = data.button.count
ForEach(0 ..< count, id: \.self) { index in
let btn = data.wrappedValue.button[index]
Button(role: btn.role) {
printLog(btn)
if let function = btn.function { function() }
} label: {
Text("\(btn.name)")
}
}
} message: { data in
Text("\(data.body.wrappedValue)")
}
}
}
extension View {
func setBaseViewModifier() -> some View {
self.modifier(BaseViewModifier())
}
}

View File

@ -0,0 +1,27 @@
//
// NetworkMonitor.swift
// JJUNGTABLE
//
// Created by Sean Kim on 6/11/24.
//
import Network
import Combine
class NetworkMonitor: ObservableObject {
static let shared = NetworkMonitor()
private let monitor = NWPathMonitor()
private let queue = DispatchQueue.global(qos: .background)
@Published var isConnected: Bool = true
private init() {
monitor.pathUpdateHandler = { [weak self] path in
DispatchQueue.main.async {
self?.isConnected = (path.status == .satisfied)
}
}
monitor.start(queue: queue)
}
}

View File

@ -0,0 +1,139 @@
//
// SwiftUI_Modifier.swift
// PersonalHealthDiary
//
// Created by Sean Kim on 2/20/24.
//
import SwiftUI
extension View {
func makeSystemButton(_ systemName: String, text: String = "",color: Color = .black, img:CGFloat = 40,size: CGFloat = 20) -> some View {
modifier(BottomModifier(systemName: systemName,color: color,text: text, fontSize: size, imgSize: img))
}
func fullPage(_ backColor: Color) -> some View {
self
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(backColor)
}
func font(_ type: FontType)-> some View {
switch type {
case .Title:
return AnyView(self.modifier(TitleFont()))
case .Content:
return AnyView(self.modifier(ContentFont()))
case .Small:
return AnyView(self.modifier(SmallFont()))
}
}
}
#if canImport(UIKit)
extension View {
func hideKeyboard() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
#endif
struct BottomModifier: ViewModifier {
var systemName: String
var color: Color
var text: String
var fontSize: CGFloat
var imgSize: CGFloat
func body(content: Content) -> some View {
VStack {
Image(systemName: systemName)
.resizable().aspectRatio(contentMode: .fill)
.tint(color)
.frame(width: imgSize ,height: imgSize)
.padding(.init(top: 0, leading: 10, bottom: 0, trailing: 10))
if text != "" {
Text(text)
.tint(color)
.font(.system(size: fontSize))
.padding(.init(top: 0, leading: 0, bottom: 5, trailing: 0))
}
}
}
}
struct MenuButtonBack: ViewModifier {
func body(content: Content) -> some View {
content
.font(.nps(size: 24))
.tint(.brand)
.frame(width: 40, height: 40, alignment: .center)
.background{
RoundedRectangle(cornerRadius: 10)
.strokeBorder(.brand,
style: StrokeStyle(lineWidth: 2))
}
}
}
struct TitleFont: ViewModifier {
func body(content: Content) -> some View {
content
.font(.nps(font: .bold, size: 32))
.minimumScaleFactor(0.1)
.tint(.brand)
.frame(maxHeight: 32, alignment: .leading)
}
}
// Title 40%
struct ContentFont: ViewModifier {
func body(content: Content) -> some View {
content
.font(.nps(size: 20))
.minimumScaleFactor(0.1)
.tint(.brand)
.frame(maxHeight: 20, alignment: .leading)
}
}
// Content 30%
struct SmallFont: ViewModifier {
func body(content: Content) -> some View {
content
.font(.nps(size: 14))
.minimumScaleFactor(0.1)
.tint(.brand)
.frame(maxHeight: 14, alignment: .leading)
}
}
struct AlignmentView: ViewModifier {
enum AlignmentType {
case leading
case trailing
case top
case bottom
}
var type: AlignmentType
func body(content: Content) -> some View {
if type == .leading || type == .trailing {
HStack(spacing: 0) {
if type == .trailing { Spacer() }
content
if type == .leading { Spacer() }
}
}
else {
VStack(spacing: 0) {
if type == .bottom { Spacer() }
content
if type == .top { Spacer() }
}
}
}
}

View File

@ -0,0 +1,448 @@
//
// SwiftUI_Prefix.swift
// PersonalHealthDiary
//
// Created by Sean Kim on 2/20/24.
//
import SwiftUI
// MARK: - TYPEALIAS
typealias VOID_TO_VOID = () -> ()
// MARK: - VARIABLE
public var APPSTORE_URL = "https://itunes.apple.com/app/"
public var KEYBOARD_UP_HEIGHT: CGFloat = 46.0
enum Compare: Int{
case bigger = 0
case smaller
case equal
case error
}
// MARK: - FUNCTION
/// print
public func printLog<T>(_ object: T, _ file: String = #file, _ function: String = #function, _ line: Int = #line){
#if DEBUG
let dateString = Date().convertString("yyyy/MM/dd HH:mm:ss:SSS")
Swift.print(
// """
// __________ __________
// |* TIME = [\(dateString)] || FILE = [\(file.lastPathComponent)]
// | NAME = [\(function)] || LINE = [\(line)]
// |>>> PRINT = \(object)
//
// """
"""
__________ __________ __________ __________
* LOCATION : [\(file.lastPathComponent) : \(line)] - \(function)
| TIME : [\(dateString)]
> NOTE : \(object)
"""
)
#else
#endif
}
public func getDeviceWidth() -> CGFloat { UIScreen.main.bounds.size.width }
public func getDeviceHeight() -> CGFloat { UIScreen.main.bounds.size.height }
///
/// false
public func isIllegalDevice() -> Bool {
func canOpen(path: String) -> Bool {
let file = fopen(path, "r")
guard file != nil else { return false }
fclose(file)
return true
}
guard let cydiaUrlScheme = NSURL(string: "cydia://package/com.example.package") else { return false }
if UIApplication.shared.canOpenURL(cydiaUrlScheme as URL) {
return true
}
#if arch(i386) || arch(x86_64)
return false
#endif
let fileManager = FileManager.default
if fileManager.fileExists(atPath: "/Applications/Cydia.app") ||
fileManager.fileExists(atPath: "/Library/MobileSubstrate/MobileSubstrate.dylib") ||
fileManager.fileExists(atPath: "/bin/bash") ||
fileManager.fileExists(atPath: "/usr/sbin/sshd") ||
fileManager.fileExists(atPath: "/etc/apt") ||
fileManager.fileExists(atPath: "/usr/bin/ssh") ||
fileManager.fileExists(atPath: "/private/var/lib/apt") {
return true
}
if canOpen(path: "/Applications/Cydia.app") ||
canOpen(path: "/Library/MobileSubstrate/MobileSubstrate.dylib") ||
canOpen(path: "/bin/bash") ||
canOpen(path: "/usr/sbin/sshd") ||
canOpen(path: "/etc/apt") ||
canOpen(path: "/usr/bin/ssh") {
return true
}
let path = "/private/" + NSUUID().uuidString
do {
try "anyString".write(toFile: path, atomically: true, encoding: String.Encoding.utf8)
try fileManager.removeItem(atPath: path)
return true
} catch let error { //
printLog("Jail ERROR: \(error))")
return false
}
}
public func fontNameCheck() {
for family: String in UIFont.familyNames {
print(family)
for names : String in UIFont.fontNames(forFamilyName: family){
printLog("\(names)")
}
}
}
/// a b true ( false)
public func isBigger (_ a: Int, _ b: Int) -> Bool {
if a > b { return true } else { return false }
}
/// JSON String Dictionary
public func jsonToDict(_ input: String) -> [String: Any] {
if let jsonData = input.data(using: .utf8){
do {
if let jsonObject = try JSONSerialization.jsonObject(with: jsonData, options: []) as? [String: Any] {
return jsonObject
}
} catch let error { //
printLog("JSON ERROR: \(error))")
}
}
return [:]
}
func currentVersion() -> String {
guard let currentVer = Bundle.main.infoDictionary?["CFBundleShortVersionString"] as? String else { return "" }
return currentVer
}
func versionChange(ver: String) -> [Int] {
return ver.components(separatedBy: ["."]).map {Int($0) ?? 0}
}
/// a b OOO .
func compareVersion(_ a: String, _ b: String) -> Compare {
let aList = versionChange(ver: a)
let bList = versionChange(ver: b)
if aList.count != bList.count { return .error }
else {
for i in 0 ..< aList.count {
if aList[i] > bList[i] { return .bigger }
else if aList[i] < bList[i] { return .smaller }
}
return .equal
}
}
func copyToClipboard(_ text: String){
UIPasteboard.general.string = text
}
// MARK: - CUSTOM COMPONENTS
// MARK: - EXTENSION
extension String {
///
var lastPathComponent: String {
get {
return (self as NSString).lastPathComponent
}
}
///
func cut(start: Int, end: Int) -> String {
let startIndex = self.index(self.startIndex,offsetBy: start >= 0 ? start : 0)
let endIndex = self.index(self.startIndex,offsetBy: end >= 0 ? end : 0)
let result: String = "\(self[startIndex ..< endIndex])"
return result
}
///
func letter() -> [String] {
return self.map { String($0) }
}
/// ()
func word() -> [String] {
return self.components(separatedBy: " ")
}
/// Date() -> (Bool, Date)
func convertDate(_ dateFormat: String = "yyyyMMdd") -> (Bool, Date) {
let dateFormatter = Date().setDateFormatter(dateFormat)
if let convert = dateFormatter.date(from: self) {
return (true, convert)
} else {
return (false, Date())
}
}
///
///
/// : "[A-Z0-9a-z._%+-]+@[A-Z0-9a-z._%+-]+\\.[A-Za-z]{2,64}"
/// : "[A-Z0-9a-z._%+-]{6,12}"
func checkFilter(_ filter: String) -> Bool {
if self == "" { return false }
return self.range(of: filter, options: .regularExpression) != nil
}
/// Bool DateFormat
static func makeDateFormat(year: Bool, month: Bool, day: Bool, dayOfWeek: Bool = false, am_pm: Bool = false, hour: Bool = false,_ fullTime: Bool = true, minute: Bool = false, second: Bool = false, mSecond: Bool = false, mSDigit: Int = 1) -> String {
var dateFormat = ""
if year {
dateFormat = dateFormat + "yyyy"
}
if month {
dateFormat = dateFormat + "MM"
}
if day {
dateFormat = dateFormat + "dd"
}
if dayOfWeek {
dateFormat = dateFormat + "EEEEEE"
}
if am_pm {
dateFormat = dateFormat + "a"
}
if fullTime { // 24
if hour {
dateFormat = dateFormat + "HH"
}
} else { // 12
if hour {
dateFormat = dateFormat + "hh"
}
}
if minute {
dateFormat = dateFormat + "mm"
}
if second {
dateFormat = dateFormat + "ss"
}
if mSecond {
for _ in 0 ..< mSDigit {
dateFormat = dateFormat + "S"
}
}
return dateFormat
}
/// String
static func combineDate(year: Int, month: Int, day: Int) -> String {
return "\(year * 10000 + month * 100 + day)"
}
func stringToInt() -> Int {
if let intValue = Int(self) {
return intValue
} else {
return 0
}
}
}
extension Date {
///
///
///
var year: Int {
let dateFormatter = self.setDateFormatter("yyyy")
if let year = Int(dateFormatter.string(from: self)){
return year
} else {
return Calendar.current.component(.year, from: self)
}
}
///
///
///
var month: Int {
let dateFormatter = self.setDateFormatter("MM")
if let month = Int(dateFormatter.string(from: self)) {
return month
} else {
return Calendar.current.component(.month, from: self)
}
}
///
///
///
var day: Int {
let dateFormatter = self.setDateFormatter("dd")
if let day = Int(dateFormatter.string(from: self)) {
return day
} else {
return Calendar.current.component(.day, from: self)
}
}
///
///
/// 0~6
///
/// -1
var dayOfWeek: Int {
let dateFormatter = self.setDateFormatter("EEEEEE")
let convert = dateFormatter.string(from: self)
switch convert {
case "":
return 0
case "":
return 1
case "":
return 2
case "":
return 3
case "":
return 4
case "":
return 5
case "":
return 6
default:
return -1
}
}
func setDateFormatter(_ dateFormat: String) -> DateFormatter {
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = dateFormat
dateFormatter.timeZone = TimeZone(abbreviation: "KST")
dateFormatter.locale = Locale(identifier: "ko_kr")
return dateFormatter
}
/// String
func convertString(_ dateFormat: String = "yyyyMMdd") -> String {
let dateFormatter = self.setDateFormatter(dateFormat)
return dateFormatter.string(from: self)
}
///
///
///
func checkLeapMonth() -> Bool {
if self.year % 4 == 0 {
if self.year % 100 == 0 {
if self.year % 400 == 0 {
return true
}
} else {
return true
}
}
return false
}
///
///
///
func getLastDayOfMonth() -> Int {
switch self.month {
case 1,3,5,7,8,10,12 :
return 31
case 2:
if self.checkLeapMonth() {
return 29
} else {
return 28
}
case 4,6,9,11:
return 30
default:
return -1
}
}
}
extension Font {
enum NPS_Font : String {
case regular
case bold
var value: String {
switch self {
case .regular:
return "NPS-font-Regular"
case .bold:
return "NPS-font-Bold"
}
}
}
static func nps(font: NPS_Font = .regular, size: CGFloat = 12) -> Font {
return .custom(font.value, size: size)
}
}
extension View {
func endTextEditing() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
}
// MARK: - ANNOTATION
///
/// @UserDefault (key: "keyName", defaultValue: "default") var
/// print()
/// - UserDefaults key
/// =
/// - UserDefaults key
@propertyWrapper
struct UserDefault<T> {
private let ud: UserDefaults = .standard
private let key: String
private var defaultValue: T
var wrappedValue: T {
set { ud.set(newValue, forKey: key) }
get { ud.object(forKey: key) as? T ?? defaultValue }
}
init(key: String, defaultValue: T) {
self.key = key
self.defaultValue = defaultValue
}
///: _.removeData()
/// - _
func removeData() {
ud.removeObject(forKey: key)
}
}

View File

@ -0,0 +1,28 @@
//
// KEY.swift
// JJUNGTABLE
//
// Created by Sean Kim on 1/9/24.
//
import Foundation
enum KEY {
static let kakaoAppKey: String = "8ff66cbbf8fb74673db5c642c64dda73"
static let appStoreURL: String = ""
// public var SERVER_URL = "http://ipstein.myds.me:6004/"
#if DEVELOPE
static let apiLink: String = ""
#else
static let apiLink: String = "http://ipstein.myds.me:6000/"
#endif
static let naverGeocodingURL: String = "https://naveropenapi.apigw.ntruss.com/map-geocode/v2/geocode?"
static let naverReverseGeocodingURL: String = "https://naveropenapi.apigw.ntruss.com/map-reversegeocode/v2/gc?"
static let naverClientID = ("X-NCP-APIGW-API-KEY-ID", "qc2z3auwbq")
static let naverClientSecret = ("X-NCP-APIGW-API-KEY", "OY9b0gsIppzwvqzYMcamyBGSI3QblFsICGBBuHpN")
// web
static let githubPagesLink: String = "https://sean-59.github.io/Kakao-Postcode/"
}

View File

@ -0,0 +1,102 @@
//
// Parameter.swift
// RememberbyAnything
//
// Created by Sean Kim on 4/26/24.
//
import SwiftUI
//MARK: - Alert
enum AlertType {
case sign
}
struct AlertData {
var title: String
var body: String
var button: [ButtonType]
init(title: String = "알림", body: String, button: [ButtonType] = [.init(name: "확인", role: .none, function: nil)]) {
self.title = title
self.body = body
self.button = button
}
}
struct ButtonType {
var name: String
var role: ButtonRole?
var function: (()->())?
}
// MARK: - API ERROR
struct API_ERROR:Error {
var caseType: CASE
var message: String
enum CASE: Error{
case API_PLIST_WRONG
case API_PATH_WRONG
case API_CONNECT
case API_READ
}
}
struct LOGIN_ERROR: Error {
var caseType: CASE
var message: String
enum CASE: Error {
case KAKAO_LOGIN
case KAKAO_ACC_USER
case APPLE_LOGIN
}
}
//MARK: - FB_CRUD
struct FB_ERROR:Error {
var caseType: CASE
var message: String
enum CASE: Error{
case FB_CREATE_PARSING
case FB_CREATE_SAVING
case FB_UPDATE_DOC_READ
case FB_UPDATE_TRY
case FB_READ_PARSING
case FB_READ_PATH
case FB_READ_EXIST
case FB_DELETE_TRY
case FB_PATH_WRONG
}
}
//MARK: -
enum Role: String {
case Admin = "A"
case Tester = "T"
case Master = "M"
case Employee = "E"
}
struct userData {
var name: String
var code: String
var company: String
var role: Role
var noReadAlert: [String]
var readAlert: [String]
init(name: String, code: String, company: String, role: Role, noReadAlert: [String], readAlert: [String]) {
self.name = name
self.code = code
self.company = company
self.role = role
self.noReadAlert = noReadAlert
self.readAlert = readAlert
}
}

View File

@ -0,0 +1,84 @@
//
// UI_Func_Prefix.swift
// SwiftDataTest
//
// Created by Sean Kim on 3/27/24.
//
import SwiftUI
enum FontType {
case Title
case Content
case Small
}
enum Icon {
static let left = Image(systemName: "chevron.left")
static let right = Image(systemName: "chevron.right")
static let up = Image(systemName: "chevron.up")
static let down = Image(systemName: "chevron.down")
static let menu = Image(systemName: "line.3.horizontal")
static let house = Image(systemName: "house")
static let magazine = Image(systemName: "magazine")
static let calendar = Image(systemName: "calendar")
static let gearshape = Image(systemName: "gearshape")
static let plus = Image(systemName: "plus")
static let bookmark = Image(systemName: "bookmark")
static let bookmark_fill = Image(systemName: "bookmark.fill")
static let book = Image(systemName: "book")
static let book_closed = Image(systemName: "book.closed")
static let books = Image(systemName: "books.vertical")
static let filter = Image(systemName: "line.3.horizontal.decrease")
static let circle = Image(systemName: "circle")
static let circle_fill = Image(systemName: "circle.fill")
static let circle_check = Image(systemName: "checkmark.circle")
static let smallCircle = Image(systemName: "smallcircle.filled.circle")
static let checkmark = Image(systemName: "checkmark")
static let trash = Image(systemName: "trash")
static let xmarkCircle = Image(systemName: "xmark.circle.fill")
}
// MARK: -
enum CodeName: String{
case group = "01"
case item = "02"
}
func makeCode(_ name: CodeName) -> String{
let dateString = Date().convertString("yyyyMMddHHmmssSSS") // 17
return "\(name.rawValue):\(dateString)"
}
func generate8Code() -> String {
let letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
let digits = "0123456789"
let allCharacters = letters + digits
var code: [Character] = []
for _ in 0..<3 {
if let digit = digits.randomElement() {
code.append(digit)
}
}
for _ in 0..<5 {
if let char = allCharacters.randomElement() {
code.append(char)
}
}
code.shuffle()
return String(code)
}

View File

@ -0,0 +1,47 @@
//
// ViewModel.swift
// CheckAnything
//
// Created by Sean Kim on 5/29/24.
//
import SwiftUI
import Combine
class ViewModel: ObservableObject {
@UserDefault (key: "isUpdate", defaultValue: "N") var isUpdate
@UserDefault (key: "deviceToken", defaultValue: "") var deviceToken
@UserDefault (key: "fcmToken", defaultValue: "") var pushFCMToken
@UserDefault (key: "notiBadge", defaultValue: 0) var notiBadge
/*
@UserDefault (key: "userId", defaultValue: "") var userId
@UserDefault (key: "noReadAlertList", defaultValue: [""]) var noReadAlertList
@UserDefault (key: "errorApp", defaultValue: [String:String]()) var errorApp
*/
@Published var showAlert: Bool = false
var alertData: AlertData = .init(body: "")
// func setBadge() async {
// let center = UNUserNotificationCenter.current()
// do {
// try await center.setBadgeCount(noReadAlertList.count)
// } catch {
// // Handle any errors.
// }
// }
func systemErrorAlert() -> AlertData {
return .init(body: """
.
.
""",
button: [ButtonType(name: "확인", role: .none , function: {exit(1)})])
}
}

50
JJUNGTABLE/Document.md Normal file
View File

@ -0,0 +1,50 @@
# 계정 관련
## KAKAO
Link:https://developers.kakao.com/console/app/987284
Account: sean.kk@kakao.com
## NAVER
Link: https://console.ncloud.com/naver-service/application
Account: sean_kk@naver.com
# Protocol 관련
## 공통단으로 사용하기 위한 protocol 운영시에 Any로 값을 보내는데 해당 값을 구성하는 방식은 보내는 쪽의 (Object's Identifier: Data) 식으로 보내서 구분이 가능하게 하는게 좋을것 같다.
# 주석
## [THINKING] 의 경우 조건 생각해볼것
## Remove, test 처리 된 코드는 다 삭제 할 예정
func readDataBase(key: String, completion: @escaping (DataBase) -> Void) {
// key 가 빈값으로 올 경우 바로 Type으로 만들지만 그게 아니고 key에 다른 주소가 같이 들어온다면 그 부분을 포함해서 주소 구성
self.readDataBase(key: "go") { result in
if let check2 = result as? DB_FAILURE {
printLog(check2)
}
}
self.readDataBase(key: "") { result in
printLog(result)
}
if key == "" {
completion(DB_FAILURE(key: "out", type: .friends, errorType: .db_CreateERROR))
} else {
completion(DB_SUCCESS(key: "go", type: .getFriend))
}
}
DatabaseManager().readDataBase(.user, key: loginId) { dataBase in
if let db = dataBase as? DB_SUCCESS {
printLog(db.key)
printLog(db.value)
}
else if let db = dataBase as? DB_FAILURE {
printLog(db.key)
}
}

View File

@ -0,0 +1,32 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>API_KEY</key>
<string>AIzaSyCeHcMO2hbmfxuYaiC8BATYvLbpWdQyNxA</string>
<key>GCM_SENDER_ID</key>
<string>480609810019</string>
<key>PLIST_VERSION</key>
<string>1</string>
<key>BUNDLE_ID</key>
<string>kr.kro.sean-k.JJUNGTABLE</string>
<key>PROJECT_ID</key>
<string>jjungtable-e5087</string>
<key>STORAGE_BUCKET</key>
<string>jjungtable-e5087.appspot.com</string>
<key>IS_ADS_ENABLED</key>
<false></false>
<key>IS_ANALYTICS_ENABLED</key>
<false></false>
<key>IS_APPINVITE_ENABLED</key>
<true></true>
<key>IS_GCM_ENABLED</key>
<true></true>
<key>IS_SIGNIN_ENABLED</key>
<true></true>
<key>GOOGLE_APP_ID</key>
<string>1:480609810019:ios:9a49754201d22353462a56</string>
<key>DATABASE_URL</key>
<string>https://jjungtable-e5087-default-rtdb.firebaseio.com</string>
</dict>
</plist>

82
JJUNGTABLE/Info.plist Normal file
View File

@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>ipstein.myds.me</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</dict>
<key>ServerURL</key>
<dict>
<key>httpURL</key>
<string>http://ipstein.myds.me</string>
<key>httpsURL</key>
<string>https://ipstein.myds.me</string>
<key>PORT</key>
<string>6000</string>
</dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleTypeRole</key>
<string>Editor</string>
<key>CFBundleURLSchemes</key>
<array>
<string>kakao8ff66cbbf8fb74673db5c642c64dda73</string>
<string>app-1-480609810019-ios-9a49754201d22353462a56</string>
</array>
</dict>
</array>
<key>FirebaseAppDelegateProxyEnabled</key>
<false/>
<key>LSApplicationQueriesSchemes</key>
<array>
<string>kakaokompassauth</string>
<string>kakaolink</string>
<string>kakaoplus</string>
</array>
<key>NMFClientId</key>
<string>qc2z3auwbq</string>
<key>UIAppFonts</key>
<array>
<string>NPSfont_regular.otf</string>
<string>NPSfont_bold.otf</string>
<string>NPSfont_extrabold.otf</string>
</array>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UISceneConfigurationName</key>
<string>Default Configuration</string>
<key>UISceneDelegateClassName</key>
<string>$(PRODUCT_MODULE_NAME).SceneDelegate</string>
</dict>
</array>
</dict>
</dict>
<key>UIBackgroundModes</key>
<array>
<string>external-accessory</string>
<string>fetch</string>
<string>remote-notification</string>
</array>
</dict>
</plist>

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>aps-environment</key>
<string>development</string>
<key>com.apple.developer.applesignin</key>
<array>
<string>Default</string>
</array>
</dict>
</plist>

BIN
JJUNGTABLE/Resource/.DS_Store vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
JJUNGTABLE/View/.DS_Store vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,134 @@
//
// ContentView.swift
// JJUNGTABLE
//
// Created by Sean Kim on 3/5/24.
//
import SwiftUI
import Combine
struct ContentView: View {
@EnvironmentObject var viewModel: ViewModel
@StateObject private var login = Login()
@State private var cancellables = Set<AnyCancellable>()
@State private var selectedOption = "Option 1"
let options = ["Option 1", "Option 2", "Option 3", "Option 4"]
@State private var phoneNum = ("0000", "0000")
var body: some View {
VStack(spacing: 0) {
Spacer()
Button {
Login().tryKakaoLogin()
.sink { completion in
if case .failure(_) = completion {
viewModel.alertData = .init(body: "SNS 로그인에 실패했습니다.")
viewModel.showAlert.toggle()
}
} receiveValue: { data in
printLog(data)
API.shared.readData(path: "/db/userInfo/read",
queryItems: [
URLQueryItem(name: "id", value: data),
URLQueryItem(name: "type", value: "01")
])
.sink { completion in
switch completion {
case .finished:
break
case .failure(let error):
printLog(error)
}
} receiveValue: { data in
do {
let decoder = JSONDecoder()
let cid = try decoder.decode([UserCID].self, from: data)
printLog(cid)
} catch {
printLog(error)
self.viewModel.alertData = self.viewModel.systemErrorAlert()
self.viewModel.showAlert.toggle()
}
}
.store(in: &cancellables)
}
.store(in: &cancellables)
} label: {
Text("Kakao ID로 로그인")
.font(.nps(font: .bold, size: 32))
}
.padding(.bottom,20)
Button {
login.tryAppleLogin()
.sink { completion in
} receiveValue: { data in
printLog("APPLE ID: \(data)")
}
.store(in: &cancellables)
} label: {
Text("Apple ID로 로그인")
.font(.nps(font: .bold, size: 32))
}
HStack(spacing: 0){
Picker("Select an option", selection: $selectedOption) {
ForEach(options, id: \.self) { option in
Text(option).tag(option)
}
}
.pickerStyle(MenuPickerStyle()) // This line makes the Picker a dropdown menu
.background {
RoundedRectangle(cornerRadius: 10)
.foregroundStyle(.clear)
.frame(height: 50)
}
TextField("digit 4",text: $phoneNum.0)
TextField("last",text: $phoneNum.1)
.font(.Content)
.padding([.top,.bottom,.leading],5)
.frame(height: 50)
.cornerRadius(10)
}
.background {
RoundedRectangle(cornerRadius: 10)
.stroke(Color.brand,lineWidth: 2)
.foregroundStyle(.clear)
}
.padding()
Button {
login.sendCodeToPhone()
} label: {
Text("code")
.font(.nps(font: .bold, size: 32))
}
Button {
login.verifyCode(code: phoneNum.1)
} label: {
Text("veri")
.font(.nps(font: .bold, size: 32))
}
Spacer()
}
.fullPage(.pageBack)
.setBaseViewModifier()
}
}

236
README.md Normal file
View File

@ -0,0 +1,236 @@
README.md
# 목차
[1. 개발 일지](#개발-일지)
[2. 생각 거리](#생각-거리)
---
---
# 개발 일지
### 2024.02.27
<details>
<summary>내용</summary>
1. 새롭게 작업 진행
- 서류 작업 진행 중 : [Google Docs](https://docs.google.com/document/d/1g_SE7cnZK-gPrU62XBe27zmer31h1jtdHPL6NYA95OY/edit?usp=sharing)
</details>
### 2024.02.01
<details>
<summary>내용</summary>
1. UI Code 전환
- TopView 전환 완료
- BottomView 전환 완료
- CommonAlertVC 에 Coordinator 적용완료
- 디테일한 부분은 전환 요소 파악해서 로직 자체를 다시 짤 필요가 있어 보임
</details>
### 2024.01.29
<details>
<summary>내용</summary>
1. common 단 변화 시도 및 각종 VC들 변환 작업 중
</details>
### 2024.01.28
<details>
<summary>내용</summary>
1. UI 작성 코드들 모듈화(?) 처리를 통해서 중복되는 코드 줄임
- Common.TopView 변환 작업 중
- MainVC 변환 작업 중
</details>
### 2024.01.26
<details>
<summary>내용</summary>
1. Coordinator 패턴 적용 중
- AppCoordinator 생성
- IntroCoordinator 생성 - IntroVC 와 적용
- LoginCoordinator 생성 - LoginVC 와 적용
- MainCoordinator 생성 - MainVC 미적용
2. .xib -> SnapKit Code 전환
- IntroVC 에 대한 화면 UI 코드 전환 완료
- LoginVC 에 대한 화면 UI 코드 전환 완료
- MainVC 화면 UI 코드 전환 중
3. VC 기능 동작 확인
- IntroVC 패턴 적용하고 코드 전환 후 기능 적용 완료
- LoginVC 패턴 적용하고 코드 전환 후 기능 적용 완료
- MainVC 전환 적용 중
</details>
### 2024.01.25
<details>git
<summary>내용</summary>
1. 프로젝트 진행 방향에 대한 생각 변경
- 최대한 빠르게 만들어지는 대로 만들어서 앱을 스토어에 올릴 생각이었으나 데이터를 관리하는 서버와 DB단의 변경으로 인해서 프로젝트 자체의 대규모 변경이 필요함을 느낌
2. 변경 내용
1. iOS APP 관련
- Design Pattern 도입 (Coordinator Pattern, Observer Pattern)
- UI 작성 방식 변경 (xib -> code)
- 서버가 추가 됨으로 인해 내부 로직들 대거 변경
2. 서버 추가
- firebase 의 realTime DB를 활용한 데이터 이용을 하였으나 실 서버에 대한 필요성을 느끼게 되어 서버를 추가 하기로 결정
- 물리적인 서버는 개인 NAS가 존재하여 해당 기기를 활용
- Back 단은 Node.js 를 사용
- DB 는 MongoDB(MySQL) 를 사용
3. MongoDB 에 테이블 생성
<div align = center>
<img src ="./JJUNGTABLE/Resource/Images/tableArchitecture.png" width=300>
</div>
</details>
### 2024.01.22
<details>
<summary>내용</summary>
1. 개발 무기한 중단
- 서버 및 데이터 전환 작업
- firebase -> node.js
- firebase.realtiemDB -> MariaDB
</details>
### 2024.01.18
<details>
<summary>내용</summary>
1. 예약 PAGE 수정
- 뒤에 시간 건들고 앞에 건들면 뒤에꺼 날아가는 오류
2. Main 자체에서 오류들 발생
- 싹다 로직 전체 수정으로 해결
</details>
### 2024.01.17
<details>
<summary>내용</summary>
1. 예약 PAGE 완료
- 예약 관련 부분 완료
2. Main 자체에서 오류들 발생
- 문제
1. 처음 가입시 이름이 Name으로 표기되는 오류
2. 예약 받고 나면 떠있는 창 지우고 오늘의 일정에 해당되면 오늘의 일정에도 띄우는 작업을 진행해야 함
- 당연 예약을 준사람도 작업을 해줘야 함
3. 친구 추가 했을 떄 친구 요청을 갱신해야 받아오는데 이부분을 Main에서 하기에 해당 창 진입시 데이터 불러오게 변경
4. 오늘의 일정에서 알림 토글 부분에 문제가 있음
5. 친구cell에 있는 버튼 누르고 다른 VC 갔다가 돌아오면 친구cell 버튼이 동작을 안함
- Main 자체에 Logic에서 문제점을 다수 발생하여 해당 부분을 전면 수정 중
</details>
### 2024.01.16
<details>
<summary>내용</summary>
1. 예약 PAGE view 작동
- DB 작업해서 다른 아이디에서도 아무 이상없이 잘 뜨는지 확인 필요
2. Add Friends 부분에서 문제점이 발견
- 친구 조회가 안되는 문제가 발견
- 검색하는 DBManager 부분이 오류가 생긴듯
</details>
### 2024.01.13
<details>
<summary>내용</summary>
1. SecondReserveView 추가
- View 추가
2. reserveData 추가해서 데이터 모델변경
</details>
### 2024.01.10
<details>
<summary>내용</summary>
1. SearchAddressView 추가
- 주소 입력하는데 Map을 보여줄 필요는 없다는 판단이 들어서 해당 부분을 Kakao의 주소 검색 API를 사용하기로 함
- 따로 라이브러리로 존재하는것이 아니라 직접 HTML로 깃 허브에 올려둔 상태에서 Handler로 받아서 사용하는 WebView 형식으로 만들었음
2. ReserveView 정리
- 날짜 선택과 관련한 오류들 수정
- 빈 값인데도 스크롤이 되는 오류 수정
- 날짜, 시간, 장소 저장까지는 완료 이제 다음 예약 로직으로 넘어가면 됨
</details>
### 2024.01.09
<details>
<summary>내용</summary>
1. View 다듬기
- NaverView 와 ReserveView 가 조금더 자연스러울 수 있게 다듬기
</details>
### 2024.01.07
<details>
<summary>내용</summary>
1. MapView
- 지도의 권한 허용 팝업 멘트 설정 및 권한 동작 구현
- 현재 위치의 좌표를 받아와 현재 위치로 이동
</details>
### 2024.01.06
<details>
<summary>내용</summary>
1. ReserveView: datePicker 수정
- 오늘 날짜보다 이전 예약은 막아야 하는데 내부 로직 상 날짜 입력이 제대로 처리 되지 않아 수정
- yyyyMMdd 로 되어야 하는데 두자리 수 미만의 [월,일]이 입력되는 경우에 yyyyMd 와 같이 이상한 형태로 들어오는것을 확인 하였음
2. ReserveView: MapView_searchView 수정
- 지도 확인을 위해 띄우는 VC에서 AutoLayout 설정과 꺼졌다 켜짐 등에 대한 부분을 수정
</details>
### 2024.01.05
<details>
<summary>내용</summary>
1. Git 등록
- Local 관리를 하다가 체계적인 관리의 필요성을 다시 느껴서 작업물을 Git에 등록
2. 내부 로직 수정
- 내부 로직을 대대로 수정하면서 "InputUserInfoView" 와의 연결이 끊겨 있는 문제를 수정
</details>
---
---
# 생각 거리
### 생각중
<details>
<summary>2024.01.06</summary>
```
[ ] 1. ViewDelegate와 BaseVCDelegate 를 활용하는데 이 부분을 나중에 다른 요소로 대체를 할 수 있으면 해야 할 것으로 보임
```
> 이건 너무 과하게 전 범위를 커버치려고 하다보니 세세하게 하나하나 다 고려를 해야 하고 값을 넣어줘야 하는 문제가 있음을 느낌
</details>
### 실행
<details>
<summary>2024.01.05</summary>
```
[✓] 1. DatabaseManager의 Delegate 부분이 너무나도 불편하게 구성이 되어있음 completion 방식으로 변경 하는게 어떠할까 함
```
> 불편하게 구성이 되어있다보니 common 단으로 구성을 했음에도 불구하고 계속해서 특정 상황에 맞는 매개변수를 추가하고 하는 이상한 짓을 하게 되어서 수정을 해야 함을 느낌
</details>