// // ProviderBadge.swift // Mobile Music Assistant // // Created by Sven Hanold on 06.04.26. // import SwiftUI /// Small monochrome badge indicating which music provider an item comes from. /// Uses the URI scheme first, then falls back to the image provider field. struct ProviderBadge: View { let uri: String var imageProvider: String? = nil private var provider: MusicProvider? { // Try URI scheme first (provider-specific items like subsonic://...) if let fromScheme = MusicProvider.from(scheme: URL(string: uri)?.scheme), fromScheme != .library { return fromScheme } // Fall back to the image provider metadata if let imageProvider, let fromImage = MusicProvider.from(providerKey: imageProvider) { return fromImage } // URI scheme is library:// and no image provider — show library badge if URL(string: uri)?.scheme?.lowercased() == "library" { return .library } return nil } var body: some View { if let provider { Image(systemName: provider.icon) .font(.system(size: 9, weight: .bold)) .foregroundStyle(.white) .frame(width: 20, height: 20) .background(.black.opacity(0.55)) .clipShape(Circle()) } } } // MARK: - Provider Mapping enum MusicProvider { case library case subsonic case spotify case tidal case qobuz case plex case ytmusic case appleMusic case deezer case soundcloud case tunein case filesystem case jellyfin case dlna /// SF Symbol name for this provider. var icon: String { switch self { case .library: return "building.columns.fill" case .subsonic: return "sailboat.fill" case .spotify: return "antenna.radiowaves.left.and.right.circle.fill" case .tidal: return "water.waves" case .qobuz: return "hifispeaker.fill" case .plex: return "play.square.stack.fill" case .ytmusic: return "play.rectangle.fill" case .appleMusic: return "applelogo" case .deezer: return "waveform" case .soundcloud: return "cloud.fill" case .tunein: return "radio.fill" case .filesystem: return "folder.fill" case .jellyfin: return "server.rack" case .dlna: return "wifi" } } /// Match a URI scheme to a known provider. static func from(scheme: String?) -> MusicProvider? { guard let scheme = scheme?.lowercased() else { return nil } if scheme == "library" { return .library } if scheme.hasPrefix("subsonic") { return .subsonic } if scheme.hasPrefix("spotify") { return .spotify } if scheme.hasPrefix("tidal") { return .tidal } if scheme.hasPrefix("qobuz") { return .qobuz } if scheme.hasPrefix("plex") { return .plex } if scheme.hasPrefix("ytmusic") { return .ytmusic } if scheme.hasPrefix("apple") { return .appleMusic } if scheme.hasPrefix("deezer") { return .deezer } if scheme.hasPrefix("soundcloud") { return .soundcloud } if scheme.hasPrefix("tunein") { return .tunein } if scheme.hasPrefix("filesystem") { return .filesystem } if scheme.hasPrefix("jellyfin") { return .jellyfin } if scheme.hasPrefix("dlna") { return .dlna } return nil } /// Match a provider key from image metadata (e.g. "subsonic", "spotify", "filesystem_local"). static func from(providerKey key: String) -> MusicProvider? { let k = key.lowercased() if k.hasPrefix("subsonic") { return .subsonic } if k.hasPrefix("spotify") { return .spotify } if k.hasPrefix("tidal") { return .tidal } if k.hasPrefix("qobuz") { return .qobuz } if k.hasPrefix("plex") { return .plex } if k.hasPrefix("ytmusic") { return .ytmusic } if k.hasPrefix("apple") { return .appleMusic } if k.hasPrefix("deezer") { return .deezer } if k.hasPrefix("soundcloud") { return .soundcloud } if k.hasPrefix("tunein") { return .tunein } if k.hasPrefix("filesystem") { return .filesystem } if k.hasPrefix("jellyfin") { return .jellyfin } if k.hasPrefix("dlna") { return .dlna } // Common image-only providers — not a music source if k == "lastfm" || k == "musicbrainz" || k == "fanarttv" { return nil } return nil } }