@@ -107,6 +107,7 @@ fn browse_history_session(
107107 selected : 0 ,
108108 sort_field : HistorySortField :: TimePlayed ,
109109 descending : true ,
110+ pending_delete : false ,
110111 } ;
111112 refresh_history_panel ( & mut panel, & storage) ?;
112113
@@ -148,6 +149,25 @@ fn browse_history_session(
148149 refresh_history_panel ( & mut panel, & storage) ?;
149150 }
150151 }
152+ KeyCommand :: HistoryDelete => {
153+ if !panel. rows . is_empty ( ) {
154+ panel. pending_delete = true ;
155+ }
156+ }
157+ KeyCommand :: HistoryDeleteConfirm => {
158+ if let Some ( row) = panel. rows . get ( panel. selected ) {
159+ let replay_target = row. replay_target . clone ( ) ;
160+ storage
161+ . lock ( )
162+ . unwrap ( )
163+ . delete_by_replay_target ( & replay_target) ?;
164+ }
165+ panel. pending_delete = false ;
166+ refresh_history_panel ( & mut panel, & storage) ?;
167+ }
168+ KeyCommand :: HistoryDeleteCancel => {
169+ panel. pending_delete = false ;
170+ }
151171 KeyCommand :: HistoryReplay => {
152172 if let Some ( row) = panel. rows . get ( panel. selected ) {
153173 let target = row. replay_target . clone ( ) ;
@@ -676,6 +696,37 @@ fn dispatch_command(
676696 * needs_render = true ;
677697 Ok ( None )
678698 }
699+ KeyCommand :: HistoryDelete => {
700+ if let Some ( panel) = state. history_panel . as_mut ( ) {
701+ if !panel. rows . is_empty ( ) {
702+ panel. pending_delete = true ;
703+ * needs_render = true ;
704+ }
705+ }
706+ Ok ( None )
707+ }
708+ KeyCommand :: HistoryDeleteConfirm => {
709+ if let Some ( panel) = state. history_panel . as_mut ( ) {
710+ if let Some ( row) = panel. rows . get ( panel. selected ) {
711+ let replay_target = row. replay_target . clone ( ) ;
712+ storage
713+ . lock ( )
714+ . unwrap ( )
715+ . delete_by_replay_target ( & replay_target) ?;
716+ }
717+ panel. pending_delete = false ;
718+ refresh_history_panel ( panel, storage) ?;
719+ * needs_render = true ;
720+ }
721+ Ok ( None )
722+ }
723+ KeyCommand :: HistoryDeleteCancel => {
724+ if let Some ( panel) = state. history_panel . as_mut ( ) {
725+ panel. pending_delete = false ;
726+ * needs_render = true ;
727+ }
728+ Ok ( None )
729+ }
679730 KeyCommand :: None => Ok ( None ) ,
680731 }
681732}
@@ -813,10 +864,19 @@ pub(crate) enum KeyCommand {
813864 HistoryReverse ,
814865 HistoryReplay ,
815866 HistoryToggleFavorite ,
867+ HistoryDelete ,
868+ HistoryDeleteConfirm ,
869+ HistoryDeleteCancel ,
816870}
817871
818872fn handle_key_event ( key : KeyEvent , state : & AppState ) -> KeyCommand {
819- if state. history_panel . is_some ( ) {
873+ if let Some ( panel) = & state. history_panel {
874+ if panel. pending_delete {
875+ return match key. code {
876+ KeyCode :: Char ( 'y' ) | KeyCode :: Char ( 'Y' ) => KeyCommand :: HistoryDeleteConfirm ,
877+ _ => KeyCommand :: HistoryDeleteCancel ,
878+ } ;
879+ }
820880 match ( key. code , key. modifiers ) {
821881 ( KeyCode :: Esc , _) | ( KeyCode :: Char ( 'p' ) , _) => KeyCommand :: ToggleHistory ,
822882 ( KeyCode :: Char ( 'j' ) , _) => KeyCommand :: HistoryNext ,
@@ -825,6 +885,7 @@ fn handle_key_event(key: KeyEvent, state: &AppState) -> KeyCommand {
825885 ( KeyCode :: Char ( 'h' ) , _) => KeyCommand :: HistorySortPrev ,
826886 ( KeyCode :: Char ( 'r' ) , _) => KeyCommand :: HistoryReverse ,
827887 ( KeyCode :: Char ( 's' ) , _) => KeyCommand :: HistoryToggleFavorite ,
888+ ( KeyCode :: Char ( 'd' ) , _) if !panel. rows . is_empty ( ) => KeyCommand :: HistoryDelete ,
828889 ( KeyCode :: Enter , _) => KeyCommand :: HistoryReplay ,
829890 ( KeyCode :: Char ( 'q' ) , _) | ( KeyCode :: Char ( 'c' ) , KeyModifiers :: CONTROL ) => {
830891 KeyCommand :: Quit
@@ -853,13 +914,20 @@ fn handle_key_event(key: KeyEvent, state: &AppState) -> KeyCommand {
853914}
854915
855916fn handle_history_browser_key_event ( key : KeyEvent , panel : & HistoryPanelState ) -> KeyCommand {
917+ if panel. pending_delete {
918+ return match key. code {
919+ KeyCode :: Char ( 'y' ) | KeyCode :: Char ( 'Y' ) => KeyCommand :: HistoryDeleteConfirm ,
920+ _ => KeyCommand :: HistoryDeleteCancel ,
921+ } ;
922+ }
856923 match ( key. code , key. modifiers ) {
857924 ( KeyCode :: Char ( 'j' ) , _) => KeyCommand :: HistoryNext ,
858925 ( KeyCode :: Char ( 'k' ) , _) => KeyCommand :: HistoryPrev ,
859926 ( KeyCode :: Char ( 'l' ) , _) => KeyCommand :: HistorySortNext ,
860927 ( KeyCode :: Char ( 'h' ) , _) => KeyCommand :: HistorySortPrev ,
861928 ( KeyCode :: Char ( 'r' ) , _) => KeyCommand :: HistoryReverse ,
862929 ( KeyCode :: Char ( 's' ) , _) if !panel. rows . is_empty ( ) => KeyCommand :: HistoryToggleFavorite ,
930+ ( KeyCode :: Char ( 'd' ) , _) if !panel. rows . is_empty ( ) => KeyCommand :: HistoryDelete ,
863931 ( KeyCode :: Enter , _) if !panel. rows . is_empty ( ) => KeyCommand :: HistoryReplay ,
864932 ( KeyCode :: Char ( 'q' ) , _) | ( KeyCode :: Char ( 'c' ) , KeyModifiers :: CONTROL ) => KeyCommand :: Quit ,
865933 _ => KeyCommand :: None ,
@@ -877,6 +945,7 @@ fn toggle_history_panel(state: &mut AppState, storage: &SharedStorage) -> Result
877945 selected : 0 ,
878946 sort_field : HistorySortField :: TimePlayed ,
879947 descending : true ,
948+ pending_delete : false ,
880949 } ;
881950 refresh_history_panel ( & mut panel, storage) ?;
882951 state. history_panel = Some ( panel) ;
@@ -1767,6 +1836,7 @@ mod tests {
17671836 selected : 0 ,
17681837 sort_field : HistorySortField :: TimePlayed ,
17691838 descending : true ,
1839+ pending_delete : false ,
17701840 } ) ;
17711841
17721842 assert_eq ! (
@@ -1825,6 +1895,7 @@ mod tests {
18251895 selected : 0 ,
18261896 sort_field : HistorySortField :: TimePlayed ,
18271897 descending : true ,
1898+ pending_delete : false ,
18281899 } ;
18291900
18301901 assert_eq ! (
@@ -1850,6 +1921,7 @@ mod tests {
18501921 selected : 0 ,
18511922 sort_field : HistorySortField :: TimePlayed ,
18521923 descending : true ,
1924+ pending_delete : false ,
18531925 } ;
18541926
18551927 assert_eq ! (
@@ -1860,4 +1932,82 @@ mod tests {
18601932 KeyCommand :: None
18611933 ) ;
18621934 }
1935+
1936+ fn panel_with_one_row ( pending_delete : bool ) -> HistoryPanelState {
1937+ HistoryPanelState {
1938+ rows : vec ! [ HistoryRow {
1939+ track_key: "a" . into( ) ,
1940+ replay_target: "a" . into( ) ,
1941+ title: "A" . into( ) ,
1942+ platform: "Local" . into( ) ,
1943+ is_favorite: false ,
1944+ play_count: 1 ,
1945+ total_play_seconds: 10 ,
1946+ first_played_at: 0 ,
1947+ last_played_at: 0 ,
1948+ last_played_computer: String :: new( ) ,
1949+ } ] ,
1950+ selected : 0 ,
1951+ sort_field : HistorySortField :: TimePlayed ,
1952+ descending : true ,
1953+ pending_delete,
1954+ }
1955+ }
1956+
1957+ #[ test]
1958+ fn history_browser_arms_delete_with_d ( ) {
1959+ let panel = panel_with_one_row ( false ) ;
1960+ assert_eq ! (
1961+ handle_history_browser_key_event(
1962+ KeyEvent :: new( KeyCode :: Char ( 'd' ) , KeyModifiers :: NONE ) ,
1963+ & panel
1964+ ) ,
1965+ KeyCommand :: HistoryDelete
1966+ ) ;
1967+ }
1968+
1969+ #[ test]
1970+ fn history_browser_ignores_delete_when_empty ( ) {
1971+ let panel = HistoryPanelState {
1972+ rows : Vec :: new ( ) ,
1973+ selected : 0 ,
1974+ sort_field : HistorySortField :: TimePlayed ,
1975+ descending : true ,
1976+ pending_delete : false ,
1977+ } ;
1978+ assert_eq ! (
1979+ handle_history_browser_key_event(
1980+ KeyEvent :: new( KeyCode :: Char ( 'd' ) , KeyModifiers :: NONE ) ,
1981+ & panel
1982+ ) ,
1983+ KeyCommand :: None
1984+ ) ;
1985+ }
1986+
1987+ #[ test]
1988+ fn pending_delete_routes_y_to_confirm_and_other_to_cancel ( ) {
1989+ let panel = panel_with_one_row ( true ) ;
1990+ assert_eq ! (
1991+ handle_history_browser_key_event(
1992+ KeyEvent :: new( KeyCode :: Char ( 'y' ) , KeyModifiers :: NONE ) ,
1993+ & panel
1994+ ) ,
1995+ KeyCommand :: HistoryDeleteConfirm
1996+ ) ;
1997+ // Any non-`y` key cancels — including keys that normally do something.
1998+ assert_eq ! (
1999+ handle_history_browser_key_event(
2000+ KeyEvent :: new( KeyCode :: Char ( 'n' ) , KeyModifiers :: NONE ) ,
2001+ & panel
2002+ ) ,
2003+ KeyCommand :: HistoryDeleteCancel
2004+ ) ;
2005+ assert_eq ! (
2006+ handle_history_browser_key_event(
2007+ KeyEvent :: new( KeyCode :: Char ( 'j' ) , KeyModifiers :: NONE ) ,
2008+ & panel
2009+ ) ,
2010+ KeyCommand :: HistoryDeleteCancel
2011+ ) ;
2012+ }
18632013}
0 commit comments