Save entire list state when beginning search
This commit is contained in:
parent
5b7263d5d8
commit
9cf29b99b8
@ -3,7 +3,7 @@
|
||||
use musichoard::collection::Collection;
|
||||
|
||||
use crate::tui::{
|
||||
app::selection::{ActiveSelection, Delta, Selection},
|
||||
app::selection::{Delta, IdSelection, Selection, ListSelection},
|
||||
lib::IMusicHoard,
|
||||
};
|
||||
|
||||
@ -143,7 +143,7 @@ pub struct App<MH: IMusicHoard> {
|
||||
state: AppState<(), (), (), String, String, String>,
|
||||
// FIXME: is it possible to use a wrapper struct? - when state() is called return a wrapper
|
||||
// around App<MH> which will contain App.
|
||||
orig: Option<usize>,
|
||||
orig: Option<ListSelection>,
|
||||
memo: Vec<(Option<usize>, bool)>,
|
||||
}
|
||||
|
||||
@ -250,8 +250,7 @@ impl<MH: IMusicHoard> IAppInteractBrowse for App<MH> {
|
||||
fn begin_search(&mut self) {
|
||||
assert!(self.state.is_browse());
|
||||
self.state = AppState::Search(String::new());
|
||||
// FIXME: this should be the entire selection - not just the artist.
|
||||
self.orig = self.selection.selected_artist();
|
||||
self.orig = Some(ListSelection::get(&self.selection));
|
||||
self.memo = vec![];
|
||||
self.selection
|
||||
.reset_artist(self.music_hoard.get_collection());
|
||||
@ -267,13 +266,13 @@ impl<MH: IMusicHoard> IAppInteractInfo for App<MH> {
|
||||
|
||||
impl<MH: IMusicHoard> IAppInteractReload for App<MH> {
|
||||
fn reload_library(&mut self) {
|
||||
let previous = ActiveSelection::get(self.music_hoard.get_collection(), &self.selection);
|
||||
let previous = IdSelection::get(self.music_hoard.get_collection(), &self.selection);
|
||||
let result = self.music_hoard.rescan_library();
|
||||
self.refresh(previous, result);
|
||||
}
|
||||
|
||||
fn reload_database(&mut self) {
|
||||
let previous = ActiveSelection::get(self.music_hoard.get_collection(), &self.selection);
|
||||
let previous = IdSelection::get(self.music_hoard.get_collection(), &self.selection);
|
||||
let result = self.music_hoard.load_from_database();
|
||||
self.refresh(previous, result);
|
||||
}
|
||||
@ -285,11 +284,11 @@ impl<MH: IMusicHoard> IAppInteractReload for App<MH> {
|
||||
}
|
||||
|
||||
trait IAppInteractReloadPrivate {
|
||||
fn refresh(&mut self, previous: ActiveSelection, result: Result<(), musichoard::Error>);
|
||||
fn refresh(&mut self, previous: IdSelection, result: Result<(), musichoard::Error>);
|
||||
}
|
||||
|
||||
impl<MH: IMusicHoard> IAppInteractReloadPrivate for App<MH> {
|
||||
fn refresh(&mut self, previous: ActiveSelection, result: Result<(), musichoard::Error>) {
|
||||
fn refresh(&mut self, previous: IdSelection, result: Result<(), musichoard::Error>) {
|
||||
assert!(self.state.is_reload());
|
||||
match result {
|
||||
Ok(()) => {
|
||||
@ -342,8 +341,7 @@ impl<MH: IMusicHoard> IAppInteractSearch for App<MH> {
|
||||
|
||||
fn cancel_search(&mut self) {
|
||||
assert!(self.state.is_search());
|
||||
let collection = self.music_hoard.get_collection();
|
||||
self.selection.select_artist(collection, self.orig);
|
||||
self.selection.select_by_list(self.orig.take().unwrap());
|
||||
self.state = AppState::Browse(());
|
||||
}
|
||||
}
|
||||
|
@ -70,12 +70,14 @@ impl Selection {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn select_by_id(&mut self, artists: &[Artist], selected: ActiveSelection) {
|
||||
self.artist.reinitialise(artists, selected.artist);
|
||||
pub fn select_by_list(&mut self, selected: ListSelection) {
|
||||
self.artist.state.list = selected.artist;
|
||||
self.artist.album.state.list = selected.album;
|
||||
self.artist.album.track.state.list = selected.track;
|
||||
}
|
||||
|
||||
pub fn selected_artist(&mut self) -> Option<usize> {
|
||||
self.artist.state.list.selected()
|
||||
pub fn select_by_id(&mut self, artists: &[Artist], selected: IdSelection) {
|
||||
self.artist.reinitialise(artists, selected.artist);
|
||||
}
|
||||
|
||||
pub fn select_artist(&mut self, artists: &[Artist], index: Option<usize>) {
|
||||
@ -84,7 +86,7 @@ impl Selection {
|
||||
|
||||
pub fn reset_artist(&mut self, artists: &[Artist]) {
|
||||
if self.artist.state.list.selected() != Some(0) {
|
||||
self.select_by_id(artists, ActiveSelection { artist: None });
|
||||
self.select_by_id(artists, IdSelection { artist: None });
|
||||
}
|
||||
}
|
||||
|
||||
@ -165,7 +167,7 @@ impl ArtistSelection {
|
||||
selection
|
||||
}
|
||||
|
||||
fn reinitialise(&mut self, artists: &[Artist], active: Option<ActiveArtist>) {
|
||||
fn reinitialise(&mut self, artists: &[Artist], active: Option<IdSelectArtist>) {
|
||||
if let Some(active) = active {
|
||||
let result = artists.binary_search_by(|a| a.get_sort_key().cmp(&active.artist_id));
|
||||
match result {
|
||||
@ -181,7 +183,7 @@ impl ArtistSelection {
|
||||
&mut self,
|
||||
artists: &[Artist],
|
||||
index: usize,
|
||||
active_album: Option<ActiveAlbum>,
|
||||
active_album: Option<IdSelectAlbum>,
|
||||
) {
|
||||
if artists.is_empty() {
|
||||
self.state.list.select(None);
|
||||
@ -359,7 +361,7 @@ impl AlbumSelection {
|
||||
selection
|
||||
}
|
||||
|
||||
fn reinitialise(&mut self, albums: &[Album], album: Option<ActiveAlbum>) {
|
||||
fn reinitialise(&mut self, albums: &[Album], album: Option<IdSelectAlbum>) {
|
||||
if let Some(album) = album {
|
||||
let result = albums.binary_search_by(|a| a.get_sort_key().cmp(&album.album_id));
|
||||
match result {
|
||||
@ -375,7 +377,7 @@ impl AlbumSelection {
|
||||
&mut self,
|
||||
albums: &[Album],
|
||||
index: usize,
|
||||
active_track: Option<ActiveTrack>,
|
||||
active_track: Option<IdSelectTrack>,
|
||||
) {
|
||||
if albums.is_empty() {
|
||||
self.state.list.select(None);
|
||||
@ -443,7 +445,7 @@ impl TrackSelection {
|
||||
selection
|
||||
}
|
||||
|
||||
fn reinitialise(&mut self, tracks: &[Track], track: Option<ActiveTrack>) {
|
||||
fn reinitialise(&mut self, tracks: &[Track], track: Option<IdSelectTrack>) {
|
||||
if let Some(track) = track {
|
||||
let result = tracks.binary_search_by(|t| t.get_sort_key().cmp(&track.track_id));
|
||||
match result {
|
||||
@ -494,61 +496,77 @@ impl TrackSelection {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ActiveSelection {
|
||||
artist: Option<ActiveArtist>,
|
||||
pub struct ListSelection {
|
||||
artist: ListState,
|
||||
album: ListState,
|
||||
track: ListState,
|
||||
}
|
||||
|
||||
struct ActiveArtist {
|
||||
artist_id: ArtistId,
|
||||
album: Option<ActiveAlbum>,
|
||||
}
|
||||
|
||||
struct ActiveAlbum {
|
||||
album_id: AlbumId,
|
||||
track: Option<ActiveTrack>,
|
||||
}
|
||||
|
||||
struct ActiveTrack {
|
||||
track_id: TrackId,
|
||||
}
|
||||
|
||||
impl ActiveSelection {
|
||||
pub fn get(collection: &Collection, selection: &Selection) -> Self {
|
||||
ActiveSelection {
|
||||
artist: ActiveArtist::get(collection, &selection.artist),
|
||||
impl ListSelection {
|
||||
pub fn get(selection: &Selection) -> Self {
|
||||
ListSelection {
|
||||
artist: selection.artist.state.list.clone(),
|
||||
album: selection.artist.album.state.list.clone(),
|
||||
track: selection.artist.album.track.state.list.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveArtist {
|
||||
pub struct IdSelection {
|
||||
artist: Option<IdSelectArtist>,
|
||||
}
|
||||
|
||||
struct IdSelectArtist {
|
||||
artist_id: ArtistId,
|
||||
album: Option<IdSelectAlbum>,
|
||||
}
|
||||
|
||||
struct IdSelectAlbum {
|
||||
album_id: AlbumId,
|
||||
track: Option<IdSelectTrack>,
|
||||
}
|
||||
|
||||
struct IdSelectTrack {
|
||||
track_id: TrackId,
|
||||
}
|
||||
|
||||
impl IdSelection {
|
||||
pub fn get(collection: &Collection, selection: &Selection) -> Self {
|
||||
IdSelection {
|
||||
artist: IdSelectArtist::get(collection, &selection.artist),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl IdSelectArtist {
|
||||
fn get(artists: &[Artist], selection: &ArtistSelection) -> Option<Self> {
|
||||
selection.state.list.selected().map(|index| {
|
||||
let artist = &artists[index];
|
||||
ActiveArtist {
|
||||
IdSelectArtist {
|
||||
artist_id: artist.get_sort_key().clone(),
|
||||
album: ActiveAlbum::get(&artist.albums, &selection.album),
|
||||
album: IdSelectAlbum::get(&artist.albums, &selection.album),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveAlbum {
|
||||
impl IdSelectAlbum {
|
||||
fn get(albums: &[Album], selection: &AlbumSelection) -> Option<Self> {
|
||||
selection.state.list.selected().map(|index| {
|
||||
let album = &albums[index];
|
||||
ActiveAlbum {
|
||||
IdSelectAlbum {
|
||||
album_id: album.get_sort_key().clone(),
|
||||
track: ActiveTrack::get(&album.tracks, &selection.track),
|
||||
track: IdSelectTrack::get(&album.tracks, &selection.track),
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveTrack {
|
||||
impl IdSelectTrack {
|
||||
fn get(tracks: &[Track], selection: &TrackSelection) -> Option<Self> {
|
||||
selection.state.list.selected().map(|index| {
|
||||
let track = &tracks[index];
|
||||
ActiveTrack {
|
||||
IdSelectTrack {
|
||||
track_id: track.get_sort_key().clone(),
|
||||
}
|
||||
})
|
||||
@ -626,20 +644,20 @@ mod tests {
|
||||
|
||||
// Re-initialise.
|
||||
let expected = sel.clone();
|
||||
let active_track = ActiveTrack::get(tracks, &sel);
|
||||
let active_track = IdSelectTrack::get(tracks, &sel);
|
||||
sel.reinitialise(tracks, active_track);
|
||||
assert_eq!(sel, expected);
|
||||
|
||||
// Re-initialise out-of-bounds.
|
||||
let mut expected = sel.clone();
|
||||
expected.decrement(tracks, Delta::Line);
|
||||
let active_track = ActiveTrack::get(tracks, &sel);
|
||||
let active_track = IdSelectTrack::get(tracks, &sel);
|
||||
sel.reinitialise(&tracks[..(tracks.len() - 1)], active_track);
|
||||
assert_eq!(sel, expected);
|
||||
|
||||
// Re-initialise empty.
|
||||
let expected = TrackSelection::initialise(&[]);
|
||||
let active_track = ActiveTrack::get(tracks, &sel);
|
||||
let active_track = IdSelectTrack::get(tracks, &sel);
|
||||
sel.reinitialise(&[], active_track);
|
||||
assert_eq!(sel, expected);
|
||||
}
|
||||
@ -748,20 +766,20 @@ mod tests {
|
||||
|
||||
// Re-initialise.
|
||||
let expected = sel.clone();
|
||||
let active_album = ActiveAlbum::get(albums, &sel);
|
||||
let active_album = IdSelectAlbum::get(albums, &sel);
|
||||
sel.reinitialise(albums, active_album);
|
||||
assert_eq!(sel, expected);
|
||||
|
||||
// Re-initialise out-of-bounds.
|
||||
let mut expected = sel.clone();
|
||||
expected.decrement(albums, Delta::Line);
|
||||
let active_album = ActiveAlbum::get(albums, &sel);
|
||||
let active_album = IdSelectAlbum::get(albums, &sel);
|
||||
sel.reinitialise(&albums[..(albums.len() - 1)], active_album);
|
||||
assert_eq!(sel, expected);
|
||||
|
||||
// Re-initialise empty.
|
||||
let expected = AlbumSelection::initialise(&[]);
|
||||
let active_album = ActiveAlbum::get(albums, &sel);
|
||||
let active_album = IdSelectAlbum::get(albums, &sel);
|
||||
sel.reinitialise(&[], active_album);
|
||||
assert_eq!(sel, expected);
|
||||
}
|
||||
@ -870,20 +888,20 @@ mod tests {
|
||||
|
||||
// Re-initialise.
|
||||
let expected = sel.clone();
|
||||
let active_artist = ActiveArtist::get(artists, &sel);
|
||||
let active_artist = IdSelectArtist::get(artists, &sel);
|
||||
sel.reinitialise(artists, active_artist);
|
||||
assert_eq!(sel, expected);
|
||||
|
||||
// Re-initialise out-of-bounds.
|
||||
let mut expected = sel.clone();
|
||||
expected.decrement(artists, Delta::Line);
|
||||
let active_artist = ActiveArtist::get(artists, &sel);
|
||||
let active_artist = IdSelectArtist::get(artists, &sel);
|
||||
sel.reinitialise(&artists[..(artists.len() - 1)], active_artist);
|
||||
assert_eq!(sel, expected);
|
||||
|
||||
// Re-initialise empty.
|
||||
let expected = ArtistSelection::initialise(&[]);
|
||||
let active_artist = ActiveArtist::get(artists, &sel);
|
||||
let active_artist = IdSelectArtist::get(artists, &sel);
|
||||
sel.reinitialise(&[], active_artist);
|
||||
assert_eq!(sel, expected);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user