feat(media): mobile entry, routes and photo library permission

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NLSCTnhge4umMnemGXWr1w
This commit is contained in:
Claude 2026-10-03 19:22:49 +00:00
parent ed0cb29e16
commit e1226cff9b
No known key found for this signature in database
5 changed files with 67 additions and 2 deletions

View File

@ -33,12 +33,21 @@
[
"expo-image-picker",
{
"photosPermission": "Rakazo uses your photo library so you can attach images to a bot message.",
"photosPermission": "Rakazo uses your photo library so you can attach images and turn your photos and videos into projects.",
"cameraPermission": "Rakazo uses the camera so you can attach photos to a bot message.",
"microphonePermission": false
}
],
"expo-sharing",
[
"expo-media-library",
{
"photosPermission": "Rakazo uses your photo library so you can attach images and turn your photos and videos into projects.",
"savePhotosPermission": false,
"isAccessMediaLocationEnabled": true,
"granularPermissions": ["photo", "video"]
}
],
"./plugins/with-worklets-headers",
"./plugins/with-scene-lifecycle"
],
@ -52,7 +61,7 @@
},
"infoPlist": {
"NSCameraUsageDescription": "Rakazo uses the camera so you can attach photos to a bot message.",
"NSPhotoLibraryUsageDescription": "Rakazo uses your photo library so you can attach images to a bot message.",
"NSPhotoLibraryUsageDescription": "Rakazo uses your photo library so you can attach images and turn your photos and videos into projects.",
"NSLocalNetworkUsageDescription": "Rakazo connects to a self-hosted Rakazo server on your local network.",
"NSAppTransportSecurity": {
"NSAllowsLocalNetworking": true

View File

@ -13,10 +13,16 @@ import {
configureForegroundNotifications,
resumeLiveNotifications,
} from "../lib/live-notifications";
import { useMediaNotificationRouting } from "../lib/media-api";
import { native, useResolvedAppearance } from "../lib/native";
configureForegroundNotifications();
function MediaNotificationRouting() {
useMediaNotificationRouting();
return null;
}
export default function Layout() {
const { t } = useI18n();
const [ready, setReady] = useState(false);
@ -121,8 +127,12 @@ export default function Layout() {
<Stack.Screen name="thread" options={{ title: t("Thread") }} />
<Stack.Screen name="routine" options={{ title: t("Routine") }} />
<Stack.Screen name="computer" options={{ title: t("Computer") }} />
<Stack.Screen name="media" options={{ title: t("Media") }} />
<Stack.Screen name="media-session" options={{ title: "" }} />
<Stack.Screen name="media-project" options={{ title: "" }} />
</Stack>
<ComputerUpdateProgress />
<MediaNotificationRouting />
</ThemeProvider>
</AvatarStyleProvider>
) : (

View File

@ -44,6 +44,7 @@ import {
openPromotedNotificationSettings,
setLiveNotificationSettings,
} from "../lib/live-notifications";
import { useMediaAvailable } from "../lib/media-api";
import { presentMessageActionSheet } from "../lib/message-action-sheet";
import { native, useResolvedAppearance, useThemedStyles } from "../lib/native";
import { registerPushToken } from "../lib/push";
@ -55,6 +56,7 @@ export default function Account() {
const { t, locale } = useI18n();
const colorScheme = useResolvedAppearance();
const router = useRouter();
const mediaAvailable = useMediaAvailable();
const { focus } = useLocalSearchParams<{ focus?: string }>();
const [me, setMe] = useState<MobileMe | null>(null);
const [password, setPassword] = useState("");
@ -424,6 +426,18 @@ export default function Account() {
<Text style={styles.chevron}>›</Text>
</Pressable>
{mediaAvailable ? (
<Pressable
accessibilityRole="button"
disabled={pending}
onPress={() => router.push("/media")}
style={({ pressed }) => [styles.settingsButton, pressed && styles.pressed]}
>
<Text style={styles.settingsTitle}>{t("Media")}</Text>
<Text style={styles.chevron}>›</Text>
</Pressable>
) : null}
<Pressable
accessibilityRole="button"
disabled={pending}

View File

@ -600,4 +600,20 @@ export const RU_MESSAGES: Record<string, string> = {
"{name} (permission denied)": "{name} (в разрешении отказано)",
"{name} (unsupported type)": "{name} (неподдерживаемый тип)",
"Saved {name} locally": "{name} сохранен локально.",
"Allow photo access": "Разрешить доступ к фото",
Approve: "Утвердить",
Blocked: "Заблокировано",
"Choose photos and videos": "Выбрать фото и видео",
"Edit on web or desktop.": "Редактируйте в веб-версии или на компьютере.",
Media: "Медиа",
"No sessions yet": "Сессий пока нет",
"Open Settings": "Открыть настройки",
Projects: "Проекты",
"Rendering {percent}%": "Рендеринг {percent}%",
Sessions: "Сессии",
"Upload and create project": "Загрузить и создать проект",
Upload: "Загрузить",
"Uploading {percent}%": "Загрузка {percent}%",
"{count} items could not be uploaded.": "Не удалось загрузить элементов: {count}.",
"{count} items": "Элементов: {count}",
};

View File

@ -584,4 +584,20 @@ export const ZH_MESSAGES: Record<string, string> = {
"Extra high": "超高",
Low: "低",
High: "高",
"Allow photo access": "允许访问照片",
Approve: "批准",
Blocked: "已阻止",
"Choose photos and videos": "选择照片和视频",
"Edit on web or desktop.": "请在网页版或桌面版中编辑。",
Media: "媒体",
"No sessions yet": "暂无会话",
"Open Settings": "打开设置",
Projects: "项目",
"Rendering {percent}%": "正在渲染 {percent}%",
Sessions: "会话",
"Upload and create project": "上传并创建项目",
Upload: "上传",
"Uploading {percent}%": "正在上传 {percent}%",
"{count} items could not be uploaded.": "{count} 个项目无法上传。",
"{count} items": "{count} 个项目",
};