Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions .github/workflows/v2-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
4 changes: 4 additions & 0 deletions v2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion v2/crates/core/data/app-lists/launchers.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
9 changes: 9 additions & 0 deletions v2/crates/core/src/commands/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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!(
Expand Down
4 changes: 2 additions & 2 deletions v2/crates/core/src/engine/launcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<String>,
Expand Down
7 changes: 7 additions & 0 deletions v2/screenshots/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
Binary file modified v2/screenshots/gallery-light.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified v2/screenshots/gallery.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion v2/src/lib/demo-mock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 },
Expand Down
5 changes: 2 additions & 3 deletions v2/src/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
22 changes: 9 additions & 13 deletions v2/src/routes/devices/[serial]/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -2654,19 +2654,6 @@
>
{busy ? "Opening…" : "Open Play Store on TV"}
</button>
<!-- The Play Store button drives the TV's own store, which
is no help for a launcher that store doesn't carry. This
opens the launcher's official page here instead; it
downloads and installs nothing. -->
{#if l.entry.source_url}
<button
class="small-action subtle launcher-get"
onclick={() => openInBrowser(l.entry.source_url ?? "")}
data-tip="Opens the developer's page in your browser, for launchers the TV's Play Store doesn't carry"
data-tip-align="end"
aria-label="Open the developer's page for {l.entry.name} in your browser"
><Icon name="open_in_new" size={14} /> <span>Source site</span></button>
{/if}
{:else}
{#if !l.enabled}
<button
Expand Down Expand Up @@ -2710,6 +2697,15 @@
>Current default</span>
{/if}
{/if}
{#if l.entry.source_url}
<button
class="small-action subtle launcher-get"
onclick={() => openInBrowser(l.entry.source_url ?? "")}
data-tip="Opens the developer's page in your browser. Nothing is downloaded, uninstalled, or changed on the TV."
data-tip-align="end"
aria-label="Open the developer's page for {l.entry.name} in your browser"
><Icon name="open_in_new" size={14} /> <span>Source site</span></button>
{/if}
</div>
</li>
{/each}
Expand Down
8 changes: 8 additions & 0 deletions v2/tests/launcher-rows.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Loading