all: remove dependence on androidviewmodel

Entirely remove dependence on AndroidViewModel, replacing it with
dependency injection.
This commit is contained in:
Alexander Capehart 2023-01-29 20:37:06 -07:00
parent ccbd77918b
commit 138a2c3c1c
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
35 changed files with 282 additions and 102 deletions

View file

@ -12,6 +12,9 @@ track/disc fields
#### What's Fixed
- Fixed non-functioning "repeat all" repeat mode
#### Dev/Meta
- Started using dependency injection
## 3.0.2
#### What's New

View file

@ -20,6 +20,7 @@ package org.oxycblt.auxio
import android.content.Intent
import android.os.Bundle
import android.view.View
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.view.WindowCompat
@ -31,7 +32,6 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.state.InternalPlayer
import org.oxycblt.auxio.playback.system.PlaybackService
import org.oxycblt.auxio.ui.UISettings
import org.oxycblt.auxio.util.androidViewModels
import org.oxycblt.auxio.util.isNight
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.systemBarInsetsCompat
@ -53,7 +53,7 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat
*/
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
private val playbackModel: PlaybackViewModel by androidViewModels()
private val playbackModel: PlaybackViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

View file

@ -58,7 +58,7 @@ class MainFragment :
ViewBindingFragment<FragmentMainBinding>(),
ViewTreeObserver.OnPreDrawListener,
NavController.OnDestinationChangedListener {
private val playbackModel: PlaybackViewModel by androidActivityViewModels()
private val playbackModel: PlaybackViewModel by activityViewModels()
private val navModel: NavigationViewModel by activityViewModels()
private val selectionModel: SelectionViewModel by activityViewModels()
private val callback = DynamicBackPressedCallback()

View file

@ -54,7 +54,7 @@ class AlbumDetailFragment :
ListFragment<Song, FragmentDetailBinding>(), AlbumDetailAdapter.Listener {
private val detailModel: DetailViewModel by activityViewModels()
override val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val playbackModel: PlaybackViewModel by activityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
// Information about what album to display is initially within the navigation arguments
// as a UID, as that is the only safe way to parcel an album.

View file

@ -42,7 +42,6 @@ import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.library.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.collect
import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.logD
@ -58,7 +57,7 @@ class ArtistDetailFragment :
ListFragment<Music, FragmentDetailBinding>(), DetailAdapter.Listener<Music> {
private val detailModel: DetailViewModel by activityViewModels()
override val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val playbackModel: PlaybackViewModel by activityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
// Information about what artist to display is initially within the navigation arguments
// as a UID, as that is the only safe way to parcel an artist.

View file

@ -20,7 +20,10 @@ package org.oxycblt.auxio.detail
import android.app.Application
import androidx.annotation.StringRes
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
@ -47,12 +50,15 @@ import org.oxycblt.auxio.util.*
* @param application [Application] context required to initialize certain information.
* @author Alexander Capehart (OxygenCobalt)
*/
class DetailViewModel(application: Application) :
AndroidViewModel(application), MusicRepository.Listener {
@HiltViewModel
class DetailViewModel
@Inject
constructor(
private val audioInfoProvider: AudioInfo.Provider,
private val musicSettings: MusicSettings,
private val playbackSettings: PlaybackSettings
) : ViewModel(), MusicRepository.Listener {
private val musicRepository = MusicRepository.get()
private val musicSettings = MusicSettings.from(application)
private val playbackSettings = PlaybackSettings.from(application)
private val audioInfoProvider = AudioInfo.Provider.from(application)
private var currentSongJob: Job? = null

View file

@ -43,7 +43,6 @@ import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.library.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.collect
import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.logD
@ -59,7 +58,7 @@ class GenreDetailFragment :
ListFragment<Music, FragmentDetailBinding>(), DetailAdapter.Listener<Music> {
private val detailModel: DetailViewModel by activityViewModels()
override val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val playbackModel: PlaybackViewModel by activityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
// Information about what genre to display is initially within the navigation arguments
// as a UID, as that is the only safe way to parcel an genre.

View file

@ -22,6 +22,7 @@ import android.text.format.Formatter
import android.view.LayoutInflater
import androidx.appcompat.app.AlertDialog
import androidx.core.view.isInvisible
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
import dagger.hilt.android.AndroidEntryPoint
@ -31,7 +32,6 @@ import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.format.AudioInfo
import org.oxycblt.auxio.playback.formatDurationMs
import org.oxycblt.auxio.ui.ViewBindingDialogFragment
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.collectImmediately
/**
@ -40,7 +40,7 @@ import org.oxycblt.auxio.util.collectImmediately
*/
@AndroidEntryPoint
class SongDetailDialog : ViewBindingDialogFragment<DialogSongDetailBinding>() {
private val detailModel: DetailViewModel by androidActivityViewModels()
private val detailModel: DetailViewModel by activityViewModels()
// Information about what song to display is initially within the navigation arguments
// as a UID, as that is the only safe way to parcel an song.
private val args: SongDetailDialogArgs by navArgs()

View file

@ -68,10 +68,10 @@ import org.oxycblt.auxio.util.*
@AndroidEntryPoint
class HomeFragment :
SelectionFragment<FragmentHomeBinding>(), AppBarLayout.OnOffsetChangedListener {
private val homeModel: HomeViewModel by androidActivityViewModels()
private val homeModel: HomeViewModel by activityViewModels()
private val musicModel: MusicViewModel by activityViewModels()
private val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val playbackModel: PlaybackViewModel by activityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
private var storagePermissionLauncher: ActivityResultLauncher<String>? = null

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2023 Auxio Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.home
import android.content.Context
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
class HomeModule {
@Provides fun settings(@ApplicationContext context: Context) = HomeSettings.from(context)
}

View file

@ -17,8 +17,9 @@
package org.oxycblt.auxio.home
import android.app.Application
import androidx.lifecycle.AndroidViewModel
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.home.tabs.Tab
@ -32,12 +33,15 @@ import org.oxycblt.auxio.util.logD
* The ViewModel for managing the tab data and lists of the home view.
* @author Alexander Capehart (OxygenCobalt)
*/
class HomeViewModel(application: Application) :
AndroidViewModel(application), MusicRepository.Listener, HomeSettings.Listener {
@HiltViewModel
class HomeViewModel
@Inject
constructor(
private val homeSettings: HomeSettings,
private val playbackSettings: PlaybackSettings,
private val musicSettings: MusicSettings
) : ViewModel(), MusicRepository.Listener, HomeSettings.Listener {
private val musicRepository = MusicRepository.get()
private val homeSettings = HomeSettings.from(application)
private val musicSettings = MusicSettings.from(application)
private val playbackSettings = PlaybackSettings.from(application)
private val _songsList = MutableStateFlow(listOf<Song>())
/** A list of [Song]s, sorted by the preferred [Sort], to be shown in the home view. */

View file

@ -42,7 +42,6 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.formatDurationMs
import org.oxycblt.auxio.playback.secsToMs
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.collectImmediately
/**
@ -56,7 +55,7 @@ class AlbumListFragment :
FastScrollRecyclerView.PopupProvider {
private val homeModel: HomeViewModel by activityViewModels()
override val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val playbackModel: PlaybackViewModel by activityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
private val albumAdapter = AlbumAdapter(this)
// Save memory by re-using the same formatter and string builder when creating popup text

View file

@ -42,7 +42,6 @@ import org.oxycblt.auxio.music.library.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.formatDurationMs
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.nonZeroOrNull
@ -57,7 +56,7 @@ class ArtistListFragment :
FastScrollRecyclerView.Listener {
private val homeModel: HomeViewModel by activityViewModels()
override val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val playbackModel: PlaybackViewModel by activityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
private val artistAdapter = ArtistAdapter(this)

View file

@ -42,7 +42,6 @@ import org.oxycblt.auxio.music.library.Sort
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.formatDurationMs
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.collectImmediately
/**
@ -56,7 +55,7 @@ class GenreListFragment :
FastScrollRecyclerView.Listener {
private val homeModel: HomeViewModel by activityViewModels()
override val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val playbackModel: PlaybackViewModel by activityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
private val genreAdapter = GenreAdapter(this)

View file

@ -45,7 +45,6 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.formatDurationMs
import org.oxycblt.auxio.playback.secsToMs
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.collectImmediately
/**
@ -59,7 +58,7 @@ class SongListFragment :
FastScrollRecyclerView.Listener {
private val homeModel: HomeViewModel by activityViewModels()
override val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val playbackModel: PlaybackViewModel by activityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
private val songAdapter = SongAdapter(this)
// Save memory by re-using the same formatter and string builder when creating popup text

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2023 Auxio Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.image
import android.content.Context
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
class ImageModule {
@Provides fun settings(@ApplicationContext context: Context) = ImageSettings.from(context)
}

View file

@ -0,0 +1,34 @@
/*
* Copyright (c) 2023 Auxio Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.music
import android.content.Context
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import org.oxycblt.auxio.music.format.AudioInfo
@Module
@InstallIn(SingletonComponent::class)
class MusicModule {
@Provides fun settings(@ApplicationContext context: Context) = MusicSettings.from(context)
@Provides
fun audioInfoProvider(@ApplicationContext context: Context) = AudioInfo.Provider.from(context)
}

View file

@ -28,9 +28,9 @@ import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.room.TypeConverter
import androidx.room.TypeConverters
import org.oxycblt.auxio.music.RealSong
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.format.Date
import org.oxycblt.auxio.music.library.RealSong
import org.oxycblt.auxio.music.parsing.correctWhitespace
import org.oxycblt.auxio.music.parsing.splitEscaped
import org.oxycblt.auxio.util.*

View file

@ -28,8 +28,8 @@ import androidx.core.database.getIntOrNull
import androidx.core.database.getStringOrNull
import java.io.File
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.RealSong
import org.oxycblt.auxio.music.format.Date
import org.oxycblt.auxio.music.library.RealSong
import org.oxycblt.auxio.music.parsing.parseId3v2PositionField
import org.oxycblt.auxio.music.parsing.transformPositionField
import org.oxycblt.auxio.music.storage.Directory

View file

@ -22,9 +22,9 @@ import androidx.core.text.isDigitsOnly
import com.google.android.exoplayer2.MediaItem
import com.google.android.exoplayer2.MetadataRetriever
import kotlinx.coroutines.flow.flow
import org.oxycblt.auxio.music.RealSong
import org.oxycblt.auxio.music.format.Date
import org.oxycblt.auxio.music.format.TextTags
import org.oxycblt.auxio.music.library.RealSong
import org.oxycblt.auxio.music.parsing.parseId3v2PositionField
import org.oxycblt.auxio.music.parsing.parseVorbisPositionField
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
package org.oxycblt.auxio.music.library
import android.content.Context
import androidx.annotation.VisibleForTesting
@ -25,10 +25,16 @@ import java.text.Collator
import java.util.UUID
import kotlin.math.max
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.format.Date
import org.oxycblt.auxio.music.format.Disc
import org.oxycblt.auxio.music.format.ReleaseType
import org.oxycblt.auxio.music.library.Sort
import org.oxycblt.auxio.music.parsing.parseId3GenreNames
import org.oxycblt.auxio.music.parsing.parseMultiValue
import org.oxycblt.auxio.music.storage.Directory
@ -225,8 +231,7 @@ class RealSong(raw: Raw, musicSettings: MusicSettings) : Song {
}
/** Raw information about a [RealSong] obtained from the filesystem/Extractor instances. */
class Raw
constructor(
class Raw(
/**
* The ID of the [RealSong]'s audio file, obtained from MediaStore. Note that this ID is
* highly unstable and should only be used for accessing the audio file.
@ -438,7 +443,7 @@ class RealAlbum(val raw: Raw, override val songs: List<RealSong>) : Album {
* These instances will be linked to this [RealArtist].
* @author Alexander Capehart (OxygenCobalt)
*/
class RealArtist constructor(private val raw: Raw, songAlbums: List<Music>) : Artist {
class RealArtist(private val raw: Raw, songAlbums: List<Music>) : Artist {
override val uid =
// Attempt to use a MusicBrainz ID first before falling back to a hashed UID.
raw.musicBrainzId?.let { Music.UID.musicBrainz(MusicMode.ARTISTS, it) }
@ -569,7 +574,7 @@ class RealArtist constructor(private val raw: Raw, songAlbums: List<Music>) : Ar
* Library-backed implementation of [RealGenre].
* @author Alexander Capehart (OxygenCobalt)
*/
class RealGenre constructor(private val raw: Raw, override val songs: List<RealSong>) : Genre {
class RealGenre(private val raw: Raw, override val songs: List<RealSong>) : Genre {
override val uid = Music.UID.auxio(MusicMode.GENRES) { update(raw.name) }
override val rawName = raw.name
override val rawSortName = rawName

View file

@ -18,6 +18,7 @@
package org.oxycblt.auxio.music.picker
import android.os.Bundle
import androidx.fragment.app.activityViewModels
import androidx.navigation.fragment.navArgs
import androidx.recyclerview.widget.RecyclerView
import dagger.hilt.android.AndroidEntryPoint
@ -25,7 +26,6 @@ import org.oxycblt.auxio.databinding.DialogMusicPickerBinding
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.requireIs
import org.oxycblt.auxio.util.unlikelyToBeNull
@ -35,7 +35,7 @@ import org.oxycblt.auxio.util.unlikelyToBeNull
*/
@AndroidEntryPoint
class ArtistPlaybackPickerDialog : ArtistPickerDialog() {
private val playbackModel: PlaybackViewModel by androidActivityViewModels()
private val playbackModel: PlaybackViewModel by activityViewModels()
// Information about what Song to show choices for is initially within the navigation arguments
// as UIDs, as that is the only safe way to parcel a Song.
private val args: ArtistPlaybackPickerDialogArgs by navArgs()

View file

@ -20,6 +20,7 @@ package org.oxycblt.auxio.music.picker
import android.os.Bundle
import android.view.LayoutInflater
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import androidx.navigation.fragment.navArgs
@ -32,7 +33,6 @@ import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.ViewBindingDialogFragment
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.requireIs
import org.oxycblt.auxio.util.unlikelyToBeNull
@ -45,7 +45,7 @@ import org.oxycblt.auxio.util.unlikelyToBeNull
class GenrePlaybackPickerDialog :
ViewBindingDialogFragment<DialogMusicPickerBinding>(), ClickableListListener<Genre> {
private val pickerModel: PickerViewModel by viewModels()
private val playbackModel: PlaybackViewModel by androidActivityViewModels()
private val playbackModel: PlaybackViewModel by activityViewModels()
// Information about what Song to show choices for is initially within the navigation arguments
// as UIDs, as that is the only safe way to parcel a Song.
private val args: GenrePlaybackPickerDialogArgs by navArgs()

View file

@ -30,6 +30,7 @@ import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.extractor.*
import org.oxycblt.auxio.music.library.Library
import org.oxycblt.auxio.music.library.RealSong
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logE
import org.oxycblt.auxio.util.logW

View file

@ -28,7 +28,6 @@ import org.oxycblt.auxio.playback.state.RepeatMode
import org.oxycblt.auxio.ui.MainNavigationAction
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.ui.ViewBindingFragment
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.getAttrColorCompat
import org.oxycblt.auxio.util.getColorCompat
@ -39,7 +38,7 @@ import org.oxycblt.auxio.util.getColorCompat
*/
@AndroidEntryPoint
class PlaybackBarFragment : ViewBindingFragment<FragmentPlaybackBarBinding>() {
private val playbackModel: PlaybackViewModel by androidActivityViewModels()
private val playbackModel: PlaybackViewModel by activityViewModels()
private val navModel: NavigationViewModel by activityViewModels()
override fun onCreateBinding(inflater: LayoutInflater) =

View file

@ -0,0 +1,36 @@
/*
* Copyright (c) 2023 Auxio Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.playback
import android.content.Context
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import org.oxycblt.auxio.playback.persist.PersistenceRepository
@Module
@InstallIn(SingletonComponent::class)
class PlaybackModule {
@Provides fun settings(@ApplicationContext context: Context) = PlaybackSettings.from(context)
@Provides
fun persistenceRepository(@ApplicationContext context: Context) =
PersistenceRepository.from(context)
}

View file

@ -39,7 +39,6 @@ import org.oxycblt.auxio.playback.ui.StyledSeekBar
import org.oxycblt.auxio.ui.MainNavigationAction
import org.oxycblt.auxio.ui.NavigationViewModel
import org.oxycblt.auxio.ui.ViewBindingFragment
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.showToast
import org.oxycblt.auxio.util.systemBarInsetsCompat
@ -54,7 +53,7 @@ class PlaybackPanelFragment :
ViewBindingFragment<FragmentPlaybackPanelBinding>(),
Toolbar.OnMenuItemClickListener,
StyledSeekBar.Listener {
private val playbackModel: PlaybackViewModel by androidActivityViewModels()
private val playbackModel: PlaybackViewModel by activityViewModels()
private val navModel: NavigationViewModel by activityViewModels()
private var equalizerLauncher: ActivityResultLauncher<Intent>? = null

View file

@ -17,9 +17,11 @@
package org.oxycblt.auxio.playback
import android.app.Application
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.Job
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
@ -34,12 +36,15 @@ import org.oxycblt.auxio.playback.state.*
* An [AndroidViewModel] that provides a safe UI frontend for the current playback state.
* @author Alexander Capehart (OxygenCobalt)
*/
class PlaybackViewModel(application: Application) :
AndroidViewModel(application), PlaybackStateManager.Listener {
private val musicSettings = MusicSettings.from(application)
private val playbackSettings = PlaybackSettings.from(application)
@HiltViewModel
class PlaybackViewModel
@Inject
constructor(
private val persistenceRepository: PersistenceRepository,
private val playbackSettings: PlaybackSettings,
private val musicSettings: MusicSettings
) : ViewModel(), PlaybackStateManager.Listener {
private val playbackManager = PlaybackStateManager.get()
private val persistenceRepository = PersistenceRepository.from(application)
private val musicRepository = MusicRepository.get()
private var lastPositionJob: Job? = null

View file

@ -32,7 +32,6 @@ import org.oxycblt.auxio.list.adapter.BasicListInstructions
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.ui.ViewBindingFragment
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.collectImmediately
/**
@ -42,7 +41,7 @@ import org.oxycblt.auxio.util.collectImmediately
@AndroidEntryPoint
class QueueFragment : ViewBindingFragment<FragmentQueueBinding>(), EditableListListener<Song> {
private val queueModel: QueueViewModel by activityViewModels()
private val playbackModel: PlaybackViewModel by androidActivityViewModels()
private val playbackModel: PlaybackViewModel by activityViewModels()
private val queueAdapter = QueueAdapter(this)
private var touchHelper: ItemTouchHelper? = null

View file

@ -26,6 +26,7 @@ import androidx.core.view.isInvisible
import androidx.core.view.postDelayed
import androidx.core.widget.addTextChangedListener
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.navigation.fragment.findNavController
import com.google.android.material.transition.MaterialSharedAxis
import dagger.hilt.android.AndroidEntryPoint
@ -56,10 +57,10 @@ import org.oxycblt.auxio.util.*
*/
@AndroidEntryPoint
class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
private val searchModel: SearchViewModel by androidViewModels()
override val navModel: NavigationViewModel by activityViewModels()
override val playbackModel: PlaybackViewModel by androidActivityViewModels()
override val playbackModel: PlaybackViewModel by activityViewModels()
override val selectionModel: SelectionViewModel by activityViewModels()
private val searchModel: SearchViewModel by viewModels()
private val searchAdapter = SearchAdapter(this)
private var imm: InputMethodManager? = null
private var launchedKeyboard = false

View file

@ -0,0 +1,32 @@
/*
* Copyright (c) 2023 Auxio Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.search
import android.content.Context
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
@Module
@InstallIn(SingletonComponent::class)
class SearchModule {
@Provides fun engine(@ApplicationContext context: Context) = SearchEngine.from(context)
@Provides fun settings(@ApplicationContext context: Context) = SearchSettings.from(context)
}

View file

@ -17,10 +17,12 @@
package org.oxycblt.auxio.search
import android.app.Application
import androidx.annotation.IdRes
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@ -39,12 +41,15 @@ import org.oxycblt.auxio.util.logD
* An [AndroidViewModel] that keeps performs search operations and tracks their results.
* @author Alexander Capehart (OxygenCobalt)
*/
class SearchViewModel(application: Application) :
AndroidViewModel(application), MusicRepository.Listener {
@HiltViewModel
class SearchViewModel
@Inject
constructor(
private val searchEngine: SearchEngine,
private val searchSettings: SearchSettings,
private val playbackSettings: PlaybackSettings,
) : ViewModel(), MusicRepository.Listener {
private val musicRepository = MusicRepository.get()
private val searchSettings = SearchSettings.from(application)
private val playbackSettings = PlaybackSettings.from(application)
private var searchEngine = SearchEngine.from(application)
private var lastQuery: String? = null
private var currentSearchJob: Job? = null

View file

@ -29,7 +29,6 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
import org.oxycblt.auxio.util.androidActivityViewModels
import org.oxycblt.auxio.util.showToast
/**
@ -38,7 +37,7 @@ import org.oxycblt.auxio.util.showToast
*/
@AndroidEntryPoint
class RootPreferenceFragment : BasePreferenceFragment(R.xml.preferences_root) {
private val playbackModel: PlaybackViewModel by androidActivityViewModels()
private val playbackModel: PlaybackViewModel by activityViewModels()
private val musicModel: MusicViewModel by activityViewModels()
override fun onCreate(savedInstanceState: Bundle?) {

View file

@ -0,0 +1,31 @@
/*
* Copyright (c) 2023 Auxio Project
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.oxycblt.auxio.ui
import android.content.Context
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.android.qualifiers.ApplicationContext
import dagger.hilt.components.SingletonComponent
import org.oxycblt.auxio.image.ImageSettings
@Module
@InstallIn(SingletonComponent::class)
class UIModule {
fun settings(@ApplicationContext context: Context) = ImageSettings.from(context)
}

View file

@ -23,18 +23,12 @@ import android.graphics.drawable.Drawable
import android.os.Build
import android.view.View
import android.view.WindowInsets
import androidx.activity.viewModels
import androidx.annotation.RequiresApi
import androidx.appcompat.app.AppCompatActivity
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.graphics.Insets
import androidx.core.graphics.drawable.DrawableCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.activityViewModels
import androidx.fragment.app.viewModels
import androidx.lifecycle.AndroidViewModel
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.lifecycleScope
import androidx.lifecycle.repeatOnLifecycle
import androidx.recyclerview.widget.RecyclerView
@ -196,35 +190,6 @@ private fun Fragment.launch(
viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(state, block) }
}
/**
* An extension to [viewModels] that automatically provides an
* [ViewModelProvider.AndroidViewModelFactory]. Use whenever an [AndroidViewModel] is used.
*/
inline fun <reified T : AndroidViewModel> Fragment.androidViewModels() =
viewModels<T> { ViewModelProvider.AndroidViewModelFactory(requireActivity().application) }
/**
* An extension to [viewModels] that automatically provides an
* [ViewModelProvider.AndroidViewModelFactory]. Use whenever an [AndroidViewModel] is used. Note
* that this implementation is for an [AppCompatActivity], and thus makes this functionally
* equivalent in scope to [androidActivityViewModels].
*/
inline fun <reified T : AndroidViewModel> AppCompatActivity.androidViewModels() =
viewModels<T> { ViewModelProvider.AndroidViewModelFactory(application) }
/**
* An extension to [activityViewModels] that automatically provides an
* [ViewModelProvider.AndroidViewModelFactory]. Use whenever an [AndroidViewModel] is used.
*/
inline fun <reified T : AndroidViewModel> Fragment.androidActivityViewModels() =
activityViewModels<T> {
ViewModelProvider.AndroidViewModelFactory(requireActivity().application)
}
/** The [Context] provided to an [AndroidViewModel]. */
inline val AndroidViewModel.context: Context
get() = getApplication()
/**
* Get the "System Bar" [Insets] in this [WindowInsets] instance in a version-compatible manner This
* can be used to prevent [View] elements from intersecting with the navigation bars.