Add ability to choose alarm sound

Closes #5
This commit is contained in:
Brandon Presley 2022-08-25 20:41:01 +12:00
parent 537a1b960d
commit 48d4d59ac8
8 changed files with 61 additions and 10 deletions

View File

@ -14,7 +14,7 @@ import {
} from 'react-native-paper';
import {SQLiteDatabase} from 'react-native-sqlite-storage';
import Ionicon from 'react-native-vector-icons/Ionicons';
import {createPlans, createSets, createSettings, getDb} from './db';
import {addSound, createPlans, createSets, createSettings, getDb} from './db';
import Routes from './Routes';
export const Drawer = createDrawerNavigator<DrawerParamList>();
@ -58,6 +58,7 @@ const App = () => {
await _db.executeSql(createPlans);
await _db.executeSql(createSets);
await _db.executeSql(createSettings);
await _db.executeSql(addSound).catch(() => null);
setDb(_db);
const [result] = await _db.executeSql(`SELECT * FROM settings LIMIT 1`);
if (result.rows.length === 0)

View File

@ -36,7 +36,11 @@ export default function EditSet() {
const settings: Settings = result.rows.item(0);
if (!settings.alarm) return;
const milliseconds = settings.minutes * 60 * 1000 + settings.seconds * 1000;
NativeModules.AlarmModule.timer(milliseconds, !!settings.vibrate);
NativeModules.AlarmModule.timer(
milliseconds,
!!settings.vibrate,
settings.sound,
);
}, [db]);
const update = useCallback(

View File

@ -6,11 +6,12 @@ import React, {
useState,
} from 'react';
import {NativeModules, StyleSheet, Text, View} from 'react-native';
import {Searchbar, TextInput} from 'react-native-paper';
import {Button, Searchbar, TextInput} from 'react-native-paper';
import {DatabaseContext, SnackbarContext} from './App';
import ConfirmDialog from './ConfirmDialog';
import MassiveSwitch from './MassiveSwitch';
import Settings from './settings';
import DocumentPicker from 'react-native-document-picker';
export default function SettingsPage() {
const [vibrate, setVibrate] = useState(true);
@ -19,6 +20,7 @@ export default function SettingsPage() {
const [seconds, setSeconds] = useState<string>('');
const [alarm, setAlarm] = useState<boolean>(false);
const [predictive, setPredictive] = useState<boolean>(false);
const [sound, setSound] = useState<string>('');
const [battery, setBattery] = useState(false);
const [ignoring, setIgnoring] = useState(false);
const [search, setSearch] = useState('');
@ -35,6 +37,7 @@ export default function SettingsPage() {
setPredictive(!!settings.predict);
setMaxSets(settings.sets.toString());
setVibrate(!!settings.vibrate);
setSound(settings.sound);
NativeModules.AlarmModule.ignoringBattery(setIgnoring);
}, [db]);
@ -44,10 +47,10 @@ export default function SettingsPage() {
useEffect(() => {
db.executeSql(
`UPDATE settings SET vibrate=?,minutes=?,sets=?,seconds=?,alarm=?,predict=?`,
[vibrate, minutes, maxSets, seconds, alarm, predictive],
`UPDATE settings SET vibrate=?,minutes=?,sets=?,seconds=?,alarm=?,predict=?,sound=?`,
[vibrate, minutes, maxSets, seconds, alarm, predictive, sound],
);
}, [vibrate, minutes, maxSets, seconds, alarm, predictive, db]);
}, [vibrate, minutes, maxSets, seconds, alarm, predictive, sound, db]);
const changeAlarmEnabled = useCallback(
(enabled: boolean) => {
@ -72,6 +75,14 @@ export default function SettingsPage() {
[setVibrate],
);
const changeSound = useCallback(async () => {
const {fileCopyUri} = await DocumentPicker.pickSingle({
type: 'audio/*',
copyTo: 'documentDirectory',
});
if (fileCopyUri) setSound(fileCopyUri);
}, []);
const items: {name: string; element: ReactNode}[] = [
{
name: 'Sets per workout',
@ -162,6 +173,15 @@ export default function SettingsPage() {
</>
),
},
{
name: 'Alarm sound',
element: (
<Button onPress={changeSound}>
Alarm sound
{sound ? ': ' + sound.split('/')[sound.split('/').length - 1] : null}
</Button>
),
},
];
return (

View File

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

View File

@ -7,6 +7,7 @@ import android.os.Vibrator
import androidx.annotation.RequiresApi
import android.content.Intent
import android.media.AudioAttributes
import android.net.Uri
import android.os.Build
import android.os.VibrationEffect
import android.os.IBinder
@ -21,9 +22,25 @@ class AlarmService : Service(), OnPreparedListener {
onDestroy()
return START_STICKY
}
mediaPlayer = MediaPlayer.create(applicationContext, R.raw.argon)
mediaPlayer?.start()
mediaPlayer?.setOnCompletionListener { vibrator?.cancel() }
val sound = intent.extras?.getString("sound")
if (sound == null) {
mediaPlayer = MediaPlayer.create(applicationContext, R.raw.argon)
mediaPlayer?.start()
mediaPlayer?.setOnCompletionListener { vibrator?.cancel() }
} else {
mediaPlayer = MediaPlayer().apply {
setAudioAttributes(
AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_MUSIC)
.setUsage(AudioAttributes.USAGE_MEDIA)
.build()
)
setDataSource(applicationContext, Uri.parse(sound))
prepare()
start()
setOnCompletionListener { vibrator?.cancel() }
}
}
val pattern = longArrayOf(0, 300, 1300, 300, 1300, 300)
vibrator = applicationContext.getSystemService(VIBRATOR_SERVICE) as Vibrator
val audioAttributes = AudioAttributes.Builder()

View File

@ -19,12 +19,14 @@ class TimerService : Service() {
private var currentMs: Long? = null
private var countdownTimer: CountDownTimer? = null
private var vibrate: Boolean = true
private var sound: String? = null
@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")
vibrate = intent!!.extras!!.getBoolean("vibrate")
sound = intent.extras?.getString("sound")
if (intent.action == "add") {
manager?.cancel(NOTIFICATION_ID_DONE)
endMs = currentMs!!.toInt().plus(60000)
@ -80,6 +82,7 @@ class TimerService : Service() {
manager?.cancel(NOTIFICATION_ID_PENDING)
val alarmIntent = Intent(applicationContext, AlarmService::class.java)
alarmIntent.putExtra("vibrate", vibrate)
alarmIntent.putExtra("sound", sound)
applicationContext.startService(alarmIntent)
}
}

4
db.ts
View File

@ -32,3 +32,7 @@ export const createSettings = `
sets INTEGER NOT NULL DEFAULT 3
);
`;
export const addSound = `
ALTER TABLE settings ADD COLUMN sound TEXT NULL;
`;

View File

@ -5,4 +5,5 @@ export default interface Settings {
vibrate: number;
predict: number;
sets: number;
sound: string;
}