Some checks failed
Build & Release APK / build (push) Has been cancelled
- GuideDisc breathes with work/rest inside the sweep ring; flicks pulse at flick rhythm since each 1s step re-triggers inflate - Button variants (primary/secondary/danger) with pressed feedback - Done screen: spring-in check ring + session stats card - Settings: round -/+ stepper, disabled at 5-30s bounds - Home hero glow, shared Card, drawn SVG gear replaces emoji Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
81 lines
3.2 KiB
TypeScript
81 lines
3.2 KiB
TypeScript
import { Alert, Pressable, StyleSheet, Text, View } from "react-native";
|
||
import { Button, Card, StatRow } from "../components/ui";
|
||
import { adjustHold, currentHold, resetProgress } from "../lib/store";
|
||
import { C } from "../lib/theme";
|
||
import { useStore } from "../lib/useStore";
|
||
import { MAX_HOLD, MIN_HOLD } from "../lib/workout";
|
||
|
||
function StepperButton({ label, disabled, onPress }: { label: string; disabled: boolean; onPress: () => void }) {
|
||
return (
|
||
<Pressable
|
||
style={({ pressed }) => [s.step, disabled && s.stepDisabled, pressed && !disabled && s.stepPressed]}
|
||
onPress={onPress}
|
||
disabled={disabled}
|
||
>
|
||
<Text style={[s.stepText, disabled && s.stepTextDisabled]}>{label}</Text>
|
||
</Pressable>
|
||
);
|
||
}
|
||
|
||
export default function Settings() {
|
||
const { sessionsCompleted, holdAdjust } = useStore();
|
||
const hold = currentHold();
|
||
|
||
return (
|
||
<View style={s.screen}>
|
||
<Text style={s.section}>Difficulty</Text>
|
||
<Card style={{ marginBottom: 12 }}>
|
||
<View style={s.stepperRow}>
|
||
<StepperButton label="−" disabled={hold <= MIN_HOLD} onPress={() => adjustHold(-1)} />
|
||
<View style={s.stepperValue}>
|
||
<Text style={s.holdValue}>{hold}s</Text>
|
||
<Text style={s.holdLabel}>hold length</Text>
|
||
</View>
|
||
<StepperButton label="+" disabled={hold >= MAX_HOLD} onPress={() => adjustHold(1)} />
|
||
</View>
|
||
<StatRow label="Manual adjustment" value={`${holdAdjust >= 0 ? "+" : ""}${holdAdjust}s`} />
|
||
</Card>
|
||
<Text style={s.hint}>
|
||
Holds grow automatically by 1s every 3 completed sessions ({MIN_HOLD}–{MAX_HOLD}s). Adjust here if a session
|
||
feels too easy or too hard — the adjustment stacks with the automatic progression.
|
||
</Text>
|
||
|
||
<Text style={s.section}>Progress</Text>
|
||
<Button
|
||
title="Reset progress"
|
||
variant="danger"
|
||
onPress={() =>
|
||
Alert.alert("Reset progress?", `This clears ${sessionsCompleted} completed sessions and starts over at ${MIN_HOLD}s holds.`, [
|
||
{ text: "Cancel", style: "cancel" },
|
||
{ text: "Reset", style: "destructive", onPress: resetProgress },
|
||
])
|
||
}
|
||
/>
|
||
</View>
|
||
);
|
||
}
|
||
|
||
const s = StyleSheet.create({
|
||
screen: { flex: 1, backgroundColor: C.bg, padding: 20 },
|
||
section: { color: C.muted, fontSize: 13, textTransform: "uppercase", letterSpacing: 1.2, marginBottom: 8, marginTop: 12 },
|
||
stepperRow: { flexDirection: "row", alignItems: "center", justifyContent: "space-between", paddingVertical: 14 },
|
||
stepperValue: { alignItems: "center" },
|
||
holdValue: { color: C.accent, fontSize: 34, fontWeight: "700", fontVariant: ["tabular-nums"] },
|
||
holdLabel: { color: C.muted, fontSize: 12, textTransform: "uppercase", letterSpacing: 1.2, marginTop: 2 },
|
||
step: {
|
||
width: 52,
|
||
height: 52,
|
||
borderRadius: 26,
|
||
backgroundColor: C.surface2,
|
||
borderWidth: 1,
|
||
borderColor: C.border,
|
||
alignItems: "center",
|
||
justifyContent: "center",
|
||
},
|
||
stepPressed: { opacity: 0.7, transform: [{ scale: 0.95 }] },
|
||
stepDisabled: { opacity: 0.35 },
|
||
stepText: { color: C.text, fontSize: 26, fontWeight: "600", lineHeight: 30 },
|
||
stepTextDisabled: { color: C.muted },
|
||
hint: { color: C.muted, fontSize: 13, lineHeight: 19, marginBottom: 12 },
|
||
});
|