'use client'; import { useEffect, useMemo, useState } from 'react'; import Link from 'next/link'; import { ArrowRight, Download, ShieldCheck, Smartphone, Sparkles } from 'lucide-react'; import { BrandLogo } from '@/components/id/brand-logo'; import { usePublicSettings } from '@/components/id/public-settings-provider'; import { Button } from '@/components/ui/button'; import { AppRelease, buildAppReleaseDownloadUrl, fetchPublicAppReleases } from '@/lib/api'; import { formatReleaseVariantLabel, groupReleasesByVersion } from '@/lib/app-release-variants'; function formatBytes(value: string) { const size = Number(value); if (!Number.isFinite(size) || size <= 0) return '—'; const units = ['Б', 'КБ', 'МБ', 'ГБ']; let amount = size; let unit = 0; while (amount >= 1024 && unit < units.length - 1) { amount /= 1024; unit += 1; } return `${amount.toFixed(amount >= 10 || unit === 0 ? 0 : 1)} ${units[unit]}`; } function formatDate(value: string) { return new Intl.DateTimeFormat('ru-RU', { day: '2-digit', month: 'long', year: 'numeric' }).format(new Date(value)); } export default function DownloadsPage() { const { projectName } = usePublicSettings(); const [releases, setReleases] = useState([]); const [loading, setLoading] = useState(true); useEffect(() => { void (async () => { try { const response = await fetchPublicAppReleases('ANDROID'); setReleases(response.releases ?? []); } finally { setLoading(false); } })(); }, []); const groupedReleases = useMemo( () => groupReleasesByVersion(releases.filter((item) => item.platform === 'ANDROID')), [releases] ); const latestGroup = groupedReleases[0] ?? null; const latestVariants = latestGroup?.variants ?? []; const preferredLatest = latestVariants.find((item) => item.variant === 'universal') ?? latestVariants[0] ?? null; return (
Официальная сборка {projectName}

Скачайте приложение

Актуальная версия для Android. Доступны разные сборки: universal, arm64-v8a и другие. Каждый файл подписан SHA-256.

Android

Выберите подходящую сборку APK

{loading ? (

Проверяем доступные версии...

) : latestGroup && preferredLatest ? ( <>

Последняя версия

v{latestGroup.version} build {latestGroup.versionCode} {latestVariants.length > 1 ? ( {latestVariants.length} сборки ) : null}

{formatDate(preferredLatest.createdAt)}

{preferredLatest.releaseNotes ? (

{preferredLatest.releaseNotes}

) : null}
{latestVariants.map((release) => (

{formatReleaseVariantLabel(release.variant)}

{formatBytes(release.fileSize)} · {release.fileName}

))}
) : (

Сборка для Android пока не опубликована.

)}

История версий

{loading ? (

Загружаем список версий...

) : groupedReleases.length ? ( groupedReleases.map((group, groupIndex) => (
v{group.version} build {group.versionCode} {groupIndex === 0 ? ( Актуальная ) : null}
{group.variants.map((release) => (

{formatReleaseVariantLabel(release.variant)}

{formatDate(release.createdAt)} · {formatBytes(release.fileSize)}

))}
)) ) : (

Версии пока не опубликованы.

)}

Проверка обновлений в приложении

Мобильный клиент может запрашивать{' '} GET /idp-api/releases/check?platform=ANDROID&versionCode=...{' '} и получать список всех сборок последней версии в поле variants. Для конкретной архитектуры используйте{' '} /downloads/android?variant=arm64-v8a.

); }