clean up + update dfile
All checks were successful
Create and publish a Docker image / build-and-push-image (push) Successful in 6m0s
All checks were successful
Create and publish a Docker image / build-and-push-image (push) Successful in 6m0s
This commit is contained in:
parent
7904c80642
commit
8fd41b1090
8 changed files with 314 additions and 335 deletions
152
api/src/templates.rs
Normal file
152
api/src/templates.rs
Normal file
|
|
@ -0,0 +1,152 @@
|
|||
use libseptastic::{direction::Direction, stop_schedule::{Trip, TripTracking}};
|
||||
use std::{cmp::Ordering, collections::BTreeMap};
|
||||
use serde::{Serialize};
|
||||
use libseptastic::stop_schedule::TripTracking::Tracked;
|
||||
|
||||
#[derive(askama::Template)]
|
||||
#[template(path = "layout.html")]
|
||||
pub struct ContentTemplate<T: askama::Template> {
|
||||
pub content: T,
|
||||
pub page_title: Option<String>,
|
||||
pub page_desc: Option<String>,
|
||||
}
|
||||
|
||||
#[derive(askama::Template)]
|
||||
#[template(path = "route.html")]
|
||||
pub struct RouteTemplate {
|
||||
pub route: libseptastic::route::Route,
|
||||
pub directions: Vec<libseptastic::direction::Direction>,
|
||||
pub timetables: Vec<TimetableDirection>,
|
||||
pub filter_stops: Option<Vec<i64>>
|
||||
}
|
||||
|
||||
#[derive(askama::Template)]
|
||||
#[template(path = "routes.html")]
|
||||
pub struct RoutesTemplate {
|
||||
pub rr_routes: Vec<libseptastic::route::Route>,
|
||||
pub subway_routes: Vec<libseptastic::route::Route>,
|
||||
pub trolley_routes: Vec<libseptastic::route::Route>,
|
||||
pub bus_routes: Vec<libseptastic::route::Route>
|
||||
}
|
||||
|
||||
#[derive(askama::Template)]
|
||||
#[template(path = "index.html")]
|
||||
pub struct IndexTemplate {
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct TimetableStopRow {
|
||||
pub stop_id: i64,
|
||||
pub stop_name: String,
|
||||
pub stop_sequence: i64,
|
||||
pub times: Vec<Option<i64>>
|
||||
}
|
||||
|
||||
|
||||
#[derive(Debug, Serialize)]
|
||||
pub struct TimetableDirection {
|
||||
pub direction: Direction,
|
||||
pub trip_ids: Vec<String>,
|
||||
pub tracking_data: Vec<TripTracking>,
|
||||
pub rows: Vec<TimetableStopRow>
|
||||
}
|
||||
|
||||
pub fn build_timetables(
|
||||
directions: &[Direction],
|
||||
trips: &[Trip],
|
||||
) -> Vec<TimetableDirection> {
|
||||
let mut results = Vec::new();
|
||||
|
||||
for direction in directions {
|
||||
let mut direction_trips: Vec<&Trip> = trips
|
||||
.iter()
|
||||
.filter(|trip| trip.direction_id == direction.direction_id)
|
||||
.collect();
|
||||
|
||||
direction_trips.sort_by_key(|trip| {
|
||||
trip.schedule
|
||||
.iter()
|
||||
.filter_map(|s| Some(s.arrival_time))
|
||||
.min()
|
||||
.unwrap_or(i64::MAX)
|
||||
});
|
||||
|
||||
let trip_ids: Vec<String> = direction_trips
|
||||
.iter()
|
||||
.map(|t| t.trip_id.clone())
|
||||
.collect();
|
||||
|
||||
let live_trips: Vec<TripTracking> = direction_trips
|
||||
.iter()
|
||||
.map(|t| t.tracking_data.clone())
|
||||
.collect();
|
||||
|
||||
|
||||
let mut stop_map: BTreeMap<i64, (i64, String, Vec<Option<i64>>)> = BTreeMap::new();
|
||||
|
||||
for (trip_index, trip) in direction_trips.iter().enumerate() {
|
||||
for stop in &trip.schedule {
|
||||
let entry = stop_map
|
||||
.entry(stop.stop_id)
|
||||
.or_insert((stop.stop_sequence, stop.stop_name.clone(), vec![None; direction_trips.len()]));
|
||||
|
||||
// If this stop_id appears in multiple trips with different sequences, keep the lowest
|
||||
entry.0 = entry.0.max(stop.stop_sequence);
|
||||
entry.1 = stop.stop_name.clone();
|
||||
entry.2[trip_index] = Some(stop.arrival_time);
|
||||
}
|
||||
}
|
||||
|
||||
let mut rows: Vec<TimetableStopRow> = stop_map
|
||||
.into_iter()
|
||||
.map(|(stop_id, (stop_sequence, stop_name, times))| TimetableStopRow {
|
||||
stop_id,
|
||||
stop_sequence,
|
||||
stop_name,
|
||||
times,
|
||||
})
|
||||
.collect();
|
||||
|
||||
rows.sort_by(| a, b| {
|
||||
if a.stop_sequence < b.stop_sequence {
|
||||
Ordering::Less
|
||||
} else {
|
||||
Ordering::Greater
|
||||
}
|
||||
});
|
||||
|
||||
assert!(trip_ids.len() == live_trips.len());
|
||||
for row in &rows {
|
||||
assert!(row.times.len() == live_trips.len());
|
||||
}
|
||||
|
||||
|
||||
results.push(TimetableDirection {
|
||||
direction: direction.clone(),
|
||||
trip_ids,
|
||||
rows,
|
||||
tracking_data: live_trips
|
||||
});
|
||||
}
|
||||
|
||||
results
|
||||
}
|
||||
|
||||
mod filters {
|
||||
pub fn format_time(
|
||||
seconds_since_midnight: &i64,
|
||||
_: &dyn askama::Values,
|
||||
) -> askama::Result<String> {
|
||||
let total_minutes = seconds_since_midnight / 60;
|
||||
let (hours, ampm) = {
|
||||
let hrs = total_minutes / 60;
|
||||
if hrs > 12 {
|
||||
(hrs - 12, "PM")
|
||||
} else {
|
||||
(hrs, "AM")
|
||||
}
|
||||
};
|
||||
let minutes = total_minutes % 60;
|
||||
Ok(format!("{}:{:02} {}", hours, minutes, ampm))
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue