Add WATERMARK tab with custom draggable text; hide FRAME in camera; fix double-dark after highlight capture

This commit is contained in:
2026-09-10 07:17:14 +07:00
parent 2512e05c92
commit 144b211d35
7 changed files with 315 additions and 42 deletions
+43 -3
View File
@@ -1,9 +1,9 @@
import React, { useEffect, useState } from 'react';
import { View, Text, TouchableOpacity, ScrollView } from 'react-native';
import { View, Text, TextInput, TouchableOpacity, ScrollView } from 'react-native';
import Slider from '@react-native-community/slider';
import * as Haptics from 'expo-haptics';
import { Trash2 } from 'lucide-react-native';
import { Recipe, ColorAdjustments, FrameId, BaseFilter } from '../types';
import { Recipe, ColorAdjustments, CustomWatermark, FrameId, BaseFilter } from '../types';
import { FRAMES } from '../utils/frameUtils';
import { PARAM_DEFS, ContinuousParamDef } from '../utils/paramDefs';
import { FILM_SIMS, filmSimToRecipe } from '../utils/defaultRecipes';
@@ -15,7 +15,7 @@ import RecipeCreateModal from './RecipeCreateModal';
// Tapping a parameter chip toggles its slider row; chips stay visible.
// Darkroom-flavoured: amber = active/edited, red = destructive, mono labels.
type TabId = 'recipes' | 'iq' | 'wb' | 'filters' | 'frame';
type TabId = 'recipes' | 'iq' | 'wb' | 'filters' | 'frame' | 'watermark';
// Choice-group keys that open a strip above the chip row: color chrome groups
// (wb tab) and the D.RANGE selector (iq tab).
type GroupKey = 'cx' | 'cxb' | 'dr';
@@ -46,6 +46,10 @@ interface AdjustmentPanelProps {
onToggleGeotag: (enabled: boolean) => void;
onSaveRecipe: (name: string) => void;
onDeleteRecipe: (id: string) => void;
// WATERMARK tab state — lifted to App so the live Viewfinder overlay, this
// input and the export options all read the same object.
customWm: CustomWatermark;
onUpdateCustomWm: (wm: CustomWatermark) => void;
}
interface ChipDef {
@@ -102,6 +106,8 @@ export default function AdjustmentPanel({
onUpdateFrame,
onToggleGeotag,
onDeleteRecipe,
customWm,
onUpdateCustomWm,
}: AdjustmentPanelProps) {
// The single choice-group whose strip (OFF/WEAK/STRONG, or the DR ladder) is
// open above the chips (same one-row-at-a-time pattern as openParam — which
@@ -230,6 +236,7 @@ export default function AdjustmentPanel({
wb: toRows(PARAM_DEFS.wb),
filters: toRows(PARAM_DEFS.filters),
frame: [],
watermark: [],
};
// Active WB chip: the remembered preset wins while the engine pair still
@@ -409,12 +416,28 @@ export default function AdjustmentPanel({
selectedFrame,
(val) => onUpdateFrame(val as FrameId)
)}
</ScrollView>
);
case 'watermark':
return (
<ScrollView
horizontal
showsHorizontalScrollIndicator={false}
contentContainerStyle={{ alignItems: 'center', paddingHorizontal: 8, paddingVertical: 8 }}
>
{renderChip({
key: 'gps',
label: useGeotag ? 'GPS WATERMARK ON' : 'GPS WATERMARK OFF',
active: useGeotag,
onPress: () => onToggleGeotag(!useGeotag),
})}
{renderChip({
key: 'custom-wm',
label: customWm.enabled ? 'CUSTOM WATERMARK ON' : 'CUSTOM WATERMARK OFF',
active: customWm.enabled,
onPress: () => onUpdateCustomWm({ ...customWm, enabled: !customWm.enabled }),
})}
</ScrollView>
);
@@ -516,6 +539,23 @@ export default function AdjustmentPanel({
</ScrollView>
</View>
)}
{activeTab === 'watermark' && customWm.enabled && (
<View className="border-b border-amber-500/30 bg-amber-500/5 px-3 py-2">
<TextInput
value={customWm.text}
onChangeText={(text) => onUpdateCustomWm({ ...customWm, text })}
placeholder="TYPE WATERMARK TEXT"
placeholderTextColor="#a1a1aa"
className="rounded-md border border-amber-500/70 bg-black/40 px-3 py-2 font-mono text-sm font-bold text-amber-300"
maxLength={80}
/>
<Text className="mt-1 font-mono text-[9px] font-bold tracking-widest text-amber-400/80">
{customWm.text.trim().length > 0
? 'DRAG ON IMAGE TO MOVE — TAP TO PLACE'
: 'TYPE TEXT ABOVE, THEN DRAG ON IMAGE TO PLACE'}
</Text>
</View>
)}
{chipsRow}
<RecipeCreateModal
visible={createVisible}