Files
sodalive-ios/SodaLive/Sources/Common/BaseView.swift

135 lines
3.6 KiB
Swift

//
// BaseView.swift
// SodaLive
//
// Created by klaus on 2023/08/09.
//
import SwiftUI
struct BaseView<Content: View>: View {
let content: Content
@Binding var isLoading: Bool
init(isLoading: Binding<Bool> = .constant(false), @ViewBuilder content: () -> Content) {
self._isLoading = isLoading
self.content = content()
}
var body: some View {
ZStack {
Color.black.ignoresSafeArea()
content
if isLoading {
LoadingView()
}
}
}
}
struct BaseView_Previews: PreviewProvider {
static var previews: some View {
BaseView(isLoading: .constant(false)) {}
}
}
private struct SodaToastModifier: ViewModifier {
@Binding var isPresented: Bool
let message: String
let autohideIn: Double
private let toastBackgroundColor = Color(
red: 59.0 / 255.0,
green: 185.0 / 255.0,
blue: 241.0 / 255.0,
opacity: 0.92
)
@State private var dismissWorkItem: DispatchWorkItem?
func body(content: Content) -> some View {
content
.overlay(alignment: .top) {
GeometryReader { geo in
if isPresented, !message.isEmpty {
Text(message)
.appFont(size: 12, weight: .medium)
.foregroundColor(.white)
.multilineTextAlignment(.center)
.lineLimit(2)
.padding(.horizontal, 18)
.padding(.vertical, 12)
.background(
Capsule()
.fill(toastBackgroundColor)
)
.overlay(
Capsule()
.stroke(Color.white.opacity(0.15), lineWidth: 1)
)
.padding(.top, geo.safeAreaInsets.top + 8)
.padding(.horizontal, 24)
.frame(maxWidth: .infinity, alignment: .top)
.transition(.move(edge: .top).combined(with: .opacity))
}
}
.allowsHitTesting(false)
}
.animation(.easeInOut(duration: 0.2), value: isPresented)
.onAppear {
if isPresented {
scheduleDismiss()
}
}
.onChange(of: isPresented) { newValue in
if newValue {
scheduleDismiss()
} else {
cancelDismiss()
}
}
.onDisappear {
cancelDismiss()
}
}
private func scheduleDismiss() {
cancelDismiss()
guard autohideIn > 0 else {
return
}
let workItem = DispatchWorkItem {
withAnimation {
isPresented = false
}
}
dismissWorkItem = workItem
DispatchQueue.main.asyncAfter(deadline: .now() + autohideIn, execute: workItem)
}
private func cancelDismiss() {
dismissWorkItem?.cancel()
dismissWorkItem = nil
}
}
extension View {
func sodaToast(isPresented: Binding<Bool>, message: String, autohideIn: Double = 2) -> some View {
modifier(
SodaToastModifier(
isPresented: isPresented,
message: message,
autohideIn: autohideIn
)
)
}
}