Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,4 @@ serde_json = "1"
anyhow = "1"
tzf-rs = "0.4"
chrono-tz = "0.10"
toml = { version = "0.8", features = ["parse"] }
toml = { version = "0.8", features = ["parse", "display"] }
23 changes: 13 additions & 10 deletions config.example.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,19 @@
# Stellui configuration file
# Stellui configuration
# Copy to:
# Linux/macOS: ~/.config/stellui/config.toml
# Windows: %APPDATA%\stellui\config.toml

# Observer location
lat = 40.71 # latitude in degrees (-90 to 90, N positive)
lon = -74.01 # longitude in degrees (-180 to 180, E positive)
height = 0.0 # elevation in meters above sea level
# Faintest magnitude to display (0 = brightest, 8 = very faint)
max_mag = 5.5

# Timezone (IANA name, e.g. "America/New_York")
# If omitted, auto-detected from lat/lon.
# timezone = "America/New_York"
[[locations]]
name = "New York"
lat = 40.71
lon = -74.01
height = 0.0
# timezone = "America/New_York" # optional; auto-detected if omitted

# Faintest magnitude to display (0 = brightest, 8 = very faint)
# max_mag = 5.5
[[locations]]
name = "London"
lat = 51.51
lon = -0.13
38 changes: 35 additions & 3 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,18 @@ pub enum Tab {

pub enum InputMode {
Normal,
EditingLat,
EditingLon,
LocationPicker,
AddingLocation,
EditingDatetime,
EditingTimezone,
}

pub struct NewLocationDraft {
pub bufs: [String; 4], // [name, lat, lon, height]
pub field: usize,
pub error: Option<String>,
}

pub struct App {
pub tab: Tab,
pub input_mode: InputMode,
Expand All @@ -78,6 +84,11 @@ pub struct App {

pub test_mode: bool,

pub locations: Vec<crate::config::Location>,
pub location_index: usize,
pub picker_sel: usize,
pub new_loc_draft: Option<NewLocationDraft>,

pub stars: Vec<RenderedStar>,
pub sun_moon: SunMoonInfo,
pub planets: Vec<RenderedPlanet>,
Expand All @@ -91,7 +102,12 @@ pub struct App {
}

impl App {
pub fn new(lat: f64, lon: f64, height: f64, timezone_override: Option<chrono_tz::Tz>, max_mag_override: Option<f64>) -> Self {
pub fn new(locations: Vec<crate::config::Location>, initial_index: usize, max_mag_override: Option<f64>) -> Self {
let loc = &locations[initial_index];
let timezone_override = loc.timezone.as_deref().and_then(|s| s.parse().ok());
let lat = loc.lat;
let lon = loc.lon;
let height = loc.height;
let timezone = timezone_override.or_else(|| resolve_tz(lat, lon));
let mut app = Self {
tab: Tab::Sky,
Expand All @@ -109,6 +125,10 @@ impl App {
last_tick: Instant::now(),
max_mag: max_mag_override.unwrap_or(5.5),
test_mode: false,
locations,
location_index: initial_index,
picker_sel: initial_index,
new_loc_draft: None,
stars: Vec::new(),
planets: Vec::new(),
orrery: OrreryInfo { planets: Vec::new() },
Expand All @@ -127,6 +147,18 @@ impl App {
app
}

pub fn switch_location(&mut self, index: usize) {
if index >= self.locations.len() { return; }
let loc = &self.locations[index];
let timezone_override = loc.timezone.as_deref().and_then(|s| s.parse().ok());
self.lat = loc.lat;
self.lon = loc.lon;
self.height = loc.height;
self.timezone = timezone_override.or_else(|| resolve_tz(self.lat, self.lon));
self.location_index = index;
self.recompute();
}

pub fn recompute(&mut self) {
self.stars = sky::compute_stars(
self.lat,
Expand Down
47 changes: 41 additions & 6 deletions src/config.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
use serde::Deserialize;
use serde::{Deserialize, Serialize};

#[derive(Debug, Default, Deserialize)]
pub struct Config {
pub lat: Option<f64>,
pub lon: Option<f64>,
pub height: Option<f64>,
#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct Location {
pub name: String,
pub lat: f64,
pub lon: f64,
#[serde(default)]
pub height: f64,
pub timezone: Option<String>,
}

#[derive(Debug, Default, Deserialize, Serialize)]
pub struct Config {
#[serde(default)]
pub locations: Vec<Location>,
pub max_mag: Option<f64>,
}

Expand Down Expand Up @@ -36,4 +44,31 @@ impl Config {
toml::from_str(&text).unwrap_or_default()
}

pub fn effective_locations(&self) -> Vec<Location> {
if !self.locations.is_empty() {
self.locations.clone()
} else {
vec![Location {
name: "New York".to_string(),
lat: 40.71,
lon: -74.01,
height: 0.0,
timezone: None,
}]
}
}

pub fn save(locations: &[Location], max_mag: Option<f64>) {
let Some(path) = config_path() else { return };
if let Some(parent) = path.parent() {
let _ = std::fs::create_dir_all(parent);
}
let cfg = Config {
locations: locations.to_vec(),
max_mag,
};
if let Ok(text) = toml::to_string(&cfg) {
let _ = std::fs::write(&path, text);
}
}
}
Loading
Loading