diff --git a/src/app.rs b/src/app.rs index d6a9120..cdfc425 100644 --- a/src/app.rs +++ b/src/app.rs @@ -39,7 +39,8 @@ pub struct App { pub task_list_scroll: u16, pub detail_scroll: u16, pub notes_scroll: u16, - pub calendar_scroll: u16, + pub calendar_scrolls: [u16; 4], + pub calendar_active_week: usize, pub db: Arc, #[allow(dead_code)] pub api_client: Arc, @@ -110,7 +111,8 @@ impl App { task_list_scroll: 0, detail_scroll: 0, notes_scroll: 0, - calendar_scroll: 0, + calendar_scrolls: [0; 4], + calendar_active_week: 0, db, api_client, needs_auth: !has_token, @@ -312,12 +314,24 @@ impl App { match key.code { KeyCode::Tab => { - self.focus = match self.focus { - Focus::Tabs => Focus::TaskList, - Focus::TaskList => Focus::Detail, - Focus::Detail => Focus::Calendar, - Focus::Calendar => Focus::Tabs, - }; + match self.focus { + Focus::Calendar => { + if self.calendar_active_week < 3 { + self.calendar_active_week += 1; + } else { + self.calendar_active_week = 0; + self.focus = Focus::Tabs; + } + } + _ => { + self.focus = match self.focus { + Focus::Tabs => Focus::TaskList, + Focus::TaskList => Focus::Detail, + Focus::Detail => Focus::Calendar, + _ => Focus::Tabs, + }; + } + } } KeyCode::Up if key.modifiers.contains(KeyModifiers::ALT) => { if self.focus == Focus::TaskList && !self.tasks.is_empty() { @@ -340,7 +354,7 @@ impl App { self.detail_scroll = self.detail_scroll.saturating_sub(1); } Focus::Calendar => { - self.calendar_scroll = self.calendar_scroll.saturating_sub(1); + self.calendar_scrolls[self.calendar_active_week] = self.calendar_scrolls[self.calendar_active_week].saturating_sub(1); } _ => {} }, @@ -355,24 +369,40 @@ impl App { self.detail_scroll += 1; } Focus::Calendar => { - self.calendar_scroll += 1; + self.calendar_scrolls[self.calendar_active_week] = self.calendar_scrolls[self.calendar_active_week].saturating_add(1); } _ => {} }, KeyCode::Right => { - if self.focus == Focus::Tabs && !self.lists.is_empty() { - if self.selected_list + 1 < self.lists.len() { - self.selected_list += 1; - self.load_tasks(); + match self.focus { + Focus::Tabs => { + if !self.lists.is_empty() && self.selected_list + 1 < self.lists.len() { + self.selected_list += 1; + self.load_tasks(); + } } + Focus::Calendar => { + if self.calendar_active_week < 3 { + self.calendar_active_week += 1; + } + } + _ => {} } } KeyCode::Left => { - if self.focus == Focus::Tabs && !self.lists.is_empty() { - if self.selected_list > 0 { - self.selected_list -= 1; - self.load_tasks(); + match self.focus { + Focus::Tabs => { + if !self.lists.is_empty() && self.selected_list > 0 { + self.selected_list -= 1; + self.load_tasks(); + } } + Focus::Calendar => { + if self.calendar_active_week > 0 { + self.calendar_active_week -= 1; + } + } + _ => {} } } KeyCode::Char('n') | KeyCode::Char('N') => { diff --git a/src/main.rs b/src/main.rs index c92e7f9..66bd13d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -150,7 +150,8 @@ fn main() -> io::Result<()> { task_list_scroll: app.task_list_scroll, detail_scroll: app.detail_scroll, notes_scroll: app.notes_scroll, - calendar_scroll: app.calendar_scroll, + calendar_scrolls: &app.calendar_scrolls, + calendar_active_week: app.calendar_active_week, auth_error: app.auth_error.as_deref(), sync_stats: &app.sync_stats, }; diff --git a/src/ui/components.rs b/src/ui/components.rs index 9bcc08f..cb0ffa7 100644 --- a/src/ui/components.rs +++ b/src/ui/components.rs @@ -602,7 +602,8 @@ pub fn render_calendar_panel( area: Rect, events: &[CalendarEvent], focused: bool, - _scroll: u16, + scrolls: &[u16; 4], + active_week: usize, ) { if area.width < 20 || area.height < 3 { return; @@ -629,7 +630,7 @@ pub fn render_calendar_panel( let week_title = format!(" W/C {} ", week_start.format("%d/%m")); let col_area = cols[week_idx]; - let border = if focused { FOCUS_COLOR } else { Color::DarkGray }; + let border = if focused && week_idx == active_week { FOCUS_COLOR } else { Color::DarkGray }; let block = Block::default() .borders(Borders::ALL) .border_style(Style::default().fg(border)) @@ -651,9 +652,6 @@ pub fn render_calendar_panel( continue; } - let inner = block.inner(col_area); - let inner_h = inner.height as usize; - let mut lines: Vec = Vec::new(); for day_offset in 0..7 { @@ -661,6 +659,8 @@ pub fn render_calendar_panel( let day_style = if day == today { Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD) + } else if matches!(day.weekday(), chrono::Weekday::Sat | chrono::Weekday::Sun) { + Style::default().fg(Color::Magenta).add_modifier(Modifier::BOLD) } else { Style::default().fg(Color::Cyan).add_modifier(Modifier::BOLD) }; @@ -679,10 +679,6 @@ pub fn render_calendar_panel( ); lines.push(Line::from(Span::styled(day_label, day_style))); - if lines.len() >= inner_h { - break; - } - for event in events.iter().filter(|e| e.start.map_or(false, |s| s.date() == day)) { let time_str = event.start.map(|s| s.format("%H:%M").to_string()).unwrap_or_default(); let line_text = format!(" {} {}", time_str, event.summary); @@ -690,14 +686,12 @@ pub fn render_calendar_panel( line_text, Style::default().fg(DETAIL_COLOR), ))); - - if lines.len() >= inner_h { - break; - } } } - let paragraph = Paragraph::new(Text::from(lines)).block(block); + let paragraph = Paragraph::new(Text::from(lines)) + .block(block) + .scroll((scrolls[week_idx], 0)); frame.render_widget(paragraph, col_area); } } diff --git a/src/ui/mod.rs b/src/ui/mod.rs index a726970..9508d1c 100644 --- a/src/ui/mod.rs +++ b/src/ui/mod.rs @@ -48,7 +48,8 @@ pub struct AppView<'a> { pub detail_scroll: u16, pub notes_scroll: u16, pub calendar_events: &'a [CalendarEvent], - pub calendar_scroll: u16, + pub calendar_scrolls: &'a [u16; 4], + pub calendar_active_week: usize, pub auth_error: Option<&'a str>, pub sync_stats: &'a SyncStats, } @@ -104,7 +105,8 @@ pub fn draw(frame: &mut Frame, view: AppView) { calendar_area, view.calendar_events, is_calendar_focused, - view.calendar_scroll, + view.calendar_scrolls, + view.calendar_active_week, ); render_status_bar(frame, status_area, view.network_status, view.sync_stats);