Drop the in-app unlock key: only the PRO apk opens PRO
The set is two apks and the unlock key was a second, weaker lock on the same door. A verifier that runs offline has to carry its secret inside the lite apk, so anyone who unpacked it could mint a key. Nothing in the lite build can flip the gate now. - entitlement.ts keeps the gate (which look is PRO, what an export carries in lite) and exports IS_PRO straight from the build flag. - SETTINGS loses the key field; the plan chip still says LITE / PRO ACTIVE and the helper text says what lite cannot export. - The upsell alerts just name the build that has the feature. - tools/keygen.mjs goes with the verifier it fed.
This commit is contained in:
@@ -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 { LITE_MARK, LITE_RECIPE_LIMIT, activatePro, loadPro, proLookInUse } from './src/utils/entitlement';
|
||||
import { IS_PRO, LITE_MARK, LITE_RECIPE_LIMIT, proLookInUse } from './src/utils/entitlement';
|
||||
import UltraWide from './modules/recipescam-ultrawide';
|
||||
|
||||
// @ts-ignore
|
||||
@@ -97,12 +97,8 @@ export default function App() {
|
||||
};
|
||||
}, []);
|
||||
const [recipes, setRecipes] = useState<Recipe[]>([]);
|
||||
// Lite (free) vs PRO (unlocked key). Read once at startup; the unlock key
|
||||
// flips it in place, so every later export drops the mark and the look gate.
|
||||
const [pro, setPro] = useState(false);
|
||||
useEffect(() => {
|
||||
loadPro().then(setPro);
|
||||
}, []);
|
||||
// LITE (free) vs PRO (the paid build): fixed for the life of the install.
|
||||
const pro = IS_PRO;
|
||||
// Lite stores up to LITE_RECIPE_LIMIT recipes of its own; past that the save
|
||||
// paths ask for PRO. Deleting one is PRO as well, so a Lite list only grows.
|
||||
const customRecipeCount = recipes.filter((r) => r.isCustom).length;
|
||||
@@ -1035,41 +1031,20 @@ export default function App() {
|
||||
// The native Kotlin exporter has no text-watermark draw, so a Lite export
|
||||
// (which always carries the mark) must take the Skia engine.
|
||||
const nativeExport = NATIVE_EXPORT && pro;
|
||||
// Shutter/export with a PRO look: nothing is rendered — name the feature and
|
||||
// point at the unlock.
|
||||
// Shutter/export with a PRO look: nothing is rendered — name the feature so
|
||||
// the user knows which PRO build would render it.
|
||||
const promptPro = (feature: string) => {
|
||||
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning);
|
||||
Alert.alert(
|
||||
'PRO LOOK',
|
||||
`${feature} can be previewed and edited for free, but exporting it needs PRO. Your own key unlocks it in SETTINGS.`,
|
||||
[
|
||||
{ text: 'LATER', style: 'cancel' },
|
||||
{ text: 'SETTINGS', onPress: () => setSettingsVisible(true) },
|
||||
]
|
||||
`${feature} can be previewed and edited for free, but exporting it needs the PRO build.`
|
||||
);
|
||||
};
|
||||
// Saving, starring, spawning: the action IS the feature, so there is no
|
||||
// look to preview first — a Lite tap names it and points at the unlock,
|
||||
// and nothing else happens.
|
||||
// Saving, starring, spawning: the action IS the feature, so there is no look
|
||||
// to preview first — a LITE tap names it and nothing else happens.
|
||||
const promptProFeature = (feature: string) => {
|
||||
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Warning);
|
||||
Alert.alert(
|
||||
'PRO FEATURE',
|
||||
`${feature} needs PRO. Your own key unlocks it in SETTINGS.`,
|
||||
[
|
||||
{ text: 'LATER', style: 'cancel' },
|
||||
{ text: 'SETTINGS', onPress: () => setSettingsVisible(true) },
|
||||
]
|
||||
);
|
||||
};
|
||||
// Settings unlock: a valid key persists PRO and returns true.
|
||||
const handleUnlock = async (key: string): Promise<boolean> => {
|
||||
const ok = await activatePro(key);
|
||||
if (ok) {
|
||||
setPro(true);
|
||||
Haptics.notificationAsync(Haptics.NotificationFeedbackType.Success);
|
||||
}
|
||||
return ok;
|
||||
Alert.alert('PRO FEATURE', `${feature} needs the PRO build.`);
|
||||
};
|
||||
|
||||
// Watermark handed to the export engines (Skia + native): the ACCEPTED mark
|
||||
@@ -1712,7 +1687,6 @@ export default function App() {
|
||||
startupMode={startupMode}
|
||||
onStartupMode={handleStartupMode}
|
||||
pro={pro}
|
||||
onUnlock={handleUnlock}
|
||||
/>
|
||||
|
||||
{/* Session photo viewer (swipe across captured/exported photos) */}
|
||||
|
||||
Reference in New Issue
Block a user