Skip to content

Commit

Permalink
Merge pull request #20 from saying121/dev
Browse files Browse the repository at this point in the history
feat(tui): show user's avatar
  • Loading branch information
saying121 authored Aug 25, 2024
2 parents fd26e6d + 952a2e1 commit 91d2557
Show file tree
Hide file tree
Showing 27 changed files with 918 additions and 412 deletions.
693 changes: 615 additions & 78 deletions Cargo.lock

Large diffs are not rendered by default.

8 changes: 7 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,20 @@ paste = { version = "^1" }

ratatui = { version = "^0.28" }
tui-textarea = { version = "^0.6" }
tabled = { version = "^0.15", default-features = true }
ratatui-image = { version = "^1", default-features = true, features = ["crossterm"] }
image = { version = "^0.25", default-features = true, features = ["jpeg"] }

tabled = { version = "^0.15" }

open = { version = "^5" }

colored = { version = "^2" }
unicode-width = { version = "^0.1" }
scraper = { version = "^0.20" }
strum = { version = "^0.26" }
simsearch = { version = "^0.2" }
# nucleo = { version = "0.4.0" }
# nucleo-matcher = { version = "0.3.1" }

notify-rust = { version = "^4.10", default-features = false, features = ["d"] }
rayon = { version = "^1" }
Expand Down
4 changes: 2 additions & 2 deletions crates/lcode-config/src/config/user_nested.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,8 @@ impl Display for Suffix {
}

impl Urls {
pub fn new(suffi: Suffix) -> Self {
let suffix = match suffi {
pub fn new(suffix: Suffix) -> Self {
let suffix = match suffix {
Suffix::Cn => "cn",
Suffix::Com => "com",
};
Expand Down
11 changes: 5 additions & 6 deletions crates/lcode/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,9 @@ tracing = { workspace = true }
tracing-appender = { workspace = true }
tracing-subscriber = { workspace = true }

# nucleo = { version = "0.4.0" }
# nucleo-matcher = { version = "0.3.1" }
simsearch = { version = "^0.2" }
# nucleo = { workspace = true }
# nucleo-matcher = { workspace = true }
simsearch = { workspace = true }

inquire = { workspace = true }
atoi = { workspace = true }
Expand All @@ -48,9 +48,8 @@ ratatui = { workspace = true }
crossterm = { workspace = true, features = ["event-stream"] }
tui-textarea = { workspace = true }

# Shit, decode leetcode avator error: `InvalidSignature`
# ratatui-image = { version = "^1", default-features = true }
# image = { version = "^0.24", default-features = true, features = ["png", "gif", "jpeg"] }
ratatui-image = { workspace = true }
image = { workspace = true }

# tui-term = { version = "0.1.2" }
# tui-logger = { version = "0.9.5" }
Expand Down
2 changes: 1 addition & 1 deletion crates/lcode/src/app/impl_app/edit_qs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ impl<'app_lf> App<'app_lf> {
tokio::spawn(async move {
let qs = glob_leetcode()
.await
.get_qs_detail(idslug, force)
.get_qs_detail(idslug, force, true)
.await
.unwrap_or_else(Question::new_with_info);
eve_tx
Expand Down
49 changes: 47 additions & 2 deletions crates/lcode/src/app/impl_app/get_info.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
use std::{path::PathBuf, time::Duration};
use std::{path::PathBuf, sync::mpsc, thread, time::Duration};

use image::Rgb;
use lcode_config::global::G_USER_CONFIG;
use leetcode_api::{
glob_leetcode,
leetcode::resps::{checkin::TotalPoints, pass_qs::PassData, user_data::UserStatus},
};
use miette::IntoDiagnostic;
use notify_rust::Notification;
use ratatui::prelude::*;
use ratatui_image::{picker::Picker, protocol::StatefulProtocol, thread::ThreadProtocol, Resize};
use tokio::join;

use crate::{app::inner::App, mytui::myevent::UserEvent};
Expand Down Expand Up @@ -96,14 +100,55 @@ impl<'app> App<'app> {
});
}

pub fn get_status_done(&mut self, info: (UserStatus, TotalPoints, PassData, PathBuf)) {
pub fn get_status_done(
&mut self,
info: (UserStatus, TotalPoints, PassData, PathBuf),
) -> miette::Result<()> {
(
self.info.user_status,
self.info.points,
self.info.pass_data,
self.info.avatar_path,
) = info;

if self.img_state.is_none() {
#[cfg(not(target_os = "windows"))]
let mut picker =
Picker::from_termios().or(Err(miette::miette!("Image Picker error")))?;
#[cfg(target_os = "windows")]
let mut picker = Picker::new((11, 11));

picker.guess_protocol();
picker.background_color = Some(Rgb::<u8>([255, 0, 255]));
let dyn_img = image::ImageReader::open(&self.info.avatar_path)
.into_diagnostic()?
.with_guessed_format()
.into_diagnostic()?
.decode()
.into_diagnostic()?
.resize_to_fill(150, 150, ratatui_image::FilterType::Triangle);

// Send a [ResizeProtocol] to resize and encode it in a separate thread.
let (tx_worker, rec_worker) =
mpsc::channel::<(Box<dyn StatefulProtocol>, Resize, Rect)>();

// Resize and encode in background thread.
let tx_main_render = self.events.tx.clone();
thread::spawn(move || loop {
if let Ok((mut protocol, resize, area)) = rec_worker.recv() {
protocol.resize_encode(&resize, None, area);
if let Err(e) = tx_main_render.send(UserEvent::RedrawImg(protocol)) {
tracing::error!("{e}");
}
}
});

let async_state = ThreadProtocol::new(tx_worker, picker.new_resize_protocol(dyn_img));
self.img_state = Some(async_state);
}

self.render();

Ok(())
}
}
4 changes: 3 additions & 1 deletion crates/lcode/src/app/inner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use leetcode_api::{
leetcode::{question::qs_detail::Question, IdSlug},
};
use miette::{IntoDiagnostic, Result};
use ratatui_image::thread::ThreadProtocol;
use tokio::{
fs::{File, OpenOptions},
io::{AsyncBufReadExt, AsyncWriteExt, BufReader},
Expand All @@ -16,7 +17,6 @@ use crate::{
mytui::myevent::EventsHandler,
};

#[derive(Debug)]
#[derive(Default)]
pub struct App<'app> {
pub titles: Box<[&'app str]>,
Expand All @@ -26,6 +26,7 @@ pub struct App<'app> {
pub edit: EditCode<'app>,
pub topic: topic::TopicTagsQS<'app>,
pub info: info::Info<'app>,
pub img_state: Option<ThreadProtocol>,

pub cur_qs: Question,

Expand Down Expand Up @@ -173,6 +174,7 @@ impl<'app_lf> App<'app_lf> {
.expect("get IdSlug failed"),
),
false,
true,
)
.await?;
}
Expand Down
6 changes: 3 additions & 3 deletions crates/lcode/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ pub async fn run() -> Result<()> {
Commands::Detail(args) => {
let qs = glob_leetcode()
.await
.get_qs_detail(IdSlug::Id(args.id), args.force)
.get_qs_detail(IdSlug::Id(args.id), args.force, true)
.await?;
qs.render_with_mdcat();
},
Expand Down Expand Up @@ -228,7 +228,7 @@ async fn fzy_search(args: InterArgs) -> Result<(), miette::Error> {

let qs = glob_leetcode()
.await
.get_qs_detail(IdSlug::Id(id), detail_args.force)
.get_qs_detail(IdSlug::Id(id), detail_args.force, true)
.await?;
qs.render_with_mdcat();
},
Expand All @@ -251,7 +251,7 @@ async fn fzy_search(args: InterArgs) -> Result<(), miette::Error> {

let qs = glob_leetcode()
.await
.get_qs_detail(IdSlug::Id(id), false)
.get_qs_detail(IdSlug::Id(id), false, true)
.await?;
qs.render_with_mdcat();
},
Expand Down
2 changes: 1 addition & 1 deletion crates/lcode/src/editor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ impl Editor {

let qs = glob_leetcode()
.await
.get_qs_detail(idslug, false)
.get_qs_detail(idslug, false, true)
.await?;

if G_USER_CONFIG.config.cargo_integr && G_USER_CONFIG.config.lang.as_str() == "rust" {
Expand Down
12 changes: 12 additions & 0 deletions crates/lcode/src/mytui/helper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,18 @@ pub(super) fn centered_rect_percent(percent_x: u16, percent_y: u16, r: Rect) ->
.areas(popup_layout);
area
}
pub(super) fn top_right_rect_percent(percent_x: u16, percent_y: u16, r: Rect) -> Rect {
let [popup_layout, _] = Layout::default()
.direction(Direction::Vertical)
.constraints([Constraint::Percentage(percent_y), Constraint::Min(0)].as_ref())
.areas(r);

let [_, area] = Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Min(0), Constraint::Percentage(percent_x)].as_ref())
.areas(popup_layout);
area
}

pub fn title_block<'a, T>(title: T) -> Block<'a>
where
Expand Down
8 changes: 7 additions & 1 deletion crates/lcode/src/mytui/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ pub async fn run() -> Result<()> {
Term::stop()?;
break;
},
UserEvent::UserInfo(info) => app.get_status_done(*info),
UserEvent::UserInfo(info) => app.get_status_done(*info)?,
UserEvent::SubmitDone(s_res) => {
// update info
if s_res.total_correct == s_res.total_testcases {
Expand All @@ -56,6 +56,12 @@ pub async fn run() -> Result<()> {
},
Event::FocusGained | Event::FocusLost | Event::Mouse(_) | Event::Paste(_) => {},
},
UserEvent::RedrawImg(protocol) => {
if let Some(state) = &mut app.img_state {
state.set_protocol(protocol);
app.render();
}
},
}
}

Expand Down
72 changes: 0 additions & 72 deletions crates/lcode/src/mytui/my_widget/as_image.rs

This file was deleted.

1 change: 0 additions & 1 deletion crates/lcode/src/mytui/my_widget/mod.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1 @@
// pub mod as_image;
pub mod botton;
4 changes: 2 additions & 2 deletions crates/lcode/src/mytui/myevent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,15 @@ use leetcode_api::leetcode::{
resps::{checkin::TotalPoints, pass_qs::PassData, run_res::RunResult, user_data::UserStatus},
};
use miette::Result;
use ratatui_image::protocol::StatefulProtocol;
use tokio::{
select,
sync::{mpsc, oneshot},
task::JoinHandle,
};
use tracing::error;

#[derive(PartialEq)]
#[derive(Clone)]
#[derive(Debug)]
#[non_exhaustive]
pub enum UserEvent {
TermEvent(Event),
Expand All @@ -34,6 +33,7 @@ pub enum UserEvent {
Quit,

Render,
RedrawImg(Box<dyn StatefulProtocol>),
}

#[derive(Debug)]
Expand Down
34 changes: 12 additions & 22 deletions crates/lcode/src/mytui/ui/info.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use lcode_config::global::G_THEME;
use ratatui::{prelude::*, widgets::*};
use ratatui_image::{thread::ThreadImage, Resize};

use crate::{app::inner::App, mytui::helper};

Expand Down Expand Up @@ -76,29 +77,18 @@ pub fn draw_info(f: &mut Frame, app: &mut App, area: Rect) {
.split(chunks[0]);
assert!(chunks1.len() >= 2);
f.render_widget(user_info_list, chunks1[0]);
draw_avatar(
f,
app,
helper::top_right_rect_percent(20, 100, chunks1[0].inner(Margin::new(1, 1))),
);
f.render_widget(pass_info_list, chunks1[1]);
f.render_stateful_widget(keymap_list, chunks[1], &mut app.info.keymap.list_state);
}

// pub fn draw_avatar(
// f: &mut Frame,
// app: &mut App,
// area: Rect,
// ) -> Result<(), Box<dyn std::error::Error>> {
// let mut picker = Picker::from_termios()?;
// picker.guess_protocol();
// picker.background_color = Some(image::Rgb::<u8>([255, 0, 255]));
// let dyn_img = Reader::open(app.info.avatar_path.as_path())?.decode()?;
//
// let mut image_state = picker.new_resize_protocol(dyn_img);
//
// // let (tx_worker, rec_worker) = mpsc::channel::<(Box<dyn StatefulProtocol>, Resize, Rect)>();
//
// // let mut async_state = ThreadProtocol::new(tx_worker, picker.new_resize_protocol(dyn_img));
// // let img = ThreadImage::new().resize(Resize::Fit);
//
// let img = StatefulImage::new(None).resize(Resize::Fit);
// f.render_stateful_widget(img, area, &mut image_state);
//
// Ok(())
// }
pub fn draw_avatar(f: &mut Frame, app: &mut App, area: Rect) {
let image = ThreadImage::default().resize(Resize::Fit(None));
if let Some(state) = &mut app.img_state {
f.render_stateful_widget(image, area, state);
}
}
Loading

0 comments on commit 91d2557

Please sign in to comment.