From 3273e7a0fbbce82f4ce6cacbcdb7b6d6848f6c1b Mon Sep 17 00:00:00 2001
From: JustZvan <justzvan@justzvan.xyz>
Date: Mon, 6 Apr 2026 15:32:51 +0200
Subject: feat: gallery scanning preferences

---
 app/(tabs)/controls.tsx | 90 ++++++++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 81 insertions(+), 9 deletions(-)

(limited to 'app/(tabs)/controls.tsx')

diff --git a/app/(tabs)/controls.tsx b/app/(tabs)/controls.tsx
index ac44f1b..3e41b6a 100644
--- a/app/(tabs)/controls.tsx
+++ b/app/(tabs)/controls.tsx
@@ -1,6 +1,11 @@
 import { useEffect, useState } from "react";
 import { Pressable, Switch, View } from "react-native";
-import { ControlsData, getControlsData, updateSafetyControl } from "../../api";
+import {
+  ControlsData,
+  SafetyControlValue,
+  getControlsData,
+  updateSafetyControl,
+} from "../../api";
 import { useDevice } from "../../lib/device";
 import { t } from "../../lib/locales";
 import { colors } from "../../lib/theme";
@@ -18,14 +23,16 @@ import {
 
 export default function ControlsScreen() {
   const [data, setData] = useState<ControlsData | null>(null);
-  const [state, setState] = useState<Record<string, boolean>>({});
+  const [state, setState] = useState<Record<string, SafetyControlValue>>({});
   const [communication, setCommunication] = useState<"scan" | "block">("scan");
   const [communicationModalVisible, setCommunicationModalVisible] =
     useState(false);
+  const [galleryScanningMode, setGalleryScanningMode] = useState<
+    "delete" | "notify" | "none"
+  >("none");
+  const [galleryScanningModalVisible, setGalleryScanningModalVisible] =
+    useState(false);
   const [confirmModalVisible, setConfirmModalVisible] = useState(false);
-  const [pendingSelection, setPendingSelection] = useState<
-    "scan" | "block" | null
-  >(null);
 
   const {
     devices,
@@ -34,6 +41,16 @@ export default function ControlsScreen() {
     isLoading: isDeviceLoading,
   } = useDevice();
 
+  const normalizeGalleryScanningMode = (
+    value: SafetyControlValue | undefined,
+  ): "delete" | "notify" | "none" => {
+    if (value === "delete" || value === "notify" || value === "none") {
+      return value;
+    }
+
+    return "none";
+  };
+
   useEffect(() => {
     if (selectedDevice) {
       getControlsData().then((d) => {
@@ -47,15 +64,34 @@ export default function ControlsScreen() {
           (c) => c.key === "block_strangers",
         )?.defaultValue;
         setCommunication(blockDefault ? "block" : "scan");
+        const galleryDefault = d.safetyControls.find(
+          (c) => c.key === "gallery_scanning_mode",
+        )?.defaultValue;
+        setGalleryScanningMode(normalizeGalleryScanningMode(galleryDefault));
       });
     }
   }, [selectedDevice]);
 
-  const handleToggle = (key: string, value: boolean) => {
+  const handleToggle = (key: string, value: SafetyControlValue) => {
     setState((prev) => ({ ...prev, [key]: value }));
     updateSafetyControl(key, value);
   };
 
+  const handleGalleryScanningModeChange = (
+    value: "delete" | "notify" | "none",
+  ) => {
+    setGalleryScanningMode(value);
+    handleToggle("gallery_scanning_mode", value);
+    setGalleryScanningModalVisible(false);
+  };
+
+  const galleryScanningLabel =
+    galleryScanningMode === "delete"
+      ? t("galleryScanningDelete")
+      : galleryScanningMode === "notify"
+        ? t("galleryScanningNotify")
+        : t("galleryScanningNone");
+
   const openCommunicationOptions = () => {
     setCommunicationModalVisible(true);
   };
@@ -67,7 +103,6 @@ export default function ControlsScreen() {
       setCommunicationModalVisible(false);
     } else {
       // block chosen - show confirmation
-      setPendingSelection("block");
       setConfirmModalVisible(true);
       setCommunicationModalVisible(false);
     }
@@ -77,12 +112,10 @@ export default function ControlsScreen() {
     setCommunication("block");
     handleToggle("block_strangers", true);
     setConfirmModalVisible(false);
-    setPendingSelection(null);
   };
 
   const cancelConfirm = () => {
     setConfirmModalVisible(false);
-    setPendingSelection(null);
   };
 
   if (!selectedDevice && !isDeviceLoading)
@@ -265,6 +298,45 @@ export default function ControlsScreen() {
           }
         />
       </Card>
+
+      <Card>
+        <H2>{t("galleryScanning")}</H2>
+        <Divider />
+        <Row
+          left={
+            <View style={{ gap: 4 }}>
+              <H2>{t("galleryScanning")}</H2>
+              <Muted>{t("scanGalleryForInappropriateImages")}</Muted>
+            </View>
+          }
+          right={
+            <Pressable onPress={() => setGalleryScanningModalVisible(true)}>
+              <Muted>{galleryScanningLabel}</Muted>
+            </Pressable>
+          }
+        />
+
+        <SelectDialog
+          visible={galleryScanningModalVisible}
+          title={t("galleryScanningTitle")}
+          options={[
+            {
+              label: t("galleryScanningNone"),
+              onPress: () => handleGalleryScanningModeChange("none"),
+            },
+            {
+              label: t("galleryScanningNotify"),
+              onPress: () => handleGalleryScanningModeChange("notify"),
+            },
+            {
+              label: t("galleryScanningDelete"),
+              onPress: () => handleGalleryScanningModeChange("delete"),
+              destructive: true,
+            },
+          ]}
+          onClose={() => setGalleryScanningModalVisible(false)}
+        />
+      </Card>
     </Screen>
   );
 }
-- 
cgit v1.2.3

