Add tabview, add playlists to search

This commit is contained in:
KoffeinFlummi
2019-03-28 13:47:04 +01:00
parent d2dc2f0ecc
commit 3c7b3e3618
5 changed files with 176 additions and 12 deletions

View File

@@ -108,7 +108,7 @@ impl Playlists {
}
}
fn process_playlist(list: &SimplifiedPlaylist, spotify: &Spotify) -> Playlist {
pub fn process_playlist(list: &SimplifiedPlaylist, spotify: &Spotify) -> Playlist {
debug!("got list: {}", list.name);
let id = list.id.clone();

View File

@@ -15,7 +15,7 @@ use rspotify::spotify::client::ApiError;
use rspotify::spotify::client::Spotify as SpotifyAPI;
use rspotify::spotify::model::page::Page;
use rspotify::spotify::model::playlist::{PlaylistTrack, SimplifiedPlaylist};
use rspotify::spotify::model::search::SearchTracks;
use rspotify::spotify::model::search::{SearchTracks, SearchPlaylists};
use failure::Error;
@@ -428,10 +428,14 @@ impl Spotify {
result.map(|r| r.id)
}
pub fn search(&self, query: &str, limit: u32, offset: u32) -> Option<SearchTracks> {
pub fn search_track(&self, query: &str, limit: u32, offset: u32) -> Option<SearchTracks> {
self.api_with_retry(|api| api.search_track(query, limit, offset, None))
}
pub fn search_playlist(&self, query: &str, limit: u32, offset: u32) -> Option<SearchPlaylists> {
self.api_with_retry(|api| api.search_playlist(query, limit, offset, None))
}
pub fn current_user_playlist(
&self,
limit: u32,

View File

@@ -5,3 +5,4 @@ pub mod playlists;
pub mod queue;
pub mod search;
pub mod statusbar;
pub mod tabview;

View File

@@ -10,16 +10,19 @@ use std::cell::RefCell;
use std::sync::{Arc, Mutex, RwLock};
use commands::CommandResult;
use playlists::{Playlist, Playlists};
use queue::Queue;
use spotify::Spotify;
use track::Track;
use traits::ViewExt;
use ui::listview::ListView;
use ui::tabview::TabView;
pub struct SearchView {
results: Arc<RwLock<Vec<Track>>>,
results_tracks: Arc<RwLock<Vec<Track>>>,
results_playlists: Arc<RwLock<Vec<Playlist>>>,
edit: IdView<EditView>,
list: IdView<ListView<Track>>,
list: IdView<TabView>,
edit_focused: bool,
spotify: Arc<Spotify>,
}
@@ -28,7 +31,8 @@ pub const LIST_ID: &str = "search_list";
pub const EDIT_ID: &str = "search_edit";
impl SearchView {
pub fn new(spotify: Arc<Spotify>, queue: Arc<Queue>) -> SearchView {
let results = Arc::new(RwLock::new(Vec::new()));
let results_tracks = Arc::new(RwLock::new(Vec::new()));
let results_playlists = Arc::new(RwLock::new(Vec::new()));
let searchfield = EditView::new()
.on_submit(move |s, input| {
@@ -40,14 +44,18 @@ impl SearchView {
}
})
.with_id(EDIT_ID);
let list = ListView::new(results.clone(), queue).with_id(LIST_ID);
let tabs = TabView::new()
.tab("tracks", "Tracks", ListView::new(results_tracks.clone(), queue.clone()))
.tab("playlists", "Playlists", ListView::new(results_playlists.clone(), queue.clone()));
SearchView {
results,
results_tracks,
results_playlists,
edit: searchfield,
list,
list: tabs.with_id(LIST_ID),
edit_focused: true,
spotify,
spotify
}
}
@@ -66,17 +74,29 @@ impl SearchView {
v.set_content(q);
});
if let Some(results) = self.spotify.search(&query, 50, 0) {
if let Some(results) = self.spotify.search_track(&query, 50, 0) {
let tracks = results
.tracks
.items
.iter()
.map(|ft| Track::new(ft))
.collect();
let mut r = self.results.write().unwrap();
let mut r = self.results_tracks.write().unwrap();
*r = tracks;
self.edit_focused = false;
}
if let Some(results) = self.spotify.search_playlist(&query, 50, 0) {
let pls = results
.playlists
.items
.iter()
.map(|sp| Playlists::process_playlist(sp, &&self.spotify))
.collect();
let mut r = self.results_playlists.write().unwrap();
*r = pls;
self.edit_focused = false;
}
}
}

139
src/ui/tabview.rs Normal file
View File

@@ -0,0 +1,139 @@
use std::cmp::{max, min};
use std::collections::HashMap;
use cursive::align::HAlign;
use cursive::theme::{ColorStyle, ColorType, PaletteColor};
use cursive::traits::View;
use cursive::{Cursive, Printer, Vec2};
use unicode_width::UnicodeWidthStr;
use commands::CommandResult;
use traits::{ViewExt, IntoBoxedViewExt};
pub struct Tab {
title: String,
view: Box<dyn ViewExt>,
}
pub struct TabView {
tabs: Vec<Tab>,
ids: HashMap<String, usize>,
selected: usize
}
impl TabView {
pub fn new() -> Self {
Self {
tabs: Vec::new(),
ids: HashMap::new(),
selected: 0
}
}
pub fn add_tab<S: Into<String>, V: IntoBoxedViewExt>(&mut self, id: S, title: S, view: V) {
let tab = Tab {
title: title.into(),
view: view.as_boxed_view_ext()
};
self.tabs.push(tab);
self.ids.insert(id.into(), self.tabs.len() - 1);
}
pub fn tab<S: Into<String>, V: IntoBoxedViewExt>(mut self, id: S, title: S, view: V) -> Self {
self.add_tab(id, title, view);
self
}
pub fn move_focus_to(&mut self, target: usize) {
let len = self.tabs.len().saturating_sub(1);
self.selected = min(target, len);
}
pub fn move_focus(&mut self, delta: i32) {
let new = self.selected as i32 + delta;
self.move_focus_to(max(new, 0) as usize);
}
}
impl View for TabView {
fn draw(&self, printer: &Printer<'_, '_>) {
if self.tabs.len() == 0 {
return;
}
let tabwidth = printer.size.x / self.tabs.len();
for (i, tab) in self.tabs.iter().enumerate() {
let style = if self.selected == i {
ColorStyle::new(
ColorType::Palette(PaletteColor::Tertiary),
ColorType::Palette(PaletteColor::Highlight),
)
} else {
ColorStyle::primary()
};
let mut width = tabwidth;
if i == self.tabs.len() {
width += printer.size.x % self.tabs.len();
}
let offset = HAlign::Center.get_offset(tab.title.width(), width);
printer.with_color(style, |printer| {
printer.print_hline((i * tabwidth, 0), width, " ");
printer.print((i * tabwidth + offset, 0), &tab.title);
});
}
if let Some(tab) = self.tabs.get(self.selected) {
let printer = printer
.offset((0, 1))
.cropped((printer.size.x, printer.size.y - 1));
tab.view.draw(&printer);
}
}
fn layout(&mut self, size: Vec2) {
if let Some(tab) = self.tabs.get_mut(self.selected) {
tab.view.layout(Vec2::new(size.x, size.y - 1));
}
}
}
impl ViewExt for TabView {
fn on_command(
&mut self,
s: &mut Cursive,
cmd: &str,
args: &[String],
) -> Result<CommandResult, String> {
if cmd == "move" {
if let Some(dir) = args.get(0) {
let amount: i32 = args
.get(1)
.unwrap_or(&"1".to_string())
.parse()
.map_err(|e| format!("{:?}", e))?;
let len = self.tabs.len();
if dir == "left" && self.selected > 0 {
self.move_focus(-amount);
return Ok(CommandResult::Consumed(None));
}
if dir == "right" && self.selected < len - 1 {
self.move_focus(amount);
return Ok(CommandResult::Consumed(None));
}
}
}
if let Some(tab) = self.tabs.get_mut(self.selected) {
tab.view.on_command(s, cmd, args)
} else {
Ok(CommandResult::Ignored)
}
}
}