Add vibration setting for timers

This commit is contained in:
Brandon Presley 2022-08-20 16:37:59 +12:00
parent 16ba002387
commit 4c185f0346
9 changed files with 62 additions and 34 deletions

View File

@ -62,6 +62,8 @@ const App = () => {
if (seconds === null) await setItem('seconds', '30');
const alarmEnabled = await getItem('alarmEnabled');
if (alarmEnabled === null) await setItem('alarmEnabled', 'false');
const vibrate = await getItem('vibrate');
if (vibrate === null) await setItem('vibrate', 'true');
if (!(await getItem('predictiveSets')))
await setItem('predictiveSets', 'true');
if (!(await getItem('maxSets'))) await setItem('maxSets', '3');

View File

@ -29,13 +29,14 @@ export default function EditSet() {
}, [navigation]),
);
const notify = useCallback(async () => {
const startTimer = useCallback(async () => {
const enabled = await AsyncStorage.getItem('alarmEnabled');
if (enabled !== 'true') return;
const minutes = await AsyncStorage.getItem('minutes');
const seconds = await AsyncStorage.getItem('seconds');
const milliseconds = Number(minutes) * 60 * 1000 + Number(seconds) * 1000;
NativeModules.AlarmModule.timer(milliseconds);
const vibrate = (await AsyncStorage.getItem('vibrate')) === 'true';
NativeModules.AlarmModule.timer(milliseconds, vibrate);
}, []);
const update = useCallback(
@ -57,11 +58,11 @@ export default function EditSet() {
INSERT INTO sets(name, reps, weight, created, unit)
VALUES (?,?,?,strftime('%Y-%m-%dT%H:%M:%S', 'now', 'localtime'),?)
`;
startTimer();
await db.executeSql(insert, [name, reps, weight, unit]);
notify();
navigation.goBack();
},
[db, navigation, notify],
[db, navigation, startTimer],
);
const save = useCallback(

View File

@ -121,7 +121,7 @@ export default function SetList() {
todaysWorkouts[todaysWorkouts.indexOf(todaysSets[0].name!) + 1];
}
const best = await getBest(nextWorkout);
setNextSet({...best, created: new Date().toISOString()});
setNextSet({...best});
}, [getTodaysSets, getTodaysPlan, getBest]);
useFocusEffect(
@ -171,7 +171,6 @@ export default function SetList() {
reps: 0,
weight: 0,
unit: 'kg',
created: new Date().toISOString(),
};
navigation.navigate('EditSet', {set: nextSet || set});
}, [navigation, nextSet]);

View File

@ -14,19 +14,20 @@ import MassiveSwitch from './MassiveSwitch';
const {getItem, setItem} = AsyncStorage;
export default function SettingsPage() {
const [vibrate, setVibrate] = useState(true);
const [minutes, setMinutes] = useState<string>('');
const [maxSets, setMaxSets] = useState<string>('3');
const [seconds, setSeconds] = useState<string>('');
const [alarmEnabled, setAlarmEnabled] = useState<boolean>(false);
const [predictiveSets, setPredictiveSets] = useState<boolean>(false);
const [showBattery, setShowBattery] = useState(false);
const [alarm, setAlarm] = useState<boolean>(false);
const [predictive, setPredictive] = useState<boolean>(false);
const [battery, setBattery] = useState(false);
const [ignoring, setIgnoring] = useState(false);
const refresh = useCallback(async () => {
setMinutes((await getItem('minutes')) || '');
setSeconds((await getItem('seconds')) || '');
setAlarmEnabled((await getItem('alarmEnabled')) === 'true');
setPredictiveSets((await getItem('predictiveSets')) === 'true');
setAlarm((await getItem('alarmEnabled')) === 'true');
setPredictive((await getItem('predictiveSets')) === 'true');
setMaxSets((await getItem('maxSets')) || '');
NativeModules.AlarmModule.ignoringBattery(setIgnoring);
}, []);
@ -37,27 +38,27 @@ export default function SettingsPage() {
const changeAlarmEnabled = useCallback(
(enabled: boolean) => {
setAlarmEnabled(enabled);
if (enabled && !ignoring) setShowBattery(true);
setAlarm(enabled);
if (enabled && !ignoring) setBattery(true);
setItem('alarmEnabled', enabled ? 'true' : 'false');
},
[setShowBattery, ignoring],
[setBattery, ignoring],
);
const changePredictive = useCallback(
(enabled: boolean) => {
setPredictiveSets(enabled);
setPredictive(enabled);
setItem('predictiveSets', enabled ? 'true' : 'false');
ToastAndroid.show(
'Predictive sets guess whats next based on todays plan.',
ToastAndroid.LONG,
);
},
[setPredictiveSets],
[setPredictive],
);
return (
<View style={styles.container}>
const textInputs = (
<>
<TextInput
label="Rest minutes"
value={minutes}
@ -68,8 +69,8 @@ export default function SettingsPage() {
setItem('minutes', text);
}}
style={styles.text}
selectTextOnFocus
/>
<TextInput
label="Rest seconds"
value={seconds}
@ -80,8 +81,8 @@ export default function SettingsPage() {
setItem('seconds', s);
}}
style={styles.text}
selectTextOnFocus
/>
<TextInput
label="Sets per workout"
value={maxSets}
@ -91,30 +92,48 @@ export default function SettingsPage() {
setItem('maxSets', value);
}}
style={styles.text}
selectTextOnFocus
/>
</>
);
const changeVibrate = useCallback(
(value: boolean) => {
setVibrate(value);
setItem('vibrate', value ? 'true' : 'false');
},
[setVibrate],
);
return (
<View style={styles.container}>
{textInputs}
<Text style={styles.text}>Rest timers</Text>
<MassiveSwitch
style={[styles.text, {alignSelf: 'flex-start'}]}
value={alarmEnabled}
value={alarm}
onValueChange={changeAlarmEnabled}
/>
<Text style={styles.text}>Vibrate</Text>
<MassiveSwitch
style={[styles.text, {alignSelf: 'flex-start'}]}
value={vibrate}
onValueChange={changeVibrate}
/>
<ConfirmDialog
title="Battery optimizations"
show={showBattery}
setShow={setShowBattery}
show={battery}
setShow={setBattery}
onOk={() => {
NativeModules.AlarmModule.openSettings();
setShowBattery(false);
setBattery(false);
}}>
Disable battery optimizations for Massive to use rest timers.
</ConfirmDialog>
<Text style={styles.text}>Predictive sets</Text>
<MassiveSwitch
style={[styles.text, {alignSelf: 'flex-start'}]}
value={predictiveSets}
value={predictive}
onValueChange={changePredictive}
/>
</View>

View File

@ -83,7 +83,7 @@ export default function ViewBest() {
<XAxis
style={{marginHorizontal: -10, height: xAxisHeight}}
data={sets}
formatLabel={(_value, index) => formatMonth(sets[index].created)}
formatLabel={(_value, index) => formatMonth(sets[index].created!)}
contentInset={{left: 10, right: 10}}
svg={axesSvg}
/>

View File

@ -23,10 +23,11 @@ class AlarmModule internal constructor(context: ReactApplicationContext?) :
@RequiresApi(api = Build.VERSION_CODES.O)
@ReactMethod
fun timer(milliseconds: Int) {
fun timer(milliseconds: Int, vibrate: Boolean) {
Log.d("AlarmModule", "Queue alarm for $milliseconds delay")
val intent = Intent(reactApplicationContext, TimerService::class.java)
intent.putExtra("milliseconds", milliseconds)
intent.putExtra("vibrate", vibrate)
reactApplicationContext.startService(intent)
}

View File

@ -30,7 +30,9 @@ class AlarmService : Service(), OnPreparedListener {
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM)
.build()
vibrator!!.vibrate(VibrationEffect.createWaveform(pattern, 1), audioAttributes)
val vibrate = intent.extras!!.getBoolean("vibrate")
if (vibrate)
vibrator!!.vibrate(VibrationEffect.createWaveform(pattern, 1), audioAttributes)
return START_STICKY
}

View File

@ -19,17 +19,19 @@ class TimerService : Service() {
private var endMs: Int? = null
private var currentMs: Long? = null
private var countdownTimer: CountDownTimer? = null
private var vibrate: Boolean = true
@RequiresApi(Build.VERSION_CODES.O)
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
Log.d("TimerService", "Started timer service.")
Log.d("TimerService", "endMs=$endMs,currentMs=$currentMs")
if (intent?.action == "add") {
vibrate = intent!!.extras!!.getBoolean("vibrate")
if (intent.action == "add") {
endMs = currentMs!!.toInt().plus(60000)
applicationContext.stopService(Intent(applicationContext, AlarmService::class.java))
}
else {
endMs = intent!!.extras!!.getInt("milliseconds")
endMs = intent.extras!!.getInt("milliseconds")
}
Log.d("TimerService", "endMs=$endMs,currentMs=$currentMs")
notificationManager = getManager(applicationContext)
@ -68,7 +70,9 @@ class TimerService : Service() {
.setCategory(NotificationCompat.CATEGORY_ALARM)
.priority = NotificationCompat.PRIORITY_HIGH
notificationManager.notify(NOTIFICATION_ID, builder.build())
applicationContext.startService(Intent(applicationContext, AlarmService::class.java))
val alarmIntent = Intent(applicationContext, AlarmService::class.java)
alarmIntent.putExtra("vibrate", vibrate)
applicationContext.startService(alarmIntent)
}
}
}

2
set.ts
View File

@ -3,6 +3,6 @@ export default interface Set {
name: string;
reps: number;
weight: number;
created: string;
created?: string;
unit?: string;
}