Add intensity-based preferences and harden E2EE payload verification

This commit is contained in:
jjbrunton committed 2026-01-07 19:53:09 +00:00
1 parent e23f4557bb
commit 0a919f06fc
20 files changed
+2033 -251

No files matched your search

+75 -15
View File
@@ -20,9 +20,38 @@ import { PackTeaser } from "../../../src/components/PackTeaser";
import { colors, spacing, radius, typography } from "../../../src/theme";
import type { QuestionPack, Category } from "../../../src/types";
const HEADER_MAX_HEIGHT = 180;
const HEADER_MIN_HEIGHT = 100;
const HEADER_SCROLL_DISTANCE = HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT;
const HEADER_MAX_HEIGHT = 180;
const HEADER_MIN_HEIGHT = 100;
const HEADER_SCROLL_DISTANCE = HEADER_MAX_HEIGHT - HEADER_MIN_HEIGHT;
const INTENSITY_LABELS: Record<number, string> = {
1: "Light",
2: "Mild",
3: "Moderate",
4: "Spicy",
5: "Intense",
};
const clampIntensity = (value: number) => Math.min(5, Math.max(1, Math.round(value)));
const isValidIntensity = (value?: number | null): value is number =>
typeof value === "number" && value >= 1 && value <= 5;
const getIntensityDisplay = (pack: QuestionPack) => {
const min = isValidIntensity(pack.min_intensity) ? pack.min_intensity : null;
const max = isValidIntensity(pack.max_intensity) ? pack.max_intensity : null;
const avg = typeof pack.avg_intensity === "number" ? clampIntensity(pack.avg_intensity) : null;
const flameCount = max ?? avg ?? (pack.is_explicit ? 5 : 2);
const label = min && max
? min === max
? INTENSITY_LABELS[min]
: `${INTENSITY_LABELS[min]} - ${INTENSITY_LABELS[max]}`
: INTENSITY_LABELS[flameCount];
return { flameCount, label };
};
interface PackRowProps {
pack: QuestionPack;
@@ -34,8 +63,10 @@ interface PackRowProps {
onInfoPress: () => void;
}
function PackRow({ pack, isEnabled, isPremiumLocked, isExpanded, onToggle, onPress, onInfoPress }: PackRowProps) {
const questionCount = pack.questions?.[0]?.count || 0;
function PackRow({ pack, isEnabled, isPremiumLocked, isExpanded, onToggle, onPress, onInfoPress }: PackRowProps) {
const questionCount = pack.questions?.[0]?.count || 0;
const intensityDisplay = getIntensityDisplay(pack);
return (
<Pressable onPress={onPress} style={styles.packRow}>
@@ -58,11 +89,25 @@ function PackRow({ pack, isEnabled, isPremiumLocked, isExpanded, onToggle, onPre
</View>
)}
</View>
<Text style={styles.packMeta}>
{questionCount} {questionCount === 1 ? "question" : "questions"}
{isEnabled && <Text style={styles.packMetaEnabled}> · Enabled</Text>}
</Text>
</View>
<Text style={styles.packMeta}>
{questionCount} {questionCount === 1 ? "question" : "questions"}
{isEnabled && <Text style={styles.packMetaEnabled}> · Enabled</Text>}
</Text>
<View style={styles.packIntensityRow}>
<View style={styles.packIntensityFlames}>
{Array.from({ length: 5 }).map((_, index) => (
<Ionicons
key={`intensity-${pack.id}-${index}`}
name={index < intensityDisplay.flameCount ? "flame" : "flame-outline"}
size={12}
color={index < intensityDisplay.flameCount ? colors.primary : colors.textTertiary}
/>
))}
</View>
<Text style={styles.packIntensityText}>{intensityDisplay.label}</Text>
</View>
</View>
<Ionicons
name={isExpanded ? "chevron-up" : "chevron-down"}
@@ -670,11 +715,26 @@ const styles = StyleSheet.create({
color: colors.textTertiary,
marginTop: 2,
},
packMetaEnabled: {
color: colors.primary,
},
// Expanded Pack
packMetaEnabled: {
color: colors.primary,
},
packIntensityRow: {
flexDirection: "row",
alignItems: "center",
gap: 6,
marginTop: spacing.xs,
},
packIntensityFlames: {
flexDirection: "row",
gap: 2,
},
packIntensityText: {
...typography.caption2,
color: colors.textSecondary,
fontWeight: "600",
},
// Expanded Pack
packExpanded: {
paddingHorizontal: spacing.md,
paddingBottom: spacing.md,