Files
gitlab-instance-0a899031_do…/mobile/app/(tabs)/more.tsx
2026-03-24 14:47:03 -05:00

178 lines
5.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useCallback, useEffect, useState } from 'react'
import {
View,
Text,
ScrollView,
StyleSheet,
TextInput,
Pressable,
Switch,
RefreshControl,
} from 'react-native'
import { SafeAreaView } from 'react-native-safe-area-context'
import { useBind } from '@/context/BindContext'
import { apiFetch } from '@/lib/api'
import { theme } from '@/constants/theme'
type ProxyState = { enabled: boolean; http: string; socks: string }
export default function MoreScreen() {
const { bind } = useBind()
const [proxy, setProxy] = useState<ProxyState>({ enabled: false, http: '', socks: '' })
const [metrics, setMetrics] = useState<string>('')
const [msg, setMsg] = useState('')
const [refreshing, setRefreshing] = useState(false)
const load = useCallback(async () => {
if (!bind) return
setMsg('')
try {
const pr = await apiFetch(bind, '/proxy_config')
if (pr.ok) {
const p = (await pr.json()) as ProxyState
setProxy({
enabled: !!p.enabled,
http: String(p.http || ''),
socks: String(p.socks || ''),
})
}
const mr = await apiFetch(bind, '/system_metrics')
if (mr.ok) {
const m = await mr.json()
setMetrics(JSON.stringify(m, null, 2))
}
} catch (e) {
setMsg(e instanceof Error ? e.message : String(e))
}
}, [bind])
useEffect(() => {
void load()
}, [load])
const onRefresh = useCallback(async () => {
setRefreshing(true)
await load()
setRefreshing(false)
}, [load])
const saveProxy = useCallback(async () => {
if (!bind) return
try {
const res = await apiFetch(bind, '/proxy_config', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(proxy),
})
if (!res.ok) throw new Error(String(res.status))
setMsg('代理已保存')
} catch (e) {
setMsg(e instanceof Error ? e.message : String(e))
}
}, [bind, proxy])
if (!bind) {
return (
<SafeAreaView style={styles.safe}>
<Text style={styles.muted}></Text>
</SafeAreaView>
)
}
return (
<SafeAreaView style={styles.safe} edges={['bottom']}>
<ScrollView
contentContainerStyle={styles.scroll}
refreshControl={<RefreshControl refreshing={refreshing} onRefresh={() => void onRefresh()} />}
>
<Text style={styles.h1}></Text>
<View style={styles.card}>
<Text style={styles.cardTitle}></Text>
<View style={styles.row}>
<Text style={styles.label}></Text>
<Switch value={proxy.enabled} onValueChange={(v) => setProxy((p) => ({ ...p, enabled: v }))} />
</View>
<Text style={styles.label}>HTTP</Text>
<TextInput
style={styles.input}
value={proxy.http}
onChangeText={(t) => setProxy((p) => ({ ...p, http: t }))}
placeholder="http://..."
placeholderTextColor={theme.muted}
autoCapitalize="none"
/>
<Text style={styles.label}>SOCKS</Text>
<TextInput
style={styles.input}
value={proxy.socks}
onChangeText={(t) => setProxy((p) => ({ ...p, socks: t }))}
placeholder="socks5://..."
placeholderTextColor={theme.muted}
autoCapitalize="none"
/>
<Pressable style={styles.btn} onPress={() => void saveProxy()}>
<Text style={styles.btnText}></Text>
</Pressable>
</View>
<View style={styles.card}>
<Text style={styles.cardTitle}></Text>
{metrics ? <Text style={styles.pre}>{metrics}</Text> : <Text style={styles.muted}></Text>}
</View>
<View style={styles.card}>
<Text style={styles.cardTitle}> Chatbot</Text>
<Text style={styles.muted}>
Chatbot Windows
</Text>
</View>
{!!msg && <Text style={styles.ok}>{msg}</Text>}
</ScrollView>
</SafeAreaView>
)
}
const styles = StyleSheet.create({
safe: { flex: 1, backgroundColor: theme.bg },
scroll: { padding: 20, paddingBottom: 40 },
h1: { fontSize: 22, fontWeight: '700', color: theme.text, marginBottom: 16 },
card: {
padding: 14,
borderRadius: 12,
backgroundColor: theme.bgCard,
borderWidth: 1,
borderColor: theme.border,
marginBottom: 14,
},
cardTitle: { fontSize: 15, fontWeight: '600', color: theme.text, marginBottom: 12 },
row: { flexDirection: 'row', alignItems: 'center', justifyContent: 'space-between', marginBottom: 12 },
label: { fontSize: 12, color: theme.muted, marginBottom: 6 },
input: {
borderWidth: 1,
borderColor: theme.border,
borderRadius: 10,
padding: 10,
color: theme.text,
marginBottom: 12,
backgroundColor: theme.bg,
},
btn: {
backgroundColor: '#3d7eff',
paddingVertical: 12,
borderRadius: 10,
alignItems: 'center',
},
btnText: { color: '#fff', fontWeight: '700' },
pre: {
fontFamily: 'monospace',
fontSize: 10,
color: '#c8cdd5',
lineHeight: 16,
},
muted: { color: theme.muted, fontSize: 13, lineHeight: 20 },
ok: { color: theme.success, marginTop: 8 },
})