Sell PRO as an in-app unlock, take shared photos, and let FX run negative
- One free Play app (com.locphamtran.recipescamera) with an expo-iap PRO unlock, replacing the paid apk for the store channel - Android SEND/SEND_MULTIPLE share target feeds photos into the editor, on cold start and on resume - BACK button in the TopBar and press-and-hold PEEK replace the chip row - NOISE REDUCTION and SHARPENING accept -10: a negative SHARPENING softens the frame before the grain pass, a negative NOISE REDUCTION re-grains it, in the Skia engine, the live preview and the Kotlin export path alike
This commit is contained in:
@@ -6,7 +6,7 @@ import { Star, Trash2 } from 'lucide-react-native';
|
||||
import { Skia } from '@shopify/react-native-skia';
|
||||
import { Recipe, ColorAdjustments, CustomWatermark, GpsWatermark, FrameId, BaseFilter, CropRatio } from '../types';
|
||||
import { FRAMES } from '../utils/frameUtils';
|
||||
import { IS_PRO, PRO_FRAMES } from '../utils/entitlement';
|
||||
import { PRO_FRAMES } from '../utils/entitlement';
|
||||
import { PARAM_DEFS, ContinuousParamDef } from '../utils/paramDefs';
|
||||
import { FILM_SIMS, filmSimToRecipe } from '../utils/defaultRecipes';
|
||||
import RecipeCreateModal from './RecipeCreateModal';
|
||||
@@ -66,6 +66,10 @@ interface AdjustmentPanelProps {
|
||||
onApplyCrop: () => void;
|
||||
cropEnabled?: boolean;
|
||||
useGeotag: boolean;
|
||||
// Runtime tier: PRO apk or a LITE apk that bought the unlock. A LITE build
|
||||
// keeps every PRO chip on screen, greyed with its corner tag, so the panel
|
||||
// has to read the value at render time rather than at build time.
|
||||
pro: boolean;
|
||||
// RAW (DNG sidecar) / aspect-ratio / metering-mode now live in the gear
|
||||
// Settings sheet (gear between library picker and shutter) — no longer
|
||||
// tool-rail tabs.
|
||||
@@ -141,6 +145,9 @@ interface AdjustmentPanelProps {
|
||||
// FRAME → WATERMARK sub-panel is open: App needs this to arm the mark's
|
||||
// drag/pinch layer on the image (the old `activeTab === 'watermark'`).
|
||||
onWmPanelChange: (open: boolean) => void;
|
||||
// BACK (undo) and PEEK (hold to compare) both work on the whole LOOK, not on
|
||||
// one parameter, and both left this panel: BACK is a button in the top bar,
|
||||
// PEEK is a hold on the picture itself (TopBar, Viewfinder).
|
||||
}
|
||||
|
||||
interface ChipDef {
|
||||
@@ -229,6 +236,7 @@ export default function AdjustmentPanel({
|
||||
onApplyCrop,
|
||||
cropEnabled,
|
||||
useGeotag,
|
||||
pro,
|
||||
openParam,
|
||||
onOpenParamChange,
|
||||
currentBaseFilter,
|
||||
@@ -338,9 +346,8 @@ export default function AdjustmentPanel({
|
||||
? 'border-amber-500/70 bg-amber-500/15'
|
||||
: 'border-zinc-700/60 bg-titan/80';
|
||||
const textTone = c.active || c.amberValue ? 'text-amber-500' : 'text-zinc-300';
|
||||
// LITE only: corner tag on every chip whose look LITE cannot export. PRO
|
||||
// never sees it (there the condition is a constant false).
|
||||
const proTag = c.pro && !IS_PRO;
|
||||
// LITE only: corner tag on every chip whose look LITE cannot export.
|
||||
const proTag = c.pro && !pro;
|
||||
return (
|
||||
<View
|
||||
key={c.key}
|
||||
@@ -424,7 +431,7 @@ export default function AdjustmentPanel({
|
||||
// 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,
|
||||
disabled: !!p.pro && !pro,
|
||||
onPress: () => toggleParam(p.key),
|
||||
}));
|
||||
|
||||
@@ -560,7 +567,7 @@ export default function AdjustmentPanel({
|
||||
const wmFontOptions = useMemo(() => {
|
||||
// LITE ships a single basic face: the platform's own families (what
|
||||
// DEFAULT is not) are the paid half of the FONT strip.
|
||||
if (!IS_PRO) return [{ v: 'DEFAULT', d: 'DEFAULT' }];
|
||||
if (!pro) return [{ v: 'DEFAULT', d: 'DEFAULT' }];
|
||||
const mgr = Skia.FontMgr.System();
|
||||
const names = new Set<string>();
|
||||
for (let i = 0; i < mgr.countFamilies() && names.size < 120; i++) {
|
||||
@@ -571,7 +578,7 @@ export default function AdjustmentPanel({
|
||||
{ v: 'DEFAULT', d: 'DEFAULT' },
|
||||
...[...names].sort().map((n) => ({ v: n, d: n })),
|
||||
];
|
||||
}, []);
|
||||
}, [pro]);
|
||||
const groupDefs: Record<Exclude<GroupKey, 'wm'>, { label: string; off: string; value: string; options: { v: string; d: string }[]; onPick: (v: string) => void }> = {
|
||||
cx: {
|
||||
label: 'COLOR CHROME', off: 'none', value: a.colorChrome || 'none', options: chromeOptions,
|
||||
|
||||
Reference in New Issue
Block a user