Files

65 lines
1.9 KiB
Swift

//
// ViewsComponentsToastOverlay.swift
// Mobile Music Assistant
//
// Created by Sven Hanold on 09.04.26.
//
import SwiftUI
// MARK: - Toast Manager
@Observable
class MAToastManager {
private(set) var message: String = ""
private(set) var icon: String = "heart.fill"
private(set) var iconColor: Color = .red
private(set) var isVisible: Bool = false
private var hideTask: Task<Void, Never>?
func show(_ message: String, icon: String = "heart.fill", iconColor: Color = .red) {
self.message = message
self.icon = icon
self.iconColor = iconColor
withAnimation(.spring(duration: 0.3)) { isVisible = true }
hideTask?.cancel()
hideTask = Task { @MainActor in
try? await Task.sleep(for: .seconds(2))
guard !Task.isCancelled else { return }
withAnimation(.easeOut(duration: 0.4)) { isVisible = false }
}
}
}
// MARK: - Toast View Modifier
struct ToastOverlayModifier: ViewModifier {
@Environment(MAToastManager.self) private var toastManager
func body(content: Content) -> some View {
content.overlay(alignment: .top) {
if toastManager.isVisible {
HStack(spacing: 8) {
Image(systemName: toastManager.icon)
.foregroundStyle(toastManager.iconColor)
Text(toastManager.message)
.font(.subheadline.weight(.medium))
.lineLimit(1)
}
.padding(.horizontal, 18)
.padding(.vertical, 11)
.background(.ultraThinMaterial, in: Capsule())
.shadow(color: .black.opacity(0.15), radius: 8, y: 4)
.padding(.top, 12)
.transition(.move(edge: .top).combined(with: .opacity))
}
}
}
}
extension View {
func withToast() -> some View {
modifier(ToastOverlayModifier())
}
}