Skip to content

Commit e46b676

Browse files
authored
Merge pull request #3 from akarsh1995/dev
v0.3.0
2 parents c3dd527 + 6b072e0 commit e46b676

30 files changed

+1074
-641
lines changed

CHANGELOG.md

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,6 @@ All notable changes to this project will be documented in this file.
77
- Sort questions by:
88
- likes dislikes ratio.
99

10-
- Filter
11-
12-
- Search feature.
13-
1410
- Scroll bar visible list
1511

1612
- Take input directly from the user lc session
@@ -22,17 +18,28 @@ All notable changes to this project will be documented in this file.
2218

2319
- Invalidate questions cache through `userSessionProgress`
2420

25-
## [0.2.1] - [Unreleased]
21+
- Fix re-request when there's network error in fetching question.
22+
23+
## [0.2.1] - 2023-08-10
2624

2725
### Added
2826

2927
- Neetcode 75 question list.
28+
- Search feature on keypress `/`
3029

3130
### Changed
3231

3332
- Not null constraints on the fields that are never null from the server.
3433
- `QuestionModelContainer { question: RefCell<QuestionModel> }` changed to `Rc<RefCell<QuestionModel>>`
3534
- As prior implemented hash. Hashables should not be mutable.
35+
- Colorscheme as per tokyonight style.
36+
37+
### Fixed
38+
39+
- Some questions did not appear in "All" question list because they were not attached to any topic.
40+
- To resolve Unknown topic tag is added to the questions which do not have any topic tag.
41+
- App now successfully restores the terminal state. No residual prints on closing the app.
42+
- High CPU usage due to 100ms tick interval. Now tick interval changed to 5 seconds.
3643

3744
## [0.2.0] - 2023-07-30
3845

Cargo.lock

Lines changed: 11 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "leetcode-tui-rs"
3-
version = "0.2.0"
3+
version = "0.3.0"
44
edition = "2021"
55
authors = ["Akarsh <[email protected]>"]
66
description = "Leetcode terminal UI. Helps you browse leetcode stats and manage your leetcode from terminal."
@@ -18,7 +18,7 @@ async-trait = "0.1.71"
1818
crossbeam = "0.8.2"
1919
crossterm = { version = "0.26.1", features = ["event-stream"] }
2020
futures = "0.3.28"
21-
futures-timer = "3.0.2"
21+
fuzzy-matcher = "0.3.7"
2222
html2text = "0.6.0"
2323
indexmap = "2.0.0"
2424
kdam = "0.3.0"

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
# Use Leetcode in your terminal.
44

5-
![Demo](https://vhs.charm.sh/vhs-7mc1SjatwAFIfEpRjylgaO.gif)
5+
![Demo](https://vhs.charm.sh/vhs-6HARsZDGe7mSVwTepHFUJv.gif)
66

77
### Why this TUI:
88

@@ -41,6 +41,8 @@ leetui
4141
- Submit and run solution in multiple languages
4242
- Read Stats of your performance
4343
- Solved questions are marked with ✔️
44+
- Neetcode 75
45+
- For Fuzzy search questions in the question list use `/`
4446

4547
Few related projects:
4648

src/app_ui/app.rs

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
use crate::app_ui::widgets::CommonStateManager;
12
use std::collections::VecDeque;
23
use std::rc::Rc;
34
use std::sync::atomic::AtomicBool;
45
use std::sync::Arc;
56

6-
use super::async_task_channel::{ChannelRequestSender, ChannelResponseReceiver};
7+
use super::async_task_channel::{ChannelRequestSender, TaskResponse};
78
use super::event::VimPingSender;
89
use super::widgets::help_bar::HelpBar;
910
use super::widgets::notification::{Notification, WidgetName, WidgetVariant};
@@ -14,6 +15,7 @@ use super::widgets::topic_list::TopicTagListWidget;
1415
use super::widgets::Widget;
1516
use crate::config::Config;
1617
use crate::errors::AppResult;
18+
use crossterm::event::{KeyCode, KeyEvent, KeyModifiers};
1719
use indexmap::IndexMap;
1820

1921
/// Application.
@@ -28,8 +30,6 @@ pub struct App {
2830

2931
pub task_request_sender: ChannelRequestSender,
3032

31-
pub task_response_recv: ChannelResponseReceiver,
32-
3333
pub pending_notifications: VecDeque<Option<Notification>>,
3434

3535
pub(crate) popup_stack: Vec<Popup>,
@@ -45,7 +45,6 @@ impl App {
4545
/// Constructs a new instance of [`App`].
4646
pub fn new(
4747
task_request_sender: ChannelRequestSender,
48-
task_response_recv: ChannelResponseReceiver,
4948
vim_tx: VimPingSender,
5049
vim_running: Arc<AtomicBool>,
5150
config: Rc<Config>,
@@ -82,7 +81,6 @@ impl App {
8281
widget_map: IndexMap::from(order),
8382
selected_wid_idx: 0,
8483
task_request_sender,
85-
task_response_recv,
8684
pending_notifications: vec![].into(),
8785
popup_stack: vec![],
8886
vim_running,
@@ -158,7 +156,11 @@ impl App {
158156
}
159157

160158
/// Handles the tick event of the terminal.
161-
pub fn tick(&mut self) -> AppResult<()> {
159+
pub fn tick(&mut self, task: Option<TaskResponse>) -> AppResult<()> {
160+
if let Some(task) = task {
161+
self.process_task(task)?;
162+
}
163+
162164
if let Some(popup) = self.get_current_popup_mut() {
163165
if !popup.is_active() {
164166
self.popup_stack.pop();
@@ -177,19 +179,15 @@ impl App {
177179
self.pending_notifications.push_back(Some(notif));
178180
}
179181
}
180-
181-
self.check_for_task()?;
182182
self.process_pending_notification()?;
183183
Ok(())
184184
}
185185

186-
fn check_for_task(&mut self) -> AppResult<()> {
187-
if let Ok(task_result) = self.task_response_recv.try_recv() {
188-
self.widget_map
189-
.get_mut(&task_result.get_widget_name())
190-
.unwrap()
191-
.process_task_response(task_result)?;
192-
}
186+
pub fn process_task(&mut self, task: TaskResponse) -> AppResult<()> {
187+
self.widget_map
188+
.get_mut(&task.get_widget_name())
189+
.unwrap()
190+
.process_task_response(task)?;
193191
Ok(())
194192
}
195193

@@ -218,4 +216,36 @@ impl App {
218216
pub fn quit(&mut self) {
219217
self.running = false;
220218
}
219+
220+
pub fn handle_key_events(&mut self, key_event: KeyEvent) -> AppResult<()> {
221+
let mut p_notif = None;
222+
223+
// if ui has active popups then send only events registered with popup
224+
if let Some(popup) = self.get_current_popup_mut() {
225+
p_notif = popup.handler(key_event)?;
226+
} else if self.get_current_widget().parent_can_handle_events() {
227+
match key_event.code {
228+
KeyCode::Left => p_notif = self.next_widget()?,
229+
KeyCode::Right => p_notif = self.prev_widget()?,
230+
KeyCode::Char('q') | KeyCode::Char('Q') => {
231+
self.running = false;
232+
}
233+
KeyCode::Char('c') | KeyCode::Char('C') => {
234+
if key_event.modifiers == KeyModifiers::CONTROL {
235+
self.running = false;
236+
}
237+
}
238+
_ => {
239+
p_notif = self.get_current_widget_mut().handler(key_event)?;
240+
}
241+
}
242+
} else {
243+
p_notif = self.get_current_widget_mut().handler(key_event)?;
244+
}
245+
246+
self.pending_notifications.push_back(p_notif);
247+
self.tick(None)?;
248+
249+
Ok(())
250+
}
221251
}

src/app_ui/async_task_channel.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,8 +111,3 @@ use super::widgets::notification::WidgetName;
111111

112112
pub type RequestSendError = tokio::sync::mpsc::error::SendError<TaskRequest>;
113113
pub type RequestRecvError = tokio::sync::mpsc::error::TryRecvError;
114-
115-
pub type ResponseSendError = crossbeam::channel::SendError<TaskResponse>;
116-
pub type ResponseReceiveError = crossbeam::channel::RecvError;
117-
118-
// pub type

0 commit comments

Comments
 (0)