feat(android): EventsApi + wire types for /api/events
Retrofit interface + the four request body variants (play_started / play_ended / play_skipped / play_offline) matching flutter_client/lib/api/endpoints/events.dart. play_started's response carries play_event_id (nullable). Not wired into any caller yet — PlayEventsReporter lands later. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,31 @@
|
||||
package com.fabledsword.minstrel.api.endpoints
|
||||
|
||||
import com.fabledsword.minstrel.models.wire.PlayEndedRequest
|
||||
import com.fabledsword.minstrel.models.wire.PlayOfflineRequest
|
||||
import com.fabledsword.minstrel.models.wire.PlaySkippedRequest
|
||||
import com.fabledsword.minstrel.models.wire.PlayStartedRequest
|
||||
import com.fabledsword.minstrel.models.wire.PlayStartedResponse
|
||||
import retrofit2.http.Body
|
||||
import retrofit2.http.POST
|
||||
|
||||
/**
|
||||
* Retrofit interface for `POST /api/events`. Mirrors the relevant
|
||||
* slice of `flutter_client/lib/api/endpoints/events.dart`. All four
|
||||
* variants share the same URL — the discriminator is in the request
|
||||
* body's `type` field. Server contract is best-effort per spec;
|
||||
* callers (the live path in PlayEventsReporter) swallow errors and
|
||||
* fall back to the offline mutation queue on failure.
|
||||
*/
|
||||
interface EventsApi {
|
||||
@POST("api/events")
|
||||
suspend fun playStarted(@Body body: PlayStartedRequest): PlayStartedResponse
|
||||
|
||||
@POST("api/events")
|
||||
suspend fun playEnded(@Body body: PlayEndedRequest)
|
||||
|
||||
@POST("api/events")
|
||||
suspend fun playSkipped(@Body body: PlaySkippedRequest)
|
||||
|
||||
@POST("api/events")
|
||||
suspend fun playOffline(@Body body: PlayOfflineRequest)
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.fabledsword.minstrel.models.wire
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
/**
|
||||
* Wire shapes for `POST /api/events`. The endpoint multiplexes four
|
||||
* variants on the `type` discriminator field, mirroring
|
||||
* `flutter_client/lib/api/endpoints/events.dart`.
|
||||
*
|
||||
* play_started returns the server-assigned play_event_id (nullable —
|
||||
* server may suppress under certain conditions); the other three
|
||||
* variants return 204-equivalent (no body).
|
||||
*/
|
||||
|
||||
@Serializable
|
||||
data class PlayStartedRequest(
|
||||
val type: String = "play_started",
|
||||
@SerialName("track_id") val trackId: String,
|
||||
@SerialName("client_id") val clientId: String,
|
||||
val source: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class PlayStartedResponse(
|
||||
@SerialName("play_event_id") val playEventId: String? = null,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class PlayEndedRequest(
|
||||
val type: String = "play_ended",
|
||||
@SerialName("play_event_id") val playEventId: String,
|
||||
@SerialName("duration_played_ms") val durationPlayedMs: Long,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class PlaySkippedRequest(
|
||||
val type: String = "play_skipped",
|
||||
@SerialName("play_event_id") val playEventId: String,
|
||||
@SerialName("position_ms") val positionMs: Long,
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class PlayOfflineRequest(
|
||||
val type: String = "play_offline",
|
||||
@SerialName("track_id") val trackId: String,
|
||||
@SerialName("client_id") val clientId: String,
|
||||
val at: String,
|
||||
@SerialName("duration_played_ms") val durationPlayedMs: Long,
|
||||
val source: String? = null,
|
||||
)
|
||||
Reference in New Issue
Block a user