feat(android): port cached_resume_state + fix CacheSource enum (M8 4.2 slice 8)
Two related fixes from re-reading the Drift source for slice 8:
1. The plan called this slice "last_played" but the Drift table is
`cached_resume_state` — kept Drift's name for cross-reference
during the port. Single-row JSON-blob pattern (queue, currentIndex,
positionMs, source) — ResumeController (Phase 6.5) handles the
Kotlin-side encode/decode so the schema stays stable across
resume-shape evolution.
2. CacheSource enum was incomplete: Task 4.1 ported only 3 of the 5
Drift variants. Added AUTO_LIKED + AUTO_PLAYLIST (used by the
auto-cache prefetcher to tag cached files by reason — drives the
bucket eviction priority order INCIDENTAL > AUTO_PREFETCH >
AUTO_PLAYLIST > AUTO_LIKED > MANUAL).
No data migration needed — schema version is still 1 and we have no
real users yet.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import com.fabledsword.minstrel.cache.db.dao.CachedArtistDao
|
||||
import com.fabledsword.minstrel.cache.db.dao.CachedLikeDao
|
||||
import com.fabledsword.minstrel.cache.db.dao.CachedMutationDao
|
||||
import com.fabledsword.minstrel.cache.db.dao.CachedPlaylistDao
|
||||
import com.fabledsword.minstrel.cache.db.dao.CachedResumeStateDao
|
||||
import com.fabledsword.minstrel.cache.db.dao.CachedPlaylistTrackDao
|
||||
import com.fabledsword.minstrel.cache.db.dao.CachedQuarantineDao
|
||||
import com.fabledsword.minstrel.cache.db.dao.CachedTrackDao
|
||||
@@ -19,6 +20,7 @@ import com.fabledsword.minstrel.cache.db.entities.CachedArtistEntity
|
||||
import com.fabledsword.minstrel.cache.db.entities.CachedLikeEntity
|
||||
import com.fabledsword.minstrel.cache.db.entities.CachedMutationEntity
|
||||
import com.fabledsword.minstrel.cache.db.entities.CachedPlaylistEntity
|
||||
import com.fabledsword.minstrel.cache.db.entities.CachedResumeStateEntity
|
||||
import com.fabledsword.minstrel.cache.db.entities.CachedPlaylistTrackEntity
|
||||
import com.fabledsword.minstrel.cache.db.entities.CachedQuarantineEntity
|
||||
import com.fabledsword.minstrel.cache.db.entities.CachedTrackEntity
|
||||
@@ -49,6 +51,7 @@ import com.fabledsword.minstrel.cache.db.entities.SyncMetadataEntity
|
||||
CachedQuarantineEntity::class,
|
||||
AudioCacheIndexEntity::class,
|
||||
CachedMutationEntity::class,
|
||||
CachedResumeStateEntity::class,
|
||||
],
|
||||
version = 1,
|
||||
exportSchema = true,
|
||||
@@ -65,4 +68,5 @@ abstract class AppDatabase : RoomDatabase() {
|
||||
abstract fun cachedQuarantineDao(): CachedQuarantineDao
|
||||
abstract fun audioCacheIndexDao(): AudioCacheIndexDao
|
||||
abstract fun cachedMutationDao(): CachedMutationDao
|
||||
abstract fun cachedResumeStateDao(): CachedResumeStateDao
|
||||
}
|
||||
|
||||
+8
-3
@@ -5,13 +5,18 @@ import kotlinx.datetime.Instant
|
||||
|
||||
/**
|
||||
* Source category for a cached audio file. Mirrors the Drift `CacheSource`
|
||||
* enum used by the Flutter client's `audio_cache_index` table.
|
||||
* enum used by the Flutter client's `audio_cache_index` table 1:1.
|
||||
*
|
||||
* - `MANUAL`: user explicitly pinned (e.g. "save for offline")
|
||||
* - `INCIDENTAL`: cached as a side effect of playback streaming
|
||||
* - `AUTO_LIKED`: auto-cached because the track is liked
|
||||
* - `AUTO_PLAYLIST`: auto-cached because it's in a pinned playlist
|
||||
* - `AUTO_PREFETCH`: pre-warmed by background prefetch heuristics
|
||||
* - `INCIDENTAL`: cached as a side effect of playback streaming
|
||||
*
|
||||
* Eviction priority order (first to evict): INCIDENTAL → AUTO_PREFETCH
|
||||
* → AUTO_PLAYLIST → AUTO_LIKED → MANUAL.
|
||||
*/
|
||||
enum class CacheSource { MANUAL, INCIDENTAL, AUTO_PREFETCH }
|
||||
enum class CacheSource { MANUAL, AUTO_LIKED, AUTO_PLAYLIST, AUTO_PREFETCH, INCIDENTAL }
|
||||
|
||||
/**
|
||||
* Cross-cutting Room type converters. Registered on `@Database` via
|
||||
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package com.fabledsword.minstrel.cache.db.dao
|
||||
|
||||
import androidx.room.Dao
|
||||
import androidx.room.Insert
|
||||
import androidx.room.OnConflictStrategy
|
||||
import androidx.room.Query
|
||||
import com.fabledsword.minstrel.cache.db.entities.CachedResumeStateEntity
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
|
||||
@Dao
|
||||
interface CachedResumeStateDao {
|
||||
@Query("SELECT * FROM cached_resume_state WHERE id = 1")
|
||||
suspend fun get(): CachedResumeStateEntity?
|
||||
|
||||
@Query("SELECT * FROM cached_resume_state WHERE id = 1")
|
||||
fun observe(): Flow<CachedResumeStateEntity?>
|
||||
|
||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
suspend fun upsert(row: CachedResumeStateEntity)
|
||||
|
||||
@Query("DELETE FROM cached_resume_state")
|
||||
suspend fun clear()
|
||||
}
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
package com.fabledsword.minstrel.cache.db.entities
|
||||
|
||||
import androidx.room.Entity
|
||||
import androidx.room.PrimaryKey
|
||||
import kotlinx.datetime.Clock
|
||||
import kotlinx.datetime.Instant
|
||||
|
||||
/**
|
||||
* Single-row snapshot of the last playback session — queue (as JSON),
|
||||
* current index, position, and source tag. Mirrors
|
||||
* `flutter_client/lib/cache/db.dart`'s `CachedResumeState` Drift table.
|
||||
*
|
||||
* Lets a torn-down session (the player's idle/dismissed teardown)
|
||||
* resume on next launch; without it the headset / lock-screen play
|
||||
* button has nothing to act on. The Flutter codebase persists this on
|
||||
* every queue change and reads on cold start.
|
||||
*
|
||||
* The `json` field carries the entire ResumeState shape (queue trackrefs,
|
||||
* currentIndex, positionMs, sourceTag). Kotlin-side deserialization
|
||||
* happens in the ResumeController (Phase 6.5) so the schema stays
|
||||
* stable across resume-shape changes.
|
||||
*/
|
||||
@Entity(tableName = "cached_resume_state")
|
||||
data class CachedResumeStateEntity(
|
||||
@PrimaryKey val id: Int = 1,
|
||||
val json: String,
|
||||
val updatedAt: Instant = Clock.System.now(),
|
||||
)
|
||||
Reference in New Issue
Block a user