Skip to content

Commit

Permalink
feat: Add modal to display assets in an item
Browse files Browse the repository at this point in the history
  • Loading branch information
heyrict committed Mar 16, 2020
1 parent af4502d commit 58e48e8
Show file tree
Hide file tree
Showing 4 changed files with 441 additions and 100 deletions.
46 changes: 41 additions & 5 deletions src/app.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::event::ModalState;
use crate::event::SaveModalState;
use dirs::config_dir;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
Expand Down Expand Up @@ -49,6 +49,8 @@ pub struct Question {
pub answer: Option<String>,
#[serde(default, with = "selection_flags_serde")]
pub user_selection: SelectionFlags,
#[serde(default)]
pub assets: Vec<String>,
#[serde(flatten)]
pub extra: HashMap<String, serde_json::Value>,
}
Expand Down Expand Up @@ -82,8 +84,9 @@ impl HasQuestionResult for Question {

#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Card {
question: String,
answer: String,
pub question: String,
pub answer: String,
pub assets: Vec<String>,
}

#[derive(Clone, Debug, Serialize, Deserialize)]
Expand Down Expand Up @@ -207,14 +210,21 @@ impl Home {
}
}

pub enum AssetsModalState {
Hidden,
Show(ListState),
}

pub struct Modal {
pub save_modal_state: ModalState,
pub save_modal_state: SaveModalState,
pub assets_modal_state: AssetsModalState,
}

impl Default for Modal {
fn default() -> Modal {
Modal {
save_modal_state: ModalState::Hidden,
save_modal_state: SaveModalState::Hidden,
assets_modal_state: AssetsModalState::Hidden,
}
}
}
Expand All @@ -227,6 +237,8 @@ pub struct Config {
pub show_usage: bool,
#[serde(default = "Config::_default_pretty_printing")]
pub pretty_printing: bool,
#[serde(default = "Config::_default_launcher")]
pub launcher: String,
}

impl Config {
Expand All @@ -239,6 +251,20 @@ impl Config {
const fn _default_pretty_printing() -> bool {
false
}
fn _default_launcher() -> String {
#[cfg(target_os = "macos")]
{
"open".to_owned()
}
#[cfg(target_os = "linux")]
{
"xdg-open".to_owned()
}
#[cfg(target_os = "windows")]
{
"explorer".to_owned()
}
}
}

impl Default for Config {
Expand All @@ -247,6 +273,7 @@ impl Default for Config {
items_per_line: Self::_default_items_per_line(),
show_usage: Self::_default_show_usage(),
pretty_printing: Self::_default_pretty_printing(),
launcher: Self::_default_launcher(),
}
}
}
Expand Down Expand Up @@ -306,6 +333,15 @@ impl Exam {
}
}

impl Item {
pub fn get_assets(&self) -> &Vec<String> {
match self {
Item::Question(question) => &question.assets,
Item::Card(card) => &card.assets,
}
}
}

impl Question {
pub fn num_selections(&self) -> usize {
self.selections.len()
Expand Down
21 changes: 15 additions & 6 deletions src/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ pub enum UpdateQuestionIndexEvent {
}

#[derive(Debug)]
pub enum UpdateHomeSelectedEvent {
pub enum UpdateListSelectedEvent {
Next,
Prev,
Home,
Expand All @@ -28,32 +28,41 @@ pub enum QuitAction {
}

#[derive(Debug)]
pub enum ModalState {
pub enum SaveModalState {
Hidden,
ShowSave,
ShowQuit(QuitAction),
}

#[derive(Debug)]
pub enum ModalActions {
Open(ModalState),
pub enum SaveModalActions {
Open(SaveModalState),
Quit(QuitAction),
Okay,
Cancel,
}

#[derive(Debug)]
pub enum AssetsModalActions {
Open,
Select(UpdateListSelectedEvent),
OpenFile,
Close,
}

#[derive(Debug)]
pub enum Messages {
Input(KeyEvent),
Resize,
ChangeRoute(AppRoute),
UpdateQuestionIndex(UpdateQuestionIndexEvent),
ScrollQuestion(u16),
UpdateHomeSelected(UpdateHomeSelectedEvent),
UpdateHomeSelected(UpdateListSelectedEvent),
UpdateJumpboxValue(u16),
ToggleSelection(SelectionFlags),
LoadFile,
ModalAction(ModalActions),
SaveModalAction(SaveModalActions),
AssetsModalAction(AssetsModalActions),
UnsavedChanges(bool),
FileLoaded(Exam),
SetOpenMode(OpenMode),
Expand Down
110 changes: 98 additions & 12 deletions src/reducer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,11 @@ use crate::event::*;
use libflate::gzip::{Decoder, Encoder};
use std::fs::File;
use std::io::Read;
use std::process::Command;
use std::sync::mpsc;
use std::thread;
use std::thread::JoinHandle;
use tui::widgets::ListState;

pub fn reduce(state: &mut App, event: Messages, tx: mpsc::Sender<Messages>) -> Option<Messages> {
// Route handler
Expand Down Expand Up @@ -123,7 +125,7 @@ pub fn reduce(state: &mut App, event: Messages, tx: mpsc::Sender<Messages>) -> O
};
let selected = state.home.list_state.selected();
let next_index = match &evt {
UpdateHomeSelectedEvent::Next => selected
UpdateListSelectedEvent::Next => selected
.map(|selected| {
if selected < max_index {
selected + 1
Expand All @@ -132,7 +134,7 @@ pub fn reduce(state: &mut App, event: Messages, tx: mpsc::Sender<Messages>) -> O
}
})
.unwrap_or(0),
UpdateHomeSelectedEvent::Prev => selected
UpdateListSelectedEvent::Prev => selected
.map(|selected| {
if selected > 0 {
selected - 1
Expand All @@ -141,8 +143,8 @@ pub fn reduce(state: &mut App, event: Messages, tx: mpsc::Sender<Messages>) -> O
}
})
.unwrap_or(0),
UpdateHomeSelectedEvent::Home => 0,
UpdateHomeSelectedEvent::End => max_index,
UpdateListSelectedEvent::Home => 0,
UpdateListSelectedEvent::End => max_index,
};
state.home.list_state.select(Some(next_index));
None
Expand Down Expand Up @@ -211,13 +213,13 @@ pub fn reduce(state: &mut App, event: Messages, tx: mpsc::Sender<Messages>) -> O
state.exam = Some(exam);
None
}
Messages::ModalAction(action) => match action {
ModalActions::Open(modal_state) => {
Messages::SaveModalAction(action) => match action {
SaveModalActions::Open(modal_state) => {
state.modal.save_modal_state = modal_state;
None
}
ModalActions::Quit(quit_action) => {
state.modal.save_modal_state = ModalState::Hidden;
SaveModalActions::Quit(quit_action) => {
state.modal.save_modal_state = SaveModalState::Hidden;

match quit_action {
QuitAction::BackHome => {
Expand All @@ -229,13 +231,97 @@ pub fn reduce(state: &mut App, event: Messages, tx: mpsc::Sender<Messages>) -> O
};
None
}
ModalActions::Okay => {
SaveModalActions::Okay => {
save_state(&state, tx.clone());
state.modal.save_modal_state = ModalState::Hidden;
state.modal.save_modal_state = SaveModalState::Hidden;
None
}
ModalActions::Cancel => {
state.modal.save_modal_state = ModalState::Hidden;
SaveModalActions::Cancel => {
state.modal.save_modal_state = SaveModalState::Hidden;
None
}
},
Messages::AssetsModalAction(action) => match action {
AssetsModalActions::Open => {
let exam = state.exam.as_ref().unwrap();
let current_item = exam.question_at(exam.display.question_index).unwrap();
let num_assets = current_item.get_assets().len();

if num_assets > 0 {
state.modal.assets_modal_state = AssetsModalState::Show(ListState::default());
}
None
}
AssetsModalActions::Close => {
state.modal.assets_modal_state = AssetsModalState::Hidden;
None
}
AssetsModalActions::Select(evt) => {
let exam = state.exam.as_ref().unwrap();
let current_item = exam.question_at(exam.display.question_index).unwrap();
let assets = current_item.get_assets();

let max_index = if assets.len() > 0 {
assets.len() - 1
} else {
return None;
};

let next_index = {
let selected = match &state.modal.assets_modal_state {
AssetsModalState::Show(list_state) => list_state.selected(),
AssetsModalState::Hidden => return None,
};

match &evt {
UpdateListSelectedEvent::Next => selected
.map(|selected| {
if selected < max_index {
selected + 1
} else {
0
}
})
.unwrap_or(0),
UpdateListSelectedEvent::Prev => selected
.map(|selected| {
if selected > 0 {
selected - 1
} else {
max_index
}
})
.unwrap_or(0),
UpdateListSelectedEvent::Home => 0,
UpdateListSelectedEvent::End => max_index,
}
};

if let AssetsModalState::Show(list_state) = &mut state.modal.assets_modal_state {
list_state.select(Some(next_index));
};
None
}
AssetsModalActions::OpenFile => {
let launcher = &state.config.launcher;
let current_path = &state.home.current_path;

let assets_list_state = match &state.modal.assets_modal_state {
AssetsModalState::Show(list_state) => list_state,
AssetsModalState::Hidden => unreachable!(),
};
let exam = state.exam.as_ref().unwrap();
exam.question_at(exam.display.question_index)
.map(|current_item| current_item.get_assets())
.and_then(|assets| {
let selected = assets_list_state.selected()?;
let current_file = assets.get(selected)?;
Command::new(launcher)
.arg(current_path.join(current_file))
.spawn()
.ok()
});

None
}
},
Expand Down
Loading

0 comments on commit 58e48e8

Please sign in to comment.