Ao abrir, o app consulta o latest.json da release no GitHub; havendo versão nova, um cartão oferece Atualizar agora: baixa, confere a assinatura com a chave pública embutida, instala e reabre (AppImage substituído no lugar; Windows e macOS pelo instalador). Instalação por .deb ou .rpm só avisa. Configurações ganha a opção de desligar a consulta e o botão Verificar agora. A release assina os pacotes com a chave guardada no ambiente 'release' do GitHub (só tags v*) e o latest.json é montado de uma vez por scripts/make-latest-json.py, depois que todos os jobs de empacotamento terminam. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
142 lines
3.9 KiB
Rust
142 lines
3.9 KiB
Rust
//! Preferências do usuário (tema etc.), compartilhadas entre o app normal e o
|
|
//! reiniciado como administrador.
|
|
|
|
use crate::error::Result;
|
|
use serde::{Deserialize, Serialize};
|
|
use std::path::PathBuf;
|
|
|
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
|
pub struct Settings {
|
|
/// "auto", "light" ou "dark".
|
|
#[serde(default = "auto")]
|
|
pub theme: String,
|
|
/// Idioma da interface: "auto", "pt" ou "en".
|
|
#[serde(default = "auto")]
|
|
pub lang: String,
|
|
/// Idioma que a interface resolveu de fato ("pt" ou "en"), para as
|
|
/// notificações do sistema e a saída do terminal acompanharem a tela.
|
|
#[serde(default, skip_serializing_if = "Option::is_none")]
|
|
pub ui_lang: Option<String>,
|
|
/// Notificação do sistema quando uma tarefa longa termina.
|
|
#[serde(default = "yes")]
|
|
pub notify: bool,
|
|
/// Mostrar mapas das fotos com GPS (baixa blocos do OpenStreetMap pela internet).
|
|
#[serde(default)]
|
|
pub maps: bool,
|
|
/// Procurar versão nova no GitHub ao abrir o app (uma consulta ao `latest.json` da release,
|
|
/// sem enviar nada além do que qualquer navegador envia).
|
|
#[serde(default = "yes")]
|
|
pub updates: bool,
|
|
}
|
|
|
|
fn auto() -> String {
|
|
"auto".into()
|
|
}
|
|
|
|
fn yes() -> bool {
|
|
true
|
|
}
|
|
|
|
impl Default for Settings {
|
|
fn default() -> Self {
|
|
Self {
|
|
theme: auto(),
|
|
lang: auto(),
|
|
ui_lang: None,
|
|
notify: true,
|
|
maps: false,
|
|
updates: true,
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Pasta de configuração do usuário *real*, mesmo quando rodando como root
|
|
/// via sudo/pkexec (para o tema não "mudar" ao elevar privilégios).
|
|
pub fn config_dir() -> PathBuf {
|
|
if let Ok(d) = std::env::var("GUARA_CONFIG_DIR") {
|
|
if !d.is_empty() {
|
|
return PathBuf::from(d);
|
|
}
|
|
}
|
|
#[cfg(unix)]
|
|
{
|
|
if let Some(u) = crate::owner::invoking_user() {
|
|
return default_dir(u.home);
|
|
}
|
|
}
|
|
default_dir(PathBuf::from(
|
|
std::env::var("HOME")
|
|
.or_else(|_| std::env::var("USERPROFILE"))
|
|
.unwrap_or_default(),
|
|
))
|
|
}
|
|
|
|
fn default_dir(home: PathBuf) -> PathBuf {
|
|
#[cfg(windows)]
|
|
{
|
|
if let Ok(a) = std::env::var("APPDATA") {
|
|
return PathBuf::from(a).join("Guara");
|
|
}
|
|
home.join("AppData").join("Roaming").join("Guara")
|
|
}
|
|
#[cfg(target_os = "macos")]
|
|
{
|
|
home.join("Library")
|
|
.join("Application Support")
|
|
.join("Guara")
|
|
}
|
|
#[cfg(all(unix, not(target_os = "macos")))]
|
|
{
|
|
match std::env::var("XDG_CONFIG_HOME") {
|
|
Ok(x)
|
|
if !x.is_empty()
|
|
&& std::env::var("SUDO_USER").is_err()
|
|
&& std::env::var("PKEXEC_UID").is_err() =>
|
|
{
|
|
PathBuf::from(x).join("guara")
|
|
}
|
|
_ => home.join(".config").join("guara"),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn file() -> PathBuf {
|
|
config_dir().join("settings.json")
|
|
}
|
|
|
|
pub fn load() -> Settings {
|
|
std::fs::read(file())
|
|
.ok()
|
|
.and_then(|b| serde_json::from_slice(&b).ok())
|
|
.unwrap_or_default()
|
|
}
|
|
|
|
/// Idioma efetivo para textos gerados fora da interface (notificações e CLI).
|
|
/// Usa o que a interface informou; sem isso, a preferência e o ambiente.
|
|
pub fn ui_lang() -> String {
|
|
let s = load();
|
|
if let Some(l) = s.ui_lang.as_deref() {
|
|
if l == "pt" || l == "en" {
|
|
return l.to_string();
|
|
}
|
|
}
|
|
if s.lang == "pt" || s.lang == "en" {
|
|
return s.lang;
|
|
}
|
|
let env = std::env::var("LC_ALL")
|
|
.or_else(|_| std::env::var("LC_MESSAGES"))
|
|
.or_else(|_| std::env::var("LANG"))
|
|
.unwrap_or_default()
|
|
.to_ascii_lowercase();
|
|
if env.starts_with("pt") {
|
|
"pt".into()
|
|
} else {
|
|
"en".into()
|
|
}
|
|
}
|
|
|
|
pub fn save(s: &Settings) -> Result<()> {
|
|
crate::owner::write_owned(&file(), serde_json::to_vec_pretty(s)?)?;
|
|
Ok(())
|
|
}
|