Commit Graph
15 Commits
Author SHA1 Message Date
haraldandClaude Opus 5.5 b8748c56d4 feat(sync): built-in Nextcloud sync (Issue #49, stage 2)
Sign in to any Nextcloud server (also private ones in a subfolder, with
their own port or a self-signed certificate) through the browser with
Login Flow v2; the app gets an app password of its own, which
"Disconnect" revokes again.

A background thread syncs the storage folder with the folder ink-notes
on the server every 30 seconds and shortly after saving, three-way
against the state after the last pass: one-sided changes are copied,
manifests and library.json are merged, a page changed on both sides is
kept twice (the server's version as conflict copy, which disk_watch
turns into a page), empty pages give way, deletions go into the trash
on both sides and lose against changes. Changes to the open notebook
wait while it has unsaved changes. Folder ETags spare listing unchanged
notebooks; the pass stops instead of deleting when the storage folder
or the server folder is missing.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 19:24:49 +01:00
haraldandClaude Opus 5.5 3d6dbf09da fix(android): keep the toolbar out of the status and navigation bars (Issue #50)
NativeActivity draws the whole window, also below the system bars, so the
top toolbar button lay under the status bar and taps there went to
Android (no other notebook could be opened). InkActivity now reports the
system bar and cutout insets; the app shrinks egui's screen rect to the
free area and adds the side insets to the page centering. The page itself
still scrolls below the bars.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 15:32:43 +01:00
haraldandClaude Opus 5.5 307c803246 feat(math): offer the result next to a handwritten = (Issue #46, stage 3)
New module math_assist.rs: when the last two strokes form an = and the pen
rests for 500 ms, the strokes left of it (in a band around the =, up to a
wide gap) are recognized and computed. The suggestion appears next to
the = and shows what was read, e.g. "2⁴ = 16"; tapping it with the pen
or clicking inserts the result as a text box in the ink color and as high
as the handwriting, as one undo step. The chip is not interactive for
egui, so fingers and palms pass through. Any new stroke drops it. In a
chain like x = 2 · 3 = the part after the previous = is computed.

Off by default: ☰ → Input → "Compute formulas after =", saved in
ui.json. math::display writes the recognized expression neatly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-28 14:45:00 +01:00
haraldandClaude Opus 5.5 0be321837c feat(android): Java activity for keyboard text and the system file dialog (Issue #42)
InkActivity extends NativeActivity:
- An invisible view with its own input connection receives the soft
  keyboard's text (commitText, deleteSurroundingText), so characters
  without a key event (umlauts by long press, ...) arrive as well. The
  field is a visible-password field, so keyboards commit each character
  instead of composing words.
- Import and "insert image" open the system file dialog
  (ACTION_OPEN_DOCUMENT); the chosen file is copied to the cache folder
  and handed to Rust by path.

src/android_bridge.rs calls the activity through JNI and receives its
native calls; package-android.sh compiles the class with javac and d8.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 21:23:52 +01:00
haraldandClaude Opus 5.5 a8aef30db7 feat(android): pen input, soft keyboard and exports to Downloads (Issues #42, #44)
- Pen vs. finger (#44): the patched winit hands Android pointers with
  tool type stylus/eraser to the app separately (take_pen_samples, with
  hover and button state) instead of as touch events. src/pen.rs turns
  them, like octotablet's events on the desktop, into one PenInput
  stream, so pen buttons, the eraser end and palm rejection work the
  same everywhere. Hover exit right before touch-down does not count as
  leaving; a pen without hover leaves 150 ms after lifting.
- Soft keyboard: shown via AndroidApp::show_soft_input when a text field
  gets focus, hidden when it loses it. The patched winit now fills
  KeyEvent::text, so typed characters reach egui.
- Exports (PDF, PNG, SVG) are written to the app folder and copied to
  Download/ink-notes through the MediaStore (Android 10+, via JNI).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 20:54:48 +01:00
haraldandClaude Opus 5.5 6b80cd672a fix: stop redrawing endlessly while idle (battery drain)
egui-winit reports `repaint: true` for every RedrawRequested, and the app
followed that with another request_redraw – so it redrew at full frame
rate all the time, keeping the app and the compositor (gnome-shell) busy.
Follow-up frames egui needs already come via `repaint_delay`.

The toast no longer redraws every frame either: one wake-up when its
fade-out starts is enough. While the updater checks or downloads, the
loop looks for its results every 100 ms instead.

Idle CPU under Xvfb/lavapipe: 187 % before, 0 % after.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 20:14:46 +01:00
haraldandClaude Opus 5.5 7faf78ddeb feat(android): follow the activity lifecycle and build an APK (Issue #42)
- The drawing surface is created once the native window exists (Resumed)
  and released when the app goes to the background (Suspended); before
  that everything is saved, as Android may stop the app at any time
- Android's back button acts like Escape instead of closing the app
- Panics are written to logcat; no update check on Android yet
- scripts/package-android.sh builds target/ink-notes_<version>_arm64.apk
  without Gradle (NDK, aapt2, zipalign, apksigner); signing key from
  ANDROID_KEYSTORE/ANDROID_KEYSTORE_PASS/ANDROID_KEY_ALIAS, otherwise
  the debug key

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 18:23:28 +01:00
haraldandClaude Opus 5.5 8034c88f8b fix(windows): don't let Windows Ink report the mouse as a pen (Issue #48)
octotablet's default emulates a pen tool from the mouse on Windows Ink, so
every mouse move counted as pen hover and every click as pen down, while the
regular mouse events were ignored as duplicates.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 15:44:42 +01:00
haraldandClaude Opus 5.5 e5a8601f87 feat: Windows build and Android groundwork (Issues #48, #42)
Shared groundwork:
- paths.rs: folders for data, settings and downloads per system (Linux XDG
  unchanged, Windows %APPDATA%/%LOCALAPPDATA%, Android app folder)
- Linux-only parts behind cfg: Wayland on-screen keyboard (osk/wayland.rs),
  display backend and app id, the vendored winit touch extensions
- run_with(event_loop) so that other entry points can start the app

Windows (#48):
- cross-compiled with MinGW into a portable ink-notes_<version>_x86_64.exe
  (system DLLs only), no console window in release builds
- file picker: user folders and drives; held notebook locks are detected
  (ERROR_LOCK_VIOLATION)
- updater: replaces the running .exe via rename, active at the next start
- octotablet panicking without the Tablet PC components no longer crashes
  the app
- release: .exe built in CI and part of the signed checksums
- all library tests pass under wine

Android (#42):
- android_main entry point, winit with android-native-activity,
  android_logger; octotablet and arboard left out there
- cargo check and the cdylib build for aarch64-linux-android pass; the window
  surface does not follow the activity lifecycle yet

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 15:13:37 +01:00
haraldandClaude Opus 5.5 9b34e30475 feat: sync notebooks between devices via a synced folder (Issue #49, stage 1)
- Storage location setting: the notebooks can be moved into a folder kept in
  sync by Nextcloud, Google Drive, Syncthing etc. (subfolder `ink-notes`);
  existing notebooks are copied there if it is still empty, the originals stay.
- Changes from other devices are taken over while everything local is saved:
  changed pages are reloaded, new/removed/reordered pages and titles come in
  through the manifest. A page file still being synced is retried later
  instead of being set aside as damaged.
- Conflict copies made by sync clients become pages of their own.
- `.opened_by.json` marks the device that has a notebook open; opening a
  notebook open elsewhere shows a warning.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 13:09:39 +01:00
haraldandClaude Opus 5.5 397bf3bfe4 feat: import Saber notebooks (Issue #47)
The import now also accepts Saber files: .sbn2 (BSON) with its asset
files next to it, .sba archives (zip with main.sbn2 and assets) and the
old JSON .sbn, including the layout before format version 8 with
strokes outside the pages. Taken over: strokes with pen pressure and
perfect_freehand's thinning, highlighters, circle and rectangle shapes,
typed text (Quill delta as one text field), images (SVG rasterized),
background images and PDF pages as PDF backgrounds, paper patterns.

BSON and zip are read by small built-in readers, so no new
dependencies. The SVG rasterizer moved to src/import.rs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 12:25:29 +01:00
haraldandClaude Opus 5.5 46026eb8e5 feat: import Rnote notebooks (Issue #47)
The import (menu entry and drag & drop) now also accepts .rnote files
from Rnote 0.5.10 on, including the transformation and document config
layouts that changed in 0.13 and 0.15. Taken over: brush strokes with
their pressure curve, shapes as outlines, texts, bitmap images and SVG
images, which are rasterized with resvg (Rnote stores imported PDF
pages as SVG). Fixed-size and continuous documents keep their pages;
infinite ones become an endless notebook.

The parts shared with the Xournal++ import moved to src/import.rs.
resvg and its dependencies were added to the Flatpak cargo sources.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 11:40:51 +01:00
haraldandClaude Opus 5.5 2bd697ef82 feat: import Xournal++ and Xournal notebooks (Issue #47)
The import menu entry (formerly "Import PDF") and drag & drop now also
accept .xopp and .xoj files. Each Xournal page becomes a page of a new
notebook: strokes with pen pressure, highlighters, texts, embedded
images, lined/squared/dotted paper, image backgrounds and PDF
backgrounds (looked up at the stored path and next to the file). All
layers are flattened in order; LaTeX formulas are skipped and counted
in the status message.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-27 11:10:34 +01:00
haraldandClaude Opus 5.5 dd515787ec fix: measure the swipe speed with the compositor's touch event times (Issue #28)
Pia's log shows the lift arriving 200-300 ms after the last move on every
swipe, so the release looked like a resting finger and nothing glided. The
vendored winit now keeps the Wayland timestamp of each touch event
(take_touch_time), and the fling measures with those times instead of when
the app got around to handling the events. The diagnostics log both gaps and
any event handling that blocks the app for more than 40 ms.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-26 14:08:13 +01:00
haraldandClaude Opus 5.5 b11fb2d762 refactor: move the event loop into the library as app::run (prep for Issue #42)
src/main.rs is now only the desktop entry point; the app itself lives in
src/app.rs, so other entry points such as android_main can start it. The code
is unchanged apart from crate:: paths; the source scans in the i18n and UI
tests and the docs point to app.rs.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 14:02:43 +01:00