Add vertical scroll to Notes field in EditTask popup

- Added notes_scroll to App and AppView
- Up/Down in Notes field scrolls (Tab cycles fields instead)
- Reset scroll on opening EditTask popup
- Notes Paragraph uses .scroll((notes_scroll, 0))
This commit is contained in:
Ruben Rosario
2026-06-21 17:05:01 +01:00
parent 915f0a3197
commit fa03a30a31
4 changed files with 28 additions and 6 deletions
+21 -4
View File
@@ -37,6 +37,7 @@ pub struct App {
pub should_quit: bool, pub should_quit: bool,
pub task_list_scroll: u16, pub task_list_scroll: u16,
pub detail_scroll: u16, pub detail_scroll: u16,
pub notes_scroll: u16,
pub db: Arc<Db>, pub db: Arc<Db>,
#[allow(dead_code)] #[allow(dead_code)]
pub api_client: Arc<ApiClient>, pub api_client: Arc<ApiClient>,
@@ -104,6 +105,7 @@ impl App {
should_quit: false, should_quit: false,
task_list_scroll: 0, task_list_scroll: 0,
detail_scroll: 0, detail_scroll: 0,
notes_scroll: 0,
db, db,
api_client, api_client,
needs_auth: !has_token, needs_auth: !has_token,
@@ -347,6 +349,7 @@ impl App {
self.popup_secondary.clear(); self.popup_secondary.clear();
self.popup_secondary_cursor = 0; self.popup_secondary_cursor = 0;
self.edit_field = 0; self.edit_field = 0;
self.notes_scroll = 0;
self.show_popup = Some(Popup::EditTask { field: 0 }); self.show_popup = Some(Popup::EditTask { field: 0 });
} }
} }
@@ -365,6 +368,7 @@ impl App {
self.popup_secondary = task.notes.clone().unwrap_or_default(); self.popup_secondary = task.notes.clone().unwrap_or_default();
self.popup_secondary_cursor = self.popup_secondary.len(); self.popup_secondary_cursor = self.popup_secondary.len();
self.edit_field = 0; self.edit_field = 0;
self.notes_scroll = 0;
self.show_popup = Some(Popup::EditTask { field: 0 }); self.show_popup = Some(Popup::EditTask { field: 0 });
} }
} }
@@ -500,15 +504,28 @@ impl App {
self.editing_task_id = None; self.editing_task_id = None;
self.show_popup = None; self.show_popup = None;
} }
KeyCode::Tab | KeyCode::Down => { KeyCode::Tab => {
let new_field = (field + 1) % 5; let new_field = (field + 1) % 5;
self.edit_field = new_field; self.edit_field = new_field;
self.show_popup = Some(Popup::EditTask { field: new_field }); self.show_popup = Some(Popup::EditTask { field: new_field });
} }
KeyCode::Down => {
if *field == 1 {
self.notes_scroll = self.notes_scroll.saturating_add(1);
} else {
let new_field = (field + 1) % 5;
self.edit_field = new_field;
self.show_popup = Some(Popup::EditTask { field: new_field });
}
}
KeyCode::Up => { KeyCode::Up => {
let new_field = (field + 4) % 5; if *field == 1 {
self.edit_field = new_field; self.notes_scroll = self.notes_scroll.saturating_sub(1);
self.show_popup = Some(Popup::EditTask { field: new_field }); } else {
let new_field = (field + 4) % 5;
self.edit_field = new_field;
self.show_popup = Some(Popup::EditTask { field: new_field });
}
} }
KeyCode::Enter => { KeyCode::Enter => {
let title = self.popup_input.trim().to_string(); let title = self.popup_input.trim().to_string();
+1
View File
@@ -141,6 +141,7 @@ fn main() -> io::Result<()> {
network_status: &app.network_status, network_status: &app.network_status,
task_list_scroll: app.task_list_scroll, task_list_scroll: app.task_list_scroll,
detail_scroll: app.detail_scroll, detail_scroll: app.detail_scroll,
notes_scroll: app.notes_scroll,
auth_error: app.auth_error.as_deref(), auth_error: app.auth_error.as_deref(),
sync_stats: &app.sync_stats, sync_stats: &app.sync_stats,
}; };
+3 -1
View File
@@ -326,6 +326,7 @@ pub fn render_edit_task_popup(
title_cursor: usize, title_cursor: usize,
notes: &str, notes: &str,
notes_cursor: usize, notes_cursor: usize,
notes_scroll: u16,
active_field: usize, active_field: usize,
) { ) {
let popup_area = centered_rect(75, 14, area); let popup_area = centered_rect(75, 14, area);
@@ -382,7 +383,8 @@ pub fn render_edit_task_popup(
let notes_lines: Vec<Line> = notes.lines().map(|l| Line::from(Span::raw(l.to_string()))).collect(); let notes_lines: Vec<Line> = notes.lines().map(|l| Line::from(Span::raw(l.to_string()))).collect();
let notes_para = Paragraph::new(Text::from(notes_lines)) let notes_para = Paragraph::new(Text::from(notes_lines))
.block(notes_block) .block(notes_block)
.wrap(Wrap { trim: false }); .wrap(Wrap { trim: false })
.scroll((notes_scroll, 0));
frame.render_widget(notes_para, rows[2]); frame.render_widget(notes_para, rows[2]);
// ── Date buttons row ── // ── Date buttons row ──
+3 -1
View File
@@ -45,6 +45,7 @@ pub struct AppView<'a> {
pub network_status: &'a NetworkStatus, pub network_status: &'a NetworkStatus,
pub task_list_scroll: u16, pub task_list_scroll: u16,
pub detail_scroll: u16, pub detail_scroll: u16,
pub notes_scroll: u16,
pub auth_error: Option<&'a str>, pub auth_error: Option<&'a str>,
pub sync_stats: &'a SyncStats, pub sync_stats: &'a SyncStats,
} }
@@ -99,7 +100,8 @@ pub fn draw(frame: &mut Frame, view: AppView) {
Popup::Input => render_input_popup(frame, area, view.popup_input, view.popup_cursor), Popup::Input => render_input_popup(frame, area, view.popup_input, view.popup_cursor),
Popup::EditTask { field } => render_edit_task_popup( Popup::EditTask { field } => render_edit_task_popup(
frame, area, view.popup_input, view.popup_cursor, frame, area, view.popup_input, view.popup_cursor,
view.popup_secondary, view.popup_secondary_cursor, *field, view.popup_secondary, view.popup_secondary_cursor,
view.notes_scroll, *field,
), ),
Popup::DatePicker => render_date_picker(frame, area, view.draft_date), Popup::DatePicker => render_date_picker(frame, area, view.draft_date),
Popup::ConfirmDelete => render_confirm_popup(frame, area), Popup::ConfirmDelete => render_confirm_popup(frame, area),