From 42756ac7c344792e44d15ff7d2e539e74495a4f3 Mon Sep 17 00:00:00 2001 From: locphamtran Date: Mon, 14 Sep 2026 21:20:56 +0700 Subject: [PATCH] Cap LITE at one FAVORITED recipe Freeing the FAVORITED tab for LITE put no ceiling on the list, and a list of your own picks is what PRO is selling. One star is free, the second names the build; un-starring stays open so the list can always come back under the limit. --- App.tsx | 8 +++++++- src/utils/entitlement.ts | 11 ++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/App.tsx b/App.tsx index 5b97366..d25996f 100644 --- a/App.tsx +++ b/App.tsx @@ -26,7 +26,7 @@ import { processAndExportPhoto } from './src/utils/exportEngine'; import { processAndExportPhotoNative } from './src/utils/nativeExport'; import { exportRecipeXml, importRecipeXml } from './src/utils/recipeShare'; import { PARAM_DEFS } from './src/utils/paramDefs'; -import { IS_PRO, LITE_MARK, LITE_RECIPE_LIMIT, proLookInUse } from './src/utils/entitlement'; +import { IS_PRO, LITE_FAVORITE_LIMIT, LITE_MARK, LITE_RECIPE_LIMIT, proLookInUse } from './src/utils/entitlement'; import UltraWide from './modules/recipescam-ultrawide'; // @ts-ignore @@ -949,6 +949,12 @@ export default function App() { // untouched either way. const handleToggleFavorite = (id: string) => { const on = !favoriteIds.includes(id); + // LITE gets one favorite; PRO is what buys a list. Un-starring is never + // gated, so the way back under the limit is always open. + if (on && !pro && favoriteIds.length >= LITE_FAVORITE_LIMIT) { + promptProFeature(`Favoriting more than ${LITE_FAVORITE_LIMIT} recipe`); + return; + } setFavoriteIds((ids) => (on ? [...ids, id] : ids.filter((x) => x !== id))); setFavoriteId(id, on).catch((e) => console.warn('Failed to save favorite:', e)); }; diff --git a/src/utils/entitlement.ts b/src/utils/entitlement.ts index 67ff3ca..ee40e0d 100644 --- a/src/utils/entitlement.ts +++ b/src/utils/entitlement.ts @@ -16,9 +16,9 @@ export const IS_PRO = IS_PRO_BUILD; // // What LITE owns outright: the eight film sims, the bundled recipes, its own // recipes up to LITE_RECIPE_LIMIT, its own watermark text (in one face), the -// plain frames and every parameter. What needs PRO: the three printed frames, -// the GPS stamp, the platform's other fonts, and the next recipe past the -// limit. +// plain frames, one favorite and every parameter. What needs PRO: the three +// printed frames, the GPS stamp, the platform's other fonts, the next recipe +// past the limit, and the second favorite. // Frames on the LITE side: the plain export only. The three printed looks are // PRO (the artwork/card geometry is the paid half of the FRAME tab). @@ -28,6 +28,11 @@ export const PRO_FRAMES: FrameId[] = ['classic-white', 'polaroid', 'wallframe']; // free, deleting one is PRO — so a LITE list only ever grows to this size. export const LITE_RECIPE_LIMIT = 3; +// FAVORITED is a LITE feature, but only one deep: the first star is free, the +// second needs PRO. Un-starring is always free, so the list can always come +// back under the limit. +export const LITE_FAVORITE_LIMIT = 1; + // Burned into every LITE export, bottom-right of the photo/frame area. Fractions // of the stamp canvas, same space the custom mark uses. The user's own mark is // free on top of it.