game/layer/
favorites.rs

1use std::collections::BTreeSet;
2
3use serde::{Deserialize, Serialize};
4
5use abstutil::Timer;
6use map_model::osm::OsmID;
7use map_model::BuildingID;
8use widgetry::{Color, Drawable, EventCtx, GeomBatch, GfxCtx, Panel, RewriteColor};
9
10use crate::app::App;
11use crate::layer::{header, Layer, LayerOutcome, PANEL_PLACEMENT};
12
13/// A set of buildings that the player has starred, persisted as player data.
14#[derive(Serialize, Deserialize)]
15pub struct Favorites {
16    pub buildings: BTreeSet<OsmID>,
17}
18
19impl Favorites {
20    fn load(app: &App) -> Favorites {
21        abstio::maybe_read_json::<Favorites>(Favorites::path(app), &mut Timer::throwaway())
22            .unwrap_or_else(|_| Favorites {
23                buildings: BTreeSet::new(),
24            })
25    }
26
27    fn path(app: &App) -> String {
28        let name = app.primary.map.get_name();
29        abstio::path_player(format!(
30            "favorites/{}/{}/{}.json",
31            name.city.country, name.city.city, name.map
32        ))
33    }
34
35    pub fn contains(app: &App, b: BuildingID) -> bool {
36        Favorites::load(app)
37            .buildings
38            .contains(&app.primary.map.get_b(b).orig_id)
39    }
40
41    pub fn add(app: &App, b: BuildingID) {
42        let mut faves = Favorites::load(app);
43        faves.buildings.insert(app.primary.map.get_b(b).orig_id);
44        abstio::write_json(Favorites::path(app), &faves);
45    }
46
47    pub fn remove(app: &App, b: BuildingID) {
48        let mut faves = Favorites::load(app);
49        faves.buildings.remove(&app.primary.map.get_b(b).orig_id);
50        abstio::write_json(Favorites::path(app), &faves);
51    }
52}
53
54pub struct ShowFavorites {
55    panel: Panel,
56    draw: Drawable,
57}
58
59impl Layer for ShowFavorites {
60    fn name(&self) -> Option<&'static str> {
61        Some("favorites")
62    }
63    fn event(&mut self, ctx: &mut EventCtx, _: &mut App) -> Option<LayerOutcome> {
64        <dyn Layer>::simple_event(ctx, &mut self.panel)
65    }
66    fn draw(&self, g: &mut GfxCtx, _: &App) {
67        self.panel.draw(g);
68        g.redraw(&self.draw);
69    }
70    fn draw_minimap(&self, g: &mut GfxCtx) {
71        g.redraw(&self.draw);
72    }
73}
74
75impl ShowFavorites {
76    pub fn new(ctx: &mut EventCtx, app: &App) -> ShowFavorites {
77        let mut batch = GeomBatch::new();
78        for orig_id in Favorites::load(app).buildings.into_iter() {
79            if let Some(b) = app.primary.map.find_b_by_osm_id(orig_id) {
80                batch.append(
81                    GeomBatch::load_svg(ctx, "system/assets/tools/star.svg")
82                        .centered_on(app.primary.map.get_b(b).polygon.center())
83                        .color(RewriteColor::ChangeAll(Color::RED)),
84                );
85            }
86        }
87
88        let panel = Panel::new_builder(header(ctx, "Your favorite buildings"))
89            .aligned_pair(PANEL_PLACEMENT)
90            .build(ctx);
91
92        ShowFavorites {
93            panel,
94            draw: ctx.upload(batch),
95        }
96    }
97}