From 6c27125fff32dea9a27553b2aaee60cbc9a96002 Mon Sep 17 00:00:00 2001 From: rgdevment Date: Thu, 24 Sep 2026 00:50:21 -0300 Subject: [PATCH 1/2] feat: the star is asked for where it counts, and the readme shows the picker working A copy the Store sold was being asked for a star on GitHub, which does nothing there. What decides whether anybody searching the Store ever finds this is the rating, so that is what such a copy is asked for now, and the card offering the other one steps aside so the same favour is not asked twice. The table of alternatives said Choosy runs on Windows. It does not, it is macOS only, and its site has moved besides. Browserino and Switchbar were missing, and Browserosaurus does more than sit unmaintained: it sends its own readers to Browserino, which is what the paragraph now says. Teams and Outlook each carry a setting that hands links to the default browser, and the answer about them went straight to the channel nobody can intercept without mentioning it. Most people arriving at that question can fix it without installing anything; they are told so first. The header image is the one drawn for it, and What It Does opens with the picker actually working: a link clicked inside a desktop application, the picker naming where it came from, the browser chosen. What the other screenshots would have shown is said in a line of prose instead, which costs a reader nothing to scroll past. --- README.md | 20 +++++++++---- app/src/settings/About.tsx | 13 ++++++--- app/src/settings/Star.test.tsx | 30 +++++++++++++++++++- app/src/settings/Star.tsx | 9 ++++-- resources/assets/github-en/a-dark.png | Bin 0 -> 161371 bytes resources/assets/github-en/b-blue.png | Bin 0 -> 186427 bytes resources/assets/github-es/a-oscuro.png | Bin 0 -> 161946 bytes resources/assets/github-es/b-azul.png | Bin 0 -> 190941 bytes resources/assets/linkUnbound_2_picker.gif | Bin 0 -> 102638 bytes resources/assets/store-en/01-picker.png | Bin 0 -> 282846 bytes resources/assets/store-en/02-rules.png | Bin 0 -> 246839 bytes resources/assets/store-en/03-privacy.png | Bin 0 -> 284911 bytes resources/assets/store-es/01-selector.png | Bin 0 -> 286942 bytes resources/assets/store-es/02-reglas.png | Bin 0 -> 247378 bytes resources/assets/store-es/03-privacidad.png | Bin 0 -> 289893 bytes 15 files changed, 59 insertions(+), 13 deletions(-) create mode 100644 resources/assets/github-en/a-dark.png create mode 100644 resources/assets/github-en/b-blue.png create mode 100644 resources/assets/github-es/a-oscuro.png create mode 100644 resources/assets/github-es/b-azul.png create mode 100644 resources/assets/linkUnbound_2_picker.gif create mode 100644 resources/assets/store-en/01-picker.png create mode 100644 resources/assets/store-en/02-rules.png create mode 100644 resources/assets/store-en/03-privacy.png create mode 100644 resources/assets/store-es/01-selector.png create mode 100644 resources/assets/store-es/02-reglas.png create mode 100644 resources/assets/store-es/03-privacidad.png diff --git a/README.md b/README.md index a045194..47af3f2 100644 --- a/README.md +++ b/README.md @@ -26,7 +26,7 @@

- LinkUnbound: the settings window on the Rules page, and the browser picker that appears next to a link with the browsers, their profiles and the keys 1 to 3 + LinkUnbound: choose which browser opens every link. The picker sits next to the link, listing Google Chrome, Mozilla Firefox and Vivaldi with the profiles each one carries

Download LinkUnbound

@@ -87,6 +87,12 @@ There is no company behind this. I am one developer who got tired of the operati ## What It Does +

+ A link is clicked inside a desktop application; the picker opens beside the cursor naming the address and the application it came from, and the link opens in the browser chosen +

+ +The picker names the address and the application the link came from, and each browser carries the profile it will open in. The settings window covers the rest: the rules and how they are matched, the browsers it found and the ones you add by hand, the diagnostic report, and what is kept on disk. + - **Registers as default browser** — intercepts every link click system-wide on Windows and macOS - **Shows a floating picker** near your cursor, in two looks: a classic list or a mosaic of tiles. Pick with the mouse or the keys `1`–`9`; hold **Shift** for a private window; `Ctrl+C` copies the address; `Esc` puts it away - **Remembers the choice at the reach you pick** — this URL, this subdomain, the whole site, or everything a given app sends @@ -234,7 +240,9 @@ Yes. LinkUnbound detects all browsers registered with the operating system. You Yes. LinkUnbound unwraps SafeLinks before matching rules, so your rules work on the actual destination — and the picker names it, not the wrapper. **Why do Teams and Outlook still open Edge?** -Some Microsoft applications hand links straight to Edge down a channel of their own, skipping the default browser, and Windows 11 no longer lets another application stand in the middle of it. When one of those links arrives wrapped in a SafeLink it is unwrapped; the rest is Microsoft's to change. +Both carry a setting of their own that sends links to whatever your default browser is, and that is the first thing to change: in Teams it lives under *Settings → Files and links*, and in classic Outlook under *File → Options → Advanced → «Open hyperlinks from Outlook in»*. Microsoft moves these menus about, so look for «link open preference» or «hyperlinks» if they are not where this says. Set that way, their links reach LinkUnbound like anybody else's. + +What is left after that is a channel of Microsoft's own that hands links straight to Edge, skipping the default browser altogether, and Windows 11 no longer lets another application stand in the middle of it. When one of those arrives wrapped in a SafeLink it is unwrapped; the rest is Microsoft's to change. **I do not see the tray icon on Windows.** It is there, in the hidden icons behind the `^` at the right of the taskbar: Windows keeps every new application's icon in that overflow until you drag it onto the bar, or promote it under Settings → Personalization → Taskbar → Other system tray icons. Closing the settings window never stops the resident; only *Exit* in the tray menu does. @@ -301,14 +309,16 @@ Other browser pickers, so you can pick the one that fits. Platform and licence c | Project | Platform | Licence | | :-- | :-- | :-- | | [Finicky](https://github.com/johnste/finicky) | macOS | MIT | -| [Browserosaurus](https://github.com/will-stone/browserosaurus) | macOS | GPL-3.0, archived by its author | +| [Browserino](https://github.com/AlexStrNik/Browserino) | macOS | GPL-3.0 | +| [Browserosaurus](https://github.com/will-stone/browserosaurus) | macOS | GPL-3.0, no longer maintained | | [BrowserPicker](https://github.com/mortenn/BrowserPicker) | Windows | MIT | | [Browser Tamer](https://github.com/aloneguid/bt) | Windows, Linux | Apache-2.0 | | [Junction](https://github.com/sonnyp/Junction) | Linux | GPL-3.0 | -| [Choosy](https://www.choosyosx.com/) | macOS, Windows | Paid | +| [Switchbar](https://switchbar.app/) | Windows, macOS | Freemium, closed source | +| [Choosy](https://choosy.app/) | macOS | Paid | | [Velja](https://sindresorhus.com/velja) | macOS | Free, closed source | -What LinkUnbound does that most of these do not: **one build for Windows and macOS**, rules that match **the app a link came from** and not only its address, **browser profiles** detected on their own, and signed automatic updates. Finicky is configured in a file and is macOS only; Browserosaurus is no longer maintained; Junction is Linux only. +What LinkUnbound does that most of these do not: **one build for Windows and macOS**, rules that match **the app a link came from** and not only its address, **browser profiles** detected on their own, and signed automatic updates. Finicky is configured in a file and is macOS only; Junction is Linux only; Browserosaurus now points its own readers at Browserino, which is macOS only too. --- diff --git a/app/src/settings/About.tsx b/app/src/settings/About.tsx index 464dfaf..987e297 100644 --- a/app/src/settings/About.tsx +++ b/app/src/settings/About.tsx @@ -293,6 +293,11 @@ export default function About({ useEffect(look, [look]); + const store = build?.keptByTheStore ?? false; + const offerStar = !starring || store; + const offerRate = store && !starring; + const lopsided = (offerStar ? 1 : 0) + (offerRate ? 1 : 0) === 1; + return ( <>
@@ -357,14 +362,14 @@ export default function About({ /> )} - {starring && } + {starring && }

{t("aboutSupportWhy")}

- {!starring && ( + {offerStar && ( void openUrl(REPO).catch(noop)} @@ -375,7 +380,7 @@ export default function About({ /> )} - {build?.keptByTheStore && ( + {offerRate && ( { invoke.mockReset(); invoke.mockResolvedValue(null); settled.mockReset(); - render(); + render(); }); it("opens the repository and is never asked for again", async () => { @@ -53,3 +53,31 @@ describe("the card that asks for a star", () => { expect(settled).toHaveBeenCalled(); }); }); + +/// The star does nothing for a copy the Store sold: what decides whether anybody searching the +/// Store ever sees this is the rating, and that is what such a copy has to be asked for. +describe("the same card in a copy the Store sold", () => { + beforeEach(() => { + opened.length = 0; + invoke.mockReset(); + invoke.mockResolvedValue(null); + settled.mockReset(); + render(); + }); + + it("asks for the rating, and opens the Store rather than the repository", async () => { + expect(screen.queryByRole("button", { name: "Dar una estrella" })).toBeNull(); + await userEvent.click(said("Valorar en la Store")); + + expect(opened).toEqual(["ms-windows-store://review/?ProductId=9N9F7C8Q43KC"]); + expect(invoke).toHaveBeenCalledWith("star_done"); + expect(settled).toHaveBeenCalled(); + }); + + it("is retired the same way when the answer is no", async () => { + await userEvent.click(said("No mostrar más")); + + expect(opened).toEqual([]); + expect(invoke).toHaveBeenCalledWith("star_done"); + }); +}); diff --git a/app/src/settings/Star.tsx b/app/src/settings/Star.tsx index 0c0817b..f931735 100644 --- a/app/src/settings/Star.tsx +++ b/app/src/settings/Star.tsx @@ -3,14 +3,17 @@ import { openUrl } from "@tauri-apps/plugin-opener"; import { useWords } from "../i18n"; const REPO = "https://github.com/rgdevment/LinkUnbound"; +const RATING = "ms-windows-store://review/?ProductId=9N9F7C8Q43KC"; -export default function Star({ onSettled }: { onSettled: () => void }) { +/// A copy the Store sold is asked for the rating instead of the star: the rating is what decides +/// whether anybody searching the Store ever sees this, and the star does nothing there. +export default function Star({ store, onSettled }: { store: boolean; onSettled: () => void }) { const t = useWords(); const settle = (open: boolean) => { onSettled(); void invoke("star_done").catch(noop); - if (open) void openUrl(REPO).catch(noop); + if (open) void openUrl(store ? RATING : REPO).catch(noop); }; return ( @@ -39,7 +42,7 @@ export default function Star({ onSettled }: { onSettled: () => void }) { onClick={() => settle(true)} className="rounded-md bg-[#2F62D8] px-3 py-1.5 text-[11.5px] font-medium text-white dark:bg-[#6E9BFF] dark:text-[#12141B]" > - {t("starGo")} + {t(store ? "aboutRate" : "starGo")}