152 lines
5.5 KiB
Swift
152 lines
5.5 KiB
Swift
|
|
//
|
||
|
|
// SettingsView.swift
|
||
|
|
// iris
|
||
|
|
//
|
||
|
|
// Settings UI for music source selection and Spotify connection.
|
||
|
|
//
|
||
|
|
|
||
|
|
import MusicKit
|
||
|
|
import SwiftUI
|
||
|
|
|
||
|
|
@available(iOS 16.0, *)
|
||
|
|
struct SettingsView: View {
|
||
|
|
@EnvironmentObject private var orchestrator: ContextOrchestrator
|
||
|
|
@EnvironmentObject private var spotifyAuth: SpotifyAuthManager
|
||
|
|
|
||
|
|
var body: some View {
|
||
|
|
NavigationStack {
|
||
|
|
List {
|
||
|
|
Section("Music Source") {
|
||
|
|
Picker("Source", selection: Binding(
|
||
|
|
get: { orchestrator.musicSource },
|
||
|
|
set: { newValue in
|
||
|
|
if newValue == .spotify && !spotifyAuth.isConnected {
|
||
|
|
return
|
||
|
|
}
|
||
|
|
orchestrator.musicSource = newValue
|
||
|
|
}
|
||
|
|
)) {
|
||
|
|
ForEach(MusicSource.allCases, id: \.self) { source in
|
||
|
|
Text(source.displayName).tag(source)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
.pickerStyle(.segmented)
|
||
|
|
|
||
|
|
if !spotifyAuth.isConnected {
|
||
|
|
Text("Connect Spotify below to enable it as a source")
|
||
|
|
.font(.caption)
|
||
|
|
.foregroundStyle(.secondary)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Section {
|
||
|
|
if spotifyAuth.isConnected {
|
||
|
|
HStack {
|
||
|
|
Label("Connected", systemImage: "checkmark.circle.fill")
|
||
|
|
.foregroundColor(.green)
|
||
|
|
Spacer()
|
||
|
|
}
|
||
|
|
Button("Disconnect", role: .destructive) {
|
||
|
|
spotifyAuth.disconnect()
|
||
|
|
if orchestrator.musicSource == .spotify {
|
||
|
|
orchestrator.musicSource = .appleMusic
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
Button {
|
||
|
|
spotifyAuth.startAuth()
|
||
|
|
} label: {
|
||
|
|
HStack {
|
||
|
|
Label("Connect to Spotify", systemImage: "link")
|
||
|
|
Spacer()
|
||
|
|
if spotifyAuth.isAuthenticating {
|
||
|
|
ProgressView()
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
.disabled(spotifyAuth.isAuthenticating)
|
||
|
|
}
|
||
|
|
|
||
|
|
if let error = spotifyAuth.error {
|
||
|
|
Text(error)
|
||
|
|
.font(.caption)
|
||
|
|
.foregroundColor(.red)
|
||
|
|
}
|
||
|
|
} header: {
|
||
|
|
Text("Spotify")
|
||
|
|
} footer: {
|
||
|
|
if !spotifyAuth.isConnected {
|
||
|
|
Text("Connect your Spotify account to display current track on Glass.")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Section {
|
||
|
|
HStack {
|
||
|
|
Text("Authorization")
|
||
|
|
Spacer()
|
||
|
|
Text(authStatusText(orchestrator.musicAuthorization))
|
||
|
|
.foregroundStyle(.secondary)
|
||
|
|
}
|
||
|
|
} header: {
|
||
|
|
Text("Apple Music")
|
||
|
|
}
|
||
|
|
|
||
|
|
Section {
|
||
|
|
if let nowPlayingInfo = currentNowPlaying {
|
||
|
|
VStack(alignment: .leading, spacing: 4) {
|
||
|
|
Text(nowPlayingInfo.title)
|
||
|
|
.font(.headline)
|
||
|
|
if let artist = nowPlayingInfo.artist {
|
||
|
|
Text(artist)
|
||
|
|
.font(.subheadline)
|
||
|
|
.foregroundStyle(.secondary)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
Text("Nothing playing")
|
||
|
|
.foregroundStyle(.secondary)
|
||
|
|
}
|
||
|
|
} header: {
|
||
|
|
Text("Now Playing")
|
||
|
|
} footer: {
|
||
|
|
Text("Source: \(orchestrator.musicSource.displayName)")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
.navigationTitle("Settings")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private var currentNowPlaying: (title: String, artist: String?)? {
|
||
|
|
switch orchestrator.musicSource {
|
||
|
|
case .appleMusic:
|
||
|
|
guard let np = orchestrator.nowPlaying else { return nil }
|
||
|
|
return (np.title, np.artist)
|
||
|
|
case .spotify:
|
||
|
|
guard let np = orchestrator.spotifyNowPlaying else { return nil }
|
||
|
|
return (np.title, np.artist)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
private func authStatusText(_ status: MusicAuthorization.Status) -> String {
|
||
|
|
switch status {
|
||
|
|
case .notDetermined: return "Not Determined"
|
||
|
|
case .denied: return "Denied"
|
||
|
|
case .restricted: return "Restricted"
|
||
|
|
case .authorized: return "Authorized"
|
||
|
|
@unknown default: return "Unknown"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
@available(iOS 16.0, *)
|
||
|
|
struct SettingsView_Previews: PreviewProvider {
|
||
|
|
static var previews: some View {
|
||
|
|
let ble = BlePeripheralManager()
|
||
|
|
let spotifyAuth = SpotifyAuthManager()
|
||
|
|
let orchestrator = ContextOrchestrator(ble: ble, spotifyAuth: spotifyAuth)
|
||
|
|
SettingsView()
|
||
|
|
.environmentObject(orchestrator)
|
||
|
|
.environmentObject(spotifyAuth)
|
||
|
|
}
|
||
|
|
}
|