Commit graph

127 commits

Author SHA1 Message Date
jima
7b68e6404b Audit 2026-04-12: C++ hardening, crash fix, dead code, quality
Fifth full codebase audit across all five modules (lib-ssh, lib-terminal-view,
lib-terminal-keyboard, lib-vault-crypto, app).

Security:
- Added cppFlags to lib-vault-crypto build — vault_crypto.cpp JNI bridge was
  missing all compiler hardening flags (-fstack-protector-strong, -D_FORTIFY_SOURCE=2)

Bugs fixed:
- SessionNotifier crash: first{} → firstOrNull to prevent NoSuchElementException
- Keyboard modifiers not consumed on SwitchPage/ToggleNumBlock — armed CTRL/ALT
  would persist and incorrectly modify the next key press
- KeyManagerViewModel silent exception swallow — now logs errors via FileLogger
- TelnetSession.sendTerminalType() variable shadowing fix

Dead code removed:
- Vt100Parser empty class (Vt220Parser now extends BaseTermParser directly)
- XtermParser.sendPrimaryDA() redundant override (identical to parent)
- TerminalKeyboard dead fields: menuPopupActive, menuPopupItems, miniContainer
- SpecialAction.SETTINGS_OPENED never emitted
- Deprecated 3-arg saveHostKeyFingerprint overload (no callers)

Code quality:
- Color(0xFF6E7979) → AppColors.Muted in ConnectionListScreen
- Hardcoded "v1.0.0" → BuildConfig.VERSION_NAME in SettingsScreen
- SubscriptionScreen back button contentDescription for accessibility
- TAG → companion const val in StartupCommandRunner, PortForwardManager, SftpSessionManager
- TerminalRenderer swapped KDoc comments fixed

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 15:09:05 +02:00
jima
56b875b9fc Web platform scaffold, applicationId change to com.roundingmobile.sshwb
ApplicationId changed from com.roundingmobile.sshworkbench to
com.roundingmobile.sshwb (Firebase auto-key blocked Play Console
registration). Namespace stays com.roundingmobile.sshworkbench.
Web platform in www/: Docker stack (nginx+Node.js+MariaDB), landing
page, login (OAuth+email/pw), dashboard (vault sync+session logs),
API routes, MariaDB schema.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 14:47:01 +02:00
jima
c4ead07fa4 Version bump, AppSwitch, cloud backend docs, audit files to docs/, gitignore cleanup
- Bump version 0.0.38 → 0.0.39
- AppSwitch: scaled-down (0.75x) Material3 Switch with full touch target,
  replaces default Switch in KeyboardSettingsDialog for consistent narrow style
- Cloud backend spec: FUTURE.md summary + FUTURE_BACKEND.md full architecture
  (zero-knowledge sync, packs, team sharing, web dashboard, swb CLI) +
  FUTURE_BACKEND_TECH.md implementation details
- Move Audit.md and SecurityAudit.md into docs/ folder
- Add scripts/ to .gitignore (test results, deploy scripts — local only)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 11:47:17 +02:00
jima
e0cbcc6d43 Settings from terminal view, scrollback truncation dialog, drawer about footer
- Add "Settings" item to tab bar and drawer bar kebab menus — opens full
  SettingsScreen from the terminal view via NavHost navigation
- Add Settings row + compact about footer (app icon, version, developer)
  to drawer content panel
- Scrollback truncation: when user lowers scrollback value with active
  SSH/Telnet/Local sessions, confirmation dialog warns about history loss.
  ScreenBuffer.truncateHistory() trims oldest lines and clamps scrollOffset.
- TerminalService.truncateAllScrollback() iterates all session buffers

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 11:45:20 +02:00
jima
ca4359a996 Vault settings export/import, jump chain pro message fix, free vault import gate
- Add optional "Include settings" checkbox (unchecked by default) to both
  Save Vault Locally and Export Vault flows — exports 56 DataStore prefs
  (keyboard, display, QuickBar customization, hardware actions, etc.)
- Import automatically restores settings when present in vault file
- EXPORTABLE_*_KEYS lists in TerminalPrefsKeys define which prefs are backed up
- Fix misleading "Jump Host" pro upgrade message — now says "Jump host chaining"
  so free users understand single jump hosts work, only chaining is pro-gated
- Gate vault import for free users: can only import local vault saves (MODE_LOCAL),
  not pro-exported vaults (MODE_PASSWORD/MODE_QR)
- All strings in EN/ES/SV/FR/DE

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 09:58:15 +02:00
jima
6c1440e80e Security audit 2026-04-11: PEM/Bearer redaction, telnet warning, host key prefix
Fourth full security audit (prod-only). Fixed 5 findings, deferred 3 high-priority items.

- FileLogger redacts PEM private key blocks and Bearer tokens
- EditConnectionScreen shows persistent telnet cleartext warning card
- SubscriptionRepository.migrateFromProApk made internal + idempotent
- Host key fingerprints stored as <keyType>:<fingerprint> with backward-compat fallback
- MainActivity.onUrlTapped allowlists http/https/ftp schemes only

Also bundled from this session:
- SFTP back button no longer navigates up folders
- Vault local save requires strong password (12+ chars, mixed)
- SSHSession cancel-on-auth stops retry loop immediately
- Version bump to 0.0.38

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 01:02:00 +02:00
jima
338f4085b0 Hardware Key Actions: volume keys + shake, single + double press, custom sequences
- New ActionsScreen (Settings → Terminal → Hardware Key Actions): collapsible accordion cards mapping Volume Up/Down + Shake to terminal actions
- HardwareActionHandler.kt extracted from MainActivity (~284 lines): owns volume key state, double-press detection, shake sensor lifecycle, action execution
- Actions: disabled, close session, font up/down, next/prev session, scroll up/down, custom key sequence
- Double press for volume keys with configurable 200-500ms delay (default 300ms)
- Single-disabled + double-enabled = volume still works, replayed via AudioManager after delay
- Custom key sequences parsed via QuickBar's textToMenuItemAction (supports [Ctrl]x, [Alt]x, [Esc], [F1]-[F12], 0xHH)
- Layered overlapping icons for double press cards
- Accordion: only one card open at a time
- SessionEntry callbacks (onFontSizeRequest, onScrollRequest) for external view updates from Compose tree
- Shake sensor only registers when enabled and Activity resumed (zero battery cost when disabled)
- Settings: section headers in teal Space Grotesk uppercase 13sp, About section with cropped pro launcher icon
- Language moved from General to Display section, value subtitles use mono muted style
- Translated in EN/ES/SV/FR/DE
- FUTURE.md: detect remote OS, automatic session logging, opt-in diagnostic data

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-11 00:20:51 +02:00
jima
81e247288e Terminal-style UI overhaul, AppColors, Language screen, FR/DE translations, drawer animation
- AppColors centralized palette in ui/theme/Theme.kt — single source of truth for all colors
- All 15 screen files migrated from hardcoded Color() to AppColors references
- TopAppBar terminal style on all screens: teal Space Grotesk uppercase, #10141A bg, divider
- Settings section headers: teal, uppercase, Space Grotesk, 13sp, letter-spaced
- Settings cards: #181C22 bg, explicit #DFE2EB/#BDC9C8 text colors
- Settings About section: cropped pro icon, centered branding, version in mono
- Settings: session navigation moved above scrollback lines
- LanguageScreen: full-screen language selector with flag emojis, accent bars, fixed info card
- French and German translations (complete ~590 strings each)
- Spanish marked as Español (España) for region clarity
- Drawer bar: AnimatedContent label transition, hamburger icon with teal border/bg
- Drawer kebab menu anchored to icon (was anchored to row)
- Top bar preview: tab switching animation
- Drawer preview: hamburger glow on tap
- Wider horizontal padding (24dp) on screens >400dp

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 19:59:09 +02:00
jima
818c358d1c Telnet jump host support, SFTP SSH-only, duplicate fix, cycle detection UX
- Telnet connections can now tunnel through SSH jump hosts via direct-tcpip channel
- TelnetSession.connectVia() accepts pre-opened streams for tunneled connections
- Jump host picker shown for both SSH and Telnet in EditConnectionScreen
- SFTP option hidden for telnet/local in tab bar overflow and connection list
- Duplicate session fixed for telnet (username=null early return) and local shell
- Session badge shows correct type label (Telnet/Local/SSH) with protocol color
- Label numbering only counts live sessions, not disconnected ones
- Cycle-causing jump hosts shown in red and disabled in dropdown
- Save/Save&Connect disabled when jump host cycle detected

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:59:21 +02:00
jima
d591291c28 Time format setting, protocol-aware card colors, local shell proper IDs, startup commands fix
- Time Format setting (Device default / 12h / 24h) under Display
- Protocol-aware connection card accents: green SSH, amber SFTP, violet Telnet, sky blue Local
- Local shell uses generated sessionId/savedConnectionId (was hardcoded 0)
- Local shell startup commands + lastOutputTimeNs silence detection
- SFTP updates lastConnected for sort order; SFTP option hidden for non-SSH
- Quick connect bar colors unified with lock/key (#7A8888), purged #3E4949
- Pulse animation tuned to 100%→60% over 2s

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 17:07:34 +02:00
jima
7f4aa15830 Server-driven auth, 3-attempt retry, remember-on-success, legacy test lab doc
Auth flow rewritten to be fully server-driven: no pre-connect password
dialog. TCP + KEX + host key verification happen first; password prompt
only appears when the server actually asks via keyboard-interactive or
the new prompted-password fallback (for servers that only accept the
"password" SSH method). Up to 3 password attempts per connection,
matching OpenSSH's NumberOfPasswordPrompts default.

"Remember password" checkbox now functional: AuthPromptResult threads
the remember flag through the callback chain; SSHSession stashes the
typed password in pendingRememberPassword; TerminalService persists it
to CredentialStore only after session.connect() succeeds — wrong
passwords are never saved.

Removed dead pre-connect dialog code: PasswordDialog composable,
PasswordResult, TerminalDialogRequest.PasswordPrompt, and
passwordPromptHandler.

Added docs/LEGACY_TEST_LAB.md: self-contained 2100-line guide for
building a dedicated server with 56 historical/modern Unix systems
for terminal parser conformance testing (Docker, QEMU/KVM, SIMH,
polarhome, IBM PowerVS). Includes all Dockerfiles, compose.yml,
SIMH configs, systemd units, and helper scripts inline.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 19:50:18 +02:00
jima
e243b8e1e5 VP2 rotation fix, NumBlok mini toggle, HW keyboard auto-hide, audit
ViewPager2 rotation phantom (Google Issue 175796502):
- KeyboardView.onSizeChanged rebuilds buildPages() on any width
  transition including initial 0→actual layout, not just on resize.
  The first buildPages() from setup() runs at width=0 (view still
  detached), VP2's internal RecyclerView can't reliably re-anchor to
  the real dimensions that arrive later, leaving a fractional scroll
  offset that leaks the neighbor page on the right edge. A second
  buildPages() once the real size is known produces a clean result.
- KeyboardView.lastModifierStates caches CTRL/ALT/SHIFT state so it
  survives the rebuild.
- Works around an unfixed VP2 1.1.0 bug for non-FragmentStateAdapter
  usage. Fresh launches and all rotation paths confirmed clean on S23.

NumBlok toggle on mini numpad:
- KeyDefinition gains numLabel/numAction optional fields
- KeyAction gains ToggleNumBlock data object
- LayoutParser understands "numLabel"/"numAction" JSON and the
  "toggle_numblock" action type
- KeyboardPageView.numBlockActive swaps label rendering; toggle key
  gets LOCKED-style amber glow while active
- TerminalKeyboard.numBlockActive state; handleKeyAction swaps
  action→numAction; attachMiniTo carries state across rotation rebuilds
- Mini last row: Num 0 \ (base) → Num Ins ~ (numblock)
- Rows 1-3 map to PC-keypad nav: Home/↑/PgUp, ←/Esc/→, End/↓/PgDn
- QuickBarCustomizer serializer/deserializer learned toggle_numblock

Hardware keyboard auto-hide:
- MainActivity derives hasHwKeyboard from LocalConfiguration.current.
  keyboard != KEYBOARD_NOKEYS && hardKeyboardHidden != HARDKEYBOARDHIDDEN_YES
- LaunchedEffect(hasHwKeyboard) { ckbHidden = hasHwKeyboard } seeds
  the toggle on every HW kb connect/disconnect
- In HW kb mode the kebab Show/Hide controls both CKB and QuickBar as
  a pair: val qbShownByUser = if (hasHwKeyboard) !ckbHidden else
  quickBarVisible
- Normal mode unchanged (QB follows its own quickBarVisible pref)

Number row dropdown:
- KeyboardSettingsDialog now shows all four options (top/left/right/
  hidden) in both orientations. Previously left/right were filtered
  out in portrait, preventing the user from setting the mini mode
  without first rotating into landscape.
- Portrait-override on the effective numberRowMode stays in place
  (mini is landscape-only by design — documented in CLAUDE.md and
  auto-memory).

Audit fixes:
- KeyboardPageView: removed key.hint!! by capturing into a local
  hintText val so smart-cast flows through the render branches
- SSHKeyLoader.loadEd25519FromPkcs8: require(seed.size == 32) so a
  malformed PKCS#8 blob fails fast with a clear message instead of
  crashing deep inside EdDSAPrivateKeySpec
- vault_crypto.cpp nativeEncrypt: secure_zero(ptPtr, ptLen) before
  ReleaseByteArrayElements on all three paths (success + two error
  paths), matching the existing key-handling pattern for plaintext
  defence-in-depth through the JNI boundary

Docs:
- TECHNICAL.md: NumBlok, VP2 rebuild workaround, HW keyboard auto-hide,
  portrait mini override notes
- CLAUDE.md: lib-terminal-keyboard module description updated with
  the same invariants
- TODO.md: recently-completed items through 2026-04-06
- Audit.md: investigation log including false positives for future
  reference

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 13:23:13 +02:00
jima
f6f0e5e078 Theme picker, drawer back button, mini numpad 15%, session drawer mode
Theme picker:
- EditConnection now shows "Default (<global theme>)" using the actual
  global theme from TerminalPreferences, not the hardcoded "Default Dark"
- Dropdown adds a Default entry at the top that clears the per-connection
  override (empty string)
- SessionTabBar theme picker replaced hardcoded 7-theme list with
  TerminalTheme.builtInThemes (all 20 themes), scrollable column, and a
  Default entry that clears the per-session override
- MainViewModel exposes globalThemeName StateFlow; threaded through
  SessionTabBar and SessionDrawerContent
- Fix setSessionTheme: blank name clears the override (was wrongly
  treating the literal "Default Dark" as "clear")

Drawer back button:
- Back in terminal pane closes the drawer first if drawer mode is active
  and the drawer is open; otherwise falls back to terminal → nav host
- Drawer state/scope declarations moved above BackHandler

Session drawer mode (already in progress pre-session):
- SessionDrawerBar (hamburger + active label + kebab) and
  SessionDrawerContent (session list with type-colored rows) composables
- New strings: switch_to_top_bar, switch_to_drawer, open_drawer,
  sessions_header (EN, ES, SV)

Mini numpad:
- widthPercent 10 → 15 in all three layout JSONs (EN, ES, SV)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 11:24:40 +02:00
jima
bda8967ab1 Key import validation, 20 themes, 10 fonts, settings redesign, cursor speed/blink, terminal type
Key Import:
- SSHKeyLoader validates imported keys, extracts real pubkey/fingerprint
- ZIP file support with password handling (zip4j)
- Import chooser dialog: ZIP or single file
- Results dialog: valid/encrypted/invalid sections

Theme & Font:
- 20 color themes (10 new: Ayu Dark, Catppuccin Mocha, Everforest Dark, etc.)
- 10 bundled monospace fonts (JetBrains Mono, Fira Mono, Hack, etc.)
- Combined ThemePickerSheet: color scheme combo, font combo, font size slider
- Live preview with scrollable terminal output, adapts to landscape
- Typeface support in TerminalRenderer/TerminalSurfaceView

Settings:
- Material 3 grouped card layout (7 sections)
- Cursor speed: Slow/Normal/Fast/Rapid with key repeat acceleration
- Cursor blink: 530ms toggle, 15s idle auto-stop
- Keep screen on wired to FLAG_KEEP_SCREEN_ON
- Removed Show session tab bar toggle (always visible)
- Font size stepper replaced slider in settings

Terminal:
- Per-connection terminal type (TERM env var) in Edit Connection
- DB migration v1→v2 for termType column
- configChanges prevents activity recreation on rotation

Fixes:
- Vault import hosted in-place (no popBackStack)
- Clickable radio/checkbox/switch rows (text tappable)
- Password rules shown above field in vault export
- Deploy script cleans all stale APKs
- Telnet uses per-connection termType

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-06 02:01:06 +02:00
jima
84e71b2517 Dev/prod split, local vault, Keys & Vault screen, FLAG_SECURE settings
- Dev flavor: .dev applicationId suffix (coexists with prod), yellow icon,
  all pro features via flavor ProFeaturesModule, no FLAG_SECURE
- Prod flavor: subscription-gated ProFeaturesModule, teal/gold icons
- FLAG_SECURE: three granular settings (Full App / Vault / Terminal),
  biometric-gated, all default OFF, replaces single toggle
- Keys & Vault screen: combines SSH Keys, Save Vault Locally, Export/Import
- Local vault (mode 0x03): device-bound backup with DeviceFingerprint,
  password-only, verified on import via ANDROID_ID + brand + model
- Free users see "Import Local Vault", pro users can import both types
- Connection list: kebab menu replaced with direct Settings gear icon
- singleTask launch mode fixes Home→icon returning to connection list
- QR scanner locked to portrait orientation
- Deploy script deletes older APK versions on duero before uploading
- Test scripts updated for .dev package name

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 19:35:08 +02:00
jima
ca16651d69 Security audit: TOFU hardening, FLAG_SECURE, paste sanitization, compiler hardening
Production security audit (OWASP-aligned, prod-only scope):
- Default TOFU to REJECT when no UI handler (prevents silent accept during service-start window)
- Add FLAG_SECURE with preventScreenCapture preference (default ON, Settings → Security)
- Sanitize bracketed paste content (strip \e[200~/\e[201~ to prevent paste-escape injection)
- Add VaultCrypto ProGuard keep rule (prevents R8 stripping JNI methods in release)
- Create network_security_config.xml (system CAs only, cleartext disabled)
- Add compiler hardening flags to both native modules (-fstack-protector-strong, -D_FORTIFY_SOURCE=2)
- Set EXTRA_IS_SENSITIVE on all clipboard writes (terminal copy, key copy, SFTP path copy)
- Remove file:// from URL detection (prevents local file access via crafted terminal output)
- Verify signing certificate in pro APK migration (prevents fake APK granting free features)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 16:04:05 +02:00
jima
17250598b1 Subscription model, dev/prod flavors, vault import fix, font default
Major architecture change: single APK with Google Play Billing
subscriptions (monthly/yearly/lifetime) replacing free/pro build
flavors. Runtime feature gating via SubscriptionProFeatures with
grandfathering support. Dev/prod flavor split isolates all debug
infrastructure (ADB receiver, test profiles, log icons) from
production builds via DevConfig with const val dead code elimination.

- billing/: BillingManager, SubscriptionRepository, SubscriptionStore, SubscriptionState
- SubscriptionProFeatures replaces FreeProFeatures/FullProFeatures
- SubscriptionScreen for in-app purchase UI
- Activity-alias icon switching (teal free / gold pro)
- Pro APK migration detection
- Vault import: fix credential/key/jumpHost re-linking (id=0 bug)
- DB reset to v1 (new package, no migrations needed)
- Default font 10sp (was 14sp in library), global pref applied to new sessions
- Log download no longer clears the log (only Clear does)
- Active session timer always visible (not gated behind sessionTracking)
- Build timestamp shows version number (dev only)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 15:01:26 +02:00
jima
379d2e0677 Edge-to-edge layout, SFTP footer at nav bar, cleanup
- enableEdgeToEdge() before super.onCreate() for proper inset handling
- SFTP rendered at Box level (outside terminal Column) so Scaffold
  bottomBar with navigationBarsPadding() reaches the nav bar edge
- SFTP only composed when active tab (prevents invisible touch blocking)
- Status bar + 41dp top padding on SFTP overlay for tab bar visibility
- Removed windowInsetsPadding from terminal Column (edge-to-edge handles it)
- Cleaned unused imports and debug parameters
- docs: number row modes in KEYBOARD.md, SFTP folder reconnect done in FUTURE.md

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-05 00:36:19 +02:00
jima
ea98dafad1 QB re-attach, SFTP compact header, back button nav, slider fix, hint colors
- QB re-attaches when keyboard is recreated (number row mode change)
- LaunchedEffect keys include keyboard for settings re-apply
- Page indicators applied synchronously in update block (no flash)
- SFTP: compact header (Row instead of TopAppBar), tight breadcrumbs
- SFTP: system back button navigates up one folder (BackHandler)
- SFTP: bottomBar footer, reconnect remembers last folder
- SFTP: --ez sftp true launch param opens SFTP-only (no terminal)
- Slider: commit-on-drag-end prevents accidental changes while scrolling
- Hidden number hints: top-right corner position, light blue (#99CCFF)
- hintColor field on KeyDefinition for per-key hint color override
- Glossary: back button = OS nav bar back button

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 21:49:07 +02:00
jima
293fbcba1e Number row modes, mini numpad, font scaling, tablet defaults
- Number row setting: top (legacy), left/right (mini numpad), hidden (long-press)
- Mini numpad: JSON-defined side section (3x3+1 grid), separate KeyboardPageView
  with touch handling, LinearLayout split in AndroidView, clipChildren fix for
  SurfaceView rendering
- Font scaling: proportional 45%/25% of tallest key height, 10sp/7sp floor
  (was 13sp/8sp clamping to theme minimum, too big on small keyboards)
- Tablet defaults: sameSizeBoth=false, landscape height min 20% (phones 30%)
- Disconnect notification tap navigates to session, red badge on connection cards
- CKB hide/show via tab bar kebab menu
- KeyboardDisplaySettings Eagerly shared to avoid stale initial values

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 20:32:19 +02:00
jima
d2f925cc4d QB Customizer overhaul: view-swap pattern, 55-key pool, app editor, sequential action parser
QuickBar Customizer:
- Keys tab: view-swap pattern (Your Keys ↔ Available Keys full-screen)
- 55 keys in 4 sections (Modifiers/Navigation/Symbols/F-Keys) with OutlinedButton style
- App Shortcuts: list with undo-on-delete snackbar, tap to open editor
- App Shortcut Editor: editable name, maxCols stepper (2-6), key map drag-reorder
- Action format: sequential parser with [Ctrl]x, [Alt]x, [Esc], [F1]-[F12], 0xHH, \n, \t
- Validate/OK two-step flow, modifier insert buttons, auto-close tokens, case normalization
- Reset dialog with "also reset key order" checkbox

Connection list & tabs:
- Duplicate connection appears below original with 10s blue flash highlight
- Tab labels show end of name (start-ellipsis) for long names
- Duplicate nickname validation in EditConnectionScreen
- Save button in EditConnection title bar, Save & Connect full width

Naming & quality:
- "Quick Bar" → "QuickBar" (one word) across all UI, docs, locales
- All hardcoded strings moved to strings.xml (EN/ES/SV)
- StateFlow atomic .update{} for thread safety (20 sites in MainViewModel)
- Removed dead code: unused imports, variables, parameters
- Fixed localized string truncation (.take(60) → TextOverflow.Ellipsis)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 15:10:10 +02:00
jima
8e59db01f4 QB Customizer: drag-and-drop reorder, trashcan delete, grid for available keys
Replace up/down arrows with drag handles (Modifier.draggable) for reordering
in both Keys and App Shortcuts tabs. Replace ✕ with trashcan icon positioned
left of drag handle. Available keys now shown in a compact 4-column grid
instead of a vertical list. App shortcuts auto-collapse when drag starts.
Menu items within expanded apps also use drag-and-drop reorder.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-04 01:27:55 +02:00
jima
21d96b71f0 QB Customizer: reorder/add/remove keys and app shortcuts, CQB/AQB independent
Two-tab Compose dialog (Keys + App Shortcuts) accessible from KB Settings →
Quick Bar tab → Customize, or AQB Settings → Customize. Pro-gated.
Keys tab: 29-key pool, up/down reorder, remove, add from available.
App Shortcuts tab: reorder/add/remove apps, expand to edit individual key
maps with label + action (hex bytes, escape sequences, or text macros).
Independent DataStore prefs for CQB and AQB configurations.
ADB test (06_qb_customizer.py) verifies full flow.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 23:56:15 +02:00
jima
f41d9298f6 Full codebase audit: security fixes, bug fixes, dead code, Compose migration
Security: QR key bytes zeroed in vault export/import, Socks5 null-safety fix.
Bugs: SSH auth cascade no longer silently succeeds without callback, stderr
readLoop no longer causes premature disconnect, dimension overlay cols×rows,
cursorUp/Down respects scroll region boundaries.
Quality: runBlocking→StateFlow (27 calls), MaterialAlertDialogBuilder→Compose
dialog, SSHJ stderr capture race serialized, dead code cleanup across all
modules, string resources for hardcoded text, doc updates.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 22:32:03 +02:00
jima
eb4a1cc7ef QB font scaling fix, AQB settings live preview, unsaved changes dialog
QuickBarView:
- Font/icon scaling uses constraining dimension: rect.width() for vertical,
  rect.height() for horizontal. Clamped to 6sp-22sp.
- W icon keeps square aspect ratio (no stretching)
- onMeasure uses parent height from Compose (not fixed config height)

AQB Settings:
- Live preview with real QuickBarView (non-interactive, edge-to-edge)
- Vertical positions: Row layout (QB sidebar + settings), full height
- Horizontal: Column layout (QB preview on top)
- Preview updates live on size/color/orientation changes
- Unsaved changes dialog (Save/Cancel/Discard) on BACK
- Reset to defaults button
- "Above keyboard" added to AQB position options
- "Hidden" hides preview

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 21:33:28 +02:00
jima
a439e577a1 QB position/color/CTRL wiring, tab bar kebab menu, connect debounce
QB positioning:
- All 5 positions work: top, above_keyboard, vertical_left, vertical_right, none (hidden)
- Compose layout restructured: Row for vertical, Column for horizontal
- Orientation set in update block (not LaunchedEffect) for reliable timing
- Popup direction: RIGHT for top/left, LEFT for right, UP for bottom
- Popup item order reverses based on direction so vim stays closest to W
- Minimum 56dp width for vertical mode
- Scroll over W/snippets buttons no longer triggers them

QB color:
- Custom colors applied via setCustomColors(keyBg, keyText) on QuickBarView
- Reads CQB or AQB color prefs based on keyboard mode

CTRL modifier:
- AKB input intercepted: armed CTRL → Ctrl+key (a-z → 0x01-0x1A), ALT → ESC+key
- getActiveModifiers() exposed from TerminalKeyboard

Tab bar:
- + button replaced with kebab menu (New Session + KB/QB Settings)
- Session label duplicate numbering: SSHTest, SSHTest (2), SSHTest (3)
- Long labels show suffix: "…kap (2)" instead of "Nordka..."

Other:
- Connect debounce (1s) prevents rapid multi-tap opening multiple sessions
- Quick-connect independent: no saved connection lookup, shows user@host as label
- W glossary entry added

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 20:00:11 +02:00
jima
256d059d51 QB app shortcuts, Canvas key icons, bounded scroll, alt buffer reflow fix
Quick Bar:
- App shortcuts button (W icon, far-left) opens two-level popup:
  vim/nano/tmux/scr/F1-12 → 3-column key map grid
- AppShortcutsPopupView: Canvas-based, direction-aware, tap-to-select
- PopupWindow replaced with DecorView overlay + onBackPressedDispatcher
  + layout listener for AKB close detection (one BACK closes both)
- W button toggles popup; toggle_mod actions keep popup open
- Canvas-drawn key icons (tab, backtab, arrows, pgup, pgdn) via labelIcon
- Bounded scroll mode (infiniteScroll=false default)
- CTRL, HOME, END, PGUP, PGDN added to QB scrollable keys
- Menu keys (vim/nano/tmux/screen) removed from scrollable area

Tab bar:
- + button replaced with kebab menu (New Session + KB/QB Settings)
- KB Settings label adapts to keyboard mode (CKB vs AKB)

Bug fixes:
- Alt buffer reflow: main screen content preserved during resize when
  vim/htop is active (was lost on navigate away + return)
- Quick-connect: no saved connection lookup for connectionId=0, tab
  label shows user@host instead of saved connection nickname
- ADB broadcast: enter fires independently from text

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 18:53:54 +02:00
jima
2417b442f1 Add __pycache__ to .gitignore, remove cached .pyc files
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 15:00:43 +02:00
jima
2a87fb58d1 100% Compose migration, AQB/CQB separation, password prompt, ADB test framework
Compose migration (4 files, 2059 lines of View code → Compose):
- ThemePickerDialog: Compose Canvas preview, LazyColumn theme list
- TerminalDialogs: 6 dead dialogs deleted, 2 migrated (hostKey, authPrompt)
  with TerminalDialogRequest sealed interface on MainViewModel for
  imperative→declarative bridge. Added PasswordDialog for no-stored-pw case.
- SnippetDialogs: full-screen Compose dialog with LazyColumn, search,
  inline create form, context menu
- KeyboardSettingsDialog: TabRow, Slider, Canvas preview, color picker.
  Data classes extracted to KeyboardModels.kt

AQB/CQB separation:
- Independent Quick Bar preferences for AKB vs CKB modes
- Settings UI mode-aware: CKB shows full keyboard dialog, AKB shows QB-only
- AQB positions filtered (no above/below keyboard)
- New docs: KEYBOARD.md, GLOSSARY.md (TV, AKB, CKB, AQB, CQB)

Password prompt:
- TerminalService prompts for password when no stored auth (SSHAuth.None)
- Compose PasswordDialog with remember checkbox
- clearPassword ADB broadcast for test cleanup

ADB test framework (Python):
- test.py runner with menu, --all, single test modes
- AI visual verification via claude -p reading screenshots
- 5 tests, 52 checks: connect, htop, vim, password prompt, multi-session
- Timestamped results with manifest.json for cross-run comparison

Coding conventions updated: 100% Compose mandated, no programmatic Views.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 15:00:35 +02:00
jima
bb7662ca63 Audit: security hardening, bug fixes, dead code cleanup across all modules
vault-crypto: secure_zero for all sensitive buffers (Argon2 core, BLAKE2b,
GCM tag/lengths), JNI NewByteArray null checks, Kotlin input validation.
lib-ssh: SSHSession thread safety (debugLogBuffer sync), EOF check fix,
session reuse guard, stderr restoration in finally block.
lib-terminal-view: italic rendering (faux skew), hidden text (fg=bg),
DECCKM reset fix, reflowResize mode preservation, render thread TOCTOU fix.
lib-terminal-keyboard: dead code removal, kotlin.math migration, touch
allocation elimination in KeyboardPageView.
app: Hilt-injected CredentialStore (was duplicate instance), hardcoded
strings to resources (BiometricAuthManager, VaultImportViewModel),
null safety (!! elimination in 5 files), deprecated API fixes, unused
imports/strings cleanup, test API drift fixes, migration 10→11 test.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 08:44:45 +02:00
jima
429ad179ec SFTP: ProxyJump, keepalive, disconnect UI, Connect to Terminal; fling fix, callback audit
SFTP standalone sessions now use shared buildJumpChain for ProxyJump support,
start keepalive monitor for zombie detection, and have full disconnect/reconnect
UI with SSH state monitoring. Tab overflow menu adds "Connect to Terminal".

Fling scroll removes hard distance cap (flingMaxRows) so momentum decays
naturally. Selection toolbar Google button wired. Mouse reporting gated by
pro feature. Dead code (onSaveSnippet) removed. Write logging for paste debug.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-03 00:39:03 +02:00
jima
2fd8308056 Mouse tap-only, ProxyJump probe fix, Ed25519 key loading, jump tunnel monitor
Mouse mode: only taps forwarded as clicks, scroll/select/fling always work.
Active pane zIndex ensures touch events reach correct session.
SSHKeyLoader: auto-detect key format, Ed25519 PKCS#8 via net.i2p.crypto.eddsa.
ProxyJump probe: tunneled connections trust isConnected (no raw socket).
Jump monitor: watches tunnel state, force-disconnects on tunnel death.
Copy Private Key works without biometric lock enabled.
KeyLoadingTest: 9 tests covering all key formats.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 22:55:29 +02:00
jima
9c980bbea7 Session lifecycle: fix service death on unbind, ProxyJump ID, quick-connect history
Critical fixes:
- ensureStarted() counteracts previous stopSelf() before creating any session,
  preventing service destruction when Activity unbinds (screen off, Home, task switch)
- onTaskRemoved() re-starts service to survive swipe-from-recents
- Auto-reconnect no longer removes session from map (prevents empty-map window)
- Auto-reconnect clones password CharArray before disconnect zeroes the original
- checkStopSelf() now includes SFTP sessions in the empty check

ProxyJump fix:
- onConnect callback now passes savedConnectionId directly instead of re-looking
  up by host/port/username (LIMIT 1 picked wrong duplicate connection)
- Threaded through ConnectionListScreen → NavGraph → MainActivity → MainViewModel

UX improvements:
- Quick-connect history (pro): stores 100 entries with timestamps, shows 20 in
  dropdown with relative dates, X to remove, dismiss on focus loss
- Disconnect snackbar suppressed for active session (user already sees the bar)
- DisconnectedBar: muted dark background with teal/grey buttons instead of
  red/green/blue Christmas lights
- Session auto-switch works for Idle state (ProxyJump sessions start in Idle
  during jump chain build)

Refactoring:
- SshConnectionHelper extracted: shared auth lookup, TOFU, session factory
  (eliminates duplication between connectSSH, buildJumpChain, openSftpSession)
- Remove redundant stopForeground call from updateNotification

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 16:33:45 +02:00
jima
898306922b Standalone SFTP: own SSH connection, per-type session counts, audit fixes
SFTP is now fully standalone — each SFTP tab creates its own SSH
connection (tunnelOnly=true) instead of reusing a terminal session's.
SFTP lives independently: disconnecting terminal SSH does not affect
SFTP sessions, and SFTP can be opened from the connection list without
any existing terminal session.

- SftpSessionManager owns SSH+SFTP lifecycle per session
- TerminalService.openSftpSession builds auth, TOFU, connects standalone
- Connection list "New SFTP Session" shows unconditionally (no gate)
- Session picker shows SFTP tabs (amber dots) with labels, scrollbar
- Per-type session counts on connection cards (green/amber badges)
- Connected-since time uses earliest active session, not Room overwrite
- Failed SFTP keeps tab with error instead of auto-closing
- Duplicate SFTP fixed (was passing sessionId instead of connectionId)
- Session observer preserves SFTP tab labels (retainAll includes SFTP keys)
- SFTP cleanup in onDestroy (closeAll)
- Pane switching only when on terminal screen (not from connection list)
- Disconnect button for SFTP sessions in session picker

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 12:06:41 +02:00
jima
8cf34f7a8b Tab bar: type-specific colors, SFTP auto-close, connection list SFTP menu
- Tab colors preserve type identity in all states: teal (SSH), amber (SFTP),
  violet (Telnet). Disconnected tabs show dimmed type color + red dot instead
  of uniform red, so you can tell session types apart at a glance.
- SFTP tabs auto-close when parent SSH disconnects (fixes frozen SFTP tab
  after overnight disconnect).
- SFTP tab labels use connection alias without "SFTP" suffix (amber color
  already identifies type), with host/username fallback to avoid "Session N".
- New SFTP Session option in connection list context menu and session picker
  bottom sheet (amber folder icon, requires connected SSH session).
- i18n: new_sftp_session string in EN/ES/SV.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 10:46:50 +02:00
jima
34325f7119 Full codebase audit: crypto hardening, 6 critical bugs, i18n, dead code cleanup
Security:
- lib-vault-crypto: secure_zero (volatile memset ptr) replaces memset for all
  sensitive memory zeroing, null checks on JNI array access, key/password
  buffers zeroed before release, input validation on Kotlin API
- lib-ssh: keyboard-interactive auth no longer falls back to empty password

Critical bugs fixed:
- SFTP multi-select delete now handles all selected files (was only first)
- reconnectSession() handles Telnet and Local shell types (was always SSH)
- _activeSessions StateFlow updates now atomic via .update{}
- Telnet sessions now execute startup commands
- Clipboard queries cached on UI thread (render thread crash risk on some OEMs)
- TextAttr color mask fixed from 20-bit to 24-bit

Thread safety: @Volatile on SftpSession.sftpClient, SftpViewModel._allEntries;
synchronized debugLogBuffer; onViewRecycled prevents allPageViews leak

i18n: 37 new string resources (EN/ES/SV) for disconnect reasons, network
status, terminal banners, port forward errors, toolbar labels, toast messages

Dead code: removed boilerplate tests, tautological assertions, unused
StateFlows/functions, redundant night theme, unused string resources

Tests: fixed startupCommands mock (false→true), updated stale test names

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 10:00:26 +02:00
jima
5b07e2d686 SFTP: fix SSH disconnect, file type icons, multi-select, hidden files
Critical fix: SFTPClient.close() kills the parent SSH transport by
sending a channel EOF. Removed the close() call — just null out the
reference, SFTP subsystem cleans up when SSH connection closes.

Other SFTP fixes:
- Single SFTP session open (was opening twice — race corrupted transport)
- SftpSessionManager.open() is now suspend (no 500ms guesswork delay)
- SftpScreen always composed (preserves SAF launchers across picker)
- Keyboard/QuickBar hidden on SFTP tabs (tab type check)
- Disconnect notifications suppressed when app in foreground
- Title shows connection name (titleSmall style)

New SFTP features:
- File type icons (32dp): APK, image, video, audio, archive, PDF, code,
  shell, keys, text — color-coded per type
- Multi-select: tap icon to select, batch download/delete bar
- Hidden files hidden by default, toggle in overflow menu
- i18n strings for hidden files toggle (EN/ES/SV)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 02:53:25 +02:00
jima
8f957ae0e7 QB menu keys: vim, nano, tmux, screen combo popups
Add menu key system to Quick Bar — tap a menu key to show a popup strip
with common combos. Each item fires the right byte sequence on tap.

- MenuItem model + menuItems on KeyDefinition, parsed from JSON
- LongPressPopupView: menu mode with auto-sized cells, gaps, borders
- QuickBarView: onMenuKeyTap callback routes menu keys
- TerminalKeyboard: full-screen overlay captures tap on popup item
- New "menu" style in all 4 keyboard themes (purple accent)
- vim: :w, :q, :wq, :q!, :%s/, ciw, >>, <<, redo
- nano: save, exit, find, repl, cut, paste, help, goto
- tmux: new, nxt, prv, det, sp│, sp─, scr, zoom, kill
- screen: new, nxt, prv, det, sp─, sp│, cpy, kill, list

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 02:01:00 +02:00
jima
678295b03b CKB hide/show, keyboard hints, QB fixes, nav fix, logcat in log export
- CKB: temporary hide via ckbHidden state (not pref change), tap terminal to reshow
- CKB/QB input now scrolls terminal to bottom (was IME-only)
- Keyboard hints: all keys get hints (removed label length filter), smart
  positioning (above by default, flips below if off-screen, clamped to edges)
- Long-press popup: auto-shrinks cells to fit screen width
- QB: hints on all keys (onKeyDown on ACTION_DOWN for all, not just repeatable),
  scroll cancels key repeat
- PICK_HOST Back returns to terminal when sessions are open
- Copy Log ZIP now includes logcat.txt (last 5000 lines)
- TerminalKeyboard.attachTo() safe for re-attachment
- SFTP: long-press context menu, settings detail expansion, i18n additions

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 01:12:38 +02:00
jima
1a35a9b57f Post-audit cleanup: i18n, Hilt DI, oversized file extractions
- Extract 40+ hardcoded strings from TerminalDialogs, FreeProFeatures,
  KeyboardSettingsDialog, VaultExportSheet, VaultImportSheet to strings.xml
  with EN/ES/SV translations. SSH technical labels kept in English.
- Add StringResolver interface for ViewModel localization (injected via Hilt)
  — fixes hardcoded strings in VaultExport/Import, Main, KeyManager ViewModels.
- TerminalService: replace duplicate Room instance with @AndroidEntryPoint
  Hilt-injected DAOs. Extract SftpSessionManager, PortForwardManager,
  StartupCommandRunner into standalone classes.
- EditConnectionScreen: extract PortForwardSection (bottom sheet, rows, dialogs).
- ConnectionListScreen: extract ConnectionItemCard and TimeFormatUtils.
- TerminalSurfaceView: extract MouseReporter.
- Delete TODO2.md (all items completed). Update TODO.md, TECHNICAL.md.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 22:17:44 +02:00
jima
1d3b4b053c Full codebase audit: 7 critical bugs, DECSCNM rendering, UTF-8 chunk buffering, i18n
Critical bugs fixed:
- Missing MIGRATION_10_11 in TerminalService (crash on upgrade)
- jumpHostSessions was global (multi-session corruption) — moved to SessionEntry
- KeyboardSettings reset skipped every other view (forward-remove loop)
- DCS parser leaked backslash (ESC \ consumed 1 byte instead of 2)
- SOCKS5 clientThreads grew unbounded (memory leak)
- TelnetSession scope leaked on connect failure
- Host key + auth dialogs never wired up — silent TOFU, broken 2FA

Parser/renderer:
- DECSCNM (reverse screen mode) now rendered — swaps fg/bg screen-wide
- UTF-8 partial sequences buffered across chunk boundaries (11 new tests)

Hardcoded strings → string resources (EN/ES/SV):
- KeyManagerScreen (~22 strings), ConnectionListScreen (~24 strings)
- TerminalService/SessionNotifier notifications, SftpScreen, SftpViewModel
- SessionTabBar fallback label

Dead code removed:
- showSaveSnippet, qrDerivedKey, LANGUAGE_OPTIONS, LightColorScheme
- notifyOnReconnect preference, setPreviewTextColor, markActionTime
- anchorX/anchorY, production Log.d calls, 7 dead string resources

Code quality:
- SftpSession streams wrapped in .use{}, FileLogger.getLogFile respects
  useDownloads, FastSSHConfig unused keepalive removed, var→val fixes
- TabTypeAndLabelTest updated for TELNET/LOCAL enum values

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 19:55:28 +02:00
jima
f58258a842 Keyboard: remove Term page, add arrows to symbols, fix long-press on drag
- Remove Term page (ABC → #+= → F1-12, was 4 pages now 3)
- Add arrow keys to #+= bottom row replacing CTRL/space
- Cancel long-press timer when finger drags off key, re-enable page swiping

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 18:00:03 +02:00
jima
9e5c3100e2 Session stability, logging, disconnect notifications, save output, pinch-zoom in mouse mode
- Fix foreground service lifecycle: keep service alive while disconnected sessions exist,
  preventing Android from killing sessions when app is backgrounded during WiFi drops
- Fix cleanupDisconnectedSession: keep sessions in _activeSessions map so UI shows
  disconnect bar and tab indicator instead of silently removing them
- FileLogger: append mode (persists across app opens), fallback to app-private dir,
  ZIP export with .bin recordings, comprehensive trace logging across all components
- SessionNotifier: batched disconnect notifications (5s window), auto-cancel on reconnect,
  smart handling of partial reconnects (5 disconnect, 3 reconnect → shows 2 remaining)
- Save Output: export scrollback + screen to Download/<alias>_<timestamp>.txt
- Disconnect bar: styled pill buttons, timestamps on all disconnect/reconnect messages
- Session tab bar: red accent + dark red background for disconnected tabs
- In-app snackbar: brief "Duero disconnected" alert when session drops while in app
- Pinch-zoom in mouse mode: scale detector fed before mouse intercept, multi-finger
  gestures bypass mouse reporting so htop/vim resize works
- Snippet manager: duplicate action, list refreshes after edit/delete/duplicate
- Notify on disconnect setting (default on), build timestamp on connection list
- Deploy script fix, SessionRecorder rolling reset at 1MB

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-01 15:13:15 +02:00
jima
40650286dc VT52 compatibility mode with DEC Special Graphics charset
Implement VT52 mode as a standalone delegate class (Vt52Parser), activated
via CSI ?2l (DECANM reset) and exited via ESC <. Supports all VT52 escape
sequences: cursor movement (A-D), direct addressing (ESC Y row col), erase
(J/K), reverse index (I), home (H), and DECID response (ESC /Z).

Graphics character mode (ESC F/G) maps ASCII 0x5F-0x7E to DEC Special
Graphics glyphs (box-drawing, math symbols) — same charset as VT100's G0 '0'.

37 unit tests, all vttest tests 1-11 now pass including test 7 (VT52 mode).
New docs/TERMINAL_PARSER.md with full parser architecture, state machine,
DECCOLM quirks, VT52 implementation details, and graphics charset table.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 09:47:40 +02:00
jima
e72c4de55d Fix DECCOLM mid-chunk data loss and CSI leading zeros truncation
replaceEngine now updates the old parser's screen reference so remaining
bytes in a chunk after DECCOLM are written to the new buffer instead of
the discarded one. Also bumps MAX_PARAM_LEN 10→16 so vttest's 11-digit
leading-zero parameters parse correctly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 01:06:41 +02:00
jima
b2d8354ebf DECCOLM support: 80/132 column mode switching for vttest compatibility
- Handle CSI?3h (132-col) and CSI?3l (80-col) in setDecPrivateMode:
  clear screen, reset scroll margins, home cursor, fire listener callback
- Add onColumnModeChange callback to TerminalListener interface
- TerminalService handles DECCOLM by reflowing ScreenBuffer to requested
  column count and sending PTY resize to the SSH server
- Add onBufferReplaced callback so TerminalSurfaceView picks up the new
  ScreenBuffer immediately (not just on next Compose recomposition)
- Add DECCOLM parity tests verifying match with Termux behavior
- vttest test 1 now renders correctly on terminals wider than 80 columns

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 00:33:10 +02:00
jima
65df2338a7 Launch intent profile auto-connect, PTY size fix, vttest parity test, screen dump
- Add --es profile "Name" launch intent to auto-connect by connection name/nickname
- Add --ez clearLog true intent extra to clear debug log on launch
- Add --ez dump true ADB broadcast to dump full screen buffer to log file
- Fix PTY allocation to use actual terminal dimensions instead of hardcoded 80x24:
  SSHSession.resize() now stores dimensions even while Connecting, and PTY
  allocation picks up the latest values instead of the initial config
- Add connectByProfile() to MainViewModel for profile-based connections
- Add VttestParityTest: replays recorded vttest session through both our engine
  and Termux at 80x24 and 102x38, verifying cell-by-cell parity (both pass)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:58:28 +02:00
jima
c4f60b05cb Edge-to-edge insets, quick bar redesign, multi-session focus, keyboard settings
- Add status bar insets to SessionTabBar and navigation bar insets to terminal
  Column for proper edge-to-edge rendering on Samsung S23 (Android 14+)
- Redesign quick bar: ESC, TAB, :, ~, |, arrows, shift-tab (remove Ctrl+C)
- Defer haptic in infinite scroll mode until tap is confirmed (no haptic on scroll)
- Manage focus explicitly when switching sessions — clear focus on invisible
  views, request focus + restartInput on visible to fix Samsung IME routing
- Wire space long-press gear to KeyboardSettingsDialog from terminal pane
- Add diagnostic logging for writeInput drops and null session entries

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 23:02:00 +02:00
jima
70ab307294 Pinch-to-zoom fixes, telnet tab color, SFTP simplify, render reliability
Zoom: defer commit to ACTION_UP so ScaleGestureDetector min-span restarts
don't interrupt continuous zoom-out. Suppress tap after pinch to prevent
AKB appearing on finger lift. Thread-safe font metrics (@Volatile).

Tabs: telnet sessions show violet accent, detect session type (SSH/Telnet/
Local) via TabType enum. Connection list now sorts by last-used (call
updateLastConnected on connect).

SFTP: simplify large download confirmation (inline threshold check),
AndroidViewModel for string resource access, proper error on null stream.

Render: consume dirty after lockCanvas, re-request on lockCanvas failure,
extra render after zoom settle. Default font size 10sp. Dismiss soft
keyboard when navigating to NavHost. Paste preview color matches keyboard
hint (#888888).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-30 09:42:15 +02:00
jima
63c110f5fd Vault import: QR from image, share-to-app, export safeguards
Import can now read QR from a saved image (Pick image button) in
addition to camera scanning. Register ACTION_SEND image/* intent
filter so QR images shared from WhatsApp/Telegram auto-open the
import flow. Export screen enforces strong passwords (12+ chars,
upper/lower/digit/special), gates QR export on save/share, and
shows confirmation dialog before exporting with QR mode.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-29 23:35:29 +02:00