feat: collect gyro and gps

This commit is contained in:
2026-05-24 07:17:51 +02:00
parent 4315944733
commit c11ad041d7
11 changed files with 616 additions and 0 deletions

View File

@@ -16,6 +16,8 @@ import at.lockstep.player.util.FolderMp3Scanner
import at.lockstep.player.util.MediaStoreMp3Scanner
import at.lockstep.player.util.Mp3EmbeddedMetadata
import at.lockstep.player.util.Mp3FolderCandidate
import at.lockstep.player.util.RunDataStorage
import at.lockstep.player.util.RunTrackDataSnapshot
import at.lockstep.player.util.TrackFileMatching
import at.lockstep.player.util.mp3DisplayNameFromUri
import kotlinx.coroutines.Dispatchers
@@ -66,12 +68,25 @@ class LockstepViewModel(
false,
)
val collectRunData: StateFlow<Boolean> =
prefs.collectRunData.stateIn(
viewModelScope,
SharingStarted.Eagerly,
false,
)
fun setAnnotationMode(enabled: Boolean) {
viewModelScope.launch {
prefs.setAnnotationMode(enabled)
}
}
fun setCollectRunData(enabled: Boolean) {
viewModelScope.launch {
prefs.setCollectRunData(enabled)
}
}
private val context get() = getApplication<Application>()
/**
@@ -175,6 +190,60 @@ class LockstepViewModel(
}
}
/**
* Writes one JSON file under public Documents/Lockstep/{runSessionFolder}/ when a track finishes or is skipped.
* Skips when [samples] is empty or the track has no paired local URI.
*/
fun persistRunData(
playlistId: String,
playlistDisplayName: String,
runSessionFolder: String,
event: TrackBoundaryEvent,
snapshot: RunTrackDataSnapshot,
) {
if (snapshot.isEmpty()) {
return
}
viewModelScope.launch(Dispatchers.IO) {
val pairing = pairingDao.findForTrack(playlistId, event.trackId)
val meta = pairing?.localUri?.takeIf { it.isNotBlank() } ?: return@launch
RunDataStorage.writeRunDataFile(
context = getApplication(),
runSessionFolder = runSessionFolder,
playlistDisplayName = playlistDisplayName,
trackQueueIndex0Based = event.queueIndex,
metaContentUri = meta,
snapshot = snapshot,
)
}
}
/** Flush in-progress run data when leaving Now Playing before a track boundary fires. */
fun persistRunDataForCurrentTrack(
playlistId: String,
playlistDisplayName: String,
runSessionFolder: String,
trackId: String,
queueIndex: Int,
snapshot: RunTrackDataSnapshot,
) {
if (snapshot.isEmpty()) {
return
}
viewModelScope.launch(Dispatchers.IO) {
val pairing = pairingDao.findForTrack(playlistId, trackId)
val meta = pairing?.localUri?.takeIf { it.isNotBlank() } ?: return@launch
RunDataStorage.writeRunDataFile(
context = getApplication(),
runSessionFolder = runSessionFolder,
playlistDisplayName = playlistDisplayName,
trackQueueIndex0Based = queueIndex,
metaContentUri = meta,
snapshot = snapshot,
)
}
}
suspend fun syncJukeboxIfToken(): String? {
val token = spotifyAccessToken.value
if (token.isNullOrBlank()) {