1
0
forked from GRIN/grim

goblin: appearance settings additions for Build 140

Three settings-surface additions:

- Hide amounts: a toggle (same switch widget as the incoming-requests
  toggle) under the amount-privacy rows, persisted in the app config
  (serde-default off so old configs load). When on, the received-payment
  notification masks the numeric grin with dots.

- Language: a picker under Appearance beside the theme row. Lists the six
  shipped locales in their own names; tapping one switches and persists the
  active locale.

- Update available: a badge pinned to the right of the settings profile
  panel, shown only when the release check has found a newer build (reuses
  the existing AppConfig::app_update state); tapping it opens the release
  download page.

New user-facing strings added to all six locales.
This commit is contained in:
2ro
2026-07-05 13:11:23 -04:00
parent 037e727756
commit bdedcba498
9 changed files with 145 additions and 1 deletions
+4
View File
@@ -487,6 +487,10 @@ goblin:
requests: "Anfragen"
incoming_requests: "Eingehende Anfragen"
incoming_requests_sub: "Erlaube anderen, Geld von dir anzufordern"
hide_amounts: "Beträge verbergen"
hide_amounts_sub: "Empfangene Beträge in Benachrichtigungen verbergen"
language: "Sprache"
update_available: "Update verfügbar"
appearance: "Erscheinungsbild"
theme: "Design"
theme_light: "Hell"
+4
View File
@@ -487,6 +487,10 @@ goblin:
requests: "Requests"
incoming_requests: "Incoming requests"
incoming_requests_sub: "Let others request money from you"
hide_amounts: "Hide amounts"
hide_amounts_sub: "Hide received amounts in notifications"
language: "Language"
update_available: "Update available"
appearance: "Appearance"
theme: "Theme"
theme_light: "Light"
+4
View File
@@ -487,6 +487,10 @@ goblin:
requests: "Demandes"
incoming_requests: "Demandes entrantes"
incoming_requests_sub: "Laisser les autres vous demander de l'argent"
hide_amounts: "Masquer les montants"
hide_amounts_sub: "Masquer les montants reçus dans les notifications"
language: "Langue"
update_available: "Mise à jour disponible"
appearance: "Apparence"
theme: "Thème"
theme_light: "Clair"
+4
View File
@@ -487,6 +487,10 @@ goblin:
requests: "Запросы"
incoming_requests: "Входящие запросы"
incoming_requests_sub: "Разрешить другим запрашивать у вас деньги"
hide_amounts: "Скрыть суммы"
hide_amounts_sub: "Скрывать полученные суммы в уведомлениях"
language: "Язык"
update_available: "Доступно обновление"
appearance: "Внешний вид"
theme: "Тема"
theme_light: "Светлая"
+4
View File
@@ -487,6 +487,10 @@ goblin:
requests: "İstekler"
incoming_requests: "Gelen istekler"
incoming_requests_sub: "Başkalarının senden para istemesine izin ver"
hide_amounts: "Tutarları gizle"
hide_amounts_sub: "Bildirimlerde alınan tutarları gizle"
language: "Dil"
update_available: "Güncelleme mevcut"
appearance: "Görünüm"
theme: "Tema"
theme_light: "Açık"
+4
View File
@@ -487,6 +487,10 @@ goblin:
requests: "请求"
incoming_requests: "收到的请求"
incoming_requests_sub: "允许他人向你请求付款"
hide_amounts: "隐藏金额"
hide_amounts_sub: "在通知中隐藏收到的金额"
language: "语言"
update_available: "有可用更新"
appearance: "外观"
theme: "主题"
theme_light: "浅色"
+96
View File
@@ -138,6 +138,7 @@ enum SettingsPage {
Relays,
Nips,
Pairing,
Language,
Slatepack,
Privacy,
Advanced,
@@ -2430,6 +2431,7 @@ impl GoblinWalletView {
SettingsPage::Relays => return self.relays_ui(ui, wallet, cb),
SettingsPage::Nips => return self.nips_ui(ui),
SettingsPage::Pairing => return self.pairing_settings_ui(ui),
SettingsPage::Language => return self.language_settings_ui(ui),
SettingsPage::Slatepack => return self.slatepack_ui(ui, wallet, cb),
SettingsPage::Privacy => return self.privacy_ui(ui),
SettingsPage::Advanced => return self.advanced_ui(ui, wallet, cb),
@@ -2535,6 +2537,31 @@ impl GoblinWalletView {
.request_repaint_after(std::time::Duration::from_millis(600));
}
});
// Update-available badge, pinned to the right of the profile
// panel. Shown only when the release check found a newer build
// (reuses the AppConfig::app_update state the wallet list uses);
// tapping it opens the release download page.
if let Some(update) = crate::AppConfig::app_update() {
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
let (rect, resp) =
ui.allocate_exact_size(Vec2::splat(36.0), Sense::click());
ui.painter().circle_filled(rect.center(), 18.0, t.accent);
ui.painter().text(
rect.center(),
egui::Align2::CENTER_CENTER,
crate::gui::icons::CLOUD_ARROW_DOWN,
FontId::new(18.0, fonts::regular()),
t.accent_ink,
);
if resp
.on_hover_cursor(egui::CursorIcon::PointingHand)
.on_hover_text(t!("goblin.settings.update_available").to_string())
.clicked()
{
open_url(ui, &update.url);
}
});
}
});
});
@@ -2759,6 +2786,16 @@ impl GoblinWalletView {
) {
open_pairing = true;
}
// Hide received amounts in payment notifications/alerts. Same
// switch widget as the incoming-requests toggle below.
if let Some(v) = settings_row_toggle(
ui,
&t!("goblin.settings.hide_amounts"),
&t!("goblin.settings.hide_amounts_sub"),
crate::AppConfig::hide_amounts(),
) {
crate::AppConfig::set_hide_amounts(v);
}
});
if open_pairing {
self.settings_page = SettingsPage::Pairing;
@@ -2790,6 +2827,7 @@ impl GoblinWalletView {
ui.add_space(16.0);
w::kicker(ui, &t!("goblin.settings.appearance"));
ui.add_space(8.0);
let mut open_language = false;
w::card(ui, |ui| {
let theme_label = match crate::AppConfig::theme() {
crate::gui::theme::ThemeKind::Light => t!("goblin.settings.theme_light"),
@@ -2799,7 +2837,21 @@ impl GoblinWalletView {
if settings_row_btn(ui, &t!("goblin.settings.theme"), &theme_label) {
cycle_theme(ui.ctx());
}
// Language sits beside theme under Appearance; the value is the
// active language in its own name (e.g. "Deutsch").
let current = crate::AppConfig::locale()
.unwrap_or_else(|| rust_i18n::locale().to_string());
if settings_row_nav(
ui,
&t!("goblin.settings.language"),
&t!("lang_name", locale = current.as_str()),
) {
open_language = true;
}
});
if open_language {
self.settings_page = SettingsPage::Language;
}
ui.add_space(16.0);
w::kicker(ui, &t!("goblin.settings.archive"));
@@ -2999,6 +3051,50 @@ impl GoblinWalletView {
});
}
/// Language picker: the six shipped locales, each in its own name. Tapping one
/// switches the active locale and persists it (mirrors the GRIM interface
/// settings, but in Goblin's row style like the pairing picker).
fn language_settings_ui(&mut self, ui: &mut egui::Ui) {
let t = theme::tokens();
if self.sub_header(ui, &t!("goblin.settings.language")) {
self.settings_page = SettingsPage::Main;
return;
}
let current = crate::AppConfig::locale().unwrap_or_else(|| rust_i18n::locale().to_string());
ScrollArea::vertical()
.auto_shrink([false; 2])
.scroll_bar_visibility(egui::scroll_area::ScrollBarVisibility::AlwaysHidden)
.show(ui, |ui| {
settings_group(ui, &t!("goblin.settings.language"), |ui| {
for locale in rust_i18n::available_locales!() {
let active = current == locale;
let row = ui.horizontal(|ui| {
ui.label(
RichText::new(t!("lang_name", locale = locale))
.font(FontId::new(15.0, fonts::medium()))
.color(t.surface_text),
);
ui.with_layout(Layout::right_to_left(Align::Center), |ui| {
if active {
ui.label(
RichText::new(crate::gui::icons::CHECK)
.font(FontId::new(16.0, fonts::regular()))
.color(t.pos),
);
}
});
});
ui.add_space(10.0);
if !active && row.response.interact(Sense::click()).clicked() {
rust_i18n::set_locale(locale);
crate::AppConfig::save_locale(locale);
}
}
});
ui.add_space(16.0);
});
}
/// Network-privacy breakdown: what rides the Nym mixnet versus what connects
/// directly. Honest by design — no claim that node traffic is mixed, and no
/// toggle to route it (chain sync is heavy and not tied to your identity).
+7 -1
View File
@@ -2144,7 +2144,13 @@ async fn handle_wrap(svc: &Arc<NostrService>, wallet: &Wallet, event: Event) {
{
let name =
crate::gui::views::goblin::data::contact_title(&svc.store, &sender_hex);
let amount = amount_to_hr_string(slate.amount, true);
// Honor the "hide amounts" setting: keep the numeric grin
// out of the received-payment alert when the user opted in.
let amount = if crate::AppConfig::hide_amounts() {
"•••".to_string()
} else {
amount_to_hr_string(slate.amount, true)
};
crate::notify_payment_received(&name, &amount);
}
match svc
+18
View File
@@ -94,6 +94,10 @@ pub struct AppConfig {
/// Application update information.
app_update: Option<AppUpdate>,
/// Hide received grin amounts in payment notifications/alerts. Default false
/// so existing configs (and new wallets) keep showing the amount.
hide_amounts: Option<bool>,
/// Last-known-good Nym ENTRY gateway (base58 identity). Only the gateway
/// CHOICE is remembered — the mixnet keys stay ephemeral — so a warm reconnect
/// can skip re-picking a (possibly dead) random first hop.
@@ -212,6 +216,7 @@ impl Default for AppConfig {
// update check — payments, relays and identity still stay mixnet-only.
check_updates: Some(true),
app_update: None,
hide_amounts: None,
nym_entry_gateway: None,
nym_last_ipr: None,
}
@@ -624,6 +629,19 @@ impl AppConfig {
}
w_config.save();
}
/// Whether received grin amounts are hidden in payment notifications/alerts.
pub fn hide_amounts() -> bool {
let r_config = Settings::app_config_to_read();
r_config.hide_amounts.unwrap_or(false)
}
/// Set whether received grin amounts are hidden in notifications/alerts.
pub fn set_hide_amounts(hide: bool) {
let mut w_config = Settings::app_config_to_update();
w_config.hide_amounts = Some(hide);
w_config.save();
}
}
#[cfg(test)]