all: start injecting shared objects

Start injecting shared object instances.

This is not a 100% conversion, as certain portions of the code are not
really ready for 100% DI constructors just yet.
This commit is contained in:
Alexander Capehart 2023-02-02 20:53:41 -07:00
parent 2a3e81889b
commit 8536c3da31
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
31 changed files with 97 additions and 95 deletions

View file

@ -50,12 +50,11 @@ import org.oxycblt.auxio.util.*
class DetailViewModel
@Inject
constructor(
private val musicRepository: MusicRepository,
private val audioInfoProvider: AudioInfo.Provider,
private val musicSettings: MusicSettings,
private val playbackSettings: PlaybackSettings
) : ViewModel(), MusicRepository.Listener {
private val musicRepository = MusicRepository.get()
private var currentSongJob: Job? = null
// --- SONG ---

View file

@ -39,10 +39,9 @@ class HomeViewModel
constructor(
private val homeSettings: HomeSettings,
private val playbackSettings: PlaybackSettings,
private val musicRepository: MusicRepository,
private val musicSettings: MusicSettings
) : ViewModel(), MusicRepository.Listener, HomeSettings.Listener {
private val musicRepository = MusicRepository.get()
private val _songsList = MutableStateFlow(listOf<Song>())
/** A list of [Song]s, sorted by the preferred [Sort], to be shown in the home view. */
val songsList: StateFlow<List<Song>>

View file

@ -18,6 +18,8 @@
package org.oxycblt.auxio.list.selection
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import org.oxycblt.auxio.music.*
@ -27,9 +29,9 @@ import org.oxycblt.auxio.music.library.Library
* A [ViewModel] that manages the current selection.
* @author Alexander Capehart (OxygenCobalt)
*/
class SelectionViewModel : ViewModel(), MusicRepository.Listener {
private val musicRepository = MusicRepository.get()
@HiltViewModel
class SelectionViewModel @Inject constructor(private val musicRepository: MusicRepository) :
ViewModel(), MusicRepository.Listener {
private val _selected = MutableStateFlow(listOf<Music>())
/** the currently selected items. These are ordered in earliest selected and latest selected. */
val selected: StateFlow<List<Music>>

View file

@ -23,11 +23,15 @@ import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import javax.inject.Singleton
import org.oxycblt.auxio.music.metadata.AudioInfo
import org.oxycblt.auxio.music.system.Indexer
@Module
@InstallIn(SingletonComponent::class)
class MusicModule {
@Singleton @Provides fun musicRepository() = MusicRepository.new()
@Singleton @Provides fun indexer() = Indexer.new()
@Provides fun settings(@ApplicationContext context: Context) = MusicSettings.from(context)
@Provides
fun audioInfoProvider(@ApplicationContext context: Context) = AudioInfo.Provider.from(context)

View file

@ -62,24 +62,11 @@ interface MusicRepository {
}
companion object {
@Volatile private var INSTANCE: MusicRepository? = null
/**
* Get a singleton instance.
* @return The (possibly newly-created) singleton instance.
* Create a new instance.
* @return A newly-created implementation of [MusicRepository].
*/
fun get(): MusicRepository {
val currentInstance = INSTANCE
if (currentInstance != null) {
return currentInstance
}
synchronized(this) {
val newInstance = RealMusicRepository()
INSTANCE = newInstance
return newInstance
}
}
fun new(): MusicRepository = RealMusicRepository()
}
}

View file

@ -18,6 +18,8 @@
package org.oxycblt.auxio.music
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import org.oxycblt.auxio.music.system.Indexer
@ -26,8 +28,9 @@ import org.oxycblt.auxio.music.system.Indexer
* A [ViewModel] providing data specific to the music loading process.
* @author Alexander Capehart (OxygenCobalt)
*/
class MusicViewModel : ViewModel(), Indexer.Listener {
private val indexer = Indexer.get()
@HiltViewModel
class MusicViewModel @Inject constructor(private val indexer: Indexer) :
ViewModel(), Indexer.Listener {
private val _indexerState = MutableStateFlow<Indexer.State?>(null)
/** The current music loading state, or null if no loading is going on. */

View file

@ -31,10 +31,9 @@ import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.yield
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.library.RawSong
import org.oxycblt.auxio.music.library.RealSong
import org.oxycblt.auxio.music.metadata.Date
import org.oxycblt.auxio.music.parsing.parseId3v2PositionField
import org.oxycblt.auxio.music.parsing.transformPositionField
import org.oxycblt.auxio.music.metadata.parseId3v2PositionField
import org.oxycblt.auxio.music.metadata.transformPositionField
import org.oxycblt.auxio.music.storage.Directory
import org.oxycblt.auxio.music.storage.contentResolverSafe
import org.oxycblt.auxio.music.storage.directoryCompat
@ -282,10 +281,10 @@ private abstract class RealMediaStoreExtractor(private val context: Context) : M
protected abstract fun addDirToSelector(dir: Directory, args: MutableList<String>): Boolean
/**
* Populate a [RawSong] with the "File Data" of the given [MediaStore] [Cursor], which
* is the data that cannot be cached. This includes any information not intrinsic to the file
* and instead dependent on the file-system, which could change without invalidating the cache
* due to volume additions or removals.
* Populate a [RawSong] with the "File Data" of the given [MediaStore] [Cursor], which is the
* data that cannot be cached. This includes any information not intrinsic to the file and
* instead dependent on the file-system, which could change without invalidating the cache due
* to volume additions or removals.
* @param cursor The [Cursor] to read from.
* @param rawSong The [RawSong] to populate.
* @see populateMetadata
@ -302,9 +301,9 @@ private abstract class RealMediaStoreExtractor(private val context: Context) : M
}
/**
* Populate a [RawSong] with the Metadata of the given [MediaStore] [Cursor], which is
* the data about a [RawSong] that can be cached. This includes any information
* intrinsic to the file or it's file format, such as music tags.
* Populate a [RawSong] with the Metadata of the given [MediaStore] [Cursor], which is the data
* about a [RawSong] that can be cached. This includes any information intrinsic to the file or
* it's file format, such as music tags.
* @param cursor The [Cursor] to read from.
* @param rawSong The [RawSong] to populate.
* @see populateFileData

View file

@ -30,10 +30,9 @@ import androidx.room.TypeConverter
import androidx.room.TypeConverters
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.library.RawSong
import org.oxycblt.auxio.music.library.RealSong
import org.oxycblt.auxio.music.metadata.Date
import org.oxycblt.auxio.music.parsing.correctWhitespace
import org.oxycblt.auxio.music.parsing.splitEscaped
import org.oxycblt.auxio.music.metadata.correctWhitespace
import org.oxycblt.auxio.music.metadata.splitEscaped
import org.oxycblt.auxio.util.*
/**

View file

@ -24,11 +24,10 @@ import com.google.android.exoplayer2.MetadataRetriever
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.yield
import org.oxycblt.auxio.music.library.RawSong
import org.oxycblt.auxio.music.library.RealSong
import org.oxycblt.auxio.music.metadata.Date
import org.oxycblt.auxio.music.metadata.TextTags
import org.oxycblt.auxio.music.parsing.parseId3v2PositionField
import org.oxycblt.auxio.music.parsing.parseVorbisPositionField
import org.oxycblt.auxio.music.metadata.parseId3v2PositionField
import org.oxycblt.auxio.music.metadata.parseVorbisPositionField
import org.oxycblt.auxio.music.storage.toAudioUri
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logW

View file

@ -22,7 +22,10 @@ import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.metadata.*
import org.oxycblt.auxio.music.storage.Directory
/** Raw information about a [RealSong] obtained from the filesystem/Extractor instances. */
/**
* Raw information about a [RealSong] obtained from the filesystem/Extractor instances.
* @author Alexander Capehart (OxygenCobalt)
*/
class RawSong(
/**
* The ID of the [RealSong]'s audio file, obtained from MediaStore. Note that this ID is highly
@ -83,7 +86,10 @@ class RawSong(
var genreNames: List<String> = listOf()
)
/** Raw information about an [RealAlbum] obtained from the component [RealSong] instances. */
/**
* Raw information about an [RealAlbum] obtained from the component [RealSong] instances.
* @author Alexander Capehart (OxygenCobalt)
*/
class RawAlbum(
/**
* The ID of the [RealAlbum]'s grouping, obtained from MediaStore. Note that this ID is highly
@ -128,6 +134,7 @@ class RawAlbum(
/**
* Raw information about an [RealArtist] obtained from the component [RealSong] and [RealAlbum]
* instances.
* @author Alexander Capehart (OxygenCobalt)
*/
class RawArtist(
/** @see Music.UID */
@ -166,7 +173,10 @@ class RawArtist(
}
}
/** Raw information about a [RealGenre] obtained from the component [RealSong] instances. */
/**
* Raw information about a [RealGenre] obtained from the component [RealSong] instances.
* @author Alexander Capehart (OxygenCobalt)
*/
class RawGenre(
/** @see Music.rawName */
val name: String? = null

View file

@ -34,8 +34,8 @@ import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.metadata.Date
import org.oxycblt.auxio.music.metadata.Disc
import org.oxycblt.auxio.music.metadata.ReleaseType
import org.oxycblt.auxio.music.parsing.parseId3GenreNames
import org.oxycblt.auxio.music.parsing.parseMultiValue
import org.oxycblt.auxio.music.metadata.parseId3GenreNames
import org.oxycblt.auxio.music.metadata.parseMultiValue
import org.oxycblt.auxio.music.storage.MimeType
import org.oxycblt.auxio.music.storage.Path
import org.oxycblt.auxio.music.storage.toAudioUri

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.music.parsing
package org.oxycblt.auxio.music.metadata
/**
* Defines the allowed separator characters that can be used to delimit multi-value tags.

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.music.parsing
package org.oxycblt.auxio.music.metadata
import android.os.Bundle
import android.view.LayoutInflater

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.music.parsing
package org.oxycblt.auxio.music.metadata
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.util.nonZeroOrNull

View file

@ -21,7 +21,6 @@ import com.google.android.exoplayer2.metadata.Metadata
import com.google.android.exoplayer2.metadata.id3.InternalFrame
import com.google.android.exoplayer2.metadata.id3.TextInformationFrame
import com.google.android.exoplayer2.metadata.vorbis.VorbisComment
import org.oxycblt.auxio.music.parsing.correctWhitespace
/**
* Processing wrapper for [Metadata] that allows organized access to text-based audio tags.

View file

@ -200,8 +200,6 @@ interface Indexer {
}
companion object {
@Volatile private var INSTANCE: Indexer? = null
/**
* A version-compatible identifier for the read external storage permission required by the
* system to load audio.
@ -215,21 +213,10 @@ interface Indexer {
}
/**
* Get a singleton instance.
* @return The (possibly newly-created) singleton instance.
* Create a new instance.
* @return A newly-created implementation of [Indexer].
*/
fun get(): Indexer {
val currentInstance = INSTANCE
if (currentInstance != null) {
return currentInstance
}
synchronized(this) {
val newInstance = RealIndexer()
INSTANCE = newInstance
return newInstance
}
}
fun new(): Indexer = RealIndexer()
}
}

View file

@ -27,6 +27,7 @@ import android.os.PowerManager
import android.provider.MediaStore
import coil.imageLoader
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@ -55,9 +56,9 @@ import org.oxycblt.auxio.util.logD
*/
@AndroidEntryPoint
class IndexerService : Service(), Indexer.Controller, MusicSettings.Listener {
private val indexer = Indexer.get()
private val musicRepository = MusicRepository.get()
private val playbackManager = PlaybackStateManager.get()
@Inject lateinit var indexer: Indexer
@Inject lateinit var musicRepository: MusicRepository
@Inject lateinit var playbackManager: PlaybackStateManager
private val serviceJob = Job()
private val indexScope = CoroutineScope(serviceJob + Dispatchers.IO)
private var currentIndexJob: Job? = null

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.music.picker
package org.oxycblt.auxio.picker
import android.view.View
import android.view.ViewGroup

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.music.picker
package org.oxycblt.auxio.picker
import android.os.Bundle
import androidx.fragment.app.activityViewModels

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.music.picker
package org.oxycblt.auxio.picker
import android.os.Bundle
import android.view.LayoutInflater

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.music.picker
package org.oxycblt.auxio.picker
import android.os.Bundle
import androidx.fragment.app.activityViewModels

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.music.picker
package org.oxycblt.auxio.picker
import android.view.View
import android.view.ViewGroup

View file

@ -15,7 +15,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.music.picker
package org.oxycblt.auxio.picker
import android.os.Bundle
import android.view.LayoutInflater

View file

@ -15,9 +15,11 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.music.picker
package org.oxycblt.auxio.picker
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import org.oxycblt.auxio.music.*
@ -29,8 +31,9 @@ import org.oxycblt.auxio.util.unlikelyToBeNull
* contain the music themselves and then exit if the library changes.
* @author Alexander Capehart (OxygenCobalt)
*/
class PickerViewModel : ViewModel(), MusicRepository.Listener {
private val musicRepository = MusicRepository.get()
@HiltViewModel
class PickerViewModel @Inject constructor(private val musicRepository: MusicRepository) :
ViewModel(), MusicRepository.Listener {
private val _currentItem = MutableStateFlow<Music?>(null)
/** The current item whose artists should be shown in the picker. Null if there is no item. */

View file

@ -24,10 +24,13 @@ import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import org.oxycblt.auxio.playback.persist.PersistenceRepository
import org.oxycblt.auxio.playback.state.PlaybackStateManager
@Module
@InstallIn(SingletonComponent::class)
class PlaybackModule {
@Provides fun playbackStateManager() = PlaybackStateManager.get()
@Provides fun settings(@ApplicationContext context: Context) = PlaybackSettings.from(context)
@Provides

View file

@ -39,12 +39,12 @@ import org.oxycblt.auxio.playback.state.*
class PlaybackViewModel
@Inject
constructor(
private val persistenceRepository: PersistenceRepository,
private val playbackManager: PlaybackStateManager,
private val playbackSettings: PlaybackSettings,
private val persistenceRepository: PersistenceRepository,
private val musicRepository: MusicRepository,
private val musicSettings: MusicSettings
) : ViewModel(), PlaybackStateManager.Listener {
private val playbackManager = PlaybackStateManager.get()
private val musicRepository = MusicRepository.get()
private var lastPositionJob: Job? = null
private val _song = MutableStateFlow<Song?>(null)

View file

@ -18,6 +18,8 @@
package org.oxycblt.auxio.playback.queue
import androidx.lifecycle.ViewModel
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import org.oxycblt.auxio.list.adapter.BasicListInstructions
@ -30,8 +32,9 @@ import org.oxycblt.auxio.playback.state.PlaybackStateManager
*
* @author Alexander Capehart (OxygenCobalt)
*/
class QueueViewModel : ViewModel(), PlaybackStateManager.Listener {
private val playbackManager = PlaybackStateManager.get()
@HiltViewModel
class QueueViewModel @Inject constructor(private val playbackManager: PlaybackStateManager) :
ViewModel(), PlaybackStateManager.Listener {
private val _queue = MutableStateFlow(listOf<Song>())
/** The current queue. */

View file

@ -39,6 +39,7 @@ import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
import com.google.android.exoplayer2.mediacodec.MediaCodecSelector
import com.google.android.exoplayer2.source.DefaultMediaSourceFactory
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
@ -93,11 +94,11 @@ class PlaybackService :
private val systemReceiver = PlaybackReceiver()
// Shared components
private val playbackManager = PlaybackStateManager.get()
private lateinit var playbackSettings: PlaybackSettings
private lateinit var persistenceRepository: PersistenceRepository
private val musicRepository = MusicRepository.get()
private lateinit var musicSettings: MusicSettings
@Inject lateinit var playbackManager: PlaybackStateManager
@Inject lateinit var playbackSettings: PlaybackSettings
@Inject lateinit var persistenceRepository: PersistenceRepository
@Inject lateinit var musicRepository: MusicRepository
@Inject lateinit var musicSettings: MusicSettings
// State
private lateinit var foregroundManager: ForegroundManager
@ -148,8 +149,6 @@ class PlaybackService :
.also { it.addListener(this) }
replayGainProcessor.addToListeners(player)
// Initialize the core service components
musicSettings = MusicSettings.from(this)
playbackSettings = PlaybackSettings.from(this)
persistenceRepository = PersistenceRepository.from(this)
foregroundManager = ForegroundManager(this)
// Initialize any listener-dependent components last as we wouldn't want a listener race

View file

@ -44,11 +44,11 @@ import org.oxycblt.auxio.util.logD
class SearchViewModel
@Inject
constructor(
private val musicRepository: MusicRepository,
private val searchEngine: SearchEngine,
private val searchSettings: SearchSettings,
private val playbackSettings: PlaybackSettings,
) : ViewModel(), MusicRepository.Listener {
private val musicRepository = MusicRepository.get()
private var lastQuery: String? = null
private var currentSearchJob: Job? = null

View file

@ -30,7 +30,7 @@
<dialog
android:id="@+id/artist_playback_picker_dialog"
android:name="org.oxycblt.auxio.music.picker.ArtistPlaybackPickerDialog"
android:name="org.oxycblt.auxio.picker.ArtistPlaybackPickerDialog"
android:label="artist_playback_picker_dialog"
tools:layout="@layout/dialog_music_picker">
<argument
@ -40,7 +40,7 @@
<dialog
android:id="@+id/artist_navigation_picker_dialog"
android:name="org.oxycblt.auxio.music.picker.ArtistNavigationPickerDialog"
android:name="org.oxycblt.auxio.picker.ArtistNavigationPickerDialog"
android:label="artist_navigation_picker_dialog"
tools:layout="@layout/dialog_music_picker">
<argument
@ -50,7 +50,7 @@
<dialog
android:id="@+id/genre_playback_picker_dialog"
android:name="org.oxycblt.auxio.music.picker.GenrePlaybackPickerDialog"
android:name="org.oxycblt.auxio.picker.GenrePlaybackPickerDialog"
android:label="genre_playback_picker_dialog"
tools:layout="@layout/dialog_music_picker">
<argument
@ -148,7 +148,7 @@
tools:layout="@layout/dialog_music_dirs" />
<dialog
android:id="@+id/separators_dialog"
android:name="org.oxycblt.auxio.music.parsing.SeparatorsDialog"
android:name="org.oxycblt.auxio.music.metadata.SeparatorsDialog"
android:label="music_dirs_dialog"
tools:layout="@layout/dialog_separators" />

View file

@ -20,6 +20,12 @@ package org.oxycblt.auxio.music.parsing
import org.junit.Assert.assertEquals
import org.junit.Test
import org.oxycblt.auxio.music.FakeMusicSettings
import org.oxycblt.auxio.music.metadata.correctWhitespace
import org.oxycblt.auxio.music.metadata.parseId3GenreNames
import org.oxycblt.auxio.music.metadata.parseId3v2PositionField
import org.oxycblt.auxio.music.metadata.parseMultiValue
import org.oxycblt.auxio.music.metadata.parseVorbisPositionField
import org.oxycblt.auxio.music.metadata.splitEscaped
class ParsingUtilTest {
@Test