mirror of
https://code.gri.mw/GUI/grim.git
synced 2026-07-15 03:08:56 +00:00
goblin: double-back at Home returns to the wallet switcher (Build 148)
At the wallet Home (the top level, where back was silently swallowed), the first Android back now shows a brief non-blocking pill — "Press back again to leave this wallet" — and a second back within two seconds DESELECTS the wallet to the switcher. The wallet stays UNLOCKED (select(None)-style deselection, no close, no logout), so returning is one tap and its nostr service keeps running untouched. Quitting the app lives only at the switcher, via GRIM's existing native exit-confirmation on back (unchanged). In-wallet sub-screens keep normal back navigation, no hint. The second back never quits directly. The hint is a bottom-anchored fading pill above the tab bar (goblin view), armed by the host (WalletsContent::back_exit_at) in the swallowed-no-op branch; nothing else about back handling changes. New goblin.home.back_again string in all six locales; drift green.
This commit is contained in:
@@ -376,6 +376,7 @@ goblin:
|
||||
nav_activity: "Aktivität"
|
||||
nav_receive: "Empfangen"
|
||||
nav_settings: "Einstellungen"
|
||||
back_again: "Erneut Zurück drücken, um diese Wallet zu verlassen"
|
||||
activity: "Aktivität"
|
||||
news: "Neuigkeiten"
|
||||
empty_title: "Noch keine Aktivität"
|
||||
|
||||
@@ -376,6 +376,7 @@ goblin:
|
||||
nav_activity: "Activity"
|
||||
nav_receive: "Receive"
|
||||
nav_settings: "Settings"
|
||||
back_again: "Press back again to leave this wallet"
|
||||
activity: "Activity"
|
||||
news: "News"
|
||||
empty_title: "No activity yet"
|
||||
|
||||
@@ -376,6 +376,7 @@ goblin:
|
||||
nav_activity: "Activité"
|
||||
nav_receive: "Recevoir"
|
||||
nav_settings: "Réglages"
|
||||
back_again: "Appuyez à nouveau sur retour pour quitter ce portefeuille"
|
||||
activity: "Activité"
|
||||
news: "Actualités"
|
||||
empty_title: "Aucune activité"
|
||||
|
||||
@@ -376,6 +376,7 @@ goblin:
|
||||
nav_activity: "Действия"
|
||||
nav_receive: "Получить"
|
||||
nav_settings: "Настройки"
|
||||
back_again: "Нажмите «назад» ещё раз, чтобы выйти из этого кошелька"
|
||||
activity: "Действия"
|
||||
news: "Новости"
|
||||
empty_title: "Пока нет действий"
|
||||
|
||||
@@ -376,6 +376,7 @@ goblin:
|
||||
nav_activity: "Etkinlik"
|
||||
nav_receive: "Al"
|
||||
nav_settings: "Ayarlar"
|
||||
back_again: "Bu cüzdandan ayrılmak için tekrar geri bas"
|
||||
activity: "Etkinlik"
|
||||
news: "Haberler"
|
||||
empty_title: "Henüz etkinlik yok"
|
||||
|
||||
@@ -376,6 +376,7 @@ goblin:
|
||||
nav_activity: "动态"
|
||||
nav_receive: "收款"
|
||||
nav_settings: "设置"
|
||||
back_again: "再按一次返回即可离开此钱包"
|
||||
activity: "动态"
|
||||
news: "新闻"
|
||||
empty_title: "暂无动态"
|
||||
|
||||
@@ -132,6 +132,9 @@ pub struct GoblinWalletView {
|
||||
wipe_confirm: bool,
|
||||
/// Minimum-confirmations value being edited in its modal (GRIM parity).
|
||||
min_conf_edit: String,
|
||||
/// When the first back of the double-back was pressed at Home, for the
|
||||
/// brief "press back again for the wallet switcher" hint. Display only.
|
||||
back_hint: Option<std::time::Instant>,
|
||||
}
|
||||
|
||||
/// Whether the per-identity cue is drawn on activity rows (owner-approved). The
|
||||
@@ -262,6 +265,7 @@ impl Default for GoblinWalletView {
|
||||
copy_flash: None,
|
||||
wipe_confirm: false,
|
||||
min_conf_edit: String::new(),
|
||||
back_hint: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -471,6 +475,57 @@ impl GoblinWalletView {
|
||||
std::mem::take(&mut self.switch_requested)
|
||||
}
|
||||
|
||||
/// Show the brief "press back again for the wallet switcher" hint. Called
|
||||
/// by the host when the first back of the double-back lands at the wallet
|
||||
/// Home (the second deselects to the switcher, wallet left unlocked).
|
||||
pub fn show_back_hint(&mut self) {
|
||||
self.back_hint = Some(std::time::Instant::now());
|
||||
}
|
||||
|
||||
/// Draw the transient back hint as a small bottom-anchored pill above the
|
||||
/// tab bar, non-blocking, fading out with the double-back window.
|
||||
fn back_hint_ui(&mut self, ctx: &egui::Context) {
|
||||
const SHOW_SECS: f32 = 2.0;
|
||||
let Some(at) = self.back_hint else {
|
||||
return;
|
||||
};
|
||||
let elapsed = at.elapsed().as_secs_f32();
|
||||
if elapsed >= SHOW_SECS {
|
||||
self.back_hint = None;
|
||||
return;
|
||||
}
|
||||
let t = theme::tokens();
|
||||
// Fade over the final 0.5s.
|
||||
let alpha = ((SHOW_SECS - elapsed) / 0.5).clamp(0.0, 1.0);
|
||||
let text = t!("goblin.home.back_again");
|
||||
let font = FontId::new(14.0, fonts::medium());
|
||||
egui::Area::new(egui::Id::new("goblin_back_hint"))
|
||||
.order(egui::Order::Foreground)
|
||||
.anchor(
|
||||
egui::Align2::CENTER_BOTTOM,
|
||||
Vec2::new(0.0, -(View::get_bottom_inset() + 92.0)),
|
||||
)
|
||||
.interactable(false)
|
||||
.show(ctx, |ui| {
|
||||
let galley =
|
||||
ui.painter()
|
||||
.layout_no_wrap(text.to_string(), font.clone(), t.surface_text);
|
||||
let pad = Vec2::new(16.0, 10.0);
|
||||
let size = galley.size() + pad * 2.0;
|
||||
let (rect, _) = ui.allocate_exact_size(size, Sense::hover());
|
||||
ui.painter().rect(
|
||||
rect,
|
||||
CornerRadius::same((size.y / 2.0) as u8),
|
||||
t.surface2.gamma_multiply(alpha),
|
||||
Stroke::new(1.0, t.line.gamma_multiply(alpha)),
|
||||
egui::StrokeKind::Inside,
|
||||
);
|
||||
ui.painter()
|
||||
.galley(rect.min + pad, galley, t.surface_text.gamma_multiply(alpha));
|
||||
});
|
||||
ctx.request_repaint_after(std::time::Duration::from_millis(50));
|
||||
}
|
||||
|
||||
/// Whether back navigation has anything left to consume: an overlay, a
|
||||
/// settings sub-page, or a non-Home tab (back routes to Home). Mirrors
|
||||
/// [`Self::on_back`], so the host never falls back to the wallet chooser.
|
||||
@@ -667,6 +722,9 @@ impl GoblinWalletView {
|
||||
Tab::Me => self.me_ui(ui, wallet, cb),
|
||||
});
|
||||
});
|
||||
// Transient "press back again" hint (first back at Home; the second
|
||||
// goes to the wallet switcher, wallet left unlocked).
|
||||
self.back_hint_ui(ui.ctx());
|
||||
}
|
||||
|
||||
/// 3-item bar: Wallet · Pay (center ツ) · Activity. A floating pill on most
|
||||
|
||||
@@ -43,6 +43,7 @@ use crate::gui::views::wallets::wallet::RecoverySettings;
|
||||
use crate::gui::views::wallets::wallet::types::{WalletContentContainer, wallet_status_text};
|
||||
use crate::gui::views::{Content, Modal, TitlePanel, View};
|
||||
use crate::http::{ReleaseInfo, retrieve_release};
|
||||
use crate::node::Node;
|
||||
use crate::settings::AppUpdate;
|
||||
use crate::wallet::types::{ConnectionMethod, WalletTask};
|
||||
use crate::wallet::{Wallet, WalletList};
|
||||
@@ -52,6 +53,10 @@ pub struct WalletsContent {
|
||||
/// List of wallets.
|
||||
wallets: WalletList,
|
||||
|
||||
/// When Android back was last swallowed at the wallet Home, arming the
|
||||
/// standard double-back-to-exit window (the first press shows a hint).
|
||||
back_exit_at: Option<std::time::Instant>,
|
||||
|
||||
/// Initial wallet creation [`Modal`] content.
|
||||
add_wallet_modal_content: AddWalletModal,
|
||||
/// Wallet opening [`Modal`] content.
|
||||
@@ -92,6 +97,7 @@ impl Default for WalletsContent {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
wallets: WalletList::default(),
|
||||
back_exit_at: None,
|
||||
wallet_selection_content: WalletListModal::new(None, None, true),
|
||||
open_wallet_content: OpenWalletModal::new(),
|
||||
add_wallet_modal_content: AddWalletModal::default(),
|
||||
@@ -411,7 +417,26 @@ impl WalletsContent {
|
||||
// never a back fallback to the chooser.
|
||||
if self.wallet_content.can_back() {
|
||||
self.wallet_content.back(cb);
|
||||
return false;
|
||||
}
|
||||
// Wallet Home with nothing to pop: double-back to the WALLET
|
||||
// SWITCHER. The first press arms a short window and shows a "press
|
||||
// back again" hint; a second press inside it DESELECTS the wallet —
|
||||
// it stays UNLOCKED (no close, no logout; its nostr listener keeps
|
||||
// running) and the chooser shows. Quitting the app lives only at
|
||||
// the switcher, via GRIM's native exit-confirmation on back.
|
||||
// Sub-screens above kept normal back navigation, no hint.
|
||||
if self
|
||||
.back_exit_at
|
||||
.map(|at| at.elapsed() <= Duration::from_secs(2))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
self.back_exit_at = None;
|
||||
self.wallets.select(None);
|
||||
return false;
|
||||
}
|
||||
self.back_exit_at = Some(std::time::Instant::now());
|
||||
self.wallet_content.show_back_hint();
|
||||
return false;
|
||||
}
|
||||
true
|
||||
|
||||
@@ -325,6 +325,12 @@ impl WalletContent {
|
||||
self.goblin.take_switch_request()
|
||||
}
|
||||
|
||||
/// Show the goblin surface's brief "press back again" hint (first back of
|
||||
/// the double-back-to-switcher at the wallet Home).
|
||||
pub fn show_back_hint(&mut self) {
|
||||
self.goblin.show_back_hint();
|
||||
}
|
||||
|
||||
/// Navigate back on navigation stack. Returns true if not consumed.
|
||||
pub fn back(&mut self, cb: &dyn PlatformCallbacks) -> bool {
|
||||
if self.goblin.overlay_active() {
|
||||
|
||||
Reference in New Issue
Block a user