Skip to content

Latest commit

 

History

History
436 lines (363 loc) · 23.4 KB

File metadata and controls

436 lines (363 loc) · 23.4 KB

Changelog

All notable changes to this project will be documented in this file.

The format is based on Keep a Changelog, and this project adheres to Semantic Versioning.

0.8.0 - 2026-08-26

Changed

  • The UI fits itself to the screen it is on. Every screen is laid out in points against a 640×480 design, and one zoom factor carries the lot — fonts, rows, gaps — so a desktop window and a 752×560 Flip panel show the same layout at the size each has room for, rather than the design at 1:1 pixels and text that shrinks with the panel. A panel only a little past the design keeps a whole zoom: fractional zoom lands glyphs between pixels, which reads as uneven type where there is no subpixel positioning, so the spare pixels become margin instead. A phone held upright is the same screen turned, so the fit measures long edge to long edge and the lists get a narrower measure, not smaller rows.
  • RETSEND_SCALE now pins the base the setting is read over, instead of being the whole answer. Android no longer passes the display density — the fit lands on the same physical size at any density.

Added

  • A muOS package, retsend-muos.muxapp, installed from Archive Manager and listed under Applications rather than under Ports as the PortMaster build is. The launcher hands muOS's own SETUP_APP the pad and the governor, holds the device awake for the length of a transfer, and points saves at ROMS/ on the card that booted. B on the home screen quits, which muOS needs: its only exit is a kill -9 that would cut a transfer where it stands, so the app answers the key itself and closes the sockets on the way out. Other ports leave B inert — there the launcher owns quitting — and the launcher opts in with RETSEND_BACK_QUIT. The home tabs name the key in their hints only where it is on, so nowhere else grows a hint for a button that does nothing.

  • A "UI scale" setting, 60% to 160% of what the screen itself asks for, stepped with ◂ ▸ on its row (L1/R1 still switch tabs, and the hints name both arrows so a screen with no pad can reach them). Persisted as [display] scale, applied live.

  • A send can be repeated from the History tab, with A on its row. The log now keeps the source paths of a send and the address it went to; the resend dials the peer under that alias as the radar has it now, so a device that changed address in between is still reached, and falls back to the recorded address when it is off the radar. Files deleted since are left out — the rest still go, and a toast says how many were missing. Sends of more than 64 files are logged without their paths rather than growing history.json without bound, and their rows offer no resend.

  • A history row can be dropped from the log, with X.

0.7.1 - 2026-08-24

Changed

  • Pinned rows sit in a band of their own in the file browser, closed by a rule where the folder's own entries start. They lead every listing but belong to other folders, and a star alone left them reading as rows of the folder being looked at.

Fixed

  • The file browser opened inside the app's own folder on the Miyoo CFWs and would not leave it. /mnt/SDCARD was no known mount point, so the only root left was $HOME — which those launchers point at the app folder for a writable path — and a root is the one directory B cannot leave. The card is a root now, and $HOME only becomes one when it sits outside every other.

0.7.0 - 2026-08-24

Added

  • An Allium package, retsend-allium.zip, for the same Miyoo Mini Plus and Flip the OnionOS one serves. Allium is a launcher on the stock firmware, so the binary and the bundled SDL2 are the OnionOS package's; what differs is the layout (Apps/Retsend.pak/ — only a .pak folder counts as an app there) and the launcher. Allium keeps no kill helper and does nothing with MENU for an app, so the app answers the key itself, behind RETSEND_MENU_QUIT — set by that launcher alone, so OnionOS keeps its helper and its behaviour.
  • A spruceOS package, retsend-spruceos.zip, for those same two devices. spruce reads App/Retsend/ as OnionOS does, so what the package adds is a config.json naming the devices it belongs on and a launcher; the bundled SDL2 counts for more here, since spruce carries a Miyoo build of its own whose drivers answer to other names. MENU is the way out and genuinely the app's: spruce's own handler returns early for anything launched out of App/ rather than Emu/. The launcher writes a line into spruce's log when wifi is off in its settings, since an empty radar otherwise reads as a bug.
  • Retsend in Allium's Games tab, from a ports/Retsend.port/ folder the Allium package carries. Copied to Roms/PORTS/, the Ports Collection console runs its launch.sh, which hands over to the install under Apps/ — one copy of the app, and one identity on the network.
  • SIGTERM closes the app instead of killing it, so powering the device off or closing the lid stops the announcer and shuts the sockets down first, and a peer sees a transfer end rather than a connection that stopped answering. A second signal still kills outright, and the headless receiver is left alone.

Fixed

  • Starts on an Allium card, which carries neither libGLESv2.so nor libshmvar.so — an OnionOS card supplies both, and the bundled SDL2 names them in DT_NEEDED while calling into neither. lib/fallback/ holds empty stubs with the right SONAMEs, last on LD_LIBRARY_PATH so a real library still wins.
  • Fills the Miyoo Mini Flip's screen. Its panel is 752x560 and the bundled drivers assumed the Mini's 640x480: the renderer scales by an integer factor and centres what it draws, so the app ran as a 640x480 island in a black margin. The bundled SDL2 is now our own fork of steward-fu's, which reads the framebuffer's real size, reports it through SDL_GetDesktopDisplayMode and takes its texture limit from it; the app opens its window at that size. A Mini and a Mini+ resolve to the same 640x480 they always did.

0.6.0 - 2026-08-20

Added

  • An Android build, retsend-android-arm64.apk. SDL2's Android port loads the Rust code as a cdylib and enters it through SDL_main, so windowing, the GLES path, gamepad input and the whole net stack are the ones the handhelds run — what is Android's alone is packaging, storage and the Back button, all of it behind cfg(target_os = "android") or additive Cargo entries. The system Back button is B and quits at the top level, and the activity holds a MulticastLock so the Wi-Fi driver stops filtering out the announces discovery is built on. It runs landscape, which is both the UI it already had and one less relayout to get wrong. The app asks for all-files access before starting: granted, received files land in Download/ where an emulator can find them; denied, it keeps to its own external folder, which file managers can't open on Android 11+. Built with android/scripts/build.sh; the port is written up in android/README.md.
  • Touch and mouse input, which the UI had never read: it is painted from a cursor that only a pad or the keyboard moved, so on a phone there was nothing to press. A tap now becomes the same AppCommand a button emits — on a row it places the cursor there and confirms, so tapping a device sends to it and tapping a file picks it, and each slot of the footer hint bar is the button it names, which is what makes Start/Select/X/Y reachable without a pad. The same applies to a desktop mouse, where clicking used to do nothing.
  • RETSEND_BROWSER_ROOTS (:-separated) adds file-browser roots a launcher knows and no built-in candidate could name, and RETSEND_ALIAS seeds the device name where there is no hostname to read. The Android activity passes its storage volumes and Build.MODEL through them.

0.5.5 - 2026-08-18

Changed

  • The OnionOS package carries an SDL2 built from steward-fu/sdl2 instead of the copy taken from the Ports-Collection. The old build declared two texture formats but filled slots 0 and 2 of the table, so SDL read RGB565 and a zero and could offer no 32-bit format at all: every frame was converted down to RGB565 on the CPU before the panel saw it, and flat fills and thin dividers banded. This one declares RGB565 and ARGB8888, so the frame reaches the SoC's blitter as it was drawn. It also drops that build's SELECT + R1 scaling hotkey, which ate the R1 press that pages a list. Its video driver is named Mini rather than mmiyoo, so the launcher names the render driver and asks for the pad layout outright, and libSDL2_image and libSDL2_ttf are gone from the bundle with the fonts and image codecs they pulled in.

Fixed

  • The rendering artifacts on the devices that fall back to SDL's renderer, the Miyoo among them, are gone — fixed in the egui-sdl2 releases the app has moved onto. egui's colours are premultiplied and SDL's blend multiplied by alpha a second time, so a panel's fade-in flashed close to black for a few frames; a feathered edge ran to black rather than to invisible, drawing a dark line along the bottom and right of the screen; and the frame the blit path presents was blended with the window instead of replacing it, dimming everything short of opaque. The three of them reached a release in 0.5.3, where they went unrecorded here; the banding above is this release's.

0.5.4 - 2026-08-13

Fixed

  • Receiving from LocalSend 1.18+. It streams uploads through reqwest, which frames the body Transfer-Encoding: chunked instead of sending a Content-Length, and the server answered every chunked request with 411 — the sender saw statusCode(status: 411). Chunked bodies are now decoded; extensions and trailers are dropped, and a Content-Length sent beside chunked framing is ignored rather than trusted. Transfer codings we can't decode moved from 411 to 501.

0.5.3 - 2026-08-13

Fixed

  • Sending to a receiver that requires client authentication. LocalSend's newer core makes a client certificate mandatory whenever it isn't also serving its web UI, and we presented none, so the handshake died before the first request and the transfer read Send failed: certificate required. Outbound requests now carry our persisted identity — the same certificate the announced fingerprint hashes. It is loaded even with https = false, since a peer announces its own scheme and we can be the client of an HTTPS receiver while serving plain http.

0.5.2 - 2026-08-08

Fixed

  • The settings list scrolls. Its nine rows are taller than a 640x480 screen has room for, and the list had no scroll area, so the last row (About) was cut off at the panel edge — the cursor still moved onto it, off-screen. A smaller panel or a larger RETSEND_SCALE cut it sooner.

0.5.1 - 2026-08-08

Changed

  • The tab bar leads with Receive, the tab the app opens on. Landing mid-bar meant left and right stepped off the landing screen in two unrelated directions.
  • Button hints name what the button does. A on the radar reads Choose files, not "Send" — it opens the file browser, and Start is what sends. Select on Receive reads Announce rather than the radar's "Refresh": there is nothing to refresh there, the button re-multicasts our announce. X on an incoming request reads Save to… rather than "Folder".
  • Settings rows are grouped: the settings that decide what happens to an incoming file now run unbroken, and Port — set once, if ever — moved down next to About. Alias is Device name, Save to is Save folder, and Existing files asks If a file exists.
  • A settings row's action moved out of the row and into the footer, where every other screen keeps its buttons.
  • The radar badges only peers announcing plain HTTP, in red. Encryption is the norm now, so an HTTPS badge on every row was noise and the exception was not visible as an exception.
  • History rows use the tab bar's arrows for direction — ↓ came in, ↑ went out — instead of a second, unrelated arrow language.
  • A transfer's ETA reads in minutes and hours once it passes a minute ("5m 05s"), rather than counting seconds to "~305s".

Added

  • The Receive screen shows the folder incoming files land in, under the address.
  • The destination picker's countdown turns red for its last ten seconds.

0.5.0 - 2026-08-08

Added

  • Folders are received as folders. Protocol v2 carries a folder transfer as files whose fileName holds the relative path, which the receiver flattened to a basename; it now rebuilds the sender's tree under the save folder, up to eight levels deep, with every component sanitized on its own so a path still cannot leave the save folder. Files that arrive inside a folder skip the save routes — a folder lands whole instead of split across console folders — and loose files route as before. Settings → Received folders switches it off ([transfer] keep_folders = false) for the old flattening.

0.4.1 - 2026-08-05

Changed

  • A held direction wakes the event loop once per auto-repeat instead of spinning it. The loop stopped blocking on the event pump at all while a direction was down, so it ran a core flat out to fire repeats at the configured interval; the block is now bounded by the earlier of egui's repaint request and the moment the next repeat comes due.
  • The browser and history lists lay out and paint only the rows in view. A ROM folder can hold thousands of entries, and every one of them was a laid-out, painted row on every frame. History rows differ in height depending on whether they carry a path line, so their tops are prefix sums rather than a fixed step.
  • A frame builds the data for the one screen it draws. Peers, history rows and save routes were all assembled every frame no matter which screen was on top, so covered screens still paid for their allocations; the base-screen precedence the render pass already followed now picks what to build. The peer and history counts the command router clamps its cursors against are from the last frame that showed those tabs.
  • Directory listings sort on a cached lowercase key — one allocation per entry rather than two per comparison.

Added

  • The About screen names the author, next to the version, build date, commit and project URL.

0.4.0 - 2026-08-04

Changed

  • Left and right switch tabs, on every tab — the tab bar no longer needs the shoulder buttons, which some of these pads place awkwardly. L1/R1 still do it. The port is typed on the on-screen keyboard now (A on the row) rather than stepped one number at a time with left/right, which was the only thing left holding those two directions; every other settings row was already on A.
  • The ARM binaries are cross-built with cargo-zigbuild, which puts the glibc floor in the target triple instead of pinning the build to whichever distro ships that glibc — no archived apt suites in the pipeline. One build per arch feeds every package, so the armhf binary in the PortMaster zip is the same file the OnionOS zip carries. tools/arm/build.sh runs the same thing locally.

Added

  • An OnionOS package for the Miyoo Mini Plus and Flip (the plain Mini has no wifi): retsend-onionos.zip unzips at the card root into App/Retsend/, built and released by a workflow of its own. It ships the SDL2 the platform's own ports use and preloads it the same way, keeps the config and received files on the card, skips the GL probes the SSD202 cannot answer, and wires MENU to quit through pressMenu2Kill — nothing on these devices raises an SDL quit event.

Fixed

  • The armhf binary starts on a glibc 2.28 userland, and the aarch64 one now loads on older ArkOS. Both were built against whatever glibc the CI runner had — 2.31 for armhf, 2.35 for aarch64 — so armhf asked for log, log2, pow@GLIBC_2.29 and gettid@GLIBC_2.30 on a 2.28 userland and the loader refused it before main(). Both are built with cargo-zigbuild against a pinned glibc 2.28 now, and CI fails the job if a reference above the floor comes back. port.json states that floor for PortMaster.
  • Text is no longer clipped along the bottom of every glyph on the Miyoo Mini Plus and Flip, and the UI no longer stutters. Both came from the same place: egui's meshes were rasterized as triangles, and the SDL 2.26 those devices' SDL2 forks are built on drops the last row of a textured triangle. Glyphs and plain rectangles are blitted now instead, which is also cheaper than per-pixel triangle work on a CPU with no GPU behind it.
  • Buttons work on the Miyoo Mini Plus and Flip. Their SDL2 offers the pad as a joystick with no gamepad mapping and sends key presses instead (A is Space, B is Left Ctrl, Start is Return), none of which matched the desktop bindings. The layout is picked from the mmiyoo video driver, or by RETSEND_KEYMAP.

0.3.0 - 2026-08-02

Added

  • Devices can be added to the radar by IP: X on the Send tab types ip[:port] (port defaults to 53317) and registers with whatever answers there — the way in on networks where multicast discovery never arrives, like guest Wi-Fi and AP-isolated access points. HTTPS is tried before plain HTTP, /info before giving up, and a hand-added device stays on the radar instead of expiring after two minutes of silence. It still has to be routable: this replaces discovery, not the network path.
  • The incoming-request modal takes a folder: X opens the browser, Start drops that transfer into the folder on screen. The pick is the whole answer to "where" — save routes are skipped, so nothing gets moved out of the folder just chosen. The request keeps counting down while you browse, so the header shows the seconds left before it auto-declines.
  • armhf builds for 32-bit handhelds: a retsend-linux-armhf.zip release asset, and both binaries in the PortMaster zip, picked by DEVICE_ARCH at launch.
  • Missing GL is no longer fatal: GLES 3.0, then desktop GL, then SDL's renderer (software if that is all there is). RETSEND_SOFTWARE=1 skips GL outright. Every build needs SDL 2.0.18 or newer on the device now — that painter calls SDL_RenderGeometry.

0.2.1 - 2026-07-30

Fixed

  • PortMaster: received files default to the ROMs folder on muOS too. The launcher took PortMaster's $directory for the ROMs root, which on muOS is the card root (/mnt/mmc) one level above ROMS. Installs that already have a config keep their folder — change it in Settings.

0.2.0 - 2026-07-30

Changed

  • Every footer now ends with A, so the confirm hint sits under the same thumb on all screens: the Send tab and the on-screen keyboard used to lead with it.
  • The on-screen keyboard erases with X; B now just leaves it, instead of erasing and then closing once the buffer ran empty.
  • The routes editor scrolls through the auto save routes: the cursor carries on past the add row into them, so a list longer than the screen no longer hides its last rows. They stay read-only — A does nothing there.

Added

  • History rows show the folder the files landed in () or were sent from (), so a save route that moved a ROM somewhere unexpected is visible without hunting for it. A session split across routes shows the first folder and how many more it used. Entries logged before this stay two-line.
  • The incoming-request modal names the routed destinations instead of the plain save directory, so the folders the files will actually land in are visible before pressing A — one line per folder when the save routes spread a request over several, up to four before the rest collapse into a count.
  • X in the send browser selects every file of the current folder (and clears them again), so a folder full of saves goes out without walking the list. Subfolders stay out: the protocol only carries a flat list of files.
  • Pinned paths: Y in the file browser pins the folder or file under the cursor, and pinned rows lead every listing — a pinned folder is one press away from anywhere in the tree, a pinned file can be sent without navigating ([transfer] pinned_paths). The send browser also reopens where the last send came from ([transfer] last_send_dir).
  • Automatic save routes: received ROMs are sorted into the console folders that already exist in the save directory, using the folder names KNULLI, ROCKNIX, and muOS each actually use. Nothing is created, and only extensions that name exactly one console take part. Toggled from Settings → Auto save routes ([transfer] auto_routes, on by default); explicit [transfer.routes] entries still win.

0.1.0 - 2026-07-28

Initial release. A Rust LocalSend client built for handheld and gamepad-first use (Knulli, muOS, ROCKNIX), running on desktop Linux too.

Added

  • LocalSend protocol v2.1: multicast announce and /register discovery, shown as a live radar of nearby devices.
  • Receive flow: accept/decline dialog with countdown, progress with speed and ETA, and cancel from either side; quick-save mode auto-accepts.
  • Send flow: gamepad file browser with multi-select and switchable roots, staged files, a waiting phase, and per-file progress.
  • Encryption: the protocol's HTTPS mode, on by default — a self-signed identity generated once and served via rustls, announced as the certificate's SHA-256 fingerprint. Works with the official app's defaults both ways.
  • Save routes: received files sorted into folders by extension, editable on the device from Settings → Save routes.
  • Settings on device: alias, save folder, and port, applied live — the network layer restarts on a port change.
  • History tab: persisted transfer log with a configurable limit.
  • On-screen keyboard (3-layer grid) for text entry without a keyboard.
  • Tabbed navigation (Send, Receive, History, Settings) and an about overlay.
  • Headless --receive mode for SSH and scripting.
  • Streaming writes with sanitized names, one transfer at a time, and a sweep of stale .part files at startup.
  • Brand wordmark and window icon.
  • Builds for Linux x86_64 and aarch64, with PortMaster packaging.