indicate best catch path
This commit is contained in:
parent
e04a98a7fd
commit
dc3f955b1b
3 changed files with 150 additions and 7 deletions
78
src/data.rs
78
src/data.rs
|
@ -1,9 +1,12 @@
|
||||||
use std::collections::HashMap;
|
use core::fmt;
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
fmt::{write, Display},
|
||||||
|
};
|
||||||
|
|
||||||
use chrono::{DateTime, Datelike, Duration, Timelike, Utc};
|
use chrono::{DateTime, Datelike, Duration, Timelike, Utc};
|
||||||
use chrono_humanize::HumanTime;
|
use chrono_humanize::HumanTime;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serde_json::map::Entry;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
clock,
|
clock,
|
||||||
|
@ -32,6 +35,8 @@ pub struct SubData {
|
||||||
pub fishing_spots: HashMap<u32, FishingSpot>,
|
pub fishing_spots: HashMap<u32, FishingSpot>,
|
||||||
#[serde(alias = "WEATHER_TYPES")]
|
#[serde(alias = "WEATHER_TYPES")]
|
||||||
pub weather_types: HashMap<u32, WeatherType>,
|
pub weather_types: HashMap<u32, WeatherType>,
|
||||||
|
#[serde(alias = "ITEMS")]
|
||||||
|
pub items: HashMap<u32, Item>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Default)]
|
#[derive(Serialize, Deserialize, Debug, Default)]
|
||||||
|
@ -51,6 +56,75 @@ pub struct FishEntry {
|
||||||
pub big_fish: bool,
|
pub big_fish: bool,
|
||||||
pub weather_set: Vec<u32>,
|
pub weather_set: Vec<u32>,
|
||||||
pub previous_weather_set: Vec<u32>,
|
pub previous_weather_set: Vec<u32>,
|
||||||
|
pub hookset: Option<Hookset>,
|
||||||
|
pub tug: Option<Tug>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy)]
|
||||||
|
pub enum Hookset {
|
||||||
|
#[default]
|
||||||
|
Precision,
|
||||||
|
Powerful,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Hookset {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let string = match self {
|
||||||
|
Self::Precision => {
|
||||||
|
"https://v2.xivapi.com/api/asset?path=ui/icon/001000/001116.tex&format=png"
|
||||||
|
}
|
||||||
|
Self::Powerful => {
|
||||||
|
"https://v2.xivapi.com/api/asset?path=ui/icon/001000/001115.tex&format=png"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
write!(f, "{}", string)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Tug {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::Light => write!(f, "!"),
|
||||||
|
Self::Medium => write!(f, "!!"),
|
||||||
|
Self::Heavy => write!(f, "!!!"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug, Default, Clone, Copy)]
|
||||||
|
#[serde(rename_all = "lowercase")]
|
||||||
|
pub enum Tug {
|
||||||
|
#[default]
|
||||||
|
Light,
|
||||||
|
Medium,
|
||||||
|
Heavy,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
pub struct Item {
|
||||||
|
#[serde(alias = "_id")]
|
||||||
|
pub id: u32,
|
||||||
|
pub name_en: String,
|
||||||
|
pub icon: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Item {
|
||||||
|
pub fn get_icon_url(&self) -> String {
|
||||||
|
let mut icon_cat = self.icon.clone();
|
||||||
|
icon_cat.replace_range(3..6, "000");
|
||||||
|
format!(
|
||||||
|
"https://v2.xivapi.com/api/asset?path=ui/icon/{}/{}.tex&format=png",
|
||||||
|
icon_cat, self.icon
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_hookset(&self, data: &Data) -> Option<Hookset> {
|
||||||
|
data.db_data.fish.get(&self.id).and_then(|f| f.hookset)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_tug(&self, data: &Data) -> Option<Tug> {
|
||||||
|
data.db_data.fish.get(&self.id).and_then(|f| f.tug)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug)]
|
#[derive(Serialize, Deserialize, Debug)]
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use std::{cmp::Ordering, sync::Arc};
|
use std::{cmp::Ordering, sync::Arc};
|
||||||
|
|
||||||
use axum::extract::State;
|
use axum::extract::State;
|
||||||
use chrono::Duration;
|
|
||||||
use maud::{html, Markup, DOCTYPE};
|
use maud::{html, Markup, DOCTYPE};
|
||||||
|
|
||||||
use crate::{clock, data::CombinedFish, AppState};
|
use crate::{clock, data::CombinedFish, AppState};
|
||||||
|
@ -33,10 +32,23 @@ pub fn main_page(state: State<Arc<AppState>>, with_layout: bool) -> Markup {
|
||||||
.then(bfish.rarity.total_cmp(&afish.rarity).reverse())
|
.then(bfish.rarity.total_cmp(&afish.rarity).reverse())
|
||||||
.then(bfish.meta.name_en.cmp(&afish.meta.name_en))
|
.then(bfish.meta.name_en.cmp(&afish.meta.name_en))
|
||||||
});
|
});
|
||||||
|
// values.sort_by(|afish, bfish| {
|
||||||
|
// if !afish.is_up && !bfish.is_up && !afish.windows.is_empty() && !bfish.windows.is_empty() {
|
||||||
|
// bfish
|
||||||
|
// .windows
|
||||||
|
// .first()
|
||||||
|
// .unwrap()
|
||||||
|
// .start_time
|
||||||
|
// .cmp(&afish.windows.first().unwrap().start_time)
|
||||||
|
// .reverse()
|
||||||
|
// } else {
|
||||||
|
// Ordering::Equal
|
||||||
|
// }
|
||||||
|
// });
|
||||||
let template = html! {
|
let template = html! {
|
||||||
h1 { "Hello! Current ET: " (clock::get_current_eorzea_date().format("%H:%M")) }
|
h1 { "Hello! Current ET: " (clock::get_current_eorzea_date().format("%H:%M")) }
|
||||||
@for fish in values {
|
@for fish in values {
|
||||||
section.up[fish.is_up || fish.is_always_up].alwaysup[fish.is_always_up] {
|
section.up[fish.is_up].alwaysup[fish.is_always_up] {
|
||||||
.title {
|
.title {
|
||||||
h3 { (fish.meta.name_en) }
|
h3 { (fish.meta.name_en) }
|
||||||
.subtitle {
|
.subtitle {
|
||||||
|
@ -52,6 +64,23 @@ pub fn main_page(state: State<Arc<AppState>>, with_layout: bool) -> Markup {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
.how {
|
||||||
|
@for item_id in &fish.entry.best_catch_path {
|
||||||
|
@if let Some(item) = state.data.db_data.items.get(item_id) {
|
||||||
|
span.catchpath title=(item.name_en) {
|
||||||
|
img src=(item.get_icon_url()) width="35";
|
||||||
|
|
||||||
|
@if let Some(hookset) = item.get_hookset(&state.data) {
|
||||||
|
img.hookset src=(hookset) width="20";
|
||||||
|
}
|
||||||
|
|
||||||
|
@if let Some(tug) = item.get_tug(&state.data) {
|
||||||
|
span.tug { (tug) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.meta {
|
.meta {
|
||||||
@if fish.entry.start_hour.is_some() && fish.entry.end_hour.is_some() {
|
@if fish.entry.start_hour.is_some() && fish.entry.end_hour.is_some() {
|
||||||
div {
|
div {
|
||||||
|
@ -72,7 +101,7 @@ pub fn main_page(state: State<Arc<AppState>>, with_layout: bool) -> Markup {
|
||||||
|
|
||||||
if with_layout {
|
if with_layout {
|
||||||
layout(html! {
|
layout(html! {
|
||||||
main hx-get="/" hx-trigger="every 3s" {
|
main hx-get="/" hx-trigger="every 10s" {
|
||||||
(template)
|
(template)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -6,7 +6,7 @@ body {
|
||||||
section {
|
section {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr 1fr;
|
grid-template-columns: 1fr 1fr 1fr 1fr;
|
||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,8 @@ section {
|
||||||
text-align: end;
|
text-align: end;
|
||||||
}
|
}
|
||||||
|
|
||||||
.when {
|
.when,
|
||||||
|
.how {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -52,3 +53,42 @@ section.alwaysup {
|
||||||
);
|
);
|
||||||
background-size: 50px 50px;
|
background-size: 50px 50px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* .catchpath:not(:first-of-type) {
|
||||||
|
margin-left: 5px;
|
||||||
|
} */
|
||||||
|
|
||||||
|
.catchpath {
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catchpath img {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hookset {
|
||||||
|
position: absolute;
|
||||||
|
top: -10px;
|
||||||
|
right: -10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tug {
|
||||||
|
position: absolute;
|
||||||
|
background-color: black;
|
||||||
|
color: white;
|
||||||
|
bottom: -10px;
|
||||||
|
right: -10px;
|
||||||
|
padding: 2px;
|
||||||
|
font-size: 10px;
|
||||||
|
font-weight: bolder;
|
||||||
|
font-family: monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.catchpath:not(:first-of-type)::before {
|
||||||
|
content: ">";
|
||||||
|
display: inline-block;
|
||||||
|
margin: 0 5px;
|
||||||
|
vertical-align: middle;
|
||||||
|
color: gray;
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue