Provide search functionality through the TUI #134
@ -224,6 +224,8 @@ impl<MH: IMusicHoard> IAppInteractBrowse for App<MH> {
|
||||
fn begin_search(&mut self) {
|
||||
assert!(self.state.is_browse());
|
||||
self.state = AppState::Search(String::new());
|
||||
self.selection
|
||||
.reset_artist(self.music_hoard.get_collection());
|
||||
}
|
||||
}
|
||||
|
||||
@ -274,14 +276,24 @@ impl<MH: IMusicHoard> IAppInteractReloadPrivate for App<MH> {
|
||||
impl<MH: IMusicHoard> IAppInteractSearch for App<MH> {
|
||||
fn append_character(&mut self, ch: char) {
|
||||
match self.state {
|
||||
AppState::Search(ref mut s) => s.push(ch),
|
||||
AppState::Search(ref mut s) => {
|
||||
s.push(ch);
|
||||
self.selection
|
||||
.incremental_artist_search(self.music_hoard.get_collection(), s);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
fn remove_character(&mut self) {
|
||||
match self.state {
|
||||
AppState::Search(ref mut s) => s.pop(),
|
||||
AppState::Search(ref mut s) => {
|
||||
s.pop();
|
||||
self.selection
|
||||
.reset_artist(self.music_hoard.get_collection());
|
||||
self.selection
|
||||
.incremental_artist_search(self.music_hoard.get_collection(), s);
|
||||
}
|
||||
_ => unreachable!(),
|
||||
};
|
||||
}
|
||||
|
@ -73,6 +73,12 @@ impl Selection {
|
||||
self.artist.reinitialise(artists, selected.artist);
|
||||
}
|
||||
|
||||
pub fn reset_artist(&mut self, artists: &[Artist]) {
|
||||
if self.artist.state.list.selected() != Some(0) {
|
||||
self.select(artists, ActiveSelection { artist: None });
|
||||
}
|
||||
}
|
||||
|
||||
pub fn increment_category(&mut self) {
|
||||
self.active = match self.active {
|
||||
Category::Artist => Category::Album,
|
||||
@ -89,6 +95,10 @@ impl Selection {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn incremental_artist_search(&mut self, collection: &Collection, artist_name: &str) {
|
||||
self.artist.incremental_search(collection, artist_name);
|
||||
}
|
||||
|
||||
pub fn increment_selection(&mut self, collection: &Collection, delta: Delta) {
|
||||
match self.active {
|
||||
Category::Artist => self.increment_artist(collection, delta),
|
||||
@ -172,16 +182,47 @@ impl ArtistSelection {
|
||||
}
|
||||
}
|
||||
|
||||
fn select_to(&mut self, artists: &[Artist], mut to: usize) {
|
||||
if to >= artists.len() {
|
||||
to = artists.len() - 1;
|
||||
}
|
||||
if self.state.list.selected() != Some(to) {
|
||||
self.state.list.select(Some(to));
|
||||
self.album = AlbumSelection::initialise(&artists[to].albums);
|
||||
}
|
||||
}
|
||||
|
||||
fn incremental_search(&mut self, artists: &[Artist], artist_name: &str) {
|
||||
if let Some(index) = self.state.list.selected() {
|
||||
let case_sensitive = artist_name
|
||||
.chars()
|
||||
.any(|ch| !(ch.is_lowercase() || ch.is_whitespace()));
|
||||
let slice = &artists[index..];
|
||||
|
||||
let result = if case_sensitive {
|
||||
slice.binary_search_by(|probe| probe.get_sort_key().name.as_str().cmp(artist_name))
|
||||
} else {
|
||||
slice.binary_search_by(|probe| {
|
||||
probe
|
||||
.get_sort_key()
|
||||
.name
|
||||
.to_lowercase()
|
||||
.as_str()
|
||||
.cmp(artist_name)
|
||||
})
|
||||
};
|
||||
|
||||
let new_index = match result {
|
||||
Ok(slice_index) | Err(slice_index) => index + slice_index,
|
||||
};
|
||||
self.select_to(artists, new_index);
|
||||
}
|
||||
}
|
||||
|
||||
fn increment_by(&mut self, artists: &[Artist], by: usize) {
|
||||
if let Some(index) = self.state.list.selected() {
|
||||
let mut result = index.saturating_add(by);
|
||||
if result >= artists.len() {
|
||||
result = artists.len() - 1;
|
||||
}
|
||||
if self.state.list.selected() != Some(result) {
|
||||
self.state.list.select(Some(result));
|
||||
self.album = AlbumSelection::initialise(&artists[result].albums);
|
||||
}
|
||||
let result = index.saturating_add(by);
|
||||
self.select_to(artists, result);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -53,35 +53,35 @@ impl<APP: IAppInteract> IEventHandler<APP> for EventHandler {
|
||||
|
||||
impl<APP: IAppInteract> IEventHandlerPrivate<APP> for EventHandler {
|
||||
fn handle_key_event(app: &mut APP, key_event: KeyEvent) {
|
||||
match key_event.code {
|
||||
// Exit application on `Ctrl-C`.
|
||||
KeyCode::Char('c') | KeyCode::Char('C') => {
|
||||
if key_event.modifiers == KeyModifiers::CONTROL {
|
||||
if key_event.modifiers == KeyModifiers::CONTROL {
|
||||
match key_event.code {
|
||||
// Exit application on `Ctrl-C`.
|
||||
KeyCode::Char('c') | KeyCode::Char('C') => {
|
||||
app.force_quit();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
match app.state() {
|
||||
AppState::Browse(browse) => {
|
||||
<Self as IEventHandlerPrivate<APP>>::handle_browse_key_event(browse, key_event);
|
||||
}
|
||||
AppState::Info(info) => {
|
||||
<Self as IEventHandlerPrivate<APP>>::handle_info_key_event(info, key_event);
|
||||
}
|
||||
AppState::Reload(reload) => {
|
||||
<Self as IEventHandlerPrivate<APP>>::handle_reload_key_event(reload, key_event);
|
||||
}
|
||||
AppState::Search(search) => {
|
||||
<Self as IEventHandlerPrivate<APP>>::handle_search_key_event(search, key_event);
|
||||
}
|
||||
AppState::Error(error) => {
|
||||
<Self as IEventHandlerPrivate<APP>>::handle_error_key_event(error, key_event);
|
||||
}
|
||||
AppState::Critical(critical) => {
|
||||
<Self as IEventHandlerPrivate<APP>>::handle_critical_key_event(critical, key_event);
|
||||
}
|
||||
_ => match app.state() {
|
||||
AppState::Browse(browse) => {
|
||||
<Self as IEventHandlerPrivate<APP>>::handle_browse_key_event(browse, key_event);
|
||||
}
|
||||
AppState::Info(info) => {
|
||||
<Self as IEventHandlerPrivate<APP>>::handle_info_key_event(info, key_event);
|
||||
}
|
||||
AppState::Reload(reload) => {
|
||||
<Self as IEventHandlerPrivate<APP>>::handle_reload_key_event(reload, key_event);
|
||||
}
|
||||
AppState::Search(search) => {
|
||||
<Self as IEventHandlerPrivate<APP>>::handle_search_key_event(search, key_event);
|
||||
}
|
||||
AppState::Error(error) => {
|
||||
<Self as IEventHandlerPrivate<APP>>::handle_error_key_event(error, key_event);
|
||||
}
|
||||
AppState::Critical(critical) => {
|
||||
<Self as IEventHandlerPrivate<APP>>::handle_critical_key_event(
|
||||
critical, key_event,
|
||||
);
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user