use iced::{
Alignment, Element, Length, Size,
widget::{button, column, container, pick_list, scrollable, text, text_input},
window,
};
use jiff::civil::{Date, DateTime, Time};
pub fn main() -> iced::Result {
iced::application(
FlightBooker::default,
FlightBooker::update,
FlightBooker::view,
)
.title("Flight Booker")
.window(window::Settings {
size: Size {
width: 300.0,
height: 250.0,
},
..Default::default()
})
.run()
}
#[derive(Default)]
struct FlightBooker {
selected_flight: Flight,
one_way_flight: String,
one_way_flight_date: Option<DateTime>,
return_flight: String,
return_flight_date: Option<DateTime>,
book: bool,
show_dialogue: bool,
dialogue_string: String,
}
#[derive(Debug, Clone)]
enum Message {
Book,
FlightSelected(Flight),
OneWayFlightChanged(String),
ReturnFlightChanged(String),
}
impl FlightBooker {
fn _print_flights(&self) {
println!(
"flight: {}, return_flight: {}",
self.one_way_flight, self.return_flight
);
}
fn validate_flights(&mut self) -> anyhow::Result<()> {
match self.selected_flight {
Flight::OneWay => match validate_flight(&self.one_way_flight) {
Ok(flight) => {
self.one_way_flight_date = Some(flight);
Ok(())
}
Err(error) => {
self.one_way_flight_date = None;
Err(error)
}
},
Flight::Return => {
if let (Ok(flight), Ok(return_flight)) = (
validate_flight(&self.one_way_flight),
validate_flight(&self.return_flight),
) {
self.one_way_flight_date = Some(flight);
self.return_flight_date = Some(return_flight);
if self.one_way_flight_date <= self.return_flight_date {
Ok(())
} else {
Err(anyhow::Error::msg(
"the return flight date is before the flight date",
))
}
} else {
self.one_way_flight_date = None;
self.return_flight_date = None;
Err(anyhow::Error::msg("invalid date"))
}
}
}
}
fn update(&mut self, message: Message) {
match message {
Message::Book => {
if let Err(error) = self.validate_flights() {
self.show_dialogue = false;
eprintln!("error: {error}");
} else {
self.show_dialogue = true;
let one_way_string = format!(
"You have booked a one-way flight on {}",
self.one_way_flight
);
let return_string = format!(
"You have booked a flight leaving on {} and returning on {}",
self.one_way_flight, self.return_flight,
);
match self.selected_flight {
Flight::OneWay => self.dialogue_string = one_way_string,
Flight::Return => self.dialogue_string = return_string,
}
}
}
Message::FlightSelected(flight) => {
self.show_dialogue = false;
self.selected_flight = flight;
}
Message::OneWayFlightChanged(date) => {
self.show_dialogue = false;
self.one_way_flight = date;
match self.validate_flights() {
Ok(()) => self.book = true,
Err(error) => {
eprintln!("error: {error}");
self.book = false;
}
}
}
Message::ReturnFlightChanged(date) => {
self.show_dialogue = false;
self.return_flight = date;
match self.validate_flights() {
Ok(()) => self.book = true,
Err(error) => {
eprintln!("error: {error}");
self.book = false;
}
}
}
}
}
fn view(&self) -> Element<'_, Message> {
let pick_list = pick_list(
[Flight::OneWay, Flight::Return],
Some(self.selected_flight),
Message::FlightSelected,
)
.width(Length::Fill);
let one_way_flight = text_input("choose a flight date", &self.one_way_flight)
.on_input(Message::OneWayFlightChanged);
let return_flight = if self.selected_flight == Flight::Return {
text_input("choose a flight date", &self.return_flight)
.on_input(Message::ReturnFlightChanged)
} else {
text_input("", &self.one_way_flight)
};
let mut book = button(text("Book").center().width(Length::Fill)).width(Length::Fill);
if self.book {
book = book.on_press(Message::Book);
}
let mut column = column![pick_list, one_way_flight, return_flight, book]
.width(Length::Fill)
.align_x(Alignment::Center)
.padding(10)
.spacing(10);
if self.book && self.show_dialogue {
column = column.push(text(self.dialogue_string.clone()));
}
container(scrollable(column))
.width(Length::Fill)
.height(Length::Fill)
.into()
}
}
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
enum Flight {
#[default]
OneWay,
Return,
}
impl std::fmt::Display for Flight {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Flight::OneWay => "one-way flight",
Flight::Return => "return flight",
}
)
}
}
fn validate_flight(string: &str) -> anyhow::Result<DateTime> {
let mut day_month_year = string.split('.');
let Some(day) = day_month_year.next() else {
return Err(anyhow::Error::msg("invalid day string"));
};
let Some(month) = day_month_year.next() else {
return Err(anyhow::Error::msg("invalid month string"));
};
let Some(year) = day_month_year.next() else {
return Err(anyhow::Error::msg("invalid year string"));
};
Ok(DateTime::from_parts(
Date::new(year.parse()?, month.parse()?, day.parse()?)?,
Time::new(0, 0, 0, 0)?,
))
}