indicate best catch path

This commit is contained in:
insects 2025-02-05 22:32:23 +01:00
parent e04a98a7fd
commit dc3f955b1b
3 changed files with 150 additions and 7 deletions

View file

@ -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_humanize::HumanTime;
use serde::{Deserialize, Serialize};
use serde_json::map::Entry;
use crate::{
clock,
@ -32,6 +35,8 @@ pub struct SubData {
pub fishing_spots: HashMap<u32, FishingSpot>,
#[serde(alias = "WEATHER_TYPES")]
pub weather_types: HashMap<u32, WeatherType>,
#[serde(alias = "ITEMS")]
pub items: HashMap<u32, Item>,
}
#[derive(Serialize, Deserialize, Debug, Default)]
@ -51,6 +56,75 @@ pub struct FishEntry {
pub big_fish: bool,
pub 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)]

View file

@ -1,7 +1,6 @@
use std::{cmp::Ordering, sync::Arc};
use axum::extract::State;
use chrono::Duration;
use maud::{html, Markup, DOCTYPE};
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.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! {
h1 { "Hello! Current ET: " (clock::get_current_eorzea_date().format("%H:%M")) }
@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 {
h3 { (fish.meta.name_en) }
.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 {
@if fish.entry.start_hour.is_some() && fish.entry.end_hour.is_some() {
div {
@ -72,7 +101,7 @@ pub fn main_page(state: State<Arc<AppState>>, with_layout: bool) -> Markup {
if with_layout {
layout(html! {
main hx-get="/" hx-trigger="every 3s" {
main hx-get="/" hx-trigger="every 10s" {
(template)
}
})

View file

@ -6,7 +6,7 @@ body {
section {
margin-bottom: 5px;
display: grid;
grid-template-columns: 1fr 1fr 1fr;
grid-template-columns: 1fr 1fr 1fr 1fr;
padding: 0 10px;
align-items: center;
}
@ -30,7 +30,8 @@ section {
text-align: end;
}
.when {
.when,
.how {
text-align: center;
}
@ -52,3 +53,42 @@ section.alwaysup {
);
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;
}