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