diff --git a/app/src/main/java/com/radiola/data/repository/FavoritesRepositoryImpl.kt b/app/src/main/java/com/radiola/data/repository/FavoritesRepositoryImpl.kt new file mode 100644 index 0000000..d112aac --- /dev/null +++ b/app/src/main/java/com/radiola/data/repository/FavoritesRepositoryImpl.kt @@ -0,0 +1,47 @@ +package com.radiola.data.repository + +import com.radiola.data.local.AppDatabase +import com.radiola.data.local.entity.StationEntity +import com.radiola.domain.model.Station +import com.radiola.domain.repository.FavoritesRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject + +class FavoritesRepositoryImpl @Inject constructor( + private val db: AppDatabase +) : FavoritesRepository { + + override fun getFavorites(): Flow> { + return db.stationDao().getFavorites().map { list -> + list.map { it.toDomain() } + } + } + + override suspend fun addFavorite(station: Station) { + db.stationDao().setFavorite(station.id, true) + } + + override suspend fun removeFavorite(stationId: Int) { + db.stationDao().setFavorite(stationId, false) + } + + override fun isFavorite(stationId: Int): Flow { + return db.stationDao().isFavorite(stationId) + } + + override suspend fun reorderFavorites(orderedIds: List) { + // TODO: implement drag-sort reordering + } + + private fun StationEntity.toDomain(): Station = Station( + id = id, + name = name, + prefix = prefix, + streamUrl = streamUrl, + coverUrl = coverUrl, + genre = genre, + tags = tags.split(",").filter { it.isNotBlank() }, + sortOrder = sortOrder + ) +} diff --git a/app/src/main/java/com/radiola/data/repository/NowPlayingRepositoryImpl.kt b/app/src/main/java/com/radiola/data/repository/NowPlayingRepositoryImpl.kt new file mode 100644 index 0000000..b64bc84 --- /dev/null +++ b/app/src/main/java/com/radiola/data/repository/NowPlayingRepositoryImpl.kt @@ -0,0 +1,34 @@ +package com.radiola.data.repository + +import com.radiola.data.remote.RecordApi +import com.radiola.data.remote.ApiMapper.toDomain +import com.radiola.domain.model.Track +import com.radiola.domain.repository.NowPlayingRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.map +import javax.inject.Inject + +class NowPlayingRepositoryImpl @Inject constructor( + private val api: RecordApi +) : NowPlayingRepository { + + private val _nowPlaying = MutableStateFlow>(emptyMap()) + + override fun getNowPlaying(stationPrefix: String): Flow { + return _nowPlaying.map { it[stationPrefix] } + } + + override fun getAllNowPlaying(): Flow> = _nowPlaying + + override suspend fun refreshNowPlaying(): Result { + return try { + val response = api.getNowPlaying() + val map = response.result.associate { it.prefix to it.toDomain() } + _nowPlaying.value = map + Result.success(Unit) + } catch (e: Exception) { + Result.failure(e) + } + } +} diff --git a/app/src/main/java/com/radiola/data/repository/SettingsRepositoryImpl.kt b/app/src/main/java/com/radiola/data/repository/SettingsRepositoryImpl.kt new file mode 100644 index 0000000..86c35c6 --- /dev/null +++ b/app/src/main/java/com/radiola/data/repository/SettingsRepositoryImpl.kt @@ -0,0 +1,51 @@ +package com.radiola.data.repository + +import android.content.Context +import androidx.datastore.core.DataStore +import androidx.datastore.preferences.core.Preferences +import androidx.datastore.preferences.core.booleanPreferencesKey +import androidx.datastore.preferences.core.edit +import androidx.datastore.preferences.core.intPreferencesKey +import androidx.datastore.preferences.core.stringPreferencesKey +import androidx.datastore.preferences.core.stringSetPreferencesKey +import androidx.datastore.preferences.preferencesDataStore +import com.radiola.domain.repository.SettingsRepository +import dagger.hilt.android.qualifiers.ApplicationContext +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject + +private val Context.dataStore: DataStore by preferencesDataStore(name = "settings") + +class SettingsRepositoryImpl @Inject constructor( + @ApplicationContext private val context: Context +) : SettingsRepository { + + private val dataStore = context.dataStore + + companion object { + private val LAST_STATION_ID = intPreferencesKey("last_station_id") + private val SLEEP_TIMER = intPreferencesKey("sleep_timer_minutes") + private val ENABLED_SERVICES = stringSetPreferencesKey("enabled_deeplink_services") + private val EQUALIZER_PRESET = stringPreferencesKey("equalizer_preset") + private val RECORDING_ENABLED = booleanPreferencesKey("recording_enabled") + } + + override fun getLastStationId(): Flow = dataStore.data.map { it[LAST_STATION_ID] } + override suspend fun setLastStationId(id: Int) = dataStore.edit { it[LAST_STATION_ID] = id } + + override fun getSleepTimerMinutes(): Flow = dataStore.data.map { it[SLEEP_TIMER] ?: 30 } + override suspend fun setSleepTimerMinutes(minutes: Int) = dataStore.edit { it[SLEEP_TIMER] = minutes } + + override fun getEnabledDeeplinkServices(): Flow> = dataStore.data.map { + it[ENABLED_SERVICES] ?: setOf("yandex", "vk", "spotify", "apple", "youtube") + } + override suspend fun setEnabledDeeplinkServices(serviceIds: Set) = + dataStore.edit { it[ENABLED_SERVICES] = serviceIds } + + override fun getEqualizerPreset(): Flow = dataStore.data.map { it[EQUALIZER_PRESET] ?: "Flat" } + override suspend fun setEqualizerPreset(preset: String) = dataStore.edit { it[EQUALIZER_PRESET] = preset } + + override fun isRecordingEnabled(): Flow = dataStore.data.map { it[RECORDING_ENABLED] ?: false } + override suspend fun setRecordingEnabled(enabled: Boolean) = dataStore.edit { it[RECORDING_ENABLED] = enabled } +} diff --git a/app/src/main/java/com/radiola/data/repository/StationRepositoryImpl.kt b/app/src/main/java/com/radiola/data/repository/StationRepositoryImpl.kt new file mode 100644 index 0000000..7741d08 --- /dev/null +++ b/app/src/main/java/com/radiola/data/repository/StationRepositoryImpl.kt @@ -0,0 +1,62 @@ +package com.radiola.data.repository + +import com.radiola.data.local.AppDatabase +import com.radiola.data.local.entity.StationEntity +import com.radiola.data.remote.RecordApi +import com.radiola.data.remote.ApiMapper.toDomain +import com.radiola.domain.model.Station +import com.radiola.domain.repository.StationRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject + +class StationRepositoryImpl @Inject constructor( + private val api: RecordApi, + private val db: AppDatabase +) : StationRepository { + + override fun getStations(): Flow> { + return db.stationDao().getAll().map { entities -> + entities.map { it.toDomain() } + } + } + + override suspend fun refreshStations(): Result { + return try { + val response = api.getStations() + val entities = response.result.mapIndexed { index, dto -> + val domain = dto.toDomain() + StationEntity( + id = domain.id, + name = domain.name, + prefix = domain.prefix, + streamUrl = domain.streamUrl, + coverUrl = domain.coverUrl, + genre = domain.genre, + tags = domain.tags.joinToString(","), + sortOrder = index, + isFavorite = false + ) + } + db.stationDao().insertAll(entities) + Result.success(Unit) + } catch (e: Exception) { + Result.failure(e) + } + } + + override fun getStationById(id: Int): Flow { + return db.stationDao().getById(id).map { it?.toDomain() } + } + + private fun StationEntity.toDomain(): Station = Station( + id = id, + name = name, + prefix = prefix, + streamUrl = streamUrl, + coverUrl = coverUrl, + genre = genre, + tags = tags.split(",").filter { it.isNotBlank() }, + sortOrder = sortOrder + ) +} diff --git a/app/src/main/java/com/radiola/data/repository/TrackHistoryRepositoryImpl.kt b/app/src/main/java/com/radiola/data/repository/TrackHistoryRepositoryImpl.kt new file mode 100644 index 0000000..0f30c86 --- /dev/null +++ b/app/src/main/java/com/radiola/data/repository/TrackHistoryRepositoryImpl.kt @@ -0,0 +1,47 @@ +package com.radiola.data.repository + +import com.radiola.data.local.AppDatabase +import com.radiola.data.local.entity.TrackHistoryEntity +import com.radiola.domain.model.Track +import com.radiola.domain.repository.TrackHistoryRepository +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.map +import javax.inject.Inject + +class TrackHistoryRepositoryImpl @Inject constructor( + private val db: AppDatabase +) : TrackHistoryRepository { + + override fun getHistory(): Flow> { + return db.trackHistoryDao().getAll().map { list -> + list.map { it.toDomain() } + } + } + + override suspend fun addTrack(track: Track) { + val entity = TrackHistoryEntity( + artist = track.artist, + song = track.song, + stationName = track.stationName, + coverUrl = track.coverUrl, + timestamp = System.currentTimeMillis() + ) + db.trackHistoryDao().insert(entity) + db.trackHistoryDao().cleanupOld() + } + + override suspend fun removeTrack(track: Track) { + // Requires lookup by composite key; simplified for now + } + + override suspend fun searchHistory(query: String): List { + return db.trackHistoryDao().search(query).map { it.toDomain() } + } + + private fun TrackHistoryEntity.toDomain(): Track = Track( + artist = artist, + song = song, + coverUrl = coverUrl, + stationName = stationName + ) +}