mirror of
https://code.gri.mw/GUI/grim.git
synced 2026-07-19 13:19:39 +00:00
Build 9: QR scan, camera fixes, first-run onboarding, sweep fixes
Camera/QR (validated live with a v4l2loopback virtual camera): - decode non-MJPEG frames on Linux (raw YUYV was undecodable: eternal spinner), enumerate devices off the UI thread without unwrap, open cameras by their real device index (list position broke whenever /dev/video0 was absent), show "No camera found" after 5s - scan-to-pay: QR button in the send recipient search row and the mobile home header; in-surface camera panel feeding recipient resolution; only text payloads accepted (seeds/slatepacks refused) - receive QR was unscannable: full cells (0.5px gaps fragmented finder patterns at 4.5px cells), always ink-on-white plate (inverted codes fail many scanners), center mark 26% -> 19% (zbar chokes above); rqrr+zbar both decode the live card now; unit tests cover the exact widget geometry First-run onboarding (replaces the stock empty state only; the wallet list, add-wallet modal and GRIM creation flow stay for later wallets): - intro -> node choice (Private integrated / Instant external with URL) -> create or restore (wraps MnemonicSetup; word grid, paste, SeedQR scan) -> optional @username claim with prominent skip - fonts bind at creation context so frame one can use Geist families Sweep fixes (22 confirmed findings, the simple ones): - yellow theme: active sidebar nav was dark-on-dark (P1) - window frame ring painted with theme bg: transparent clear color rendered as a black band without a compositor (P2) - import/rotate identity inputs get visible field wells (P2) - receive buttons: verb labels + transient "Copied" feedback - review hero card fills the column; fee row copy; pay-tab stale and duplicated hints; unlock modal copy; node card subtitle truncation - build number stays current (.git/logs/HEAD rerun trigger) Backup restore: import accepts the export-time password and re-encrypts under the current wallet password; cross-device restores work. 31 lib tests green. Mainnet-validated: both flows restored real wallets; 0.1 grin sent B->A through NIP-17 over Tor with async open/close ping-pong; tx 71fbfce4f591 posted on-chain. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -16,8 +16,8 @@ use eframe::epaint::RectShape;
|
||||
use egui::os::OperatingSystem;
|
||||
use egui::scroll_area::ScrollBarVisibility;
|
||||
use egui::{
|
||||
Align, CornerRadius, CursorIcon, Id, Layout, Margin, OpenUrl, RichText, ScrollArea, Sense,
|
||||
StrokeKind, UiBuilder,
|
||||
Align, CornerRadius, CursorIcon, Id, Layout, Margin, OpenUrl, ScrollArea, Sense, StrokeKind,
|
||||
UiBuilder,
|
||||
};
|
||||
use egui_async::Bind;
|
||||
use std::time::Duration;
|
||||
@@ -25,10 +25,11 @@ use std::time::Duration;
|
||||
use crate::AppConfig;
|
||||
use crate::gui::Colors;
|
||||
use crate::gui::icons::{
|
||||
ARROW_LEFT, BOOKMARKS, CALENDAR_CHECK, CLOUD_ARROW_DOWN, COMPUTER_TOWER, FOLDER_PLUS, GEAR,
|
||||
GEAR_FINE, GLOBE, GLOBE_SIMPLE, LOCK_KEY, NOTEPAD, PLUS, SIDEBAR_SIMPLE, SUITCASE,
|
||||
ARROW_LEFT, BOOKMARKS, CALENDAR_CHECK, CLOUD_ARROW_DOWN, COMPUTER_TOWER, GEAR, GEAR_FINE,
|
||||
GLOBE, GLOBE_SIMPLE, LOCK_KEY, NOTEPAD, PLUS, SIDEBAR_SIMPLE, SUITCASE,
|
||||
};
|
||||
use crate::gui::platform::PlatformCallbacks;
|
||||
use crate::gui::views::goblin::onboarding::OnboardingContent;
|
||||
use crate::gui::views::settings::SettingsContent;
|
||||
use crate::gui::views::types::{
|
||||
ContentContainer, LinePosition, ModalPosition, TitleContentType, TitleType,
|
||||
@@ -64,6 +65,8 @@ pub struct WalletsContent {
|
||||
wallet_content: WalletContent,
|
||||
/// Wallet creation content.
|
||||
creation_content: Option<WalletCreationContent>,
|
||||
/// First-run onboarding content, shown while no wallets exist.
|
||||
onboarding: Option<OnboardingContent>,
|
||||
|
||||
/// Settings content.
|
||||
settings_content: Option<SettingsContent>,
|
||||
@@ -95,6 +98,7 @@ impl Default for WalletsContent {
|
||||
wallet_settings_content: WalletSettingsModal::new(ConnectionMethod::Integrated),
|
||||
wallet_content: WalletContent::default(),
|
||||
creation_content: None,
|
||||
onboarding: None,
|
||||
settings_content: None,
|
||||
check_update: Bind::new(false),
|
||||
update_info: (false, None),
|
||||
@@ -194,16 +198,21 @@ impl ContentContainer for WalletsContent {
|
||||
let showing_settings = self.showing_settings();
|
||||
let creating_wallet = self.creating_wallet();
|
||||
let showing_wallet = self.showing_wallet() && !creating_wallet && !showing_settings;
|
||||
// First-run onboarding owns the surface while no wallets exist (and
|
||||
// keeps it through its identity step, when the new wallet is already
|
||||
// open but not yet selected).
|
||||
let onboarding_active = !showing_wallet && self.onboarding_active();
|
||||
let dual_panel = is_dual_panel_mode(ui);
|
||||
let content_width = ui.available_width();
|
||||
let list_hidden = showing_settings
|
||||
|| creating_wallet
|
||||
|| onboarding_active
|
||||
|| self.wallets.list().is_empty()
|
||||
|| (showing_wallet && (!dual_panel || !AppConfig::show_wallets_at_dual_panel()));
|
||||
|
||||
// Show title panel, except over the full-bleed Goblin wallet surface
|
||||
// (it has its own header/navigation; lock + node info live there).
|
||||
if !showing_wallet {
|
||||
// and onboarding (they have their own header/navigation).
|
||||
if !showing_wallet && !onboarding_active {
|
||||
self.title_ui(ui, dual_panel, cb);
|
||||
}
|
||||
|
||||
@@ -300,6 +309,8 @@ impl ContentContainer for WalletsContent {
|
||||
},
|
||||
fill: if self.showing_settings() {
|
||||
Colors::fill_lite()
|
||||
} else if onboarding_active {
|
||||
Colors::fill()
|
||||
} else {
|
||||
Colors::fill_deep()
|
||||
},
|
||||
@@ -337,20 +348,17 @@ impl ContentContainer for WalletsContent {
|
||||
self.select_wallet(w, None, cb);
|
||||
}
|
||||
}
|
||||
} else if self.wallets.list().is_empty() {
|
||||
View::center_content(ui, 350.0 + View::get_bottom_inset(), |ui| {
|
||||
View::app_logo_name_version(ui);
|
||||
ui.add_space(4.0);
|
||||
|
||||
let text = t!("wallets.create_desc");
|
||||
ui.label(RichText::new(text).size(16.0).color(Colors::gray()));
|
||||
ui.add_space(8.0);
|
||||
// Show wallet creation button.
|
||||
let add_text = format!("{} {}", FOLDER_PLUS, t!("wallets.add"));
|
||||
View::button(ui, add_text, Colors::white_or_black(false), || {
|
||||
self.show_add_wallet_modal();
|
||||
});
|
||||
});
|
||||
} else if onboarding_active {
|
||||
// First-run onboarding replaces the stock empty state;
|
||||
// later wallets still use the list's add-wallet flow.
|
||||
if self.onboarding.is_none() {
|
||||
self.onboarding = Some(OnboardingContent::default());
|
||||
}
|
||||
let ob = self.onboarding.as_mut().unwrap();
|
||||
if let Some(w) = ob.ui(ui, &mut self.wallets, cb) {
|
||||
self.onboarding = None;
|
||||
self.select_wallet(&w, None, cb);
|
||||
}
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
@@ -402,6 +410,14 @@ impl WalletsContent {
|
||||
self.creation_content.is_some()
|
||||
}
|
||||
|
||||
/// Check if first-run onboarding owns the surface (no wallets yet, or
|
||||
/// the onboarding identity step is still finishing).
|
||||
pub fn onboarding_active(&self) -> bool {
|
||||
!self.showing_settings()
|
||||
&& !self.creating_wallet()
|
||||
&& (self.onboarding.is_some() || self.wallets.list().is_empty())
|
||||
}
|
||||
|
||||
/// Check if application settings are showing.
|
||||
pub fn showing_settings(&self) -> bool {
|
||||
self.settings_content.is_some()
|
||||
|
||||
@@ -133,7 +133,7 @@ impl MnemonicSetup {
|
||||
}
|
||||
|
||||
/// Draw grid of words for mnemonic phrase.
|
||||
fn word_list_ui(&mut self, ui: &mut egui::Ui, edit: bool) {
|
||||
pub(crate) fn word_list_ui(&mut self, ui: &mut egui::Ui, edit: bool) {
|
||||
ui.add_space(6.0);
|
||||
ui.scope(|ui| {
|
||||
// Setup spacing between columns.
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
mod creation;
|
||||
pub(crate) mod creation;
|
||||
pub mod modals;
|
||||
|
||||
mod content;
|
||||
|
||||
Reference in New Issue
Block a user