Compare commits
8 Commits
7d47c6e14e
...
38f2aa2f8f
| Author | SHA1 | Date | |
|---|---|---|---|
| 38f2aa2f8f | |||
| 40f8425d94 | |||
| 2157a30192 | |||
| bef3c0c47d | |||
| 5c570613c8 | |||
| 567732206e | |||
| 0dcc09fc5f | |||
| 82d3178119 |
Binary file not shown.
@@ -271,12 +271,18 @@
|
||||
"console_app": "App",
|
||||
"console_auto_scroll": "Automatisch scrollen",
|
||||
"console_available_commands": "Verfügbare Befehle:",
|
||||
"console_backend_reference": "Backend-Befehlsreferenz",
|
||||
"console_backend_unavailable": "Kein Backend",
|
||||
"console_capturing_output": "Erfasse Daemon-Ausgabe...",
|
||||
"console_cat_advanced": "Erweitert",
|
||||
"console_cat_blockchain": "Blockchain",
|
||||
"console_cat_control": "Steuerung",
|
||||
"console_cat_keys": "Schlüssel & Sicherheit",
|
||||
"console_cat_mining": "Mining",
|
||||
"console_cat_network": "Netzwerk",
|
||||
"console_cat_raw_transactions": "Rohtransaktionen",
|
||||
"console_cat_send": "Senden",
|
||||
"console_cat_sync": "Synchronisierung",
|
||||
"console_cat_utility": "Dienstprogramme",
|
||||
"console_cat_wallet": "Wallet",
|
||||
"console_clear": "Leeren",
|
||||
@@ -310,11 +316,14 @@
|
||||
"console_help_help": " help - Diese Hilfe anzeigen",
|
||||
"console_help_setgenerate": " setgenerate - Mining steuern",
|
||||
"console_help_stop": " stop - Daemon stoppen",
|
||||
"console_last_error": "Letzter Fehler:",
|
||||
"console_line_count": "%zu Zeilen",
|
||||
"console_matches": "Treffer",
|
||||
"console_new_lines": "%d neue Zeilen",
|
||||
"console_no_daemon": "Kein Daemon",
|
||||
"console_no_output": "(keine Ausgabe)",
|
||||
"console_not_connected": "Fehler: Nicht mit Daemon verbunden",
|
||||
"console_not_connected_lite": "Fehler: Keine Wallet geöffnet",
|
||||
"console_quit_note": "'quit'/'exit' werden hier nicht benötigt — schließen Sie einfach das Fenster.",
|
||||
"console_ref_builds": "Ergibt",
|
||||
"console_ref_cancel": "Abbrechen",
|
||||
@@ -330,12 +339,14 @@
|
||||
"console_ref_run_confirm": "%s jetzt ausführen? Dies ist ein folgenreicher Befehl.",
|
||||
"console_ref_search_hint": "Nach Name oder Aufgabe suchen…",
|
||||
"console_ref_select_hint": "Wählen Sie einen Befehl, um zu sehen, was er tut.",
|
||||
"console_ref_value": "Wert",
|
||||
"console_rpc_reference": "RPC-Befehlsreferenz",
|
||||
"console_rpc_trace": "RPC",
|
||||
"console_scanline": "Konsolen-Scanline",
|
||||
"console_search_commands": "Befehle suchen...",
|
||||
"console_select_all": "Alles auswählen",
|
||||
"console_show_app_output": "[App]-Wallet-Protokollzeilen anzeigen",
|
||||
"console_show_backend_ref": "Backend-Befehlsreferenz anzeigen",
|
||||
"console_show_daemon_output": "Daemon-Ausgabe anzeigen",
|
||||
"console_show_errors_only": "Nur Fehler anzeigen",
|
||||
"console_show_rpc_ref": "RPC-Befehlsreferenz anzeigen",
|
||||
@@ -348,6 +359,7 @@
|
||||
"console_status_stopped": "Gestoppt",
|
||||
"console_status_stopping": "Stoppt",
|
||||
"console_status_unknown": "Unbekannt",
|
||||
"console_stop_confirm_node": "'stop' fährt den Node herunter und trennt die Wallet. Geben Sie zur Bestätigung erneut 'stop' ein.",
|
||||
"console_tab_completion": "Tab zur Vervollständigung",
|
||||
"console_text_colors": "Textfarben",
|
||||
"console_toggle_accents": "Farbakzente der Zeilen umschalten",
|
||||
@@ -626,6 +638,7 @@
|
||||
"lite_birthday_backup": "Geburtstag: %llu (auch diesen sichern)",
|
||||
"lite_birthday_hint": "Blockhöhe, ab der gescannt werden soll. Bei 0 belassen, falls unbekannt (langsamerer vollständiger Scan).",
|
||||
"lite_birthday_label": "Geburtsblock",
|
||||
"lite_console_backend_commands": "Backend-Befehle:",
|
||||
"lite_console_help_passthrough": "Jede andere Eingabe wird als Lite-Wallet-Konsolenbefehl ausgeführt.",
|
||||
"lite_copy": "Kopieren",
|
||||
"lite_could_not_write": "Konnte nicht schreiben ",
|
||||
@@ -643,6 +656,7 @@
|
||||
"lite_net_add_url_hint": "https://ihr-lite-server",
|
||||
"lite_net_checking": "wird geprüft…",
|
||||
"lite_net_connected": "Verbunden",
|
||||
"lite_net_connecting": "Verbinde…",
|
||||
"lite_net_custom": "Benutzerdefiniert",
|
||||
"lite_net_disconnected": "Nicht verbunden",
|
||||
"lite_net_hidden_section": "Ausgeblendete Server",
|
||||
|
||||
@@ -271,12 +271,18 @@
|
||||
"console_app": "App",
|
||||
"console_auto_scroll": "Auto-desplazamiento",
|
||||
"console_available_commands": "Comandos disponibles:",
|
||||
"console_backend_reference": "Referencia de Comandos del Backend",
|
||||
"console_backend_unavailable": "Sin backend",
|
||||
"console_capturing_output": "Capturando salida del daemon...",
|
||||
"console_cat_advanced": "Avanzado",
|
||||
"console_cat_blockchain": "Blockchain",
|
||||
"console_cat_control": "Control",
|
||||
"console_cat_keys": "Claves y seguridad",
|
||||
"console_cat_mining": "Minería",
|
||||
"console_cat_network": "Red",
|
||||
"console_cat_raw_transactions": "Transacciones sin procesar",
|
||||
"console_cat_send": "Enviar",
|
||||
"console_cat_sync": "Sincronización",
|
||||
"console_cat_utility": "Utilidades",
|
||||
"console_cat_wallet": "Cartera",
|
||||
"console_clear": "Limpiar",
|
||||
@@ -310,11 +316,14 @@
|
||||
"console_help_help": " help - Mostrar este mensaje de ayuda",
|
||||
"console_help_setgenerate": " setgenerate - Controlar minería",
|
||||
"console_help_stop": " stop - Detener el daemon",
|
||||
"console_last_error": "Último error:",
|
||||
"console_line_count": "%zu líneas",
|
||||
"console_matches": "coincidencias",
|
||||
"console_new_lines": "%d nuevas líneas",
|
||||
"console_no_daemon": "Sin daemon",
|
||||
"console_no_output": "(sin salida)",
|
||||
"console_not_connected": "Error: No conectado al daemon",
|
||||
"console_not_connected_lite": "Error: No hay ninguna cartera abierta",
|
||||
"console_quit_note": "'quit'/'exit' no son necesarios aquí — simplemente cierra la ventana.",
|
||||
"console_ref_builds": "Genera",
|
||||
"console_ref_cancel": "Cancelar",
|
||||
@@ -330,12 +339,14 @@
|
||||
"console_ref_run_confirm": "¿Ejecutar %s ahora? Es un comando con consecuencias.",
|
||||
"console_ref_search_hint": "Buscar por nombre o tarea…",
|
||||
"console_ref_select_hint": "Selecciona un comando para ver qué hace.",
|
||||
"console_ref_value": "valor",
|
||||
"console_rpc_reference": "Referencia de Comandos RPC",
|
||||
"console_rpc_trace": "RPC",
|
||||
"console_scanline": "Líneas de consola",
|
||||
"console_search_commands": "Buscar comandos...",
|
||||
"console_select_all": "Seleccionar Todo",
|
||||
"console_show_app_output": "Mostrar las líneas de registro de la cartera [app]",
|
||||
"console_show_backend_ref": "Mostrar referencia de comandos del backend",
|
||||
"console_show_daemon_output": "Mostrar salida del daemon",
|
||||
"console_show_errors_only": "Mostrar solo errores",
|
||||
"console_show_rpc_ref": "Mostrar referencia de comandos RPC",
|
||||
@@ -348,6 +359,7 @@
|
||||
"console_status_stopped": "Detenido",
|
||||
"console_status_stopping": "Deteniendo",
|
||||
"console_status_unknown": "Desconocido",
|
||||
"console_stop_confirm_node": "'stop' apagará el nodo y desconectará la cartera. Escribe 'stop' de nuevo para confirmar.",
|
||||
"console_tab_completion": "Tab para completar",
|
||||
"console_text_colors": "Colores de texto",
|
||||
"console_toggle_accents": "Alternar acentos de color de línea",
|
||||
@@ -626,6 +638,7 @@
|
||||
"lite_birthday_backup": "Cumpleaños: %llu (respalda esto también)",
|
||||
"lite_birthday_hint": "Altura de bloque desde la que empezar a escanear. Deja 0 si se desconoce (escaneo completo más lento).",
|
||||
"lite_birthday_label": "Fecha de creación",
|
||||
"lite_console_backend_commands": "Comandos del backend:",
|
||||
"lite_console_help_passthrough": "Cualquier otra entrada se ejecuta como un comando de consola de la cartera lite.",
|
||||
"lite_copy": "Copiar",
|
||||
"lite_could_not_write": "No se pudo escribir ",
|
||||
@@ -643,6 +656,7 @@
|
||||
"lite_net_add_url_hint": "https://tu-servidor-lite",
|
||||
"lite_net_checking": "comprobando…",
|
||||
"lite_net_connected": "Conectado",
|
||||
"lite_net_connecting": "Conectando…",
|
||||
"lite_net_custom": "Personalizado",
|
||||
"lite_net_disconnected": "No conectado",
|
||||
"lite_net_hidden_section": "Servidores ocultos",
|
||||
|
||||
@@ -271,12 +271,18 @@
|
||||
"console_app": "App",
|
||||
"console_auto_scroll": "Défilement auto",
|
||||
"console_available_commands": "Commandes disponibles :",
|
||||
"console_backend_reference": "Référence des commandes du backend",
|
||||
"console_backend_unavailable": "Aucun backend",
|
||||
"console_capturing_output": "Capture de la sortie du daemon...",
|
||||
"console_cat_advanced": "Avancé",
|
||||
"console_cat_blockchain": "Blockchain",
|
||||
"console_cat_control": "Contrôle",
|
||||
"console_cat_keys": "Clés et sécurité",
|
||||
"console_cat_mining": "Minage",
|
||||
"console_cat_network": "Réseau",
|
||||
"console_cat_raw_transactions": "Transactions brutes",
|
||||
"console_cat_send": "Envoyer",
|
||||
"console_cat_sync": "Synchronisation",
|
||||
"console_cat_utility": "Utilitaires",
|
||||
"console_cat_wallet": "Portefeuille",
|
||||
"console_clear": "Effacer",
|
||||
@@ -310,11 +316,14 @@
|
||||
"console_help_help": " help - Afficher ce message d'aide",
|
||||
"console_help_setgenerate": " setgenerate - Contrôler le minage",
|
||||
"console_help_stop": " stop - Arrêter le daemon",
|
||||
"console_last_error": "Dernière erreur :",
|
||||
"console_line_count": "%zu lignes",
|
||||
"console_matches": "correspondances",
|
||||
"console_new_lines": "%d nouvelles lignes",
|
||||
"console_no_daemon": "Pas de daemon",
|
||||
"console_no_output": "(aucune sortie)",
|
||||
"console_not_connected": "Erreur : Non connecté au daemon",
|
||||
"console_not_connected_lite": "Erreur : Aucun portefeuille ouvert",
|
||||
"console_quit_note": "'quit'/'exit' ne sont pas nécessaires ici — fermez simplement la fenêtre.",
|
||||
"console_ref_builds": "Génère",
|
||||
"console_ref_cancel": "Annuler",
|
||||
@@ -330,12 +339,14 @@
|
||||
"console_ref_run_confirm": "Exécuter %s maintenant ? C'est une commande à conséquences.",
|
||||
"console_ref_search_hint": "Rechercher par nom ou tâche…",
|
||||
"console_ref_select_hint": "Sélectionnez une commande pour voir ce qu'elle fait.",
|
||||
"console_ref_value": "valeur",
|
||||
"console_rpc_reference": "Référence des commandes RPC",
|
||||
"console_rpc_trace": "RPC",
|
||||
"console_scanline": "Scanline de la console",
|
||||
"console_search_commands": "Rechercher des commandes...",
|
||||
"console_select_all": "Tout sélectionner",
|
||||
"console_show_app_output": "Afficher les lignes du journal du portefeuille [app]",
|
||||
"console_show_backend_ref": "Afficher la référence des commandes du backend",
|
||||
"console_show_daemon_output": "Afficher la sortie du daemon",
|
||||
"console_show_errors_only": "Afficher uniquement les erreurs",
|
||||
"console_show_rpc_ref": "Afficher la référence des commandes RPC",
|
||||
@@ -348,6 +359,7 @@
|
||||
"console_status_stopped": "Arrêté",
|
||||
"console_status_stopping": "Arrêt",
|
||||
"console_status_unknown": "Inconnu",
|
||||
"console_stop_confirm_node": "'stop' arrêtera le nœud et déconnectera le portefeuille. Tapez à nouveau 'stop' pour confirmer.",
|
||||
"console_tab_completion": "Tab pour compléter",
|
||||
"console_text_colors": "Couleurs du texte",
|
||||
"console_toggle_accents": "Basculer les accents de couleur des lignes",
|
||||
@@ -626,6 +638,7 @@
|
||||
"lite_birthday_backup": "Date de création : %llu (à sauvegarder également)",
|
||||
"lite_birthday_hint": "Hauteur de bloc à partir de laquelle commencer l'analyse. Laissez 0 si inconnue (analyse complète plus lente).",
|
||||
"lite_birthday_label": "Bloc de création",
|
||||
"lite_console_backend_commands": "Commandes du backend :",
|
||||
"lite_console_help_passthrough": "Toute autre entrée est exécutée comme une commande de la console du portefeuille lite.",
|
||||
"lite_copy": "Copier",
|
||||
"lite_could_not_write": "Impossible d'écrire ",
|
||||
@@ -643,6 +656,7 @@
|
||||
"lite_net_add_url_hint": "https://votre-serveur-lite",
|
||||
"lite_net_checking": "vérification…",
|
||||
"lite_net_connected": "Connecté",
|
||||
"lite_net_connecting": "Connexion…",
|
||||
"lite_net_custom": "Personnalisé",
|
||||
"lite_net_disconnected": "Non connecté",
|
||||
"lite_net_hidden_section": "Serveurs masqués",
|
||||
|
||||
@@ -271,12 +271,18 @@
|
||||
"console_app": "アプリ",
|
||||
"console_auto_scroll": "自動スクロール",
|
||||
"console_available_commands": "利用可能なコマンド:",
|
||||
"console_backend_reference": "バックエンドコマンドリファレンス",
|
||||
"console_backend_unavailable": "バックエンドなし",
|
||||
"console_capturing_output": "デーモン出力をキャプチャ中...",
|
||||
"console_cat_advanced": "詳細設定",
|
||||
"console_cat_blockchain": "ブロックチェーン",
|
||||
"console_cat_control": "制御",
|
||||
"console_cat_keys": "鍵とセキュリティ",
|
||||
"console_cat_mining": "マイニング",
|
||||
"console_cat_network": "ネットワーク",
|
||||
"console_cat_raw_transactions": "生トランザクション",
|
||||
"console_cat_send": "送金",
|
||||
"console_cat_sync": "同期",
|
||||
"console_cat_utility": "ユーティリティ",
|
||||
"console_cat_wallet": "ウォレット",
|
||||
"console_clear": "クリア",
|
||||
@@ -310,11 +316,14 @@
|
||||
"console_help_help": " help - このヘルプを表示",
|
||||
"console_help_setgenerate": " setgenerate - マイニングを制御",
|
||||
"console_help_stop": " stop - デーモンを停止",
|
||||
"console_last_error": "最後のエラー:",
|
||||
"console_line_count": "%zu 行",
|
||||
"console_matches": "件一致",
|
||||
"console_new_lines": "%d 新しい行",
|
||||
"console_no_daemon": "デーモンなし",
|
||||
"console_no_output": "(出力なし)",
|
||||
"console_not_connected": "エラー:デーモンに接続されていません",
|
||||
"console_not_connected_lite": "エラー:ウォレットが開かれていません",
|
||||
"console_quit_note": "ここでは 'quit'/'exit' は不要です — ウィンドウを閉じるだけで構いません。",
|
||||
"console_ref_builds": "生成",
|
||||
"console_ref_cancel": "キャンセル",
|
||||
@@ -330,12 +339,14 @@
|
||||
"console_ref_run_confirm": "%s を今すぐ実行しますか? 影響の大きいコマンドです。",
|
||||
"console_ref_search_hint": "名前または用途で検索…",
|
||||
"console_ref_select_hint": "コマンドを選ぶと内容が表示されます。",
|
||||
"console_ref_value": "値",
|
||||
"console_rpc_reference": "RPCコマンドリファレンス",
|
||||
"console_rpc_trace": "RPC",
|
||||
"console_scanline": "コンソールスキャンライン",
|
||||
"console_search_commands": "コマンドを検索...",
|
||||
"console_select_all": "すべて選択",
|
||||
"console_show_app_output": "[app] ウォレットのログ行を表示",
|
||||
"console_show_backend_ref": "バックエンドコマンドリファレンスを表示",
|
||||
"console_show_daemon_output": "デーモン出力を表示",
|
||||
"console_show_errors_only": "エラーのみ表示",
|
||||
"console_show_rpc_ref": "RPCコマンドリファレンスを表示",
|
||||
@@ -348,6 +359,7 @@
|
||||
"console_status_stopped": "停止済み",
|
||||
"console_status_stopping": "停止中",
|
||||
"console_status_unknown": "不明",
|
||||
"console_stop_confirm_node": "'stop' はノードを停止し、ウォレットを切断します。確認するにはもう一度 'stop' と入力してください。",
|
||||
"console_tab_completion": "Tabで補完",
|
||||
"console_text_colors": "テキスト色",
|
||||
"console_toggle_accents": "行のカラーアクセントを切り替え",
|
||||
@@ -626,6 +638,7 @@
|
||||
"lite_birthday_backup": "誕生日:%llu (これもバックアップしてください)",
|
||||
"lite_birthday_hint": "スキャンを開始するブロック高。不明な場合は0のままにしてください(完全スキャンが遅くなります)。",
|
||||
"lite_birthday_label": "バースデー",
|
||||
"lite_console_backend_commands": "バックエンドコマンド:",
|
||||
"lite_console_help_passthrough": "その他の入力はライトウォレットのコンソールコマンドとして実行されます。",
|
||||
"lite_copy": "コピー",
|
||||
"lite_could_not_write": "書き込めませんでした ",
|
||||
@@ -643,6 +656,7 @@
|
||||
"lite_net_add_url_hint": "https://your-lite-server",
|
||||
"lite_net_checking": "確認中…",
|
||||
"lite_net_connected": "接続済み",
|
||||
"lite_net_connecting": "接続中…",
|
||||
"lite_net_custom": "カスタム",
|
||||
"lite_net_disconnected": "未接続",
|
||||
"lite_net_hidden_section": "非表示のサーバー",
|
||||
|
||||
@@ -271,12 +271,18 @@
|
||||
"console_app": "앱",
|
||||
"console_auto_scroll": "자동 스크롤",
|
||||
"console_available_commands": "사용 가능한 명령어:",
|
||||
"console_backend_reference": "백엔드 명령어 참조",
|
||||
"console_backend_unavailable": "백엔드 없음",
|
||||
"console_capturing_output": "데몬 출력 캡처 중...",
|
||||
"console_cat_advanced": "고급",
|
||||
"console_cat_blockchain": "블록체인",
|
||||
"console_cat_control": "제어",
|
||||
"console_cat_keys": "키 및 보안",
|
||||
"console_cat_mining": "채굴",
|
||||
"console_cat_network": "네트워크",
|
||||
"console_cat_raw_transactions": "원시 트랜잭션",
|
||||
"console_cat_send": "보내기",
|
||||
"console_cat_sync": "동기화",
|
||||
"console_cat_utility": "유틸리티",
|
||||
"console_cat_wallet": "지갑",
|
||||
"console_clear": "지우기",
|
||||
@@ -310,11 +316,14 @@
|
||||
"console_help_help": " help - 도움말 표시",
|
||||
"console_help_setgenerate": " setgenerate - 채굴 제어",
|
||||
"console_help_stop": " stop - 데몬 중지",
|
||||
"console_last_error": "마지막 오류:",
|
||||
"console_line_count": "%zu줄",
|
||||
"console_matches": "일치",
|
||||
"console_new_lines": "%d 새 줄",
|
||||
"console_no_daemon": "데몬 없음",
|
||||
"console_no_output": "(출력 없음)",
|
||||
"console_not_connected": "오류: 데몬에 연결되지 않았습니다",
|
||||
"console_not_connected_lite": "오류: 열린 지갑 없음",
|
||||
"console_quit_note": "여기서는 'quit'/'exit'가 필요 없습니다 — 그냥 창을 닫으세요.",
|
||||
"console_ref_builds": "생성",
|
||||
"console_ref_cancel": "취소",
|
||||
@@ -330,12 +339,14 @@
|
||||
"console_ref_run_confirm": "%s 을(를) 지금 실행할까요? 영향이 큰 명령입니다.",
|
||||
"console_ref_search_hint": "이름 또는 용도로 검색…",
|
||||
"console_ref_select_hint": "명령을 선택하면 설명이 표시됩니다.",
|
||||
"console_ref_value": "값",
|
||||
"console_rpc_reference": "RPC 명령어 참조",
|
||||
"console_rpc_trace": "RPC",
|
||||
"console_scanline": "콘솔 스캔라인",
|
||||
"console_search_commands": "명령어 검색...",
|
||||
"console_select_all": "모두 선택",
|
||||
"console_show_app_output": "[app] 지갑 로그 줄 표시",
|
||||
"console_show_backend_ref": "백엔드 명령어 참조 표시",
|
||||
"console_show_daemon_output": "데몬 출력 표시",
|
||||
"console_show_errors_only": "오류만 표시",
|
||||
"console_show_rpc_ref": "RPC 명령어 참조 표시",
|
||||
@@ -348,6 +359,7 @@
|
||||
"console_status_stopped": "중지됨",
|
||||
"console_status_stopping": "중지 중",
|
||||
"console_status_unknown": "알 수 없음",
|
||||
"console_stop_confirm_node": "'stop'은 노드를 종료하고 지갑 연결을 끊습니다. 확인하려면 'stop'을 다시 입력하세요.",
|
||||
"console_tab_completion": "Tab으로 자동 완성",
|
||||
"console_text_colors": "텍스트 색상",
|
||||
"console_toggle_accents": "줄 색상 강조 전환",
|
||||
@@ -626,6 +638,7 @@
|
||||
"lite_birthday_backup": "생성 블록: %llu (이 값도 백업하세요)",
|
||||
"lite_birthday_hint": "스캔을 시작할 블록 높이입니다. 모르면 0으로 두세요(전체 스캔이 느려짐).",
|
||||
"lite_birthday_label": "생일 블록",
|
||||
"lite_console_backend_commands": "백엔드 명령:",
|
||||
"lite_console_help_passthrough": "그 외 입력은 라이트 지갑 콘솔 명령으로 실행됩니다.",
|
||||
"lite_copy": "복사",
|
||||
"lite_could_not_write": "쓸 수 없습니다: ",
|
||||
@@ -643,6 +656,7 @@
|
||||
"lite_net_add_url_hint": "https://your-lite-server",
|
||||
"lite_net_checking": "확인 중…",
|
||||
"lite_net_connected": "연결됨",
|
||||
"lite_net_connecting": "연결 중…",
|
||||
"lite_net_custom": "사용자 지정",
|
||||
"lite_net_disconnected": "연결되지 않음",
|
||||
"lite_net_hidden_section": "숨겨진 서버",
|
||||
|
||||
@@ -271,12 +271,18 @@
|
||||
"console_app": "App",
|
||||
"console_auto_scroll": "Rolagem automática",
|
||||
"console_available_commands": "Comandos disponíveis:",
|
||||
"console_backend_reference": "Referência de Comandos do Backend",
|
||||
"console_backend_unavailable": "Sem backend",
|
||||
"console_capturing_output": "Capturando saída do daemon...",
|
||||
"console_cat_advanced": "Avançado",
|
||||
"console_cat_blockchain": "Blockchain",
|
||||
"console_cat_control": "Controle",
|
||||
"console_cat_keys": "Chaves e segurança",
|
||||
"console_cat_mining": "Mineração",
|
||||
"console_cat_network": "Rede",
|
||||
"console_cat_raw_transactions": "Transações brutas",
|
||||
"console_cat_send": "Enviar",
|
||||
"console_cat_sync": "Sincronização",
|
||||
"console_cat_utility": "Utilitários",
|
||||
"console_cat_wallet": "Carteira",
|
||||
"console_clear": "Limpar",
|
||||
@@ -310,11 +316,14 @@
|
||||
"console_help_help": " help - Mostrar esta mensagem de ajuda",
|
||||
"console_help_setgenerate": " setgenerate - Controlar mineração",
|
||||
"console_help_stop": " stop - Parar o daemon",
|
||||
"console_last_error": "Último erro:",
|
||||
"console_line_count": "%zu linhas",
|
||||
"console_matches": "correspondências",
|
||||
"console_new_lines": "%d novas linhas",
|
||||
"console_no_daemon": "Sem daemon",
|
||||
"console_no_output": "(sem saída)",
|
||||
"console_not_connected": "Erro: Não conectado ao daemon",
|
||||
"console_not_connected_lite": "Erro: Nenhuma carteira aberta",
|
||||
"console_quit_note": "'quit'/'exit' não são necessários aqui — basta fechar a janela.",
|
||||
"console_ref_builds": "Gera",
|
||||
"console_ref_cancel": "Cancelar",
|
||||
@@ -330,12 +339,14 @@
|
||||
"console_ref_run_confirm": "Executar %s agora? Este é um comando com consequências.",
|
||||
"console_ref_search_hint": "Pesquisar por nome ou tarefa…",
|
||||
"console_ref_select_hint": "Selecione um comando para ver o que ele faz.",
|
||||
"console_ref_value": "valor",
|
||||
"console_rpc_reference": "Referência de Comandos RPC",
|
||||
"console_rpc_trace": "RPC",
|
||||
"console_scanline": "Scanline do console",
|
||||
"console_search_commands": "Pesquisar comandos...",
|
||||
"console_select_all": "Selecionar Tudo",
|
||||
"console_show_app_output": "Mostrar linhas do log da carteira [app]",
|
||||
"console_show_backend_ref": "Mostrar referência de comandos do backend",
|
||||
"console_show_daemon_output": "Mostrar saída do daemon",
|
||||
"console_show_errors_only": "Mostrar apenas erros",
|
||||
"console_show_rpc_ref": "Mostrar referência de comandos RPC",
|
||||
@@ -348,6 +359,7 @@
|
||||
"console_status_stopped": "Parado",
|
||||
"console_status_stopping": "Parando",
|
||||
"console_status_unknown": "Desconhecido",
|
||||
"console_stop_confirm_node": "'stop' irá desligar o nó e desconectar a carteira. Digite 'stop' novamente para confirmar.",
|
||||
"console_tab_completion": "Tab para completar",
|
||||
"console_text_colors": "Cores do texto",
|
||||
"console_toggle_accents": "Alternar destaques de cor das linhas",
|
||||
@@ -626,6 +638,7 @@
|
||||
"lite_birthday_backup": "Aniversário: %llu (faça o backup disto também)",
|
||||
"lite_birthday_hint": "Altura do bloco a partir da qual começar a escanear. Deixe 0 se desconhecida (escaneamento completo mais lento).",
|
||||
"lite_birthday_label": "Data de nascimento",
|
||||
"lite_console_backend_commands": "Comandos do backend:",
|
||||
"lite_console_help_passthrough": "Qualquer outra entrada é executada como um comando de console da carteira leve.",
|
||||
"lite_copy": "Copiar",
|
||||
"lite_could_not_write": "Não foi possível gravar ",
|
||||
@@ -643,6 +656,7 @@
|
||||
"lite_net_add_url_hint": "https://seu-servidor-lite",
|
||||
"lite_net_checking": "verificando…",
|
||||
"lite_net_connected": "Conectado",
|
||||
"lite_net_connecting": "Conectando…",
|
||||
"lite_net_custom": "Personalizado",
|
||||
"lite_net_disconnected": "Não conectado",
|
||||
"lite_net_hidden_section": "Servidores ocultos",
|
||||
|
||||
@@ -271,12 +271,18 @@
|
||||
"console_app": "Прил.",
|
||||
"console_auto_scroll": "Авто-прокрутка",
|
||||
"console_available_commands": "Доступные команды:",
|
||||
"console_backend_reference": "Справочник команд бэкенда",
|
||||
"console_backend_unavailable": "Нет бэкенда",
|
||||
"console_capturing_output": "Захват вывода daemon...",
|
||||
"console_cat_advanced": "Дополнительно",
|
||||
"console_cat_blockchain": "Блокчейн",
|
||||
"console_cat_control": "Управление",
|
||||
"console_cat_keys": "Ключи и безопасность",
|
||||
"console_cat_mining": "Майнинг",
|
||||
"console_cat_network": "Сеть",
|
||||
"console_cat_raw_transactions": "Сырые транзакции",
|
||||
"console_cat_send": "Отправка",
|
||||
"console_cat_sync": "Синхронизация",
|
||||
"console_cat_utility": "Утилиты",
|
||||
"console_cat_wallet": "Кошелёк",
|
||||
"console_clear": "Очистить",
|
||||
@@ -310,11 +316,14 @@
|
||||
"console_help_help": " help - Показать эту справку",
|
||||
"console_help_setgenerate": " setgenerate - Управление майнингом",
|
||||
"console_help_stop": " stop - Остановить daemon",
|
||||
"console_last_error": "Последняя ошибка:",
|
||||
"console_line_count": "%zu строк",
|
||||
"console_matches": "совпадений",
|
||||
"console_new_lines": "%d новых строк",
|
||||
"console_no_daemon": "Нет daemon",
|
||||
"console_no_output": "(нет вывода)",
|
||||
"console_not_connected": "Ошибка: Не подключено к daemon",
|
||||
"console_not_connected_lite": "Ошибка: Нет открытого кошелька",
|
||||
"console_quit_note": "Здесь не нужны 'quit'/'exit' — просто закройте окно.",
|
||||
"console_ref_builds": "Формирует",
|
||||
"console_ref_cancel": "Отмена",
|
||||
@@ -330,12 +339,14 @@
|
||||
"console_ref_run_confirm": "Выполнить %s сейчас? Это ответственная команда.",
|
||||
"console_ref_search_hint": "Поиск по названию или задаче…",
|
||||
"console_ref_select_hint": "Выберите команду, чтобы увидеть, что она делает.",
|
||||
"console_ref_value": "значение",
|
||||
"console_rpc_reference": "Справочник RPC-команд",
|
||||
"console_rpc_trace": "RPC",
|
||||
"console_scanline": "Скан-линия консоли",
|
||||
"console_search_commands": "Поиск команд...",
|
||||
"console_select_all": "Выбрать всё",
|
||||
"console_show_app_output": "Показать строки журнала кошелька [app]",
|
||||
"console_show_backend_ref": "Показать справочник команд бэкенда",
|
||||
"console_show_daemon_output": "Показать вывод daemon",
|
||||
"console_show_errors_only": "Показать только ошибки",
|
||||
"console_show_rpc_ref": "Показать справочник RPC-команд",
|
||||
@@ -348,6 +359,7 @@
|
||||
"console_status_stopped": "Остановлен",
|
||||
"console_status_stopping": "Остановка",
|
||||
"console_status_unknown": "Неизвестно",
|
||||
"console_stop_confirm_node": "'stop' остановит узел и отключит кошелёк. Введите 'stop' ещё раз для подтверждения.",
|
||||
"console_tab_completion": "Tab для дополнения",
|
||||
"console_text_colors": "Цвета текста",
|
||||
"console_toggle_accents": "Переключить цветовые акценты строк",
|
||||
@@ -626,6 +638,7 @@
|
||||
"lite_birthday_backup": "Дата рождения: %llu (сохраните её тоже)",
|
||||
"lite_birthday_hint": "Высота блока, с которой начинать сканирование. Оставьте 0, если неизвестно (медленное полное сканирование).",
|
||||
"lite_birthday_label": "Дата рождения",
|
||||
"lite_console_backend_commands": "Команды бэкенда:",
|
||||
"lite_console_help_passthrough": "Любой другой ввод выполняется как команда консоли лайт-кошелька.",
|
||||
"lite_copy": "Копировать",
|
||||
"lite_could_not_write": "Не удалось записать ",
|
||||
@@ -643,6 +656,7 @@
|
||||
"lite_net_add_url_hint": "https://your-lite-server",
|
||||
"lite_net_checking": "проверка…",
|
||||
"lite_net_connected": "Подключено",
|
||||
"lite_net_connecting": "Подключение…",
|
||||
"lite_net_custom": "Свой",
|
||||
"lite_net_disconnected": "Не подключено",
|
||||
"lite_net_hidden_section": "Скрытые серверы",
|
||||
|
||||
@@ -271,12 +271,18 @@
|
||||
"console_app": "应用",
|
||||
"console_auto_scroll": "自动滚动",
|
||||
"console_available_commands": "可用命令:",
|
||||
"console_backend_reference": "后端命令参考",
|
||||
"console_backend_unavailable": "无后端",
|
||||
"console_capturing_output": "正在捕获守护进程输出...",
|
||||
"console_cat_advanced": "高级",
|
||||
"console_cat_blockchain": "区块链",
|
||||
"console_cat_control": "控制",
|
||||
"console_cat_keys": "密钥与安全",
|
||||
"console_cat_mining": "挖矿",
|
||||
"console_cat_network": "网络",
|
||||
"console_cat_raw_transactions": "原始交易",
|
||||
"console_cat_send": "发送",
|
||||
"console_cat_sync": "同步",
|
||||
"console_cat_utility": "实用工具",
|
||||
"console_cat_wallet": "钱包",
|
||||
"console_clear": "清除",
|
||||
@@ -310,11 +316,14 @@
|
||||
"console_help_help": " help - 显示此帮助信息",
|
||||
"console_help_setgenerate": " setgenerate - 控制挖矿",
|
||||
"console_help_stop": " stop - 停止守护进程",
|
||||
"console_last_error": "上次错误:",
|
||||
"console_line_count": "%zu 行",
|
||||
"console_matches": "个匹配",
|
||||
"console_new_lines": "%d 新行",
|
||||
"console_no_daemon": "无守护进程",
|
||||
"console_no_output": "(无输出)",
|
||||
"console_not_connected": "错误:未连接到守护进程",
|
||||
"console_not_connected_lite": "错误:没有打开的钱包",
|
||||
"console_quit_note": "这里不需要 'quit'/'exit'——直接关闭窗口即可。",
|
||||
"console_ref_builds": "生成",
|
||||
"console_ref_cancel": "取消",
|
||||
@@ -330,12 +339,14 @@
|
||||
"console_ref_run_confirm": "立即运行 %s?这是一个有重大影响的命令。",
|
||||
"console_ref_search_hint": "按名称或用途搜索…",
|
||||
"console_ref_select_hint": "选择一个命令以查看其功能。",
|
||||
"console_ref_value": "值",
|
||||
"console_rpc_reference": "RPC 命令参考",
|
||||
"console_rpc_trace": "RPC",
|
||||
"console_scanline": "控制台扫描线",
|
||||
"console_search_commands": "搜索命令...",
|
||||
"console_select_all": "全选",
|
||||
"console_show_app_output": "显示[应用]钱包日志行",
|
||||
"console_show_backend_ref": "显示后端命令参考",
|
||||
"console_show_daemon_output": "显示守护进程输出",
|
||||
"console_show_errors_only": "仅显示错误",
|
||||
"console_show_rpc_ref": "显示 RPC 命令参考",
|
||||
@@ -348,6 +359,7 @@
|
||||
"console_status_stopped": "已停止",
|
||||
"console_status_stopping": "停止中",
|
||||
"console_status_unknown": "未知",
|
||||
"console_stop_confirm_node": "'stop' 将关闭节点并断开钱包连接。再次输入 'stop' 以确认。",
|
||||
"console_tab_completion": "Tab 补全",
|
||||
"console_text_colors": "文本颜色",
|
||||
"console_toggle_accents": "切换行颜色强调",
|
||||
@@ -626,6 +638,7 @@
|
||||
"lite_birthday_backup": "生日区块:%llu (也请一并备份)",
|
||||
"lite_birthday_hint": "开始扫描的区块高度。如未知请保留 0(完整扫描更慢)。",
|
||||
"lite_birthday_label": "诞生区块",
|
||||
"lite_console_backend_commands": "后端命令:",
|
||||
"lite_console_help_passthrough": "其他任何输入都将作为轻钱包控制台命令运行。",
|
||||
"lite_copy": "复制",
|
||||
"lite_could_not_write": "无法写入 ",
|
||||
@@ -643,6 +656,7 @@
|
||||
"lite_net_add_url_hint": "https://your-lite-server",
|
||||
"lite_net_checking": "检查中…",
|
||||
"lite_net_connected": "已连接",
|
||||
"lite_net_connecting": "连接中…",
|
||||
"lite_net_custom": "自定义",
|
||||
"lite_net_disconnected": "未连接",
|
||||
"lite_net_hidden_section": "隐藏的服务器",
|
||||
|
||||
167
res/themes/jade.toml
Normal file
167
res/themes/jade.toml
Normal file
@@ -0,0 +1,167 @@
|
||||
[theme]
|
||||
name = "Jade"
|
||||
author = "The Hush Developers"
|
||||
dark = true
|
||||
elevation = { --elevation-0 = "#071210", --elevation-1 = "#0C1A16", --elevation-2 = "#16261F", --elevation-3 = "#1D3128", --elevation-4 = "#243B30" }
|
||||
images = { background_image = "backgrounds/texture/jade_bg.png", logo = "logos/logo_ObsidianDragon_dark.png" }
|
||||
|
||||
[theme.palette]
|
||||
--primary = "#2FA07A"
|
||||
--primary-variant = "#1E7357"
|
||||
--primary-light = "#7FD1B5"
|
||||
--secondary = "#C9A24E"
|
||||
--secondary-variant = "#A8842F"
|
||||
--secondary-light = "#E0C583"
|
||||
--background = "#071210"
|
||||
--surface = "#0C1A16"
|
||||
--surface-variant = "#16261F"
|
||||
--on-primary = "#FFFFFF"
|
||||
--on-secondary = "#000000"
|
||||
--on-background = "#DCEDE4"
|
||||
--on-surface = "#DCEDE4"
|
||||
--on-surface-medium = "rgba(220,237,228,0.85)"
|
||||
--on-surface-disabled = "rgba(220,237,228,0.58)"
|
||||
--error = "#CF6679"
|
||||
--on-error = "#000000"
|
||||
--success = "#81C784"
|
||||
--on-success = "#000000"
|
||||
--warning = "#FFB74D"
|
||||
--on-warning = "#000000"
|
||||
--divider = "rgba(130,205,170,0.14)"
|
||||
--outline = "rgba(130,205,170,0.16)"
|
||||
--scrim = "rgba(0,0,0,0.6)"
|
||||
--surface-hover = "rgba(130,205,170,0.07)"
|
||||
--surface-alt = "rgba(130,205,170,0.05)"
|
||||
--surface-active = "rgba(130,205,170,0.10)"
|
||||
--glass-button = "rgba(130,205,170,0.06)"
|
||||
--glass-button-hover = "rgba(130,205,170,0.12)"
|
||||
--card-border = "rgba(130,205,170,0.26)"
|
||||
--text-shadow = "rgba(0,0,0,0.50)"
|
||||
--input-overlay-text = "rgba(220,237,228,0.30)"
|
||||
--slider-text = "rgba(220,237,228,0.85)"
|
||||
--thumb-fill = "rgba(130,205,170,0.15)"
|
||||
--thumb-border = "rgba(130,205,170,0.50)"
|
||||
--disabled-label = "rgba(130,205,170,0.18)"
|
||||
--chart-grid = "rgba(130,205,170,0.05)"
|
||||
--chart-crosshair = "rgba(130,205,170,0.15)"
|
||||
--chart-hover-ring = "rgba(130,205,170,0.30)"
|
||||
--tooltip-bg = "rgba(9,20,16,0.92)"
|
||||
--tooltip-border = "rgba(130,205,170,0.12)"
|
||||
--glass-fill = "rgba(130,205,170,0.08)"
|
||||
--glass-border = "rgba(47,160,122,0.30)"
|
||||
--glass-noise-tint = "rgba(130,205,170,0.03)"
|
||||
--tactile-top = "rgba(130,205,170,0.06)"
|
||||
--tactile-bottom = "rgba(130,205,170,0.0)"
|
||||
--hover-overlay = "rgba(130,205,170,0.05)"
|
||||
--active-overlay = "rgba(130,205,170,0.10)"
|
||||
--rim-light = "rgba(130,205,170,0.14)"
|
||||
--status-divider = "rgba(130,205,170,0.08)"
|
||||
--sidebar-hover = "rgba(130,205,170,0.10)"
|
||||
--sidebar-icon = "rgba(130,205,170,0.42)"
|
||||
--sidebar-badge = "rgba(220,237,228,1.0)"
|
||||
--sidebar-divider = "rgba(130,205,170,0.06)"
|
||||
--chart-line = "rgba(130,205,170,0.10)"
|
||||
--window-control = "rgba(220,237,228,0.78)"
|
||||
--window-control-hover = "rgba(130,205,170,0.12)"
|
||||
--window-close-hover = "rgba(232,17,35,0.78)"
|
||||
--spinner-track = "rgba(130,205,170,0.10)"
|
||||
--spinner-active = "rgba(79,184,154,0.85)"
|
||||
--shutdown-panel-bg = "rgba(7,18,14,0.90)"
|
||||
--shutdown-panel-border = "rgba(130,205,170,0.07)"
|
||||
--ram-bar-app = "#2FA07A"
|
||||
--ram-bar-system = "rgba(255,255,255,0.18)"
|
||||
--accent-total = "#7FD1B5"
|
||||
--accent-shielded = "#4FB89A"
|
||||
--accent-transparent = "#C9A24E"
|
||||
--accent-action = "#2FA07A"
|
||||
--accent-market = "#4FB89A"
|
||||
--accent-portfolio = "#7FD1B5"
|
||||
--toast-info-accent = "#2FA07A"
|
||||
--toast-info-text = "#7FD1B5"
|
||||
--toast-success-accent = "rgba(50,180,80,1.0)"
|
||||
--toast-success-text = "rgba(180,255,180,1.0)"
|
||||
--toast-warning-accent = "rgba(204,166,50,1.0)"
|
||||
--toast-warning-text = "rgba(255,230,130,1.0)"
|
||||
--toast-error-accent = "rgba(204,64,64,1.0)"
|
||||
--toast-error-text = "rgba(255,153,153,1.0)"
|
||||
--snackbar-bg = "rgba(24,40,34,0.95)"
|
||||
--snackbar-text = "rgba(220,237,228,0.87)"
|
||||
--snackbar-action = "rgba(79,184,154,1.0)"
|
||||
--snackbar-action-hover = "rgba(127,209,181,1.0)"
|
||||
--switch-track-off = "rgba(130,205,170,0.12)"
|
||||
--switch-track-on = "rgba(47,160,122,0.50)"
|
||||
--switch-thumb-off = "#A0C0B4"
|
||||
--switch-thumb-on = "#DCEDE4"
|
||||
--control-shadow = "rgba(0,0,0,0.24)"
|
||||
--checkbox-check = "#000000"
|
||||
--app-bar-shadow = "rgba(0,0,0,0.25)"
|
||||
|
||||
[backdrop]
|
||||
base-color-top = "rgba(14,32,26,210)"
|
||||
base-color-bottom = "rgba(6,18,14,210)"
|
||||
texture-tint-alpha = 120
|
||||
gradient-top-r = 10
|
||||
gradient-top-g = 30
|
||||
gradient-top-b = 22
|
||||
gradient-top-a = 90
|
||||
gradient-bottom-r = 5
|
||||
gradient-bottom-g = 16
|
||||
gradient-bottom-b = 12
|
||||
gradient-bottom-a = 70
|
||||
background-alpha = 0.42
|
||||
surface-alpha = 0.56
|
||||
frame-alpha = 0.78
|
||||
surface-inline-alpha = 0.58
|
||||
background-inline-alpha = 0.40
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Theme Visual Effects — Jade (polished stone sheen + gold veining)
|
||||
# A soft jade specular highlight drifts across panels like light on
|
||||
# polished nephrite; the active sidebar button traces a jade-to-gold
|
||||
# border echoing the stone's veins — restrained, like Obsidian.
|
||||
# ---------------------------------------------------------------------------
|
||||
[effects]
|
||||
hue-cycle-enabled = { size = 0.0 }
|
||||
rainbow-border-enabled = { size = 0.0 }
|
||||
|
||||
# No shimmer sweep — replaced by specular glare
|
||||
shimmer-enabled = { size = 0.0 }
|
||||
|
||||
positional-hue-enabled = { size = 0.0 }
|
||||
|
||||
glow-pulse-enabled = { size = 0.0 }
|
||||
edge-trace-enabled = { size = 0.0 }
|
||||
|
||||
# Specular glare — soft blurred jade highlights
|
||||
specular-glare-enabled = { size = 1.0 }
|
||||
specular-glare-speed = { size = 0.018 }
|
||||
specular-glare-intensity = { size = 0.008 }
|
||||
specular-glare-radius = { size = 0.65 }
|
||||
specular-glare-count = { size = 1.0 }
|
||||
specular-glare-color = { color = "rgba(150,220,180,1.0)" }
|
||||
|
||||
# Jade-to-gold color-shifting border on the active sidebar button
|
||||
gradient-border-enabled = { size = 1.0 }
|
||||
gradient-border-speed = { size = 0.12 }
|
||||
gradient-border-thickness = { size = 1.5 }
|
||||
gradient-border-alpha = { size = 0.55 }
|
||||
gradient-border-color-a = { color = "#7FD1B5" }
|
||||
gradient-border-color-b = { color = "#C9A24E" }
|
||||
|
||||
ember-rise-enabled = { size = 0.0 }
|
||||
|
||||
# Shader-like viewport overlay — deep green stone atmosphere
|
||||
viewport-wash-enabled = { size = 1.0 }
|
||||
viewport-wash-alpha = { size = 0.05 }
|
||||
viewport-wash-tl = { color = "#12402E" }
|
||||
viewport-wash-tr = { color = "#0E3828" }
|
||||
viewport-wash-bl = { color = "#16442E" }
|
||||
viewport-wash-br = { color = "#1A4A34" }
|
||||
viewport-wash-rotate = { size = 0.015 }
|
||||
viewport-wash-pulse = { size = 0.0 }
|
||||
viewport-wash-pulse-depth = { size = 0.0 }
|
||||
|
||||
viewport-vignette-enabled = { size = 1.0 }
|
||||
viewport-vignette-color = { color = "#04140D" }
|
||||
viewport-vignette-radius = { size = 0.22 }
|
||||
viewport-vignette-alpha = { size = 0.15 }
|
||||
@@ -2005,8 +2005,8 @@ void App::render()
|
||||
// Send confirm popup
|
||||
ui::RenderSendConfirmPopup(this);
|
||||
|
||||
// Console RPC Command Reference popup
|
||||
console_tab_.renderCommandsPopupModal();
|
||||
// Console command-reference popup (full-node RPC reference / lite backend verbs).
|
||||
console_tab_.renderCommandsPopupModal(console_exec_.get());
|
||||
|
||||
// Key export dialog (triggered from balance tab context menu)
|
||||
ui::KeyExportDialog::render(this);
|
||||
|
||||
@@ -434,8 +434,15 @@ std::optional<NetworkRefreshService::PriceRefreshResult> NetworkRefreshService::
|
||||
result.market.market_cap = data.value("usd_market_cap", 0.0);
|
||||
|
||||
char buf[64];
|
||||
std::tm* tm = std::localtime(&fetchedAt);
|
||||
if (tm && std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", tm) > 0) {
|
||||
// Runs on the RPC worker thread — std::localtime shares a process-wide static tm, so use the
|
||||
// reentrant variant into a local tm (matches the rest of the codebase).
|
||||
std::tm tmv{};
|
||||
#ifdef _WIN32
|
||||
localtime_s(&tmv, &fetchedAt);
|
||||
#else
|
||||
localtime_r(&fetchedAt, &tmv);
|
||||
#endif
|
||||
if (std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", &tmv) > 0) {
|
||||
result.market.last_updated = buf;
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -557,9 +557,20 @@ void RenderChatTab(App* app)
|
||||
const float metaSz = scaledSize(metaFont);
|
||||
|
||||
// ---- Left: new-conversation button + conversation list ----
|
||||
// Faint sidebar tint so the list reads as distinct from the thread pane (V6).
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImGui::ColorConvertU32ToFloat4(material::WithAlpha(material::OnSurface(), 10)));
|
||||
ImGui::BeginChild("##ChatList", ImVec2(listW, avail.y), ImGuiChildFlags_Borders,
|
||||
// Frosted-glass pane so the list blurs the backdrop like the rest of the app (the contacts_tab
|
||||
// pattern): draw the glass behind the child, then give the child a TRANSPARENT bg. A flat ChildBg
|
||||
// tint (the old approach) never samples the acrylic blur, so the raw texture showed through.
|
||||
{
|
||||
ImDrawList* paneDL = ImGui::GetWindowDrawList();
|
||||
const ImVec2 pMin = ImGui::GetCursorScreenPos();
|
||||
material::GlassPanelSpec g; g.rounding = 12.0f * Layout::dpiScale(); g.fillAlpha = 20; g.borderAlpha = 34;
|
||||
material::DrawGlassPanel(paneDL, pMin, ImVec2(pMin.x + listW, pMin.y + avail.y), g);
|
||||
}
|
||||
// Inner padding so the list content (buttons, search, conversation cards) doesn't hug the glass
|
||||
// pane's edges now that it's a visible frosted card.
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(12.0f * Layout::dpiScale(), 10.0f * Layout::dpiScale()));
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(0, 0, 0, 0)); // transparent — the frosted glass shows through
|
||||
ImGui::BeginChild("##ChatList", ImVec2(listW, avail.y), ImGuiChildFlags_AlwaysUseWindowPadding,
|
||||
ImGuiWindowFlags_NoScrollWithMouse);
|
||||
material::ApplySmoothScroll(); // wheel-driven lerp scroll, matching the rest of the app
|
||||
if (s_show_emoji_picker) {
|
||||
@@ -683,6 +694,7 @@ void RenderChatTab(App* app)
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::PopStyleColor(); // list ChildBg tint (V6)
|
||||
ImGui::PopStyleVar(); // list inner WindowPadding
|
||||
|
||||
ImGui::SameLine(0.0f, 10.0f * Layout::dpiScale()); // breathing gutter between the list and thread panes
|
||||
|
||||
@@ -699,7 +711,21 @@ void RenderChatTab(App* app)
|
||||
// the box doesn't jump when a reply arrives.
|
||||
const float composerAreaH = sel ? (composerBoxH + metaSz + 12.0f * tdp) : 0.0f;
|
||||
|
||||
ImGui::BeginChild("##ChatThread", ImVec2(0, avail.y - composerAreaH), true);
|
||||
// Frosted-glass thread pane (same reasoning as the list): glass behind + transparent child bg so
|
||||
// the message area blurs the backdrop instead of showing the sharp texture. Replaces the old
|
||||
// bordered child (which drew the flat, translucent WindowBg) — the glass supplies the border.
|
||||
{
|
||||
ImDrawList* paneDL = ImGui::GetWindowDrawList();
|
||||
const ImVec2 pMin = ImGui::GetCursorScreenPos();
|
||||
const float pW = ImGui::GetContentRegionAvail().x;
|
||||
material::GlassPanelSpec g; g.rounding = 12.0f * tdp; g.fillAlpha = 12; g.borderAlpha = 34;
|
||||
material::DrawGlassPanel(paneDL, pMin, ImVec2(pMin.x + pW, pMin.y + (avail.y - composerAreaH)), g);
|
||||
}
|
||||
// Inner padding so the header + messages don't hug the glass card's edges (the message child
|
||||
// below trims its own inset to compensate so bubbles aren't double-indented).
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(12.0f * tdp, 10.0f * tdp));
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(0, 0, 0, 0)); // transparent — frosted glass shows through
|
||||
ImGui::BeginChild("##ChatThread", ImVec2(0, avail.y - composerAreaH), ImGuiChildFlags_AlwaysUseWindowPadding);
|
||||
{
|
||||
if (sel) {
|
||||
app->markChatConversationSeen(sel->cid, sel->lastTs); // viewing the thread clears its unread (Q1)
|
||||
@@ -942,14 +968,15 @@ void RenderChatTab(App* app)
|
||||
ImGui::Separator();
|
||||
|
||||
const float dp = Layout::dpiScale();
|
||||
// Inset the message list from the pane edges so bubbles don't hug the border/scrollbar (8px).
|
||||
// Small message-list inset (the ##ChatThread WindowPadding above already holds content off
|
||||
// the glass edge; keep a little here so bubbles don't hug the scrollbar).
|
||||
// Zero the VERTICAL item spacing: the message loop reserves its own gaps via Dummy() (tight
|
||||
// within a run so the grouped/merged corners read right), so the theme's 6px would double them.
|
||||
const float origSpacingX = ImGui::GetStyle().ItemSpacing.x;
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(8.0f * dp, 8.0f * dp));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(4.0f * dp, 8.0f * dp));
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(origSpacingX, 0.0f));
|
||||
ImGui::BeginChild("##ChatMessages", ImVec2(0, ImGui::GetContentRegionAvail().y),
|
||||
ImGuiChildFlags_None, ImGuiWindowFlags_NoScrollWithMouse);
|
||||
ImGuiChildFlags_AlwaysUseWindowPadding, ImGuiWindowFlags_NoScrollWithMouse);
|
||||
material::ApplySmoothScroll(); // smooth wheel scroll; syncs with the auto-scroll-to-bottom below
|
||||
bool atBottom = true;
|
||||
const ImVec2 msgWinMin = ImGui::GetWindowPos();
|
||||
@@ -1148,6 +1175,8 @@ void RenderChatTab(App* app)
|
||||
}
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::PopStyleColor(); // ##ChatThread transparent ChildBg (GetItemRect below still reads the child)
|
||||
ImGui::PopStyleVar(); // ##ChatThread inner WindowPadding
|
||||
|
||||
// ── Composer — OUTSIDE / below the bordered message box, spanning its width. No divider above it.
|
||||
// Layout (all placed by absolute screen pos so nothing wraps to the window's left edge): a thin
|
||||
@@ -1204,7 +1233,17 @@ void RenderChatTab(App* app)
|
||||
s_emoji_search[0] = '\0';
|
||||
}
|
||||
}
|
||||
// Input.
|
||||
// Input — frosted so it blurs the backdrop like the panes above (glass behind + transparent
|
||||
// FrameBg); a flat FrameBg showed the sharp texture.
|
||||
{
|
||||
ImDrawList* cdl = ImGui::GetWindowDrawList();
|
||||
material::GlassPanelSpec g; g.rounding = 8.0f * tdp; g.fillAlpha = 16; g.borderAlpha = 34;
|
||||
material::DrawGlassPanel(cdl, ImVec2(inputX, rowY),
|
||||
ImVec2(inputX + inputW, rowY + composerBoxH), g);
|
||||
}
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBg, IM_COL32(0, 0, 0, 0));
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgHovered, IM_COL32(0, 0, 0, 0));
|
||||
ImGui::PushStyleColor(ImGuiCol_FrameBgActive, IM_COL32(0, 0, 0, 0));
|
||||
ImGui::SetCursorScreenPos(ImVec2(inputX, rowY));
|
||||
// Enter-to-send (setting): on → Enter sends + Ctrl+Enter newline; off → Enter is a newline and
|
||||
// the Send button is the only way to send. NOTE: without EnterReturnsTrue, InputTextMultiline
|
||||
@@ -1216,6 +1255,7 @@ void RenderChatTab(App* app)
|
||||
: ImGuiInputTextFlags_None;
|
||||
const bool inputReturned = ImGui::InputTextMultiline("##compose", s_compose, sizeof(s_compose),
|
||||
ImVec2(inputW, composerBoxH), composeFlags);
|
||||
ImGui::PopStyleColor(3); // composer FrameBg (transparent — glass shows through)
|
||||
bool submit = enterSends && inputReturned; // off-mode sends only via the Send button
|
||||
// Send.
|
||||
ImGui::SetCursorScreenPos(ImVec2(sendX, rowY));
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
#include "console_command_executor.h"
|
||||
#include "console_channel.h"
|
||||
#include "console_command_reference.h" // consoleCommandCategories / liteConsoleCommandCategories
|
||||
#include "console_input_model.h" // BuildConsoleRpcCall
|
||||
|
||||
#include "../../app.h"
|
||||
@@ -194,6 +195,11 @@ void FullNodeConsoleExecutor::printHelp(const ConsoleAddLineFn& add)
|
||||
add(TR("console_tab_completion"), ConsoleChannel::Info);
|
||||
}
|
||||
|
||||
const std::vector<ConsoleCommandCategory>* FullNodeConsoleExecutor::commandReference() const
|
||||
{
|
||||
return &consoleCommandCategories();
|
||||
}
|
||||
|
||||
ConsoleStatusLine FullNodeConsoleExecutor::toolbarStatus() const
|
||||
{
|
||||
ConsoleStatusLine s;
|
||||
@@ -258,7 +264,7 @@ bool LiteConsoleExecutor::pollResult(std::string& result, bool& isError)
|
||||
if (!lw) return false;
|
||||
wallet::LiteConsoleResult res;
|
||||
if (!lw->takeConsoleResult(res)) return false;
|
||||
result = res.response.empty() ? std::string("(no output)") : res.response;
|
||||
result = res.response.empty() ? std::string(TR("console_no_output")) : res.response;
|
||||
isError = !res.ok;
|
||||
return true;
|
||||
}
|
||||
@@ -286,6 +292,19 @@ void LiteConsoleExecutor::printHelp(const ConsoleAddLineFn& add)
|
||||
add(TR("console_help_clear"), ConsoleChannel::None);
|
||||
add(TR("console_help_help"), ConsoleChannel::None);
|
||||
add(TR("lite_console_help_passthrough"), ConsoleChannel::Info);
|
||||
// The lite backend's own command verbs (literal command tokens, not RPC methods — mirrors the
|
||||
// backend's get_commands() registry). Listed for discoverability: the C++ tab intercepts `help`
|
||||
// before it can reach the backend's own HelpCommand, so its "type help" advice would dead-end.
|
||||
add(TR("lite_console_backend_commands"), ConsoleChannel::Info);
|
||||
add(" sync syncstatus balance addresses height info list notes encryptionstatus", ConsoleChannel::None);
|
||||
add(" send shield new seed import timport export", ConsoleChannel::None);
|
||||
add(" encrypt decrypt lock unlock rescan save sietch saplingtree coinsupply", ConsoleChannel::None);
|
||||
add(TR("console_click_commands"), ConsoleChannel::Info);
|
||||
}
|
||||
|
||||
const std::vector<ConsoleCommandCategory>* LiteConsoleExecutor::commandReference() const
|
||||
{
|
||||
return &liteConsoleCommandCategories();
|
||||
}
|
||||
|
||||
std::vector<ConsoleStatusLine> LiteConsoleExecutor::statusLines() const
|
||||
@@ -294,20 +313,20 @@ std::vector<ConsoleStatusLine> LiteConsoleExecutor::statusLines() const
|
||||
wallet::LiteWalletController* lw = app_->liteWallet();
|
||||
if (lw && lw->walletOpen()) {
|
||||
const SyncInfo& sync = app_->state().sync;
|
||||
char buf[96];
|
||||
char buf[128];
|
||||
if (sync.syncing && !sync.isSynced()) {
|
||||
double vp = sync.verification_progress;
|
||||
if (vp < 0.0) vp = 0.0; else if (vp > 1.0) vp = 1.0;
|
||||
std::snprintf(buf, sizeof(buf), "Syncing %.1f%% (block %d / %d)",
|
||||
vp * 100.0, sync.blocks, sync.headers);
|
||||
std::snprintf(buf, sizeof(buf), "%s %.1f%% (block %d / %d)",
|
||||
TR("lite_net_syncing"), vp * 100.0, sync.blocks, sync.headers);
|
||||
} else {
|
||||
std::snprintf(buf, sizeof(buf), "Synced (block %d)", sync.blocks);
|
||||
std::snprintf(buf, sizeof(buf), "%s (block %d)", TR("lite_net_synced"), sync.blocks);
|
||||
}
|
||||
out.push_back({std::string(buf), OnSurfaceMedium(), false});
|
||||
}
|
||||
const std::string& err = app_->liteOpenError();
|
||||
if (!err.empty() && (!lw || !lw->walletOpen()))
|
||||
out.push_back({std::string("Last error: ") + err, Error(), false});
|
||||
out.push_back({std::string(TR("console_last_error")) + " " + err, Error(), false});
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -315,10 +334,10 @@ ConsoleStatusLine LiteConsoleExecutor::toolbarStatus() const
|
||||
{
|
||||
ConsoleStatusLine s;
|
||||
wallet::LiteWalletController* lw = app_->liteWallet();
|
||||
if (!lw) { s.text = "No backend"; s.color = Error(); return s; }
|
||||
if (lw->walletOpen()) { s.text = "Connected"; s.color = Success(); }
|
||||
else if (lw->openInProgress()) { s.text = "Connecting"; s.color = Warning(); s.pulse = true; }
|
||||
else { s.text = "Disconnected"; s.color = Error(); }
|
||||
if (!lw) { s.text = TR("console_backend_unavailable"); s.color = Error(); return s; }
|
||||
if (lw->walletOpen()) { s.text = TR("lite_net_connected"); s.color = Success(); }
|
||||
else if (lw->openInProgress()) { s.text = TR("lite_net_connecting"); s.color = Warning(); s.pulse = true; }
|
||||
else { s.text = TR("lite_net_disconnected"); s.color = Error(); }
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,8 @@ namespace dragonx {
|
||||
class App;
|
||||
namespace ui {
|
||||
|
||||
struct ConsoleCommandCategory; // console_command_reference.h — command-reference table
|
||||
|
||||
using ConsoleAddLineFn = std::function<void(const std::string&, ConsoleChannel)>;
|
||||
|
||||
struct ConsoleStatusLine {
|
||||
@@ -64,7 +66,13 @@ public:
|
||||
virtual void pollLogLines(const ConsoleAddLineFn& add) { (void)add; }
|
||||
|
||||
// UI-chrome capabilities.
|
||||
virtual bool hasRpcReference() const { return false; } // show the RPC command-reference popup
|
||||
// True when this backend speaks JSON-RPC to a daemon (the full node). Gates daemon-specific
|
||||
// console behavior (the 'stop' shutdown confirm, "not connected to daemon" wording) and the
|
||||
// command-reference modal's JSON string-arg quoting — the lite backend takes bare tokens.
|
||||
virtual bool hasRpcReference() const { return false; }
|
||||
// The command-reference table this backend offers (browsed by the console's reference modal),
|
||||
// or nullptr for none. Full node = the JSON-RPC reference; lite = its own backend verbs.
|
||||
virtual const std::vector<ConsoleCommandCategory>* commandReference() const { return nullptr; }
|
||||
// Which log-filter toggles the toolbar should show (default: none).
|
||||
virtual ConsoleLogFilterCaps logFilterCaps() const { return {}; }
|
||||
|
||||
@@ -88,6 +96,7 @@ public:
|
||||
bool pollResult(std::string& result, bool& isError) override;
|
||||
void pollLogLines(const ConsoleAddLineFn& add) override;
|
||||
bool hasRpcReference() const override { return true; }
|
||||
const std::vector<ConsoleCommandCategory>* commandReference() const override;
|
||||
// Full node: daemon/xmrig log, errors-only, RPC trace, and app messages.
|
||||
ConsoleLogFilterCaps logFilterCaps() const override { return {true, true, true, true}; }
|
||||
void printHelp(const ConsoleAddLineFn& add) override;
|
||||
@@ -119,6 +128,7 @@ public:
|
||||
// Lite: no daemon log / RPC trace — its diagnostics ring maps to the App + Error
|
||||
// channels, so offer errors-only + app-messages (plus the always-shown text filter).
|
||||
ConsoleLogFilterCaps logFilterCaps() const override { return {false, true, false, true}; }
|
||||
const std::vector<ConsoleCommandCategory>* commandReference() const override;
|
||||
void printHelp(const ConsoleAddLineFn& add) override;
|
||||
std::vector<ConsoleStatusLine> statusLines() const override;
|
||||
ConsoleStatusLine toolbarStatus() const override;
|
||||
|
||||
@@ -280,6 +280,105 @@ const ConsoleCommandEntry kUtilityCommands[] = {
|
||||
"reconsiderblock \"0000000000abc123\"", "undo invalidate accept block again re-enable block restore chain reconsider fix rollback fork", true},
|
||||
};
|
||||
|
||||
// ============================================================================
|
||||
// Lite backend command set — the verbs the SDXL lite backend accepts (see its
|
||||
// commands.rs get_commands()). Unlike the full node these are NOT JSON-RPC: the
|
||||
// backend takes plain, space-separated tokens (no quoting), so the reference
|
||||
// modal inserts them bare. clear/help/quit are intentionally omitted — the C++
|
||||
// console tab intercepts those before they reach the backend.
|
||||
// ============================================================================
|
||||
|
||||
const ConsoleCommandEntry kLiteWalletCommands[] = {
|
||||
{"balance", "Show your DRGX balance", "",
|
||||
"Shows the DRGX balance held in this wallet across all its shielded and transparent addresses.",
|
||||
"balance", "money funds amount total holdings"},
|
||||
{"addresses", "List all addresses in the wallet", "",
|
||||
"Lists every address this wallet owns \xE2\x80\x94 shielded (zs1...) and transparent (R.../t...) \xE2\x80\x94 so you can pick one to receive to.",
|
||||
"addresses", "receive address list wallet mine deposit"},
|
||||
{"new", "Create a new address in this wallet", "type",
|
||||
"Creates a fresh receive address. Pass zs for a shielded (private) sapling address, or R (a capital R) for a transparent one \xE2\x80\x94 those exact tokens (case-sensitive).",
|
||||
"new zs", "create address receive generate new shielded transparent zs"},
|
||||
{"list", "List all transactions in the wallet", "",
|
||||
"Shows the wallet's transaction history \xE2\x80\x94 sends, receives and shields \xE2\x80\x94 with amounts, addresses and confirmations.",
|
||||
"list", "history transactions txs payments activity sent received"},
|
||||
{"notes", "List sapling notes and UTXOs", "[all]",
|
||||
"Lists the individual shielded notes and transparent UTXOs that make up your balance. Pass all to include spent ones.",
|
||||
"notes", "utxo notes unspent coins inputs sapling"},
|
||||
{"info", "Get the lightwalletd server's info", "",
|
||||
"Reports the lightwalletd server the wallet is connected to \xE2\x80\x94 its version, chain and block height.",
|
||||
"info", "server node lightwalletd version connection status"},
|
||||
};
|
||||
|
||||
const ConsoleCommandEntry kLiteSyncCommands[] = {
|
||||
{"sync", "Download compact blocks and sync to the server", "",
|
||||
"Fetches new compact blocks from the lightwalletd server and scans them for transactions belonging to this wallet.",
|
||||
"sync", "update refresh scan blocks download catch up"},
|
||||
{"syncstatus", "Get the sync status of the wallet", "",
|
||||
"Reports how far the wallet has synced \xE2\x80\x94 whether a sync is in progress and the block it has reached.",
|
||||
"syncstatus", "progress status syncing scanning percent blocks"},
|
||||
{"height", "Get the latest block height the wallet is at", "",
|
||||
"Shows the block height the wallet has scanned up to. Compare with the network height to gauge sync.",
|
||||
"height", "block height number chain tip synced"},
|
||||
{"rescan", "Rescan the wallet from scratch", "",
|
||||
"Discards the scanned state and re-downloads/re-scans every block from the wallet's birthday. Slow, but fixes a stuck or incomplete balance.",
|
||||
"rescan", "rescan resync repair fix balance rebuild from scratch"},
|
||||
{"save", "Save the wallet file to disk", "",
|
||||
"Writes the current wallet state to disk. The wallet also saves automatically after a sync or send.",
|
||||
"save", "save persist write disk store"},
|
||||
};
|
||||
|
||||
const ConsoleCommandEntry kLiteSendCommands[] = {
|
||||
{"send", "Send DRGX to an address", "[{\"address\":\"zs1...\",\"amount\":0}]",
|
||||
"Sends DRGX from the console using a JSON array of recipients (the Send tab is the easy way; this is the power-user form). amount is in puposhis (the base unit); memo is optional and delivered privately to shielded recipients.",
|
||||
"send [{\"address\":\"zs1exampleaddress\",\"amount\":100000000,\"memo\":\"thanks\"}]",
|
||||
"pay transfer send spend money transaction json", true},
|
||||
{"shield", "Shield transparent DRGX into a sapling address", "[address]",
|
||||
"Moves your transparent (public) DRGX into a shielded sapling address for privacy. With no address it shields to the wallet's own sapling address.",
|
||||
"shield", "shield private sapling transparent move protect", true},
|
||||
};
|
||||
|
||||
const ConsoleCommandEntry kLiteKeyCommands[] = {
|
||||
{"seed", "Display the wallet seed phrase", "",
|
||||
"Reveals the seed phrase that backs up this wallet. Anyone who sees it can spend your funds \xE2\x80\x94 keep it secret and offline.",
|
||||
"seed", "seed phrase mnemonic backup recovery words secret", true},
|
||||
{"export", "Export the private key for an address", "[address]",
|
||||
"Prints the private/spending key for a wallet address \xE2\x80\x94 anyone with it controls the funds. With no address it exports every key.",
|
||||
"export zs1exampleaddress", "export private key spending backup secret", true},
|
||||
{"import", "Import a spending or viewing key", "key",
|
||||
"Imports a shielded spending or viewing key (pass just the key). The wallet rescans from the sapling activation height to find the key's transactions.",
|
||||
"import somekey", "import restore key spending viewing add watch"},
|
||||
{"timport", "Import a transparent WIF private key", "wif",
|
||||
"Imports a transparent private key in WIF format (begins with U, 5, K or L) so the wallet can spend its funds.",
|
||||
"timport somewifkey", "import transparent wif private key taddr"},
|
||||
{"encrypt", "Encrypt the wallet with a password", "password",
|
||||
"Encrypts the wallet with a password and locks it immediately. You will need the password to send or reveal keys afterwards. If you forget it, only the seed phrase can recover the wallet.",
|
||||
"encrypt strongpassword", "encrypt password protect lock secure passphrase", true},
|
||||
{"decrypt", "Completely remove wallet encryption", "password",
|
||||
"Permanently removes the wallet's password encryption, leaving it unprotected on disk. Requires the current password.",
|
||||
"decrypt strongpassword", "decrypt remove encryption password unprotect", true},
|
||||
{"unlock", "Unlock the wallet for spending", "password",
|
||||
"Temporarily unlocks an encrypted wallet so it can send or reveal keys. Use lock to re-lock it.",
|
||||
"unlock strongpassword", "unlock password spend open temporarily"},
|
||||
{"lock", "Lock a temporarily-unlocked wallet", "",
|
||||
"Re-locks a wallet that was unlocked for spending, without removing its encryption.",
|
||||
"lock", "lock secure re-lock protect close"},
|
||||
{"encryptionstatus", "Check if the wallet is encrypted and locked", "",
|
||||
"Reports whether the wallet is encrypted and, if so, whether it is currently locked or unlocked.",
|
||||
"encryptionstatus", "encryption status locked unlocked encrypted state"},
|
||||
};
|
||||
|
||||
const ConsoleCommandEntry kLiteAdvancedCommands[] = {
|
||||
{"sietch", "Create a Sietch address", "[type]",
|
||||
"Creates a Sietch address, used for enhanced-privacy sends. Pass zs for a sapling Sietch address.",
|
||||
"sietch zs", "sietch privacy address decoy sapling advanced"},
|
||||
{"saplingtree", "Dump the latest Sapling commitment tree (debug)", "",
|
||||
"Prints the latest Sapling commitment tree state \xE2\x80\x94 a debugging aid, not needed for everyday use.",
|
||||
"saplingtree", "sapling tree commitment debug advanced merkle"},
|
||||
{"coinsupply", "Get the coin supply info", "",
|
||||
"Reports coin-supply figures for the chain as seen by the wallet's server.",
|
||||
"coinsupply", "supply coins total emission circulating amount"},
|
||||
};
|
||||
|
||||
} // namespace
|
||||
|
||||
const std::vector<ConsoleCommandCategory>& consoleCommandCategories()
|
||||
@@ -296,5 +395,17 @@ const std::vector<ConsoleCommandCategory>& consoleCommandCategories()
|
||||
return categories;
|
||||
}
|
||||
|
||||
const std::vector<ConsoleCommandCategory>& liteConsoleCommandCategories()
|
||||
{
|
||||
static const std::vector<ConsoleCommandCategory> categories = {
|
||||
{"Wallet", kLiteWalletCommands, CountOf(kLiteWalletCommands)},
|
||||
{"Sync", kLiteSyncCommands, CountOf(kLiteSyncCommands)},
|
||||
{"Send", kLiteSendCommands, CountOf(kLiteSendCommands)},
|
||||
{"Keys & Security", kLiteKeyCommands, CountOf(kLiteKeyCommands)},
|
||||
{"Advanced", kLiteAdvancedCommands, CountOf(kLiteAdvancedCommands)},
|
||||
};
|
||||
return categories;
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
} // namespace dragonx
|
||||
|
||||
@@ -23,7 +23,12 @@ struct ConsoleCommandCategory {
|
||||
int count;
|
||||
};
|
||||
|
||||
// The full-node daemon's JSON-RPC command reference (browsed by the console's command-reference modal).
|
||||
const std::vector<ConsoleCommandCategory>& consoleCommandCategories();
|
||||
|
||||
// The lite backend's own command set (the ~25 verbs the SDXL backend accepts) — the lite-variant
|
||||
// analog of the RPC reference, shown by the same modal when the executor is the lite one.
|
||||
const std::vector<ConsoleCommandCategory>& liteConsoleCommandCategories();
|
||||
|
||||
} // namespace ui
|
||||
} // namespace dragonx
|
||||
|
||||
@@ -464,12 +464,18 @@ void ConsoleTab::render(ConsoleCommandExecutor& exec)
|
||||
ImGui::EndChild();
|
||||
}
|
||||
|
||||
void ConsoleTab::renderCommandsPopupModal()
|
||||
void ConsoleTab::renderCommandsPopupModal(ConsoleCommandExecutor* exec)
|
||||
{
|
||||
if (!show_commands_popup_) {
|
||||
return;
|
||||
}
|
||||
renderCommandsPopup();
|
||||
// Need a backend that offers a reference table. If the console hasn't built its executor yet
|
||||
// (popup can't have been opened normally) or the backend has none, just dismiss.
|
||||
if (!exec || !exec->commandReference()) {
|
||||
show_commands_popup_ = false;
|
||||
return;
|
||||
}
|
||||
renderCommandsPopup(*exec);
|
||||
}
|
||||
|
||||
void ConsoleTab::renderToolbar(ConsoleCommandExecutor& exec)
|
||||
@@ -544,14 +550,16 @@ void ConsoleTab::renderToolbar(ConsoleCommandExecutor& exec)
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
// Commands reference button (full-node RPC reference only)
|
||||
if (exec.hasRpcReference()) {
|
||||
// Commands reference button — shown whenever the backend offers a reference table (full-node
|
||||
// JSON-RPC commands, or the lite backend's own verbs).
|
||||
if (exec.commandReference()) {
|
||||
if (TactileButton(TR("console_commands"), ImVec2(0, 0), schema::UI().resolveFont("button"))) {
|
||||
command_search_[0] = '\0'; // fresh search each open (dismiss paths don't all reset it)
|
||||
show_commands_popup_ = true;
|
||||
}
|
||||
if (ImGui::IsItemHovered()) {
|
||||
material::Tooltip("%s", TR("console_show_rpc_ref"));
|
||||
material::Tooltip("%s", exec.hasRpcReference() ? TR("console_show_rpc_ref")
|
||||
: TR("console_show_backend_ref"));
|
||||
}
|
||||
ImGui::SameLine();
|
||||
}
|
||||
@@ -611,7 +619,7 @@ void ConsoleTab::drawToolbarStatus(ConsoleCommandExecutor& exec)
|
||||
ImVec2 cp = ImGui::GetCursorScreenPos();
|
||||
float dotR = schema::UI().drawElement("tabs.console", "status-dot-radius-base").size + schema::UI().drawElement("tabs.console", "status-dot-radius-scale").size * Layout::hScale();
|
||||
float dotY = cp.y + ImGui::GetTextLineHeight() * 0.5f;
|
||||
float dotX = cp.x + dotR + 2;
|
||||
float dotX = cp.x + dotR + 2.0f * Layout::dpiScale();
|
||||
|
||||
if (st.pulse) {
|
||||
float a = schema::UI().drawElement("animations", "pulse-base-glow").size + schema::UI().drawElement("animations", "pulse-amp-glow").size * (float)std::sin((double)ImGui::GetTime() * schema::UI().drawElement("animations", "pulse-speed-fast").size);
|
||||
@@ -621,7 +629,7 @@ void ConsoleTab::drawToolbarStatus(ConsoleCommandExecutor& exec)
|
||||
dl->AddCircleFilled(ImVec2(dotX, dotY), dotR, st.color);
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2(dotR * 2 + 6, 0));
|
||||
ImGui::Dummy(ImVec2(dotR * 2 + 6.0f * Layout::dpiScale(), 0));
|
||||
ImGui::SameLine();
|
||||
Type().textColored(TypeStyle::Caption, st.color, st.text.c_str());
|
||||
} else {
|
||||
@@ -1434,18 +1442,22 @@ bool ConsoleTab::submitConsoleCommand(ConsoleCommandExecutor& exec, const std::s
|
||||
exec.printHelp(add);
|
||||
} else if (first == "quit" || first == "exit") {
|
||||
addLine(TR("console_quit_note"), ConsoleChannel::Info);
|
||||
} else if (first == "stop") {
|
||||
} else if (first == "stop" && exec.hasRpcReference()) {
|
||||
// Full-node 'stop' shuts down the daemon (destructive) — gate behind a confirming second
|
||||
// 'stop'. Lite has no node: `stop` isn't a backend verb, so it falls through below and the
|
||||
// backend reports it as unknown — no misleading "shut down the node" warning or dead gate.
|
||||
if (!stop_confirm_pending_) {
|
||||
stop_confirm_pending_ = true;
|
||||
addLine("'stop' will shut down the node and disconnect the wallet. Type 'stop' again to confirm.",
|
||||
ConsoleChannel::Warning);
|
||||
addLine(TR("console_stop_confirm_node"), ConsoleChannel::Warning);
|
||||
} else {
|
||||
stop_confirm_pending_ = false;
|
||||
if (!exec.isReady()) addLine(TR("console_not_connected"), ConsoleChannel::Error);
|
||||
else exec.submit(cmd);
|
||||
}
|
||||
} else if (!exec.isReady()) {
|
||||
addLine(TR("console_not_connected"), ConsoleChannel::Error);
|
||||
// Full node connects to a daemon; the lite backend opens a wallet — word the error per variant.
|
||||
addLine(exec.hasRpcReference() ? TR("console_not_connected") : TR("console_not_connected_lite"),
|
||||
ConsoleChannel::Error);
|
||||
} else {
|
||||
exec.submit(cmd);
|
||||
}
|
||||
@@ -1557,6 +1569,11 @@ const char* consoleCategoryLabel(const char* name)
|
||||
if (!std::strcmp(name, "Wallet")) return TR("console_cat_wallet");
|
||||
if (!std::strcmp(name, "Raw Transactions")) return TR("console_cat_raw_transactions");
|
||||
if (!std::strcmp(name, "Utility")) return TR("console_cat_utility");
|
||||
// Lite backend reference categories.
|
||||
if (!std::strcmp(name, "Sync")) return TR("console_cat_sync");
|
||||
if (!std::strcmp(name, "Send")) return TR("console_cat_send");
|
||||
if (!std::strcmp(name, "Keys & Security")) return TR("console_cat_keys");
|
||||
if (!std::strcmp(name, "Advanced")) return TR("console_cat_advanced");
|
||||
return name;
|
||||
}
|
||||
} // namespace
|
||||
@@ -1576,7 +1593,7 @@ void ConsoleTab::insertCommandToInput(const ConsoleCommandEntry& cmd)
|
||||
show_commands_popup_ = false;
|
||||
}
|
||||
|
||||
void ConsoleTab::renderCommandDetail(const ConsoleCommandEntry& cmd, const char* catLabel)
|
||||
void ConsoleTab::renderCommandDetail(const ConsoleCommandEntry& cmd, const char* catLabel, bool jsonArgs)
|
||||
{
|
||||
using namespace material;
|
||||
float dp = Layout::dpiScale();
|
||||
@@ -1627,8 +1644,11 @@ void ConsoleTab::renderCommandDetail(const ConsoleCommandEntry& cmd, const char*
|
||||
ImGui::PopFont();
|
||||
ImGui::SameLine(labelW);
|
||||
ImGui::SetNextItemWidth(-1);
|
||||
// Lite backend args are bare freeform tokens, so its param types (string/number) don't
|
||||
// apply — show a neutral "value" hint there instead of a misleading "number".
|
||||
std::string typeHint = jsonArgs ? s.type : std::string(TR("console_ref_value"));
|
||||
std::string hint = s.optional
|
||||
? (s.type + " \xC2\xB7 " + std::string(TR("console_ref_optional"))) : s.type;
|
||||
? (typeHint + " \xC2\xB7 " + std::string(TR("console_ref_optional"))) : typeHint;
|
||||
ImGui::InputTextWithHint("##pv", hint.c_str(), cmd_param_bufs_[k], sizeof(cmd_param_bufs_[k]));
|
||||
ImGui::PopID();
|
||||
}
|
||||
@@ -1658,7 +1678,9 @@ void ConsoleTab::renderCommandDetail(const ConsoleCommandEntry& cmd, const char*
|
||||
built += " " + specs[k].raw;
|
||||
complete = false;
|
||||
} else {
|
||||
if (specs[k].type == "string" && val.front() != '"' && val.front() != '\'' &&
|
||||
// JSON-RPC (full node) auto-quotes string args; the lite backend takes bare tokens, so
|
||||
// leave the value exactly as typed there (quoting would break its address/key parsing).
|
||||
if (jsonArgs && specs[k].type == "string" && val.front() != '"' && val.front() != '\'' &&
|
||||
val.front() != '[' && val.front() != '{')
|
||||
val = "\"" + val + "\"";
|
||||
built += " " + val;
|
||||
@@ -1731,13 +1753,16 @@ void ConsoleTab::renderCommandDetail(const ConsoleCommandEntry& cmd, const char*
|
||||
}
|
||||
}
|
||||
|
||||
void ConsoleTab::renderCommandsPopup()
|
||||
void ConsoleTab::renderCommandsPopup(ConsoleCommandExecutor& exec)
|
||||
{
|
||||
using namespace material;
|
||||
float dp = Layout::dpiScale();
|
||||
|
||||
// Full node speaks JSON-RPC (quote string args); the lite backend takes bare tokens.
|
||||
const bool jsonArgs = exec.hasRpcReference();
|
||||
|
||||
material::OverlayDialogSpec ov;
|
||||
ov.title = TR("console_rpc_reference");
|
||||
ov.title = jsonArgs ? TR("console_rpc_reference") : TR("console_backend_reference");
|
||||
ov.p_open = &show_commands_popup_;
|
||||
ov.style = material::OverlayStyle::BlurFloat; // floating content on the blur, plain heading
|
||||
ov.cardWidth = 960.0f; // wide enough for two panes
|
||||
@@ -1766,7 +1791,7 @@ void ConsoleTab::renderCommandsPopup()
|
||||
std::transform(q.begin(), q.end(), q.begin(), ::tolower);
|
||||
const bool searching = !q.empty();
|
||||
|
||||
const auto& categories = consoleCommandCategories();
|
||||
const auto& categories = *exec.commandReference(); // non-null: guarded by renderCommandsPopupModal
|
||||
|
||||
// Flat display order of (cat,idx): ranked when searching, category order when browsing. Drives
|
||||
// keyboard nav + auto-selection; the browse view still renders grouped headers below.
|
||||
@@ -1908,7 +1933,7 @@ void ConsoleTab::renderCommandsPopup()
|
||||
if (cmd_sel_cat_ >= 0 && cmd_sel_cat_ < (int)categories.size() &&
|
||||
cmd_sel_idx_ >= 0 && cmd_sel_idx_ < categories[cmd_sel_cat_].count) {
|
||||
renderCommandDetail(categories[cmd_sel_cat_].commands[cmd_sel_idx_],
|
||||
consoleCategoryLabel(categories[cmd_sel_cat_].name));
|
||||
consoleCategoryLabel(categories[cmd_sel_cat_].name), jsonArgs);
|
||||
} else {
|
||||
ImVec2 av = ImGui::GetContentRegionAvail();
|
||||
ImGui::SetCursorPosY(av.y * 0.4f);
|
||||
|
||||
@@ -44,10 +44,11 @@ public:
|
||||
void render(ConsoleCommandExecutor& exec);
|
||||
|
||||
/**
|
||||
* @brief Render the RPC Command Reference popup at top-level scope.
|
||||
* Must be called outside any child window so the modal blocks all input.
|
||||
* @brief Render the command-reference popup at top-level scope.
|
||||
* Must be called outside any child window so the modal blocks all input. `exec` supplies the
|
||||
* reference table (full-node RPC vs lite backend verbs); may be null (no console yet) -> no-op.
|
||||
*/
|
||||
void renderCommandsPopupModal();
|
||||
void renderCommandsPopupModal(ConsoleCommandExecutor* exec);
|
||||
|
||||
// Debug/UI-sweep hook: force the RPC command-reference popup open/closed so the full UI sweep
|
||||
// can capture it (the popup is otherwise opened only by a toolbar button).
|
||||
@@ -115,8 +116,9 @@ private:
|
||||
// Format a completed command result (JSON role -> channel) into console lines.
|
||||
void addFormattedResult(const std::string& result, bool is_error);
|
||||
void renderStatusHeader(ConsoleCommandExecutor& exec);
|
||||
void renderCommandsPopup();
|
||||
void renderCommandDetail(const ConsoleCommandEntry& cmd, const char* catLabel); // right pane
|
||||
void renderCommandsPopup(ConsoleCommandExecutor& exec);
|
||||
// right pane; jsonArgs=true (full-node RPC) auto-quotes string args, false (lite) inserts bare
|
||||
void renderCommandDetail(const ConsoleCommandEntry& cmd, const char* catLabel, bool jsonArgs);
|
||||
void insertCommandToInput(const ConsoleCommandEntry& cmd); // fill input + close the modal
|
||||
|
||||
// renderToolbar() draws the top bar; these are its sub-steps:
|
||||
@@ -186,10 +188,11 @@ private:
|
||||
// consumed by the renderer + hit-testing.
|
||||
mutable ConsoleLayout layout_;
|
||||
|
||||
// Commands popup (RPC command explorer)
|
||||
// Commands popup (command explorer) — indexes into the active executor's commandReference()
|
||||
// table (full-node RPC commands or the lite backend verbs), not always the full-node one.
|
||||
bool show_commands_popup_ = false;
|
||||
char command_search_[128] = {0}; // RPC-reference search filter (cleared when the modal opens)
|
||||
int cmd_sel_cat_ = -1; // detail-pane selection: category index into consoleCommandCategories()
|
||||
char command_search_[128] = {0}; // reference search filter (cleared when the modal opens)
|
||||
int cmd_sel_cat_ = -1; // detail-pane selection: category index into that table
|
||||
int cmd_sel_idx_ = -1; // detail-pane selection: command index within that category
|
||||
std::string pending_submit_; // command to run next frame (deferred so the modal needs no executor)
|
||||
const ConsoleCommandEntry* run_confirm_cmd_ = nullptr; // destructive "Insert & run" awaiting confirmation
|
||||
|
||||
@@ -1005,9 +1005,23 @@ void RenderContactsTab(App* app)
|
||||
|
||||
if (viewMode == 2) {
|
||||
// ── TABLE mode (material-ized): no outer/grid borders, row backgrounds, interactive sort. ──
|
||||
// Frosted-glass panel behind the table so it blurs the backdrop like the card/list view (the
|
||||
// table's translucent row backgrounds let the blur show through). A BeginTable can't take
|
||||
// AlwaysUseWindowPadding, so inset the table itself inside the glass so its headers/cells
|
||||
// don't hug the container edges.
|
||||
ImDrawList* tpdl = ImGui::GetWindowDrawList();
|
||||
const ImVec2 tpMin = ImGui::GetCursorScreenPos();
|
||||
const float tpW = ImGui::GetContentRegionAvail().x;
|
||||
const float tIpad = 12.0f * dp, tVpad = 10.0f * dp;
|
||||
{
|
||||
material::GlassPanelSpec g; g.rounding = 12.0f * dp; g.fillAlpha = 14; g.borderAlpha = 34;
|
||||
material::DrawGlassPanel(tpdl, tpMin, ImVec2(tpMin.x + tpW, tpMin.y + listH), g);
|
||||
}
|
||||
ImGui::SetCursorScreenPos(ImVec2(tpMin.x + tIpad, tpMin.y + tVpad));
|
||||
if (ImGui::BeginTable("AddressBookTable", 3,
|
||||
ImGuiTableFlags_RowBg | ImGuiTableFlags_Sortable |
|
||||
ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY, ImVec2(0, listH)))
|
||||
ImGuiTableFlags_Resizable | ImGuiTableFlags_ScrollY,
|
||||
ImVec2(tpW - 2.0f * tIpad, listH - 2.0f * tVpad)))
|
||||
{
|
||||
ImGui::TableSetupColumn(TR("label"), ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_DefaultSort, 1.5f);
|
||||
ImGui::TableSetupColumn(TR("address_label"), ImGuiTableColumnFlags_WidthStretch, 2.6f);
|
||||
@@ -1093,8 +1107,20 @@ void RenderContactsTab(App* app)
|
||||
return toLower(entries[a].label).compare(toLower(entries[b].label)) < 0;
|
||||
});
|
||||
}
|
||||
// Frosted-glass list container so the contacts area blurs the backdrop (peers_tab pattern:
|
||||
// glass behind a NoBackground list child) instead of showing the raw texture through the pane.
|
||||
{
|
||||
ImDrawList* pdl = ImGui::GetWindowDrawList();
|
||||
const ImVec2 pMin = ImGui::GetCursorScreenPos();
|
||||
const float pW = ImGui::GetContentRegionAvail().x;
|
||||
material::GlassPanelSpec g; g.rounding = 12.0f * dp; g.fillAlpha = 14; g.borderAlpha = 34;
|
||||
material::DrawGlassPanel(pdl, pMin, ImVec2(pMin.x + pW, pMin.y + listH), g);
|
||||
}
|
||||
// AlwaysUseWindowPadding: a borderless child ignores WindowPadding without it, so the rows
|
||||
// would hug the frosted container's edges.
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(12.0f * dp, 10.0f * dp));
|
||||
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0,0,0,0));
|
||||
ImGui::BeginChild("##contactList", ImVec2(0, listH), false,
|
||||
ImGui::BeginChild("##contactList", ImVec2(0, listH), ImGuiChildFlags_AlwaysUseWindowPadding,
|
||||
ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoScrollWithMouse);
|
||||
material::ApplySmoothScroll(); // wheel-lerp scroll, matching the rest of the app
|
||||
if (visibleRows.empty()) {
|
||||
@@ -1243,6 +1269,7 @@ void RenderContactsTab(App* app)
|
||||
}
|
||||
ImGui::EndChild();
|
||||
ImGui::PopStyleColor();
|
||||
ImGui::PopStyleVar(); // ##contactList inner WindowPadding
|
||||
}
|
||||
|
||||
// Shared right-click context menu (opened by either view's row right-click; acts on the selection).
|
||||
|
||||
@@ -1395,6 +1395,12 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["console_available_commands"] = "Available commands:";
|
||||
strings_["console_quit_note"] = "'quit'/'exit' aren't needed here — just close the window.";
|
||||
strings_["lite_console_help_passthrough"] = "Any other input runs as a lite-wallet console command.";
|
||||
strings_["lite_console_backend_commands"] = "Backend commands:";
|
||||
strings_["console_no_output"] = "(no output)";
|
||||
strings_["console_backend_unavailable"] = "No backend";
|
||||
strings_["console_last_error"] = "Last error:";
|
||||
strings_["console_not_connected_lite"] = "Error: no wallet open";
|
||||
strings_["console_stop_confirm_node"] = "'stop' will shut down the node and disconnect the wallet. Type 'stop' again to confirm.";
|
||||
strings_["console_capturing_output"] = "Capturing daemon output...";
|
||||
strings_["console_clear"] = "Clear";
|
||||
strings_["console_clear_console"] = "Clear Console";
|
||||
@@ -1434,6 +1440,7 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["console_no_daemon"] = "No daemon";
|
||||
strings_["console_not_connected"] = "Error: Not connected to daemon";
|
||||
strings_["console_rpc_reference"] = "RPC Command Reference";
|
||||
strings_["console_backend_reference"] = "Backend Command Reference";
|
||||
strings_["console_rpc_trace"] = "RPC";
|
||||
strings_["console_app"] = "App";
|
||||
strings_["console_show_app_output"] = "Show [app] wallet log lines";
|
||||
@@ -1442,6 +1449,7 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["console_show_daemon_output"] = "Show daemon output";
|
||||
strings_["console_show_errors_only"] = "Show errors only";
|
||||
strings_["console_show_rpc_ref"] = "Show RPC command reference";
|
||||
strings_["console_show_backend_ref"] = "Show backend command reference";
|
||||
strings_["console_show_rpc_trace"] = "Show app RPC calls";
|
||||
strings_["console_showing_lines"] = "Showing %zu of %zu lines";
|
||||
strings_["console_starting_node"] = "Starting node...";
|
||||
@@ -1467,10 +1475,15 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["console_cat_wallet"] = "Wallet";
|
||||
strings_["console_cat_raw_transactions"] = "Raw Transactions";
|
||||
strings_["console_cat_utility"] = "Utility";
|
||||
strings_["console_cat_sync"] = "Sync";
|
||||
strings_["console_cat_send"] = "Send";
|
||||
strings_["console_cat_keys"] = "Keys & Security";
|
||||
strings_["console_cat_advanced"] = "Advanced";
|
||||
strings_["console_ref_search_hint"] = "Search by name or task\xE2\x80\xA6";
|
||||
strings_["console_ref_parameters"] = "Parameters";
|
||||
strings_["console_ref_no_params"] = "Takes no parameters.";
|
||||
strings_["console_ref_optional"] = "optional";
|
||||
strings_["console_ref_value"] = "value";
|
||||
strings_["console_ref_example"] = "Example";
|
||||
strings_["console_ref_builds"] = "Builds";
|
||||
strings_["console_ref_destructive"] = "Consequential";
|
||||
@@ -1854,6 +1867,7 @@ void I18n::loadBuiltinEnglish()
|
||||
strings_["lite_net_show_hidden"] = "Show hidden servers";
|
||||
strings_["lite_net_hidden_section"] = "Hidden servers";
|
||||
strings_["lite_net_connected"] = "Connected";
|
||||
strings_["lite_net_connecting"] = "Connecting";
|
||||
strings_["lite_net_disconnected"] = "Not connected";
|
||||
strings_["lite_net_syncing"] = "Syncing";
|
||||
strings_["lite_net_synced"] = "Synced";
|
||||
|
||||
@@ -57,7 +57,15 @@ void Logger::write(const std::string& message)
|
||||
now.time_since_epoch()) % 1000;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::put_time(std::localtime(&time), "%Y-%m-%d %H:%M:%S");
|
||||
// Reachable from worker/monitor threads — std::localtime shares a process-wide static tm, so use the
|
||||
// reentrant variant into a local tm (the logger's own mutex can't protect other localtime callers).
|
||||
std::tm tmv{};
|
||||
#ifdef _WIN32
|
||||
localtime_s(&tmv, &time);
|
||||
#else
|
||||
localtime_r(&time, &tmv);
|
||||
#endif
|
||||
ss << std::put_time(&tmv, "%Y-%m-%d %H:%M:%S");
|
||||
ss << '.' << std::setfill('0') << std::setw(3) << ms.count();
|
||||
ss << " | " << message;
|
||||
|
||||
|
||||
@@ -5300,8 +5300,11 @@ void testXmrigAssetSelection()
|
||||
EXPECT_TRUE(linux >= 0);
|
||||
EXPECT_TRUE(win >= 0);
|
||||
EXPECT_TRUE(linux != win);
|
||||
EXPECT_TRUE(rel.assets[linux].name.find("linux-x64.zip") != std::string::npos);
|
||||
EXPECT_TRUE(rel.assets[win].name.find("win-x64.zip") != std::string::npos);
|
||||
// Guard the index reads: select*Asset returns -1 when nothing matches, and EXPECT_TRUE doesn't
|
||||
// abort this harness, so an unguarded rel.assets[-1] on a fixture/parser regression would SIGSEGV
|
||||
// the whole suite instead of reporting the failed EXPECT above.
|
||||
if (linux >= 0) EXPECT_TRUE(rel.assets[linux].name.find("linux-x64.zip") != std::string::npos);
|
||||
if (win >= 0) EXPECT_TRUE(rel.assets[win].name.find("win-x64.zip") != std::string::npos);
|
||||
// No macOS build in this fixture -> graceful "not found".
|
||||
EXPECT_EQ(selectXmrigAsset(rel, "macos-x86_64"), -1);
|
||||
EXPECT_EQ(selectXmrigAsset(rel, "macos-arm64"), -1);
|
||||
@@ -5607,9 +5610,11 @@ void testDaemonAssetSelection()
|
||||
const int win = selectDaemonAsset(rel, "win64");
|
||||
EXPECT_TRUE(lin >= 0 && mac >= 0 && win >= 0);
|
||||
EXPECT_TRUE(lin != mac && mac != win && lin != win);
|
||||
EXPECT_TRUE(rel.assets[lin].name.find("linux-amd64.zip") != std::string::npos);
|
||||
EXPECT_TRUE(rel.assets[mac].name.find("macos.zip") != std::string::npos);
|
||||
EXPECT_TRUE(rel.assets[win].name.find("win64.zip") != std::string::npos);
|
||||
// Guard the index reads (select*Asset returns -1 on no match; EXPECT_TRUE doesn't abort here) so a
|
||||
// fixture/parser regression reports the failed EXPECT above instead of an OOB rel.assets[-1] crash.
|
||||
if (lin >= 0) EXPECT_TRUE(rel.assets[lin].name.find("linux-amd64.zip") != std::string::npos);
|
||||
if (mac >= 0) EXPECT_TRUE(rel.assets[mac].name.find("macos.zip") != std::string::npos);
|
||||
if (win >= 0) EXPECT_TRUE(rel.assets[win].name.find("win64.zip") != std::string::npos);
|
||||
// Wrong/foreign tokens (e.g. the miner's naming) must NOT match the daemon archives.
|
||||
EXPECT_EQ(selectDaemonAsset(rel, "linux-x64"), -1);
|
||||
EXPECT_EQ(selectDaemonAsset(rel, "linux-arm64"), -1);
|
||||
@@ -6357,8 +6362,11 @@ void testAddressBookScope()
|
||||
fs::create_directories(tmp);
|
||||
setenv("HOME", tmp.string().c_str(), 1);
|
||||
|
||||
// A pre-scoping addressbook.json (no "scope" field) migrates to global on load.
|
||||
fs::path cfg = tmp / ".config" / "ObsidianDragon";
|
||||
// A pre-scoping addressbook.json (no "scope" field) migrates to global on load. Write to the
|
||||
// SAME per-variant config dir AddressBook::load() reads from (Lite -> ObsidianDragonLite/),
|
||||
// resolved under the temp HOME set above. Hardcoding ".config/ObsidianDragon" made the lite-build
|
||||
// ctest write where load() never looks -> 0 entries -> the entries()[0] below segfaulted.
|
||||
fs::path cfg = dragonx::util::Platform::getConfigDir();
|
||||
fs::create_directories(cfg);
|
||||
std::ofstream(cfg / "addressbook.json")
|
||||
<< R"({"entries":[{"label":"Legacy","address":"zs1legacy","notes":""}]})";
|
||||
@@ -6366,7 +6374,9 @@ void testAddressBookScope()
|
||||
AddressBook book;
|
||||
EXPECT_TRUE(book.load());
|
||||
EXPECT_EQ(book.size(), (size_t)1);
|
||||
EXPECT_TRUE(book.entries()[0].isGlobal()); // migrated -> global
|
||||
// Guard the [0] access — EXPECT_EQ doesn't abort this harness, so an empty book here must not
|
||||
// SIGSEGV the whole suite (it would take every later test down with it).
|
||||
EXPECT_TRUE(!book.entries().empty() && book.entries()[0].isGlobal()); // migrated -> global
|
||||
}
|
||||
|
||||
// Same address may be a contact in two DIFFERENT wallets, but not twice in one; and a global
|
||||
|
||||
Reference in New Issue
Block a user