1use crate::i18n::Language;
2use bevy::prelude::*;
3use bevy_inspector_egui::DefaultInspectorConfigPlugin;
4use egui_i18n::{set_language, tr};
5use strum::IntoEnumIterator;
6use strum_macros::EnumIter;
7
8pub struct SettingsPlugin;
9impl Plugin for SettingsPlugin {
10 fn build(&self, app: &mut App) {
11 app.insert_resource(ApplicationSettings::default())
12 .add_systems(
13 Update,
14 update_language_setting.run_if(resource_changed_or_removed::<ApplicationSettings>),
15 )
16 .add_plugins(DefaultInspectorConfigPlugin);
17 }
18}
19
20fn update_language_setting(settings: Res<ApplicationSettings>) {
24 set_language(settings.language.identifier());
25}
26
27#[derive(Reflect, Clone, Copy, Debug, EnumIter, PartialEq, Eq)]
29pub enum TerminologyScheme {
30 Paiagram,
31 ChineseRailway,
32 JapaneseRailway,
33}
34
35impl TerminologyScheme {
36 pub fn name(self) -> &'static str {
37 match self {
38 Self::Paiagram => "Paiagram",
39 Self::ChineseRailway => "Chinese Railway",
40 Self::JapaneseRailway => "Japanese Railway",
41 }
42 }
43}
44
45#[derive(Reflect, Clone, Copy, Debug, EnumIter, PartialEq, Eq)]
46pub enum PinyinScheme {
47 Sogou,
48 Microsoft,
49}
50
51#[derive(Reflect, Clone, Debug)]
52pub enum Author {
53 Unknown,
54 OpenStreetMapContributors,
55 Lead(String),
56 Contributor(String),
57}
58
59#[derive(Reflect, Clone, Debug)]
60pub struct AuthorList(pub Vec<Author>);
61
62#[derive(Reflect, Resource)]
64#[reflect(Resource)]
65pub struct ApplicationSettings {
66 pub enable_romaji_search: bool,
67 pub show_performance_stats: bool,
68 pub pinyin_scheme: Vec<String>,
69 pub terminology_scheme: TerminologyScheme,
70 pub language: Language,
71 pub authors: AuthorList,
72 pub remarks: String,
73 pub autosave_enabled: bool,
74 pub autosave_interval_minutes: u32,
75 pub is_developer_mode: bool,
76}
77
78impl Default for ApplicationSettings {
79 fn default() -> Self {
80 Self {
81 enable_romaji_search: false,
82 show_performance_stats: cfg!(debug_assertions),
83 pinyin_scheme: vec!["quanpin".into(), "diletter_microsoft".into()],
84 terminology_scheme: TerminologyScheme::Paiagram,
85 language: Language::EnCA,
86 authors: AuthorList(if cfg!(target_arch = "wasm32") {
87 vec![Author::Unknown]
88 } else {
89 vec![
90 std::env::var("USER")
91 .or_else(|_| std::env::var("USERNAME"))
92 .map(Author::Lead)
93 .unwrap_or(Author::Unknown),
94 ]
95 }),
96 remarks: String::new(),
97 autosave_enabled: true,
98 autosave_interval_minutes: 5,
99 is_developer_mode: cfg!(debug_assertions),
100 }
101 }
102}
103
104impl egui::Widget for &mut ApplicationSettings {
105 fn ui(self, ui: &mut egui::Ui) -> egui::Response {
106 ui.checkbox(
107 &mut self.enable_romaji_search,
108 tr!("settings-enable-romaji-search"),
109 );
110 ui.checkbox(
111 &mut self.show_performance_stats,
112 tr!("settings-show-performance-stats"),
113 );
114 egui::ComboBox::from_id_salt("Language")
115 .selected_text(self.language.name())
116 .show_ui(ui, |ui| {
117 for lang in Language::iter() {
118 ui.selectable_value(&mut self.language, lang, lang.name());
119 }
120 });
121 egui::ComboBox::from_id_salt("Terminology scheme")
122 .selected_text(self.terminology_scheme.name())
123 .show_ui(ui, |ui| {
124 for scheme in TerminologyScheme::iter() {
125 ui.selectable_value(&mut self.terminology_scheme, scheme, scheme.name());
126 }
127 });
128 ui.text_edit_multiline(&mut self.remarks);
129 ui.checkbox(&mut self.autosave_enabled, tr!("settings-enable-autosave"));
130 ui.add(
131 egui::Slider::new(&mut self.autosave_interval_minutes, 1..=10)
132 .text(tr!("settings-autosave-interval")),
133 );
134 ui.checkbox(
135 &mut self.is_developer_mode,
136 tr!("settings-enable-developer-mode"),
137 )
138 }
139}