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

Reviewed-on: https://git.ipstein.myds.me/AcaMate/AcaMate_iOS/pulls/2
This commit is contained in:
김선규 2024-12-13 08:49:57 +00:00
commit 584ab61cdc
11 changed files with 390 additions and 71 deletions

View File

@ -45,7 +45,7 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
center.delegate = self center.delegate = self
//MARK: - //MARK: -
// _ = NetworkMonitor.shared _ = NetworkMonitor.shared
printLog("End Set AppDelegate") printLog("End Set AppDelegate")
return true return true

View File

@ -0,0 +1,87 @@
//
// NavigationView.swift
// AcaMate
//
// Created by Sean Kim on 12/12/24.
//
import SwiftUI
import Combine
struct NavigationView: View {
@State private var naviState : NaviState = .init(act: .NONE, path: .Intro)
@State private var history: [PathName] = [.Intro]
var body: some View {
ZStack {
switch naviState.path {
case .NONE:
EmptyView()
case .Intro:
IntroView(naviState: $naviState)
case .Login :
LoginView(naviState: $naviState)
case .Main:
EmptyView()
}
}
.onChange(of: naviState) { old, new in
switch new.act {
case .NONE:
break
case .ADD:
addHistory(path: new.path)
case .POP:
popHistory()
case .RESET:
resetHistory(path: new.path)
case .MOVE:
moveHistory(path: new.path)
}
// LOG
printLog("\(old.path) => \(new.path)")
showHistory()
}
.fullView(.Normal.normal)
.setAlert()
.setNetwork()
}
private func addHistory(path: PathName) {
history.append(path)
}
private func popHistory() {
history.removeLast()
naviState.set(act: .NONE, path: history.last ?? .NONE)
}
private func resetHistory(path: PathName) {
history.removeAll()
addHistory(path: path)
}
private func moveHistory(path: PathName) {
if path == .NONE {
naviState.set(act: .RESET, path: history.first ?? .Main)
}
if history.contains(path) {
let remove = history.count - history.firstIndex(of: path)! - 1
history.removeLast(remove)
if remove > 0 {
naviState.set(act: .NONE, path: path)
return
}
}
naviState.set(act: .RESET, path: path)
}
private func showHistory() {
printLog(history)
}
}

View File

@ -9,10 +9,11 @@ import SwiftUI
import Combine import Combine
struct IntroView: View { struct IntroView: View {
@EnvironmentObject var alertController: AlertController
@State var cancellables: Set<AnyCancellable> = [] @State var cancellables: Set<AnyCancellable> = []
@Binding var naviState : NaviState
var body: some View { var body: some View {
NavigationStack {
VStack(spacing: 0) { VStack(spacing: 0) {
Spacer() Spacer()
.frame(height: 100) .frame(height: 100)
@ -37,9 +38,10 @@ struct IntroView: View {
.foregroundStyle(Color(.Text.detail)) .foregroundStyle(Color(.Text.detail))
.padding(.bottom,50) .padding(.bottom,50)
} }
.fullView(.Normal.normal)
.onAppear { .onAppear {
printLog("IntroView_onAppear") printLog("IntroView_onAppear")
subscribeAlertAction()
loadVersion() loadVersion()
.sink { completion in .sink { completion in
switch completion { switch completion {
@ -48,21 +50,20 @@ struct IntroView: View {
case .finished: break case .finished: break
} }
} receiveValue: { version in } receiveValue: { version in
switch compareVersion(version.force_ver, currentVersion()){ let compareForce = compareVersion(version.force_ver, currentVersion())
case .bigger: let compareChoice = compareVersion(version.final_ver, currentVersion())
printLog("강제 업데이트") if compareForce == .bigger {
default: alertController.alertData = SetAlertData().setForceUpdate(
switch compareVersion(version.final_ver, currentVersion()) { action: alertController.alertAction
case .bigger: )
if version.choice_update_yn { alertController.showAlert.toggle()
printLog("선택 업데이트") } else if compareChoice == .bigger && version.choice_update_yn {
} alertController.alertData = SetAlertData().setSelectUpdate(
else { action: alertController.alertAction
printLog("정상 동작") )
} alertController.showAlert.toggle()
default: } else {
printLog("선택 업데이트 넘어감") naviState.set(act: .RESET, path: .Login)
}
} }
} }
.store(in: &cancellables) .store(in: &cancellables)
@ -70,6 +71,18 @@ struct IntroView: View {
} }
} }
private func subscribeAlertAction() {
alertController.alertAction
.compactMap { $0 }
.sink { action in
if action == "updateNow" {
exit(1)
//MARK: - TODO ( )
} else {
naviState.set(act: .RESET, path: .Login)
}
}.store(in: &cancellables)
} }
@ -105,11 +118,11 @@ struct IntroView: View {
private func versionChange(ver: String) -> [Int] { private func versionChange(ver: String) -> [Int] {
return ver.components(separatedBy: ["."]).map {Int($0) ?? 0} return ver.components(separatedBy: ["."]).map {Int($0) ?? 0}
} }
} }
#Preview {
IntroView()
}
//#Preview {
// IntroView(path: $NavigationPath())
//}

View File

@ -8,6 +8,9 @@
import SwiftUI import SwiftUI
struct LoginView: View { struct LoginView: View {
@EnvironmentObject var alertController: AlertController
@Binding var naviState : NaviState
var body: some View { var body: some View {
VStack(spacing: 0) { VStack(spacing: 0) {
Image("Team_Icon") Image("Team_Icon")
@ -34,12 +37,21 @@ struct LoginView: View {
} }
} }
Button {
alertController.alertData = SetAlertData().setTest()
alertController.showAlert.toggle()
// naviState.set(act: .MOVE,path: .Intro)
} label: {
Text("111111111")
}
.padding()
} }
.fullView(.Normal.normal) .fullView(.Normal.normal)
} }
} }
#Preview { //#Preview {
LoginView() // LoginView()
} //}

View File

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

View File

@ -6,6 +6,7 @@
// //
import SwiftUI import SwiftUI
import Combine
struct AlertData { struct AlertData {
var title: String var title: String
@ -24,3 +25,62 @@ struct ButtonType {
var role: ButtonRole? var role: ButtonRole?
var function: (()->())? var function: (()->())?
} }
struct SetAlertData {
func setTest() -> AlertData {
return AlertData(title: "TEST", body: "TEST용 알럿 입니다.",
button: [
ButtonType(name: "테스트", role: .cancel,
function: {
printLog("테스트 중입니다.")
})
])
}
///
func setForceUpdate(action: CurrentValueSubject<String?, Never>) -> AlertData {
return AlertData(title: "업데이트 안내",
body: """
.
.
""",
button: [
ButtonType(name: "업데이트 하기", role: .none,
function: {
action.send("updateNow")
})
])
}
///
func setSelectUpdate (action: CurrentValueSubject<String?, Never>) -> AlertData {
return AlertData(title: "업데이트 안내",
body: """
.
?
""",
button: [
ButtonType(name: "지금 업데이트", role: .cancel,
function: {
action.send("updateNow")
}),
ButtonType(name: "나중에", role: .none,
function: {
action.send("updateLater")
}),
])
}
///
func setErrorNetwork() -> AlertData {
return AlertData(title: "네트워크 오류", body: "네트워크가 불안정합니다.\n확인 후 다시 시도해주세요.",
button: [
ButtonType(name: "확인", role: .cancel, function: nil)
])
}
}

View File

@ -0,0 +1,47 @@
//
// Navigation.swift
// AcaMate
//
// Created by Sean Kim on 12/13/24.
//
import Foundation
struct NaviState: Equatable {
var act: NaviAction
var path: PathName
static func == (lhs: NaviState, rhs: NaviState) -> Bool {
return lhs.act == rhs.act && lhs.path == rhs.path
}
mutating func set(act: NaviAction = .ADD, path: PathName = .NONE) {
self.act = act
self.path = path
}
}
enum NaviAction: Hashable {
///
case ADD
///
case RESET
///
case POP
/// (path == NONE )
case MOVE
///
case NONE
/// FIRST = , MOVE =
}
enum PathName: Hashable {
case Intro
case Login
case Main
case NONE
}

View File

@ -0,0 +1,27 @@
//
// Network.swift
// AcaMate
//
// Created by Sean Kim on 12/10/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

@ -6,6 +6,44 @@
// //
import SwiftUI import SwiftUI
import Combine
struct NetworkModifier: ViewModifier {
@ObservedObject private var networkMonitor = NetworkMonitor.shared
@EnvironmentObject var alertController: AlertController
func body(content: Content) -> some View {
content
.onChange(of: networkMonitor.isConnected) { _ , new in
if !new {
alertController.alertData = SetAlertData().setErrorNetwork()
alertController.showAlert.toggle()
}
}
}
}
struct AlertModifier: ViewModifier {
@EnvironmentObject var controller: AlertController
func body(content: Content) -> some View {
content
.alert(controller.alertData.title,
isPresented: $controller.showAlert,
presenting: $controller.alertData) { data in
let btnCount = data.button.count
ForEach(0 ..< btnCount, id: \.self) { index in
let btn = data.wrappedValue.button[index]
Button(role: btn.role) {
if let function = btn.function { function() }
} label: {
Text("\(btn.name)")
}
}
} message: { data in
Text("\(data.body.wrappedValue)")
}
}
}
extension View { extension View {
func fullView(_ backColor: Color) -> some View { func fullView(_ backColor: Color) -> some View {
@ -14,7 +52,20 @@ extension View {
.background(backColor) .background(backColor)
} }
func setAlert() -> some View {
self.modifier(AlertModifier())
}
func setNetwork() -> some View {
self.modifier(NetworkModifier())
}
func endTextEditing() { func endTextEditing() {
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 {
self
.navigationBarBackButtonHidden(true)
.toolbar(.hidden, for: .navigationBar)
}
} }

View File

@ -15,6 +15,7 @@ import KakaoSDKAuth
struct AcaMateApp: App { struct AcaMateApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
var cancellables: Set<AnyCancellable> = [] var cancellables: Set<AnyCancellable> = []
var alertController = AlertController()
init() { init() {
printLog("APP INIT") printLog("APP INIT")
@ -22,11 +23,13 @@ struct AcaMateApp: App {
var body: some Scene { var body: some Scene {
WindowGroup { WindowGroup {
IntroView().onOpenURL { url in NavigationView()
.onOpenURL { url in
if (AuthApi.isKakaoTalkLoginUrl(url)) { if (AuthApi.isKakaoTalkLoginUrl(url)) {
_ = AuthController.handleOpenUrl(url: url) _ = AuthController.handleOpenUrl(url: url)
} }
} }
.environmentObject(self.alertController)
} }
} }
} }