use anyhow::{Context, Result};
use ratatui::crossterm::event::{KeyCode, KeyEvent};
use rspotify::AuthCodePkceSpotify;
use rspotify::prelude::*;
use crate::auth;
#[derive(Clone)]
pub struct DeviceEntry {
pub name: String,
pub id: Option<String>,
pub type_label: String,
pub volume: Option<u32>,
pub is_active: bool,
pub is_restricted: bool,
}
pub struct DevicePickerState {
pub items: Vec<DeviceEntry>,
pub selected: usize,
pub message: Option<String>,
}
pub enum DeviceAction {
None,
Close,
Transfer,
Reload,
}
pub fn key_action(key: KeyEvent, state: &mut DevicePickerState) -> DeviceAction {
match key.code {
KeyCode::Esc => DeviceAction::Close,
KeyCode::Up => {
state.selected = state.selected.saturating_sub(1);
DeviceAction::None
}
KeyCode::Down => {
if state.selected + 1 < state.items.len() {
state.selected += 1;
}
DeviceAction::None
}
KeyCode::Enter => DeviceAction::Transfer,
KeyCode::Char('r') => DeviceAction::Reload,
_ => DeviceAction::None,
}
}
pub async fn fetch(spotify: &AuthCodePkceSpotify) -> Result<Vec<DeviceEntry>> {
auth::ensure_fresh_token(spotify).await?;
let devices = spotify
.device()
.await
.context("failed to fetch the device list")?;
Ok(devices
.into_iter()
.map(|d| DeviceEntry {
name: d.name,
id: d.id,
type_label: format!("{:?}", d._type),
volume: d.volume_percent,
is_active: d.is_active,
is_restricted: d.is_restricted,
})
.collect())
}
pub async fn transfer(spotify: &AuthCodePkceSpotify, id: &str) -> Result<()> {
auth::ensure_fresh_token(spotify).await?;
spotify
.transfer_playback(id, Some(true))
.await
.context("failed to transfer playback to the device")?;
Ok(())
}