[✨] 네트워크 감지 기능 + 화면 전환 위한 최상단 뷰의 초기 모델 생성
This commit is contained in:
parent
3e4aa99a18
commit
eb726b0c7d
Binary file not shown.
|
@ -44,8 +44,8 @@ class AppDelegate: NSObject, UIApplicationDelegate, UNUserNotificationCenterDele
|
|||
}
|
||||
center.delegate = self
|
||||
|
||||
//MARK: - 네트워크 모니터 초기화
|
||||
// _ = NetworkMonitor.shared
|
||||
//MARK: - 네트워크 모니터 초기화
|
||||
_ = NetworkMonitor.shared
|
||||
|
||||
printLog("End Set AppDelegate")
|
||||
return true
|
||||
|
|
84
AcaMate/1. View/0. Common/NavigationView.swift
Normal file
84
AcaMate/1. View/0. Common/NavigationView.swift
Normal file
|
@ -0,0 +1,84 @@
|
|||
//
|
||||
// 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()
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
|
||||
}
|
|
@ -10,65 +10,67 @@ import Combine
|
|||
|
||||
struct IntroView: View {
|
||||
@State var cancellables: Set<AnyCancellable> = []
|
||||
@Binding var naviState : NaviState
|
||||
|
||||
var body: some View {
|
||||
NavigationStack {
|
||||
VStack(spacing: 0) {
|
||||
Spacer()
|
||||
.frame(height: 100)
|
||||
VStack(spacing: 0) {
|
||||
Spacer()
|
||||
.frame(height: 100)
|
||||
Image("Team_Icon")
|
||||
.resizable()
|
||||
.frame(width: 200, height: 200)
|
||||
.background(.white)
|
||||
.border(.black)
|
||||
.padding()
|
||||
Spacer()
|
||||
HStack(spacing: 4) {
|
||||
Image("Team_Icon")
|
||||
.resizable()
|
||||
.frame(width: 200, height: 200)
|
||||
.background(.white)
|
||||
.border(.black)
|
||||
.padding()
|
||||
Spacer()
|
||||
HStack(spacing: 4) {
|
||||
Image("Team_Icon")
|
||||
.resizable()
|
||||
.frame(width: 24, height: 24)
|
||||
Text("STEIN")
|
||||
.font(.nps(font: .bold, size: 16))
|
||||
.foregroundStyle(Color(.Text.detail))
|
||||
}
|
||||
.padding(.bottom,12)
|
||||
Text("Copyright © Team.Stein")
|
||||
.font(.nps(font: .regular, size: 14))
|
||||
.frame(width: 24, height: 24)
|
||||
Text("STEIN")
|
||||
.font(.nps(font: .bold, size: 16))
|
||||
.foregroundStyle(Color(.Text.detail))
|
||||
.padding(.bottom,50)
|
||||
}
|
||||
.fullView(.Normal.normal)
|
||||
.onAppear {
|
||||
printLog("IntroView_onAppear")
|
||||
loadVersion()
|
||||
.sink { completion in
|
||||
switch completion {
|
||||
case .failure(let error):
|
||||
printLog(error)
|
||||
case .finished: break
|
||||
}
|
||||
} receiveValue: { version in
|
||||
switch compareVersion(version.force_ver, currentVersion()){
|
||||
.padding(.bottom,12)
|
||||
Text("Copyright © Team.Stein")
|
||||
.font(.nps(font: .regular, size: 14))
|
||||
.foregroundStyle(Color(.Text.detail))
|
||||
.padding(.bottom,50)
|
||||
}
|
||||
.fullView(.Normal.normal)
|
||||
.onAppear {
|
||||
printLog("IntroView_onAppear")
|
||||
loadVersion()
|
||||
.sink { completion in
|
||||
switch completion {
|
||||
case .failure(let error):
|
||||
printLog(error)
|
||||
case .finished: break
|
||||
}
|
||||
} receiveValue: { version in
|
||||
switch compareVersion(version.force_ver, currentVersion()){
|
||||
case .bigger:
|
||||
printLog("강제 업데이트")
|
||||
default:
|
||||
switch compareVersion(version.final_ver, currentVersion()) {
|
||||
case .bigger:
|
||||
printLog("강제 업데이트")
|
||||
default:
|
||||
switch compareVersion(version.final_ver, currentVersion()) {
|
||||
case .bigger:
|
||||
if version.choice_update_yn {
|
||||
printLog("선택 업데이트")
|
||||
}
|
||||
else {
|
||||
printLog("정상 동작")
|
||||
}
|
||||
default:
|
||||
printLog("선택 업데이트 넘어감")
|
||||
if version.choice_update_yn {
|
||||
printLog("선택 업데이트")
|
||||
}
|
||||
else {
|
||||
printLog("정상 동작")
|
||||
naviState.set(act: .RESET, path: .Login)
|
||||
}
|
||||
default:
|
||||
printLog("선택 업데이트 넘어감")
|
||||
naviState.set(act: .MOVE, path: .Login)
|
||||
|
||||
}
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
}
|
||||
.store(in: &cancellables)
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -105,11 +107,11 @@ struct IntroView: View {
|
|||
private func versionChange(ver: String) -> [Int] {
|
||||
return ver.components(separatedBy: ["."]).map {Int($0) ?? 0}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
#Preview {
|
||||
IntroView()
|
||||
}
|
||||
|
||||
|
||||
|
||||
//#Preview {
|
||||
// IntroView(path: $NavigationPath())
|
||||
//}
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
import SwiftUI
|
||||
|
||||
struct LoginView: View {
|
||||
@Binding var naviState : NaviState
|
||||
|
||||
var body: some View {
|
||||
VStack(spacing: 0) {
|
||||
Image("Team_Icon")
|
||||
|
@ -34,12 +36,18 @@ struct LoginView: View {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
Button {
|
||||
naviState.set(act: .MOVE,path: .Intro)
|
||||
} label: {
|
||||
Text("111111111")
|
||||
}
|
||||
.padding()
|
||||
}
|
||||
.fullView(.Normal.normal)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#Preview {
|
||||
LoginView()
|
||||
}
|
||||
//#Preview {
|
||||
// LoginView()
|
||||
//}
|
||||
|
|
47
AcaMate/4. Model/Navigation.swift
Normal file
47
AcaMate/4. Model/Navigation.swift
Normal 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
|
||||
}
|
27
AcaMate/5. Modifier/Network.swift
Normal file
27
AcaMate/5. Modifier/Network.swift
Normal 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)
|
||||
}
|
||||
}
|
|
@ -6,9 +6,23 @@
|
|||
//
|
||||
|
||||
import SwiftUI
|
||||
import Combine
|
||||
|
||||
struct NetworkModifier: ViewModifier {
|
||||
@ObservedObject private var networkMonitor = NetworkMonitor.shared
|
||||
|
||||
func body(content: Content) -> some View {
|
||||
content
|
||||
.onChange(of: networkMonitor.isConnected) { _ , new in
|
||||
if new {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension View {
|
||||
func fullView(_ backColor: Color) -> some View{
|
||||
func fullView(_ backColor: Color) -> some View {
|
||||
return self
|
||||
.frame(maxWidth: .infinity, maxHeight: .infinity)
|
||||
.background(backColor)
|
||||
|
@ -17,4 +31,10 @@ extension View {
|
|||
func endTextEditing() {
|
||||
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
|
||||
}
|
||||
|
||||
func setNavigaion() -> some View {
|
||||
self
|
||||
.navigationBarBackButtonHidden(true)
|
||||
.toolbar(.hidden, for: .navigationBar)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ struct AcaMateApp: App {
|
|||
|
||||
var body: some Scene {
|
||||
WindowGroup {
|
||||
IntroView().onOpenURL { url in
|
||||
NavigationView().onOpenURL { url in
|
||||
if (AuthApi.isKakaoTalkLoginUrl(url)) {
|
||||
_ = AuthController.handleOpenUrl(url: url)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user