Ship HDF EFFECT to PRO only, and clean the build for Play

Rename LIGHT GLOW to HDF EFFECT and gate it behind PRO: LITE renders the
chip greyed out with a PRO tag and cannot open its slider; restoration of
older settings that carry hdf > 0 still blocks export in LITE.

Play/licence pass:
- drop unused permissions (ACTIVITY_RECOGNITION, READ_MEDIA_AUDIO/VIDEO,
  SYSTEM_ALERT_WINDOW) and requestLegacyExternalStorage
- rename the Leica sims to LC STREETLIFE CLASSIC/VIVID, drop the brand from
  comments; fix app name text, canvaskit copyright, LICENSE owner
- remove expo-image-picker and expo-sensors (no JS import), delete dead
  exports (computeMatrixTint, cinemaSeasonName, base64 helpers,
  formatCoordinate)
- versionCode 3 / versionName 1.2.1, drop the personal email from About
- add docs/privacy-policy.html for the Play listing

Size: R8 + shrinkResources + bundle compression + ABI trim, 161 MB -> 76 MB.
This commit is contained in:
2026-09-15 11:36:52 +07:00
parent 42756ac7c3
commit 27a9dfb65f
25 changed files with 177 additions and 172 deletions
+6
View File
@@ -168,6 +168,7 @@ interface ParamDef {
step: number;
display: (v: number) => string;
onChange: (v: number) => void;
pro?: boolean; // PRO-only: the LITE build cannot open this row
}
const haptic = () => Haptics.impactAsync(Haptics.ImpactFeedbackStyle.Light);
@@ -420,6 +421,10 @@ export default function AdjustmentPanel({
label: `${p.label.toUpperCase()} ${p.display(p.value)}`,
active: openParam === p.key,
amberValue: openParam !== p.key && p.value !== p.default,
// A PRO-only parameter stays visible in LITE as a greyed chip with its
// corner PRO tag — named where it is, which is the only place it can be.
pro: p.pro,
disabled: !!p.pro && !IS_PRO,
onPress: () => toggleParam(p.key),
}));
@@ -465,6 +470,7 @@ export default function AdjustmentPanel({
label: d.label,
value: d.get(a),
default: d.defaultValue,
pro: d.pro,
min: d.min,
max: d.max,
step: d.step,
+2 -12
View File
@@ -8,8 +8,8 @@ import { CREDITS, LICENSE_TEXTS, CreditEntry } from '../utils/credits';
// each project row links to its homepage, each license group expands to the
// full license text embedded in the app.
const APP_NAME = 'recipescamera';
const APP_VERSION = '1.2'; // keep in sync with app.json
const APP_NAME = 'RecipesCam';
const APP_VERSION = '1.2.1'; // keep in sync with app.json
function Group({
license,
@@ -134,16 +134,6 @@ export default function CreditsModal({
</Text>
<View className="flex-row flex-wrap items-center mt-1">
<Text className="text-zinc-400 font-mono text-[10px]">Author: Lộc Phạm</Text>
<TouchableOpacity
onPress={() => Linking.openURL('mailto:tranloclqd@gmail.com')}
accessibilityLabel="Email author"
className="flex-row items-center ml-3"
hitSlop={{ top: 6, bottom: 6, left: 6, right: 6 }}
>
<Text className="text-amber-500/90 font-mono text-[10px] underline">
tranloclqd@gmail.com
</Text>
</TouchableOpacity>
</View>
<Text className="text-zinc-600 font-mono text-[10px] mt-1">
© 2026 Lộc Phạm · Built with React Native + Expo; icons by Lucide;
+2 -2
View File
@@ -72,13 +72,13 @@ export default function PhotoViewerModal({
if (await Sharing.isAvailableAsync()) {
await Sharing.shareAsync(photo.uri, {
mimeType: 'image/jpeg',
dialogTitle: `Share with CamRecipe Pro - Preset: ${photo.recipeName}`,
dialogTitle: `Share with RecipesCam - Preset: ${photo.recipeName}`,
UTI: 'public.jpeg',
});
} else {
await Share.share({
url: photo.uri,
message: `Captured with CamRecipe Pro - Preset: ${photo.recipeName}`,
message: `Captured with RecipesCam - Preset: ${photo.recipeName}`,
});
}
} catch (error) {
+1 -1
View File
@@ -343,7 +343,7 @@ export default function RecipeCreateModal({
value={name}
onChangeText={setName}
selectTextOnFocus
placeholder="Recipe name (e.g. Fuji Retro)"
placeholder="Recipe name (e.g. Retro Film)"
placeholderTextColor="#71717a"
className="bg-carbon border border-zinc-800 rounded-lg p-2 text-white font-mono text-sm mb-2"
/>
+1 -1
View File
@@ -115,7 +115,7 @@ export default function TopBar({ mode, recipeName, onSaveRecipe, onOverwriteReci
<TextInput
value={newRecipeName}
onChangeText={setNewRecipeName}
placeholder="Recipe name (e.g. Fuji Retro)"
placeholder="Recipe name (e.g. Retro Film)"
placeholderTextColor="#71717a"
className="bg-carbon border border-zinc-800 rounded-lg p-3 text-white font-mono text-sm mb-4"
autoFocus
+1 -1
View File
@@ -2797,7 +2797,7 @@ const Viewfinder = forwardRef<ViewfinderHandle, ViewfinderProps>(function Viewfi
const cinemaOn = cinemaEffect != null && !!cinemaParams;
const useShaderPass = !!imageFitRect && ((toneEffect != null && toneOn) || cinemaOn);
// ---- CLARITY + LIGHT GLOW on the LIBRARY preview -----------------------
// ---- CLARITY + HDF EFFECT on the LIBRARY preview -----------------------
// The camera worklet and exportEngine both have these two passes; the three
// library branches below draw the photo declaratively and had neither, so a
// photo opened from the library ignored both knobs. Same maths as the camera: