Favorites, Queue, Now Playing improved
This commit is contained in:
@@ -0,0 +1,127 @@
|
||||
//
|
||||
// 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
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user