Updated settings screen.

This commit is contained in:
Patrick Fic
2025-10-22 15:35:42 -07:00
parent c62d2ab05f
commit 41a3a1fccf
5 changed files with 149 additions and 64 deletions

View File

@@ -4,7 +4,7 @@ import debounce from "lodash/debounce";
import { useCallback, useEffect, useRef, useState } from "react"; import { useCallback, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next"; import { useTranslation } from "react-i18next";
import { FlatList, View } from "react-native"; import { FlatList, View } from "react-native";
import { ActivityIndicator, Text } from "react-native-paper"; import { ActivityIndicator, Icon, Text } from "react-native-paper";
import env from "../../env"; import env from "../../env";
import ErrorDisplay from "../error/error-display"; import ErrorDisplay from "../error/error-display";
import JobListItem from "../jobs-list/job-list-item"; import JobListItem from "../jobs-list/job-list-item";
@@ -82,6 +82,7 @@ export default function GlobalSearch() {
if (globalSearch === undefined || globalSearch.trim() === "") { if (globalSearch === undefined || globalSearch.trim() === "") {
return ( return (
<View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}> <View style={{ flex: 1, justifyContent: "center", alignItems: "center" }}>
<Icon size={64} source="cloud-search" />
<Text variant="bodyMedium" style={{ margin: 12, textAlign: "center" }}> <Text variant="bodyMedium" style={{ margin: 12, textAlign: "center" }}>
{t("globalsearch.labels.entersearch")} {t("globalsearch.labels.entersearch")}
</Text> </Text>

View File

@@ -1,11 +1,14 @@
import SignOutButton from "@/components-old/sign-out-button/sign-out-button.component"; import SignOutButton from "@/components-old/sign-out-button/sign-out-button.component";
import { toggleDeleteAfterUpload } from "@/redux/app/app.actions";
import { selectDeleteAfterUpload } from "@/redux/app/app.selectors"; import { selectDeleteAfterUpload } from "@/redux/app/app.selectors";
import { selectBodyshop } from "@/redux/user/user.selectors"; import { selectBodyshop, selectCurrentUser } from "@/redux/user/user.selectors";
import { formatBytes } from "@/util/uploadUtils"; import { formatBytes } from "@/util/uploadUtils";
import AsyncStorage from "@react-native-async-storage/async-storage"; import AsyncStorage from "@react-native-async-storage/async-storage";
import { StyleSheet, View } from "react-native"; import * as Application from "expo-application";
import { Button, Divider, Text } from "react-native-paper"; import Constants from "expo-constants";
import { useTranslation } from "react-i18next";
import { Alert, ScrollView, StyleSheet, View } from "react-native";
import { Button, Card, Divider, List, Text } from "react-native-paper";
import { SafeAreaView } from "react-native-safe-area-context";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
import UploadDeleteSwitch from "./upload-delete-switch"; import UploadDeleteSwitch from "./upload-delete-switch";
@@ -13,44 +16,148 @@ import UploadDeleteSwitch from "./upload-delete-switch";
const mapStateToProps = createStructuredSelector({ const mapStateToProps = createStructuredSelector({
bodyshop: selectBodyshop, bodyshop: selectBodyshop,
deleteAfterUpload: selectDeleteAfterUpload, deleteAfterUpload: selectDeleteAfterUpload,
currentUser: selectCurrentUser,
}); });
const mapDispatchToProps = (dispatch) => ({ const mapDispatchToProps = (dispatch) => ({});
toggleDeleteAfterUpload: () => dispatch(toggleDeleteAfterUpload()),
});
export default connect(mapStateToProps, mapDispatchToProps)(Tab); export default connect(mapStateToProps, mapDispatchToProps)(Tab);
function Tab({ bodyshop, deleteAfterUpload, toggleDeleteAfterUpload }) { function Tab({ bodyshop, currentUser }) {
const { t } = useTranslation();
const handleClearStorage = () => {
Alert.alert(
"Clear Local Cache",
"This will remove persisted Redux state. Media already uploaded won't be affected. Continue?",
[
{ text: "Cancel", style: "cancel" },
{
text: "Clear",
style: "destructive",
onPress: async () => {
try {
await AsyncStorage.removeItem("persist:root");
Alert.alert("Cleared", "Local cache cleared.");
} catch (_e) {
Alert.alert("Error", "Unable to clear local cache.");
}
},
},
]
);
};
return ( return (
<View style={styles.container}> <SafeAreaView>
<Text variant="titleLarge">Settings</Text> <ScrollView contentContainerStyle={styles.container}>
<Text> <Text variant="headlineMedium" style={styles.title}>
Media Storage:{" "} Settings
{bodyshop?.uselocalmediaserver </Text>
? bodyshop.localmediaserverhttp
: "Cloud"} <Card style={styles.section}>
<Card.Title title="Storage" />
<Card.Content>
<List.Section>
<View style={styles.inlineRow}>
<Text style={styles.switchLabel}>
{" "}
{t("mediabrowser.labels.deleteafterupload")}
</Text> </Text>
{!bodyshop?.uselocalmediaserver && (
<Text>Job Size Limit: {formatBytes(bodyshop?.jobsizelimit)}</Text>
)}
<UploadDeleteSwitch /> <UploadDeleteSwitch />
<Button
onPress={() => {
AsyncStorage.removeItem("persist:root");
}}
>
Clear Storage
</Button>
<Divider />
<SignOutButton />
</View> </View>
<List.Item
title="Media Storage"
description={
bodyshop?.uselocalmediaserver
? bodyshop.localmediaserverhttp
: "Cloud"
}
left={(props) => <List.Icon {...props} icon="database" />}
/>
{!bodyshop?.uselocalmediaserver && (
<List.Item
title="Job Size Limit"
description={
bodyshop?.jobsizelimit
? formatBytes(bodyshop.jobsizelimit)
: "Not specified"
}
left={(props) => <List.Icon {...props} icon="harddisk" />}
/>
)}
</List.Section>
</Card.Content>
<Card.Actions>
<Button
onPress={handleClearStorage}
mode="contained-tonal"
icon="delete-outline"
>
Clear Cache
</Button>
</Card.Actions>
</Card>
<Card style={styles.section}>
<Card.Content>
<Text style={styles.paragraph}>
Signed in to bodyshop:{" "}
{bodyshop?.shopname || bodyshop?.id || "Unknown"}
</Text>
<Text style={styles.paragraph}>
Signed in to as: {currentUser?.email || "Unknown"}
</Text>
</Card.Content>
<Card.Actions style={styles.actionsRow}>
<SignOutButton />
</Card.Actions>
</Card>
<Divider style={styles.divider} />
<Text style={styles.footerNote} variant="bodySmall">
{t("settings.labels.version", {
number: `${Constants.expoConfig.version}(${Application.nativeBuildVersion} - ${Constants.expoConfig.extra.expover})`,
})}
</Text>
</ScrollView>
</SafeAreaView>
); );
} }
const styles = StyleSheet.create({ const styles = StyleSheet.create({
container: { container: {
flex: 1, paddingVertical: 24,
justifyContent: "center", paddingHorizontal: 20,
},
title: {
marginBottom: 12,
fontWeight: "600",
},
section: {
marginBottom: 20,
},
inlineRow: {
flexDirection: "row",
alignItems: "center", alignItems: "center",
justifyContent: "space-between",
paddingVertical: 8,
paddingHorizontal: 4,
},
switchLabel: {
fontSize: 16,
fontWeight: "500",
},
paragraph: {
marginBottom: 8,
},
actionsRow: {
justifyContent: "flex-end",
},
divider: {
marginTop: 8,
},
footerNote: {
textAlign: "center",
// color: "#666",
marginTop: 16,
}, },
}); });

View File

@@ -1,6 +1,4 @@
import React from "react"; import React from "react";
import { useTranslation } from "react-i18next";
import { StyleSheet, Text, View } from "react-native";
import { Switch } from "react-native-paper"; import { Switch } from "react-native-paper";
import { connect } from "react-redux"; import { connect } from "react-redux";
import { createStructuredSelector } from "reselect"; import { createStructuredSelector } from "reselect";
@@ -19,35 +17,14 @@ export function UploadDeleteSwitch({
deleteAfterUpload, deleteAfterUpload,
toggleDeleteAfterUpload, toggleDeleteAfterUpload,
}) { }) {
const { t } = useTranslation();
return ( return (
<View style={styles.container}>
<Text style={styles.text}>
{t("mediabrowser.labels.deleteafterupload")}
</Text>
<Switch <Switch
// trackColor={{ false: '#767577', true: '#81b0ff' }}
// thumbColor={deleteAfterUpload ? 'tomato' : '#f4f3f4'}
//ios_backgroundColor="#3e3e3e"
onValueChange={() => { onValueChange={() => {
toggleDeleteAfterUpload(); toggleDeleteAfterUpload();
}} }}
value={deleteAfterUpload} value={deleteAfterUpload}
/> />
</View>
); );
} }
const styles = StyleSheet.create({
container: {
display: "flex",
flexDirection: "row",
alignItems: "center",
margin: 10,
},
text: {
flex: 1,
},
});
export default connect(mapStateToProps, mapDispatchToProps)(UploadDeleteSwitch); export default connect(mapStateToProps, mapDispatchToProps)(UploadDeleteSwitch);

View File

@@ -21,7 +21,7 @@
}, },
"globalsearch": { "globalsearch": {
"labels": { "labels": {
"entersearch": "Recent items" "entersearch": "Job Search"
} }
}, },
"jobdetail": { "jobdetail": {

View File

@@ -21,7 +21,7 @@ export default //Custom values were used as the overrides did not work.
onBackground: "#1a1c1e", onBackground: "#1a1c1e",
surface: "#fdfcff", surface: "#fdfcff",
onSurface: "#1a1c1e", onSurface: "#1a1c1e",
surfaceVariant: "#e0e2ec", surfaceVariant: "#dededeff",
onSurfaceVariant: "#43474e", onSurfaceVariant: "#43474e",
outline: "#74777f", outline: "#74777f",
outlineVariant: "#c3c6cf", outlineVariant: "#c3c6cf",