AcaMate_iOS/AcaMate/5. Modifier/View.swift
2025-02-11 08:57:42 +09:00

154 lines
4.9 KiB
Swift

//
// View.swift
// AcaMate
//
// Created by Sean Kim on 12/1/24.
//
import SwiftUI
import Combine
struct NetworkModifier: ViewModifier {
@ObservedObject private var networkMonitor = NetworkMonitor.shared
@EnvironmentObject var appVM: AppViewModel
func body(content: Content) -> some View {
content
.onChange(of: networkMonitor.isConnected) { _ , new in
if !new {
appVM.alertData = SetAlertData().setErrorNetwork()
appVM.showAlert.toggle()
}
}
}
}
struct AlertModifier: ViewModifier {
@EnvironmentObject var appVM: AppViewModel
func body(content: Content) -> some View {
content
.alert(appVM.alertData.title,
isPresented: $appVM.showAlert,
presenting: $appVM.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)")
}
}
}
struct LoadingModifier: ViewModifier {
@Binding var isLoading: Bool
func body(content: Content) -> some View {
ZStack {
content
.disabled(isLoading)
.blur(radius: isLoading ? 3:0)
if isLoading {
Color.Text.detail.opacity(0.6)
// Color.Second.normal.opacity(0.3)
.ignoresSafeArea()
ProgressView("Loading...")
// .tint(Color.Text.black)
.tint(Color.Normal.normal)
.scaleEffect(1.5)
.foregroundStyle(Color.Normal.normal)
.font(.nps(font: .bold, size: 16))
.padding()
}
}
}
}
struct PressEffect: ViewModifier {
@State private var isPressed = false
var scale: CGFloat
var opacity: CGFloat
var duration: Double
func body(content: Content) -> some View {
content
.scaleEffect(isPressed ? scale : 1.0)
.opacity(isPressed ? opacity : 1.0)
.animation(.easeOut(duration: duration), value: isPressed)
.simultaneousGesture(
LongPressGesture(minimumDuration: 0.01)
.onChanged { _ in isPressed = true }
.onEnded { _ in isPressed = false }
)
}
}
struct PressBackgroundEffect: ViewModifier {
@State private var isPressed = false
var backgroundColor: Color
var duration: Double
func body(content: Content) -> some View {
content
.background(isPressed ? backgroundColor : Color.clear)
.animation(.easeOut(duration: duration), value: isPressed)
.simultaneousGesture(
LongPressGesture(minimumDuration: 0.01)
.onChanged { _ in isPressed = true }
.onEnded { _ in isPressed = false }
)
}
}
extension View {
/// View
func fullDrawView(_ backColor: Color) -> some View {
return self
.frame(maxWidth: .infinity, maxHeight: .infinity)
.background(backColor)
}
func setAlert() -> some View {
self.modifier(AlertModifier())
}
func setNetwork() -> some View {
self.modifier(NetworkModifier())
}
func endTextEditing() {
UIApplication.shared.sendAction(#selector(UIResponder.resignFirstResponder), to: nil, from: nil, for: nil)
}
func loadingView(isLoading: Binding<Bool>) -> some View {
self.modifier(LoadingModifier(isLoading: isLoading))
}
func innerShadow<S: Shape> (shape: S, color: Color, lineWidth: CGFloat = 6, blur: CGFloat, x: CGFloat, y: CGFloat) -> some View {
return self.overlay {
shape
.stroke(color, lineWidth: lineWidth)
.offset(x: x, y: y)
.blur(radius: blur)
.mask(shape.fill(LinearGradient(gradient: Gradient(colors: [.black, .clear]), startPoint: .topLeading, endPoint: .bottomTrailing)))
}
}
func pressAnimation(scale: CGFloat = 0.95, opacity: CGFloat = 0.85, duration: Double = 0.1) -> some View {
self.modifier(PressEffect(scale: scale, opacity: opacity, duration: duration))
}
}
extension View {
func pressColorAnimation(backgroundColor: Color = Color.black.opacity(0.1), duration: Double = 0.1) -> some View {
self.modifier(PressBackgroundEffect(backgroundColor: backgroundColor, duration: duration))
}
}