Skip to content

Commit

Permalink
Refactor Dependency Injection & Add Audio Caching
Browse files Browse the repository at this point in the history
  • Loading branch information
brahmkshatriya committed Mar 20, 2024
1 parent 3dcbaeb commit 7cdb087
Show file tree
Hide file tree
Showing 13 changed files with 108 additions and 59 deletions.
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.brahmkshatriya.echo.data.extensions
package dev.brahmkshatriya.echo.data

import android.content.Context
import androidx.core.net.toUri
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.brahmkshatriya.echo.di
package dev.brahmkshatriya.echo.data.extensions

import android.content.pm.ApplicationInfo
import tel.jeelpa.plugger.ManifestParser
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package dev.brahmkshatriya.echo.data.extensions

import android.content.Context
import dev.brahmkshatriya.echo.common.clients.ExtensionClient
import dev.brahmkshatriya.echo.data.OfflineExtension
import kotlinx.coroutines.flow.flowOf
import tel.jeelpa.plugger.PluginRepo

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package dev.brahmkshatriya.echo.di
package dev.brahmkshatriya.echo.data.extensions

import android.content.Context
import dev.brahmkshatriya.echo.common.clients.ExtensionClient
Expand Down
48 changes: 48 additions & 0 deletions app/src/main/java/dev/brahmkshatriya/echo/di/AppModule.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package dev.brahmkshatriya.echo.di

import android.app.Application
import android.content.Context
import android.content.SharedPreferences
import androidx.media3.common.util.UnstableApi
import androidx.media3.database.StandaloneDatabaseProvider
import androidx.media3.datasource.cache.LeastRecentlyUsedCacheEvictor
import androidx.media3.datasource.cache.SimpleCache
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dev.brahmkshatriya.echo.player.Queue
import kotlinx.coroutines.flow.MutableSharedFlow
import java.io.File
import javax.inject.Singleton


@Module
@InstallIn(SingletonComponent::class)
class AppModule {

@Provides
@Singleton
fun provideGlobalQueue() = Queue()

@Provides
@Singleton
fun provideThrowableFlow() = MutableSharedFlow<Throwable>()

@Provides
@Singleton
fun provideSettingsPreferences(application: Application): SharedPreferences =
application.getSharedPreferences(application.packageName, Context.MODE_PRIVATE)

@Provides
@Singleton
@UnstableApi
fun provideCache(application: Application): SimpleCache {
val databaseProvider = StandaloneDatabaseProvider(application)
return SimpleCache(
File(application.cacheDir, "exoplayer"),
LeastRecentlyUsedCacheEvictor(100 * 1024 * 1024L),
databaseProvider
)
}
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
package dev.brahmkshatriya.echo.di

import android.app.Application
import android.content.Context
import android.content.SharedPreferences
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import dev.brahmkshatriya.echo.common.clients.ExtensionClient
import dev.brahmkshatriya.echo.data.extensions.ApkManifestParser
import dev.brahmkshatriya.echo.data.extensions.LocalExtensionRepo
import dev.brahmkshatriya.echo.player.Queue
import kotlinx.coroutines.flow.MutableSharedFlow
import dev.brahmkshatriya.echo.data.extensions.RepoWithPreferences
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import tel.jeelpa.plugger.PluginRepo
Expand All @@ -22,10 +21,9 @@ import tel.jeelpa.plugger.pluginloader.file.FilePluginConfig
import tel.jeelpa.plugger.pluginloader.file.FileSystemPluginLoader
import javax.inject.Singleton


@Module
@InstallIn(SingletonComponent::class)
class PluginModule {
class ExtensionModule {

@Provides
@Singleton
Expand All @@ -44,7 +42,13 @@ class PluginModule {
return RepoWithPreferences(application, repo)
}

private val mutableExtensionFlow = MutableExtensionFlow(MutableStateFlow(null))
// Dagger cannot directly infer Foo<Bar>, if Bar is an interface
// That means the Flow<Clients?> cannot be directly injected,
// So, we need to wrap it in a data class and inject that instead
data class MutableFlow(val flow: MutableStateFlow<ExtensionClient?>)
data class ExtensionFlow(val flow: Flow<ExtensionClient?>)

private val mutableExtensionFlow = MutableFlow(MutableStateFlow(null))
private val extensionFlow = mutableExtensionFlow.flow.asStateFlow()

@Provides
Expand All @@ -53,20 +57,6 @@ class PluginModule {

@Provides
@Singleton
fun providesExtensionClient() =
ExtensionFlow(extensionFlow)

@Provides
@Singleton
fun provideGlobalQueue() = Queue()

@Provides
@Singleton
fun provideThrowableFlow() = MutableSharedFlow<Throwable>()

@Provides
@Singleton
fun provideSettingsPreferences(application: Application): SharedPreferences =
application.getSharedPreferences(application.packageName, Context.MODE_PRIVATE)
fun providesExtensionClient() = ExtensionFlow(extensionFlow)

}
12 changes: 0 additions & 12 deletions app/src/main/java/dev/brahmkshatriya/echo/di/FlowModels.kt

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import androidx.annotation.OptIn
import androidx.media3.common.AudioAttributes
import androidx.media3.common.C
import androidx.media3.common.util.UnstableApi
import androidx.media3.datasource.cache.CacheDataSource
import androidx.media3.datasource.cache.SimpleCache
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.source.DefaultMediaSourceFactory
import androidx.media3.session.DefaultMediaNotificationProvider
Expand All @@ -15,7 +17,7 @@ import androidx.media3.session.MediaSession
import dagger.hilt.android.AndroidEntryPoint
import dev.brahmkshatriya.echo.MainActivity
import dev.brahmkshatriya.echo.R
import dev.brahmkshatriya.echo.di.ExtensionFlow
import dev.brahmkshatriya.echo.di.ExtensionModule
import dev.brahmkshatriya.echo.ui.settings.AudioFragment.Companion.CLOSE_PLAYER
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
Expand All @@ -28,7 +30,7 @@ import javax.inject.Inject
@AndroidEntryPoint
class PlaybackService : MediaLibraryService() {
@Inject
lateinit var extension: ExtensionFlow
lateinit var extension: ExtensionModule.ExtensionFlow

@Inject
lateinit var global: Queue
Expand All @@ -39,6 +41,9 @@ class PlaybackService : MediaLibraryService() {
@Inject
lateinit var settings: SharedPreferences

@Inject
lateinit var cache: SimpleCache

private var mediaLibrarySession: MediaLibrarySession? = null
private val scope = CoroutineScope(Dispatchers.IO) + Job()

Expand All @@ -50,8 +55,14 @@ class PlaybackService : MediaLibraryService() {
.setContentType(C.AUDIO_CONTENT_TYPE_MUSIC).build()

val customDataSource = CustomDataSource.Factory(this, global, throwableFlow)

val cacheDataSourceFactory =
CacheDataSource.Factory()
.setCache(cache)
.setUpstreamDataSourceFactory(customDataSource)

val factory = DefaultMediaSourceFactory(this)
.setDataSourceFactory(customDataSource)
.setDataSourceFactory(cacheDataSourceFactory)

val player = ExoPlayer.Builder(this, factory)
.setHandleAudioBecomingNoisy(true)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import dev.brahmkshatriya.echo.common.clients.TrackClient
import dev.brahmkshatriya.echo.common.models.Album
import dev.brahmkshatriya.echo.common.models.Artist
import dev.brahmkshatriya.echo.common.models.Track
import dev.brahmkshatriya.echo.di.ExtensionFlow
import dev.brahmkshatriya.echo.di.ExtensionModule
import dev.brahmkshatriya.echo.utils.observe
import dev.brahmkshatriya.echo.utils.tryWith
import kotlinx.coroutines.Dispatchers
Expand All @@ -21,7 +21,7 @@ import javax.inject.Inject
@HiltViewModel
class PlayerViewModel @Inject constructor(
private val global: Queue,
trackFlow: ExtensionFlow,
trackFlow: ExtensionModule.ExtensionFlow,
private val throwableFlow: MutableSharedFlow<Throwable>,
application: Application
) : ViewModel() {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
package dev.brahmkshatriya.echo.ui.extension

import android.content.SharedPreferences
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import dev.brahmkshatriya.echo.common.clients.ExtensionClient
import dev.brahmkshatriya.echo.di.MutableExtensionFlow
import dev.brahmkshatriya.echo.di.ExtensionModule
import dev.brahmkshatriya.echo.utils.catchWith
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asStateFlow
Expand All @@ -15,8 +17,9 @@ import javax.inject.Inject

@HiltViewModel
class ExtensionViewModel @Inject constructor(
private val mutableExtensionFlow: MutableExtensionFlow,
private val mutableExtensionFlow: ExtensionModule.MutableFlow,
private val pluginRepo: PluginRepo<ExtensionClient>,
private val preferences: SharedPreferences,
val throwableFlow: MutableSharedFlow<Throwable>
) : ViewModel() {

Expand All @@ -27,23 +30,30 @@ class ExtensionViewModel @Inject constructor(
if (initialized) return
initialized = true
viewModelScope.launch {
extensionListFlow = pluginRepo.getAllPlugins { e ->
launch {
throwableFlow.emit(e)
}
}
mutableExtensionFlow.flow.value = extensionListFlow?.firstOrNull()?.firstOrNull()
extensionListFlow = pluginRepo.getAllPlugins {
launch { throwableFlow.emit(it) }
}.catchWith(throwableFlow)
val list = extensionListFlow?.firstOrNull()
val id = preferences.getString(LAST_EXTENSION_KEY, null)
mutableExtensionFlow.flow.value = list?.find {
it.metadata.id == id
} ?: list?.firstOrNull()
}
}

private var extensionListFlow: Flow<List<ExtensionClient>>? = null
fun getExtensionList() = extensionListFlow

fun setExtension(extension: ExtensionClient) {
preferences.edit().putString(LAST_EXTENSION_KEY, extension.metadata.id).apply()
viewModelScope.launch {
mutableExtensionFlow.flow.value = extension
}
}

fun getCurrentExtension() = mutableExtensionFlow.flow.value

companion object {
const val LAST_EXTENSION_KEY = "last_extension"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import androidx.paging.cachedIn
import dagger.hilt.android.lifecycle.HiltViewModel
import dev.brahmkshatriya.echo.common.clients.HomeFeedClient
import dev.brahmkshatriya.echo.common.models.MediaItemsContainer
import dev.brahmkshatriya.echo.di.ExtensionFlow
import dev.brahmkshatriya.echo.di.ExtensionModule
import dev.brahmkshatriya.echo.utils.catchWith
import dev.brahmkshatriya.echo.utils.observe
import dev.brahmkshatriya.echo.utils.tryWith
Expand All @@ -21,7 +21,8 @@ import javax.inject.Inject

@HiltViewModel
class HomeViewModel @Inject constructor(
val homeFeedFlow: ExtensionFlow, private val throwableFlow: MutableSharedFlow<Throwable>
val homeFeedFlow: ExtensionModule.ExtensionFlow,
private val throwableFlow: MutableSharedFlow<Throwable>
) : ViewModel() {

private val _feed: MutableStateFlow<PagingData<MediaItemsContainer>?> = MutableStateFlow(null)
Expand All @@ -43,10 +44,8 @@ class HomeViewModel @Inject constructor(
genre.value = genres.value?.firstOrNull()
}
tryWith(throwableFlow) {
homeClient?.getHomeFeed(genre.asStateFlow())
?.catchWith(throwableFlow)
?.cachedIn(viewModelScope)
?.collectLatest { feed ->
homeClient?.getHomeFeed(genre.asStateFlow())?.catchWith(throwableFlow)
?.cachedIn(viewModelScope)?.collectLatest { feed ->
_feed.value = feed
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import androidx.paging.PagingData
import dagger.hilt.android.lifecycle.HiltViewModel
import dev.brahmkshatriya.echo.common.clients.SearchClient
import dev.brahmkshatriya.echo.common.models.MediaItemsContainer
import dev.brahmkshatriya.echo.di.ExtensionFlow
import dev.brahmkshatriya.echo.di.ExtensionModule
import dev.brahmkshatriya.echo.utils.catchWith
import dev.brahmkshatriya.echo.utils.tryWith
import kotlinx.coroutines.Dispatchers
Expand All @@ -19,7 +19,7 @@ import javax.inject.Inject

@HiltViewModel
class SearchViewModel @Inject constructor(
val searchFlow: ExtensionFlow,
val searchFlow: ExtensionModule.ExtensionFlow,
private val throwableFlow: MutableSharedFlow<Throwable>,
) : ViewModel() {

Expand Down
4 changes: 3 additions & 1 deletion app/src/main/res/drawable/dialog_bg.xml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<inset xmlns:android="http://schemas.android.com/apk/res/android">
<inset xmlns:android="http://schemas.android.com/apk/res/android"
android:insetLeft="16dp"
android:insetRight="16dp">
<shape android:shape="rectangle">
<corners android:radius="16dp" />
<solid android:color="?attr/colorSurface" />
Expand Down

0 comments on commit 7cdb087

Please sign in to comment.