Skip to content

feat: Share game link to a friend#2149

Open
anton3x wants to merge 4 commits intohydralauncher:mainfrom
anton3x:main
Open

feat: Share game link to a friend#2149
anton3x wants to merge 4 commits intohydralauncher:mainfrom
anton3x:main

Conversation

@anton3x
Copy link
Copy Markdown

@anton3x anton3x commented Apr 14, 2026

When submitting this pull request, I confirm the following (please check the boxes):

  • I have read the Hydra documentation.
  • I have checked that there are no duplicate pull requests related to this request.
  • I have considered, and confirm that this submission is valuable to others.
  • I accept that this submission may not be used and the pull request may be closed at the discretion of the maintainers.

Fill in the PR content:

This PR solves #1994 by adding a way to share a game with another Hydra user through Hydra’s existing deep link support. The goal is to make sharing a game faster and more direct, so instead of asking someone to manually search for a title, the sender can copy a link and send them straight to the same game page in Hydra.

The generated link uses the hydralauncher://game format and includes the information needed to identify the shared repack, such as the game provider, the game ID, the repack ID, and the source URL. For example:

hydralauncher://game?shop=steam&objectId=3590&repackId=n00mN8Jn&sourceUrl=https%3A%2F%2Fhydralinks.cloud%2Fsources%2Ffitgirl.json

With this, Hydra can open the correct game details page and try to point the recipient to the same release that was originally shared.

On the sender side, the share action is available from the game details hero actions. Hydra generates the link using the current download data by matching the installed download with the corresponding repack and resolving the source URL from that repack. The deep link is then copied to the clipboard so it can be sent to a friend.

On the recipient side, opening the link launches or focuses Hydra, parses the deep link, and navigates to the existing game details route. If a repackId is present, the repacks modal opens automatically. When the repack exists locally, it is highlighted with a Shared by friend badge so the user can easily identify the intended release. If the repack is not available because the required source is missing, the game page still opens normally, but the modal shows a warning and provides an action to add the shared source through Hydra’s existing add-source flow.

image image image image image

Copilot AI review requested due to automatic review settings April 14, 2026 17:14
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a “share game” flow that generates a hydralauncher://game?... deep link for a specific repack/source, copies it to clipboard, and supports opening the repacks modal + guiding the recipient to add a missing download source.

Changes:

  • Add Share action in the game details hero panel that copies a deep link to the clipboard.
  • Extend deep link handling in the main process to route hydralauncher://game URIs to the game details page (including repack/source query params).
  • Update repacks modal to (a) auto-highlight a shared repack and (b) show a “missing source” warning with a CTA to add the shared source; add i18n strings across locales.

Reviewed changes

Copilot reviewed 40 out of 40 changed files in this pull request and generated 6 comments.

Show a summary per file
File Description
src/renderer/src/pages/game-details/modals/repacks-modal.tsx Accepts shared repack/source params, shows missing-source warning, and adds “shared by friend” badge.
src/renderer/src/pages/game-details/modals/repacks-modal.scss Styles for the missing-source warning section in the repacks modal.
src/renderer/src/pages/game-details/hero/hero-panel-actions.tsx Adds Share button and deep-link generation/copy logic.
src/renderer/src/pages/game-details/game-details.tsx Passes deep link query params down to the repacks modal.
src/renderer/src/pages/game-details/game-details-content.tsx Auto-opens repacks modal when repackId is present in the URL.
src/renderer/src/context/game-details/game-details.context.types.ts Adds getDownloadSourceById to the game details context interface.
src/renderer/src/context/game-details/game-details.context.tsx Loads download sources into context state and exposes getDownloadSourceById.
src/main/index.ts Adds main-process deep link parsing/redirect for hydralauncher://game.
src/locales/ar/translation.json Adds new i18n strings for share flow.
src/locales/be/translation.json Adds new i18n strings for share flow.
src/locales/bg/translation.json Adds new i18n strings for share flow.
src/locales/ca/translation.json Adds new i18n strings for share flow.
src/locales/cs/translation.json Adds new i18n strings for share flow.
src/locales/da/translation.json Adds new i18n strings for share flow.
src/locales/de/translation.json Adds new i18n strings for share flow.
src/locales/en/translation.json Adds new i18n strings for share flow (source-missing warning, shared badge, clipboard toast).
src/locales/es/translation.json Adds new i18n strings for share flow.
src/locales/et/translation.json Adds new i18n strings for share flow.
src/locales/fa/translation.json Adds new i18n strings for share flow.
src/locales/fi/translation.json Adds new i18n strings for share flow.
src/locales/fr/translation.json Adds new i18n strings for share flow.
src/locales/hu/translation.json Adds new i18n strings for share flow.
src/locales/id/translation.json Adds new i18n strings for share flow.
src/locales/it/translation.json Adds new i18n strings for share flow.
src/locales/kk/translation.json Adds new i18n strings for share flow.
src/locales/ko/translation.json Adds new i18n strings for share flow.
src/locales/lv/translation.json Adds new i18n strings for share flow.
src/locales/nb/translation.json Adds new i18n strings for share flow.
src/locales/nl/translation.json Adds new i18n strings for share flow.
src/locales/pl/translation.json Adds new i18n strings for share flow.
src/locales/pt-BR/translation.json Adds new i18n strings for share flow.
src/locales/pt-PT/translation.json Adds new i18n strings for share flow.
src/locales/ro/translation.json Adds new i18n strings for share flow.
src/locales/ru/translation.json Adds new i18n strings for share flow.
src/locales/sl/translation.json Adds new i18n strings for share flow.
src/locales/sv/translation.json Adds new i18n strings for share flow.
src/locales/tr/translation.json Adds new i18n strings for share flow.
src/locales/uk/translation.json Adds new i18n strings for share flow.
src/locales/uz/translation.json Adds new i18n strings for share flow.
src/locales/zh/translation.json Adds new i18n strings for share flow.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +35 to +51
&__shared-source-warning {
display: flex;
align-items: center;
justify-content: space-between;
gap: calc(globals.$spacing-unit * 2);
padding: calc(globals.$spacing-unit * 1.5) calc(globals.$spacing-unit * 2);
margin-bottom: calc(globals.$spacing-unit * 2);
border-radius: 8px;
background: var(--color-background-light);
border: 1px solid rgba(globals.$warning-color, 0.35);
}

&__shared-source-warning-text {
margin: 0;
color: globals.$body-color;
font-size: globals.$small-font-size;
}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this SCSS block, the indentation/nesting formatting is inconsistent with the rest of the .repacks-modal BEM selectors in this file (properties and the &__shared-source-warning-text selector aren’t aligned like the surrounding sections). This is likely to be reformatted by Prettier/stylelint and can cause noisy diffs—please re-indent to match the existing pattern used above (e.g., &__repacks, &__filter-top).

Copilot uses AI. Check for mistakes.
Comment on lines +172 to +174
const downloadedRepack = repacks.find((repack) =>
repack.uris.includes(downloadUri)
);
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The repack lookup for the currently-downloaded URI uses an exact match (repack.uris.includes(downloadUri)), but elsewhere (e.g., the “last downloaded option” badge logic) the code uses a substring match. If game.download.uri is only a substring of the repack URI, this will fail to find the repack and sharing will silently do nothing. Consider aligning this matching logic with checkIfLastDownloadedOption (use a .some(uri => uri.includes(downloadUri))-style check) so share works reliably.

Copilot uses AI. Check for mistakes.
Comment on lines +165 to +182
const toggleShareGame = async () => {
if (!game?.download?.uri) return;

const downloadUri = game.download.uri;
setToggleLibraryGameDisabled(true);

try {
const downloadedRepack = repacks.find((repack) =>
repack.uris.includes(downloadUri)
);

if (!downloadedRepack) return;

const source = getDownloadSourceById(downloadedRepack.downloadSourceId);
const sourceUrl = source?.url;

if (!sourceUrl) return;

Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toggleShareGame can early-return in several cases (no matching repack, download sources not loaded yet, missing source URL), but the UI provides no feedback to the user. Since this is a user-initiated action, consider showing an error toast (or disabling/hiding the share action until the required data is available) so the user understands why nothing was copied.

Copilot uses AI. Check for mistakes.
Comment on lines +327 to +336
{game.download && (
<Button
onClick={toggleShareGame}
theme="outline"
disabled={deleting}
className="hero-panel-actions__action"
>
<ShareIcon />
</Button>
)}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The share button sets toggleLibraryGameDisabled while generating/copying the link, but the button itself is only disabled by deleting. This means users can repeatedly click Share while the async operation is in flight. Consider including toggleLibraryGameDisabled in the disabled condition (or use a dedicated isSharing state) to prevent duplicate clicks and make the disabled state consistent with the handler.

Copilot uses AI. Check for mistakes.
Comment on lines 60 to 69
const {
objectId,
shopDetails,
game,
hasNSFWContentBlocked,
shop,
setShowGameOptionsModal,
setGameOptionsInitialCategory,
setShowRepacksModal
} = useContext(gameDetailsContext);
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a couple of formatting issues here that don’t match the surrounding code style: missing trailing comma in the context destructuring and missing semicolon/newline consistency. This is likely to be flagged by formatting/lint tooling—please run the formatter or align with the existing style in this file (commas/semicolons).

Copilot uses AI. Check for mistakes.
Comment on lines +149 to +152
const repackId = searchParams.get("repackId");
if (repackId) {
setShowRepacksModal(true)
}
Copy link

Copilot AI Apr 14, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing semicolon after setShowRepacksModal(true) (and the effect body’s formatting) is inconsistent with the rest of the file’s semicolon usage. This can cause lint/format CI failures; please format this block to match the surrounding style.

Copilot uses AI. Check for mistakes.
@anton3x anton3x marked this pull request as draft April 14, 2026 17:24
@anton3x anton3x marked this pull request as draft April 14, 2026 17:24
@sonarqubecloud
Copy link
Copy Markdown

@anton3x anton3x marked this pull request as ready for review April 14, 2026 18:30
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants