diff --git a/.github/workflows/v2-tests.yml b/.github/workflows/v2-tests.yml index 409c78d..08bc3a8 100644 --- a/.github/workflows/v2-tests.yml +++ b/.github/workflows/v2-tests.yml @@ -228,6 +228,22 @@ jobs: working-directory: v2 run: npm run test:context-menu + # Reviewable UI frames also allow gallery regeneration without a local browser. + - name: Capture demo screenshots + working-directory: v2 + run: node screenshots/capture.mjs + + - name: Upload demo screenshots + if: always() + uses: actions/upload-artifact@v4 + with: + name: desktop-demo-frames + path: | + v2/screenshots/frames/ + v2/screenshots/frames-light/ + retention-days: 7 + if-no-files-found: ignore + # The real Rust command layer against simulated devices, with Playwright # driving the real UI. See v2/e2e/README.md. e2e: diff --git a/v2/CHANGELOG.md b/v2/CHANGELOG.md index 566f761..1ff8bc5 100644 --- a/v2/CHANGELOG.md +++ b/v2/CHANGELOG.md @@ -22,6 +22,10 @@ this file and shows the newest few sections, dated, from its version button. ## Unreleased +### Fixed + +- Launcher source pages remain available for installed and current-default launchers. Projectivy links to its official GitHub releases; opening the page never uninstalls or changes the current launcher (#161). + ## v2-2.3.1 — 2026-10-04 Fixes for Google TV launcher switching (#122, #157, #158): Setup Wraith, Google TV's setup diff --git a/v2/crates/core/data/app-lists/launchers.json b/v2/crates/core/data/app-lists/launchers.json index c271502..053c0d2 100644 --- a/v2/crates/core/data/app-lists/launchers.json +++ b/v2/crates/core/data/app-lists/launchers.json @@ -3,7 +3,7 @@ { "name": "Projectivy Launcher", "package": "com.spocky.projengmenu", - "source_url": "https://play.google.com/store/apps/details?id=com.spocky.projengmenu" + "source_url": "https://github.com/spocky/miproja1/releases" }, { "name": "FLauncher", diff --git a/v2/crates/core/src/commands/loader.rs b/v2/crates/core/src/commands/loader.rs index 9a8df23..5f2d487 100644 --- a/v2/crates/core/src/commands/loader.rs +++ b/v2/crates/core/src/commands/loader.rs @@ -422,6 +422,15 @@ mod tests { #[test] fn every_custom_launcher_has_a_source_url_and_no_package_repeats() { let cat = load_embedded_launchers().expect("parse"); + let projectivy = cat + .custom + .iter() + .find(|entry| entry.package == "com.spocky.projengmenu") + .expect("Projectivy"); + assert_eq!( + projectivy.source_url.as_deref(), + Some("https://github.com/spocky/miproja1/releases") + ); let mut seen = std::collections::HashSet::new(); for entry in cat.custom.iter().chain(cat.stock.iter()) { assert!( diff --git a/v2/crates/core/src/engine/launcher.rs b/v2/crates/core/src/engine/launcher.rs index 6f9d0d0..5e89e67 100644 --- a/v2/crates/core/src/engine/launcher.rs +++ b/v2/crates/core/src/engine/launcher.rs @@ -12,8 +12,8 @@ use serde::{Deserialize, Serialize}; pub struct LauncherEntry { pub name: String, pub package: String, - /// Where to get it when it isn't installed — the launcher's own official - /// page. `None` for stock launchers, which ship with the device, and for + /// The launcher's official source page, also useful when already installed. + /// `None` for stock launchers, which ship with the device, and for /// HOME handlers discovered on the device rather than read from the file. #[serde(default)] pub source_url: Option, diff --git a/v2/screenshots/README.md b/v2/screenshots/README.md index 6073397..edbac63 100644 --- a/v2/screenshots/README.md +++ b/v2/screenshots/README.md @@ -24,6 +24,13 @@ The demo data is a faithful Nvidia Shield — real package names, the real launc `frames/` and `frames-light/` are gitignored (regenerable). Only `gallery.gif` and `gallery-light.gif` are committed. +## Pull-request visual review + +The frontend CI job captures both theme frame sets and publishes the `desktop-demo-frames` +artifact for review. Download it into this directory, inspect the changed screens, then run +`bash build-gif.sh` and commit both generated galleries. Captures use demo data only; they do +not connect to a device. CI leaves the branch unchanged. + ## Automatic regeneration on release The `refresh-screenshots` job in [`../../.github/workflows/v2-release.yml`](../../.github/workflows/v2-release.yml) reruns this whole pipeline on every `v2-*` tag and commits the refreshed `gallery.gif` + `gallery-light.gif` back to the default branch — so a release never ships stale screenshots. Those captures render on Linux (font stack falls through to Roboto rather than macOS's `-apple-system`), so the release-generated GIF can look subtly different from one you regenerate locally on a Mac. Both are fine; it's the same UI. diff --git a/v2/screenshots/gallery-light.gif b/v2/screenshots/gallery-light.gif index e52747a..8e41448 100644 Binary files a/v2/screenshots/gallery-light.gif and b/v2/screenshots/gallery-light.gif differ diff --git a/v2/screenshots/gallery.gif b/v2/screenshots/gallery.gif index 9830d6e..901ab19 100644 Binary files a/v2/screenshots/gallery.gif and b/v2/screenshots/gallery.gif differ diff --git a/v2/src/lib/demo-mock.ts b/v2/src/lib/demo-mock.ts index 7a0d870..0f4096c 100644 --- a/v2/src/lib/demo-mock.ts +++ b/v2/src/lib/demo-mock.ts @@ -314,7 +314,7 @@ const launchers: LauncherStatus[] = [ other: false, setup_helper: false, }, - { entry: { name: "Projectivy Launcher", package: "com.spocky.projengmenu", source_url: playStore("com.spocky.projengmenu") }, installed: true, enabled: true, stock: false, other: false, setup_helper: false }, + { entry: { name: "Projectivy Launcher", package: "com.spocky.projengmenu", source_url: "https://github.com/spocky/miproja1/releases" }, installed: true, enabled: true, stock: false, other: false, setup_helper: false }, { entry: { name: "FLauncher", package: "me.efesser.flauncher", source_url: playStore("me.efesser.flauncher") }, installed: true, enabled: true, stock: false, other: false, setup_helper: false }, { entry: { name: "ATV Launcher", package: "com.sweech.launcher", source_url: playStore("com.sweech.launcher") }, installed: false, enabled: false, stock: false, other: false, setup_helper: false }, { entry: { name: "Wolf Launcher", package: "com.wolf.firelauncher", source_url: playStore("com.wolf.firelauncher") }, installed: false, enabled: false, stock: false, other: false, setup_helper: false }, diff --git a/v2/src/lib/types.ts b/v2/src/lib/types.ts index 2d5c995..62a15b7 100644 --- a/v2/src/lib/types.ts +++ b/v2/src/lib/types.ts @@ -82,9 +82,8 @@ export interface AppStorage { export interface LauncherEntry { name: string; package: string; - /// The launcher's official page, for the "Get" link on a row that isn't - /// installed. Null for stock launchers and for HOME handlers found on the - /// device rather than in the catalog. + /// The launcher's official source page, available even when installed. + /// Null for stock launchers and HOME handlers outside the catalog. source_url: string | null; /// Setup helpers (Setup Wraith) a takeover turns off together with this /// stock launcher. Present only on a stock entry that has one. diff --git a/v2/src/routes/devices/[serial]/+page.svelte b/v2/src/routes/devices/[serial]/+page.svelte index e54291e..a1a5dc0 100644 --- a/v2/src/routes/devices/[serial]/+page.svelte +++ b/v2/src/routes/devices/[serial]/+page.svelte @@ -2654,19 +2654,6 @@ > {busy ? "Opening…" : "Open Play Store on TV"} - - {#if l.entry.source_url} - - {/if} {:else} {#if !l.enabled} + {/if} {/each} diff --git a/v2/tests/launcher-rows.mjs b/v2/tests/launcher-rows.mjs index b1dd44a..290ea30 100644 --- a/v2/tests/launcher-rows.mjs +++ b/v2/tests/launcher-rows.mjs @@ -52,6 +52,14 @@ async function launcherTab(page) { const homeAppRows = await rows.filter({ has: page.locator(".tag", { hasText: "HOME APP" }) }).count(); assert.equal(homeAppRows, 0, "no ordinary app is badged HOME APP in the demo"); + const currentProjectivy = rows.filter({ has: page.locator(".launcher-pkg", { hasText: "com.spocky.projengmenu" }) }); + assert.equal(await currentProjectivy.locator(".current-default").count(), 1); + assert.equal( + await currentProjectivy.getByRole("button", { name: "Open the developer's page for Projectivy Launcher in your browser" }).count(), + 1, + "the current default keeps its source link without offering to disable it", + ); + // The Advanced picker lists every installed app, so the leanback-only app is // reachable there — proof the fixture has it and the list above left it out. await page.locator("details.home-picker summary").click();