Skip to content

Commit fb2bdc3

Browse files
feat: more validation and icons
1 parent a8dd5c1 commit fb2bdc3

File tree

5 files changed

+109
-48
lines changed

5 files changed

+109
-48
lines changed

fonts/icons.ttf

2.45 KB
Binary file not shown.

src/course_database.rs

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,15 +41,25 @@ impl FromStr for CourseId {
4141
.split_whitespace()
4242
.filter(|string| !string.trim_start().is_empty());
4343

44+
let subject_id = pieces
45+
.next()
46+
.ok_or(anyhow!("Could not find a subject id"))?
47+
.to_uppercase()
48+
.to_string();
49+
let class_id = pieces
50+
.next()
51+
.ok_or(anyhow!("Could not find the class id"))?
52+
.parse()?;
53+
54+
if class_id < 100 || 1000 <= class_id {
55+
return Err(anyhow!(
56+
"Class id must be a number, at least 100 and less than 1000"
57+
));
58+
}
59+
4460
Ok(CourseId {
45-
subject_id: pieces
46-
.next()
47-
.ok_or(anyhow!("Could not find a subject id"))?
48-
.to_string(),
49-
class_id: pieces
50-
.next()
51-
.ok_or(anyhow!("Could not find the class id"))?
52-
.parse()?,
61+
subject_id,
62+
class_id,
5363
})
5464
}
5565
}
@@ -60,7 +70,7 @@ impl std::fmt::Display for CourseId {
6070
}
6171
}
6272

63-
#[derive(Deserialize, Clone)]
73+
#[derive(Deserialize, Clone, Debug)]
6474
pub struct Course {
6575
pub id: CourseId,
6676
pub name: String,
@@ -83,6 +93,7 @@ impl Course {
8393
}
8494
}
8595

96+
#[derive(Debug)]
8697
pub enum DatabaseNode {
8798
Course(Course),
8899
Or,
@@ -115,6 +126,7 @@ impl fmt::Display for DatabaseNode {
115126

116127
/// Abstraction over some way to retrieve course info for simplicity.
117128
/// There must only be one entry for each course.
129+
#[derive(Debug)]
118130
pub struct CourseDatabase {
119131
pub courses: DiGraph<DatabaseNode, Relation>,
120132
}

src/icons.rs

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use iced::alignment;
2+
use iced::font::Font;
3+
use iced::widget::{text, Text};
4+
5+
/// See https://fonts.google.com/icons. Just find some online icon font editor
6+
/// to modify the ttf file.
7+
pub enum Icon {
8+
AccountTree,
9+
FullStackedBarChart,
10+
SideNavigation,
11+
DragIndicator,
12+
Settings,
13+
DeleteForever,
14+
}
15+
16+
impl Icon {
17+
pub fn bytes() -> &'static [u8] {
18+
include_bytes!("../fonts/icons.ttf").as_slice()
19+
}
20+
}
21+
22+
impl Into<Text<'static>> for Icon {
23+
fn into(self) -> Text<'static> {
24+
let ch = match self {
25+
Icon::AccountTree => "A",
26+
Icon::FullStackedBarChart => "B",
27+
Icon::SideNavigation => "C",
28+
Icon::DragIndicator => "D",
29+
Icon::Settings => "E",
30+
Icon::DeleteForever => "F",
31+
};
32+
text(ch)
33+
.font(Font::with_name("icons"))
34+
.width(20)
35+
.horizontal_alignment(alignment::Horizontal::Center)
36+
}
37+
}

src/lib.rs

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,22 @@
11
#![allow(dead_code, unused_variables)]
22

3+
use std::rc::Rc;
4+
use std::sync::Arc;
5+
6+
use iced::alignment::Horizontal;
37
use iced::theme::Palette;
4-
use iced::widget::{button, column, container, horizontal_rule, row, text, text_input};
5-
use iced::{executor, Application, Color, Command, Element, Length, Theme};
8+
use iced::widget::{button, column, container, horizontal_rule, row, text, text_input, Text};
9+
use iced::{executor, font, Application, Color, Command, Element, Length, Padding, Theme};
610

711
use iced_aw::native::Split;
8-
use iced_aw::{modal, split, Card};
12+
use iced_aw::{modal, split, Card, BOOTSTRAP_FONT_BYTES};
913

1014
mod course_database;
1115
use course_database::{CourseDatabase, CourseId};
16+
use icons::Icon;
1217

1318
mod graph_widget;
19+
mod icons;
1420

1521
#[derive(Default)]
1622
pub struct FinescaleApp {
@@ -26,22 +32,18 @@ struct UiStates {
2632
course_input_val: String,
2733
}
2834

29-
#[derive(Default, Debug, Clone)]
30-
pub struct CourseGraph;
31-
3235
#[derive(Debug, Clone)]
3336
pub enum Message {
34-
LoadedCourses(CourseGraph),
37+
LoadedCourses(Arc<anyhow::Result<CourseDatabase>>),
3538
MainDividerResize(u16),
3639
CourseInputEvent(String),
3740
CourseInputSubmit,
41+
IconsLoaded(Result<(), font::Error>),
3842
ClearError,
3943
}
4044

41-
async fn load_courses<P: AsRef<std::path::Path>>(path: P) -> CourseGraph {
42-
//let reader = std::fs::File::open(path).unwrap();
43-
//let _json: serde_json::Value = serde_json::from_reader(reader).unwrap();
44-
CourseGraph
45+
async fn load_courses<P: AsRef<std::path::Path>>(path: P) -> Arc<anyhow::Result<CourseDatabase>> {
46+
CourseDatabase::new("[]").into()
4547
}
4648

4749
impl Application for FinescaleApp {
@@ -53,7 +55,10 @@ impl Application for FinescaleApp {
5355
fn new(_: Self::Flags) -> (Self, Command<Self::Message>) {
5456
(
5557
FinescaleApp::default(),
56-
Command::perform(load_courses("data/courses.json"), Message::LoadedCourses),
58+
Command::batch([
59+
Command::perform(load_courses("data/courses.ron"), Message::LoadedCourses),
60+
iced::font::load(icons::Icon::bytes()).map(Message::IconsLoaded),
61+
]),
5762
)
5863
}
5964

@@ -63,7 +68,6 @@ impl Application for FinescaleApp {
6368

6469
fn update(&mut self, _message: Self::Message) -> Command<Self::Message> {
6570
match _message {
66-
Message::LoadedCourses(_) => {}
6771
Message::ClearError => self.ui_states.error_modal = None,
6872
// TODO: Limit the divider movement
6973
Message::MainDividerResize(amt) => self.ui_states.main_divider_pos = Some(amt),
@@ -79,23 +83,45 @@ impl Application for FinescaleApp {
7983
}
8084
}
8185
}
86+
_ => {}
8287
}
8388

8489
Command::none()
8590
}
8691

8792
fn view(&self) -> Element<Self::Message> {
8893
let mut left = column![
89-
text("Desired Classes"),
94+
text("Desired Classes")
95+
.width(Length::Fill)
96+
.size(40)
97+
.style(Color::from_rgb(0.5, 0.5, 0.5))
98+
.horizontal_alignment(Horizontal::Center),
9099
text_input("Start typing!", &self.ui_states.course_input_val)
100+
.padding(15)
91101
.on_input(Message::CourseInputEvent)
92102
.on_submit(Message::CourseInputSubmit),
103+
]
104+
.spacing(10);
105+
106+
let mut right = column![
107+
row![text("Required Classes")
108+
.width(Length::Fill)
109+
.size(40)
110+
.style(Color::from_rgb(0.5, 0.5, 0.5))
111+
.horizontal_alignment(iced::alignment::Horizontal::Left),],
112+
horizontal_rule(2)
93113
];
94-
let mut right = column![row![text("Required Classes"),], horizontal_rule(2)];
95114

96115
for course in self.desired_courses.iter() {
116+
left = left.push(
117+
row![
118+
text(course).width(Length::Fill),
119+
button(Into::<Text>::into(Icon::DeleteForever)).padding(10)
120+
]
121+
.spacing(20)
122+
.align_items(iced::Alignment::Center),
123+
);
97124
right = right.push(text(course));
98-
left = left.push(text(course));
99125
}
100126

101127
// Todo read and push courses.
@@ -108,26 +134,19 @@ impl Application for FinescaleApp {
108134
);
109135

110136
let overlay = self.ui_states.error_modal.as_ref().map(|err_msg| {
111-
Card::new(text("Error"), text(err_msg)).foot(
112-
container(button("Ok").on_press(Message::ClearError))
113-
.width(Length::Fill)
114-
.align_x(iced::alignment::Horizontal::Right),
115-
)
137+
Card::new(text("Error"), text(err_msg))
138+
.foot(
139+
container(button("Ok").on_press(Message::ClearError))
140+
.width(Length::Fill)
141+
.align_x(iced::alignment::Horizontal::Right),
142+
)
143+
.max_width(250.0)
116144
});
117145

118146
modal(main_content, overlay).into()
119147
}
120148

121149
fn theme(&self) -> Self::Theme {
122-
Theme::custom(
123-
"apptheme".to_string(),
124-
Palette {
125-
background: Color::from_rgba8(14, 14, 14, 0.1),
126-
text: Color::WHITE,
127-
primary: Color::WHITE,
128-
success: Color::WHITE,
129-
danger: Color::WHITE,
130-
},
131-
)
150+
iced::Theme::Light
132151
}
133152
}

src/main.rs

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,11 @@ fn main() -> iced::Result {
55
id: Some("finescale".into()),
66
window: window::Settings {
77
size: iced::Size::new(800.0, 400.0),
8-
position: window::Position::Centered,
98
visible: true,
10-
decorations: false,
11-
transparent: true,
9+
decorations: true,
1210
..Default::default()
1311
},
1412
antialiasing: true,
1513
..Default::default()
1614
})
17-
// let reader = std::fs::File::open("data/courses.json").unwrap();
18-
// let _json: serde_json::Value = serde_json::from_reader(reader).unwrap();
19-
// let mut graph = Graph::<&str, &str>::new();
20-
21-
// Ok(())
2215
}

0 commit comments

Comments
 (0)