Files
quibot/apk/app/settings.tsx
BinarySandia04 0e7fbbfdca
All checks were successful
Build / build-web (push) Successful in 16s
Build / build-backend (push) Successful in 3s
Build / release (push) Successful in 3s
Build APK / build (push) Successful in 8m10s
Things
2026-06-11 15:09:56 +02:00

203 lines
4.8 KiB
TypeScript

import { router } from "expo-router";
import { useEffect, useState } from "react";
import {
Alert,
KeyboardAvoidingView,
Platform,
Pressable,
ScrollView,
StyleSheet,
Text,
TextInput,
View,
} from "react-native";
import { SafeAreaView } from "react-native-safe-area-context";
import {
loadRecorderSettings,
saveRecorderSettings,
} from "@/lib/recorder-settings";
export default function SettingsScreen() {
const [backendUrl, setBackendUrl] = useState("");
const [authToken, setAuthToken] = useState("");
const [fieldName, setFieldName] = useState("file");
useEffect(() => {
let isMounted = true;
async function loadSettings() {
try {
const settings = await loadRecorderSettings();
if (!isMounted) {
return;
}
setBackendUrl(settings.backendUrl);
setAuthToken(settings.authToken);
setFieldName(settings.fieldName);
} catch {
if (isMounted) {
Alert.alert("Settings error", "Could not load backend settings.");
}
}
}
void loadSettings();
return () => {
isMounted = false;
};
}, []);
async function handleSave() {
try {
await saveRecorderSettings({
authToken,
backendUrl,
fieldName,
});
router.back();
} catch {
Alert.alert("Save failed", "Could not save backend settings.");
}
}
return (
<SafeAreaView style={styles.safeArea}>
<KeyboardAvoidingView
style={styles.keyboardAvoidingView}
behavior={Platform.OS === "ios" ? "padding" : undefined}
>
<ScrollView
style={styles.scrollView}
contentContainerStyle={styles.content}
keyboardShouldPersistTaps="handled"
>
<View style={styles.headerRow}>
<Pressable onPress={() => router.back()} style={styles.navButton}>
<Text style={styles.navButtonText}>Back</Text>
</Pressable>
<Text style={styles.title}>Settings</Text>
<Pressable onPress={handleSave} style={styles.navButton}>
<Text style={styles.navButtonText}>Save</Text>
</Pressable>
</View>
<View style={styles.panel}>
<Text style={styles.label}>Backend URL</Text>
<TextInput
autoCapitalize="none"
autoCorrect={false}
keyboardType="url"
onChangeText={setBackendUrl}
placeholder="https://api.example.com/upload"
placeholderTextColor="#8f8a7c"
style={styles.input}
value={backendUrl}
/>
<Text style={styles.label}>Bearer token</Text>
<TextInput
autoCapitalize="none"
autoCorrect={false}
onChangeText={setAuthToken}
placeholder="Optional"
placeholderTextColor="#8f8a7c"
secureTextEntry
style={styles.input}
value={authToken}
/>
<Text style={styles.label}>Form field name</Text>
<TextInput
autoCapitalize="none"
autoCorrect={false}
onChangeText={setFieldName}
placeholder="file"
placeholderTextColor="#8f8a7c"
style={styles.input}
value={fieldName}
/>
<Text style={styles.helperText}>
The recording is uploaded as multipart field `{fieldName.trim() || "file"}`.
</Text>
</View>
</ScrollView>
</KeyboardAvoidingView>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
safeArea: {
flex: 1,
backgroundColor: "#f4efe4",
},
keyboardAvoidingView: {
flex: 1,
},
scrollView: {
flex: 1,
},
content: {
gap: 18,
paddingHorizontal: 20,
paddingBottom: 32,
paddingTop: 8,
},
headerRow: {
alignItems: "center",
flexDirection: "row",
justifyContent: "space-between",
},
navButton: {
borderColor: "#cdbfa8",
borderRadius: 999,
borderWidth: 1,
paddingHorizontal: 12,
paddingVertical: 8,
},
navButtonText: {
color: "#13304a",
fontSize: 14,
fontWeight: "700",
},
title: {
color: "#13304a",
fontSize: 28,
fontWeight: "800",
},
panel: {
backgroundColor: "#fffaf1",
borderColor: "#dccfb9",
borderRadius: 24,
borderWidth: 1,
gap: 12,
padding: 18,
},
label: {
color: "#13304a",
fontSize: 13,
fontWeight: "700",
marginBottom: -4,
textTransform: "uppercase",
},
input: {
backgroundColor: "#f7f0e0",
borderColor: "#d9ccb5",
borderRadius: 16,
borderWidth: 1,
color: "#1a2b39",
fontSize: 16,
paddingHorizontal: 14,
paddingVertical: 14,
},
helperText: {
color: "#665f54",
fontSize: 13,
lineHeight: 18,
},
});