import { useEffect, useSyncExternalStore } from 'react'; import { useTranslation } from 'react-i18next'; import { AppState, Modal, Pressable, ScrollView, Text, View } from 'react-native'; import { useSession, useSessionCtx } from '../lib/session'; import { updater } from '../lib/update'; import { radius, useColors } from '../theme'; import { Button } from './kit'; export function useUpdateState() { return useSyncExternalStore(updater.subscribe, () => updater.state); } /** Проверяет обновления при запуске и возврате в приложение; показывает диалог с «Что нового». */ export function UpdateDialog() { const colors = useColors(); const { t } = useTranslation(); const session = useSession(); const { server } = useSessionCtx(); const st = useUpdateState(); useEffect(() => { void updater.check(session); const sub = AppState.addEventListener('change', (s) => { if (s === 'active') void updater.check(session); }); return () => sub.remove(); }, [session]); if (st.status === 'idle' || st.status === 'checking' || st.status === 'latest') return null; if (st.status === 'available' && st.dismissed) return null; const { release, required } = st; const busy = st.status === 'downloading' || st.status === 'verifying'; const action = () => void updater.downloadAndInstall(session, server ?? ''); return ( updater.dismiss()}> {t('mobile.update_title', { version: release.version })} {required && {t('mobile.update_required')}} {release.notes_md.trim() !== '' && ( {plainNotes(release.notes_md)} )} {t('mobile.update_size', { size: (release.size / 1048576).toFixed(1), })} {st.status === 'downloading' && ( {t('mobile.update_downloading', { percent: Math.round(st.progress * 100), })} )} {st.status === 'verifying' && {t('mobile.update_verifying')}} {st.status === 'error' && ( {t(st.error === 'bad_checksum' ? 'mobile.update_bad_checksum' : 'mobile.update_failed')} )} {st.status === 'ready' && ( {t('mobile.update_allow')} void updater.openInstallSettings()} accessibilityRole="link"> {t('mobile.update_open_settings')} )}