refactor: pass globally mutable config reference
Before, copies of the configuration were passed over. This change also causes configuration reloads to affect the entire application and is easier to maintain but introduces some RwLock overhead.
This commit is contained in:
@@ -182,7 +182,7 @@ impl ListItem for Album {
|
|||||||
|
|
||||||
fn display_right(&self, library: Arc<Library>) -> String {
|
fn display_right(&self, library: Arc<Library>) -> String {
|
||||||
let saved = if library.is_saved_album(self) {
|
let saved = if library.is_saved_album(self) {
|
||||||
if library.use_nerdfont {
|
if library.cfg.values().use_nerdfont.unwrap_or(false) {
|
||||||
"\u{f62b} "
|
"\u{f62b} "
|
||||||
} else {
|
} else {
|
||||||
"✓ "
|
"✓ "
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ impl ListItem for Artist {
|
|||||||
|
|
||||||
fn display_right(&self, library: Arc<Library>) -> String {
|
fn display_right(&self, library: Arc<Library>) -> String {
|
||||||
let followed = if library.is_followed_artist(self) {
|
let followed = if library.is_followed_artist(self) {
|
||||||
if library.use_nerdfont {
|
if library.cfg.values().use_nerdfont.unwrap_or(false) {
|
||||||
"\u{f62b} "
|
"\u{f62b} "
|
||||||
} else {
|
} else {
|
||||||
"✓ "
|
"✓ "
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ pub struct CommandManager {
|
|||||||
spotify: Arc<Spotify>,
|
spotify: Arc<Spotify>,
|
||||||
queue: Arc<Queue>,
|
queue: Arc<Queue>,
|
||||||
library: Arc<Library>,
|
library: Arc<Library>,
|
||||||
|
config: Arc<Config>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CommandManager {
|
impl CommandManager {
|
||||||
@@ -39,18 +40,21 @@ impl CommandManager {
|
|||||||
spotify: Arc<Spotify>,
|
spotify: Arc<Spotify>,
|
||||||
queue: Arc<Queue>,
|
queue: Arc<Queue>,
|
||||||
library: Arc<Library>,
|
library: Arc<Library>,
|
||||||
config: &Config,
|
config: Arc<Config>,
|
||||||
) -> CommandManager {
|
) -> CommandManager {
|
||||||
|
let bindings = RefCell::new(Self::get_bindings(config.clone()));
|
||||||
CommandManager {
|
CommandManager {
|
||||||
aliases: HashMap::new(),
|
aliases: HashMap::new(),
|
||||||
bindings: RefCell::new(Self::get_bindings(config)),
|
bindings,
|
||||||
spotify,
|
spotify,
|
||||||
queue,
|
queue,
|
||||||
library,
|
library,
|
||||||
|
config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_bindings(config: &Config) -> HashMap<String, Command> {
|
pub fn get_bindings(config: Arc<Config>) -> HashMap<String, Command> {
|
||||||
|
let config = config.values();
|
||||||
let mut kb = if config.default_keybindings.unwrap_or(true) {
|
let mut kb = if config.default_keybindings.unwrap_or(true) {
|
||||||
Self::default_keybindings()
|
Self::default_keybindings()
|
||||||
} else {
|
} else {
|
||||||
@@ -161,15 +165,16 @@ impl CommandManager {
|
|||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
Command::ReloadConfig => {
|
Command::ReloadConfig => {
|
||||||
let cfg = crate::config::load()?;
|
self.config.reload();
|
||||||
|
|
||||||
// update theme
|
// update theme
|
||||||
let theme = crate::theme::load(&cfg);
|
let theme = self.config.build_theme();
|
||||||
s.set_theme(theme);
|
s.set_theme(theme);
|
||||||
|
|
||||||
// update bindings
|
// update bindings
|
||||||
self.unregister_keybindings(s);
|
self.unregister_keybindings(s);
|
||||||
self.bindings.replace(Self::get_bindings(&cfg));
|
self.bindings
|
||||||
|
.replace(Self::get_bindings(self.config.clone()));
|
||||||
self.register_keybindings(s);
|
self.register_keybindings(s);
|
||||||
Ok(None)
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::fs;
|
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::sync::RwLock;
|
use std::sync::{RwLock, RwLockReadGuard};
|
||||||
|
use std::{fs, process};
|
||||||
|
|
||||||
|
use cursive::theme::Theme;
|
||||||
use platform_dirs::AppDirs;
|
use platform_dirs::AppDirs;
|
||||||
|
|
||||||
pub const CLIENT_ID: &str = "d420a117a32841c2b3474932e49fb54b";
|
pub const CLIENT_ID: &str = "d420a117a32841c2b3474932e49fb54b";
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize, Debug, Default)]
|
#[derive(Clone, Serialize, Deserialize, Debug, Default)]
|
||||||
pub struct Config {
|
pub struct ConfigValues {
|
||||||
pub default_keybindings: Option<bool>,
|
pub default_keybindings: Option<bool>,
|
||||||
pub keybindings: Option<HashMap<String, String>>,
|
pub keybindings: Option<HashMap<String, String>>,
|
||||||
pub theme: Option<ConfigTheme>,
|
pub theme: Option<ConfigTheme>,
|
||||||
@@ -57,9 +58,40 @@ lazy_static! {
|
|||||||
pub static ref BASE_PATH: RwLock<Option<PathBuf>> = RwLock::new(None);
|
pub static ref BASE_PATH: RwLock<Option<PathBuf>> = RwLock::new(None);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load() -> Result<Config, String> {
|
pub struct Config {
|
||||||
|
values: RwLock<ConfigValues>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
let values = load().unwrap_or_else(|e| {
|
||||||
|
eprintln!("could not load config: {}", e);
|
||||||
|
process::exit(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
Self {
|
||||||
|
values: RwLock::new(values),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn values(&self) -> RwLockReadGuard<ConfigValues> {
|
||||||
|
self.values.read().expect("can't readlock config values")
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build_theme(&self) -> Theme {
|
||||||
|
let theme = &self.values().theme;
|
||||||
|
crate::theme::load(theme)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn reload(&self) {
|
||||||
|
let cfg = load().expect("could not reload config");
|
||||||
|
*self.values.write().expect("can't writelock config values") = cfg
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn load() -> Result<ConfigValues, String> {
|
||||||
let path = config_path("config.toml");
|
let path = config_path("config.toml");
|
||||||
load_or_generate_default(path, |_| Ok(Config::default()), false)
|
load_or_generate_default(path, |_| Ok(ConfigValues::default()), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn proj_dirs() -> AppDirs {
|
fn proj_dirs() -> AppDirs {
|
||||||
|
|||||||
@@ -36,11 +36,11 @@ pub struct Library {
|
|||||||
user_id: Option<String>,
|
user_id: Option<String>,
|
||||||
ev: EventManager,
|
ev: EventManager,
|
||||||
spotify: Arc<Spotify>,
|
spotify: Arc<Spotify>,
|
||||||
pub use_nerdfont: bool,
|
pub cfg: Arc<Config>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Library {
|
impl Library {
|
||||||
pub fn new(ev: &EventManager, spotify: Arc<Spotify>, use_nerdfont: bool) -> Self {
|
pub fn new(ev: &EventManager, spotify: Arc<Spotify>, cfg: Arc<Config>) -> Self {
|
||||||
let user_id = spotify.current_user().map(|u| u.id);
|
let user_id = spotify.current_user().map(|u| u.id);
|
||||||
|
|
||||||
let library = Self {
|
let library = Self {
|
||||||
@@ -53,7 +53,7 @@ impl Library {
|
|||||||
user_id,
|
user_id,
|
||||||
ev: ev.clone(),
|
ev: ev.clone(),
|
||||||
spotify,
|
spotify,
|
||||||
use_nerdfont,
|
cfg,
|
||||||
};
|
};
|
||||||
|
|
||||||
library.update_library();
|
library.update_library();
|
||||||
@@ -66,10 +66,6 @@ impl Library {
|
|||||||
.expect("could not readlock listview content")
|
.expect("could not readlock listview content")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn config(&self) -> &Config {
|
|
||||||
&self.spotify.cfg
|
|
||||||
}
|
|
||||||
|
|
||||||
fn load_cache<T: DeserializeOwned>(&self, cache_path: PathBuf, store: Arc<RwLock<Vec<T>>>) {
|
fn load_cache<T: DeserializeOwned>(&self, cache_path: PathBuf, store: Arc<RwLock<Vec<T>>>) {
|
||||||
if let Ok(contents) = std::fs::read_to_string(&cache_path) {
|
if let Ok(contents) = std::fs::read_to_string(&cache_path) {
|
||||||
debug!("loading cache from {}", cache_path.display());
|
debug!("loading cache from {}", cache_path.display());
|
||||||
|
|||||||
28
src/main.rs
28
src/main.rs
@@ -77,6 +77,7 @@ mod mpris;
|
|||||||
|
|
||||||
use crate::command::{Command, JumpMode};
|
use crate::command::{Command, JumpMode};
|
||||||
use crate::commands::CommandManager;
|
use crate::commands::CommandManager;
|
||||||
|
use crate::config::Config;
|
||||||
use crate::events::{Event, EventManager};
|
use crate::events::{Event, EventManager};
|
||||||
use crate::library::Library;
|
use crate::library::Library;
|
||||||
use crate::spotify::PlayerEvent;
|
use crate::spotify::PlayerEvent;
|
||||||
@@ -189,10 +190,7 @@ fn main() {
|
|||||||
|
|
||||||
// Things here may cause the process to abort; we must do them before creating curses windows
|
// Things here may cause the process to abort; we must do them before creating curses windows
|
||||||
// otherwise the error message will not be seen by a user
|
// otherwise the error message will not be seen by a user
|
||||||
let cfg: crate::config::Config = config::load().unwrap_or_else(|e| {
|
let cfg: Arc<crate::config::Config> = Arc::new(Config::new());
|
||||||
eprintln!("{}", e);
|
|
||||||
process::exit(1);
|
|
||||||
});
|
|
||||||
|
|
||||||
let cache = Cache::new(config::cache_path("librespot"), true);
|
let cache = Cache::new(config::cache_path("librespot"), true);
|
||||||
let mut credentials = {
|
let mut credentials = {
|
||||||
@@ -218,9 +216,8 @@ fn main() {
|
|||||||
credentials = credentials_prompt(reset, Some(error_msg));
|
credentials = credentials_prompt(reset, Some(error_msg));
|
||||||
}
|
}
|
||||||
|
|
||||||
let theme = theme::load(&cfg);
|
|
||||||
|
|
||||||
let mut cursive = Cursive::default();
|
let mut cursive = Cursive::default();
|
||||||
|
let theme = cfg.build_theme();
|
||||||
cursive.set_theme(theme.clone());
|
cursive.set_theme(theme.clone());
|
||||||
|
|
||||||
let event_manager = EventManager::new(cursive.cb_sink().clone());
|
let event_manager = EventManager::new(cursive.cb_sink().clone());
|
||||||
@@ -228,22 +225,18 @@ fn main() {
|
|||||||
let spotify = Arc::new(spotify::Spotify::new(
|
let spotify = Arc::new(spotify::Spotify::new(
|
||||||
event_manager.clone(),
|
event_manager.clone(),
|
||||||
credentials,
|
credentials,
|
||||||
&cfg,
|
cfg.clone(),
|
||||||
));
|
));
|
||||||
|
|
||||||
let queue = Arc::new(queue::Queue::new(spotify.clone()));
|
let queue = Arc::new(queue::Queue::new(spotify.clone(), cfg.clone()));
|
||||||
|
|
||||||
#[cfg(feature = "mpris")]
|
#[cfg(feature = "mpris")]
|
||||||
let mpris_manager = Arc::new(mpris::MprisManager::new(spotify.clone(), queue.clone()));
|
let mpris_manager = Arc::new(mpris::MprisManager::new(spotify.clone(), queue.clone()));
|
||||||
|
|
||||||
let library = Arc::new(Library::new(
|
let library = Arc::new(Library::new(&event_manager, spotify.clone(), cfg.clone()));
|
||||||
&event_manager,
|
|
||||||
spotify.clone(),
|
|
||||||
cfg.use_nerdfont.unwrap_or(false),
|
|
||||||
));
|
|
||||||
|
|
||||||
let mut cmd_manager =
|
let mut cmd_manager =
|
||||||
CommandManager::new(spotify.clone(), queue.clone(), library.clone(), &cfg);
|
CommandManager::new(spotify.clone(), queue.clone(), library.clone(), cfg.clone());
|
||||||
|
|
||||||
cmd_manager.register_all();
|
cmd_manager.register_all();
|
||||||
cmd_manager.register_keybindings(&mut cursive);
|
cmd_manager.register_keybindings(&mut cursive);
|
||||||
@@ -262,8 +255,11 @@ fn main() {
|
|||||||
|
|
||||||
let queueview = ui::queue::QueueView::new(queue.clone(), library.clone());
|
let queueview = ui::queue::QueueView::new(queue.clone(), library.clone());
|
||||||
|
|
||||||
let status =
|
let status = ui::statusbar::StatusBar::new(
|
||||||
ui::statusbar::StatusBar::new(queue.clone(), library, cfg.use_nerdfont.unwrap_or(false));
|
queue.clone(),
|
||||||
|
library,
|
||||||
|
cfg.values().use_nerdfont.unwrap_or(false),
|
||||||
|
);
|
||||||
|
|
||||||
let mut layout = ui::layout::Layout::new(status, &event_manager, theme)
|
let mut layout = ui::layout::Layout::new(status, &event_manager, theme)
|
||||||
.view("search", search.with_name("search"), "Search")
|
.view("search", search.with_name("search"), "Search")
|
||||||
|
|||||||
@@ -134,7 +134,7 @@ impl ListItem for Playlist {
|
|||||||
|
|
||||||
fn display_right(&self, library: Arc<Library>) -> String {
|
fn display_right(&self, library: Arc<Library>) -> String {
|
||||||
let saved = if library.is_saved_playlist(self) {
|
let saved = if library.is_saved_playlist(self) {
|
||||||
if library.use_nerdfont {
|
if library.cfg.values().use_nerdfont.unwrap_or(false) {
|
||||||
"\u{f62b} "
|
"\u{f62b} "
|
||||||
} else {
|
} else {
|
||||||
"✓ "
|
"✓ "
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use notify_rust::Notification;
|
|||||||
use rand::prelude::*;
|
use rand::prelude::*;
|
||||||
use strum_macros::Display;
|
use strum_macros::Display;
|
||||||
|
|
||||||
|
use crate::config::Config;
|
||||||
use crate::playable::Playable;
|
use crate::playable::Playable;
|
||||||
use crate::spotify::Spotify;
|
use crate::spotify::Spotify;
|
||||||
|
|
||||||
@@ -23,16 +24,18 @@ pub struct Queue {
|
|||||||
current_track: RwLock<Option<usize>>,
|
current_track: RwLock<Option<usize>>,
|
||||||
repeat: RwLock<RepeatSetting>,
|
repeat: RwLock<RepeatSetting>,
|
||||||
spotify: Arc<Spotify>,
|
spotify: Arc<Spotify>,
|
||||||
|
cfg: Arc<Config>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Queue {
|
impl Queue {
|
||||||
pub fn new(spotify: Arc<Spotify>) -> Queue {
|
pub fn new(spotify: Arc<Spotify>, cfg: Arc<Config>) -> Queue {
|
||||||
let q = Queue {
|
let q = Queue {
|
||||||
queue: Arc::new(RwLock::new(Vec::new())),
|
queue: Arc::new(RwLock::new(Vec::new())),
|
||||||
spotify,
|
spotify,
|
||||||
current_track: RwLock::new(None),
|
current_track: RwLock::new(None),
|
||||||
repeat: RwLock::new(RepeatSetting::None),
|
repeat: RwLock::new(RepeatSetting::None),
|
||||||
random_order: RwLock::new(None),
|
random_order: RwLock::new(None),
|
||||||
|
cfg,
|
||||||
};
|
};
|
||||||
q.set_repeat(q.spotify.repeat);
|
q.set_repeat(q.spotify.repeat);
|
||||||
q.set_shuffle(q.spotify.shuffle);
|
q.set_shuffle(q.spotify.shuffle);
|
||||||
@@ -248,7 +251,7 @@ impl Queue {
|
|||||||
let mut current = self.current_track.write().unwrap();
|
let mut current = self.current_track.write().unwrap();
|
||||||
current.replace(index);
|
current.replace(index);
|
||||||
self.spotify.update_track();
|
self.spotify.update_track();
|
||||||
if self.spotify.cfg.notify.unwrap_or(false) {
|
if self.cfg.values().notify.unwrap_or(false) {
|
||||||
#[cfg(feature = "notify")]
|
#[cfg(feature = "notify")]
|
||||||
if let Err(e) = Notification::new().summary(&track.to_string()).show() {
|
if let Err(e) = Notification::new().summary(&track.to_string()).show() {
|
||||||
error!("error showing notification: {:?}", e);
|
error!("error showing notification: {:?}", e);
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ impl ListItem for Show {
|
|||||||
|
|
||||||
fn display_right(&self, library: Arc<Library>) -> String {
|
fn display_right(&self, library: Arc<Library>) -> String {
|
||||||
let saved = if library.is_saved_show(self) {
|
let saved = if library.is_saved_show(self) {
|
||||||
if library.use_nerdfont {
|
if library.cfg.values().use_nerdfont.unwrap_or(false) {
|
||||||
"\u{f62b} "
|
"\u{f62b} "
|
||||||
} else {
|
} else {
|
||||||
"✓ "
|
"✓ "
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ use core::task::Poll;
|
|||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::atomic::{AtomicU16, Ordering};
|
use std::sync::atomic::{AtomicU16, Ordering};
|
||||||
use std::sync::RwLock;
|
use std::sync::{Arc, RwLock};
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
use std::{env, io};
|
use std::{env, io};
|
||||||
@@ -84,7 +84,7 @@ pub enum PlayerEvent {
|
|||||||
pub struct Spotify {
|
pub struct Spotify {
|
||||||
events: EventManager,
|
events: EventManager,
|
||||||
credentials: Credentials,
|
credentials: Credentials,
|
||||||
pub cfg: config::Config,
|
cfg: Arc<config::Config>,
|
||||||
status: RwLock<PlayerEvent>,
|
status: RwLock<PlayerEvent>,
|
||||||
api: RwLock<SpotifyAPI>,
|
api: RwLock<SpotifyAPI>,
|
||||||
elapsed: RwLock<Option<Duration>>,
|
elapsed: RwLock<Option<Duration>>,
|
||||||
@@ -246,15 +246,19 @@ impl futures::Future for Worker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Spotify {
|
impl Spotify {
|
||||||
pub fn new(events: EventManager, credentials: Credentials, cfg: &config::Config) -> Spotify {
|
pub fn new(
|
||||||
let volume = match &cfg.saved_state {
|
events: EventManager,
|
||||||
|
credentials: Credentials,
|
||||||
|
cfg: Arc<config::Config>,
|
||||||
|
) -> Spotify {
|
||||||
|
let volume = match &cfg.values().saved_state {
|
||||||
Some(state) => match state.volume {
|
Some(state) => match state.volume {
|
||||||
Some(vol) => ((std::cmp::min(vol, 100) as f32) / 100.0 * 65535_f32).ceil() as u16,
|
Some(vol) => ((std::cmp::min(vol, 100) as f32) / 100.0 * 65535_f32).ceil() as u16,
|
||||||
None => 0xFFFF as u16,
|
None => 0xFFFF as u16,
|
||||||
},
|
},
|
||||||
None => 0xFFFF as u16,
|
None => 0xFFFF as u16,
|
||||||
};
|
};
|
||||||
let repeat = match &cfg.saved_state {
|
let repeat = match &cfg.values().saved_state {
|
||||||
Some(state) => match &state.repeat {
|
Some(state) => match &state.repeat {
|
||||||
Some(s) => match s.as_str() {
|
Some(s) => match s.as_str() {
|
||||||
"track" => queue::RepeatSetting::RepeatTrack,
|
"track" => queue::RepeatSetting::RepeatTrack,
|
||||||
@@ -265,7 +269,7 @@ impl Spotify {
|
|||||||
},
|
},
|
||||||
_ => queue::RepeatSetting::None,
|
_ => queue::RepeatSetting::None,
|
||||||
};
|
};
|
||||||
let shuffle = match &cfg.saved_state {
|
let shuffle = match &cfg.values().saved_state {
|
||||||
Some(state) => matches!(&state.shuffle, Some(true)),
|
Some(state) => matches!(&state.shuffle, Some(true)),
|
||||||
None => false,
|
None => false,
|
||||||
};
|
};
|
||||||
@@ -273,7 +277,7 @@ impl Spotify {
|
|||||||
let mut spotify = Spotify {
|
let mut spotify = Spotify {
|
||||||
events,
|
events,
|
||||||
credentials,
|
credentials,
|
||||||
cfg: cfg.clone(),
|
cfg,
|
||||||
status: RwLock::new(PlayerEvent::Stopped),
|
status: RwLock::new(PlayerEvent::Stopped),
|
||||||
api: RwLock::new(SpotifyAPI::default()),
|
api: RwLock::new(SpotifyAPI::default()),
|
||||||
elapsed: RwLock::new(None),
|
elapsed: RwLock::new(None),
|
||||||
@@ -306,7 +310,14 @@ impl Spotify {
|
|||||||
let volume = self.volume();
|
let volume = self.volume();
|
||||||
let credentials = self.credentials.clone();
|
let credentials = self.credentials.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
Self::worker(events, Box::pin(rx), cfg, credentials, user_tx, volume)
|
Self::worker(
|
||||||
|
events,
|
||||||
|
Box::pin(rx),
|
||||||
|
cfg.clone(),
|
||||||
|
credentials,
|
||||||
|
user_tx,
|
||||||
|
volume,
|
||||||
|
)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -349,7 +360,7 @@ impl Spotify {
|
|||||||
let session_config = Self::session_config();
|
let session_config = Self::session_config();
|
||||||
let cache = Cache::new(
|
let cache = Cache::new(
|
||||||
config::cache_path("librespot"),
|
config::cache_path("librespot"),
|
||||||
cfg.audio_cache.unwrap_or(true),
|
cfg.values().audio_cache.unwrap_or(true),
|
||||||
);
|
);
|
||||||
let handle = core.handle();
|
let handle = core.handle();
|
||||||
debug!("opening spotify session");
|
debug!("opening spotify session");
|
||||||
@@ -391,12 +402,12 @@ impl Spotify {
|
|||||||
fn worker(
|
fn worker(
|
||||||
events: EventManager,
|
events: EventManager,
|
||||||
commands: Pin<Box<mpsc::UnboundedReceiver<WorkerCommand>>>,
|
commands: Pin<Box<mpsc::UnboundedReceiver<WorkerCommand>>>,
|
||||||
cfg: config::Config,
|
cfg: Arc<config::Config>,
|
||||||
credentials: Credentials,
|
credentials: Credentials,
|
||||||
user_tx: Option<oneshot::Sender<String>>,
|
user_tx: Option<oneshot::Sender<String>>,
|
||||||
volume: u16,
|
volume: u16,
|
||||||
) {
|
) {
|
||||||
let bitrate_str = cfg.bitrate.unwrap_or(320).to_string();
|
let bitrate_str = cfg.values().bitrate.unwrap_or(320).to_string();
|
||||||
let bitrate = Bitrate::from_str(&bitrate_str);
|
let bitrate = Bitrate::from_str(&bitrate_str);
|
||||||
if bitrate.is_err() {
|
if bitrate.is_err() {
|
||||||
error!("invalid bitrate, will use 320 instead")
|
error!("invalid bitrate, will use 320 instead")
|
||||||
@@ -405,8 +416,8 @@ impl Spotify {
|
|||||||
let player_config = PlayerConfig {
|
let player_config = PlayerConfig {
|
||||||
gapless: false,
|
gapless: false,
|
||||||
bitrate: bitrate.unwrap_or(Bitrate::Bitrate320),
|
bitrate: bitrate.unwrap_or(Bitrate::Bitrate320),
|
||||||
normalisation: cfg.volnorm.unwrap_or(false),
|
normalisation: cfg.values().volnorm.unwrap_or(false),
|
||||||
normalisation_pregain: cfg.volnorm_pregain.unwrap_or(0.0),
|
normalisation_pregain: cfg.values().volnorm_pregain.unwrap_or(0.0),
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut core = Core::new().unwrap();
|
let mut core = Core::new().unwrap();
|
||||||
@@ -419,12 +430,12 @@ impl Spotify {
|
|||||||
let mixer = create_mixer(None);
|
let mixer = create_mixer(None);
|
||||||
mixer.set_volume(volume);
|
mixer.set_volume(volume);
|
||||||
|
|
||||||
let backend = audio_backend::find(cfg.backend.clone()).unwrap();
|
let backend = audio_backend::find(cfg.values().backend.clone()).unwrap();
|
||||||
let (player, player_events) = Player::new(
|
let (player, player_events) = Player::new(
|
||||||
player_config,
|
player_config,
|
||||||
session.clone(),
|
session.clone(),
|
||||||
mixer.get_audio_filter(),
|
mixer.get_audio_filter(),
|
||||||
move || (backend)(cfg.backend_device),
|
move || (backend)(cfg.values().backend_device.clone()),
|
||||||
);
|
);
|
||||||
|
|
||||||
let worker = Worker::new(
|
let worker = Worker::new(
|
||||||
|
|||||||
55
src/theme.rs
55
src/theme.rs
@@ -3,11 +3,11 @@ use cursive::theme::Color::*;
|
|||||||
use cursive::theme::PaletteColor::*;
|
use cursive::theme::PaletteColor::*;
|
||||||
use cursive::theme::*;
|
use cursive::theme::*;
|
||||||
|
|
||||||
use crate::config::Config;
|
use crate::config::ConfigTheme;
|
||||||
|
|
||||||
macro_rules! load_color {
|
macro_rules! load_color {
|
||||||
( $cfg: expr, $member: ident, $default: expr ) => {
|
( $theme: expr, $member: ident, $default: expr ) => {
|
||||||
$cfg.theme
|
$theme
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.and_then(|t| t.$member.clone())
|
.and_then(|t| t.$member.clone())
|
||||||
.map(|c| Color::parse(c.as_ref()).expect(&format!("Failed to parse color \"{}\"", c)))
|
.map(|c| Color::parse(c.as_ref()).expect(&format!("Failed to parse color \"{}\"", c)))
|
||||||
@@ -15,41 +15,50 @@ macro_rules! load_color {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load(cfg: &Config) -> Theme {
|
pub fn load(theme_cfg: &Option<ConfigTheme>) -> Theme {
|
||||||
let mut palette = Palette::default();
|
let mut palette = Palette::default();
|
||||||
let borders = BorderStyle::Simple;
|
let borders = BorderStyle::Simple;
|
||||||
|
|
||||||
palette[Background] = load_color!(cfg, background, TerminalDefault);
|
palette[Background] = load_color!(theme_cfg, background, TerminalDefault);
|
||||||
palette[View] = load_color!(cfg, background, TerminalDefault);
|
palette[View] = load_color!(theme_cfg, background, TerminalDefault);
|
||||||
palette[Primary] = load_color!(cfg, primary, TerminalDefault);
|
palette[Primary] = load_color!(theme_cfg, primary, TerminalDefault);
|
||||||
palette[Secondary] = load_color!(cfg, secondary, Dark(Blue));
|
palette[Secondary] = load_color!(theme_cfg, secondary, Dark(Blue));
|
||||||
palette[TitlePrimary] = load_color!(cfg, title, Dark(Red));
|
palette[TitlePrimary] = load_color!(theme_cfg, title, Dark(Red));
|
||||||
palette[Tertiary] = load_color!(cfg, highlight, TerminalDefault);
|
palette[Tertiary] = load_color!(theme_cfg, highlight, TerminalDefault);
|
||||||
palette[Highlight] = load_color!(cfg, highlight_bg, Dark(Red));
|
palette[Highlight] = load_color!(theme_cfg, highlight_bg, Dark(Red));
|
||||||
palette.set_color("playing", load_color!(cfg, playing, Dark(Blue)));
|
palette.set_color("playing", load_color!(theme_cfg, playing, Dark(Blue)));
|
||||||
palette.set_color(
|
palette.set_color(
|
||||||
"playing_selected",
|
"playing_selected",
|
||||||
load_color!(cfg, playing_selected, Light(Blue)),
|
load_color!(theme_cfg, playing_selected, Light(Blue)),
|
||||||
);
|
);
|
||||||
palette.set_color("playing_bg", load_color!(cfg, playing_bg, TerminalDefault));
|
palette.set_color(
|
||||||
palette.set_color("error", load_color!(cfg, error, TerminalDefault));
|
"playing_bg",
|
||||||
palette.set_color("error_bg", load_color!(cfg, error_bg, Dark(Red)));
|
load_color!(theme_cfg, playing_bg, TerminalDefault),
|
||||||
|
);
|
||||||
|
palette.set_color("error", load_color!(theme_cfg, error, TerminalDefault));
|
||||||
|
palette.set_color("error_bg", load_color!(theme_cfg, error_bg, Dark(Red)));
|
||||||
palette.set_color(
|
palette.set_color(
|
||||||
"statusbar_progress",
|
"statusbar_progress",
|
||||||
load_color!(cfg, statusbar_progress, Dark(Blue)),
|
load_color!(theme_cfg, statusbar_progress, Dark(Blue)),
|
||||||
);
|
);
|
||||||
palette.set_color(
|
palette.set_color(
|
||||||
"statusbar_progress_bg",
|
"statusbar_progress_bg",
|
||||||
load_color!(cfg, statusbar_progress_bg, Light(Black)),
|
load_color!(theme_cfg, statusbar_progress_bg, Light(Black)),
|
||||||
);
|
);
|
||||||
palette.set_color("statusbar", load_color!(cfg, statusbar, Dark(Yellow)));
|
palette.set_color("statusbar", load_color!(theme_cfg, statusbar, Dark(Yellow)));
|
||||||
palette.set_color(
|
palette.set_color(
|
||||||
"statusbar_bg",
|
"statusbar_bg",
|
||||||
load_color!(cfg, statusbar_bg, TerminalDefault),
|
load_color!(theme_cfg, statusbar_bg, TerminalDefault),
|
||||||
|
);
|
||||||
|
palette.set_color("cmdline", load_color!(theme_cfg, cmdline, TerminalDefault));
|
||||||
|
palette.set_color(
|
||||||
|
"cmdline_bg",
|
||||||
|
load_color!(theme_cfg, cmdline_bg, TerminalDefault),
|
||||||
|
);
|
||||||
|
palette.set_color(
|
||||||
|
"search_match",
|
||||||
|
load_color!(theme_cfg, search_match, Light(Red)),
|
||||||
);
|
);
|
||||||
palette.set_color("cmdline", load_color!(cfg, cmdline, TerminalDefault));
|
|
||||||
palette.set_color("cmdline_bg", load_color!(cfg, cmdline_bg, TerminalDefault));
|
|
||||||
palette.set_color("search_match", load_color!(cfg, search_match, Light(Red)));
|
|
||||||
|
|
||||||
Theme {
|
Theme {
|
||||||
shadow: false,
|
shadow: false,
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ impl ListItem for Track {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn display_center(&self, library: Arc<Library>) -> String {
|
fn display_center(&self, library: Arc<Library>) -> String {
|
||||||
if library.config().album_column.unwrap_or(true) {
|
if library.cfg.values().album_column.unwrap_or(true) {
|
||||||
self.album.to_string()
|
self.album.to_string()
|
||||||
} else {
|
} else {
|
||||||
"".to_string()
|
"".to_string()
|
||||||
@@ -163,7 +163,7 @@ impl ListItem for Track {
|
|||||||
|
|
||||||
fn display_right(&self, library: Arc<Library>) -> String {
|
fn display_right(&self, library: Arc<Library>) -> String {
|
||||||
let saved = if library.is_saved_track(&Playable::Track(self.clone())) {
|
let saved = if library.is_saved_track(&Playable::Track(self.clone())) {
|
||||||
if library.use_nerdfont {
|
if library.cfg.values().use_nerdfont.unwrap_or(false) {
|
||||||
"\u{f62b} "
|
"\u{f62b} "
|
||||||
} else {
|
} else {
|
||||||
"✓ "
|
"✓ "
|
||||||
|
|||||||
Reference in New Issue
Block a user