feat(遊戲化): 新增大廳、附身、時間流、後日談進度等遊戲化系統功能

新增角色大廳(lobby)邀約與通話、附身(possession)、時鐘(clock)抽象、
時間流與睡眠負債、後日談進度、行為選擇與旁觀反應等模組,並補齊對應冒煙
測試(R~V)與單元測試;同步調整 web/mobile 對應頁面與元件。

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-20 09:10:26 +08:00
co-authored by Claude Sonnet 5
parent 127a59dafd
commit 1bea06e3cd
195 changed files with 17219 additions and 738 deletions
+24 -2
View File
@@ -1,8 +1,9 @@
import { useState } from "react";
import { Pressable, ScrollView, StyleSheet, Text, View } from "react-native";
import { useEffect, useState } from "react";
import { Pressable, ScrollView, StyleSheet, Switch, Text, View } from "react-native";
import * as Device from "expo-device";
import * as Notifications from "expo-notifications";
import { fetchHealth, registerPushToken } from "../../lib/api";
import { isVoiceAutoplayEnabled, setVoiceAutoplayEnabled } from "../../lib/voice-autoplay-settings";
const USER_ID = "seed-user-primary";
@@ -13,6 +14,17 @@ export default function SettingsScreen() {
const [healthStatus, setHealthStatus] = useState<string | null>(null);
const [healthError, setHealthError] = useState<string | null>(null);
const [pushStatus, setPushStatus] = useState<string | null>(null);
// T20-P3:與 apps/web 的 VoiceAutoplaySection.tsx 對應,關閉後房間畫面回到逐則點擊才播放。
const [voiceAutoplay, setVoiceAutoplay] = useState(true);
useEffect(() => {
void isVoiceAutoplayEnabled().then(setVoiceAutoplay);
}, []);
async function handleToggleVoiceAutoplay(next: boolean) {
await setVoiceAutoplayEnabled(next);
setVoiceAutoplay(next);
}
async function checkHealth() {
setHealthError(null);
@@ -64,6 +76,15 @@ export default function SettingsScreen() {
</Pressable>
{pushStatus && <Text style={styles.line}>{pushStatus}</Text>}
</View>
<View style={styles.card}>
<Text style={styles.cardTitle}>自走語音自動播放</Text>
<Text style={styles.line}>開啟後,在房間畫面時角色的新發言會自動依序念出來;關閉則回到逐則點擊才播放。</Text>
<View style={styles.switchRow}>
<Switch value={voiceAutoplay} onValueChange={(next) => void handleToggleVoiceAutoplay(next)} />
<Text style={styles.line}>在房間時自動播放角色語音</Text>
</View>
</View>
</ScrollView>
);
}
@@ -78,4 +99,5 @@ const styles = StyleSheet.create({
buttonText: { color: "#fff", fontWeight: "bold" },
line: { fontSize: 13, color: "#222" },
error: { color: "#FF7E9D", fontSize: 12 },
switchRow: { flexDirection: "row", alignItems: "center", gap: 10 },
});