feat: show android update toast
This commit is contained in:
@@ -6,6 +6,7 @@ import { McpIcon } from '@/components/icons/McpIcon';
|
||||
import { McpDropdownContent } from '@/components/mcp/McpDropdown';
|
||||
import { AboutSettings } from '@/components/sections/openchamber/AboutSettings';
|
||||
import { OpenCodeUpdateToast } from '@/components/update/OpenCodeUpdateToast';
|
||||
import { MobileAppUpdateToast } from '@/components/update/MobileAppUpdateToast';
|
||||
import { ConfigUpdateOverlay } from '@/components/ui/ConfigUpdateOverlay';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import { OpenChamberLogo } from '@/components/ui/OpenChamberLogo';
|
||||
@@ -2485,6 +2486,7 @@ export function MobileApp({ apis }: MobileAppProps) {
|
||||
<div className="h-full bg-background text-foreground">
|
||||
<SyncAppEffects embeddedBackgroundWorkEnabled={isInitialized} />
|
||||
<OpenCodeUpdateToast />
|
||||
<MobileAppUpdateToast />
|
||||
<MobileShell onActiveConnectionDeleted={() => {
|
||||
switchRuntimeEndpoint({ apiBaseUrl: '', clientToken: null, runtimeKey: 'mobile-disconnected' });
|
||||
setConnectionEpoch((value) => value + 1);
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
import * as React from 'react';
|
||||
|
||||
import { Icon } from '@/components/icon/Icon';
|
||||
import { toast } from '@/components/ui/toast';
|
||||
import { useI18n } from '@/lib/i18n';
|
||||
import { getClientPlatform } from '@/lib/platform';
|
||||
import { openExternalUrl } from '@/lib/url';
|
||||
import { useUpdateStore } from '@/stores/useUpdateStore';
|
||||
import { getDeferredSafeStorage } from '@/stores/utils/safeStorage';
|
||||
|
||||
const TOAST_ID = 'mobile-app-update-available';
|
||||
const DISMISSED_VERSION_KEY = 'mobile-app-update-toast-dismissed-version';
|
||||
|
||||
export const MobileAppUpdateToast: React.FC = () => {
|
||||
const { t } = useI18n();
|
||||
const available = useUpdateStore((state) => state.available);
|
||||
const runtimeType = useUpdateStore((state) => state.runtimeType);
|
||||
const version = useUpdateStore((state) => state.info?.version);
|
||||
const downloadUrl = useUpdateStore((state) => state.info?.downloadUrl);
|
||||
const seenVersionsRef = React.useRef(new Set<string>());
|
||||
|
||||
React.useEffect(() => {
|
||||
if (getClientPlatform() !== 'android' || runtimeType !== 'mobile' || !available || !version || !downloadUrl) {
|
||||
toast.dismiss(TOAST_ID);
|
||||
return;
|
||||
}
|
||||
|
||||
if (getDeferredSafeStorage().getItem(DISMISSED_VERSION_KEY) === version) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (seenVersionsRef.current.has(version)) {
|
||||
return;
|
||||
}
|
||||
|
||||
seenVersionsRef.current.add(version);
|
||||
|
||||
toast.info(t('mobileUpdate.toast.available.title'), {
|
||||
id: TOAST_ID,
|
||||
description: t('mobileUpdate.toast.available.description', { version }),
|
||||
duration: Infinity,
|
||||
icon: <Icon name="download" className="h-4 w-4 text-muted-foreground" />,
|
||||
action: {
|
||||
label: t('mobileUpdate.toast.actions.download'),
|
||||
onClick: () => {
|
||||
void openExternalUrl(downloadUrl);
|
||||
},
|
||||
},
|
||||
cancel: {
|
||||
label: t('mobileUpdate.toast.actions.dismiss'),
|
||||
onClick: () => {
|
||||
getDeferredSafeStorage().setItem(DISMISSED_VERSION_KEY, version);
|
||||
toast.dismiss(TOAST_ID);
|
||||
},
|
||||
},
|
||||
});
|
||||
}, [available, downloadUrl, runtimeType, t, version]);
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -2598,6 +2598,10 @@ export const dict = {
|
||||
'updateDialog.status.updating': 'Updating...',
|
||||
'updateDialog.error.updateFailed': 'Update failed',
|
||||
'updateDialog.error.takingLonger': 'Update is taking longer than expected. Wait a bit and refresh, or run: openchamber update',
|
||||
'mobileUpdate.toast.available.title': 'OpenChamber update available',
|
||||
'mobileUpdate.toast.available.description': 'Version {version} is ready for Android.',
|
||||
'mobileUpdate.toast.actions.download': 'Download',
|
||||
'mobileUpdate.toast.actions.dismiss': 'Dismiss',
|
||||
'opencodeUpdate.toast.available.title': 'OpenCode update',
|
||||
'opencodeUpdate.toast.available.description': 'Version {version} available.',
|
||||
'opencodeUpdate.toast.actions.update': 'Update',
|
||||
|
||||
@@ -2564,6 +2564,10 @@ export const dict: Record<I18nKey, string> = {
|
||||
"updateDialog.status.updating": "Actualizando...",
|
||||
"updateDialog.error.updateFailed": "No se pudo actualizar",
|
||||
"updateDialog.error.takingLonger": "La actualización está tardando más de lo esperado. Espera un poco y refresca, o ejecuta: openchamber update",
|
||||
"mobileUpdate.toast.available.title": "Actualización de OpenChamber disponible",
|
||||
"mobileUpdate.toast.available.description": "La versión {version} está lista para Android.",
|
||||
"mobileUpdate.toast.actions.download": "Descargar",
|
||||
"mobileUpdate.toast.actions.dismiss": "Descartar",
|
||||
"opencodeUpdate.toast.available.title": "Actualización de OpenCode",
|
||||
"opencodeUpdate.toast.available.description": "Versión {version} disponible.",
|
||||
"opencodeUpdate.toast.actions.update": "Actualizar",
|
||||
|
||||
@@ -2369,6 +2369,10 @@ export const dict = {
|
||||
'updateDialog.status.updating': 'Mise à jour...',
|
||||
'updateDialog.error.updateFailed': 'La mise à jour a échoué',
|
||||
'updateDialog.error.takingLonger': 'La mise à jour prend plus de temps que prévu. Attendez un peu et actualisez, ou exécutez : openchamber update',
|
||||
'mobileUpdate.toast.available.title': 'Mise à jour OpenChamber disponible',
|
||||
'mobileUpdate.toast.available.description': 'La version {version} est prête pour Android.',
|
||||
'mobileUpdate.toast.actions.download': 'Télécharger',
|
||||
'mobileUpdate.toast.actions.dismiss': 'Ignorer',
|
||||
'opencodeUpdate.toast.available.title': 'Mise à jour OpenCode',
|
||||
'opencodeUpdate.toast.available.description': 'Version {version} disponible.',
|
||||
'opencodeUpdate.toast.actions.update': 'Mise à jour',
|
||||
|
||||
@@ -2594,6 +2594,10 @@ export const dict: Record<I18nKey, string> = {
|
||||
'updateDialog.status.updating': '更新中...',
|
||||
'updateDialog.error.updateFailed': '更新に失敗しました',
|
||||
'updateDialog.error.takingLonger': '更新に予想以上に時間がかかっています。しばらく待ってから更新するか、次を実行: openchamber update',
|
||||
'mobileUpdate.toast.available.title': 'OpenChamberの更新があります',
|
||||
'mobileUpdate.toast.available.description': 'バージョン{version}をAndroidで利用できます。',
|
||||
'mobileUpdate.toast.actions.download': 'ダウンロード',
|
||||
'mobileUpdate.toast.actions.dismiss': '閉じる',
|
||||
'opencodeUpdate.toast.available.title': 'OpenCode更新',
|
||||
'opencodeUpdate.toast.available.description': 'バージョン{version}が利用可能です。',
|
||||
'opencodeUpdate.toast.actions.update': '更新',
|
||||
|
||||
@@ -2598,6 +2598,10 @@ export const dict: Record<I18nKey, string> = {
|
||||
'updateDialog.status.updating': '업데이트 중…',
|
||||
'updateDialog.error.updateFailed': '업데이트 실패',
|
||||
'updateDialog.error.takingLonger': '업데이트가 예상보다 오래 걸립니다. 잠시 기다린 뒤 새로고침하거나 `openchamber update`를 실행하세요.',
|
||||
'mobileUpdate.toast.available.title': 'OpenChamber 업데이트 사용 가능',
|
||||
'mobileUpdate.toast.available.description': 'Android용 버전 {version}이 준비되었습니다.',
|
||||
'mobileUpdate.toast.actions.download': '다운로드',
|
||||
'mobileUpdate.toast.actions.dismiss': '닫기',
|
||||
'opencodeUpdate.toast.available.title': 'OpenCode 업데이트',
|
||||
'opencodeUpdate.toast.available.description': '버전 {version} 사용 가능.',
|
||||
'opencodeUpdate.toast.actions.update': '업데이트',
|
||||
|
||||
@@ -2567,6 +2567,10 @@ export const dict: Record<I18nKey, string> = {
|
||||
'updateDialog.actions.updateNow': 'Aktualizuj teraz',
|
||||
'updateDialog.error.takingLonger': 'Aktualizacja trwa dłużej niż oczekiwano. Poczekaj chwilę i odśwież albo uruchom: openchamber update',
|
||||
'updateDialog.error.updateFailed': 'Aktualizacja nie powiodła się',
|
||||
'mobileUpdate.toast.available.title': 'Dostępna aktualizacja OpenChamber',
|
||||
'mobileUpdate.toast.available.description': 'Wersja {version} jest gotowa dla Androida.',
|
||||
'mobileUpdate.toast.actions.download': 'Pobierz',
|
||||
'mobileUpdate.toast.actions.dismiss': 'Odrzuć',
|
||||
'updateDialog.fallback.updateViaTerminal': 'Lub zaktualizuj przez terminal:',
|
||||
'updateDialog.header.updateAvailable': 'Dostępna aktualizacja',
|
||||
'updateDialog.header.updating': 'Aktualizowanie OpenChamber...',
|
||||
|
||||
@@ -2564,6 +2564,10 @@ export const dict: Record<I18nKey, string> = {
|
||||
"updateDialog.status.updating": "Atualizando...",
|
||||
"updateDialog.error.updateFailed": "Não foi possível atualizar",
|
||||
"updateDialog.error.takingLonger": "A atualização está demorando mais do que o esperado. Aguarde um pouco e atualize, ou execute: openchamber update",
|
||||
"mobileUpdate.toast.available.title": "Atualização do OpenChamber disponível",
|
||||
"mobileUpdate.toast.available.description": "A versão {version} está pronta para Android.",
|
||||
"mobileUpdate.toast.actions.download": "Baixar",
|
||||
"mobileUpdate.toast.actions.dismiss": "Dispensar",
|
||||
"opencodeUpdate.toast.available.title": "Atualização do OpenCode",
|
||||
"opencodeUpdate.toast.available.description": "Versão {version} disponível.",
|
||||
"opencodeUpdate.toast.actions.update": "Atualizar",
|
||||
|
||||
@@ -2564,6 +2564,10 @@ export const dict: Record<I18nKey, string> = {
|
||||
"updateDialog.status.updating": "Оновлення...",
|
||||
"updateDialog.error.updateFailed": "Помилка оновлення",
|
||||
"updateDialog.error.takingLonger": "Оновлення триває довше, ніж очікувалося. Зачекайте трохи та оновіть або запустіть: openchamber update",
|
||||
"mobileUpdate.toast.available.title": "Доступне оновлення OpenChamber",
|
||||
"mobileUpdate.toast.available.description": "Версія {version} готова для Android.",
|
||||
"mobileUpdate.toast.actions.download": "Завантажити",
|
||||
"mobileUpdate.toast.actions.dismiss": "Сховати",
|
||||
"opencodeUpdate.toast.available.title": "Оновлення OpenCode",
|
||||
"opencodeUpdate.toast.available.description": "Версія {version} доступна.",
|
||||
"opencodeUpdate.toast.actions.update": "Оновити",
|
||||
|
||||
@@ -2564,6 +2564,10 @@ export const dict: Record<I18nKey, string> = {
|
||||
'updateDialog.status.updating': '更新中...',
|
||||
'updateDialog.error.updateFailed': '更新失败',
|
||||
'updateDialog.error.takingLonger': '更新耗时超出预期。请稍等后刷新,或运行:openchamber update',
|
||||
'mobileUpdate.toast.available.title': 'OpenChamber 更新可用',
|
||||
'mobileUpdate.toast.available.description': '版本 {version} 已可用于 Android。',
|
||||
'mobileUpdate.toast.actions.download': '下载',
|
||||
'mobileUpdate.toast.actions.dismiss': '忽略',
|
||||
'opencodeUpdate.toast.available.title': 'OpenCode 更新',
|
||||
'opencodeUpdate.toast.available.description': '版本 {version} 可用。',
|
||||
'opencodeUpdate.toast.actions.update': '更新',
|
||||
|
||||
@@ -2561,6 +2561,10 @@ export const dict: Record<I18nKey, string> = {
|
||||
'updateDialog.status.updating': '更新中...',
|
||||
'updateDialog.error.updateFailed': '更新失敗',
|
||||
'updateDialog.error.takingLonger': '更新耗時超出預期。請稍等後重新整理,或執行:openchamber update',
|
||||
'mobileUpdate.toast.available.title': 'OpenChamber 更新可用',
|
||||
'mobileUpdate.toast.available.description': '版本 {version} 已可用於 Android。',
|
||||
'mobileUpdate.toast.actions.download': '下載',
|
||||
'mobileUpdate.toast.actions.dismiss': '忽略',
|
||||
'opencodeUpdate.toast.available.title': 'OpenCode 更新',
|
||||
'opencodeUpdate.toast.available.description': '版本 {version} 可安裝。',
|
||||
'opencodeUpdate.toast.actions.update': '更新',
|
||||
|
||||
Reference in New Issue
Block a user