feat: add TV Quick Connect to connection page for Android TV / Apple TV

When user selects Android TV or Apple TV platform (from non-TV device),
shows 5-char code input + QR scanner to send subscription to TV via
Happ TV API. Hybrid QR strategy: native Telegram scanner on mobile,
html5-qrcode CDN fallback on desktop. i18n keys for ru/en/zh/fa.

Based on PR #415 by @smediainfo.
This commit is contained in:
Fringg
2026-05-04 06:22:29 +03:00
parent d21c6637bf
commit 65f94931c5
6 changed files with 444 additions and 3 deletions

View File

@@ -11,6 +11,7 @@ import type {
import { useTheme } from '@/hooks/useTheme';
import { CardsBlock, TimelineBlock, AccordionBlock, MinimalBlock, BlockButtons } from './blocks';
import type { BlockRendererProps } from './blocks';
import TvQuickConnect from './TvQuickConnect';
const platformOrder = ['ios', 'android', 'windows', 'macos', 'linux', 'androidTV', 'appleTV'];
@@ -145,6 +146,12 @@ export default function InstallationGuide({
],
);
const selectedIsTv =
(activePlatformKey || availablePlatforms[0]) === 'androidTV' ||
(activePlatformKey || availablePlatforms[0]) === 'appleTV';
const userIsOnTv = detectedPlatform === 'androidTV' || detectedPlatform === 'appleTV';
const isTvPlatform = selectedIsTv && !userIsOnTv;
const currentPlatformKey = activePlatformKey || availablePlatforms[0];
const currentPlatformData = currentPlatformKey
? (appConfig.platforms[currentPlatformKey] as RemnawavePlatformData | undefined)
@@ -328,8 +335,32 @@ export default function InstallationGuide({
</a>
)}
{/* Blocks */}
{selectedApp && (
{/* Blocks — for TV: first block, Quick Connect, last block */}
{selectedApp && isTvPlatform && appConfig.subscriptionUrl ? (
<>
{selectedApp.blocks.length > 0 && (
<Renderer
blocks={selectedApp.blocks.slice(0, 1)}
isMobile={isMobile}
isLight={isLight}
getLocalizedText={getLocalizedText}
getSvgHtml={getSvgHtml}
renderBlockButtons={renderBlockButtons}
/>
)}
<TvQuickConnect subscriptionUrl={appConfig.subscriptionUrl} isLight={isLight} />
{selectedApp.blocks.length > 1 && (
<Renderer
blocks={selectedApp.blocks.slice(-1)}
isMobile={isMobile}
isLight={isLight}
getLocalizedText={getLocalizedText}
getSvgHtml={getSvgHtml}
renderBlockButtons={renderBlockButtons}
/>
)}
</>
) : selectedApp ? (
<Renderer
blocks={selectedApp.blocks}
isMobile={isMobile}
@@ -338,7 +369,7 @@ export default function InstallationGuide({
getSvgHtml={getSvgHtml}
renderBlockButtons={renderBlockButtons}
/>
)}
) : null}
</div>
);
}