65 lines
1.9 KiB
Swift
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())
|
|
}
|
|
}
|