Skip to content
Snippets Groups Projects
Commit 1561033f authored by thibault.capt's avatar thibault.capt
Browse files

create TUI app. Need the SQLite db

parent a5658be1
Branches
Tags
1 merge request!1Tui
......@@ -6,6 +6,4 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
termion = "2.0.1"
crossterm = "0.25.0"
cursive = "0.15.0"
\ No newline at end of file
cursive = "0.19.0"
\ No newline at end of file
/// Importer le module `Training` depuis le fichier externe
use crate::training::Training;
/// Importations des bibliothèques standard et de cursive
use std::rc::Rc;
use cursive::Cursive;
use cursive::{
views::{Button, Dialog, DummyView, EditView, LinearLayout, SelectView, TextView, NamedView, ResizedView},
traits::*,
};
/// Fonction publique pour générer le TUI
pub fn run() {
// Initialisation de Cursive
let mut siv = cursive::default();
// Vue des entraînements
let select = SelectView::<Training>::new()
.on_submit(on_submit) // Appelé lors de la soumission de la sélection
.with_name("select") // Nom de la vue
.fixed_size((10, 5)); // Taille fixe de la vue
// Buttons pour ajouter et supprimer un entraînement
let buttons = LinearLayout::vertical()
.child(Button::new("Add new", add_training)) // Bouton pour ajouter un nouvel entraînement
.child(Button::new("Delete", delete_training)) // Bouton pour supprimer un entraînement
.child(DummyView) // Vue fictive pour ajouter de l'espace
.child(Button::new("Quit", Cursive::quit)); // Bouton pour quitter l'application
// Ajout de la couche de dialogue principale à Cursive
siv.add_layer(Dialog::around(LinearLayout::horizontal()
.child(select) // Ajout de la vue de sélection
.child(DummyView) // Ajout d'espace vide
.child(buttons)) // Ajout des boutons
.title("Select a training")); // Titre de la couche de dialogue
// Exécution de la boucle principale de Cursive
siv.run();
}
/// Fonction interne pour gérer l'ajout d'un nouvel entraînement
///
/// # Arguments
///
/// * `s` - Une référence mutable à Cursive
fn add_training(s: &mut Cursive) {
fn ok(s: &mut Cursive, training: Training) {
// Ajout de l'entraînement à la vue de sélection
s.call_on_name("select", |view: &mut SelectView<Training>| {
view.add_item(training.name.clone(), training.clone()); // Using the cloned_training
});
s.pop_layer(); // Fermer la couche de dialogue
}
// Ajout d'une couche de dialogue pour l'ajout d'un nouvel entraînement
s.add_layer(Dialog::around(
LinearLayout::vertical()
.with(
|list| for item in Training::TRAINING_ITEMS.iter() {
list.add_child(create_label(item)); // Ajout d'un label pour chaque élément de l'entraînement
list.add_child(create_edit_view(item)); // Ajout d'un champ de saisie pour chaque élément
list.add_child(DummyView); // Ajout d'espace vide
})
.child(DummyView) // Ajout d'espace vide
.child(LinearLayout::horizontal()
.child(Button::new(
"Ok", |s| { // Bouton "Ok" pour valider l'ajout
// Récupération des données saisies par l'utilisateur
let name = get_view_content(s, "name");
let description = get_view_content(s, "description");
let date = get_view_content(s, "date");
let location = get_view_content(s, "location");
let duration = get_view_content(s, "duration").parse::<i32>().unwrap_or(0);
let participants_str = get_view_content(s, "participants").to_string();
let participants = participants_str.split(",").map(str::trim).collect();
// Vérification si le nom est vide
if name.is_empty() {
s.add_layer(Dialog::info("Name cannot be empty")); // Affichage d'un message d'erreur
} else {
ok(s, Training::new(&name, &description, &date, &location, duration, participants)); // Appel de la fonction `ok` pour gérer l'ajout
}
}))
.child(Button::new("Cancel", |s| {
s.pop_layer(); // Annuler l'ajout et fermer la couche de dialogue
}))))
.title("Enter a new training") // Titre de la couche de dialogue
.scrollable() // Permettre le défilement si le contenu dépasse
);
}
/// Récupérer le contenu de la vue
///
/// # Arguments
///
/// * `s` - Une référence mutable à Cursive
/// * `name` - Le nom du champ de saisie
fn get_view_content(s: &mut Cursive, name: &str) -> Rc<String> {
s.call_on_name(name, |view: &mut EditView| view.get_content()).unwrap()
}
/// Créer un label pour un champ de l'entraînement
///
/// # Arguments
///
/// * `name` - Le nom du champ
fn create_label(name: &str) -> NamedView<TextView> {
TextView::new(format!("{}:", name)).with_name(format!("{}_label", &name))
}
/// Créer un champ de saisie pour un champ de l'entraînement
///
/// # Arguments
///
/// * `name` - Le nom du champ
fn create_edit_view(name: &str) -> ResizedView<NamedView<EditView>> {
EditView::new()
.with_name(name)
.fixed_width(18)
}
/// Supprimer un entraînement
///
/// # Arguments
///
/// * `s` - Une référence mutable à Cursive
fn delete_training(s: &mut Cursive) {
let mut select = s.find_name::<SelectView<Training>>("select").unwrap(); // Trouver la vue de sélection
match select.selected_id() {
None => s.add_layer(Dialog::info("No train to remove")), // Afficher un message s'il n'y a pas de formation sélectionnée
Some(focus) => {
select.remove_item(focus); // Supprimer l'entraînement sélectionnée
}
}
}
/// Appelé lorsque l'utilisateur soumet un entraînement
///
/// # Arguments
///
/// * `s` - Une référence mutable à Cursive
/// * `training` - Une référence à la structure Training soumise
fn on_submit(s: &mut Cursive, training: &Training) {
// Afficher les informations de l'entraînement dans une couche de dialogue
s.add_layer(Dialog::text(training.to_string())
.title(format!("{}'s info", training.name)) // Titre de la couche de dialogue
.button("Quit", |s| {
s.pop_layer(); // Ajouter un bouton pour fermer la couche de dialogue
})
.scrollable() // Permettre le défilement si le contenu dépasse
);
}
\ No newline at end of file
use cursive::Cursive;
use cursive::CursiveExt;
use cursive::views::{TextView, Dialog, LinearLayout, Button};
use crate::training::Training;
pub struct App {
cursive: Cursive,
training_list: Vec<Training>,
}
impl App {
pub fn new() -> Self {
let mut cursive = Cursive::default();
let training_list = Vec::new();
// Créez une vue TextView pour afficher la liste des entraînements
let training_view = TextView::new("Liste des entraînements");
// Créez un bouton pour lire tous les entraînements
let btn_list = Button::new("Voir", |s| {
// Vous pouvez ajouter votre logique d'ajout ici
s.add_layer(Dialog::info("Fonctionnalité non implémentée"));
});
// Créez un bouton pour ajouter un nouveau entraînement
let btn_add = Button::new("Ajouter", |s| {
// Vous pouvez ajouter votre logique d'ajout ici
s.add_layer(Dialog::info("Fonctionnalité non implémentée"));
});
// Créez un bouton pour modifier un entraînement
let btn_update = Button::new("Modifier", |s| {
// Vous pouvez ajouter votre logique d'ajout ici
s.add_layer(Dialog::info("Fonctionnalité non implémentée"));
});
// Créez un bouton pour supprimer un entraînement
let btn_delete = Button::new("Supprimer", |s| {
// Vous pouvez ajouter votre logique d'ajout ici
s.add_layer(Dialog::info("Fonctionnalité non implémentée"));
});
// Créez un bouton pour supprimer un entraînement
let btn_exit = Button::new("Quitter", |s| {
// Vous pouvez ajouter votre logique d'ajout ici
s.quit();
});
// Créez un LinearLayout pour organiser la vue TextView et le bouton
let layout = LinearLayout::vertical()
.child(training_view)
.child(btn_list)
.child(btn_add)
.child(btn_update)
.child(btn_delete)
.child(btn_exit);
cursive.add_layer(layout);
cursive.add_global_callback('q', |s| s.quit());
App { cursive, training_list }
}
pub fn run(&mut self) {
self.cursive.run();
}
}
\ No newline at end of file
/// Module de l'application
mod app;
/// Module pour la gestion de l'entraînement
mod training;
mod participant;
//mod terminal;
mod gui;
use gui::App;
fn main() {
let mut app = App::new();
let _ = app.run();
app::run();
}
\ No newline at end of file
#[derive(Debug)]
pub struct Participant {
pub firstname: String,
pub lastname: String,
pub age: u8
}
impl Participant {
pub fn new(firstname: &str, lastname: &str, age: u8) -> Participant {
Participant {
firstname: String::from(firstname),
lastname: String::from(lastname),
age
}
}
}
\ No newline at end of file
use std::io;
use crate::training::Training;
use termion::event::Key;
use termion::input::TermRead;
use crate::participant::Participant;
pub struct App {
training_list: Vec<Training>
}
impl App {
pub fn new() -> Self {
App { training_list: Vec::new() }
}
fn insert_training(
&mut self,
name: String,
description: String,
date: String,
lieu: String,
duration: i32,
participants: Vec<Participant>) {
self.training_list.push(
Training::new(name, description, date, lieu, duration, participants)
);
}
pub fn run(&mut self) {
loop {
println!("Choisir: ");
println!("'i' -> Insérer");
println!("'a' -> Afficher");
println!("'q' -> Quitter");
println!();
if let Some(Ok(event)) = io::stdin().keys().next() {
match event {
Key::Char('i') => self.insert_training(
"Foot".to_string(),
"Entrainment".to_string(),
"22.09.2023".to_string(),
"Bernex".to_string(),
120,
vec![Participant::new("Thibault", "Capt", 20)]
),
Key::Char('a') => println!("{:?}", self.training_list),
Key::Esc | Key::Char('q') => break,
_ => println!("Choix incorrecte")
}
}
}
}
}
use crate::participant::Participant;
#[derive(Debug)]
/// Structure représentant un entraînement
#[derive(Clone)]
pub struct Training {
/// Nom de l'entraînement
pub name: String,
/// Description de l'entraînement
pub description: String,
/// Date de l'entraînement
pub date: String,
/// Lieu de l'entraînement
pub location: String,
/// Durée de l'entraînement en heures
pub duration: i32,
pub participants: Vec<Participant>
/// Liste des participants à l'entraînement
pub participants: Vec<String>,
}
impl Training {
/// Tableau des éléments de l'entraînement
pub const TRAINING_ITEMS: [&'static str; 6] = ["name", "description", "date", "location", "duration", "participants"];
/// Crée une nouvelle instance de la structure Training
///
/// # Arguments
///
/// * `name` - Le nom de l'entraînement
/// * `description` - La description de l'entraînement
/// * `date` - La date de l'entraînement
/// * `location` - Le lieu de l'entraînement
/// * `duration` - La durée de l'entraînement en heures
/// * `participants` - Les participants à l'entraînement sous forme de vecteur de chaînes de caractères
pub fn new(
name: String,
description: String,
date: String,
location: String,
name: &str,
description: &str,
date: &str,
location: &str,
duration: i32,
participants: Vec<Participant>
participants: Vec<&str>
) -> Training {
Training { name, description, date, location, duration, participants }
Training {
name: name.to_string(),
description: description.to_string(),
date: date.to_string(),
location: location.to_string(),
duration,
participants: participants.iter().map(ToString::to_string).collect(),
}
}
/// Convertit la structure Training en une chaîne de caractères formatée
pub fn to_string(&self) -> String {
format!("Name: {}\nDescription: {}\nDate: {}\nLocation: {}\nDuration: {}\nParticipants: {}",
self.name, self.description, self.date, self.location, self.duration.to_string(), self.participants.join(","))
}
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment