pub mod cmds;
use crossterm::event::Event as CrossEvent;
use leetcode_api::{
dao::query::{self, PassStat, Query},
entities::{new_index, topic_tags},
};
use rayon::prelude::*;
use tui_textarea::Input;
use self::cmds::{diff, intputline, question, sync_bar, topics};
use crate::fuzzy_search::filter;
#[derive(PartialEq, Eq)]
#[derive(Clone, Copy)]
#[derive(Default)]
#[derive(Debug)]
pub enum Tab2Panel {
#[default]
AllTopics,
UserTopics,
Difficulty,
Questions,
}
impl Tab2Panel {
fn left(&mut self) {
*self = match self {
Self::AllTopics | Self::Difficulty => Self::AllTopics,
Self::UserTopics => Self::UserTopics,
Self::Questions => Self::Difficulty,
}
}
fn right(&mut self) {
*self = match self {
Self::AllTopics | Self::UserTopics => Self::Difficulty,
Self::Difficulty | Self::Questions => Self::Questions,
}
}
fn up(&mut self) {
*self = match self {
Self::AllTopics | Self::UserTopics => Self::AllTopics,
Self::Difficulty => Self::Difficulty,
Self::Questions => Self::Questions,
}
}
fn down(&mut self) {
*self = match self {
Self::AllTopics | Self::UserTopics => Self::UserTopics,
Self::Difficulty => Self::Difficulty,
Self::Questions => Self::Questions,
}
}
}
#[derive(Clone)]
#[derive(Default)]
#[derive(Debug)]
pub struct TopicTagsQS<'tab2> {
pub topic: topics::TopicsState,
pub question_state: question::TopicQuestionState,
pub sync_bar: sync_bar::BarState,
pub index: Tab2Panel,
pub inputline: intputline::InputLine<'tab2>,
pub difficulty: diff::DiffState,
pub ac_status: Box<[PassStat]>,
}
impl TopicTagsQS<'_> {
pub fn keymap_insert(&mut self, event: CrossEvent) -> bool {
match event.into() {
Input { key: tui_textarea::Key::Esc, .. } => self.be_out_edit(),
Input { key: tui_textarea::Key::Enter, .. } => false, input => {
let trigger = self.inputline.handle_input(input);
if trigger {
self.refresh_filter_by_input();
}
trigger
},
}
}
pub fn be_out_edit(&mut self) -> bool {
self.inputline.out_edit();
true
}
pub fn enter_input_line(&mut self) -> bool {
self.inputline.enter_input();
true
}
pub fn up(&mut self) -> bool {
match self.index {
Tab2Panel::AllTopics => self.prev_topic(),
Tab2Panel::UserTopics => self.prev_user_topic(),
Tab2Panel::Difficulty => self.prev_diff(),
Tab2Panel::Questions => self.prev_qs(),
}
true
}
pub fn down(&mut self) -> bool {
match self.index {
Tab2Panel::AllTopics => self.next_topic(),
Tab2Panel::UserTopics => self.next_user_topic(),
Tab2Panel::Difficulty => self.next_diff(),
Tab2Panel::Questions => self.next_qs(),
}
true
}
pub fn panel_left(&mut self) -> bool {
self.index.left();
true
}
pub fn panel_right(&mut self) -> bool {
self.index.right();
true
}
pub fn panel_up(&mut self) -> bool {
self.index.up();
true
}
pub fn panel_down(&mut self) -> bool {
self.index.down();
true
}
pub fn top(&mut self) -> bool {
match self.index {
Tab2Panel::AllTopics => self.first_topic(),
Tab2Panel::UserTopics => self.first_user_topic(),
Tab2Panel::Difficulty => self.first_diff(),
Tab2Panel::Questions => self.first_qs(),
}
true
}
pub fn bottom(&mut self) -> bool {
match self.index {
Tab2Panel::AllTopics => self.last_topic(),
Tab2Panel::UserTopics => self.last_user_topic(),
Tab2Panel::Difficulty => self.last_diff(),
Tab2Panel::Questions => self.last_qs(),
}
true
}
pub async fn toggle_cursor(&mut self) -> bool {
match self.index {
Tab2Panel::AllTopics => self.add_user_topic().await,
Tab2Panel::UserTopics => self.rm_user_topic().await,
Tab2Panel::Difficulty => self.toggle_diff().await,
Tab2Panel::Questions => true,
}
}
}
impl TopicTagsQS<'_> {
pub async fn toggle_diff(&mut self) -> bool {
self.difficulty.toggle_diff();
self.refresh_filter_by_topic_diff()
.await;
self.refresh_filter_by_input();
true
}
pub fn prev_diff(&mut self) {
self.difficulty.prev();
}
pub fn next_diff(&mut self) {
self.difficulty.next();
}
pub fn first_diff(&mut self) {
self.difficulty.first();
}
pub fn last_diff(&mut self) {
self.difficulty.last();
}
}
impl<'tab2> TopicTagsQS<'tab2> {
pub async fn new() -> TopicTagsQS<'tab2> {
let (new_index, topic_tags, ac_status) = Self::base_info().await;
Self {
topic: topics::TopicsState::new(topic_tags),
question_state: question::TopicQuestionState::new(new_index),
sync_bar: sync_bar::BarState::default(),
index: Tab2Panel::AllTopics,
inputline: intputline::InputLine::default(),
difficulty: diff::DiffState::new(
ac_status
.iter()
.map(|v| v.diff.clone())
.collect(),
),
ac_status,
}
}
pub async fn base_info() -> (
Box<[new_index::Model]>,
Box<[topic_tags::Model]>,
Box<[PassStat]>,
) {
let (all_qs_res, topic_res, status) = tokio::join!(
query::Query::query_all_new_index(None),
query::Query::query_all_topic(),
query::Query::query_status()
);
(
all_qs_res.unwrap_or_default().into(),
topic_res.unwrap_or_default().into(),
status.unwrap_or_default().into(),
)
}
pub fn update_percent(&mut self, perc: f64) {
self.sync_bar.update(perc);
}
pub fn refresh_filter_by_input(&mut self) {
self.question_state.filtered_qs = self
.question_state
.all_qs
.par_iter()
.filter(|&v| filter(self.inputline.first_line(), &v.to_string()))
.cloned()
.collect();
}
pub async fn refresh_filter_by_topic_diff(&mut self) {
if self.topic.user_topic_tags.is_empty() {
self.question_state.all_qs =
Query::query_all_new_index(self.difficulty.user_diff.clone())
.await
.unwrap_or_default()
.into();
}
else {
let diff = self.difficulty.user_diff.clone();
self.question_state.all_qs =
Query::query_by_topic(&self.topic.user_topic_tags, Some(diff))
.await
.unwrap_or_default()
.into();
}
}
}
impl TopicTagsQS<'_> {
pub async fn rm_user_topic(&mut self) -> bool {
let trigger = self.topic.rm_user_topic();
if trigger {
self.refresh_filter_by_topic_diff()
.await;
self.refresh_filter_by_input();
}
trigger
}
pub async fn add_user_topic(&mut self) -> bool {
let trigger = self.topic.add_user_topic();
if trigger {
self.refresh_filter_by_topic_diff()
.await;
self.refresh_filter_by_input();
}
trigger
}
pub fn first_topic(&mut self) {
self.topic.first();
}
pub fn last_topic(&mut self) {
self.topic.last();
}
pub fn next_topic(&mut self) {
self.topic.next();
}
pub fn prev_topic(&mut self) {
self.topic.prev();
}
}
impl TopicTagsQS<'_> {
pub fn next_qs(&mut self) {
self.question_state.next();
}
pub fn prev_qs(&mut self) {
self.question_state.prev();
}
pub fn first_qs(&mut self) {
self.question_state
.filtered_topic_qs_state
.select(Some(0));
}
pub fn last_qs(&mut self) {
self.question_state.last();
}
pub fn cur_qs_slug(&self) -> Option<String> {
self.question_state.cur_qs_slug()
}
}
impl TopicTagsQS<'_> {
pub fn prev_user_topic(&mut self) {
self.topic.prev_user();
}
pub fn next_user_topic(&mut self) {
self.topic.next_user();
}
pub fn last_user_topic(&mut self) {
self.topic.last_user();
}
pub fn first_user_topic(&mut self) {
self.topic.first_user();
}
}