feat: enhance diary navigation with LoadPrev action and pagination hints
This commit is contained in:
19
Cargo.lock
generated
19
Cargo.lock
generated
@@ -1708,6 +1708,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "eebcc3aff044e5944a8fbaf69eb277d11986064cba30c468730e8b9909fb551c"
|
checksum = "eebcc3aff044e5944a8fbaf69eb277d11986064cba30c468730e8b9909fb551c"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"log",
|
"log",
|
||||||
|
"security-framework 2.11.1",
|
||||||
|
"security-framework 3.7.0",
|
||||||
"zeroize",
|
"zeroize",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -2887,7 +2889,7 @@ dependencies = [
|
|||||||
"openssl-probe",
|
"openssl-probe",
|
||||||
"rustls-pki-types",
|
"rustls-pki-types",
|
||||||
"schannel",
|
"schannel",
|
||||||
"security-framework",
|
"security-framework 3.7.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2915,7 +2917,7 @@ dependencies = [
|
|||||||
"rustls-native-certs",
|
"rustls-native-certs",
|
||||||
"rustls-platform-verifier-android",
|
"rustls-platform-verifier-android",
|
||||||
"rustls-webpki",
|
"rustls-webpki",
|
||||||
"security-framework",
|
"security-framework 3.7.0",
|
||||||
"security-framework-sys",
|
"security-framework-sys",
|
||||||
"webpki-root-certs",
|
"webpki-root-certs",
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
@@ -2975,6 +2977,19 @@ version = "1.2.0"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "security-framework"
|
||||||
|
version = "2.11.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02"
|
||||||
|
dependencies = [
|
||||||
|
"bitflags 2.11.1",
|
||||||
|
"core-foundation 0.9.4",
|
||||||
|
"core-foundation-sys",
|
||||||
|
"libc",
|
||||||
|
"security-framework-sys",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "security-framework"
|
name = "security-framework"
|
||||||
version = "3.7.0"
|
version = "3.7.0"
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ edition = "2024"
|
|||||||
[dependencies]
|
[dependencies]
|
||||||
ratatui = "0.30.0"
|
ratatui = "0.30.0"
|
||||||
|
|
||||||
keyring = "3"
|
keyring = { version = "3", features = ["apple-native"] }
|
||||||
directories = "6"
|
directories = "6"
|
||||||
csv = "1"
|
csv = "1"
|
||||||
|
|
||||||
|
|||||||
@@ -173,7 +173,7 @@ pub enum Action {
|
|||||||
SetupSubmit,
|
SetupSubmit,
|
||||||
InputChar(char), Backspace, FocusNext, FocusPrev,
|
InputChar(char), Backspace, FocusNext, FocusPrev,
|
||||||
LoginSubmit,
|
LoginSubmit,
|
||||||
ScrollDown, ScrollUp, OpenHistory, LoadMore,
|
ScrollDown, ScrollUp, OpenHistory, LoadMore, LoadPrev,
|
||||||
DeleteInit, DeleteConfirm, DeleteCancel,
|
DeleteInit, DeleteConfirm, DeleteCancel,
|
||||||
RatingUp, RatingDown, ReviewSubmit,
|
RatingUp, RatingDown, ReviewSubmit,
|
||||||
BulkParseFile, BulkImportAll, BulkCancel,
|
BulkParseFile, BulkImportAll, BulkCancel,
|
||||||
@@ -301,7 +301,7 @@ pub fn update(app: &mut App, action: Action) -> Vec<Command> {
|
|||||||
m.bulk_import.stage = BulkImportStage::EnterPath;
|
m.bulk_import.stage = BulkImportStage::EnterPath;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
Tab::AddReview | Tab::Settings => { m.tab = Tab::Diary; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vec![]
|
vec![]
|
||||||
@@ -435,8 +435,14 @@ pub fn update(app: &mut App, action: Action) -> Vec<Command> {
|
|||||||
return vec![];
|
return vec![];
|
||||||
}
|
}
|
||||||
app.api_url = url.clone();
|
app.api_url = url.clone();
|
||||||
|
let cmds = if app.token.is_some() {
|
||||||
|
app.screen = Screen::Main(MainState::new(url.clone()));
|
||||||
|
vec![Command::SaveConfig(url), Command::LoadDiary { offset: 0 }]
|
||||||
|
} else {
|
||||||
app.screen = Screen::Login(LoginState::default());
|
app.screen = Screen::Login(LoginState::default());
|
||||||
return vec![Command::SaveConfig(url)];
|
vec![Command::SaveConfig(url)]
|
||||||
|
};
|
||||||
|
return cmds;
|
||||||
}
|
}
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
@@ -515,6 +521,17 @@ pub fn update(app: &mut App, action: Action) -> Vec<Command> {
|
|||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Action::LoadPrev => {
|
||||||
|
if let Screen::Main(m) = &mut app.screen {
|
||||||
|
if m.diary.offset > 0 {
|
||||||
|
let prev = m.diary.offset.saturating_sub(20);
|
||||||
|
m.diary.offset = prev;
|
||||||
|
return vec![Command::LoadDiary { offset: prev }];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
vec![]
|
||||||
|
}
|
||||||
|
|
||||||
Action::DiaryLoaded { entries, total } => {
|
Action::DiaryLoaded { entries, total } => {
|
||||||
app.loading = false;
|
app.loading = false;
|
||||||
if let Screen::Main(m) = &mut app.screen {
|
if let Screen::Main(m) = &mut app.screen {
|
||||||
@@ -701,8 +718,12 @@ pub fn update(app: &mut App, action: Action) -> Vec<Command> {
|
|||||||
|
|
||||||
Action::BulkCancel => {
|
Action::BulkCancel => {
|
||||||
if let Screen::Main(m) = &mut app.screen {
|
if let Screen::Main(m) = &mut app.screen {
|
||||||
|
if m.bulk_import.stage == BulkImportStage::EnterPath {
|
||||||
|
m.tab = Tab::Diary;
|
||||||
|
} else {
|
||||||
m.bulk_import = BulkImportState::default();
|
m.bulk_import = BulkImportState::default();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
vec![]
|
vec![]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -246,6 +246,7 @@ fn key_to_action(app: &App, key: ratatui::crossterm::event::KeyEvent) -> Option<
|
|||||||
KeyCode::Tab => Some(Action::TabNext),
|
KeyCode::Tab => Some(Action::TabNext),
|
||||||
KeyCode::BackTab => Some(Action::TabPrev),
|
KeyCode::BackTab => Some(Action::TabPrev),
|
||||||
KeyCode::Char('>') | KeyCode::Char('m') => Some(Action::LoadMore),
|
KeyCode::Char('>') | KeyCode::Char('m') => Some(Action::LoadMore),
|
||||||
|
KeyCode::Char('<') | KeyCode::Char('b') => Some(Action::LoadPrev),
|
||||||
KeyCode::Char('1') => Some(Action::TabSelect(Tab::Diary)),
|
KeyCode::Char('1') => Some(Action::TabSelect(Tab::Diary)),
|
||||||
KeyCode::Char('2') => Some(Action::TabSelect(Tab::AddReview)),
|
KeyCode::Char('2') => Some(Action::TabSelect(Tab::AddReview)),
|
||||||
KeyCode::Char('3') => Some(Action::TabSelect(Tab::BulkImport)),
|
KeyCode::Char('3') => Some(Action::TabSelect(Tab::BulkImport)),
|
||||||
@@ -279,6 +280,10 @@ fn key_to_action(app: &App, key: ratatui::crossterm::event::KeyEvent) -> Option<
|
|||||||
KeyCode::Tab if !in_path => Some(Action::TabNext),
|
KeyCode::Tab if !in_path => Some(Action::TabNext),
|
||||||
KeyCode::BackTab if !in_path => Some(Action::TabPrev),
|
KeyCode::BackTab if !in_path => Some(Action::TabPrev),
|
||||||
KeyCode::Char('q') if !in_path => Some(Action::Quit),
|
KeyCode::Char('q') if !in_path => Some(Action::Quit),
|
||||||
|
KeyCode::Char('1') if !in_path => Some(Action::TabSelect(Tab::Diary)),
|
||||||
|
KeyCode::Char('2') if !in_path => Some(Action::TabSelect(Tab::AddReview)),
|
||||||
|
KeyCode::Char('3') if !in_path => Some(Action::TabSelect(Tab::BulkImport)),
|
||||||
|
KeyCode::Char('4') if !in_path => Some(Action::TabSelect(Tab::Settings)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -296,6 +301,10 @@ fn key_to_action(app: &App, key: ratatui::crossterm::event::KeyEvent) -> Option<
|
|||||||
},
|
},
|
||||||
KeyCode::Esc => Some(Action::Escape),
|
KeyCode::Esc => Some(Action::Escape),
|
||||||
KeyCode::Char('q') => Some(Action::Quit),
|
KeyCode::Char('q') => Some(Action::Quit),
|
||||||
|
KeyCode::Char('1') if !on_url => Some(Action::TabSelect(Tab::Diary)),
|
||||||
|
KeyCode::Char('2') if !on_url => Some(Action::TabSelect(Tab::AddReview)),
|
||||||
|
KeyCode::Char('3') if !on_url => Some(Action::TabSelect(Tab::BulkImport)),
|
||||||
|
KeyCode::Char('4') if !on_url => Some(Action::TabSelect(Tab::Settings)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -215,11 +215,13 @@ fn draw_diary(frame: &mut Frame, area: Rect, state: &DiaryState) {
|
|||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let can_load_more = (state.offset as u64 + state.entries.len() as u64) < state.total;
|
let can_load_more = (state.offset as u64 + state.entries.len() as u64) < state.total;
|
||||||
let list_title = if can_load_more {
|
let can_load_prev = state.offset > 0;
|
||||||
format!(" Diary ({} entries) [m: load more] ", state.total)
|
let page = state.offset / 20 + 1;
|
||||||
} else {
|
let total_pages = state.total.div_ceil(20).max(1);
|
||||||
format!(" Diary ({} entries) ", state.total)
|
let mut hints = format!(" Diary ({} entries, page {}/{}) ", state.total, page, total_pages);
|
||||||
};
|
if can_load_prev { hints.push_str("[b: prev] "); }
|
||||||
|
if can_load_more { hints.push_str("[m: next] "); }
|
||||||
|
let list_title = hints;
|
||||||
let mut list_state = ListState::default();
|
let mut list_state = ListState::default();
|
||||||
list_state.select(Some(state.selected));
|
list_state.select(Some(state.selected));
|
||||||
let list = List::new(items).block(Block::default().title(list_title).borders(Borders::ALL));
|
let list = List::new(items).block(Block::default().title(list_title).borders(Borders::ALL));
|
||||||
|
|||||||
Reference in New Issue
Block a user