all: fully use timber for logging
This commit is contained in:
parent
a9a35c8055
commit
6d72240336
118 changed files with 749 additions and 836 deletions
|
@ -36,7 +36,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||
import javax.inject.Inject
|
||||
import org.oxycblt.auxio.music.service.MusicServiceFragment
|
||||
import org.oxycblt.auxio.playback.service.PlaybackServiceFragment
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
@AndroidEntryPoint
|
||||
class AuxioService :
|
||||
|
@ -150,7 +150,7 @@ class AuxioService :
|
|||
}
|
||||
|
||||
override fun invalidateMusic(mediaId: String) {
|
||||
logD(mediaId)
|
||||
T.d(mediaId)
|
||||
notifyChildrenChanged(mediaId)
|
||||
}
|
||||
|
||||
|
|
|
@ -33,9 +33,8 @@ import org.oxycblt.auxio.playback.PlaybackViewModel
|
|||
import org.oxycblt.auxio.playback.state.DeferredPlayback
|
||||
import org.oxycblt.auxio.ui.UISettings
|
||||
import org.oxycblt.auxio.util.isNight
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.systemBarInsetsCompat
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Auxio's single [AppCompatActivity].
|
||||
|
@ -63,7 +62,7 @@ class MainActivity : AppCompatActivity() {
|
|||
val binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
setupEdgeToEdge(binding.root)
|
||||
logD("Activity created")
|
||||
T.d("Activity created")
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
|
@ -91,10 +90,10 @@ class MainActivity : AppCompatActivity() {
|
|||
// Apply the color scheme. The black theme requires it's own set of themes since
|
||||
// it's not possible to modify the themes at run-time.
|
||||
if (isNight && uiSettings.useBlackTheme) {
|
||||
logD("Applying black theme [accent ${uiSettings.accent}]")
|
||||
T.d("Applying black theme [accent ${uiSettings.accent}]")
|
||||
setTheme(uiSettings.accent.blackTheme)
|
||||
} else {
|
||||
logD("Applying normal theme [accent ${uiSettings.accent}]")
|
||||
T.d("Applying normal theme [accent ${uiSettings.accent}]")
|
||||
setTheme(uiSettings.accent.theme)
|
||||
}
|
||||
}
|
||||
|
@ -121,7 +120,7 @@ class MainActivity : AppCompatActivity() {
|
|||
private fun startIntentAction(intent: Intent?): Boolean {
|
||||
if (intent == null) {
|
||||
// Nothing to do.
|
||||
logD("No intent to handle")
|
||||
T.d("No intent to handle")
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -130,7 +129,7 @@ class MainActivity : AppCompatActivity() {
|
|||
// This is because onStart can run multiple times, and thus we really don't
|
||||
// want to return false and override the original delayed action with a
|
||||
// RestoreState action.
|
||||
logD("Already used this intent")
|
||||
T.d("Already used this intent")
|
||||
return true
|
||||
}
|
||||
intent.putExtra(KEY_INTENT_USED, true)
|
||||
|
@ -140,11 +139,11 @@ class MainActivity : AppCompatActivity() {
|
|||
Intent.ACTION_VIEW -> DeferredPlayback.Open(intent.data ?: return false)
|
||||
Auxio.INTENT_KEY_SHORTCUT_SHUFFLE -> DeferredPlayback.ShuffleAll
|
||||
else -> {
|
||||
logW("Unexpected intent ${intent.action}")
|
||||
T.w("Unexpected intent ${intent.action}")
|
||||
return false
|
||||
}
|
||||
}
|
||||
logD("Translated intent to $action")
|
||||
T.d("Translated intent to $action")
|
||||
playbackModel.playDeferred(action)
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -66,9 +66,9 @@ import org.oxycblt.auxio.util.coordinatorLayoutBehavior
|
|||
import org.oxycblt.auxio.util.getAttrColorCompat
|
||||
import org.oxycblt.auxio.util.getDimen
|
||||
import org.oxycblt.auxio.util.lazyReflectedMethod
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A wrapper around the home fragment that shows the playback fragment and high-level navigation.
|
||||
|
@ -145,13 +145,13 @@ class MainFragment :
|
|||
|
||||
if (queueSheetBehavior != null) {
|
||||
// In portrait mode, set up click listeners on the stacked sheets.
|
||||
logD("Configuring stacked bottom sheets")
|
||||
T.d("Configuring stacked bottom sheets")
|
||||
unlikelyToBeNull(binding.queueHandleWrapper).setOnClickListener {
|
||||
playbackModel.openQueue()
|
||||
}
|
||||
} else {
|
||||
// Dual-pane mode, manually style the static queue sheet.
|
||||
logD("Configuring dual-pane bottom sheet")
|
||||
T.d("Configuring dual-pane bottom sheet")
|
||||
binding.queueSheet.apply {
|
||||
// Emulate the elevated bottom sheet style.
|
||||
background =
|
||||
|
@ -367,11 +367,11 @@ class MainFragment :
|
|||
override fun onActionSelected(actionItem: SpeedDialActionItem): Boolean {
|
||||
when (actionItem.id) {
|
||||
R.id.action_new_playlist -> {
|
||||
logD("Creating playlist")
|
||||
T.d("Creating playlist")
|
||||
musicModel.createPlaylist()
|
||||
}
|
||||
R.id.action_import_playlist -> {
|
||||
logD("Importing playlist")
|
||||
T.d("Importing playlist")
|
||||
musicModel.importPlaylist()
|
||||
}
|
||||
else -> {}
|
||||
|
@ -402,7 +402,7 @@ class MainFragment :
|
|||
// 1. Loading placeholder for item lists
|
||||
// 2. Rework the "No Music" case to not be an error and instead result in a placeholder
|
||||
if (state is IndexingState.Completed && state.error == null) {
|
||||
logD("Received ok response")
|
||||
T.d("Received ok response")
|
||||
val binding = requireBinding()
|
||||
updateFabVisibility(
|
||||
binding,
|
||||
|
@ -427,7 +427,7 @@ class MainFragment :
|
|||
// displaying the shuffle FAB makes no sense. We also don't want the fast scroll
|
||||
// popup to overlap with the FAB, so we hide the FAB when fast scrolling too.
|
||||
if (shouldHideAllFabs(binding, songs, isFastScrolling)) {
|
||||
logD("Hiding fab: [empty: ${songs.isEmpty()} scrolling: $isFastScrolling]")
|
||||
T.d("Hiding fab: [empty: ${songs.isEmpty()} scrolling: $isFastScrolling]")
|
||||
forceHideAllFabs()
|
||||
} else {
|
||||
if (tabType != MusicType.PLAYLISTS) {
|
||||
|
@ -436,7 +436,7 @@ class MainFragment :
|
|||
}
|
||||
|
||||
if (binding.homeNewPlaylistFab.mainFab.isOrWillBeShown) {
|
||||
logD("Animating transition")
|
||||
T.d("Animating transition")
|
||||
binding.homeNewPlaylistFab.hide(
|
||||
object : FloatingActionButton.OnVisibilityChangedListener() {
|
||||
override fun onHidden(fab: FloatingActionButton) {
|
||||
|
@ -451,17 +451,17 @@ class MainFragment :
|
|||
}
|
||||
})
|
||||
} else {
|
||||
logD("Showing immediately")
|
||||
T.d("Showing immediately")
|
||||
binding.homeShuffleFab.show()
|
||||
}
|
||||
} else {
|
||||
logD("Showing playlist button")
|
||||
T.d("Showing playlist button")
|
||||
if (binding.homeNewPlaylistFab.mainFab.isOrWillBeShown) {
|
||||
return
|
||||
}
|
||||
|
||||
if (binding.homeShuffleFab.isOrWillBeShown) {
|
||||
logD("Animating transition")
|
||||
T.d("Animating transition")
|
||||
binding.homeShuffleFab.hide(
|
||||
object : FloatingActionButton.OnVisibilityChangedListener() {
|
||||
override fun onHidden(fab: FloatingActionButton) {
|
||||
|
@ -476,7 +476,7 @@ class MainFragment :
|
|||
}
|
||||
})
|
||||
} else {
|
||||
logD("Showing immediately")
|
||||
T.d("Showing immediately")
|
||||
binding.homeNewPlaylistFab.show()
|
||||
}
|
||||
}
|
||||
|
@ -551,7 +551,7 @@ class MainFragment :
|
|||
|
||||
private fun handlePanel(panel: OpenPanel?) {
|
||||
if (panel == null) return
|
||||
logD("Trying to update panel to $panel")
|
||||
T.d("Trying to update panel to $panel")
|
||||
when (panel) {
|
||||
OpenPanel.MAIN -> tryClosePlaybackPanel()
|
||||
OpenPanel.PLAYBACK -> tryOpenPlaybackPanel()
|
||||
|
@ -567,7 +567,7 @@ class MainFragment :
|
|||
|
||||
if (playbackSheetBehavior.targetState == BackportBottomSheetBehavior.STATE_COLLAPSED) {
|
||||
// Playback sheet is not expanded and not hidden, we can expand it.
|
||||
logD("Expanding playback sheet")
|
||||
T.d("Expanding playback sheet")
|
||||
playbackSheetBehavior.state = BackportBottomSheetBehavior.STATE_EXPANDED
|
||||
return
|
||||
}
|
||||
|
@ -578,7 +578,7 @@ class MainFragment :
|
|||
queueSheetBehavior.targetState == BackportBottomSheetBehavior.STATE_EXPANDED) {
|
||||
// Queue sheet and playback sheet is expanded, close the queue sheet so the
|
||||
// playback panel can shown.
|
||||
logD("Collapsing queue sheet")
|
||||
T.d("Collapsing queue sheet")
|
||||
queueSheetBehavior.state = BackportBottomSheetBehavior.STATE_COLLAPSED
|
||||
}
|
||||
}
|
||||
|
@ -589,7 +589,7 @@ class MainFragment :
|
|||
binding.playbackSheet.coordinatorLayoutBehavior as PlaybackBottomSheetBehavior
|
||||
if (playbackSheetBehavior.targetState == BackportBottomSheetBehavior.STATE_EXPANDED) {
|
||||
// Playback sheet (and possibly queue) needs to be collapsed.
|
||||
logD("Collapsing playback and queue sheets")
|
||||
T.d("Collapsing playback and queue sheets")
|
||||
val queueSheetBehavior =
|
||||
binding.queueSheet.coordinatorLayoutBehavior as QueueBottomSheetBehavior?
|
||||
playbackSheetBehavior.state = BackportBottomSheetBehavior.STATE_COLLAPSED
|
||||
|
@ -615,7 +615,7 @@ class MainFragment :
|
|||
val playbackSheetBehavior =
|
||||
binding.playbackSheet.coordinatorLayoutBehavior as PlaybackBottomSheetBehavior
|
||||
if (playbackSheetBehavior.targetState == BackportBottomSheetBehavior.STATE_HIDDEN) {
|
||||
logD("Unhiding and enabling playback sheet")
|
||||
T.d("Unhiding and enabling playback sheet")
|
||||
val queueSheetBehavior =
|
||||
binding.queueSheet.coordinatorLayoutBehavior as QueueBottomSheetBehavior?
|
||||
// Queue sheet behavior is either collapsed or expanded, no hiding needed
|
||||
|
@ -636,7 +636,7 @@ class MainFragment :
|
|||
val queueSheetBehavior =
|
||||
binding.queueSheet.coordinatorLayoutBehavior as QueueBottomSheetBehavior?
|
||||
|
||||
logD("Hiding and disabling playback and queue sheets")
|
||||
T.d("Hiding and disabling playback and queue sheets")
|
||||
|
||||
// Make both bottom sheets non-draggable so the user can't halt the hiding event.
|
||||
queueSheetBehavior?.apply {
|
||||
|
@ -720,7 +720,7 @@ class MainFragment :
|
|||
OnBackPressedCallback(false) {
|
||||
override fun handleOnBackPressed() {
|
||||
if (detailModel.dropPlaylistEdit()) {
|
||||
logD("Dropped playlist edits")
|
||||
T.d("Dropped playlist edits")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -733,7 +733,7 @@ class MainFragment :
|
|||
OnBackPressedCallback(false) {
|
||||
override fun handleOnBackPressed() {
|
||||
if (listModel.dropSelection()) {
|
||||
logD("Dropped selection")
|
||||
T.d("Dropped selection")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -41,10 +41,10 @@ import org.oxycblt.auxio.playback.formatDurationMs
|
|||
import org.oxycblt.auxio.util.collect
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.getPlural
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
import org.oxycblt.auxio.util.showToast
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ListFragment] that shows information about an [Album].
|
||||
|
@ -103,7 +103,7 @@ class AlbumDetailFragment : DetailFragment<Album, Song>() {
|
|||
|
||||
private fun updateAlbum(album: Album?) {
|
||||
if (album == null) {
|
||||
logD("No album to show, navigating away")
|
||||
T.d("No album to show, navigating away")
|
||||
findNavController().navigateUp()
|
||||
return
|
||||
}
|
||||
|
@ -153,7 +153,7 @@ class AlbumDetailFragment : DetailFragment<Album, Song>() {
|
|||
val binding = requireBinding()
|
||||
when (show) {
|
||||
is Show.SongDetails -> {
|
||||
logD("Navigating to ${show.song}")
|
||||
T.d("Navigating to ${show.song}")
|
||||
findNavController()
|
||||
.navigateSafe(AlbumDetailFragmentDirections.showSong(show.song.uid))
|
||||
}
|
||||
|
@ -162,11 +162,11 @@ class AlbumDetailFragment : DetailFragment<Album, Song>() {
|
|||
// fragment should be launched otherwise.
|
||||
is Show.SongAlbumDetails -> {
|
||||
if (unlikelyToBeNull(detailModel.currentAlbum.value) == show.song.album) {
|
||||
logD("Navigating to a ${show.song} in this album")
|
||||
T.d("Navigating to a ${show.song} in this album")
|
||||
scrollToAlbumSong(show.song)
|
||||
detailModel.toShow.consume()
|
||||
} else {
|
||||
logD("Navigating to the album of ${show.song}")
|
||||
T.d("Navigating to the album of ${show.song}")
|
||||
findNavController()
|
||||
.navigateSafe(AlbumDetailFragmentDirections.showAlbum(show.song.album.uid))
|
||||
}
|
||||
|
@ -176,27 +176,27 @@ class AlbumDetailFragment : DetailFragment<Album, Song>() {
|
|||
// detail fragment.
|
||||
is Show.AlbumDetails -> {
|
||||
if (unlikelyToBeNull(detailModel.currentAlbum.value) == show.album) {
|
||||
logD("Navigating to the top of this album")
|
||||
T.d("Navigating to the top of this album")
|
||||
binding.detailRecycler.scrollToPosition(0)
|
||||
detailModel.toShow.consume()
|
||||
} else {
|
||||
logD("Navigating to ${show.album}")
|
||||
T.d("Navigating to ${show.album}")
|
||||
findNavController()
|
||||
.navigateSafe(AlbumDetailFragmentDirections.showAlbum(show.album.uid))
|
||||
}
|
||||
}
|
||||
is Show.ArtistDetails -> {
|
||||
logD("Navigating to ${show.artist}")
|
||||
T.d("Navigating to ${show.artist}")
|
||||
findNavController()
|
||||
.navigateSafe(AlbumDetailFragmentDirections.showArtist(show.artist.uid))
|
||||
}
|
||||
is Show.SongArtistDecision -> {
|
||||
logD("Navigating to artist choices for ${show.song}")
|
||||
T.d("Navigating to artist choices for ${show.song}")
|
||||
findNavController()
|
||||
.navigateSafe(AlbumDetailFragmentDirections.showArtistChoices(show.song.uid))
|
||||
}
|
||||
is Show.AlbumArtistDecision -> {
|
||||
logD("Navigating to artist choices for ${show.album}")
|
||||
T.d("Navigating to artist choices for ${show.album}")
|
||||
findNavController()
|
||||
.navigateSafe(AlbumDetailFragmentDirections.showArtistChoices(show.album.uid))
|
||||
}
|
||||
|
@ -239,7 +239,7 @@ class AlbumDetailFragment : DetailFragment<Album, Song>() {
|
|||
val directions =
|
||||
when (decision) {
|
||||
is PlaylistDecision.Add -> {
|
||||
logD("Adding ${decision.songs.size} songs to a playlist")
|
||||
T.d("Adding ${decision.songs.size} songs to a playlist")
|
||||
AlbumDetailFragmentDirections.addToPlaylist(
|
||||
decision.songs.map { it.uid }.toTypedArray())
|
||||
}
|
||||
|
@ -268,11 +268,11 @@ class AlbumDetailFragment : DetailFragment<Album, Song>() {
|
|||
val directions =
|
||||
when (decision) {
|
||||
is PlaybackDecision.PlayFromArtist -> {
|
||||
logD("Launching play from artist dialog for $decision")
|
||||
T.d("Launching play from artist dialog for $decision")
|
||||
AlbumDetailFragmentDirections.playFromArtist(decision.song.uid)
|
||||
}
|
||||
is PlaybackDecision.PlayFromGenre -> {
|
||||
logD("Launching play from artist dialog for $decision")
|
||||
T.d("Launching play from artist dialog for $decision")
|
||||
AlbumDetailFragmentDirections.playFromGenre(decision.song.uid)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,10 +42,10 @@ import org.oxycblt.auxio.util.collect
|
|||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.context
|
||||
import org.oxycblt.auxio.util.getPlural
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
import org.oxycblt.auxio.util.showToast
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ListFragment] that shows information about an [Artist].
|
||||
|
@ -112,7 +112,7 @@ class ArtistDetailFragment : DetailFragment<Artist, Music>() {
|
|||
|
||||
private fun updateArtist(artist: Artist?) {
|
||||
if (artist == null) {
|
||||
logD("No artist to show, navigating away")
|
||||
T.d("No artist to show, navigating away")
|
||||
findNavController().navigateUp()
|
||||
return
|
||||
}
|
||||
|
@ -155,7 +155,7 @@ class ArtistDetailFragment : DetailFragment<Artist, Music>() {
|
|||
// The artist does not have any songs, so hide functionality that makes no sense.
|
||||
// ex. Play and Shuffle, Song Counts, and Genre Information.
|
||||
// Artists are always guaranteed to have albums however, so continue to show those.
|
||||
logD("Artist is empty, disabling genres and playback")
|
||||
T.d("Artist is empty, disabling genres and playback")
|
||||
binding.detailSubhead.isVisible = false
|
||||
binding.detailPlayButton?.isEnabled = false
|
||||
binding.detailShuffleButton?.isEnabled = false
|
||||
|
@ -177,14 +177,14 @@ class ArtistDetailFragment : DetailFragment<Artist, Music>() {
|
|||
val binding = requireBinding()
|
||||
when (show) {
|
||||
is Show.SongDetails -> {
|
||||
logD("Navigating to ${show.song}")
|
||||
T.d("Navigating to ${show.song}")
|
||||
findNavController()
|
||||
.navigateSafe(ArtistDetailFragmentDirections.showSong(show.song.uid))
|
||||
}
|
||||
|
||||
// Songs should be shown in their album, not in their artist.
|
||||
is Show.SongAlbumDetails -> {
|
||||
logD("Navigating to the album of ${show.song}")
|
||||
T.d("Navigating to the album of ${show.song}")
|
||||
findNavController()
|
||||
.navigateSafe(ArtistDetailFragmentDirections.showAlbum(show.song.album.uid))
|
||||
}
|
||||
|
@ -192,7 +192,7 @@ class ArtistDetailFragment : DetailFragment<Artist, Music>() {
|
|||
// Launch a new detail view for an album, even if it is part of
|
||||
// this artist.
|
||||
is Show.AlbumDetails -> {
|
||||
logD("Navigating to ${show.album}")
|
||||
T.d("Navigating to ${show.album}")
|
||||
findNavController()
|
||||
.navigateSafe(ArtistDetailFragmentDirections.showAlbum(show.album.uid))
|
||||
}
|
||||
|
@ -201,22 +201,22 @@ class ArtistDetailFragment : DetailFragment<Artist, Music>() {
|
|||
// scroll back to the top. Otherwise launch a new detail view.
|
||||
is Show.ArtistDetails -> {
|
||||
if (show.artist == detailModel.currentArtist.value) {
|
||||
logD("Navigating to the top of this artist")
|
||||
T.d("Navigating to the top of this artist")
|
||||
binding.detailRecycler.scrollToPosition(0)
|
||||
detailModel.toShow.consume()
|
||||
} else {
|
||||
logD("Navigating to ${show.artist}")
|
||||
T.d("Navigating to ${show.artist}")
|
||||
findNavController()
|
||||
.navigateSafe(ArtistDetailFragmentDirections.showArtist(show.artist.uid))
|
||||
}
|
||||
}
|
||||
is Show.SongArtistDecision -> {
|
||||
logD("Navigating to artist choices for ${show.song}")
|
||||
T.d("Navigating to artist choices for ${show.song}")
|
||||
findNavController()
|
||||
.navigateSafe(ArtistDetailFragmentDirections.showArtistChoices(show.song.uid))
|
||||
}
|
||||
is Show.AlbumArtistDecision -> {
|
||||
logD("Navigating to artist choices for ${show.album}")
|
||||
T.d("Navigating to artist choices for ${show.album}")
|
||||
findNavController()
|
||||
.navigateSafe(ArtistDetailFragmentDirections.showArtistChoices(show.album.uid))
|
||||
}
|
||||
|
@ -260,7 +260,7 @@ class ArtistDetailFragment : DetailFragment<Artist, Music>() {
|
|||
val directions =
|
||||
when (decision) {
|
||||
is PlaylistDecision.Add -> {
|
||||
logD("Adding ${decision.songs.size} songs to a playlist")
|
||||
T.d("Adding ${decision.songs.size} songs to a playlist")
|
||||
ArtistDetailFragmentDirections.addToPlaylist(
|
||||
decision.songs.map { it.uid }.toTypedArray())
|
||||
}
|
||||
|
@ -301,7 +301,7 @@ class ArtistDetailFragment : DetailFragment<Artist, Music>() {
|
|||
is PlaybackDecision.PlayFromArtist ->
|
||||
error("Unexpected playback decision $decision")
|
||||
is PlaybackDecision.PlayFromGenre -> {
|
||||
logD("Launching play from artist dialog for $decision")
|
||||
T.d("Launching play from artist dialog for $decision")
|
||||
ArtistDetailFragmentDirections.playFromGenre(decision.song.uid)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.oxycblt.auxio.music.Playlist
|
|||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.info.Disc
|
||||
import org.oxycblt.auxio.music.info.ReleaseType
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
interface DetailGenerator {
|
||||
fun any(uid: Music.UID): Detail<out MusicParent>?
|
||||
|
@ -159,7 +159,7 @@ private class DetailGeneratorImpl(
|
|||
// groupByTo normally returns a mapping to a MutableList mapping. Since MutableList
|
||||
// inherits list, we can cast upwards and save a copy by directly inserting the
|
||||
// implicit album list into the mapping.
|
||||
logD("Implicit albums present, adding to list")
|
||||
T.d("Implicit albums present, adding to list")
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
(grouping as MutableMap<DetailSection.Albums.Category, Collection<Album>>)[
|
||||
DetailSection.Albums.Category.APPEARANCES] = artist.implicitAlbums
|
||||
|
|
|
@ -54,9 +54,8 @@ import org.oxycblt.auxio.playback.PlaySong
|
|||
import org.oxycblt.auxio.playback.PlaybackSettings
|
||||
import org.oxycblt.auxio.util.Event
|
||||
import org.oxycblt.auxio.util.MutableEvent
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* [ViewModel] that manages the Song, Album, Artist, and Genre detail views. Keeps track of the
|
||||
|
@ -302,7 +301,7 @@ constructor(
|
|||
private fun showImpl(show: Show) {
|
||||
val existing = toShow.flow.value
|
||||
if (existing != null) {
|
||||
logD("Already have pending show command $existing, ignoring $show")
|
||||
T.d("Already have pending show command $existing, ignoring $show")
|
||||
return
|
||||
}
|
||||
_toShow.put(show)
|
||||
|
@ -315,10 +314,10 @@ constructor(
|
|||
* @param uid The UID of the [Song] to load. Must be valid.
|
||||
*/
|
||||
fun setSong(uid: Music.UID) {
|
||||
logD("Opening song $uid")
|
||||
T.d("Opening song $uid")
|
||||
_currentSong.value = musicRepository.deviceLibrary?.findSong(uid)?.also(::refreshAudioInfo)
|
||||
if (_currentSong.value == null) {
|
||||
logW("Given song UID was invalid")
|
||||
T.w("Given song UID was invalid")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -329,14 +328,14 @@ constructor(
|
|||
* @param uid The [Music.UID] of the [Album] to update [currentAlbum] to. Must be valid.
|
||||
*/
|
||||
fun setAlbum(uid: Music.UID) {
|
||||
logD("Opening album $uid")
|
||||
T.d("Opening album $uid")
|
||||
if (uid === _currentAlbum.value?.uid) {
|
||||
return
|
||||
}
|
||||
val album = detailGenerator.album(uid)
|
||||
refreshDetail(album, _currentAlbum, _albumSongList, _albumSongInstructions, null)
|
||||
if (_currentAlbum.value == null) {
|
||||
logW("Given album UID was invalid")
|
||||
T.w("Given album UID was invalid")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -356,7 +355,7 @@ constructor(
|
|||
* @param uid The [Music.UID] of the [Artist] to update [currentArtist] to. Must be valid.
|
||||
*/
|
||||
fun setArtist(uid: Music.UID) {
|
||||
logD("Opening artist $uid")
|
||||
T.d("Opening artist $uid")
|
||||
if (uid === _currentArtist.value?.uid) {
|
||||
return
|
||||
}
|
||||
|
@ -380,7 +379,7 @@ constructor(
|
|||
* @param uid The [Music.UID] of the [Genre] to update [currentGenre] to. Must be valid.
|
||||
*/
|
||||
fun setGenre(uid: Music.UID) {
|
||||
logD("Opening genre $uid")
|
||||
T.d("Opening genre $uid")
|
||||
if (uid === _currentGenre.value?.uid) {
|
||||
return
|
||||
}
|
||||
|
@ -404,7 +403,7 @@ constructor(
|
|||
* @param uid The [Music.UID] of the [Playlist] to update [currentPlaylist] to. Must be valid.
|
||||
*/
|
||||
fun setPlaylist(uid: Music.UID) {
|
||||
logD("Opening playlist $uid")
|
||||
T.d("Opening playlist $uid")
|
||||
if (uid === _currentPlaylist.value?.uid) {
|
||||
return
|
||||
}
|
||||
|
@ -414,7 +413,7 @@ constructor(
|
|||
/** Start a playlist editing session. Does nothing if a playlist is not being shown. */
|
||||
fun startPlaylistEdit() {
|
||||
val playlist = _currentPlaylist.value ?: return
|
||||
logD("Starting playlist edit")
|
||||
T.d("Starting playlist edit")
|
||||
_editedPlaylist.value = playlist.songs
|
||||
refreshPlaylist(playlist.uid)
|
||||
}
|
||||
|
@ -426,7 +425,7 @@ constructor(
|
|||
fun savePlaylistEdit() {
|
||||
val playlist = _currentPlaylist.value ?: return
|
||||
val editedPlaylist = _editedPlaylist.value ?: return
|
||||
logD("Committing playlist edits")
|
||||
T.d("Committing playlist edits")
|
||||
viewModelScope.launch {
|
||||
musicRepository.rewritePlaylist(playlist, editedPlaylist)
|
||||
// TODO: The user could probably press some kind of button if they were fast enough.
|
||||
|
@ -479,7 +478,7 @@ constructor(
|
|||
if (realFrom !in editedPlaylist.indices || realTo !in editedPlaylist.indices) {
|
||||
return false
|
||||
}
|
||||
logD("Moving playlist song from $realFrom [$from] to $realTo [$to]")
|
||||
T.d("Moving playlist song from $realFrom [$from] to $realTo [$to]")
|
||||
editedPlaylist.add(realFrom, editedPlaylist.removeAt(realTo))
|
||||
_editedPlaylist.value = editedPlaylist
|
||||
refreshPlaylist(playlist.uid, UpdateInstructions.Move(from, to))
|
||||
|
@ -498,7 +497,7 @@ constructor(
|
|||
if (realAt !in editedPlaylist.indices) {
|
||||
return
|
||||
}
|
||||
logD("Removing playlist song at $realAt [$at]")
|
||||
T.d("Removing playlist song at $realAt [$at]")
|
||||
editedPlaylist.removeAt(realAt)
|
||||
_editedPlaylist.value = editedPlaylist
|
||||
refreshPlaylist(
|
||||
|
@ -506,13 +505,13 @@ constructor(
|
|||
if (editedPlaylist.isNotEmpty()) {
|
||||
UpdateInstructions.Remove(at, 1)
|
||||
} else {
|
||||
logD("Playlist will be empty after removal, removing header")
|
||||
T.d("Playlist will be empty after removal, removing header")
|
||||
UpdateInstructions.Remove(at - 1, 3)
|
||||
})
|
||||
}
|
||||
|
||||
private fun refreshAudioInfo(song: Song) {
|
||||
logD("Refreshing audio info")
|
||||
T.d("Refreshing audio info")
|
||||
// Clear any previous job in order to avoid stale data from appearing in the UI.
|
||||
currentSongJob?.cancel()
|
||||
_songAudioProperties.value = null
|
||||
|
@ -520,7 +519,7 @@ constructor(
|
|||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val info = audioPropertiesFactory.extract(song)
|
||||
yield()
|
||||
logD("Updating audio info to $info")
|
||||
T.d("Updating audio info to $info")
|
||||
_songAudioProperties.value = info
|
||||
}
|
||||
}
|
||||
|
@ -587,7 +586,7 @@ constructor(
|
|||
uid: Music.UID,
|
||||
instructions: UpdateInstructions = UpdateInstructions.Diff
|
||||
) {
|
||||
logD("Refreshing playlist list")
|
||||
T.d("Refreshing playlist list")
|
||||
val edited = editedPlaylist.value
|
||||
if (edited == null) {
|
||||
val playlist = detailGenerator.playlist(uid)
|
||||
|
|
|
@ -40,10 +40,10 @@ import org.oxycblt.auxio.playback.PlaybackDecision
|
|||
import org.oxycblt.auxio.util.collect
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.getPlural
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
import org.oxycblt.auxio.util.showToast
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ListFragment] that shows information for a particular [Genre].
|
||||
|
@ -110,7 +110,7 @@ class GenreDetailFragment : DetailFragment<Genre, Music>() {
|
|||
|
||||
private fun updateGenre(genre: Genre?) {
|
||||
if (genre == null) {
|
||||
logD("No genre to show, navigating away")
|
||||
T.d("No genre to show, navigating away")
|
||||
findNavController().navigateUp()
|
||||
return
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ class GenreDetailFragment : DetailFragment<Genre, Music>() {
|
|||
private fun handleShow(show: Show?) {
|
||||
when (show) {
|
||||
is Show.SongDetails -> {
|
||||
logD("Navigating to ${show.song}")
|
||||
T.d("Navigating to ${show.song}")
|
||||
findNavController()
|
||||
.navigateSafe(GenreDetailFragmentDirections.showSong(show.song.uid))
|
||||
}
|
||||
|
@ -152,7 +152,7 @@ class GenreDetailFragment : DetailFragment<Genre, Music>() {
|
|||
// Songs should be scrolled to if the album matches, or a new detail
|
||||
// fragment should be launched otherwise.
|
||||
is Show.SongAlbumDetails -> {
|
||||
logD("Navigating to the album of ${show.song}")
|
||||
T.d("Navigating to the album of ${show.song}")
|
||||
findNavController()
|
||||
.navigateSafe(GenreDetailFragmentDirections.showAlbum(show.song.album.uid))
|
||||
}
|
||||
|
@ -160,29 +160,29 @@ class GenreDetailFragment : DetailFragment<Genre, Music>() {
|
|||
// If the album matches, no need to do anything. Otherwise launch a new
|
||||
// detail fragment.
|
||||
is Show.AlbumDetails -> {
|
||||
logD("Navigating to ${show.album}")
|
||||
T.d("Navigating to ${show.album}")
|
||||
findNavController()
|
||||
.navigateSafe(GenreDetailFragmentDirections.showAlbum(show.album.uid))
|
||||
}
|
||||
|
||||
// Always launch a new ArtistDetailFragment.
|
||||
is Show.ArtistDetails -> {
|
||||
logD("Navigating to ${show.artist}")
|
||||
T.d("Navigating to ${show.artist}")
|
||||
findNavController()
|
||||
.navigateSafe(GenreDetailFragmentDirections.showArtist(show.artist.uid))
|
||||
}
|
||||
is Show.SongArtistDecision -> {
|
||||
logD("Navigating to artist choices for ${show.song}")
|
||||
T.d("Navigating to artist choices for ${show.song}")
|
||||
findNavController()
|
||||
.navigateSafe(GenreDetailFragmentDirections.showArtistChoices(show.song.uid))
|
||||
}
|
||||
is Show.AlbumArtistDecision -> {
|
||||
logD("Navigating to artist choices for ${show.album}")
|
||||
T.d("Navigating to artist choices for ${show.album}")
|
||||
findNavController()
|
||||
.navigateSafe(GenreDetailFragmentDirections.showArtistChoices(show.album.uid))
|
||||
}
|
||||
is Show.GenreDetails -> {
|
||||
logD("Navigated to this genre")
|
||||
T.d("Navigated to this genre")
|
||||
detailModel.toShow.consume()
|
||||
}
|
||||
is Show.PlaylistDetails -> {
|
||||
|
@ -223,7 +223,7 @@ class GenreDetailFragment : DetailFragment<Genre, Music>() {
|
|||
val directions =
|
||||
when (decision) {
|
||||
is PlaylistDecision.Add -> {
|
||||
logD("Adding ${decision.songs.size} songs to a playlist")
|
||||
T.d("Adding ${decision.songs.size} songs to a playlist")
|
||||
GenreDetailFragmentDirections.addToPlaylist(
|
||||
decision.songs.map { it.uid }.toTypedArray())
|
||||
}
|
||||
|
@ -262,7 +262,7 @@ class GenreDetailFragment : DetailFragment<Genre, Music>() {
|
|||
val directions =
|
||||
when (decision) {
|
||||
is PlaybackDecision.PlayFromArtist -> {
|
||||
logD("Launching play from artist dialog for $decision")
|
||||
T.d("Launching play from artist dialog for $decision")
|
||||
GenreDetailFragmentDirections.playFromArtist(decision.song.uid)
|
||||
}
|
||||
is PlaybackDecision.PlayFromGenre -> error("Unexpected playback decision $decision")
|
||||
|
|
|
@ -49,11 +49,10 @@ import org.oxycblt.auxio.util.collect
|
|||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.context
|
||||
import org.oxycblt.auxio.util.getPlural
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
import org.oxycblt.auxio.util.showToast
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ListFragment] that shows information for a particular [Playlist].
|
||||
|
@ -82,11 +81,11 @@ class PlaylistDetailFragment :
|
|||
getContentLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
|
||||
if (uri == null) {
|
||||
logW("No URI returned from file picker")
|
||||
T.w("No URI returned from file picker")
|
||||
return@registerForActivityResult
|
||||
}
|
||||
|
||||
logD("Received playlist URI $uri")
|
||||
T.d("Received playlist URI $uri")
|
||||
musicModel.importPlaylist(uri, pendingImportTarget)
|
||||
}
|
||||
|
||||
|
@ -194,7 +193,7 @@ class PlaylistDetailFragment :
|
|||
getString(R.string.fmt_editing, playlist.name.resolve(requireContext()))
|
||||
|
||||
if (editedPlaylist != null) {
|
||||
logD("Binding edited playlist image")
|
||||
T.d("Binding edited playlist image")
|
||||
binding.detailCover.bind(
|
||||
editedPlaylist,
|
||||
binding.context.getString(R.string.desc_playlist_image, playlist.name),
|
||||
|
@ -223,7 +222,7 @@ class PlaylistDetailFragment :
|
|||
|
||||
val playable = playlist.songs.isNotEmpty() && editedPlaylist == null
|
||||
if (!playable) {
|
||||
logD("Playlist is being edited or is empty, disabling playback options")
|
||||
T.d("Playlist is being edited or is empty, disabling playback options")
|
||||
}
|
||||
|
||||
binding.detailPlayButton?.apply {
|
||||
|
@ -249,7 +248,7 @@ class PlaylistDetailFragment :
|
|||
listModel.dropSelection()
|
||||
|
||||
if (editedPlaylist != null) {
|
||||
logD("Updating save button state")
|
||||
T.d("Updating save button state")
|
||||
requireBinding().detailEditToolbar.menu.findItem(R.id.action_save).apply {
|
||||
isEnabled = editedPlaylist != detailModel.currentPlaylist.value?.songs
|
||||
}
|
||||
|
@ -261,38 +260,38 @@ class PlaylistDetailFragment :
|
|||
private fun handleShow(show: Show?) {
|
||||
when (show) {
|
||||
is Show.SongDetails -> {
|
||||
logD("Navigating to ${show.song}")
|
||||
T.d("Navigating to ${show.song}")
|
||||
findNavController()
|
||||
.navigateSafe(PlaylistDetailFragmentDirections.showSong(show.song.uid))
|
||||
}
|
||||
is Show.SongAlbumDetails -> {
|
||||
logD("Navigating to the album of ${show.song}")
|
||||
T.d("Navigating to the album of ${show.song}")
|
||||
findNavController()
|
||||
.navigateSafe(PlaylistDetailFragmentDirections.showAlbum(show.song.album.uid))
|
||||
}
|
||||
is Show.AlbumDetails -> {
|
||||
logD("Navigating to ${show.album}")
|
||||
T.d("Navigating to ${show.album}")
|
||||
findNavController()
|
||||
.navigateSafe(PlaylistDetailFragmentDirections.showAlbum(show.album.uid))
|
||||
}
|
||||
is Show.ArtistDetails -> {
|
||||
logD("Navigating to ${show.artist}")
|
||||
T.d("Navigating to ${show.artist}")
|
||||
findNavController()
|
||||
.navigateSafe(PlaylistDetailFragmentDirections.showArtist(show.artist.uid))
|
||||
}
|
||||
is Show.SongArtistDecision -> {
|
||||
logD("Navigating to artist choices for ${show.song}")
|
||||
T.d("Navigating to artist choices for ${show.song}")
|
||||
findNavController()
|
||||
.navigateSafe(PlaylistDetailFragmentDirections.showArtistChoices(show.song.uid))
|
||||
}
|
||||
is Show.AlbumArtistDecision -> {
|
||||
logD("Navigating to artist choices for ${show.album}")
|
||||
T.d("Navigating to artist choices for ${show.album}")
|
||||
findNavController()
|
||||
.navigateSafe(
|
||||
PlaylistDetailFragmentDirections.showArtistChoices(show.album.uid))
|
||||
}
|
||||
is Show.PlaylistDetails -> {
|
||||
logD("Navigated to this playlist")
|
||||
T.d("Navigated to this playlist")
|
||||
detailModel.toShow.consume()
|
||||
}
|
||||
is Show.GenreDetails -> {
|
||||
|
@ -333,7 +332,7 @@ class PlaylistDetailFragment :
|
|||
val directions =
|
||||
when (decision) {
|
||||
is PlaylistDecision.Import -> {
|
||||
logD("Importing playlist")
|
||||
T.d("Importing playlist")
|
||||
pendingImportTarget = decision.target
|
||||
requireNotNull(getContentLauncher) {
|
||||
"Content picker launcher was not available"
|
||||
|
@ -343,7 +342,7 @@ class PlaylistDetailFragment :
|
|||
return
|
||||
}
|
||||
is PlaylistDecision.Rename -> {
|
||||
logD("Renaming ${decision.playlist}")
|
||||
T.d("Renaming ${decision.playlist}")
|
||||
PlaylistDetailFragmentDirections.renamePlaylist(
|
||||
decision.playlist.uid,
|
||||
decision.template,
|
||||
|
@ -351,15 +350,15 @@ class PlaylistDetailFragment :
|
|||
decision.reason)
|
||||
}
|
||||
is PlaylistDecision.Export -> {
|
||||
logD("Exporting ${decision.playlist}")
|
||||
T.d("Exporting ${decision.playlist}")
|
||||
PlaylistDetailFragmentDirections.exportPlaylist(decision.playlist.uid)
|
||||
}
|
||||
is PlaylistDecision.Delete -> {
|
||||
logD("Deleting ${decision.playlist}")
|
||||
T.d("Deleting ${decision.playlist}")
|
||||
PlaylistDetailFragmentDirections.deletePlaylist(decision.playlist.uid)
|
||||
}
|
||||
is PlaylistDecision.Add -> {
|
||||
logD("Adding ${decision.songs.size} songs to a playlist")
|
||||
T.d("Adding ${decision.songs.size} songs to a playlist")
|
||||
PlaylistDetailFragmentDirections.addToPlaylist(
|
||||
decision.songs.map { it.uid }.toTypedArray())
|
||||
}
|
||||
|
@ -385,11 +384,11 @@ class PlaylistDetailFragment :
|
|||
val directions =
|
||||
when (decision) {
|
||||
is PlaybackDecision.PlayFromArtist -> {
|
||||
logD("Launching play from artist dialog for $decision")
|
||||
T.d("Launching play from artist dialog for $decision")
|
||||
PlaylistDetailFragmentDirections.playFromArtist(decision.song.uid)
|
||||
}
|
||||
is PlaybackDecision.PlayFromGenre -> {
|
||||
logD("Launching play from artist dialog for $decision")
|
||||
T.d("Launching play from artist dialog for $decision")
|
||||
PlaylistDetailFragmentDirections.playFromGenre(decision.song.uid)
|
||||
}
|
||||
}
|
||||
|
@ -400,15 +399,15 @@ class PlaylistDetailFragment :
|
|||
val id =
|
||||
when {
|
||||
detailModel.editedPlaylist.value != null -> {
|
||||
logD("Currently editing playlist, showing edit toolbar")
|
||||
T.d("Currently editing playlist, showing edit toolbar")
|
||||
R.id.detail_edit_toolbar
|
||||
}
|
||||
listModel.selected.value.isNotEmpty() -> {
|
||||
logD("Currently selecting, showing selection toolbar")
|
||||
T.d("Currently selecting, showing selection toolbar")
|
||||
R.id.detail_selection_toolbar
|
||||
}
|
||||
else -> {
|
||||
logD("Using normal toolbar")
|
||||
T.d("Using normal toolbar")
|
||||
R.id.detail_normal_toolbar
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ import org.oxycblt.auxio.playback.replaygain.formatDb
|
|||
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.concatLocalized
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ViewBindingMaterialDialogFragment] that shows information about a Song.
|
||||
|
@ -76,7 +76,7 @@ class SongDetailDialog : ViewBindingMaterialDialogFragment<DialogSongDetailBindi
|
|||
|
||||
private fun updateSong(song: Song?, info: AudioProperties?) {
|
||||
if (song == null) {
|
||||
logD("No song to show, navigating away")
|
||||
T.d("No song to show, navigating away")
|
||||
findNavController().navigateUp()
|
||||
return
|
||||
}
|
||||
|
|
|
@ -29,8 +29,7 @@ import org.oxycblt.auxio.music.Music
|
|||
import org.oxycblt.auxio.music.MusicRepository
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.device.DeviceLibrary
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ViewModel] that stores choice information for [ShowArtistDialog], and possibly others in the
|
||||
|
@ -60,7 +59,7 @@ class DetailPickerViewModel @Inject constructor(private val musicRepository: Mus
|
|||
val deviceLibrary = musicRepository.deviceLibrary ?: return
|
||||
// Need to sanitize different items depending on the current set of choices.
|
||||
_artistChoices.value = _artistChoices.value?.sanitize(deviceLibrary)
|
||||
logD("Updated artist choices: ${_artistChoices.value}")
|
||||
T.d("Updated artist choices: ${_artistChoices.value}")
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -69,20 +68,20 @@ class DetailPickerViewModel @Inject constructor(private val musicRepository: Mus
|
|||
* @param itemUid The [Music.UID] of the item to show. Must be a [Song] or [Album].
|
||||
*/
|
||||
fun setArtistChoiceUid(itemUid: Music.UID) {
|
||||
logD("Opening navigation choices for $itemUid")
|
||||
T.d("Opening navigation choices for $itemUid")
|
||||
// Support Songs and Albums, which have parent artists.
|
||||
_artistChoices.value =
|
||||
when (val music = musicRepository.find(itemUid)) {
|
||||
is Song -> {
|
||||
logD("Creating navigation choices for song")
|
||||
T.d("Creating navigation choices for song")
|
||||
ArtistShowChoices.FromSong(music)
|
||||
}
|
||||
is Album -> {
|
||||
logD("Creating navigation choices for album")
|
||||
T.d("Creating navigation choices for album")
|
||||
ArtistShowChoices.FromAlbum(music)
|
||||
}
|
||||
else -> {
|
||||
logW("Given song/album UID was invalid")
|
||||
T.w("Given song/album UID was invalid")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,7 +35,7 @@ import org.oxycblt.auxio.list.adapter.UpdateInstructions
|
|||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A picker [ViewBindingMaterialDialogFragment] intended for when the [Artist] to show is ambiguous.
|
||||
|
@ -85,7 +85,7 @@ class ShowArtistDialog :
|
|||
|
||||
private fun updateChoices(choices: ArtistShowChoices?) {
|
||||
if (choices == null) {
|
||||
logD("No choices to show, navigating away")
|
||||
T.d("No choices to show, navigating away")
|
||||
findNavController().navigateUp()
|
||||
return
|
||||
}
|
||||
|
|
|
@ -38,6 +38,7 @@ import org.oxycblt.auxio.list.recycler.DividerViewHolder
|
|||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.util.context
|
||||
import org.oxycblt.auxio.util.inflater
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [RecyclerView.Adapter] that implements shared behavior between lists of child items in the
|
||||
|
|
|
@ -46,7 +46,7 @@ import org.oxycblt.auxio.music.resolveNames
|
|||
import org.oxycblt.auxio.util.context
|
||||
import org.oxycblt.auxio.util.getAttrColorCompat
|
||||
import org.oxycblt.auxio.util.inflater
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [DetailListAdapter] implementing the header, sub-items, and editing state for the [Playlist]
|
||||
|
@ -97,7 +97,7 @@ class PlaylistDetailListAdapter(private val listener: Listener) :
|
|||
// Nothing to do.
|
||||
return
|
||||
}
|
||||
logD("Updating editing state [old: $isEditing new: $editing]")
|
||||
T.d("Updating editing state [old: $isEditing new: $editing]")
|
||||
this.isEditing = editing
|
||||
notifyItemRangeChanged(0, currentList.size, PAYLOAD_EDITING_CHANGED)
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.oxycblt.auxio.list.sort.Sort
|
|||
import org.oxycblt.auxio.list.sort.SortDialog
|
||||
import org.oxycblt.auxio.music.Album
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [SortDialog] that controls the [Sort] of [DetailViewModel.albumSongSort].
|
||||
|
@ -56,7 +56,7 @@ class AlbumSongSortDialog : SortDialog() {
|
|||
|
||||
private fun updateAlbum(album: Album?) {
|
||||
if (album == null) {
|
||||
logD("No album to sort, navigating away")
|
||||
T.d("No album to sort, navigating away")
|
||||
findNavController().navigateUp()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.oxycblt.auxio.list.sort.Sort
|
|||
import org.oxycblt.auxio.list.sort.SortDialog
|
||||
import org.oxycblt.auxio.music.Artist
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [SortDialog] that controls the [Sort] of [DetailViewModel.artistSongSort].
|
||||
|
@ -57,7 +57,7 @@ class ArtistSongSortDialog : SortDialog() {
|
|||
|
||||
private fun updateArtist(artist: Artist?) {
|
||||
if (artist == null) {
|
||||
logD("No artist to sort, navigating away")
|
||||
T.d("No artist to sort, navigating away")
|
||||
findNavController().navigateUp()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.oxycblt.auxio.list.sort.Sort
|
|||
import org.oxycblt.auxio.list.sort.SortDialog
|
||||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [SortDialog] that controls the [Sort] of [DetailViewModel.genreSongSort].
|
||||
|
@ -62,7 +62,7 @@ class GenreSongSortDialog : SortDialog() {
|
|||
|
||||
private fun updateGenre(genre: Genre?) {
|
||||
if (genre == null) {
|
||||
logD("No genre to sort, navigating away")
|
||||
T.d("No genre to sort, navigating away")
|
||||
findNavController().navigateUp()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.oxycblt.auxio.list.sort.Sort
|
|||
import org.oxycblt.auxio.list.sort.SortDialog
|
||||
import org.oxycblt.auxio.music.Playlist
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [SortDialog] that controls the [Sort] of [DetailViewModel.genreSongSort].
|
||||
|
@ -62,7 +62,7 @@ class PlaylistSongSortDialog : SortDialog() {
|
|||
|
||||
private fun updatePlaylist(genre: Playlist?) {
|
||||
if (genre == null) {
|
||||
logD("No genre to sort, navigating away")
|
||||
T.d("No genre to sort, navigating away")
|
||||
findNavController().navigateUp()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,10 +77,9 @@ import org.oxycblt.auxio.util.collectImmediately
|
|||
import org.oxycblt.auxio.util.getColorCompat
|
||||
import org.oxycblt.auxio.util.lazyReflectedField
|
||||
import org.oxycblt.auxio.util.lazyReflectedMethod
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
import org.oxycblt.auxio.util.showToast
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* The starting [SelectionFragment] of Auxio. Shows the user's music library and enables navigation
|
||||
|
@ -126,11 +125,11 @@ class HomeFragment :
|
|||
getContentLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
|
||||
if (uri == null) {
|
||||
logW("No URI returned from file picker")
|
||||
T.w("No URI returned from file picker")
|
||||
return@registerForActivityResult
|
||||
}
|
||||
|
||||
logD("Received playlist URI $uri")
|
||||
T.d("Received playlist URI $uri")
|
||||
musicModel.importPlaylist(uri, pendingImportTarget)
|
||||
}
|
||||
|
||||
|
@ -221,17 +220,17 @@ class HomeFragment :
|
|||
return when (item.itemId) {
|
||||
// Handle main actions (Search, Settings, About)
|
||||
R.id.action_search -> {
|
||||
logD("Navigating to search")
|
||||
T.d("Navigating to search")
|
||||
findNavController().navigateSafe(HomeFragmentDirections.search())
|
||||
true
|
||||
}
|
||||
R.id.action_settings -> {
|
||||
logD("Navigating to preferences")
|
||||
T.d("Navigating to preferences")
|
||||
homeModel.showSettings()
|
||||
true
|
||||
}
|
||||
R.id.action_about -> {
|
||||
logD("Navigating to about")
|
||||
T.d("Navigating to about")
|
||||
homeModel.showAbout()
|
||||
true
|
||||
}
|
||||
|
@ -251,7 +250,7 @@ class HomeFragment :
|
|||
true
|
||||
}
|
||||
else -> {
|
||||
logW("Unexpected menu item selected")
|
||||
T.w("Unexpected menu item selected")
|
||||
false
|
||||
}
|
||||
}
|
||||
|
@ -265,7 +264,7 @@ class HomeFragment :
|
|||
if (homeModel.currentTabTypes.size == 1) {
|
||||
// A single tab makes the tab layout redundant, hide it and disable the collapsing
|
||||
// behavior.
|
||||
logD("Single tab shown, disabling TabLayout")
|
||||
T.d("Single tab shown, disabling TabLayout")
|
||||
binding.homeTabs.isVisible = false
|
||||
binding.homeAppbar.setExpanded(true, false)
|
||||
toolbarParams.scrollFlags = 0
|
||||
|
@ -303,7 +302,7 @@ class HomeFragment :
|
|||
private fun handleRecreate(recreate: Unit?) {
|
||||
if (recreate == null) return
|
||||
val binding = requireBinding()
|
||||
logD("Recreating ViewPager")
|
||||
T.d("Recreating ViewPager")
|
||||
// Move back to position zero, as there must be a tab there.
|
||||
binding.homePager.currentItem = 0
|
||||
// Make sure tabs are set up to also follow the new ViewPager configuration.
|
||||
|
@ -320,7 +319,7 @@ class HomeFragment :
|
|||
is IndexingState.Completed -> setupCompleteState(binding, state.error)
|
||||
is IndexingState.Indexing -> setupIndexingState(binding, state.progress)
|
||||
null -> {
|
||||
logD("Indexer is in indeterminate state")
|
||||
T.d("Indexer is in indeterminate state")
|
||||
binding.homeIndexingContainer.visibility = View.INVISIBLE
|
||||
}
|
||||
}
|
||||
|
@ -328,19 +327,19 @@ class HomeFragment :
|
|||
|
||||
private fun setupCompleteState(binding: FragmentHomeBinding, error: Exception?) {
|
||||
if (error == null) {
|
||||
logD("Received ok response")
|
||||
T.d("Received ok response")
|
||||
binding.homeIndexingContainer.visibility = View.INVISIBLE
|
||||
return
|
||||
}
|
||||
|
||||
logD("Received non-ok response")
|
||||
T.d("Received non-ok response")
|
||||
val context = requireContext()
|
||||
binding.homeIndexingContainer.visibility = View.VISIBLE
|
||||
binding.homeIndexingProgress.visibility = View.INVISIBLE
|
||||
binding.homeIndexingActions.visibility = View.VISIBLE
|
||||
when (error) {
|
||||
is NoAudioPermissionException -> {
|
||||
logD("Showing permission prompt")
|
||||
T.d("Showing permission prompt")
|
||||
binding.homeIndexingStatus.setText(R.string.err_no_perms)
|
||||
// Configure the action to act as a permission launcher.
|
||||
binding.homeIndexingTry.apply {
|
||||
|
@ -355,7 +354,7 @@ class HomeFragment :
|
|||
binding.homeIndexingMore.visibility = View.GONE
|
||||
}
|
||||
is NoMusicException -> {
|
||||
logD("Showing no music error")
|
||||
T.d("Showing no music error")
|
||||
binding.homeIndexingStatus.setText(R.string.err_no_music)
|
||||
// Configure the action to act as a reload trigger.
|
||||
binding.homeIndexingTry.apply {
|
||||
|
@ -366,7 +365,7 @@ class HomeFragment :
|
|||
binding.homeIndexingMore.visibility = View.GONE
|
||||
}
|
||||
else -> {
|
||||
logD("Showing generic error")
|
||||
T.d("Showing generic error")
|
||||
binding.homeIndexingStatus.setText(R.string.err_index_failed)
|
||||
// Configure the action to act as a reload trigger.
|
||||
binding.homeIndexingTry.apply {
|
||||
|
@ -412,14 +411,14 @@ class HomeFragment :
|
|||
val directions =
|
||||
when (decision) {
|
||||
is PlaylistDecision.New -> {
|
||||
logD("Creating new playlist")
|
||||
T.d("Creating new playlist")
|
||||
HomeFragmentDirections.newPlaylist(
|
||||
decision.songs.map { it.uid }.toTypedArray(),
|
||||
decision.template,
|
||||
decision.reason)
|
||||
}
|
||||
is PlaylistDecision.Import -> {
|
||||
logD("Importing playlist")
|
||||
T.d("Importing playlist")
|
||||
pendingImportTarget = decision.target
|
||||
requireNotNull(getContentLauncher) {
|
||||
"Content picker launcher was not available"
|
||||
|
@ -429,7 +428,7 @@ class HomeFragment :
|
|||
return
|
||||
}
|
||||
is PlaylistDecision.Rename -> {
|
||||
logD("Renaming ${decision.playlist}")
|
||||
T.d("Renaming ${decision.playlist}")
|
||||
HomeFragmentDirections.renamePlaylist(
|
||||
decision.playlist.uid,
|
||||
decision.template,
|
||||
|
@ -437,15 +436,15 @@ class HomeFragment :
|
|||
decision.reason)
|
||||
}
|
||||
is PlaylistDecision.Export -> {
|
||||
logD("Exporting ${decision.playlist}")
|
||||
T.d("Exporting ${decision.playlist}")
|
||||
HomeFragmentDirections.exportPlaylist(decision.playlist.uid)
|
||||
}
|
||||
is PlaylistDecision.Delete -> {
|
||||
logD("Deleting ${decision.playlist}")
|
||||
T.d("Deleting ${decision.playlist}")
|
||||
HomeFragmentDirections.deletePlaylist(decision.playlist.uid)
|
||||
}
|
||||
is PlaylistDecision.Add -> {
|
||||
logD("Adding ${decision.songs.size} to a playlist")
|
||||
T.d("Adding ${decision.songs.size} to a playlist")
|
||||
HomeFragmentDirections.addToPlaylist(
|
||||
decision.songs.map { it.uid }.toTypedArray())
|
||||
}
|
||||
|
@ -476,38 +475,38 @@ class HomeFragment :
|
|||
private fun handleShow(show: Show?) {
|
||||
when (show) {
|
||||
is Show.SongDetails -> {
|
||||
logD("Navigating to ${show.song}")
|
||||
T.d("Navigating to ${show.song}")
|
||||
findNavController().navigateSafe(HomeFragmentDirections.showSong(show.song.uid))
|
||||
}
|
||||
is Show.SongAlbumDetails -> {
|
||||
logD("Navigating to the album of ${show.song}")
|
||||
T.d("Navigating to the album of ${show.song}")
|
||||
findNavController()
|
||||
.navigateSafe(HomeFragmentDirections.showAlbum(show.song.album.uid))
|
||||
}
|
||||
is Show.AlbumDetails -> {
|
||||
logD("Navigating to ${show.album}")
|
||||
T.d("Navigating to ${show.album}")
|
||||
findNavController().navigateSafe(HomeFragmentDirections.showAlbum(show.album.uid))
|
||||
}
|
||||
is Show.ArtistDetails -> {
|
||||
logD("Navigating to ${show.artist}")
|
||||
T.d("Navigating to ${show.artist}")
|
||||
findNavController().navigateSafe(HomeFragmentDirections.showArtist(show.artist.uid))
|
||||
}
|
||||
is Show.SongArtistDecision -> {
|
||||
logD("Navigating to artist choices for ${show.song}")
|
||||
T.d("Navigating to artist choices for ${show.song}")
|
||||
findNavController()
|
||||
.navigateSafe(HomeFragmentDirections.showArtistChoices(show.song.uid))
|
||||
}
|
||||
is Show.AlbumArtistDecision -> {
|
||||
logD("Navigating to artist choices for ${show.album}")
|
||||
T.d("Navigating to artist choices for ${show.album}")
|
||||
findNavController()
|
||||
.navigateSafe(HomeFragmentDirections.showArtistChoices(show.album.uid))
|
||||
}
|
||||
is Show.GenreDetails -> {
|
||||
logD("Navigating to ${show.genre}")
|
||||
T.d("Navigating to ${show.genre}")
|
||||
findNavController().navigateSafe(HomeFragmentDirections.showGenre(show.genre.uid))
|
||||
}
|
||||
is Show.PlaylistDetails -> {
|
||||
logD("Navigating to ${show.playlist}")
|
||||
T.d("Navigating to ${show.playlist}")
|
||||
findNavController()
|
||||
.navigateSafe(HomeFragmentDirections.showPlaylist(show.playlist.uid))
|
||||
}
|
||||
|
@ -535,7 +534,7 @@ class HomeFragment :
|
|||
binding.homeSelectionToolbar.title = getString(R.string.fmt_selected, selected.size)
|
||||
if (binding.homeToolbar.setVisible(R.id.home_selection_toolbar)) {
|
||||
// New selection started, show the AppBarLayout to indicate the new state.
|
||||
logD("Significant selection occurred, expanding AppBar")
|
||||
T.d("Significant selection occurred, expanding AppBar")
|
||||
binding.homeAppbar.expandWithScrollingRecycler()
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.oxycblt.auxio.music.MusicRepository
|
|||
import org.oxycblt.auxio.music.MusicType
|
||||
import org.oxycblt.auxio.music.Playlist
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
interface HomeGenerator {
|
||||
fun attach()
|
||||
|
@ -89,7 +89,7 @@ private class HomeGeneratorImpl(
|
|||
override fun onHideCollaboratorsChanged() {
|
||||
// Changes in the hide collaborator setting will change the artist contents
|
||||
// of the library, consider it a library update.
|
||||
logD("Collaborator setting changed, forwarding update")
|
||||
T.d("Collaborator setting changed, forwarding update")
|
||||
onMusicChanges(MusicRepository.Changes(deviceLibrary = true, userLibrary = false))
|
||||
}
|
||||
|
||||
|
@ -121,7 +121,7 @@ private class HomeGeneratorImpl(
|
|||
override fun onMusicChanges(changes: MusicRepository.Changes) {
|
||||
val deviceLibrary = musicRepository.deviceLibrary
|
||||
if (changes.deviceLibrary && deviceLibrary != null) {
|
||||
logD("Refreshing library")
|
||||
T.d("Refreshing library")
|
||||
// Get the each list of items in the library to use as our list data.
|
||||
// Applying the preferred sorting to them.
|
||||
invalidator.invalidateMusic(MusicType.SONGS, UpdateInstructions.Diff)
|
||||
|
@ -132,7 +132,7 @@ private class HomeGeneratorImpl(
|
|||
|
||||
val userLibrary = musicRepository.userLibrary
|
||||
if (changes.userLibrary && userLibrary != null) {
|
||||
logD("Refreshing playlists")
|
||||
T.d("Refreshing playlists")
|
||||
invalidator.invalidateMusic(MusicType.PLAYLISTS, UpdateInstructions.Diff)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ import org.oxycblt.auxio.R
|
|||
import org.oxycblt.auxio.home.tabs.Tab
|
||||
import org.oxycblt.auxio.music.MusicType
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* User configuration specific to the home UI.
|
||||
|
@ -68,17 +68,17 @@ class HomeSettingsImpl @Inject constructor(@ApplicationContext context: Context)
|
|||
|
||||
override fun migrate() {
|
||||
if (sharedPreferences.contains(OLD_KEY_LIB_TABS)) {
|
||||
logD("Migrating tab setting")
|
||||
T.d("Migrating tab setting")
|
||||
val oldTabs =
|
||||
Tab.fromIntCode(sharedPreferences.getInt(OLD_KEY_LIB_TABS, Tab.SEQUENCE_DEFAULT))
|
||||
?: unlikelyToBeNull(Tab.fromIntCode(Tab.SEQUENCE_DEFAULT))
|
||||
logD("Old tabs: $oldTabs")
|
||||
T.d("Old tabs: $oldTabs")
|
||||
|
||||
// The playlist tab is now parsed, but it needs to be made visible.
|
||||
val playlistIndex = oldTabs.indexOfFirst { it.type == MusicType.PLAYLISTS }
|
||||
check(playlistIndex > -1) // This should exist, otherwise we are in big trouble
|
||||
oldTabs[playlistIndex] = Tab.Visible(MusicType.PLAYLISTS)
|
||||
logD("New tabs: $oldTabs")
|
||||
T.d("New tabs: $oldTabs")
|
||||
|
||||
sharedPreferences.edit {
|
||||
putInt(getString(R.string.set_key_home_tabs), Tab.toIntCode(oldTabs))
|
||||
|
@ -90,11 +90,11 @@ class HomeSettingsImpl @Inject constructor(@ApplicationContext context: Context)
|
|||
override fun onSettingChanged(key: String, listener: HomeSettings.Listener) {
|
||||
when (key) {
|
||||
getString(R.string.set_key_home_tabs) -> {
|
||||
logD("Dispatching tab setting change")
|
||||
T.d("Dispatching tab setting change")
|
||||
listener.onTabsChanged()
|
||||
}
|
||||
getString(R.string.set_key_hide_collaborators) -> {
|
||||
logD("Dispatching collaborator setting change")
|
||||
T.d("Dispatching collaborator setting change")
|
||||
listener.onHideCollaboratorsChanged()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,7 +37,7 @@ import org.oxycblt.auxio.playback.PlaySong
|
|||
import org.oxycblt.auxio.playback.PlaybackSettings
|
||||
import org.oxycblt.auxio.util.Event
|
||||
import org.oxycblt.auxio.util.MutableEvent
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* The ViewModel for managing the tab data and lists of the home view.
|
||||
|
@ -249,7 +249,7 @@ constructor(
|
|||
* @param pagerPos The new position of the ViewPager2 instance.
|
||||
*/
|
||||
fun synchronizeTabPosition(pagerPos: Int) {
|
||||
logD("Updating current tab to ${currentTabTypes[pagerPos]}")
|
||||
T.d("Updating current tab to ${currentTabTypes[pagerPos]}")
|
||||
_currentTabType.value = currentTabTypes[pagerPos]
|
||||
}
|
||||
|
||||
|
@ -259,7 +259,7 @@ constructor(
|
|||
* @param isFastScrolling true if the user is currently fast scrolling, false otherwise.
|
||||
*/
|
||||
fun setFastScrolling(isFastScrolling: Boolean) {
|
||||
logD("Updating fast scrolling state: $isFastScrolling")
|
||||
T.d("Updating fast scrolling state: $isFastScrolling")
|
||||
_isFastScrolling.value = isFastScrolling
|
||||
}
|
||||
|
||||
|
|
|
@ -19,8 +19,7 @@
|
|||
package org.oxycblt.auxio.home.tabs
|
||||
|
||||
import org.oxycblt.auxio.music.MusicType
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A representation of a library tab suitable for configuration.
|
||||
|
@ -86,7 +85,7 @@ sealed class Tab(open val type: MusicType) {
|
|||
// Like when deserializing, make sure there are no duplicate tabs for whatever reason.
|
||||
val distinct = tabs.distinctBy { it.type }
|
||||
if (tabs.size != distinct.size) {
|
||||
logW(
|
||||
T.w(
|
||||
"Tab sequences should not have duplicates [old: ${tabs.size} new: ${distinct.size}]")
|
||||
}
|
||||
|
||||
|
@ -133,13 +132,13 @@ sealed class Tab(open val type: MusicType) {
|
|||
// Make sure there are no duplicate tabs
|
||||
val distinct = tabs.distinctBy { it.type }
|
||||
if (tabs.size != distinct.size) {
|
||||
logW(
|
||||
T.w(
|
||||
"Tab sequences should not have duplicates [old: ${tabs.size} new: ${distinct.size}]")
|
||||
}
|
||||
|
||||
// For safety, return null if we have an empty or larger-than-expected tab array.
|
||||
if (distinct.isEmpty() || distinct.size < MAX_SEQUENCE_IDX) {
|
||||
logE("Sequence size was ${distinct.size}, which is invalid")
|
||||
T.e("Sequence size was ${distinct.size}, which is invalid")
|
||||
return null
|
||||
}
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.oxycblt.auxio.list.EditClickListListener
|
|||
import org.oxycblt.auxio.list.recycler.DialogRecyclerView
|
||||
import org.oxycblt.auxio.music.MusicType
|
||||
import org.oxycblt.auxio.util.inflater
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [RecyclerView.Adapter] that displays an array of [Tab]s open for configuration.
|
||||
|
@ -55,7 +55,7 @@ class TabAdapter(private val listener: EditClickListListener<Tab>) :
|
|||
* @param newTabs The new array of tabs to show.
|
||||
*/
|
||||
fun submitTabs(newTabs: Array<Tab>) {
|
||||
logD("Force-updating tab information")
|
||||
T.d("Force-updating tab information")
|
||||
tabs = newTabs
|
||||
@Suppress("NotifyDatasetChanged") notifyDataSetChanged()
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ class TabAdapter(private val listener: EditClickListListener<Tab>) :
|
|||
* @param tab The new tab.
|
||||
*/
|
||||
fun setTab(at: Int, tab: Tab) {
|
||||
logD("Updating tab [at: $at, tab: $tab]")
|
||||
T.d("Updating tab [at: $at, tab: $tab]")
|
||||
tabs[at] = tab
|
||||
// Use a payload to avoid an item change animation.
|
||||
notifyItemChanged(at, PAYLOAD_TAB_CHANGED)
|
||||
|
@ -80,7 +80,7 @@ class TabAdapter(private val listener: EditClickListListener<Tab>) :
|
|||
* @param b The position of the second tab to swap.
|
||||
*/
|
||||
fun swapTabs(a: Int, b: Int) {
|
||||
logD("Swapping tabs [a: $a, b: $b]")
|
||||
T.d("Swapping tabs [a: $a, b: $b]")
|
||||
val tmp = tabs[b]
|
||||
tabs[b] = tabs[a]
|
||||
tabs[a] = tmp
|
||||
|
|
|
@ -31,7 +31,7 @@ import org.oxycblt.auxio.databinding.DialogTabsBinding
|
|||
import org.oxycblt.auxio.home.HomeSettings
|
||||
import org.oxycblt.auxio.list.EditClickListListener
|
||||
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ViewBindingMaterialDialogFragment] that allows the user to modify the home [Tab]
|
||||
|
@ -52,7 +52,7 @@ class TabCustomizeDialog :
|
|||
builder
|
||||
.setTitle(R.string.set_lib_tabs)
|
||||
.setPositiveButton(R.string.lbl_ok) { _, _ ->
|
||||
logD("Committing tab changes")
|
||||
T.d("Committing tab changes")
|
||||
homeSettings.homeTabs = tabAdapter.tabs
|
||||
}
|
||||
.setNegativeButton(R.string.lbl_cancel, null)
|
||||
|
@ -99,7 +99,7 @@ class TabCustomizeDialog :
|
|||
is Tab.Visible -> Tab.Invisible(old.type)
|
||||
is Tab.Invisible -> Tab.Visible(old.type)
|
||||
}
|
||||
logD("Flipping tab visibility [from: $old to: $new]")
|
||||
T.d("Flipping tab visibility [from: $old to: $new]")
|
||||
tabAdapter.setTab(index, new)
|
||||
|
||||
// Prevent the user from saving if all the tabs are Invisible, as that's an invalid state.
|
||||
|
|
|
@ -24,7 +24,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
|||
import javax.inject.Inject
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* User configuration specific to image loading.
|
||||
|
@ -58,7 +58,7 @@ class ImageSettingsImpl @Inject constructor(@ApplicationContext context: Context
|
|||
// Show album covers and Ignore MediaStore covers were unified in 3.0.0
|
||||
if (sharedPreferences.contains(OLD_KEY_SHOW_COVERS) ||
|
||||
sharedPreferences.contains(OLD_KEY_QUALITY_COVERS)) {
|
||||
logD("Migrating cover settings")
|
||||
T.d("Migrating cover settings")
|
||||
|
||||
val mode =
|
||||
when {
|
||||
|
@ -79,7 +79,7 @@ class ImageSettingsImpl @Inject constructor(@ApplicationContext context: Context
|
|||
override fun onSettingChanged(key: String, listener: ImageSettings.Listener) {
|
||||
if (key == getString(R.string.set_key_cover_mode) ||
|
||||
key == getString(R.string.set_key_square_covers)) {
|
||||
logD("Dispatching image setting change")
|
||||
T.d("Dispatching image setting change")
|
||||
listener.onImageSettingsChanged()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ import okio.source
|
|||
import org.oxycblt.auxio.image.CoverMode
|
||||
import org.oxycblt.auxio.image.ImageSettings
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Provides functionality for extracting album cover information. Meant for internal use only.
|
||||
|
@ -153,7 +153,7 @@ constructor(
|
|||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logE("Unable to extract album cover due to an error: $e")
|
||||
T.e("Unable to extract album cover due to an error: $e")
|
||||
null
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
package org.oxycblt.auxio.list
|
||||
|
||||
import androidx.annotation.StringRes
|
||||
import timber.log.Timber as T
|
||||
|
||||
// TODO: Consider breaking this up into sealed classes for individual adapters
|
||||
/** A marker for something that is a RecyclerView item. Has no functionality on it's own. */
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.oxycblt.auxio.list
|
|||
import androidx.recyclerview.widget.RecyclerView
|
||||
import androidx.viewbinding.ViewBinding
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A Fragment containing a selectable list.
|
||||
|
|
|
@ -36,8 +36,7 @@ import org.oxycblt.auxio.music.Song
|
|||
import org.oxycblt.auxio.playback.PlaySong
|
||||
import org.oxycblt.auxio.util.Event
|
||||
import org.oxycblt.auxio.util.MutableEvent
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ViewModel] that orchestrates menu dialogs and selection state.
|
||||
|
@ -94,16 +93,16 @@ constructor(private val listSettings: ListSettings, private val musicRepository:
|
|||
*/
|
||||
fun select(music: Music) {
|
||||
if (music is MusicParent && music.songs.isEmpty()) {
|
||||
logD("Cannot select empty parent, ignoring operation")
|
||||
T.d("Cannot select empty parent, ignoring operation")
|
||||
return
|
||||
}
|
||||
|
||||
val selected = _selected.value.toMutableList()
|
||||
if (!selected.remove(music)) {
|
||||
logD("Adding $music to selection")
|
||||
T.d("Adding $music to selection")
|
||||
selected.add(music)
|
||||
} else {
|
||||
logD("Removed $music from selection")
|
||||
T.d("Removed $music from selection")
|
||||
}
|
||||
|
||||
_selected.value = selected
|
||||
|
@ -131,7 +130,7 @@ constructor(private val listSettings: ListSettings, private val musicRepository:
|
|||
* @return A list of [Song]s collated from each item selected.
|
||||
*/
|
||||
fun takeSelection(): List<Song> {
|
||||
logD("Taking selection")
|
||||
T.d("Taking selection")
|
||||
return peekSelection().also { _selected.value = listOf() }
|
||||
}
|
||||
|
||||
|
@ -141,7 +140,7 @@ constructor(private val listSettings: ListSettings, private val musicRepository:
|
|||
* @return true if the prior selection was non-empty, false otherwise.
|
||||
*/
|
||||
fun dropSelection(): Boolean {
|
||||
logD("Dropping selection [empty=${_selected.value.isEmpty()}]")
|
||||
T.d("Dropping selection [empty=${_selected.value.isEmpty()}]")
|
||||
return _selected.value.isNotEmpty().also { _selected.value = listOf() }
|
||||
}
|
||||
|
||||
|
@ -155,7 +154,7 @@ constructor(private val listSettings: ListSettings, private val musicRepository:
|
|||
* should do.
|
||||
*/
|
||||
fun openMenu(@MenuRes menuRes: Int, song: Song, playWith: PlaySong) {
|
||||
logD("Opening menu for $song")
|
||||
T.d("Opening menu for $song")
|
||||
openImpl(Menu.ForSong(menuRes, song, playWith))
|
||||
}
|
||||
|
||||
|
@ -167,7 +166,7 @@ constructor(private val listSettings: ListSettings, private val musicRepository:
|
|||
* @param album The [Album] to show.
|
||||
*/
|
||||
fun openMenu(@MenuRes menuRes: Int, album: Album) {
|
||||
logD("Opening menu for $album")
|
||||
T.d("Opening menu for $album")
|
||||
openImpl(Menu.ForAlbum(menuRes, album))
|
||||
}
|
||||
|
||||
|
@ -179,7 +178,7 @@ constructor(private val listSettings: ListSettings, private val musicRepository:
|
|||
* @param artist The [Artist] to show.
|
||||
*/
|
||||
fun openMenu(@MenuRes menuRes: Int, artist: Artist) {
|
||||
logD("Opening menu for $artist")
|
||||
T.d("Opening menu for $artist")
|
||||
openImpl(Menu.ForArtist(menuRes, artist))
|
||||
}
|
||||
|
||||
|
@ -191,7 +190,7 @@ constructor(private val listSettings: ListSettings, private val musicRepository:
|
|||
* @param genre The [Genre] to show.
|
||||
*/
|
||||
fun openMenu(@MenuRes menuRes: Int, genre: Genre) {
|
||||
logD("Opening menu for $genre")
|
||||
T.d("Opening menu for $genre")
|
||||
openImpl(Menu.ForGenre(menuRes, genre))
|
||||
}
|
||||
|
||||
|
@ -203,7 +202,7 @@ constructor(private val listSettings: ListSettings, private val musicRepository:
|
|||
* @param playlist The [Playlist] to show.
|
||||
*/
|
||||
fun openMenu(@MenuRes menuRes: Int, playlist: Playlist) {
|
||||
logD("Opening menu for $playlist")
|
||||
T.d("Opening menu for $playlist")
|
||||
openImpl(Menu.ForPlaylist(menuRes, playlist))
|
||||
}
|
||||
|
||||
|
@ -215,14 +214,14 @@ constructor(private val listSettings: ListSettings, private val musicRepository:
|
|||
* @param songs The [Song] selection to show.
|
||||
*/
|
||||
fun openMenu(@MenuRes menuRes: Int, songs: List<Song>) {
|
||||
logD("Opening menu for ${songs.size} songs")
|
||||
T.d("Opening menu for ${songs.size} songs")
|
||||
openImpl(Menu.ForSelection(menuRes, songs))
|
||||
}
|
||||
|
||||
private fun openImpl(menu: Menu) {
|
||||
val existing = _menu.flow.value
|
||||
if (existing != null) {
|
||||
logW("Already opening $existing, ignoring $menu")
|
||||
T.w("Already opening $existing, ignoring $menu")
|
||||
return
|
||||
}
|
||||
_menu.put(menu)
|
||||
|
|
|
@ -21,6 +21,7 @@ package org.oxycblt.auxio.list
|
|||
import android.view.MotionEvent
|
||||
import android.view.View
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A basic listener for list interactions.
|
||||
|
|
|
@ -25,7 +25,7 @@ import androidx.recyclerview.widget.AsyncDifferConfig
|
|||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import java.util.concurrent.Executor
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A variant of ListDiffer with more flexible updates.
|
||||
|
@ -57,7 +57,7 @@ abstract class FlexibleListAdapter<T, VH : RecyclerView.ViewHolder>(
|
|||
instructions: UpdateInstructions?,
|
||||
callback: (() -> Unit)? = null
|
||||
) {
|
||||
logD("Updating list to ${newList.size} items with $instructions")
|
||||
T.d("Updating list to ${newList.size} items with $instructions")
|
||||
differ.update(newList, instructions, callback)
|
||||
}
|
||||
}
|
||||
|
@ -171,7 +171,7 @@ private class FlexibleListDiffer<T>(
|
|||
) {
|
||||
// fast simple remove all
|
||||
if (newList.isEmpty()) {
|
||||
logD("Short-circuiting diff to remove all")
|
||||
T.d("Short-circuiting diff to remove all")
|
||||
val countRemoved = oldList.size
|
||||
currentList = emptyList()
|
||||
// notify last, after list is updated
|
||||
|
@ -182,7 +182,7 @@ private class FlexibleListDiffer<T>(
|
|||
|
||||
// fast simple first insert
|
||||
if (oldList.isEmpty()) {
|
||||
logD("Short-circuiting diff to insert all")
|
||||
T.d("Short-circuiting diff to insert all")
|
||||
currentList = newList
|
||||
// notify last, after list is updated
|
||||
updateCallback.onInserted(0, newList.size)
|
||||
|
@ -244,7 +244,7 @@ private class FlexibleListDiffer<T>(
|
|||
|
||||
mainThreadExecutor.execute {
|
||||
if (maxScheduledGeneration == runGeneration) {
|
||||
logD("Applying calculated diff")
|
||||
T.d("Applying calculated diff")
|
||||
currentList = newList
|
||||
result.dispatchUpdatesTo(updateCallback)
|
||||
callback?.invoke()
|
||||
|
|
|
@ -21,8 +21,7 @@ package org.oxycblt.auxio.list.adapter
|
|||
import android.view.View
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [RecyclerView.Adapter] that supports indicating the playback status of a particular item.
|
||||
|
@ -59,7 +58,7 @@ abstract class PlayingIndicatorAdapter<T, VH : RecyclerView.ViewHolder>(
|
|||
* @param isPlaying Whether playback is ongoing or paused.
|
||||
*/
|
||||
fun setPlaying(item: T?, isPlaying: Boolean) {
|
||||
logD("Updating playing item [old: $currentItem new: $item]")
|
||||
T.d("Updating playing item [old: $currentItem new: $item]")
|
||||
|
||||
var updatedItem = false
|
||||
if (currentItem != item) {
|
||||
|
@ -72,7 +71,7 @@ abstract class PlayingIndicatorAdapter<T, VH : RecyclerView.ViewHolder>(
|
|||
if (pos > -1) {
|
||||
notifyItemChanged(pos, PAYLOAD_PLAYING_INDICATOR_CHANGED)
|
||||
} else {
|
||||
logW("oldItem was not in adapter data")
|
||||
T.w("oldItem was not in adapter data")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -82,7 +81,7 @@ abstract class PlayingIndicatorAdapter<T, VH : RecyclerView.ViewHolder>(
|
|||
if (pos > -1) {
|
||||
notifyItemChanged(pos, PAYLOAD_PLAYING_INDICATOR_CHANGED)
|
||||
} else {
|
||||
logW("newItem was not in adapter data")
|
||||
T.w("newItem was not in adapter data")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -100,7 +99,7 @@ abstract class PlayingIndicatorAdapter<T, VH : RecyclerView.ViewHolder>(
|
|||
if (pos > -1) {
|
||||
notifyItemChanged(pos, PAYLOAD_PLAYING_INDICATOR_CHANGED)
|
||||
} else {
|
||||
logW("newItem was not in adapter data")
|
||||
T.w("newItem was not in adapter data")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,7 +22,7 @@ import android.view.View
|
|||
import androidx.recyclerview.widget.DiffUtil
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [PlayingIndicatorAdapter] that also supports indicating the selection status of a group of
|
||||
|
@ -55,7 +55,7 @@ abstract class SelectionIndicatorAdapter<T, VH : RecyclerView.ViewHolder>(
|
|||
// Nothing to do.
|
||||
return
|
||||
}
|
||||
logD("Updating selection [old=${oldSelectedItems.size} new=${newSelectedItems.size}")
|
||||
T.d("Updating selection [old=${oldSelectedItems.size} new=${newSelectedItems.size}")
|
||||
|
||||
selectedItems = newSelectedItems
|
||||
for (i in currentList.indices) {
|
||||
|
|
|
@ -20,6 +20,7 @@ package org.oxycblt.auxio.list.adapter
|
|||
|
||||
import androidx.recyclerview.widget.DiffUtil
|
||||
import org.oxycblt.auxio.list.Item
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [DiffUtil.ItemCallback] that automatically implements the [areItemsTheSame] method. Use this
|
||||
|
|
|
@ -33,7 +33,7 @@ import org.oxycblt.auxio.list.ListViewModel
|
|||
import org.oxycblt.auxio.list.adapter.UpdateInstructions
|
||||
import org.oxycblt.auxio.ui.ViewBindingBottomSheetDialogFragment
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ViewBindingBottomSheetDialogFragment] that displays basic music information and a series of
|
||||
|
@ -102,7 +102,7 @@ abstract class MenuDialogFragment<M : Menu> :
|
|||
|
||||
private fun updateMenu(menu: Menu?) {
|
||||
if (menu == null) {
|
||||
logD("No menu to show, navigating away")
|
||||
T.d("No menu to show, navigating away")
|
||||
findNavController().navigateUp()
|
||||
return
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import kotlinx.coroutines.flow.StateFlow
|
|||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.MusicRepository
|
||||
import org.oxycblt.auxio.playback.PlaySong
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Manages the state information for [MenuDialogFragment] implementations.
|
||||
|
@ -55,7 +55,7 @@ class MenuViewModel @Inject constructor(private val musicRepository: MusicReposi
|
|||
fun setMenu(parcel: Menu.Parcel) {
|
||||
_currentMenu.value = unpackParcel(parcel)
|
||||
if (_currentMenu.value == null) {
|
||||
logW("Given menu parcel $parcel was invalid")
|
||||
T.w("Given menu parcel $parcel was invalid")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.oxycblt.auxio.R
|
|||
import org.oxycblt.auxio.list.recycler.MaterialDragCallback.ViewHolder
|
||||
import org.oxycblt.auxio.util.getDimen
|
||||
import org.oxycblt.auxio.util.getInteger
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A highly customized [ItemTouchHelper.Callback] that enables some extra eye candy in editable UIs,
|
||||
|
@ -94,7 +94,7 @@ abstract class MaterialDragCallback : ItemTouchHelper.Callback() {
|
|||
// this is only done once when the item is initially picked up.
|
||||
// TODO: I think this is possible to improve with a raw ValueAnimator.
|
||||
if (shouldLift && isCurrentlyActive && actionState == ItemTouchHelper.ACTION_STATE_DRAG) {
|
||||
logD("Lifting ViewHolder")
|
||||
T.d("Lifting ViewHolder")
|
||||
|
||||
val bg = holder.background
|
||||
val elevation = recyclerView.context.getDimen(MR.dimen.m3_sys_elevation_level4)
|
||||
|
@ -136,7 +136,7 @@ abstract class MaterialDragCallback : ItemTouchHelper.Callback() {
|
|||
// This function can be called multiple times, so only start the animation when the view's
|
||||
// translationZ is already non-zero.
|
||||
if (holder.root.translationZ != 0f) {
|
||||
logD("Lifting ViewHolder")
|
||||
T.d("Lifting ViewHolder")
|
||||
|
||||
val bg = holder.background
|
||||
val elevation = recyclerView.context.getDimen(MR.dimen.m3_sys_elevation_level4)
|
||||
|
|
|
@ -39,6 +39,7 @@ import org.oxycblt.auxio.music.info.ReleaseType
|
|||
import org.oxycblt.auxio.playback.replaygain.ReplayGainAdjustment
|
||||
import org.oxycblt.auxio.util.concatLocalized
|
||||
import org.oxycblt.auxio.util.toUuidOrNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Abstract music data. This contains universal information about all concrete music
|
||||
|
|
|
@ -44,9 +44,7 @@ import org.oxycblt.auxio.music.user.MutableUserLibrary
|
|||
import org.oxycblt.auxio.music.user.UserLibrary
|
||||
import org.oxycblt.auxio.util.DEFAULT_TIMEOUT
|
||||
import org.oxycblt.auxio.util.forEachWithTimeout
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Primary manager of music information and loading.
|
||||
|
@ -244,51 +242,51 @@ constructor(
|
|||
|
||||
@Synchronized
|
||||
override fun addUpdateListener(listener: MusicRepository.UpdateListener) {
|
||||
logD("Adding $listener to update listeners")
|
||||
T.d("Adding $listener to update listeners")
|
||||
updateListeners.add(listener)
|
||||
listener.onMusicChanges(MusicRepository.Changes(deviceLibrary = true, userLibrary = true))
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun removeUpdateListener(listener: MusicRepository.UpdateListener) {
|
||||
logD("Removing $listener to update listeners")
|
||||
T.d("Removing $listener to update listeners")
|
||||
if (!updateListeners.remove(listener)) {
|
||||
logW("Update listener $listener was not added prior, cannot remove")
|
||||
T.w("Update listener $listener was not added prior, cannot remove")
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun addIndexingListener(listener: MusicRepository.IndexingListener) {
|
||||
logD("Adding $listener to indexing listeners")
|
||||
T.d("Adding $listener to indexing listeners")
|
||||
indexingListeners.add(listener)
|
||||
listener.onIndexingStateChanged()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun removeIndexingListener(listener: MusicRepository.IndexingListener) {
|
||||
logD("Removing $listener from indexing listeners")
|
||||
T.d("Removing $listener from indexing listeners")
|
||||
if (!indexingListeners.remove(listener)) {
|
||||
logW("Indexing listener $listener was not added prior, cannot remove")
|
||||
T.w("Indexing listener $listener was not added prior, cannot remove")
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun registerWorker(worker: MusicRepository.IndexingWorker) {
|
||||
if (indexingWorker != null) {
|
||||
logW("Worker is already registered")
|
||||
T.w("Worker is already registered")
|
||||
return
|
||||
}
|
||||
logD("Registering worker $worker")
|
||||
T.d("Registering worker $worker")
|
||||
indexingWorker = worker
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun unregisterWorker(worker: MusicRepository.IndexingWorker) {
|
||||
if (indexingWorker !== worker) {
|
||||
logW("Given worker did not match current worker")
|
||||
T.w("Given worker did not match current worker")
|
||||
return
|
||||
}
|
||||
logD("Unregistering worker $worker")
|
||||
T.d("Unregistering worker $worker")
|
||||
indexingWorker = null
|
||||
currentIndexingState = null
|
||||
}
|
||||
|
@ -300,42 +298,42 @@ constructor(
|
|||
|
||||
override suspend fun createPlaylist(name: String, songs: List<Song>) {
|
||||
val userLibrary = synchronized(this) { userLibrary ?: return }
|
||||
logD("Creating playlist $name with ${songs.size} songs")
|
||||
T.d("Creating playlist $name with ${songs.size} songs")
|
||||
userLibrary.createPlaylist(name, songs)
|
||||
withContext(Dispatchers.Main) { dispatchLibraryChange(device = false, user = true) }
|
||||
}
|
||||
|
||||
override suspend fun renamePlaylist(playlist: Playlist, name: String) {
|
||||
val userLibrary = synchronized(this) { userLibrary ?: return }
|
||||
logD("Renaming $playlist to $name")
|
||||
T.d("Renaming $playlist to $name")
|
||||
userLibrary.renamePlaylist(playlist, name)
|
||||
withContext(Dispatchers.Main) { dispatchLibraryChange(device = false, user = true) }
|
||||
}
|
||||
|
||||
override suspend fun deletePlaylist(playlist: Playlist) {
|
||||
val userLibrary = synchronized(this) { userLibrary ?: return }
|
||||
logD("Deleting $playlist")
|
||||
T.d("Deleting $playlist")
|
||||
userLibrary.deletePlaylist(playlist)
|
||||
withContext(Dispatchers.Main) { dispatchLibraryChange(device = false, user = true) }
|
||||
}
|
||||
|
||||
override suspend fun addToPlaylist(songs: List<Song>, playlist: Playlist) {
|
||||
val userLibrary = synchronized(this) { userLibrary ?: return }
|
||||
logD("Adding ${songs.size} songs to $playlist")
|
||||
T.d("Adding ${songs.size} songs to $playlist")
|
||||
userLibrary.addToPlaylist(playlist, songs)
|
||||
withContext(Dispatchers.Main) { dispatchLibraryChange(device = false, user = true) }
|
||||
}
|
||||
|
||||
override suspend fun rewritePlaylist(playlist: Playlist, songs: List<Song>) {
|
||||
val userLibrary = synchronized(this) { userLibrary ?: return }
|
||||
logD("Rewriting $playlist with ${songs.size} songs")
|
||||
T.d("Rewriting $playlist with ${songs.size} songs")
|
||||
userLibrary.rewritePlaylist(playlist, songs)
|
||||
withContext(Dispatchers.Main) { dispatchLibraryChange(device = false, user = true) }
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun requestIndex(withCache: Boolean) {
|
||||
logD("Requesting index operation [cache=$withCache]")
|
||||
T.d("Requesting index operation [cache=$withCache]")
|
||||
indexingWorker?.requestIndex(withCache)
|
||||
}
|
||||
|
||||
|
@ -347,13 +345,13 @@ constructor(
|
|||
indexImpl(context, scope, withCache)
|
||||
} catch (e: CancellationException) {
|
||||
// Got cancelled, propagate upwards to top-level co-routine.
|
||||
logD("Loading routine was cancelled")
|
||||
T.d("Loading routine was cancelled")
|
||||
throw e
|
||||
} catch (e: Exception) {
|
||||
// Music loading process failed due to something we have not handled.
|
||||
// TODO: Still want to display this error eventually
|
||||
logE("Music indexing failed")
|
||||
logE(e.stackTraceToString())
|
||||
T.e("Music indexing failed")
|
||||
T.e(e.stackTraceToString())
|
||||
emitIndexingCompletion(e)
|
||||
}
|
||||
}
|
||||
|
@ -366,7 +364,7 @@ constructor(
|
|||
// done at the UI level, but that intertwines logic and display too much.
|
||||
if (ContextCompat.checkSelfPermission(context, PERMISSION_READ_AUDIO) ==
|
||||
PackageManager.PERMISSION_DENIED) {
|
||||
logE("Permissions were not granted")
|
||||
T.e("Permissions were not granted")
|
||||
throw NoAudioPermissionException()
|
||||
}
|
||||
|
||||
|
@ -385,7 +383,7 @@ constructor(
|
|||
// to figure out what songs are (probably) on the device, and the latter will be needed
|
||||
// for discovery (described later). These have no shared state, so they are done in
|
||||
// parallel.
|
||||
logD("Starting MediaStore query")
|
||||
T.d("Starting MediaStore query")
|
||||
emitIndexingProgress(IndexingProgress.Indeterminate)
|
||||
|
||||
val mediaStoreQueryJob =
|
||||
|
@ -406,18 +404,18 @@ constructor(
|
|||
// identical to calling async.
|
||||
val cache =
|
||||
if (withCache) {
|
||||
logD("Reading cache")
|
||||
T.d("Reading cache")
|
||||
cacheRepository.readCache()
|
||||
} else {
|
||||
null
|
||||
}
|
||||
logD("Awaiting MediaStore query")
|
||||
T.d("Awaiting MediaStore query")
|
||||
val query = mediaStoreQueryJob.await().getOrThrow()
|
||||
|
||||
// We now have all the information required to start the "discovery" process. This
|
||||
// is the point at which Auxio starts scanning each file given from MediaStore and
|
||||
// transforming it into a music library. MediaStore normally
|
||||
logD("Starting discovery")
|
||||
T.d("Starting discovery")
|
||||
val incompleteSongs = Channel<RawSong>(Channel.UNLIMITED) // Not fully populated w/metadata
|
||||
val completeSongs = Channel<RawSong>(Channel.UNLIMITED) // Populated with quality metadata
|
||||
val processedSongs = Channel<RawSong>(Channel.UNLIMITED) // Transformed into SongImpl
|
||||
|
@ -425,7 +423,7 @@ constructor(
|
|||
// MediaStoreExtractor discovers all music on the device, and forwards them to either
|
||||
// DeviceLibrary if cached metadata exists for it, or TagExtractor if cached metadata
|
||||
// does not exist. In the latter situation, it also applies it's own (inferior) metadata.
|
||||
logD("Starting MediaStore discovery")
|
||||
T.d("Starting MediaStore discovery")
|
||||
val mediaStoreJob =
|
||||
scope.async {
|
||||
try {
|
||||
|
@ -434,7 +432,7 @@ constructor(
|
|||
// To prevent a deadlock, we want to close the channel with an exception
|
||||
// to cascade to and cancel all other routines before finally bubbling up
|
||||
// to the main extractor loop.
|
||||
logE("MediaStore extraction failed: $e")
|
||||
T.e("MediaStore extraction failed: $e")
|
||||
incompleteSongs.close(
|
||||
Exception("MediaStore extraction failed: ${e.stackTraceToString()}"))
|
||||
return@async
|
||||
|
@ -444,13 +442,13 @@ constructor(
|
|||
|
||||
// TagExtractor takes the incomplete songs from MediaStoreExtractor, parses up-to-date
|
||||
// metadata for them, and then forwards it to DeviceLibrary.
|
||||
logD("Starting tag extraction")
|
||||
T.d("Starting tag extraction")
|
||||
val tagJob =
|
||||
scope.async {
|
||||
try {
|
||||
tagExtractor.consume(incompleteSongs, completeSongs)
|
||||
} catch (e: Exception) {
|
||||
logE("Tag extraction failed: $e")
|
||||
T.e("Tag extraction failed: $e")
|
||||
completeSongs.close(
|
||||
Exception("Tag extraction failed: ${e.stackTraceToString()}"))
|
||||
return@async
|
||||
|
@ -460,7 +458,7 @@ constructor(
|
|||
|
||||
// DeviceLibrary constructs music parent instances as song information is provided,
|
||||
// and then forwards them to the primary loading loop.
|
||||
logD("Starting DeviceLibrary creation")
|
||||
T.d("Starting DeviceLibrary creation")
|
||||
val deviceLibraryJob =
|
||||
scope.async(Dispatchers.Default) {
|
||||
val deviceLibrary =
|
||||
|
@ -468,7 +466,7 @@ constructor(
|
|||
deviceLibraryFactory.create(
|
||||
completeSongs, processedSongs, separators, nameFactory)
|
||||
} catch (e: Exception) {
|
||||
logE("DeviceLibrary creation failed: $e")
|
||||
T.e("DeviceLibrary creation failed: $e")
|
||||
processedSongs.close(
|
||||
Exception("DeviceLibrary creation failed: ${e.stackTraceToString()}"))
|
||||
return@async Result.failure(e)
|
||||
|
@ -499,14 +497,14 @@ constructor(
|
|||
// that the short-circuit occurs so quickly as to break the UI.
|
||||
// TODO: Do not error, instead just wipe the entire library.
|
||||
if (rawSongs.isEmpty()) {
|
||||
logE("Music library was empty")
|
||||
T.e("Music library was empty")
|
||||
throw NoMusicException()
|
||||
}
|
||||
|
||||
// Now that the library is effectively loaded, we can start the finalization step, which
|
||||
// involves writing new cache information and creating more music data that is derived
|
||||
// from the library (e.g playlists)
|
||||
logD("Discovered ${rawSongs.size} songs, starting finalization")
|
||||
T.d("Discovered ${rawSongs.size} songs, starting finalization")
|
||||
|
||||
// We have no idea how long the cache will take, and the playlist construction
|
||||
// will be too fast to indicate, so switch back to an indeterminate state.
|
||||
|
@ -515,7 +513,7 @@ constructor(
|
|||
// The UserLibrary job is split into a query and construction step, a la MediaStore.
|
||||
// This way, we can start working on playlists even as DeviceLibrary might still be
|
||||
// working on parent information.
|
||||
logD("Starting UserLibrary query")
|
||||
T.d("Starting UserLibrary query")
|
||||
val userLibraryQueryJob =
|
||||
scope.async {
|
||||
val rawPlaylists =
|
||||
|
@ -532,20 +530,20 @@ constructor(
|
|||
// since the playlist read will probably take some time.
|
||||
// TODO: Read/write from the cache incrementally instead of in bulk?
|
||||
if (cache == null || cache.invalidated) {
|
||||
logD("Writing cache [why=${cache?.invalidated}]")
|
||||
T.d("Writing cache [why=${cache?.invalidated}]")
|
||||
cacheRepository.writeCache(rawSongs)
|
||||
}
|
||||
|
||||
// Create UserLibrary once we finally get the required components for it.
|
||||
logD("Awaiting UserLibrary query")
|
||||
T.d("Awaiting UserLibrary query")
|
||||
val rawPlaylists = userLibraryQueryJob.await().getOrThrow()
|
||||
logD("Awaiting DeviceLibrary creation")
|
||||
T.d("Awaiting DeviceLibrary creation")
|
||||
val deviceLibrary = deviceLibraryJob.await().getOrThrow()
|
||||
logD("Starting UserLibrary creation")
|
||||
T.d("Starting UserLibrary creation")
|
||||
val userLibrary = userLibraryFactory.create(rawPlaylists, deviceLibrary, nameFactory)
|
||||
|
||||
// Loading process is functionally done, indicate such
|
||||
logD(
|
||||
T.d(
|
||||
"Successfully indexed music library [device=$deviceLibrary " +
|
||||
"user=$userLibrary time=${System.currentTimeMillis() - start}]")
|
||||
emitIndexingCompletion(null)
|
||||
|
@ -561,7 +559,7 @@ constructor(
|
|||
deviceLibraryChanged = this.deviceLibrary != deviceLibrary
|
||||
userLibraryChanged = this.userLibrary != userLibrary
|
||||
if (!deviceLibraryChanged && !userLibraryChanged) {
|
||||
logD("Library has not changed, skipping update")
|
||||
T.d("Library has not changed, skipping update")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -591,7 +589,7 @@ constructor(
|
|||
synchronized(this) {
|
||||
previousCompletedState = IndexingState.Completed(error)
|
||||
currentIndexingState = null
|
||||
logD("Dispatching completion state [error=$error]")
|
||||
T.d("Dispatching completion state [error=$error]")
|
||||
for (listener in indexingListeners) {
|
||||
listener.onIndexingStateChanged()
|
||||
}
|
||||
|
@ -601,7 +599,7 @@ constructor(
|
|||
@Synchronized
|
||||
private fun dispatchLibraryChange(device: Boolean, user: Boolean) {
|
||||
val changes = MusicRepository.Changes(device, user)
|
||||
logD("Dispatching library change [changes=$changes]")
|
||||
T.d("Dispatching library change [changes=$changes]")
|
||||
for (listener in updateListeners) {
|
||||
listener.onMusicChanges(changes)
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import org.oxycblt.auxio.R
|
|||
import org.oxycblt.auxio.music.dirs.MusicDirectories
|
||||
import org.oxycblt.auxio.music.fs.DocumentPathFactory
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* User configuration specific to music system.
|
||||
|
@ -108,11 +108,11 @@ constructor(
|
|||
getString(R.string.set_key_music_dirs_include),
|
||||
getString(R.string.set_key_separators),
|
||||
getString(R.string.set_key_auto_sort_names) -> {
|
||||
logD("Dispatching indexing setting change for $key")
|
||||
T.d("Dispatching indexing setting change for $key")
|
||||
listener.onIndexingSettingChanged()
|
||||
}
|
||||
getString(R.string.set_key_observing) -> {
|
||||
logD("Dispatching observing setting change")
|
||||
T.d("Dispatching observing setting change")
|
||||
listener.onObservingChanged()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,8 +33,7 @@ import org.oxycblt.auxio.music.external.ExportConfig
|
|||
import org.oxycblt.auxio.music.external.ExternalPlaylistManager
|
||||
import org.oxycblt.auxio.util.Event
|
||||
import org.oxycblt.auxio.util.MutableEvent
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ViewModel] providing data specific to the music loading process.
|
||||
|
@ -94,7 +93,7 @@ constructor(
|
|||
deviceLibrary.artists.size,
|
||||
deviceLibrary.genres.size,
|
||||
deviceLibrary.songs.sumOf { it.durationMs })
|
||||
logD("Updated statistics: ${_statistics.value}")
|
||||
T.d("Updated statistics: ${_statistics.value}")
|
||||
}
|
||||
|
||||
override fun onIndexingStateChanged() {
|
||||
|
@ -103,13 +102,13 @@ constructor(
|
|||
|
||||
/** Requests that the music library should be re-loaded while leveraging the cache. */
|
||||
fun refresh() {
|
||||
logD("Refreshing library")
|
||||
T.d("Refreshing library")
|
||||
musicRepository.requestIndex(true)
|
||||
}
|
||||
|
||||
/** Requests that the music library be re-loaded without the cache. */
|
||||
fun rescan() {
|
||||
logD("Rescanning library")
|
||||
T.d("Rescanning library")
|
||||
musicRepository.requestIndex(false)
|
||||
}
|
||||
|
||||
|
@ -127,7 +126,7 @@ constructor(
|
|||
reason: PlaylistDecision.New.Reason = PlaylistDecision.New.Reason.NEW
|
||||
) {
|
||||
if (name != null) {
|
||||
logD("Creating $name with ${songs.size} songs]")
|
||||
T.d("Creating $name with ${songs.size} songs]")
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
musicRepository.createPlaylist(name, songs)
|
||||
val message =
|
||||
|
@ -139,7 +138,7 @@ constructor(
|
|||
_playlistMessage.put(message)
|
||||
}
|
||||
} else {
|
||||
logD("Launching creation dialog for ${songs.size} songs")
|
||||
T.d("Launching creation dialog for ${songs.size} songs")
|
||||
_playlistDecision.put(PlaylistDecision.New(songs, null, reason))
|
||||
}
|
||||
}
|
||||
|
@ -158,7 +157,7 @@ constructor(
|
|||
viewModelScope.launch(Dispatchers.IO) {
|
||||
val importedPlaylist = externalPlaylistManager.import(uri)
|
||||
if (importedPlaylist == null) {
|
||||
logE("Could not import playlist")
|
||||
T.e("Could not import playlist")
|
||||
_playlistMessage.put(PlaylistMessage.ImportFailed)
|
||||
return@launch
|
||||
}
|
||||
|
@ -170,7 +169,7 @@ constructor(
|
|||
}
|
||||
|
||||
if (songs.isEmpty()) {
|
||||
logE("No songs found")
|
||||
T.e("No songs found")
|
||||
_playlistMessage.put(PlaylistMessage.ImportFailed)
|
||||
return@launch
|
||||
}
|
||||
|
@ -194,7 +193,7 @@ constructor(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
logD("Launching import picker")
|
||||
T.d("Launching import picker")
|
||||
_playlistDecision.put(PlaylistDecision.Import(target))
|
||||
}
|
||||
}
|
||||
|
@ -207,7 +206,7 @@ constructor(
|
|||
*/
|
||||
fun exportPlaylist(playlist: Playlist, uri: Uri? = null, config: ExportConfig? = null) {
|
||||
if (uri != null && config != null) {
|
||||
logD("Exporting playlist to $uri")
|
||||
T.d("Exporting playlist to $uri")
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
if (externalPlaylistManager.export(playlist, uri, config)) {
|
||||
_playlistMessage.put(PlaylistMessage.ExportSuccess)
|
||||
|
@ -216,7 +215,7 @@ constructor(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
logD("Launching export dialog")
|
||||
T.d("Launching export dialog")
|
||||
_playlistDecision.put(PlaylistDecision.Export(playlist))
|
||||
}
|
||||
}
|
||||
|
@ -238,7 +237,7 @@ constructor(
|
|||
reason: PlaylistDecision.Rename.Reason = PlaylistDecision.Rename.Reason.ACTION
|
||||
) {
|
||||
if (name != null) {
|
||||
logD("Renaming $playlist to $name")
|
||||
T.d("Renaming $playlist to $name")
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
musicRepository.renamePlaylist(playlist, name)
|
||||
if (applySongs.isNotEmpty()) {
|
||||
|
@ -252,7 +251,7 @@ constructor(
|
|||
_playlistMessage.put(message)
|
||||
}
|
||||
} else {
|
||||
logD("Launching rename dialog for $playlist")
|
||||
T.d("Launching rename dialog for $playlist")
|
||||
_playlistDecision.put(PlaylistDecision.Rename(playlist, null, applySongs, reason))
|
||||
}
|
||||
}
|
||||
|
@ -267,13 +266,13 @@ constructor(
|
|||
*/
|
||||
fun deletePlaylist(playlist: Playlist, rude: Boolean = false) {
|
||||
if (rude) {
|
||||
logD("Deleting $playlist")
|
||||
T.d("Deleting $playlist")
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
musicRepository.deletePlaylist(playlist)
|
||||
_playlistMessage.put(PlaylistMessage.DeleteSuccess)
|
||||
}
|
||||
} else {
|
||||
logD("Launching deletion dialog for $playlist")
|
||||
T.d("Launching deletion dialog for $playlist")
|
||||
_playlistDecision.put(PlaylistDecision.Delete(playlist))
|
||||
}
|
||||
}
|
||||
|
@ -285,7 +284,7 @@ constructor(
|
|||
* @param playlist The [Playlist] to add to. If null, the user will be prompted for one.
|
||||
*/
|
||||
fun addToPlaylist(song: Song, playlist: Playlist? = null) {
|
||||
logD("Adding $song to playlist")
|
||||
T.d("Adding $song to playlist")
|
||||
addToPlaylist(listOf(song), playlist)
|
||||
}
|
||||
|
||||
|
@ -296,7 +295,7 @@ constructor(
|
|||
* @param playlist The [Playlist] to add to. If null, the user will be prompted for one.
|
||||
*/
|
||||
fun addToPlaylist(album: Album, playlist: Playlist? = null) {
|
||||
logD("Adding $album to playlist")
|
||||
T.d("Adding $album to playlist")
|
||||
addToPlaylist(listSettings.albumSongSort.songs(album.songs), playlist)
|
||||
}
|
||||
|
||||
|
@ -307,7 +306,7 @@ constructor(
|
|||
* @param playlist The [Playlist] to add to. If null, the user will be prompted for one.
|
||||
*/
|
||||
fun addToPlaylist(artist: Artist, playlist: Playlist? = null) {
|
||||
logD("Adding $artist to playlist")
|
||||
T.d("Adding $artist to playlist")
|
||||
addToPlaylist(listSettings.artistSongSort.songs(artist.songs), playlist)
|
||||
}
|
||||
|
||||
|
@ -318,7 +317,7 @@ constructor(
|
|||
* @param playlist The [Playlist] to add to. If null, the user will be prompted for one.
|
||||
*/
|
||||
fun addToPlaylist(genre: Genre, playlist: Playlist? = null) {
|
||||
logD("Adding $genre to playlist")
|
||||
T.d("Adding $genre to playlist")
|
||||
addToPlaylist(listSettings.genreSongSort.songs(genre.songs), playlist)
|
||||
}
|
||||
|
||||
|
@ -330,13 +329,13 @@ constructor(
|
|||
*/
|
||||
fun addToPlaylist(songs: List<Song>, playlist: Playlist? = null) {
|
||||
if (playlist != null) {
|
||||
logD("Adding ${songs.size} songs to $playlist")
|
||||
T.d("Adding ${songs.size} songs to $playlist")
|
||||
viewModelScope.launch(Dispatchers.IO) {
|
||||
musicRepository.addToPlaylist(songs, playlist)
|
||||
_playlistMessage.put(PlaylistMessage.AddSuccess)
|
||||
}
|
||||
} else {
|
||||
logD("Launching addition dialog for songs=${songs.size}")
|
||||
T.d("Launching addition dialog for songs=${songs.size}")
|
||||
_playlistDecision.put(PlaylistDecision.Add(songs))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,7 @@ package org.oxycblt.auxio.music.cache
|
|||
|
||||
import javax.inject.Inject
|
||||
import org.oxycblt.auxio.music.device.RawSong
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A repository allowing access to cached metadata obtained in prior music loading operations.
|
||||
|
@ -51,11 +50,11 @@ class CacheRepositoryImpl @Inject constructor(private val cachedSongsDao: Cached
|
|||
// Faster to load the whole database into memory than do a query on each
|
||||
// populate call.
|
||||
val songs = cachedSongsDao.readSongs()
|
||||
logD("Successfully read ${songs.size} songs from cache")
|
||||
T.d("Successfully read ${songs.size} songs from cache")
|
||||
CacheImpl(songs)
|
||||
} catch (e: Exception) {
|
||||
logE("Unable to load cache database.")
|
||||
logE(e.stackTraceToString())
|
||||
T.e("Unable to load cache database.")
|
||||
T.e(e.stackTraceToString())
|
||||
null
|
||||
}
|
||||
|
||||
|
@ -63,12 +62,12 @@ class CacheRepositoryImpl @Inject constructor(private val cachedSongsDao: Cached
|
|||
try {
|
||||
// Still write out whatever data was extracted.
|
||||
cachedSongsDao.nukeSongs()
|
||||
logD("Successfully deleted old cache")
|
||||
T.d("Successfully deleted old cache")
|
||||
cachedSongsDao.insertSongs(rawSongs.map(CachedSong::fromRaw))
|
||||
logD("Successfully wrote ${rawSongs.size} songs to cache")
|
||||
T.d("Successfully wrote ${rawSongs.size} songs to cache")
|
||||
} catch (e: Exception) {
|
||||
logE("Unable to save cache database.")
|
||||
logE(e.stackTraceToString())
|
||||
T.e("Unable to save cache database.")
|
||||
T.e(e.stackTraceToString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -36,8 +36,8 @@ import org.oxycblt.auxio.music.PlaylistDecision
|
|||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A dialog that allows the user to pick a specific playlist to add song(s) to.
|
||||
|
@ -105,7 +105,7 @@ class AddToPlaylistDialog :
|
|||
|
||||
private fun updatePendingSongs(songs: List<Song>?) {
|
||||
if (songs == null) {
|
||||
logD("No songs to show choices for, navigating away")
|
||||
T.d("No songs to show choices for, navigating away")
|
||||
findNavController().navigateUp()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,8 +32,8 @@ import org.oxycblt.auxio.music.MusicViewModel
|
|||
import org.oxycblt.auxio.music.Playlist
|
||||
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ViewBindingMaterialDialogFragment] that asks the user to confirm the deletion of a [Playlist].
|
||||
|
@ -76,7 +76,7 @@ class DeletePlaylistDialog : ViewBindingMaterialDialogFragment<DialogDeletePlayl
|
|||
|
||||
private fun updatePlaylistToDelete(playlist: Playlist?) {
|
||||
if (playlist == null) {
|
||||
logD("No playlist to delete, navigating away")
|
||||
T.d("No playlist to delete, navigating away")
|
||||
findNavController().navigateUp()
|
||||
return
|
||||
}
|
||||
|
|
|
@ -36,9 +36,8 @@ import org.oxycblt.auxio.music.external.ExportConfig
|
|||
import org.oxycblt.auxio.music.external.M3U
|
||||
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A dialog that allows the user to configure how a playlist will be exported to a file.
|
||||
|
@ -73,18 +72,18 @@ class ExportPlaylistDialog : ViewBindingMaterialDialogFragment<DialogPlaylistExp
|
|||
registerForActivityResult(ActivityResultContracts.CreateDocument(M3U.MIME_TYPE)) { uri
|
||||
->
|
||||
if (uri == null) {
|
||||
logW("No URI returned from file picker")
|
||||
T.w("No URI returned from file picker")
|
||||
return@registerForActivityResult
|
||||
}
|
||||
|
||||
val playlist = pickerModel.currentPlaylistToExport.value
|
||||
if (playlist == null) {
|
||||
logW("No playlist to export")
|
||||
T.w("No playlist to export")
|
||||
findNavController().navigateUp()
|
||||
return@registerForActivityResult
|
||||
}
|
||||
|
||||
logD("Received playlist URI $uri")
|
||||
T.d("Received playlist URI $uri")
|
||||
musicModel.exportPlaylist(playlist, uri, pickerModel.currentExportConfig.value)
|
||||
findNavController().navigateUp()
|
||||
}
|
||||
|
@ -129,7 +128,7 @@ class ExportPlaylistDialog : ViewBindingMaterialDialogFragment<DialogPlaylistExp
|
|||
|
||||
private fun updatePlaylistToExport(playlist: Playlist?) {
|
||||
if (playlist == null) {
|
||||
logD("No playlist to export, leaving")
|
||||
T.d("No playlist to export, leaving")
|
||||
findNavController().navigateUp()
|
||||
return
|
||||
}
|
||||
|
|
|
@ -34,8 +34,8 @@ import org.oxycblt.auxio.music.MusicViewModel
|
|||
import org.oxycblt.auxio.music.PlaylistDecision
|
||||
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A dialog allowing the name of a new playlist to be chosen before committing it to the database.
|
||||
|
@ -98,7 +98,7 @@ class NewPlaylistDialog : ViewBindingMaterialDialogFragment<DialogPlaylistNameBi
|
|||
|
||||
private fun updatePendingPlaylist(pendingNewPlaylist: PendingNewPlaylist?) {
|
||||
if (pendingNewPlaylist == null) {
|
||||
logD("No playlist to create, leaving")
|
||||
T.d("No playlist to create, leaving")
|
||||
findNavController().navigateUp()
|
||||
return
|
||||
}
|
||||
|
|
|
@ -33,9 +33,7 @@ import org.oxycblt.auxio.music.Playlist
|
|||
import org.oxycblt.auxio.music.PlaylistDecision
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.external.ExportConfig
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ViewModel] managing the state of the playlist picker dialogs.
|
||||
|
@ -101,7 +99,7 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
|
|||
pendingPlaylist.template,
|
||||
pendingPlaylist.reason)
|
||||
}
|
||||
logD("Updated pending playlist: ${_currentPendingNewPlaylist.value?.preferredName}")
|
||||
T.d("Updated pending playlist: ${_currentPendingNewPlaylist.value?.preferredName}")
|
||||
|
||||
_currentSongsToAdd.value =
|
||||
_currentSongsToAdd.value?.let { pendingSongs ->
|
||||
|
@ -110,7 +108,7 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
|
|||
.ifEmpty { null }
|
||||
.also { refreshChoicesWith = it }
|
||||
}
|
||||
logD("Updated songs to add: ${_currentSongsToAdd.value?.size} songs")
|
||||
T.d("Updated songs to add: ${_currentSongsToAdd.value?.size} songs")
|
||||
}
|
||||
|
||||
val chosenName = _chosenName.value
|
||||
|
@ -122,7 +120,7 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
|
|||
// Nothing to do.
|
||||
}
|
||||
}
|
||||
logD("Updated chosen name to $chosenName")
|
||||
T.d("Updated chosen name to $chosenName")
|
||||
refreshChoicesWith = refreshChoicesWith ?: _currentSongsToAdd.value
|
||||
|
||||
// TODO: Add music syncing for other playlist states here
|
||||
|
@ -131,7 +129,7 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
|
|||
_currentPlaylistToExport.value?.let { playlist ->
|
||||
musicRepository.userLibrary?.findPlaylist(playlist.uid)
|
||||
}
|
||||
logD("Updated playlist to export to ${_currentPlaylistToExport.value}")
|
||||
T.d("Updated playlist to export to ${_currentPlaylistToExport.value}")
|
||||
}
|
||||
|
||||
refreshChoicesWith?.let(::refreshPlaylistChoices)
|
||||
|
@ -154,7 +152,7 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
|
|||
template: String?,
|
||||
reason: PlaylistDecision.New.Reason
|
||||
) {
|
||||
logD("Opening ${songUids.size} songs to create a playlist from")
|
||||
T.d("Opening ${songUids.size} songs to create a playlist from")
|
||||
val userLibrary = musicRepository.userLibrary ?: return
|
||||
val songs =
|
||||
musicRepository.deviceLibrary
|
||||
|
@ -168,10 +166,10 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
|
|||
var possibleName: String
|
||||
do {
|
||||
possibleName = context.getString(R.string.fmt_def_playlist, i)
|
||||
logD("Trying $possibleName as a playlist name")
|
||||
T.d("Trying $possibleName as a playlist name")
|
||||
++i
|
||||
} while (userLibrary.playlists.any { it.name.resolve(context) == possibleName })
|
||||
logD("$possibleName is unique, using it as the playlist name")
|
||||
T.d("$possibleName is unique, using it as the playlist name")
|
||||
possibleName
|
||||
}
|
||||
|
||||
|
@ -179,7 +177,7 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
|
|||
if (possibleName != null && songs != null) {
|
||||
PendingNewPlaylist(possibleName, songs, template, reason)
|
||||
} else {
|
||||
logW("Given song UIDs to create were invalid")
|
||||
T.w("Given song UIDs to create were invalid")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
@ -195,7 +193,7 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
|
|||
template: String?,
|
||||
reason: PlaylistDecision.Rename.Reason
|
||||
) {
|
||||
logD("Opening playlist $playlistUid to rename")
|
||||
T.d("Opening playlist $playlistUid to rename")
|
||||
val playlist = musicRepository.userLibrary?.findPlaylist(playlistUid)
|
||||
val applySongs =
|
||||
musicRepository.deviceLibrary?.let { applySongUids.mapNotNull(it::findSong) }
|
||||
|
@ -204,7 +202,7 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
|
|||
if (playlist != null && applySongs != null) {
|
||||
PendingRenamePlaylist(playlist, applySongs, template, reason)
|
||||
} else {
|
||||
logW("Given playlist UID to rename was invalid")
|
||||
T.w("Given playlist UID to rename was invalid")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
@ -215,12 +213,12 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
|
|||
* @param playlistUid The [Music.UID] of the [Playlist] to export.
|
||||
*/
|
||||
fun setPlaylistToExport(playlistUid: Music.UID) {
|
||||
logD("Opening playlist $playlistUid to export")
|
||||
T.d("Opening playlist $playlistUid to export")
|
||||
// TODO: Add this guard to the rest of the methods here
|
||||
if (_currentPlaylistToExport.value?.uid == playlistUid) return
|
||||
_currentPlaylistToExport.value = musicRepository.userLibrary?.findPlaylist(playlistUid)
|
||||
if (_currentPlaylistToExport.value == null) {
|
||||
logW("Given playlist UID to export was invalid")
|
||||
T.w("Given playlist UID to export was invalid")
|
||||
} else {
|
||||
_currentExportConfig.value = DEFAULT_EXPORT_CONFIG
|
||||
}
|
||||
|
@ -232,7 +230,7 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
|
|||
* @param exportConfig The new [ExportConfig] to use.
|
||||
*/
|
||||
fun setExportConfig(exportConfig: ExportConfig) {
|
||||
logD("Setting export config to $exportConfig")
|
||||
T.d("Setting export config to $exportConfig")
|
||||
_currentExportConfig.value = exportConfig
|
||||
}
|
||||
|
||||
|
@ -242,10 +240,10 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
|
|||
* @param playlistUid The [Music.UID] of the [Playlist] to delete.
|
||||
*/
|
||||
fun setPlaylistToDelete(playlistUid: Music.UID) {
|
||||
logD("Opening playlist $playlistUid to delete")
|
||||
T.d("Opening playlist $playlistUid to delete")
|
||||
_currentPlaylistToDelete.value = musicRepository.userLibrary?.findPlaylist(playlistUid)
|
||||
if (_currentPlaylistToDelete.value == null) {
|
||||
logW("Given playlist UID to delete was invalid")
|
||||
T.w("Given playlist UID to delete was invalid")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -255,25 +253,25 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
|
|||
* @param name The new user-inputted name, or null if not present.
|
||||
*/
|
||||
fun updateChosenName(name: String?) {
|
||||
logD("Updating chosen name to $name")
|
||||
T.d("Updating chosen name to $name")
|
||||
_chosenName.value =
|
||||
when {
|
||||
name.isNullOrEmpty() -> {
|
||||
logE("Chosen name is empty")
|
||||
T.e("Chosen name is empty")
|
||||
ChosenName.Empty
|
||||
}
|
||||
name.isBlank() -> {
|
||||
logE("Chosen name is blank")
|
||||
T.e("Chosen name is blank")
|
||||
ChosenName.Blank
|
||||
}
|
||||
else -> {
|
||||
val trimmed = name.trim()
|
||||
val userLibrary = musicRepository.userLibrary
|
||||
if (userLibrary != null && userLibrary.findPlaylist(trimmed) == null) {
|
||||
logD("Chosen name is valid")
|
||||
T.d("Chosen name is valid")
|
||||
ChosenName.Valid(trimmed)
|
||||
} else {
|
||||
logD("Chosen name already exists in library")
|
||||
T.d("Chosen name already exists in library")
|
||||
ChosenName.AlreadyExists(trimmed)
|
||||
}
|
||||
}
|
||||
|
@ -286,19 +284,19 @@ class PlaylistPickerViewModel @Inject constructor(private val musicRepository: M
|
|||
* @param songUids The [Music.UID]s of songs to add to a playlist.
|
||||
*/
|
||||
fun setSongsToAdd(songUids: Array<Music.UID>) {
|
||||
logD("Opening ${songUids.size} songs to add to a playlist")
|
||||
T.d("Opening ${songUids.size} songs to add to a playlist")
|
||||
_currentSongsToAdd.value =
|
||||
musicRepository.deviceLibrary
|
||||
?.let { songUids.mapNotNull(it::findSong).ifEmpty { null } }
|
||||
?.also(::refreshPlaylistChoices)
|
||||
if (_currentSongsToAdd.value == null || songUids.size != _currentSongsToAdd.value?.size) {
|
||||
logW("Given song UIDs to add were (partially) invalid")
|
||||
T.w("Given song UIDs to add were (partially) invalid")
|
||||
}
|
||||
}
|
||||
|
||||
private fun refreshPlaylistChoices(songs: List<Song>) {
|
||||
val userLibrary = musicRepository.userLibrary ?: return
|
||||
logD("Refreshing playlist choices")
|
||||
T.d("Refreshing playlist choices")
|
||||
_playlistAddChoices.value =
|
||||
Sort(Sort.Mode.ByName, Sort.Direction.ASCENDING).playlists(userLibrary.playlists).map {
|
||||
val songSet = it.songs.toSet()
|
||||
|
|
|
@ -32,8 +32,8 @@ import org.oxycblt.auxio.databinding.DialogPlaylistNameBinding
|
|||
import org.oxycblt.auxio.music.MusicViewModel
|
||||
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A dialog allowing the name of a new playlist to be chosen before committing it to the database.
|
||||
|
@ -94,7 +94,7 @@ class RenamePlaylistDialog : ViewBindingMaterialDialogFragment<DialogPlaylistNam
|
|||
val default =
|
||||
pendingRenamePlaylist.template
|
||||
?: pendingRenamePlaylist.playlist.name.resolve(requireContext())
|
||||
logD("Name input is not initialized, setting to $default")
|
||||
T.d("Name input is not initialized, setting to $default")
|
||||
requireBinding().playlistName.setText(default)
|
||||
initializedField = true
|
||||
}
|
||||
|
|
|
@ -35,9 +35,9 @@ import org.oxycblt.auxio.music.fs.useQuery
|
|||
import org.oxycblt.auxio.music.info.Name
|
||||
import org.oxycblt.auxio.music.metadata.Separators
|
||||
import org.oxycblt.auxio.util.forEachWithTimeout
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.sendWithTimeout
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Organized music library information obtained from device storage.
|
||||
|
@ -147,7 +147,7 @@ class DeviceLibraryFactoryImpl @Inject constructor() : DeviceLibrary.Factory {
|
|||
// UID is sufficient for something like this, and also prevents collisions from
|
||||
// causing severe issues elsewhere.
|
||||
if (songGrouping.containsKey(song.uid)) {
|
||||
logW(
|
||||
T.w(
|
||||
"Duplicate song found: ${song.path} " +
|
||||
"collides with ${unlikelyToBeNull(songGrouping[song.uid]).path}")
|
||||
// We still want to say that we "processed" the song so that the user doesn't
|
||||
|
|
|
@ -26,7 +26,7 @@ import org.oxycblt.auxio.list.recycler.DialogRecyclerView
|
|||
import org.oxycblt.auxio.music.fs.Path
|
||||
import org.oxycblt.auxio.util.context
|
||||
import org.oxycblt.auxio.util.inflater
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* [RecyclerView.Adapter] that manages a list of [Path] music directory instances.
|
||||
|
@ -55,7 +55,7 @@ class DirectoryAdapter(private val listener: Listener) :
|
|||
*/
|
||||
fun add(path: Path) {
|
||||
if (_dirs.contains(path)) return
|
||||
logD("Adding $path")
|
||||
T.d("Adding $path")
|
||||
_dirs.add(path)
|
||||
notifyItemInserted(_dirs.lastIndex)
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ class DirectoryAdapter(private val listener: Listener) :
|
|||
* @param path The [Path] instances to add.
|
||||
*/
|
||||
fun addAll(path: List<Path>) {
|
||||
logD("Adding ${path.size} directories")
|
||||
T.d("Adding ${path.size} directories")
|
||||
val oldLastIndex = path.lastIndex
|
||||
_dirs.addAll(path)
|
||||
notifyItemRangeInserted(oldLastIndex, path.size)
|
||||
|
@ -78,7 +78,7 @@ class DirectoryAdapter(private val listener: Listener) :
|
|||
* @param path The [Path] to remove. Must exist in the list.
|
||||
*/
|
||||
fun remove(path: Path) {
|
||||
logD("Removing $path")
|
||||
T.d("Removing $path")
|
||||
val idx = _dirs.indexOf(path)
|
||||
_dirs.removeAt(idx)
|
||||
notifyItemRemoved(idx)
|
||||
|
|
|
@ -36,8 +36,8 @@ import org.oxycblt.auxio.music.MusicSettings
|
|||
import org.oxycblt.auxio.music.fs.DocumentPathFactory
|
||||
import org.oxycblt.auxio.music.fs.Path
|
||||
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.showToast
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Dialog that manages the music dirs setting.
|
||||
|
@ -62,7 +62,7 @@ class MusicDirsDialog :
|
|||
.setPositiveButton(R.string.lbl_save) { _, _ ->
|
||||
val newDirs = MusicDirectories(dirAdapter.dirs, isUiModeInclude(requireBinding()))
|
||||
if (musicSettings.musicDirs != newDirs) {
|
||||
logD("Committing changes")
|
||||
T.d("Committing changes")
|
||||
musicSettings.musicDirs = newDirs
|
||||
}
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ class MusicDirsDialog :
|
|||
binding.dirsAdd.apply {
|
||||
ViewCompat.setTooltipText(this, contentDescription)
|
||||
setOnClickListener {
|
||||
logD("Opening launcher")
|
||||
T.d("Opening launcher")
|
||||
val launcher =
|
||||
requireNotNull(openDocumentTreeLauncher) {
|
||||
"Document tree launcher was not available"
|
||||
|
@ -150,7 +150,7 @@ class MusicDirsDialog :
|
|||
private fun addDocumentTreeUriToDirs(uri: Uri?) {
|
||||
if (uri == null) {
|
||||
// A null URI means that the user left the file picker without picking a directory
|
||||
logD("No URI given (user closed the dialog)")
|
||||
T.d("No URI given (user closed the dialog)")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ import org.oxycblt.auxio.music.fs.Components
|
|||
import org.oxycblt.auxio.music.fs.DocumentPathFactory
|
||||
import org.oxycblt.auxio.music.fs.Path
|
||||
import org.oxycblt.auxio.music.fs.contentResolverSafe
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Generic playlist file importing abstraction.
|
||||
|
@ -108,7 +108,7 @@ constructor(
|
|||
return ImportedPlaylist(newName, imported.paths)
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logE("Failed to import playlist: $e")
|
||||
T.e("Failed to import playlist: $e")
|
||||
null
|
||||
}
|
||||
}
|
||||
|
@ -124,7 +124,7 @@ constructor(
|
|||
return try {
|
||||
val outputStream = context.contentResolverSafe.openOutputStream(uri)
|
||||
if (outputStream == null) {
|
||||
logE("Failed to export playlist: Could not open output stream")
|
||||
T.e("Failed to export playlist: Could not open output stream")
|
||||
return false
|
||||
}
|
||||
outputStream.use {
|
||||
|
@ -132,7 +132,7 @@ constructor(
|
|||
true
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logE("Failed to export playlist: $e")
|
||||
T.e("Failed to export playlist: $e")
|
||||
false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -33,8 +33,8 @@ import org.oxycblt.auxio.music.fs.Volume
|
|||
import org.oxycblt.auxio.music.fs.VolumeManager
|
||||
import org.oxycblt.auxio.music.metadata.correctWhitespace
|
||||
import org.oxycblt.auxio.music.resolveNames
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Minimal M3U file format implementation.
|
||||
|
@ -116,7 +116,7 @@ constructor(
|
|||
}
|
||||
|
||||
if (path == null) {
|
||||
logE("Expected a path, instead got an EOF")
|
||||
T.e("Expected a path, instead got an EOF")
|
||||
break@consumeFile
|
||||
}
|
||||
|
||||
|
|
|
@ -32,8 +32,8 @@ import org.oxycblt.auxio.music.dirs.MusicDirectories
|
|||
import org.oxycblt.auxio.music.info.Date
|
||||
import org.oxycblt.auxio.music.metadata.parseId3v2PositionField
|
||||
import org.oxycblt.auxio.music.metadata.transformPositionField
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.sendWithTimeout
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* The layer that loads music from the [MediaStore] database. This is an intermediate step in the
|
||||
|
@ -127,7 +127,7 @@ private class MediaStoreExtractorImpl(
|
|||
|
||||
// Filter out audio that is not music, if enabled.
|
||||
if (constraints.excludeNonMusic) {
|
||||
logD("Excluding non-music")
|
||||
T.d("Excluding non-music")
|
||||
uniSelector += " AND ${MediaStore.Audio.AudioColumns.IS_MUSIC}=1"
|
||||
}
|
||||
|
||||
|
@ -136,10 +136,10 @@ private class MediaStoreExtractorImpl(
|
|||
val pathSelector =
|
||||
mediaStorePathInterpreterFactory.createSelector(constraints.musicDirs.dirs)
|
||||
if (pathSelector != null) {
|
||||
logD("Must select for directories")
|
||||
T.d("Must select for directories")
|
||||
uniSelector += " AND "
|
||||
if (!constraints.musicDirs.shouldInclude) {
|
||||
logD("Excluding directories in selector")
|
||||
T.d("Excluding directories in selector")
|
||||
// Without a NOT, the query will be restricted to the specified paths, resulting
|
||||
// in the "Include" mode. With a NOT, the specified paths will not be included,
|
||||
// resulting in the "Exclude" mode.
|
||||
|
@ -151,7 +151,7 @@ private class MediaStoreExtractorImpl(
|
|||
}
|
||||
|
||||
// Now we can actually query MediaStore.
|
||||
logD(
|
||||
T.d(
|
||||
"Starting song query [proj=${projection.toList()}, selector=$uniSelector, args=$uniArgs]")
|
||||
val cursor =
|
||||
context.contentResolverSafe.safeQuery(
|
||||
|
@ -159,7 +159,7 @@ private class MediaStoreExtractorImpl(
|
|||
projection,
|
||||
uniSelector,
|
||||
uniArgs.toTypedArray())
|
||||
logD("Successfully queried for ${cursor.count} songs")
|
||||
T.d("Successfully queried for ${cursor.count} songs")
|
||||
|
||||
val genreNamesMap = mutableMapOf<Long, String>()
|
||||
|
||||
|
@ -194,8 +194,8 @@ private class MediaStoreExtractorImpl(
|
|||
}
|
||||
}
|
||||
|
||||
logD("Read ${genreNamesMap.values.distinct().size} genres from MediaStore")
|
||||
logD("Finished initialization in ${System.currentTimeMillis() - start}ms")
|
||||
T.d("Read ${genreNamesMap.values.distinct().size} genres from MediaStore")
|
||||
T.d("Finished initialization in ${System.currentTimeMillis() - start}ms")
|
||||
return QueryImpl(
|
||||
cursor,
|
||||
mediaStorePathInterpreterFactory.wrap(cursor),
|
||||
|
|
|
@ -21,7 +21,7 @@ package org.oxycblt.auxio.music.fs
|
|||
import android.database.Cursor
|
||||
import android.os.Build
|
||||
import android.provider.MediaStore
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Wrapper around a [Cursor] that interprets path information on a per-API/manufacturer basis.
|
||||
|
@ -112,7 +112,7 @@ private constructor(private val cursor: Cursor, volumeManager: VolumeManager) :
|
|||
}
|
||||
}
|
||||
|
||||
logE("Could not find volume for $data [tried: ${volumes.map { it.components }}]")
|
||||
T.e("Could not find volume for $data [tried: ${volumes.map { it.components }}]")
|
||||
|
||||
return null
|
||||
}
|
||||
|
@ -181,7 +181,7 @@ private constructor(private val cursor: Cursor, volumeManager: VolumeManager) :
|
|||
val displayName = cursor.getString(displayNameIndex)
|
||||
val volume = volumes.find { it.mediaStoreName == volumeName }
|
||||
if (volume == null) {
|
||||
logE(
|
||||
T.e(
|
||||
"Could not find volume for $volumeName:$relativePath/$displayName [tried: ${volumes.map { it.mediaStoreName }}]")
|
||||
return null
|
||||
}
|
||||
|
|
|
@ -24,8 +24,8 @@ import java.text.SimpleDateFormat
|
|||
import kotlin.math.max
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.util.inRangeOrNull
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import org.oxycblt.auxio.util.positiveOrNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* An ISO-8601/RFC 3339 Date.
|
||||
|
@ -64,7 +64,7 @@ class Date private constructor(private val tokens: List<Int>) : Comparable<Date>
|
|||
try {
|
||||
format.parse("$year-$month")
|
||||
} catch (e: ParseException) {
|
||||
logE("Unable to parse fine-grained date: $e")
|
||||
T.e("Unable to parse fine-grained date: $e")
|
||||
return null
|
||||
}
|
||||
|
||||
|
|
|
@ -25,9 +25,7 @@ import dagger.hilt.android.qualifiers.ApplicationContext
|
|||
import javax.inject.Inject
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.fs.MimeType
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* The properties of a [Song]'s file.
|
||||
|
@ -75,8 +73,8 @@ constructor(@ApplicationContext private val context: Context) : AudioProperties.
|
|||
// Can feasibly fail with invalid file formats. Note that this isn't considered
|
||||
// an error condition in the UI, as there is still plenty of other song information
|
||||
// that we can show.
|
||||
logW("Unable to extract song attributes.")
|
||||
logW(e.stackTraceToString())
|
||||
T.w("Unable to extract song attributes.")
|
||||
T.w(e.stackTraceToString())
|
||||
return AudioProperties(null, null, song.mimeType)
|
||||
}
|
||||
|
||||
|
@ -92,7 +90,7 @@ constructor(@ApplicationContext private val context: Context) : AudioProperties.
|
|||
// Convert bytes-per-second to kilobytes-per-second.
|
||||
format.getInteger(MediaFormat.KEY_BIT_RATE) / 1000
|
||||
} catch (e: NullPointerException) {
|
||||
logD("Unable to extract bit rate field")
|
||||
T.d("Unable to extract bit rate field")
|
||||
null
|
||||
}
|
||||
|
||||
|
@ -100,7 +98,7 @@ constructor(@ApplicationContext private val context: Context) : AudioProperties.
|
|||
try {
|
||||
format.getInteger(MediaFormat.KEY_SAMPLE_RATE)
|
||||
} catch (e: NullPointerException) {
|
||||
logE("Unable to extract sample rate field")
|
||||
T.e("Unable to extract sample rate field")
|
||||
null
|
||||
}
|
||||
|
||||
|
@ -110,13 +108,13 @@ constructor(@ApplicationContext private val context: Context) : AudioProperties.
|
|||
try {
|
||||
format.getString(MediaFormat.KEY_MIME)
|
||||
} catch (e: NullPointerException) {
|
||||
logE("Unable to extract mime type field")
|
||||
T.e("Unable to extract mime type field")
|
||||
null
|
||||
}
|
||||
|
||||
extractor.release()
|
||||
|
||||
logD("Finished extracting audio properties")
|
||||
T.d("Finished extracting audio properties")
|
||||
|
||||
return AudioProperties(
|
||||
bitrate,
|
||||
|
|
|
@ -30,7 +30,7 @@ import org.oxycblt.auxio.R
|
|||
import org.oxycblt.auxio.databinding.DialogSeparatorsBinding
|
||||
import org.oxycblt.auxio.music.MusicSettings
|
||||
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ViewBindingMaterialDialogFragment] that allows the user to configure the separator characters
|
||||
|
@ -76,7 +76,7 @@ class SeparatorsDialog : ViewBindingMaterialDialogFragment<DialogSeparatorsBindi
|
|||
Separators.SLASH -> binding.separatorSlash.isChecked = true
|
||||
Separators.PLUS -> binding.separatorPlus.isChecked = true
|
||||
Separators.AND -> binding.separatorAnd.isChecked = true
|
||||
else -> logW("Unexpected separator in settings data")
|
||||
else -> T.w("Unexpected separator in settings data")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -41,9 +41,8 @@ import kotlinx.coroutines.yield
|
|||
import org.oxycblt.auxio.music.device.RawSong
|
||||
import org.oxycblt.auxio.music.fs.toAudioUri
|
||||
import org.oxycblt.auxio.util.forEachWithTimeout
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import org.oxycblt.auxio.util.sendWithTimeout
|
||||
import timber.log.Timber as T
|
||||
|
||||
class TagExtractor
|
||||
@Inject
|
||||
|
@ -67,7 +66,7 @@ constructor(private val mediaSourceFactory: Factory, private val tagInterpreter:
|
|||
songsIn++
|
||||
}
|
||||
|
||||
logD("All incomplete songs exhausted, starting cleanup loop")
|
||||
T.d("All incomplete songs exhausted, starting cleanup loop")
|
||||
while (!worker.idle()) {
|
||||
val completeRawSong = worker.pull()
|
||||
if (completeRawSong != null) {
|
||||
|
@ -153,8 +152,8 @@ private class MetadataWorker(
|
|||
try {
|
||||
tagInterpreter.interpret(job.rawSong, job.future.get())
|
||||
} catch (e: Exception) {
|
||||
logE("Failed to extract metadata")
|
||||
logE(e.stackTraceToString())
|
||||
T.e("Failed to extract metadata")
|
||||
T.e(e.stackTraceToString())
|
||||
}
|
||||
jobs[i] = null
|
||||
return job.rawSong
|
||||
|
@ -177,7 +176,7 @@ private class MetadataWorker(
|
|||
mediaSource = currentMediaSource
|
||||
mediaSourceCaller = currentMediaSourceCaller
|
||||
} else {
|
||||
logD("new media source yahoo")
|
||||
T.d("new media source yahoo")
|
||||
mediaSource = mediaSourceFactory.createMediaSource(job.mediaItem)
|
||||
mediaSourceCaller = MediaSourceCaller(job)
|
||||
mediaSource.prepareSource(
|
||||
|
@ -194,8 +193,8 @@ private class MetadataWorker(
|
|||
mediaPeriod.maybeThrowPrepareError()
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logE("Failed to extract MediaSource")
|
||||
logE(e.stackTraceToString())
|
||||
T.e("Failed to extract MediaSource")
|
||||
T.e(e.stackTraceToString())
|
||||
job.mediaPeriod?.let(mediaSource::releasePeriod)
|
||||
mediaSource.releaseSource(mediaSourceCaller)
|
||||
job.future.setException(e)
|
||||
|
@ -248,7 +247,7 @@ private class MetadataWorker(
|
|||
// Ignore dynamic updates.
|
||||
return
|
||||
}
|
||||
logD("yay source created")
|
||||
T.d("yay source created")
|
||||
mediaPeriodCreated = true
|
||||
val mediaPeriod =
|
||||
source.createPeriod(
|
||||
|
|
|
@ -26,8 +26,8 @@ import kotlin.math.min
|
|||
import org.oxycblt.auxio.image.extractor.CoverExtractor
|
||||
import org.oxycblt.auxio.music.device.RawSong
|
||||
import org.oxycblt.auxio.music.info.Date
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.nonZeroOrNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* An processing abstraction over the [MetadataRetriever] and [TextTags] workflow that operates on
|
||||
|
@ -82,25 +82,25 @@ class TagInterpreterImpl @Inject constructor(private val coverExtractor: CoverEx
|
|||
// val gain =
|
||||
// (((header[16]).toInt() and 0xFF) or ((header[17].toInt() shl 8)))
|
||||
// .R128ToLUFS18()
|
||||
// logD("Obtained opus base gain: $gain dB")
|
||||
// T.d("Obtained opus base gain: $gain dB")
|
||||
// if (gain != 0f) {
|
||||
// logD("Applying opus base gain")
|
||||
// T.d("Applying opus base gain")
|
||||
// rawSong.replayGainTrackAdjustment =
|
||||
// (rawSong.replayGainTrackAdjustment ?: 0f) + gain
|
||||
// rawSong.replayGainAlbumAdjustment =
|
||||
// (rawSong.replayGainAlbumAdjustment ?: 0f) + gain
|
||||
// } else {
|
||||
// logD("Ignoring opus base gain")
|
||||
// T.d("Ignoring opus base gain")
|
||||
// }
|
||||
// }
|
||||
} else {
|
||||
logD("No metadata could be extracted for ${rawSong.name}")
|
||||
T.d("No metadata could be extracted for ${rawSong.name}")
|
||||
}
|
||||
}
|
||||
|
||||
private fun populateWithId3v2(rawSong: RawSong, textFrames: Map<String, List<String>>) {
|
||||
// Song
|
||||
logD(textFrames)
|
||||
T.d(textFrames)
|
||||
(textFrames["TXXX:musicbrainz release track id"]
|
||||
?: textFrames["TXXX:musicbrainz_releasetrackid"])
|
||||
?.let { rawSong.musicBrainzId = it.first() }
|
||||
|
|
|
@ -33,7 +33,7 @@ import org.oxycblt.auxio.music.MusicRepository
|
|||
import org.oxycblt.auxio.music.MusicSettings
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||
import org.oxycblt.auxio.util.getSystemServiceCompat
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
class Indexer
|
||||
private constructor(
|
||||
|
@ -117,7 +117,7 @@ private constructor(
|
|||
}
|
||||
} else if (musicSettings.shouldBeObserving) {
|
||||
// Not observing and done loading, exit foreground.
|
||||
logD("Exiting foreground")
|
||||
T.d("Exiting foreground")
|
||||
post(observingNotification)
|
||||
} else {
|
||||
post(null)
|
||||
|
@ -125,7 +125,7 @@ private constructor(
|
|||
}
|
||||
|
||||
override fun requestIndex(withCache: Boolean) {
|
||||
logD("Starting new indexing job (previous=${currentIndexJob?.hashCode()})")
|
||||
T.d("Starting new indexing job (previous=${currentIndexJob?.hashCode()})")
|
||||
// Cancel the previous music loading job.
|
||||
currentIndexJob?.cancel()
|
||||
// Start a new music loading job on a co-routine.
|
||||
|
@ -146,7 +146,7 @@ private constructor(
|
|||
|
||||
override fun onMusicChanges(changes: MusicRepository.Changes) {
|
||||
val deviceLibrary = musicRepository.deviceLibrary ?: return
|
||||
logD("Music changed, updating shared objects")
|
||||
T.d("Music changed, updating shared objects")
|
||||
// Wipe possibly-invalidated outdated covers
|
||||
imageLoader.memoryCache?.clear()
|
||||
// Clear invalid models from PlaybackStateManager. This is not connected
|
||||
|
@ -175,7 +175,7 @@ private constructor(
|
|||
// setting changed. In such a case, the state will still be updated when
|
||||
// the music loading process ends.
|
||||
if (musicRepository.indexingState == null) {
|
||||
logD("Not loading, updating idle session")
|
||||
T.d("Not loading, updating idle session")
|
||||
foregroundListener.updateForeground(ForegroundListener.Change.INDEXER)
|
||||
}
|
||||
}
|
||||
|
@ -184,7 +184,7 @@ private constructor(
|
|||
private fun PowerManager.WakeLock.acquireSafe() {
|
||||
// Avoid unnecessary acquire calls.
|
||||
if (!wakeLock.isHeld) {
|
||||
logD("Acquiring wake lock")
|
||||
T.d("Acquiring wake lock")
|
||||
// Time out after a minute, which is the average music loading time for a medium-sized
|
||||
// library. If this runs out, we will re-request the lock, and if music loading is
|
||||
// shorter than the timeout, it will be released early.
|
||||
|
@ -196,7 +196,7 @@ private constructor(
|
|||
private fun PowerManager.WakeLock.releaseSafe() {
|
||||
// Avoid unnecessary release calls.
|
||||
if (wakeLock.isHeld) {
|
||||
logD("Releasing wake lock")
|
||||
T.d("Releasing wake lock")
|
||||
release()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ import org.oxycblt.auxio.ForegroundServiceNotification
|
|||
import org.oxycblt.auxio.IntegerTable
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.music.IndexingProgress
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.newMainPendingIntent
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A dynamic [ForegroundServiceNotification] that shows the current music loading state.
|
||||
|
@ -66,7 +66,7 @@ class IndexingNotification(private val context: Context) :
|
|||
// Indeterminate state, use a vaguer description and in-determinate progress.
|
||||
// These events are not very frequent, and thus we don't need to safeguard
|
||||
// against rate limiting.
|
||||
logD("Updating state to $progress")
|
||||
T.d("Updating state to $progress")
|
||||
lastUpdateTime = -1
|
||||
setContentText(context.getString(R.string.lng_indexing))
|
||||
setProgress(0, 0, true)
|
||||
|
@ -81,7 +81,7 @@ class IndexingNotification(private val context: Context) :
|
|||
return false
|
||||
}
|
||||
lastUpdateTime = SystemClock.elapsedRealtime()
|
||||
logD("Updating state to $progress")
|
||||
T.d("Updating state to $progress")
|
||||
setContentText(
|
||||
context.getString(R.string.fmt_indexing, progress.current, progress.total))
|
||||
setProgress(progress.total, progress.current, false)
|
||||
|
|
|
@ -31,8 +31,7 @@ import kotlinx.coroutines.launch
|
|||
import org.oxycblt.auxio.ForegroundListener
|
||||
import org.oxycblt.auxio.ForegroundServiceNotification
|
||||
import org.oxycblt.auxio.music.MusicRepository
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import timber.log.Timber as T
|
||||
|
||||
class MusicServiceFragment
|
||||
@Inject
|
||||
|
@ -124,11 +123,11 @@ constructor(
|
|||
try {
|
||||
val result = body()
|
||||
if (result == null) {
|
||||
logW("Result is null")
|
||||
T.w("Result is null")
|
||||
}
|
||||
sendResult(result)
|
||||
} catch (e: Exception) {
|
||||
logD("Error while dispatching: $e")
|
||||
T.d("Error while dispatching: $e")
|
||||
sendResult(null)
|
||||
}
|
||||
}
|
||||
|
@ -139,11 +138,11 @@ constructor(
|
|||
try {
|
||||
val result = body()
|
||||
if (result == null) {
|
||||
logW("Result is null")
|
||||
T.w("Result is null")
|
||||
}
|
||||
sendResult(result)
|
||||
} catch (e: Exception) {
|
||||
logD("Error while dispatching: $e")
|
||||
T.d("Error while dispatching: $e")
|
||||
sendResult(null)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import javax.inject.Inject
|
|||
import org.oxycblt.auxio.music.MusicRepository
|
||||
import org.oxycblt.auxio.music.MusicSettings
|
||||
import org.oxycblt.auxio.music.fs.contentResolverSafe
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ContentObserver] that observes the [MediaStore] music database for changes, a behavior known
|
||||
|
@ -68,7 +68,7 @@ constructor(
|
|||
// Check here if we should even start a reindex. This is much less bug-prone than
|
||||
// registering and de-registering this component as this setting changes.
|
||||
if (musicSettings.shouldBeObserving) {
|
||||
logD("MediaStore changed, starting re-index")
|
||||
T.d("MediaStore changed, starting re-index")
|
||||
musicRepository.requestIndex(true)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,7 @@ import org.oxycblt.auxio.music.Playlist
|
|||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.device.DeviceLibrary
|
||||
import org.oxycblt.auxio.music.info.Name
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Organized library information controlled by the user.
|
||||
|
@ -144,10 +143,10 @@ class UserLibraryFactoryImpl @Inject constructor(private val playlistDao: Playli
|
|||
override suspend fun query() =
|
||||
try {
|
||||
val rawPlaylists = playlistDao.readRawPlaylists()
|
||||
logD("Successfully read ${rawPlaylists.size} playlists")
|
||||
T.d("Successfully read ${rawPlaylists.size} playlists")
|
||||
rawPlaylists
|
||||
} catch (e: Exception) {
|
||||
logE("Unable to read playlists: $e")
|
||||
T.e("Unable to read playlists: $e")
|
||||
listOf()
|
||||
}
|
||||
|
||||
|
@ -193,11 +192,11 @@ private class UserLibraryImpl(
|
|||
|
||||
return try {
|
||||
playlistDao.insertPlaylist(rawPlaylist)
|
||||
logD("Successfully created playlist $name with ${songs.size} songs")
|
||||
T.d("Successfully created playlist $name with ${songs.size} songs")
|
||||
playlistImpl
|
||||
} catch (e: Exception) {
|
||||
logE("Unable to create playlist $name with ${songs.size} songs")
|
||||
logE(e.stackTraceToString())
|
||||
T.e("Unable to create playlist $name with ${songs.size} songs")
|
||||
T.e(e.stackTraceToString())
|
||||
synchronized(this) { playlistMap.remove(playlistImpl.uid) }
|
||||
null
|
||||
}
|
||||
|
@ -212,11 +211,11 @@ private class UserLibraryImpl(
|
|||
|
||||
return try {
|
||||
playlistDao.replacePlaylistInfo(PlaylistInfo(playlist.uid, name))
|
||||
logD("Successfully renamed $playlist to $name")
|
||||
T.d("Successfully renamed $playlist to $name")
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
logE("Unable to rename $playlist to $name: $e")
|
||||
logE(e.stackTraceToString())
|
||||
T.e("Unable to rename $playlist to $name: $e")
|
||||
T.e(e.stackTraceToString())
|
||||
synchronized(this) { playlistMap[playlistImpl.uid] = playlistImpl }
|
||||
false
|
||||
}
|
||||
|
@ -231,11 +230,11 @@ private class UserLibraryImpl(
|
|||
|
||||
return try {
|
||||
playlistDao.deletePlaylist(playlist.uid)
|
||||
logD("Successfully deleted $playlist")
|
||||
T.d("Successfully deleted $playlist")
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
logE("Unable to delete $playlist: $e")
|
||||
logE(e.stackTraceToString())
|
||||
T.e("Unable to delete $playlist: $e")
|
||||
T.e(e.stackTraceToString())
|
||||
synchronized(this) { playlistMap[playlistImpl.uid] = playlistImpl }
|
||||
false
|
||||
}
|
||||
|
@ -250,11 +249,11 @@ private class UserLibraryImpl(
|
|||
|
||||
return try {
|
||||
playlistDao.insertPlaylistSongs(playlist.uid, songs.map { PlaylistSong(it.uid) })
|
||||
logD("Successfully added ${songs.size} songs to $playlist")
|
||||
T.d("Successfully added ${songs.size} songs to $playlist")
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
logE("Unable to add ${songs.size} songs to $playlist: $e")
|
||||
logE(e.stackTraceToString())
|
||||
T.e("Unable to add ${songs.size} songs to $playlist: $e")
|
||||
T.e(e.stackTraceToString())
|
||||
synchronized(this) { playlistMap[playlistImpl.uid] = playlistImpl }
|
||||
false
|
||||
}
|
||||
|
@ -269,11 +268,11 @@ private class UserLibraryImpl(
|
|||
|
||||
return try {
|
||||
playlistDao.replacePlaylistSongs(playlist.uid, songs.map { PlaylistSong(it.uid) })
|
||||
logD("Successfully rewrote $playlist with ${songs.size} songs")
|
||||
T.d("Successfully rewrote $playlist with ${songs.size} songs")
|
||||
true
|
||||
} catch (e: Exception) {
|
||||
logE("Unable to rewrite $playlist with ${songs.size} songs: $e")
|
||||
logE(e.stackTraceToString())
|
||||
T.e("Unable to rewrite $playlist with ${songs.size} songs: $e")
|
||||
T.e(e.stackTraceToString())
|
||||
synchronized(this) { playlistMap[playlistImpl.uid] = playlistImpl }
|
||||
false
|
||||
}
|
||||
|
|
|
@ -33,7 +33,7 @@ import org.oxycblt.auxio.ui.ViewBindingFragment
|
|||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.getAttrColorCompat
|
||||
import org.oxycblt.auxio.util.getColorCompat
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ViewBindingFragment] that shows the current playback state in a compact manner.
|
||||
|
@ -128,7 +128,7 @@ class PlaybackBarFragment : ViewBindingFragment<FragmentPlaybackBarBinding>() {
|
|||
val binding = requireBinding()
|
||||
when (actionMode) {
|
||||
ActionMode.NEXT -> {
|
||||
logD("Using skip next action")
|
||||
T.d("Using skip next action")
|
||||
binding.playbackSecondaryAction.apply {
|
||||
if (tag != actionMode) {
|
||||
setIconResource(R.drawable.ic_skip_next_24)
|
||||
|
@ -140,7 +140,7 @@ class PlaybackBarFragment : ViewBindingFragment<FragmentPlaybackBarBinding>() {
|
|||
}
|
||||
}
|
||||
ActionMode.REPEAT -> {
|
||||
logD("Using repeat mode action")
|
||||
T.d("Using repeat mode action")
|
||||
binding.playbackSecondaryAction.apply {
|
||||
if (tag != actionMode) {
|
||||
contentDescription = getString(R.string.desc_change_repeat)
|
||||
|
@ -153,7 +153,7 @@ class PlaybackBarFragment : ViewBindingFragment<FragmentPlaybackBarBinding>() {
|
|||
}
|
||||
}
|
||||
ActionMode.SHUFFLE -> {
|
||||
logD("Using shuffle action")
|
||||
T.d("Using shuffle action")
|
||||
binding.playbackSecondaryAction.apply {
|
||||
if (tag != actionMode) {
|
||||
setIconResource(R.drawable.sel_shuffle_state_24)
|
||||
|
|
|
@ -43,9 +43,9 @@ import org.oxycblt.auxio.playback.ui.StyledSeekBar
|
|||
import org.oxycblt.auxio.playback.ui.SwipeCoverView
|
||||
import org.oxycblt.auxio.ui.ViewBindingFragment
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.showToast
|
||||
import org.oxycblt.auxio.util.systemBarInsetsCompat
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ViewBindingFragment] more information about the currently playing song, alongside all
|
||||
|
@ -136,7 +136,7 @@ class PlaybackPanelFragment :
|
|||
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
logD(requireBinding().playbackCover.width)
|
||||
T.d(requireBinding().playbackCover.width)
|
||||
playbackModel.song.value?.let { requireBinding().playbackCover.bind(it) }
|
||||
requireBinding().root.viewTreeObserver.addOnGlobalLayoutListener(this)
|
||||
}
|
||||
|
@ -180,7 +180,7 @@ class PlaybackPanelFragment :
|
|||
override fun onMenuItemClick(item: MenuItem): Boolean {
|
||||
if (item.itemId == R.id.action_open_equalizer) {
|
||||
// Launch the system equalizer app, if possible.
|
||||
logD("Launching equalizer")
|
||||
T.d("Launching equalizer")
|
||||
val equalizerIntent =
|
||||
Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL)
|
||||
// Provide audio session ID so the equalizer can show options for this app
|
||||
|
@ -221,7 +221,7 @@ class PlaybackPanelFragment :
|
|||
|
||||
val binding = requireBinding()
|
||||
val context = requireContext()
|
||||
logD("Updating song display: $song")
|
||||
T.d("Updating song display: $song")
|
||||
binding.playbackCover.bind(song)
|
||||
binding.playbackSong.text = song.name.resolve(context)
|
||||
binding.playbackArtist.text = song.artists.resolveNames(context)
|
||||
|
|
|
@ -27,7 +27,7 @@ import org.oxycblt.auxio.R
|
|||
import org.oxycblt.auxio.playback.replaygain.ReplayGainMode
|
||||
import org.oxycblt.auxio.playback.replaygain.ReplayGainPreAmp
|
||||
import org.oxycblt.auxio.settings.Settings
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* User configuration specific to the playback system.
|
||||
|
@ -146,7 +146,7 @@ class PlaybackSettingsImpl @Inject constructor(@ApplicationContext context: Cont
|
|||
}
|
||||
|
||||
if (sharedPreferences.contains(OLD_KEY_LIB_MUSIC_PLAYBACK_MODE)) {
|
||||
logD("Migrating $OLD_KEY_LIB_MUSIC_PLAYBACK_MODE")
|
||||
T.d("Migrating $OLD_KEY_LIB_MUSIC_PLAYBACK_MODE")
|
||||
|
||||
val mode =
|
||||
sharedPreferences
|
||||
|
@ -162,7 +162,7 @@ class PlaybackSettingsImpl @Inject constructor(@ApplicationContext context: Cont
|
|||
}
|
||||
|
||||
if (sharedPreferences.contains(OLD_KEY_DETAIL_MUSIC_PLAYBACK_MODE)) {
|
||||
logD("Migrating $OLD_KEY_DETAIL_MUSIC_PLAYBACK_MODE")
|
||||
T.d("Migrating $OLD_KEY_DETAIL_MUSIC_PLAYBACK_MODE")
|
||||
|
||||
val mode =
|
||||
sharedPreferences
|
||||
|
@ -183,19 +183,19 @@ class PlaybackSettingsImpl @Inject constructor(@ApplicationContext context: Cont
|
|||
getString(R.string.set_key_replay_gain),
|
||||
getString(R.string.set_key_pre_amp_with),
|
||||
getString(R.string.set_key_pre_amp_without) -> {
|
||||
logD("Dispatching ReplayGain setting change")
|
||||
T.d("Dispatching ReplayGain setting change")
|
||||
listener.onReplayGainSettingsChanged()
|
||||
}
|
||||
getString(R.string.set_key_notif_action) -> {
|
||||
logD("Dispatching notification setting change")
|
||||
T.d("Dispatching notification setting change")
|
||||
listener.onNotificationActionChanged()
|
||||
}
|
||||
getString(R.string.set_key_bar_action) -> {
|
||||
logD("Dispatching bar action change")
|
||||
T.d("Dispatching bar action change")
|
||||
listener.onBarActionChanged()
|
||||
}
|
||||
getString(R.string.set_key_repeat_pause) -> {
|
||||
logD("Dispatching pause on repeat change")
|
||||
T.d("Dispatching pause on repeat change")
|
||||
listener.onPauseOnRepeatChanged()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,7 +43,7 @@ import org.oxycblt.auxio.playback.state.RepeatMode
|
|||
import org.oxycblt.auxio.playback.state.ShuffleMode
|
||||
import org.oxycblt.auxio.util.Event
|
||||
import org.oxycblt.auxio.util.MutableEvent
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* An [ViewModel] that provides a safe UI frontend for the current playback state.
|
||||
|
@ -129,20 +129,20 @@ constructor(
|
|||
}
|
||||
|
||||
override fun onIndexMoved(index: Int) {
|
||||
logD("Index moved, updating current song")
|
||||
T.d("Index moved, updating current song")
|
||||
_song.value = playbackManager.currentSong
|
||||
}
|
||||
|
||||
override fun onQueueChanged(queue: List<Song>, index: Int, change: QueueChange) {
|
||||
// Other types of queue changes preserve the current song.
|
||||
if (change.type == QueueChange.Type.SONG) {
|
||||
logD("Queue changed, updating current song")
|
||||
T.d("Queue changed, updating current song")
|
||||
_song.value = playbackManager.currentSong
|
||||
}
|
||||
}
|
||||
|
||||
override fun onQueueReordered(queue: List<Song>, index: Int, isShuffled: Boolean) {
|
||||
logD("Queue completely changed, updating current song")
|
||||
T.d("Queue completely changed, updating current song")
|
||||
_isShuffled.value = isShuffled
|
||||
}
|
||||
|
||||
|
@ -152,14 +152,14 @@ constructor(
|
|||
index: Int,
|
||||
isShuffled: Boolean
|
||||
) {
|
||||
logD("New playback started, updating playback information")
|
||||
T.d("New playback started, updating playback information")
|
||||
_song.value = playbackManager.currentSong
|
||||
_parent.value = parent
|
||||
_isShuffled.value = isShuffled
|
||||
}
|
||||
|
||||
override fun onProgressionChanged(progression: Progression) {
|
||||
logD("Player state changed, starting new position polling")
|
||||
T.d("Player state changed, starting new position polling")
|
||||
_isPlaying.value = progression.isPlaying
|
||||
// Still need to update the position now due to co-routine launch delays
|
||||
_positionDs.value = progression.calculateElapsedPositionMs().msToDs()
|
||||
|
@ -187,7 +187,7 @@ constructor(
|
|||
// --- PLAYING FUNCTIONS ---
|
||||
|
||||
fun play(song: Song, with: PlaySong) {
|
||||
logD("Playing $song with $with")
|
||||
T.d("Playing $song with $with")
|
||||
playWithImpl(song, with, ShuffleMode.IMPLICIT)
|
||||
}
|
||||
|
||||
|
@ -201,7 +201,7 @@ constructor(
|
|||
|
||||
/** Shuffle all songs in the music library. */
|
||||
fun shuffleAll() {
|
||||
logD("Shuffling all songs")
|
||||
T.d("Shuffling all songs")
|
||||
playFromAllImpl(null, ShuffleMode.ON)
|
||||
}
|
||||
|
||||
|
@ -257,7 +257,7 @@ constructor(
|
|||
}
|
||||
|
||||
private fun playFromAlbumImpl(song: Song, shuffle: ShuffleMode) {
|
||||
logD("Playing $song from album")
|
||||
T.d("Playing $song from album")
|
||||
playImpl(commandFactory.songFromAlbum(song, shuffle))
|
||||
}
|
||||
|
||||
|
@ -267,7 +267,7 @@ constructor(
|
|||
playbackManager.play(params)
|
||||
return
|
||||
}
|
||||
logD(
|
||||
T.d(
|
||||
"Cannot use given artist parameter for $song [$artist from ${song.artists}], showing choice dialog")
|
||||
startPlaybackDecision(PlaybackDecision.PlayFromArtist(song))
|
||||
}
|
||||
|
@ -278,20 +278,20 @@ constructor(
|
|||
playbackManager.play(params)
|
||||
return
|
||||
}
|
||||
logD(
|
||||
T.d(
|
||||
"Cannot use given genre parameter for $song [$genre from ${song.genres}], showing choice dialog")
|
||||
startPlaybackDecision(PlaybackDecision.PlayFromArtist(song))
|
||||
}
|
||||
|
||||
private fun playFromPlaylistImpl(song: Song, playlist: Playlist, shuffle: ShuffleMode) {
|
||||
logD("Playing $song from $playlist")
|
||||
T.d("Playing $song from $playlist")
|
||||
playImpl(commandFactory.songFromPlaylist(song, playlist, shuffle))
|
||||
}
|
||||
|
||||
private fun startPlaybackDecision(decision: PlaybackDecision) {
|
||||
val existing = _playbackDecision.flow.value
|
||||
if (existing != null) {
|
||||
logD("Already handling decision $existing, ignoring $decision")
|
||||
T.d("Already handling decision $existing, ignoring $decision")
|
||||
return
|
||||
}
|
||||
_playbackDecision.put(decision)
|
||||
|
@ -303,7 +303,7 @@ constructor(
|
|||
* @param album The [Album] to play.
|
||||
*/
|
||||
fun play(album: Album) {
|
||||
logD("Playing $album")
|
||||
T.d("Playing $album")
|
||||
playImpl(commandFactory.album(album, ShuffleMode.OFF))
|
||||
}
|
||||
|
||||
|
@ -313,7 +313,7 @@ constructor(
|
|||
* @param album The [Album] to shuffle.
|
||||
*/
|
||||
fun shuffle(album: Album) {
|
||||
logD("Shuffling $album")
|
||||
T.d("Shuffling $album")
|
||||
playImpl(commandFactory.album(album, ShuffleMode.ON))
|
||||
}
|
||||
|
||||
|
@ -323,7 +323,7 @@ constructor(
|
|||
* @param artist The [Artist] to play.
|
||||
*/
|
||||
fun play(artist: Artist) {
|
||||
logD("Playing $artist")
|
||||
T.d("Playing $artist")
|
||||
playImpl(commandFactory.artist(artist, ShuffleMode.OFF))
|
||||
}
|
||||
|
||||
|
@ -333,7 +333,7 @@ constructor(
|
|||
* @param artist The [Artist] to shuffle.
|
||||
*/
|
||||
fun shuffle(artist: Artist) {
|
||||
logD("Shuffling $artist")
|
||||
T.d("Shuffling $artist")
|
||||
playImpl(commandFactory.artist(artist, ShuffleMode.ON))
|
||||
}
|
||||
|
||||
|
@ -343,7 +343,7 @@ constructor(
|
|||
* @param genre The [Genre] to play.
|
||||
*/
|
||||
fun play(genre: Genre) {
|
||||
logD("Playing $genre")
|
||||
T.d("Playing $genre")
|
||||
playImpl(commandFactory.genre(genre, ShuffleMode.OFF))
|
||||
}
|
||||
|
||||
|
@ -353,7 +353,7 @@ constructor(
|
|||
* @param genre The [Genre] to shuffle.
|
||||
*/
|
||||
fun shuffle(genre: Genre) {
|
||||
logD("Shuffling $genre")
|
||||
T.d("Shuffling $genre")
|
||||
playImpl(commandFactory.genre(genre, ShuffleMode.ON))
|
||||
}
|
||||
|
||||
|
@ -363,7 +363,7 @@ constructor(
|
|||
* @param playlist The [Playlist] to play.
|
||||
*/
|
||||
fun play(playlist: Playlist) {
|
||||
logD("Playing $playlist")
|
||||
T.d("Playing $playlist")
|
||||
playImpl(commandFactory.playlist(playlist, ShuffleMode.OFF))
|
||||
}
|
||||
|
||||
|
@ -373,7 +373,7 @@ constructor(
|
|||
* @param playlist The [Playlist] to shuffle.
|
||||
*/
|
||||
fun shuffle(playlist: Playlist) {
|
||||
logD("Shuffling $playlist")
|
||||
T.d("Shuffling $playlist")
|
||||
playImpl(commandFactory.playlist(playlist, ShuffleMode.ON))
|
||||
}
|
||||
|
||||
|
@ -383,7 +383,7 @@ constructor(
|
|||
* @param songs The [Song]s to play.
|
||||
*/
|
||||
fun play(songs: List<Song>) {
|
||||
logD("Playing ${songs.size} songs")
|
||||
T.d("Playing ${songs.size} songs")
|
||||
playImpl(commandFactory.songs(songs, ShuffleMode.OFF))
|
||||
}
|
||||
|
||||
|
@ -393,7 +393,7 @@ constructor(
|
|||
* @param songs The [Song]s to shuffle.
|
||||
*/
|
||||
fun shuffle(songs: List<Song>) {
|
||||
logD("Shuffling ${songs.size} songs")
|
||||
T.d("Shuffling ${songs.size} songs")
|
||||
playImpl(commandFactory.songs(songs, ShuffleMode.ON))
|
||||
}
|
||||
|
||||
|
@ -408,7 +408,7 @@ constructor(
|
|||
* @param action The [DeferredPlayback] to perform eventually.
|
||||
*/
|
||||
fun playDeferred(action: DeferredPlayback) {
|
||||
logD("Starting action $action")
|
||||
T.d("Starting action $action")
|
||||
playbackManager.playDeferred(action)
|
||||
}
|
||||
|
||||
|
@ -420,7 +420,7 @@ constructor(
|
|||
* @param positionDs The position to seek to, in deci-seconds (1/10th of a second).
|
||||
*/
|
||||
fun seekTo(positionDs: Long) {
|
||||
logD("Seeking to ${positionDs}ds")
|
||||
T.d("Seeking to ${positionDs}ds")
|
||||
playbackManager.seekTo(positionDs.dsToMs())
|
||||
}
|
||||
|
||||
|
@ -428,13 +428,13 @@ constructor(
|
|||
|
||||
/** Skip to the next [Song]. */
|
||||
fun next() {
|
||||
logD("Skipping to next song")
|
||||
T.d("Skipping to next song")
|
||||
playbackManager.next()
|
||||
}
|
||||
|
||||
/** Skip to the previous [Song]. */
|
||||
fun prev() {
|
||||
logD("Skipping to previous song")
|
||||
T.d("Skipping to previous song")
|
||||
playbackManager.prev()
|
||||
}
|
||||
|
||||
|
@ -444,7 +444,7 @@ constructor(
|
|||
* @param song The [Song] to add.
|
||||
*/
|
||||
fun playNext(song: Song) {
|
||||
logD("Playing $song next")
|
||||
T.d("Playing $song next")
|
||||
playbackManager.playNext(song)
|
||||
}
|
||||
|
||||
|
@ -454,7 +454,7 @@ constructor(
|
|||
* @param album The [Album] to add.
|
||||
*/
|
||||
fun playNext(album: Album) {
|
||||
logD("Playing $album next")
|
||||
T.d("Playing $album next")
|
||||
playbackManager.playNext(listSettings.albumSongSort.songs(album.songs))
|
||||
}
|
||||
|
||||
|
@ -464,7 +464,7 @@ constructor(
|
|||
* @param artist The [Artist] to add.
|
||||
*/
|
||||
fun playNext(artist: Artist) {
|
||||
logD("Playing $artist next")
|
||||
T.d("Playing $artist next")
|
||||
playbackManager.playNext(listSettings.artistSongSort.songs(artist.songs))
|
||||
}
|
||||
|
||||
|
@ -474,7 +474,7 @@ constructor(
|
|||
* @param genre The [Genre] to add.
|
||||
*/
|
||||
fun playNext(genre: Genre) {
|
||||
logD("Playing $genre next")
|
||||
T.d("Playing $genre next")
|
||||
playbackManager.playNext(listSettings.genreSongSort.songs(genre.songs))
|
||||
}
|
||||
|
||||
|
@ -484,7 +484,7 @@ constructor(
|
|||
* @param playlist The [Playlist] to add.
|
||||
*/
|
||||
fun playNext(playlist: Playlist) {
|
||||
logD("Playing $playlist next")
|
||||
T.d("Playing $playlist next")
|
||||
playbackManager.playNext(playlist.songs)
|
||||
}
|
||||
|
||||
|
@ -494,7 +494,7 @@ constructor(
|
|||
* @param songs The [Song]s to add.
|
||||
*/
|
||||
fun playNext(songs: List<Song>) {
|
||||
logD("Playing ${songs.size} songs next")
|
||||
T.d("Playing ${songs.size} songs next")
|
||||
playbackManager.playNext(songs)
|
||||
}
|
||||
|
||||
|
@ -504,7 +504,7 @@ constructor(
|
|||
* @param song The [Song] to add.
|
||||
*/
|
||||
fun addToQueue(song: Song) {
|
||||
logD("Adding $song to queue")
|
||||
T.d("Adding $song to queue")
|
||||
playbackManager.addToQueue(song)
|
||||
}
|
||||
|
||||
|
@ -514,7 +514,7 @@ constructor(
|
|||
* @param album The [Album] to add.
|
||||
*/
|
||||
fun addToQueue(album: Album) {
|
||||
logD("Adding $album to queue")
|
||||
T.d("Adding $album to queue")
|
||||
playbackManager.addToQueue(listSettings.albumSongSort.songs(album.songs))
|
||||
}
|
||||
|
||||
|
@ -524,7 +524,7 @@ constructor(
|
|||
* @param artist The [Artist] to add.
|
||||
*/
|
||||
fun addToQueue(artist: Artist) {
|
||||
logD("Adding $artist to queue")
|
||||
T.d("Adding $artist to queue")
|
||||
playbackManager.addToQueue(listSettings.artistSongSort.songs(artist.songs))
|
||||
}
|
||||
|
||||
|
@ -534,7 +534,7 @@ constructor(
|
|||
* @param genre The [Genre] to add.
|
||||
*/
|
||||
fun addToQueue(genre: Genre) {
|
||||
logD("Adding $genre to queue")
|
||||
T.d("Adding $genre to queue")
|
||||
playbackManager.addToQueue(listSettings.genreSongSort.songs(genre.songs))
|
||||
}
|
||||
|
||||
|
@ -544,7 +544,7 @@ constructor(
|
|||
* @param playlist The [Playlist] to add.
|
||||
*/
|
||||
fun addToQueue(playlist: Playlist) {
|
||||
logD("Adding $playlist to queue")
|
||||
T.d("Adding $playlist to queue")
|
||||
playbackManager.addToQueue(playlist.songs)
|
||||
}
|
||||
|
||||
|
@ -554,7 +554,7 @@ constructor(
|
|||
* @param songs The [Song]s to add.
|
||||
*/
|
||||
fun addToQueue(songs: List<Song>) {
|
||||
logD("Adding ${songs.size} songs to queue")
|
||||
T.d("Adding ${songs.size} songs to queue")
|
||||
playbackManager.addToQueue(songs)
|
||||
}
|
||||
|
||||
|
@ -562,13 +562,13 @@ constructor(
|
|||
|
||||
/** Toggle [isPlaying] (i.e from playing to paused) */
|
||||
fun togglePlaying() {
|
||||
logD("Toggling playing state")
|
||||
T.d("Toggling playing state")
|
||||
playbackManager.playing(!playbackManager.progression.isPlaying)
|
||||
}
|
||||
|
||||
/** Toggle [isShuffled] (ex. from on to off) */
|
||||
fun toggleShuffled() {
|
||||
logD("Toggling shuffled state")
|
||||
T.d("Toggling shuffled state")
|
||||
playbackManager.shuffled(!playbackManager.isShuffled)
|
||||
}
|
||||
|
||||
|
@ -578,7 +578,7 @@ constructor(
|
|||
* @see RepeatMode.increment
|
||||
*/
|
||||
fun toggleRepeatMode() {
|
||||
logD("Toggling repeat mode")
|
||||
T.d("Toggling repeat mode")
|
||||
playbackManager.repeatMode(playbackManager.repeatMode.increment())
|
||||
}
|
||||
|
||||
|
@ -599,7 +599,7 @@ constructor(
|
|||
private fun openImpl(panel: OpenPanel) {
|
||||
val existing = openPanel.flow.value
|
||||
if (existing != null) {
|
||||
logD("Already opening $existing, ignoring opening $panel")
|
||||
T.d("Already opening $existing, ignoring opening $panel")
|
||||
return
|
||||
}
|
||||
_openPanel.put(panel)
|
||||
|
|
|
@ -36,8 +36,8 @@ import org.oxycblt.auxio.music.Song
|
|||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A picker [ViewBindingMaterialDialogFragment] intended for when [Artist] playback is ambiguous.
|
||||
|
@ -88,7 +88,7 @@ class PlayFromArtistDialog :
|
|||
|
||||
private fun updateSong(song: Song?) {
|
||||
if (song == null) {
|
||||
logD("No song to show choices for, navigating away")
|
||||
T.d("No song to show choices for, navigating away")
|
||||
findNavController().navigateUp()
|
||||
return
|
||||
}
|
||||
|
|
|
@ -36,8 +36,8 @@ import org.oxycblt.auxio.music.Song
|
|||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A picker [ViewBindingMaterialDialogFragment] intended for when [Genre] playback is ambiguous.
|
||||
|
@ -88,7 +88,7 @@ class PlayFromGenreDialog :
|
|||
|
||||
private fun updateSong(song: Song?) {
|
||||
if (song == null) {
|
||||
logD("No song to show choices for, navigating away")
|
||||
T.d("No song to show choices for, navigating away")
|
||||
findNavController().navigateUp()
|
||||
return
|
||||
}
|
||||
|
|
|
@ -27,8 +27,7 @@ import org.oxycblt.auxio.music.Artist
|
|||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.MusicRepository
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ViewModel] that stores the choices shown in the playback picker dialogs.
|
||||
|
@ -64,10 +63,10 @@ class PlaybackPickerViewModel @Inject constructor(private val musicRepository: M
|
|||
* @param uid The [Music.UID] of the item to show. Must be a [Song].
|
||||
*/
|
||||
fun setPickerSongUid(uid: Music.UID) {
|
||||
logD("Opening picker for song $uid")
|
||||
T.d("Opening picker for song $uid")
|
||||
_currentPickerSong.value = musicRepository.deviceLibrary?.findSong(uid)
|
||||
if (_currentPickerSong.value != null) {
|
||||
logW("Given song UID was invalid")
|
||||
T.w("Given song UID was invalid")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -22,8 +22,7 @@ import javax.inject.Inject
|
|||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.MusicRepository
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Manages the persisted playback state in a structured manner.
|
||||
|
@ -60,8 +59,8 @@ constructor(
|
|||
heapItems = queueDao.getHeap()
|
||||
mappingItems = queueDao.getShuffledMapping()
|
||||
} catch (e: Exception) {
|
||||
logE("Unable read playback state")
|
||||
logE(e.stackTraceToString())
|
||||
T.e("Unable read playback state")
|
||||
T.e(e.stackTraceToString())
|
||||
return null
|
||||
}
|
||||
|
||||
|
@ -85,12 +84,12 @@ constructor(
|
|||
queueDao.nukeHeap()
|
||||
queueDao.nukeShuffledMapping()
|
||||
} catch (e: Exception) {
|
||||
logE("Unable to clear previous state")
|
||||
logE(e.stackTraceToString())
|
||||
T.e("Unable to clear previous state")
|
||||
T.e(e.stackTraceToString())
|
||||
return false
|
||||
}
|
||||
|
||||
logD("Successfully cleared previous state")
|
||||
T.d("Successfully cleared previous state")
|
||||
if (state != null) {
|
||||
// Transform saved state into raw state, which can then be written to the database.
|
||||
val playbackState =
|
||||
|
@ -114,12 +113,12 @@ constructor(
|
|||
queueDao.insertHeap(heap)
|
||||
queueDao.insertShuffledMapping(shuffledMapping)
|
||||
} catch (e: Exception) {
|
||||
logE("Unable to write new state")
|
||||
logE(e.stackTraceToString())
|
||||
T.e("Unable to write new state")
|
||||
T.e(e.stackTraceToString())
|
||||
return false
|
||||
}
|
||||
|
||||
logD("Successfully wrote new state")
|
||||
T.d("Successfully wrote new state")
|
||||
}
|
||||
|
||||
return true
|
||||
|
|
|
@ -37,7 +37,7 @@ import org.oxycblt.auxio.music.resolveNames
|
|||
import org.oxycblt.auxio.util.context
|
||||
import org.oxycblt.auxio.util.getAttrColorCompat
|
||||
import org.oxycblt.auxio.util.inflater
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [RecyclerView.Adapter] that shows an editable list of queue items.
|
||||
|
@ -80,7 +80,7 @@ class QueueAdapter(private val listener: EditClickListListener<Song>) :
|
|||
* @param isPlaying Whether playback is ongoing or paused.
|
||||
*/
|
||||
fun setPosition(index: Int, isPlaying: Boolean) {
|
||||
logD("Updating index")
|
||||
T.d("Updating index")
|
||||
val lastIndex = currentIndex
|
||||
currentIndex = index
|
||||
|
||||
|
@ -89,10 +89,10 @@ class QueueAdapter(private val listener: EditClickListListener<Song>) :
|
|||
// TODO: Optimize this by only updating the range between old and new indices?
|
||||
// TODO: Don't update when the index has not moved.
|
||||
if (currentIndex < lastIndex) {
|
||||
logD("Moved backwards, must update items above last index")
|
||||
T.d("Moved backwards, must update items above last index")
|
||||
notifyItemRangeChanged(0, lastIndex + 1, PAYLOAD_UPDATE_POSITION)
|
||||
} else {
|
||||
logD("Moved forwards, update items after index")
|
||||
T.d("Moved forwards, update items after index")
|
||||
notifyItemRangeChanged(0, currentIndex + 1, PAYLOAD_UPDATE_POSITION)
|
||||
}
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ import org.oxycblt.auxio.music.Song
|
|||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.ui.ViewBindingFragment
|
||||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ViewBindingFragment] that displays an editable queue.
|
||||
|
@ -122,14 +122,14 @@ class QueueFragment : ViewBindingFragment<FragmentQueueBinding>(), EditClickList
|
|||
// dependent on where we have to scroll to get to the currently playing song.
|
||||
if (notInitialized || scrollTo < start) {
|
||||
// We need to scroll upwards, or initialize the scroll, no need to offset
|
||||
logD("Not scrolling downwards, no offset needed")
|
||||
T.d("Not scrolling downwards, no offset needed")
|
||||
binding.queueRecycler.scrollToPosition(scrollTo)
|
||||
} else if (scrollTo > end) {
|
||||
// We need to scroll downwards, we need to offset by a screen of songs.
|
||||
// This does have some error due to how many completely visible items on-screen
|
||||
// can vary. This is considered okay.
|
||||
val offset = scrollTo + (end - start)
|
||||
logD("Scrolling downwards, offsetting by $offset")
|
||||
T.d("Scrolling downwards, offsetting by $offset")
|
||||
binding.queueRecycler.scrollToPosition(min(queue.lastIndex, offset))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,7 +30,7 @@ import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
|||
import org.oxycblt.auxio.playback.state.QueueChange
|
||||
import org.oxycblt.auxio.util.Event
|
||||
import org.oxycblt.auxio.util.MutableEvent
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [ViewModel] that manages the current queue state and allows navigation through the queue.
|
||||
|
@ -62,26 +62,26 @@ class QueueViewModel @Inject constructor(private val playbackManager: PlaybackSt
|
|||
}
|
||||
|
||||
override fun onIndexMoved(index: Int) {
|
||||
logD("Index moved, synchronizing and scrolling to new position")
|
||||
T.d("Index moved, synchronizing and scrolling to new position")
|
||||
_scrollTo.put(index)
|
||||
_index.value = index
|
||||
}
|
||||
|
||||
override fun onQueueChanged(queue: List<Song>, index: Int, change: QueueChange) {
|
||||
// Queue changed trivially due to item mo -> Diff queue, stay at current index.
|
||||
logD("Updating queue display")
|
||||
T.d("Updating queue display")
|
||||
_queueInstructions.put(change.instructions)
|
||||
_queue.value = queue
|
||||
if (change.type != QueueChange.Type.MAPPING) {
|
||||
// Index changed, make sure it remains updated without actually scrolling to it.
|
||||
logD("Index changed with queue, synchronizing new position")
|
||||
T.d("Index changed with queue, synchronizing new position")
|
||||
_index.value = index
|
||||
}
|
||||
}
|
||||
|
||||
override fun onQueueReordered(queue: List<Song>, index: Int, isShuffled: Boolean) {
|
||||
// Queue changed completely -> Replace queue, update index
|
||||
logD("Queue changed completely, replacing queue and position")
|
||||
T.d("Queue changed completely, replacing queue and position")
|
||||
_queueInstructions.put(UpdateInstructions.Replace(0))
|
||||
_scrollTo.put(index)
|
||||
_queue.value = queue
|
||||
|
@ -95,7 +95,7 @@ class QueueViewModel @Inject constructor(private val playbackManager: PlaybackSt
|
|||
isShuffled: Boolean
|
||||
) {
|
||||
// Entirely new queue -> Replace queue, update index
|
||||
logD("New playback, replacing queue and position")
|
||||
T.d("New playback, replacing queue and position")
|
||||
_queueInstructions.put(UpdateInstructions.Replace(0))
|
||||
_scrollTo.put(index)
|
||||
_queue.value = queue
|
||||
|
@ -117,7 +117,7 @@ class QueueViewModel @Inject constructor(private val playbackManager: PlaybackSt
|
|||
if (adapterIndex !in queue.value.indices) {
|
||||
return
|
||||
}
|
||||
logD("Going to position $adapterIndex in queue")
|
||||
T.d("Going to position $adapterIndex in queue")
|
||||
playbackManager.goto(adapterIndex)
|
||||
}
|
||||
|
||||
|
@ -131,7 +131,7 @@ class QueueViewModel @Inject constructor(private val playbackManager: PlaybackSt
|
|||
if (adapterIndex !in queue.value.indices) {
|
||||
return
|
||||
}
|
||||
logD("Removing item $adapterIndex in queue")
|
||||
T.d("Removing item $adapterIndex in queue")
|
||||
playbackManager.removeQueueItem(adapterIndex)
|
||||
}
|
||||
|
||||
|
@ -146,7 +146,7 @@ class QueueViewModel @Inject constructor(private val playbackManager: PlaybackSt
|
|||
if (adapterFrom !in queue.value.indices || adapterTo !in queue.value.indices) {
|
||||
return false
|
||||
}
|
||||
logD("Moving $adapterFrom to $adapterFrom in queue")
|
||||
T.d("Moving $adapterFrom to $adapterFrom in queue")
|
||||
playbackManager.moveQueueItem(adapterFrom, adapterTo)
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -28,7 +28,7 @@ import org.oxycblt.auxio.R
|
|||
import org.oxycblt.auxio.databinding.DialogPreAmpBinding
|
||||
import org.oxycblt.auxio.playback.PlaybackSettings
|
||||
import org.oxycblt.auxio.ui.ViewBindingMaterialDialogFragment
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* aa [ViewBindingMaterialDialogFragment] that allows user configuration of the current
|
||||
|
@ -62,7 +62,7 @@ class PreAmpCustomizeDialog : ViewBindingMaterialDialogFragment<DialogPreAmpBind
|
|||
// settings. After this, the sliders save their own state, so we do not need to
|
||||
// do any restore behavior.
|
||||
val preAmp = playbackSettings.replayGainPreAmp
|
||||
logD("Initializing from $preAmp")
|
||||
T.d("Initializing from $preAmp")
|
||||
binding.withTagsSlider.value = preAmp.with
|
||||
binding.withoutTagsSlider.value = preAmp.without
|
||||
}
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.oxycblt.auxio.music.Song
|
|||
import org.oxycblt.auxio.playback.PlaybackSettings
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||
import org.oxycblt.auxio.playback.state.QueueChange
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* An [AudioProcessor] that handles ReplayGain values and their amplification of the audio stream.
|
||||
|
@ -71,7 +71,7 @@ constructor(
|
|||
// --- OVERRIDES ---
|
||||
|
||||
override fun onIndexMoved(index: Int) {
|
||||
logD("Index moved, updating current song")
|
||||
T.d("Index moved, updating current song")
|
||||
applyReplayGain(playbackManager.currentSong)
|
||||
}
|
||||
|
||||
|
@ -88,7 +88,7 @@ constructor(
|
|||
index: Int,
|
||||
isShuffled: Boolean
|
||||
) {
|
||||
logD("New playback started, updating playback information")
|
||||
T.d("New playback started, updating playback information")
|
||||
applyReplayGain(playbackManager.currentSong)
|
||||
}
|
||||
|
||||
|
@ -106,12 +106,12 @@ constructor(
|
|||
*/
|
||||
private fun applyReplayGain(song: Song?) {
|
||||
if (song == null) {
|
||||
logD("Nothing playing, disabling adjustment")
|
||||
T.d("Nothing playing, disabling adjustment")
|
||||
volume = 1f
|
||||
return
|
||||
}
|
||||
|
||||
logD("Applying ReplayGain adjustment for $song")
|
||||
T.d("Applying ReplayGain adjustment for $song")
|
||||
|
||||
val gain = song.replayGainAdjustment
|
||||
val preAmp = playbackSettings.replayGainPreAmp
|
||||
|
@ -121,24 +121,24 @@ constructor(
|
|||
when (playbackSettings.replayGainMode) {
|
||||
// User wants no adjustment.
|
||||
ReplayGainMode.OFF -> {
|
||||
logD("ReplayGain is off")
|
||||
T.d("ReplayGain is off")
|
||||
null
|
||||
}
|
||||
// User wants track gain to be preferred. Default to album gain only if
|
||||
// there is no track gain.
|
||||
ReplayGainMode.TRACK -> {
|
||||
logD("Using track strategy")
|
||||
T.d("Using track strategy")
|
||||
gain.track ?: gain.album
|
||||
}
|
||||
// User wants album gain to be preferred. Default to track gain only if
|
||||
// here is no album gain.
|
||||
ReplayGainMode.ALBUM -> {
|
||||
logD("Using album strategy")
|
||||
T.d("Using album strategy")
|
||||
gain.album ?: gain.track
|
||||
}
|
||||
// User wants album gain to be used when in an album, track gain otherwise.
|
||||
ReplayGainMode.DYNAMIC -> {
|
||||
logD("Using dynamic strategy")
|
||||
T.d("Using dynamic strategy")
|
||||
gain.album?.takeIf {
|
||||
playbackManager.parent is Album &&
|
||||
playbackManager.currentSong?.album == playbackManager.parent
|
||||
|
@ -150,15 +150,15 @@ constructor(
|
|||
val amplifiedAdjustment =
|
||||
if (resolvedAdjustment != null) {
|
||||
// Successfully resolved an adjustment, apply the corresponding pre-amp
|
||||
logD("Applying with pre-amp")
|
||||
T.d("Applying with pre-amp")
|
||||
resolvedAdjustment + preAmp.with
|
||||
} else {
|
||||
// No adjustment found, use the corresponding user-defined pre-amp
|
||||
logD("Applying without pre-amp")
|
||||
T.d("Applying without pre-amp")
|
||||
preAmp.without
|
||||
}
|
||||
|
||||
logD("Applying ReplayGain adjustment ${amplifiedAdjustment}db")
|
||||
T.d("Applying ReplayGain adjustment ${amplifiedAdjustment}db")
|
||||
|
||||
// Final adjustment along the volume curve.
|
||||
volume = 10f.pow(amplifiedAdjustment / 20f)
|
||||
|
|
|
@ -59,8 +59,7 @@ import org.oxycblt.auxio.playback.state.RawQueue
|
|||
import org.oxycblt.auxio.playback.state.RepeatMode
|
||||
import org.oxycblt.auxio.playback.state.ShuffleMode
|
||||
import org.oxycblt.auxio.playback.state.StateAck
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import timber.log.Timber as T
|
||||
|
||||
class ExoPlaybackStateHolder(
|
||||
private val context: Context,
|
||||
|
@ -152,7 +151,7 @@ class ExoPlaybackStateHolder(
|
|||
when (action) {
|
||||
// Restore state -> Start a new restoreState job
|
||||
is DeferredPlayback.RestoreState -> {
|
||||
logD("Restoring playback state")
|
||||
T.d("Restoring playback state")
|
||||
restoreScope.launch {
|
||||
val state = persistenceRepository.readState()
|
||||
withContext(Dispatchers.Main) {
|
||||
|
@ -171,7 +170,7 @@ class ExoPlaybackStateHolder(
|
|||
}
|
||||
// Shuffle all -> Start new playback from all songs
|
||||
is DeferredPlayback.ShuffleAll -> {
|
||||
logD("Shuffling all tracks")
|
||||
T.d("Shuffling all tracks")
|
||||
playbackManager.play(
|
||||
requireNotNull(commandFactory.all(ShuffleMode.ON)) {
|
||||
"Invalid playback parameters"
|
||||
|
@ -179,7 +178,7 @@ class ExoPlaybackStateHolder(
|
|||
}
|
||||
// Open -> Try to find the Song for the given file and then play it from all songs
|
||||
is DeferredPlayback.Open -> {
|
||||
logD("Opening specified file")
|
||||
T.d("Opening specified file")
|
||||
deviceLibrary.findSongForUri(context, action.uri)?.let { song ->
|
||||
playbackManager.play(
|
||||
requireNotNull(commandFactory.song(song, ShuffleMode.IMPLICIT)) {
|
||||
|
@ -428,18 +427,18 @@ class ExoPlaybackStateHolder(
|
|||
|
||||
if (player.playWhenReady) {
|
||||
// Mark that we have started playing so that the notification can now be posted.
|
||||
logD("Player has started playing")
|
||||
T.d("Player has started playing")
|
||||
sessionOngoing = true
|
||||
if (!openAudioEffectSession) {
|
||||
// Convention to start an audioeffect session on play/pause rather than
|
||||
// start/stop
|
||||
logD("Opening audio effect session")
|
||||
T.d("Opening audio effect session")
|
||||
broadcastAudioEffectAction(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION)
|
||||
openAudioEffectSession = true
|
||||
}
|
||||
} else if (openAudioEffectSession) {
|
||||
// Make sure to close the audio session when we stop playback.
|
||||
logD("Closing audio effect session")
|
||||
T.d("Closing audio effect session")
|
||||
broadcastAudioEffectAction(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION)
|
||||
openAudioEffectSession = false
|
||||
}
|
||||
|
@ -471,7 +470,7 @@ class ExoPlaybackStateHolder(
|
|||
Player.EVENT_PLAY_WHEN_READY_CHANGED,
|
||||
Player.EVENT_IS_PLAYING_CHANGED,
|
||||
Player.EVENT_POSITION_DISCONTINUITY)) {
|
||||
logD("Player state changed, must synchronize state")
|
||||
T.d("Player state changed, must synchronize state")
|
||||
playbackManager.ack(this, StateAck.ProgressionChanged)
|
||||
}
|
||||
}
|
||||
|
@ -479,13 +478,13 @@ class ExoPlaybackStateHolder(
|
|||
override fun onPlayerError(error: PlaybackException) {
|
||||
// TODO: Replace with no skipping and a notification instead
|
||||
// If there's any issue, just go to the next song.
|
||||
logE("Player error occurred")
|
||||
logE(error.stackTraceToString())
|
||||
T.e("Player error occurred")
|
||||
T.e(error.stackTraceToString())
|
||||
playbackManager.next()
|
||||
}
|
||||
|
||||
private fun broadcastAudioEffectAction(event: String) {
|
||||
logD("Broadcasting AudioEffect event: $event")
|
||||
T.d("Broadcasting AudioEffect event: $event")
|
||||
context.sendBroadcast(
|
||||
Intent(event)
|
||||
.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.packageName)
|
||||
|
@ -498,7 +497,7 @@ class ExoPlaybackStateHolder(
|
|||
override fun onMusicChanges(changes: MusicRepository.Changes) {
|
||||
if (changes.deviceLibrary && musicRepository.deviceLibrary != null) {
|
||||
// We now have a library, see if we have anything we need to do.
|
||||
logD("Library obtained, requesting action")
|
||||
T.d("Library obtained, requesting action")
|
||||
playbackManager.requestAction(this)
|
||||
}
|
||||
}
|
||||
|
@ -524,17 +523,17 @@ class ExoPlaybackStateHolder(
|
|||
|
||||
private fun deferSave() {
|
||||
saveJob {
|
||||
logD("Waiting for save buffer")
|
||||
T.d("Waiting for save buffer")
|
||||
delay(SAVE_BUFFER)
|
||||
yield()
|
||||
logD("Committing saved state")
|
||||
T.d("Committing saved state")
|
||||
persistenceRepository.saveState(playbackManager.toSavedState())
|
||||
}
|
||||
}
|
||||
|
||||
private fun saveJob(block: suspend () -> Unit) {
|
||||
currentSaveJob?.let {
|
||||
logD("Discarding prior save job")
|
||||
T.d("Discarding prior save job")
|
||||
it.cancel()
|
||||
}
|
||||
currentSaveJob = saveScope.launch { block() }
|
||||
|
|
|
@ -27,7 +27,7 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||
import javax.inject.Inject
|
||||
import org.oxycblt.auxio.AuxioService
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [BroadcastReceiver] that forwards [Intent.ACTION_MEDIA_BUTTON] [Intent]s to
|
||||
|
@ -47,7 +47,7 @@ class MediaButtonReceiver : BroadcastReceiver() {
|
|||
// stupid this is with the state of foreground services on modern android. One
|
||||
// wrong action at the wrong time will result in the app crashing, and there is
|
||||
// nothing I can do about it.
|
||||
logD("Delivering media button intent $intent")
|
||||
T.d("Delivering media button intent $intent")
|
||||
intent.component = ComponentName(context, AuxioService::class.java)
|
||||
ContextCompat.startForegroundService(context, intent)
|
||||
}
|
||||
|
|
|
@ -47,9 +47,9 @@ import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
|||
import org.oxycblt.auxio.playback.state.Progression
|
||||
import org.oxycblt.auxio.playback.state.QueueChange
|
||||
import org.oxycblt.auxio.playback.state.RepeatMode
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.newBroadcastPendingIntent
|
||||
import org.oxycblt.auxio.util.newMainPendingIntent
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A component that mirrors the current playback state into the [MediaSessionCompat] and
|
||||
|
@ -210,10 +210,10 @@ private constructor(
|
|||
* playback is currently occuring from all songs.
|
||||
*/
|
||||
private fun updateMediaMetadata(song: Song?, parent: MusicParent?) {
|
||||
logD("Updating media metadata to $song with $parent")
|
||||
T.d("Updating media metadata to $song with $parent")
|
||||
if (song == null) {
|
||||
// Nothing playing, reset the MediaSession and close the notification.
|
||||
logD("Nothing playing, resetting media session")
|
||||
T.d("Nothing playing, resetting media session")
|
||||
mediaSession.setMetadata(emptyMetadata)
|
||||
return
|
||||
}
|
||||
|
@ -252,15 +252,15 @@ private constructor(
|
|||
MediaSessionUID.SingleItem(song.album.uid).toString())
|
||||
// These fields are nullable and so we must check first before adding them to the fields.
|
||||
song.track?.let {
|
||||
logD("Adding track information")
|
||||
T.d("Adding track information")
|
||||
builder.putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, it.toLong())
|
||||
}
|
||||
song.disc?.let {
|
||||
logD("Adding disc information")
|
||||
T.d("Adding disc information")
|
||||
builder.putLong(MediaMetadataCompat.METADATA_KEY_DISC_NUMBER, it.number.toLong())
|
||||
}
|
||||
song.date?.let {
|
||||
logD("Adding date information")
|
||||
T.d("Adding date information")
|
||||
builder.putString(MediaMetadataCompat.METADATA_KEY_DATE, it.toString())
|
||||
builder.putLong(MediaMetadataCompat.METADATA_KEY_YEAR, it.year.toLong())
|
||||
}
|
||||
|
@ -272,7 +272,7 @@ private constructor(
|
|||
song,
|
||||
object : BitmapProvider.Target {
|
||||
override fun onCompleted(bitmap: Bitmap?) {
|
||||
logD("Bitmap loaded, applying media session and posting notification")
|
||||
T.d("Bitmap loaded, applying media session and posting notification")
|
||||
if (bitmap != null) {
|
||||
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ART, bitmap)
|
||||
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap)
|
||||
|
@ -300,13 +300,13 @@ private constructor(
|
|||
// playback state.
|
||||
MediaSessionCompat.QueueItem(description, i.toLong())
|
||||
}
|
||||
logD("Uploading ${queueItems.size} songs to MediaSession queue")
|
||||
T.d("Uploading ${queueItems.size} songs to MediaSession queue")
|
||||
mediaSession.setQueue(queueItems)
|
||||
}
|
||||
|
||||
/** Invalidate the current [MediaSessionCompat]'s [PlaybackStateCompat]. */
|
||||
private fun invalidateSessionState() {
|
||||
logD("Updating media session playback state")
|
||||
T.d("Updating media session playback state")
|
||||
|
||||
val state =
|
||||
// InternalPlayer.State handles position/state information.
|
||||
|
@ -322,7 +322,7 @@ private constructor(
|
|||
val secondaryAction =
|
||||
when (playbackSettings.notificationAction) {
|
||||
ActionMode.SHUFFLE -> {
|
||||
logD("Using shuffle MediaSession action")
|
||||
T.d("Using shuffle MediaSession action")
|
||||
PlaybackStateCompat.CustomAction.Builder(
|
||||
PlaybackActions.ACTION_INVERT_SHUFFLE,
|
||||
context.getString(R.string.desc_shuffle),
|
||||
|
@ -333,7 +333,7 @@ private constructor(
|
|||
})
|
||||
}
|
||||
else -> {
|
||||
logD("Using repeat mode MediaSession action")
|
||||
T.d("Using repeat mode MediaSession action")
|
||||
PlaybackStateCompat.CustomAction.Builder(
|
||||
PlaybackActions.ACTION_INC_REPEAT_MODE,
|
||||
context.getString(R.string.desc_change_repeat),
|
||||
|
@ -356,22 +356,22 @@ private constructor(
|
|||
|
||||
/** Invalidate the "secondary" action (i.e shuffle/repeat mode). */
|
||||
private fun invalidateSecondaryAction() {
|
||||
logD("Invalidating secondary action")
|
||||
T.d("Invalidating secondary action")
|
||||
invalidateSessionState()
|
||||
|
||||
when (playbackSettings.notificationAction) {
|
||||
ActionMode.SHUFFLE -> {
|
||||
logD("Using shuffle notification action")
|
||||
T.d("Using shuffle notification action")
|
||||
_notification.updateShuffled(playbackManager.isShuffled)
|
||||
}
|
||||
else -> {
|
||||
logD("Using repeat mode notification action")
|
||||
T.d("Using repeat mode notification action")
|
||||
_notification.updateRepeatMode(playbackManager.repeatMode)
|
||||
}
|
||||
}
|
||||
|
||||
if (!bitmapProvider.isBusy) {
|
||||
logD("Not loading a bitmap, post the notification")
|
||||
T.d("Not loading a bitmap, post the notification")
|
||||
foregroundListener.updateForeground(ForegroundListener.Change.MEDIA_SESSION)
|
||||
}
|
||||
}
|
||||
|
@ -423,7 +423,7 @@ private class PlaybackNotification(
|
|||
* @param metadata The [MediaMetadataCompat] to display in this notification.
|
||||
*/
|
||||
fun updateMetadata(metadata: MediaMetadataCompat) {
|
||||
logD("Updating shown metadata")
|
||||
T.d("Updating shown metadata")
|
||||
setLargeIcon(metadata.getBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART))
|
||||
setContentTitle(metadata.getString(MediaMetadataCompat.METADATA_KEY_TITLE))
|
||||
setContentText(metadata.getText(MediaMetadataCompat.METADATA_KEY_ARTIST))
|
||||
|
@ -436,7 +436,7 @@ private class PlaybackNotification(
|
|||
* @param isPlaying Whether playback should be indicated as ongoing or paused.
|
||||
*/
|
||||
fun updatePlaying(isPlaying: Boolean) {
|
||||
logD("Updating playing state: $isPlaying")
|
||||
T.d("Updating playing state: $isPlaying")
|
||||
mActions[2] = buildPlayPauseAction(context, isPlaying)
|
||||
}
|
||||
|
||||
|
@ -446,7 +446,7 @@ private class PlaybackNotification(
|
|||
* @param repeatMode The current [RepeatMode].
|
||||
*/
|
||||
fun updateRepeatMode(repeatMode: RepeatMode) {
|
||||
logD("Applying repeat mode action: $repeatMode")
|
||||
T.d("Applying repeat mode action: $repeatMode")
|
||||
mActions[0] = buildRepeatAction(context, repeatMode)
|
||||
}
|
||||
|
||||
|
@ -456,7 +456,7 @@ private class PlaybackNotification(
|
|||
* @param isShuffled Whether the queue is currently shuffled or not.
|
||||
*/
|
||||
fun updateShuffled(isShuffled: Boolean) {
|
||||
logD("Applying shuffle action: $isShuffled")
|
||||
T.d("Applying shuffle action: $isShuffled")
|
||||
mActions[0] = buildShuffleAction(context, isShuffled)
|
||||
}
|
||||
|
||||
|
|
|
@ -47,7 +47,7 @@ import org.oxycblt.auxio.playback.state.PlaybackCommand
|
|||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||
import org.oxycblt.auxio.playback.state.RepeatMode
|
||||
import org.oxycblt.auxio.playback.state.ShuffleMode
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
class MediaSessionInterface
|
||||
@Inject
|
||||
|
@ -85,7 +85,7 @@ constructor(
|
|||
val parentUid =
|
||||
extras?.getString(MusicBrowser.KEY_CHILD_OF)?.let { MediaSessionUID.fromString(it) }
|
||||
val command = expandUidIntoCommand(uid, parentUid)
|
||||
logD(extras?.getString(MusicBrowser.KEY_CHILD_OF))
|
||||
T.d(extras?.getString(MusicBrowser.KEY_CHILD_OF))
|
||||
playbackManager.play(requireNotNull(command) { "Invalid playback configuration" })
|
||||
}
|
||||
|
||||
|
|
|
@ -27,8 +27,8 @@ import org.oxycblt.auxio.ForegroundServiceNotification
|
|||
import org.oxycblt.auxio.IntegerTable
|
||||
import org.oxycblt.auxio.playback.state.DeferredPlayback
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.widgets.WidgetComponent
|
||||
import timber.log.Timber as T
|
||||
|
||||
class PlaybackServiceFragment
|
||||
private constructor(
|
||||
|
@ -86,7 +86,7 @@ private constructor(
|
|||
fun start(startedBy: Int) {
|
||||
// At minimum we want to ensure an active playback state.
|
||||
// TODO: Possibly also force to go foreground?
|
||||
logD("Handling non-native start.")
|
||||
T.d("Handling non-native start.")
|
||||
val action =
|
||||
when (startedBy) {
|
||||
IntegerTable.START_ID_ACTIVITY -> null
|
||||
|
@ -97,7 +97,7 @@ private constructor(
|
|||
else -> DeferredPlayback.RestoreState(play = false)
|
||||
}
|
||||
if (action != null) {
|
||||
logD("Initing service fragment using action $action")
|
||||
T.d("Initing service fragment using action $action")
|
||||
playbackManager.playDeferred(action)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -27,9 +27,9 @@ import androidx.core.content.ContextCompat
|
|||
import javax.inject.Inject
|
||||
import org.oxycblt.auxio.playback.PlaybackSettings
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.widgets.WidgetComponent
|
||||
import org.oxycblt.auxio.widgets.WidgetProvider
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [BroadcastReceiver] for receiving playback-specific [Intent]s from the system that require an
|
||||
|
@ -75,7 +75,7 @@ private constructor(
|
|||
// 3. Some internal framework thing that also handles bluetooth headsets
|
||||
// Just use ACTION_HEADSET_PLUG.
|
||||
AudioManager.ACTION_HEADSET_PLUG -> {
|
||||
logD("Received headset plug event")
|
||||
T.d("Received headset plug event")
|
||||
when (intent.getIntExtra("state", -1)) {
|
||||
0 -> pauseFromHeadsetPlug()
|
||||
1 -> playFromHeadsetPlug()
|
||||
|
@ -84,37 +84,37 @@ private constructor(
|
|||
initialHeadsetPlugEventHandled = true
|
||||
}
|
||||
AudioManager.ACTION_AUDIO_BECOMING_NOISY -> {
|
||||
logD("Received Headset noise event")
|
||||
T.d("Received Headset noise event")
|
||||
pauseFromHeadsetPlug()
|
||||
}
|
||||
|
||||
// --- AUXIO EVENTS ---
|
||||
PlaybackActions.ACTION_PLAY_PAUSE -> {
|
||||
logD("Received play event")
|
||||
T.d("Received play event")
|
||||
playbackManager.playing(!playbackManager.progression.isPlaying)
|
||||
}
|
||||
PlaybackActions.ACTION_INC_REPEAT_MODE -> {
|
||||
logD("Received repeat mode event")
|
||||
T.d("Received repeat mode event")
|
||||
playbackManager.repeatMode(playbackManager.repeatMode.increment())
|
||||
}
|
||||
PlaybackActions.ACTION_INVERT_SHUFFLE -> {
|
||||
logD("Received shuffle event")
|
||||
T.d("Received shuffle event")
|
||||
playbackManager.shuffled(!playbackManager.isShuffled)
|
||||
}
|
||||
PlaybackActions.ACTION_SKIP_PREV -> {
|
||||
logD("Received skip previous event")
|
||||
T.d("Received skip previous event")
|
||||
playbackManager.prev()
|
||||
}
|
||||
PlaybackActions.ACTION_SKIP_NEXT -> {
|
||||
logD("Received skip next event")
|
||||
T.d("Received skip next event")
|
||||
playbackManager.next()
|
||||
}
|
||||
PlaybackActions.ACTION_EXIT -> {
|
||||
logD("Received exit event")
|
||||
T.d("Received exit event")
|
||||
playbackManager.endSession()
|
||||
}
|
||||
WidgetProvider.ACTION_WIDGET_UPDATE -> {
|
||||
logD("Received widget update event")
|
||||
T.d("Received widget update event")
|
||||
widgetComponent.update()
|
||||
}
|
||||
}
|
||||
|
@ -127,14 +127,14 @@ private constructor(
|
|||
if (playbackSettings.headsetAutoplay &&
|
||||
playbackManager.currentSong != null &&
|
||||
initialHeadsetPlugEventHandled) {
|
||||
logD("Device connected, resuming")
|
||||
T.d("Device connected, resuming")
|
||||
playbackManager.playing(true)
|
||||
}
|
||||
}
|
||||
|
||||
private fun pauseFromHeadsetPlug() {
|
||||
if (playbackManager.currentSong != null) {
|
||||
logD("Device disconnected, pausing")
|
||||
T.d("Device disconnected, pausing")
|
||||
playbackManager.playing(false)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,6 +29,7 @@ import org.oxycblt.auxio.music.MusicRepository
|
|||
import org.oxycblt.auxio.music.Playlist
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.playback.PlaybackSettings
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A playback command that can be passed to [PlaybackStateManager] to start new playback.
|
||||
|
|
|
@ -25,8 +25,7 @@ import org.oxycblt.auxio.music.Music
|
|||
import org.oxycblt.auxio.music.MusicParent
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager.Listener
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Core playback state controller class.
|
||||
|
@ -388,11 +387,11 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
|
|||
|
||||
@Synchronized
|
||||
override fun addListener(listener: Listener) {
|
||||
logD("Adding $listener to listeners")
|
||||
T.d("Adding $listener to listeners")
|
||||
listeners.add(listener)
|
||||
|
||||
if (isInitialized) {
|
||||
logD("Sending initial state to $listener")
|
||||
T.d("Sending initial state to $listener")
|
||||
listener.onNewPlayback(
|
||||
stateMirror.parent, stateMirror.queue, stateMirror.index, stateMirror.isShuffled)
|
||||
listener.onProgressionChanged(stateMirror.progression)
|
||||
|
@ -402,16 +401,16 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
|
|||
|
||||
@Synchronized
|
||||
override fun removeListener(listener: Listener) {
|
||||
logD("Removing $listener from listeners")
|
||||
T.d("Removing $listener from listeners")
|
||||
if (!listeners.remove(listener)) {
|
||||
logW("Listener $listener was not added prior, cannot remove")
|
||||
T.w("Listener $listener was not added prior, cannot remove")
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun registerStateHolder(stateHolder: PlaybackStateHolder) {
|
||||
if (this.stateHolder != null) {
|
||||
logW("Internal player is already registered")
|
||||
T.w("Internal player is already registered")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -430,11 +429,11 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
|
|||
@Synchronized
|
||||
override fun unregisterStateHolder(stateHolder: PlaybackStateHolder) {
|
||||
if (this.stateHolder !== stateHolder) {
|
||||
logW("Given internal player did not match current internal player")
|
||||
T.w("Given internal player did not match current internal player")
|
||||
return
|
||||
}
|
||||
|
||||
logD("Unregistering internal player $stateHolder")
|
||||
T.d("Unregistering internal player $stateHolder")
|
||||
|
||||
this.stateHolder = null
|
||||
}
|
||||
|
@ -444,7 +443,7 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
|
|||
@Synchronized
|
||||
override fun play(command: PlaybackCommand) {
|
||||
val stateHolder = stateHolder ?: return
|
||||
logD("Playing $command")
|
||||
T.d("Playing $command")
|
||||
// Played something, so we are initialized now
|
||||
isInitialized = true
|
||||
stateHolder.newPlayback(command)
|
||||
|
@ -455,32 +454,32 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
|
|||
@Synchronized
|
||||
override fun next() {
|
||||
val stateHolder = stateHolder ?: return
|
||||
logD("Going to next song")
|
||||
T.d("Going to next song")
|
||||
stateHolder.next()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun prev() {
|
||||
val stateHolder = stateHolder ?: return
|
||||
logD("Going to previous song")
|
||||
T.d("Going to previous song")
|
||||
stateHolder.prev()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun goto(index: Int) {
|
||||
val stateHolder = stateHolder ?: return
|
||||
logD("Going to index $index")
|
||||
T.d("Going to index $index")
|
||||
stateHolder.goto(index)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun playNext(songs: List<Song>) {
|
||||
if (currentSong == null) {
|
||||
logD("Nothing playing, short-circuiting to new playback")
|
||||
T.d("Nothing playing, short-circuiting to new playback")
|
||||
play(QueueCommand(songs))
|
||||
} else {
|
||||
val stateHolder = stateHolder ?: return
|
||||
logD("Adding ${songs.size} songs to start of queue")
|
||||
T.d("Adding ${songs.size} songs to start of queue")
|
||||
stateHolder.playNext(songs, StateAck.PlayNext(stateMirror.index + 1, songs.size))
|
||||
}
|
||||
}
|
||||
|
@ -488,11 +487,11 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
|
|||
@Synchronized
|
||||
override fun addToQueue(songs: List<Song>) {
|
||||
if (currentSong == null) {
|
||||
logD("Nothing playing, short-circuiting to new playback")
|
||||
T.d("Nothing playing, short-circuiting to new playback")
|
||||
play(QueueCommand(songs))
|
||||
} else {
|
||||
val stateHolder = stateHolder ?: return
|
||||
logD("Adding ${songs.size} songs to end of queue")
|
||||
T.d("Adding ${songs.size} songs to end of queue")
|
||||
stateHolder.addToQueue(songs, StateAck.AddToQueue(queue.size, songs.size))
|
||||
}
|
||||
}
|
||||
|
@ -506,21 +505,21 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
|
|||
@Synchronized
|
||||
override fun moveQueueItem(src: Int, dst: Int) {
|
||||
val stateHolder = stateHolder ?: return
|
||||
logD("Moving item $src to position $dst")
|
||||
T.d("Moving item $src to position $dst")
|
||||
stateHolder.move(src, dst, StateAck.Move(src, dst))
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun removeQueueItem(at: Int) {
|
||||
val stateHolder = stateHolder ?: return
|
||||
logD("Removing item at $at")
|
||||
T.d("Removing item at $at")
|
||||
stateHolder.remove(at, StateAck.Remove(at))
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun shuffled(shuffled: Boolean) {
|
||||
val stateHolder = stateHolder ?: return
|
||||
logD("Reordering queue [shuffled=$shuffled]")
|
||||
T.d("Reordering queue [shuffled=$shuffled]")
|
||||
stateHolder.shuffled(shuffled)
|
||||
}
|
||||
|
||||
|
@ -530,7 +529,7 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
|
|||
override fun playDeferred(action: DeferredPlayback) {
|
||||
val stateHolder = stateHolder
|
||||
if (stateHolder == null || !stateHolder.handleDeferred(action)) {
|
||||
logD("Internal player not present or did not consume action, waiting")
|
||||
T.d("Internal player not present or did not consume action, waiting")
|
||||
pendingDeferredPlayback = action
|
||||
}
|
||||
}
|
||||
|
@ -538,12 +537,12 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
|
|||
@Synchronized
|
||||
override fun requestAction(stateHolder: PlaybackStateHolder) {
|
||||
if (BuildConfig.DEBUG && this.stateHolder !== stateHolder) {
|
||||
logW("Given internal player did not match current internal player")
|
||||
T.w("Given internal player did not match current internal player")
|
||||
return
|
||||
}
|
||||
|
||||
if (pendingDeferredPlayback?.let(stateHolder::handleDeferred) == true) {
|
||||
logD("Pending action consumed")
|
||||
T.d("Pending action consumed")
|
||||
pendingDeferredPlayback = null
|
||||
}
|
||||
}
|
||||
|
@ -551,35 +550,35 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
|
|||
@Synchronized
|
||||
override fun playing(isPlaying: Boolean) {
|
||||
val stateHolder = stateHolder ?: return
|
||||
logD("Updating playing state to $isPlaying")
|
||||
T.d("Updating playing state to $isPlaying")
|
||||
stateHolder.playing(isPlaying)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun repeatMode(repeatMode: RepeatMode) {
|
||||
val stateHolder = stateHolder ?: return
|
||||
logD("Updating repeat mode to $repeatMode")
|
||||
T.d("Updating repeat mode to $repeatMode")
|
||||
stateHolder.repeatMode(repeatMode)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun seekTo(positionMs: Long) {
|
||||
val stateHolder = stateHolder ?: return
|
||||
logD("Seeking to ${positionMs}ms")
|
||||
T.d("Seeking to ${positionMs}ms")
|
||||
stateHolder.seekTo(positionMs)
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun endSession() {
|
||||
val stateHolder = stateHolder ?: return
|
||||
logD("Ending session")
|
||||
T.d("Ending session")
|
||||
stateHolder.endSession()
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
override fun ack(stateHolder: PlaybackStateHolder, ack: StateAck) {
|
||||
if (BuildConfig.DEBUG && this.stateHolder !== stateHolder) {
|
||||
logW("Given internal player did not match current internal player")
|
||||
T.w("Given internal player did not match current internal player")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -730,7 +729,7 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
|
|||
destructive: Boolean
|
||||
) {
|
||||
if (isInitialized && !destructive) {
|
||||
logW("Already initialized, cannot apply saved state")
|
||||
T.w("Already initialized, cannot apply saved state")
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -752,7 +751,7 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
|
|||
}
|
||||
}
|
||||
|
||||
logD("Created adjustment mapping [max shift=$currentShift]")
|
||||
T.d("Created adjustment mapping [max shift=$currentShift]")
|
||||
|
||||
val shuffledMapping =
|
||||
savedState.shuffledMapping.mapNotNullTo(mutableListOf()) { index ->
|
||||
|
@ -767,7 +766,7 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
|
|||
} else {
|
||||
heap.getOrNull(index)
|
||||
}
|
||||
logD(currentSong)
|
||||
T.d(currentSong)
|
||||
|
||||
return currentSong?.uid == savedState.songUid
|
||||
}
|
||||
|
@ -777,7 +776,7 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager {
|
|||
index--
|
||||
}
|
||||
|
||||
logD("Corrected index: ${savedState.index} -> $index")
|
||||
T.d("Corrected index: ${savedState.index} -> $index")
|
||||
|
||||
check(shuffledMapping.all { it in heap.indices }) {
|
||||
"Queue inconsistency detected: Shuffled mapping indices out of heap bounds"
|
||||
|
|
|
@ -26,7 +26,7 @@ import com.google.android.material.R as MR
|
|||
import com.google.android.material.button.MaterialButton
|
||||
import com.google.android.material.motion.MotionUtils
|
||||
import org.oxycblt.auxio.ui.RippleFixMaterialButton
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A [MaterialButton] that automatically morphs from a circle to a squircle shape appearance when
|
||||
|
@ -62,12 +62,12 @@ class AnimatedMaterialButton : RippleFixMaterialButton {
|
|||
val targetRadius = if (activated) 0.3f else 0.5f
|
||||
if (!isLaidOut) {
|
||||
// Not laid out, initialize it without animation before drawing.
|
||||
logD("Not laid out, immediately updating corner radius")
|
||||
T.d("Not laid out, immediately updating corner radius")
|
||||
updateCornerRadiusRatio(targetRadius)
|
||||
return
|
||||
}
|
||||
|
||||
logD("Starting corner radius animation")
|
||||
T.d("Starting corner radius animation")
|
||||
animator?.cancel()
|
||||
animator =
|
||||
ValueAnimator.ofFloat(currentCornerRadiusRatio, targetRadius).apply {
|
||||
|
|
|
@ -25,7 +25,7 @@ import kotlin.math.max
|
|||
import org.oxycblt.auxio.databinding.ViewSeekBarBinding
|
||||
import org.oxycblt.auxio.playback.formatDurationDs
|
||||
import org.oxycblt.auxio.util.inflater
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* A wrapper around [Slider] that shows position and duration values and sanitizes input to reduce
|
||||
|
@ -81,11 +81,11 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
|||
// zero, use 1 instead and disable the SeekBar.
|
||||
val to = max(value, 1)
|
||||
isEnabled = value > 0
|
||||
logD("Value sanitization finished [to=$to, enabled=$isEnabled]")
|
||||
T.d("Value sanitization finished [to=$to, enabled=$isEnabled]")
|
||||
// Sanity check 2: If the current value exceeds the new duration value, clamp it
|
||||
// down so that we don't crash and instead have an annoying visual flicker.
|
||||
if (positionDs > to) {
|
||||
logD("Clamping invalid position [current: $positionDs new max: $to]")
|
||||
T.d("Clamping invalid position [current: $positionDs new max: $to]")
|
||||
binding.seekBarSlider.value = to.toFloat()
|
||||
}
|
||||
binding.seekBarSlider.valueTo = to.toFloat()
|
||||
|
@ -93,14 +93,14 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
|
|||
}
|
||||
|
||||
override fun onStartTrackingTouch(slider: Slider) {
|
||||
logD("Starting seek mode")
|
||||
T.d("Starting seek mode")
|
||||
// User has begun seeking, place the SeekBar into a "Suspended" mode in which no
|
||||
// position updates are sent and is indicated by the position value turning accented.
|
||||
isActivated = true
|
||||
}
|
||||
|
||||
override fun onStopTrackingTouch(slider: Slider) {
|
||||
logD("Confirming seek")
|
||||
T.d("Confirming seek")
|
||||
// End of seek event, send off new value to listener.
|
||||
isActivated = false
|
||||
listener?.onSeekConfirmed(slider.value.toLong())
|
||||
|
|
|
@ -39,7 +39,7 @@ import org.oxycblt.auxio.music.Genre
|
|||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.Playlist
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* An adapter that displays search results.
|
||||
|
@ -75,7 +75,7 @@ class SearchAdapter(private val listener: SelectableListListener<Music>) :
|
|||
}
|
||||
|
||||
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
|
||||
logD(position)
|
||||
T.d(position)
|
||||
when (val item = getItem(position)) {
|
||||
is Song -> (holder as SongViewHolder).bind(item, listener)
|
||||
is Album -> (holder as AlbumViewHolder).bind(item, listener)
|
||||
|
|
|
@ -29,7 +29,7 @@ import org.oxycblt.auxio.music.Music
|
|||
import org.oxycblt.auxio.music.Playlist
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.music.info.Name
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Implements the fuzzy-ish searching algorithm used in the search view.
|
||||
|
@ -67,7 +67,7 @@ interface SearchEngine {
|
|||
class SearchEngineImpl @Inject constructor(@ApplicationContext private val context: Context) :
|
||||
SearchEngine {
|
||||
override suspend fun search(items: SearchEngine.Items, query: String): SearchEngine.Items {
|
||||
logD("Launching search for $query")
|
||||
T.d("Launching search for $query")
|
||||
return SearchEngine.Items(
|
||||
songs =
|
||||
items.songs?.searchListImpl(query) { q, song ->
|
||||
|
|
|
@ -61,11 +61,10 @@ import org.oxycblt.auxio.util.collect
|
|||
import org.oxycblt.auxio.util.collectImmediately
|
||||
import org.oxycblt.auxio.util.context
|
||||
import org.oxycblt.auxio.util.getSystemServiceCompat
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
import org.oxycblt.auxio.util.setFullWidthLookup
|
||||
import org.oxycblt.auxio.util.showToast
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* The [ListFragment] providing search functionality for the music library.
|
||||
|
@ -109,11 +108,11 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
|||
getContentLauncher =
|
||||
registerForActivityResult(ActivityResultContracts.GetContent()) { uri ->
|
||||
if (uri == null) {
|
||||
logW("No URI returned from file picker")
|
||||
T.w("No URI returned from file picker")
|
||||
return@registerForActivityResult
|
||||
}
|
||||
|
||||
logD("Received playlist URI $uri")
|
||||
T.d("Received playlist URI $uri")
|
||||
musicModel.importPlaylist(uri, pendingImportTarget)
|
||||
}
|
||||
|
||||
|
@ -140,7 +139,7 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
|||
|
||||
if (!launchedKeyboard) {
|
||||
// Auto-open the keyboard when this view is shown
|
||||
logD("Keyboard is not shown yet")
|
||||
T.d("Keyboard is not shown yet")
|
||||
showKeyboard(this)
|
||||
launchedKeyboard = true
|
||||
}
|
||||
|
@ -185,7 +184,7 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
|||
if (item.itemId != R.id.submenu_filtering) {
|
||||
// Is a change in filter mode and not just a junk submenu click, update
|
||||
// the filtering within SearchViewModel.
|
||||
logD("Filter mode selected")
|
||||
T.d("Filter mode selected")
|
||||
item.isChecked = true
|
||||
searchModel.setFilterOptionId(item.itemId)
|
||||
return true
|
||||
|
@ -223,7 +222,7 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
|||
// I would make it so that the position is only scrolled back to the top when
|
||||
// the query actually changes instead of once every re-creation event, but sadly
|
||||
// that doesn't seem possible.
|
||||
logD("Update finished, scrolling to top")
|
||||
T.d("Update finished, scrolling to top")
|
||||
binding.searchRecycler.scrollToPosition(0)
|
||||
}
|
||||
}
|
||||
|
@ -231,39 +230,39 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
|||
private fun handleShow(show: Show?) {
|
||||
when (show) {
|
||||
is Show.SongDetails -> {
|
||||
logD("Navigating to ${show.song}")
|
||||
T.d("Navigating to ${show.song}")
|
||||
findNavController().navigateSafe(SearchFragmentDirections.showSong(show.song.uid))
|
||||
}
|
||||
is Show.SongAlbumDetails -> {
|
||||
logD("Navigating to the album of ${show.song}")
|
||||
T.d("Navigating to the album of ${show.song}")
|
||||
findNavController()
|
||||
.navigateSafe(SearchFragmentDirections.showAlbum(show.song.album.uid))
|
||||
}
|
||||
is Show.AlbumDetails -> {
|
||||
logD("Navigating to ${show.album}")
|
||||
T.d("Navigating to ${show.album}")
|
||||
findNavController().navigateSafe(SearchFragmentDirections.showAlbum(show.album.uid))
|
||||
}
|
||||
is Show.ArtistDetails -> {
|
||||
logD("Navigating to ${show.artist}")
|
||||
T.d("Navigating to ${show.artist}")
|
||||
findNavController()
|
||||
.navigateSafe(SearchFragmentDirections.showArtist(show.artist.uid))
|
||||
}
|
||||
is Show.SongArtistDecision -> {
|
||||
logD("Navigating to artist choices for ${show.song}")
|
||||
T.d("Navigating to artist choices for ${show.song}")
|
||||
findNavController()
|
||||
.navigateSafe(SearchFragmentDirections.showArtistChoices(show.song.uid))
|
||||
}
|
||||
is Show.AlbumArtistDecision -> {
|
||||
logD("Navigating to artist choices for ${show.album}")
|
||||
T.d("Navigating to artist choices for ${show.album}")
|
||||
findNavController()
|
||||
.navigateSafe(SearchFragmentDirections.showArtistChoices(show.album.uid))
|
||||
}
|
||||
is Show.GenreDetails -> {
|
||||
logD("Navigating to ${show.genre}")
|
||||
T.d("Navigating to ${show.genre}")
|
||||
findNavController().navigateSafe(SearchFragmentDirections.showGenre(show.genre.uid))
|
||||
}
|
||||
is Show.PlaylistDetails -> {
|
||||
logD("Navigating to ${show.playlist}")
|
||||
T.d("Navigating to ${show.playlist}")
|
||||
findNavController()
|
||||
.navigateSafe(SearchFragmentDirections.showPlaylist(show.playlist.uid))
|
||||
}
|
||||
|
@ -297,7 +296,7 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
|||
binding.searchSelectionToolbar.title = getString(R.string.fmt_selected, selected.size)
|
||||
if (binding.searchToolbar.setVisible(R.id.search_selection_toolbar)) {
|
||||
// New selection started, show the keyboard to make selection easier.
|
||||
logD("Significant selection occurred, hiding keyboard")
|
||||
T.d("Significant selection occurred, hiding keyboard")
|
||||
hideKeyboard()
|
||||
}
|
||||
} else {
|
||||
|
@ -310,7 +309,7 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
|||
val directions =
|
||||
when (decision) {
|
||||
is PlaylistDecision.Import -> {
|
||||
logD("Importing playlist")
|
||||
T.d("Importing playlist")
|
||||
pendingImportTarget = decision.target
|
||||
requireNotNull(getContentLauncher) {
|
||||
"Content picker launcher was not available"
|
||||
|
@ -320,7 +319,7 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
|||
return
|
||||
}
|
||||
is PlaylistDecision.Rename -> {
|
||||
logD("Renaming ${decision.playlist}")
|
||||
T.d("Renaming ${decision.playlist}")
|
||||
SearchFragmentDirections.renamePlaylist(
|
||||
decision.playlist.uid,
|
||||
decision.template,
|
||||
|
@ -328,15 +327,15 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
|||
decision.reason)
|
||||
}
|
||||
is PlaylistDecision.Delete -> {
|
||||
logD("Deleting ${decision.playlist}")
|
||||
T.d("Deleting ${decision.playlist}")
|
||||
SearchFragmentDirections.deletePlaylist(decision.playlist.uid)
|
||||
}
|
||||
is PlaylistDecision.Export -> {
|
||||
logD("Exporting ${decision.playlist}")
|
||||
T.d("Exporting ${decision.playlist}")
|
||||
SearchFragmentDirections.exportPlaylist(decision.playlist.uid)
|
||||
}
|
||||
is PlaylistDecision.Add -> {
|
||||
logD("Adding ${decision.songs.size} to a playlist")
|
||||
T.d("Adding ${decision.songs.size} to a playlist")
|
||||
SearchFragmentDirections.addToPlaylist(
|
||||
decision.songs.map { it.uid }.toTypedArray())
|
||||
}
|
||||
|
@ -362,11 +361,11 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
|||
val directions =
|
||||
when (decision) {
|
||||
is PlaybackDecision.PlayFromArtist -> {
|
||||
logD("Launching play from artist dialog for $decision")
|
||||
T.d("Launching play from artist dialog for $decision")
|
||||
SearchFragmentDirections.playFromArtist(decision.song.uid)
|
||||
}
|
||||
is PlaybackDecision.PlayFromGenre -> {
|
||||
logD("Launching play from artist dialog for $decision")
|
||||
T.d("Launching play from artist dialog for $decision")
|
||||
SearchFragmentDirections.playFromGenre(decision.song.uid)
|
||||
}
|
||||
}
|
||||
|
@ -379,7 +378,7 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
|||
* @param view The [View] to focus the keyboard on.
|
||||
*/
|
||||
private fun showKeyboard(view: View) {
|
||||
logD("Launching keyboard")
|
||||
T.d("Launching keyboard")
|
||||
view.apply {
|
||||
requestFocus()
|
||||
postDelayed(200) {
|
||||
|
@ -391,7 +390,7 @@ class SearchFragment : ListFragment<Music, FragmentSearchBinding>() {
|
|||
|
||||
/** Safely hide the keyboard from this view. */
|
||||
private fun hideKeyboard() {
|
||||
logD("Hiding keyboard")
|
||||
T.d("Hiding keyboard")
|
||||
requireNotNull(imm) { "InputMethodManager was not available" }
|
||||
.hideSoftInputFromWindow(requireView().windowToken, InputMethodManager.HIDE_NOT_ALWAYS)
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ import org.oxycblt.auxio.music.device.DeviceLibrary
|
|||
import org.oxycblt.auxio.music.user.UserLibrary
|
||||
import org.oxycblt.auxio.playback.PlaySong
|
||||
import org.oxycblt.auxio.playback.PlaybackSettings
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* An [ViewModel] that keeps performs search operations and tracks their results.
|
||||
|
@ -79,7 +79,7 @@ constructor(
|
|||
|
||||
override fun onMusicChanges(changes: MusicRepository.Changes) {
|
||||
if (changes.deviceLibrary || changes.userLibrary) {
|
||||
logD("Music changed, re-searching library")
|
||||
T.d("Music changed, re-searching library")
|
||||
search(lastQuery)
|
||||
}
|
||||
}
|
||||
|
@ -98,13 +98,13 @@ constructor(
|
|||
val deviceLibrary = musicRepository.deviceLibrary
|
||||
val userLibrary = musicRepository.userLibrary
|
||||
if (query.isNullOrEmpty() || deviceLibrary == null || userLibrary == null) {
|
||||
logD("Cannot search for the current query, aborting")
|
||||
T.d("Cannot search for the current query, aborting")
|
||||
_searchResults.value = listOf()
|
||||
return
|
||||
}
|
||||
|
||||
// Searching is time-consuming, so do it in the background.
|
||||
logD("Searching music library for $query")
|
||||
T.d("Searching music library for $query")
|
||||
currentSearchJob =
|
||||
viewModelScope.launch {
|
||||
_searchResults.value =
|
||||
|
@ -122,7 +122,7 @@ constructor(
|
|||
val items =
|
||||
if (filter == null) {
|
||||
// A nulled filter type means to not filter anything.
|
||||
logD("No filter specified, using entire library")
|
||||
T.d("No filter specified, using entire library")
|
||||
SearchEngine.Items(
|
||||
deviceLibrary.songs,
|
||||
deviceLibrary.albums,
|
||||
|
@ -130,7 +130,7 @@ constructor(
|
|||
deviceLibrary.genres,
|
||||
userLibrary.playlists)
|
||||
} else {
|
||||
logD("Filter specified, reducing library")
|
||||
T.d("Filter specified, reducing library")
|
||||
SearchEngine.Items(
|
||||
songs = if (filter == MusicType.SONGS) deviceLibrary.songs else null,
|
||||
albums = if (filter == MusicType.ALBUMS) deviceLibrary.albums else null,
|
||||
|
@ -143,13 +143,13 @@ constructor(
|
|||
|
||||
return buildList {
|
||||
results.artists?.let {
|
||||
logD("Adding ${it.size} artists to search results")
|
||||
T.d("Adding ${it.size} artists to search results")
|
||||
val header = BasicHeader(R.string.lbl_artists)
|
||||
add(header)
|
||||
addAll(SORT.artists(it))
|
||||
}
|
||||
results.albums?.let {
|
||||
logD("Adding ${it.size} albums to search results")
|
||||
T.d("Adding ${it.size} albums to search results")
|
||||
val header = BasicHeader(R.string.lbl_albums)
|
||||
if (isNotEmpty()) {
|
||||
add(PlainDivider(header))
|
||||
|
@ -159,7 +159,7 @@ constructor(
|
|||
addAll(SORT.albums(it))
|
||||
}
|
||||
results.playlists?.let {
|
||||
logD("Adding ${it.size} playlists to search results")
|
||||
T.d("Adding ${it.size} playlists to search results")
|
||||
val header = BasicHeader(R.string.lbl_playlists)
|
||||
if (isNotEmpty()) {
|
||||
add(PlainDivider(header))
|
||||
|
@ -169,7 +169,7 @@ constructor(
|
|||
addAll(SORT.playlists(it))
|
||||
}
|
||||
results.genres?.let {
|
||||
logD("Adding ${it.size} genres to search results")
|
||||
T.d("Adding ${it.size} genres to search results")
|
||||
val header = BasicHeader(R.string.lbl_genres)
|
||||
if (isNotEmpty()) {
|
||||
add(PlainDivider(header))
|
||||
|
@ -179,7 +179,7 @@ constructor(
|
|||
addAll(SORT.genres(it))
|
||||
}
|
||||
results.songs?.let {
|
||||
logD("Adding ${it.size} songs to search results")
|
||||
T.d("Adding ${it.size} songs to search results")
|
||||
val header = BasicHeader(R.string.lbl_songs)
|
||||
if (isNotEmpty()) {
|
||||
add(PlainDivider(header))
|
||||
|
@ -225,7 +225,7 @@ constructor(
|
|||
R.id.option_filter_all -> null
|
||||
else -> error("Invalid option ID provided")
|
||||
}
|
||||
logD("Updating filter type to $newFilter")
|
||||
T.d("Updating filter type to $newFilter")
|
||||
searchSettings.filterTo = newFilter
|
||||
search(lastQuery)
|
||||
}
|
||||
|
|
|
@ -37,8 +37,8 @@ import org.oxycblt.auxio.settings.ui.IntListPreference
|
|||
import org.oxycblt.auxio.settings.ui.IntListPreferenceDialog
|
||||
import org.oxycblt.auxio.settings.ui.PreferenceHeaderItemDecoration
|
||||
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.systemBarInsetsCompat
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Shared [PreferenceFragmentCompat] used across all preference screens.
|
||||
|
@ -82,7 +82,7 @@ abstract class BasePreferenceFragment(@XmlRes private val screen: Int) :
|
|||
preferenceManager.onDisplayPreferenceDialogListener = this
|
||||
preferenceScreen.children.forEach(::setupPreference)
|
||||
|
||||
logD("Fragment created")
|
||||
T.d("Fragment created")
|
||||
}
|
||||
|
||||
override fun onCreateRecyclerView(
|
||||
|
|
|
@ -29,8 +29,8 @@ import dagger.hilt.android.AndroidEntryPoint
|
|||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.music.MusicViewModel
|
||||
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* The [PreferenceFragmentCompat] that displays the root settings list.
|
||||
|
@ -62,21 +62,21 @@ class RootPreferenceFragment : BasePreferenceFragment(R.xml.preferences_root) {
|
|||
// do one.
|
||||
when (preference.key) {
|
||||
getString(R.string.set_key_ui) -> {
|
||||
logD("Navigating to UI preferences")
|
||||
T.d("Navigating to UI preferences")
|
||||
findNavController().navigateSafe(RootPreferenceFragmentDirections.uiPreferences())
|
||||
}
|
||||
getString(R.string.set_key_personalize) -> {
|
||||
logD("Navigating to personalization preferences")
|
||||
T.d("Navigating to personalization preferences")
|
||||
findNavController()
|
||||
.navigateSafe(RootPreferenceFragmentDirections.personalizePreferences())
|
||||
}
|
||||
getString(R.string.set_key_music) -> {
|
||||
logD("Navigating to music preferences")
|
||||
T.d("Navigating to music preferences")
|
||||
findNavController()
|
||||
.navigateSafe(RootPreferenceFragmentDirections.musicPreferences())
|
||||
}
|
||||
getString(R.string.set_key_audio) -> {
|
||||
logD("Navigating to audio preferences")
|
||||
T.d("Navigating to audio preferences")
|
||||
findNavController().navigateSafe(RootPreferenceFragmentDirections.audioPeferences())
|
||||
}
|
||||
getString(R.string.set_key_reindex) -> musicModel.refresh()
|
||||
|
|
|
@ -22,9 +22,8 @@ import android.content.Context
|
|||
import android.content.SharedPreferences
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.preference.PreferenceManager
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Abstract user configuration information. This interface has no functionality whatsoever. Concrete
|
||||
|
@ -74,19 +73,19 @@ interface Settings<L> {
|
|||
override fun registerListener(listener: L) {
|
||||
if (this.listener == null) {
|
||||
// Registering a listener when it was null prior, attach the callback.
|
||||
logD("Registering shared preference listener")
|
||||
T.d("Registering shared preference listener")
|
||||
sharedPreferences.registerOnSharedPreferenceChangeListener(this)
|
||||
}
|
||||
logD("Registering listener $listener")
|
||||
T.d("Registering listener $listener")
|
||||
this.listener = listener
|
||||
}
|
||||
|
||||
override fun unregisterListener(listener: L) {
|
||||
if (this.listener !== listener) {
|
||||
logW("Given listener was not the current listener.")
|
||||
T.w("Given listener was not the current listener.")
|
||||
return
|
||||
}
|
||||
logD("Unregistering listener $listener")
|
||||
T.d("Unregistering listener $listener")
|
||||
this.listener = null
|
||||
// No longer have a listener, detach from the preferences instance.
|
||||
sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
|
||||
|
@ -97,7 +96,7 @@ interface Settings<L> {
|
|||
key: String?
|
||||
) {
|
||||
// FIXME: Settings initialization firing the listener.
|
||||
logD("Dispatching settings change $key")
|
||||
T.d("Dispatching settings change $key")
|
||||
onSettingChanged(unlikelyToBeNull(key), unlikelyToBeNull(listener))
|
||||
}
|
||||
|
||||
|
|
|
@ -22,8 +22,8 @@ import androidx.navigation.fragment.findNavController
|
|||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.settings.BasePreferenceFragment
|
||||
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Audio settings interface.
|
||||
|
@ -34,7 +34,7 @@ class AudioPreferenceFragment : BasePreferenceFragment(R.xml.preferences_audio)
|
|||
|
||||
override fun onOpenDialogPreference(preference: WrappedDialogPreference) {
|
||||
if (preference.key == getString(R.string.set_key_pre_amp)) {
|
||||
logD("Navigating to pre-amp dialog")
|
||||
T.d("Navigating to pre-amp dialog")
|
||||
findNavController().navigateSafe(AudioPreferenceFragmentDirections.preAmpSettings())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,8 +26,8 @@ import javax.inject.Inject
|
|||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.settings.BasePreferenceFragment
|
||||
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* "Content" settings.
|
||||
|
@ -40,7 +40,7 @@ class MusicPreferenceFragment : BasePreferenceFragment(R.xml.preferences_music)
|
|||
|
||||
override fun onOpenDialogPreference(preference: WrappedDialogPreference) {
|
||||
if (preference.key == getString(R.string.set_key_separators)) {
|
||||
logD("Navigating to separator dialog")
|
||||
T.d("Navigating to separator dialog")
|
||||
findNavController().navigateSafe(MusicPreferenceFragmentDirections.separatorsSettings())
|
||||
}
|
||||
}
|
||||
|
@ -48,10 +48,10 @@ class MusicPreferenceFragment : BasePreferenceFragment(R.xml.preferences_music)
|
|||
override fun onSetupPreference(preference: Preference) {
|
||||
if (preference.key == getString(R.string.set_key_cover_mode) ||
|
||||
preference.key == getString(R.string.set_key_square_covers)) {
|
||||
logD("Configuring cover mode setting")
|
||||
T.d("Configuring cover mode setting")
|
||||
preference.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _, _ ->
|
||||
logD("Cover mode changed, resetting image memory cache")
|
||||
T.d("Cover mode changed, resetting image memory cache")
|
||||
imageLoader.memoryCache?.clear()
|
||||
true
|
||||
}
|
||||
|
|
|
@ -22,8 +22,8 @@ import androidx.navigation.fragment.findNavController
|
|||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.settings.BasePreferenceFragment
|
||||
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Personalization settings interface.
|
||||
|
@ -33,7 +33,7 @@ import org.oxycblt.auxio.util.navigateSafe
|
|||
class PersonalizePreferenceFragment : BasePreferenceFragment(R.xml.preferences_personalize) {
|
||||
override fun onOpenDialogPreference(preference: WrappedDialogPreference) {
|
||||
if (preference.key == getString(R.string.set_key_home_tabs)) {
|
||||
logD("Navigating to home tab dialog")
|
||||
T.d("Navigating to home tab dialog")
|
||||
findNavController().navigateSafe(PersonalizePreferenceFragmentDirections.tabSettings())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -28,8 +28,8 @@ import org.oxycblt.auxio.settings.BasePreferenceFragment
|
|||
import org.oxycblt.auxio.settings.ui.WrappedDialogPreference
|
||||
import org.oxycblt.auxio.ui.UISettings
|
||||
import org.oxycblt.auxio.util.isNight
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.navigateSafe
|
||||
import timber.log.Timber as T
|
||||
|
||||
/**
|
||||
* Display preferences.
|
||||
|
@ -42,7 +42,7 @@ class UIPreferenceFragment : BasePreferenceFragment(R.xml.preferences_ui) {
|
|||
|
||||
override fun onOpenDialogPreference(preference: WrappedDialogPreference) {
|
||||
if (preference.key == getString(R.string.set_key_accent)) {
|
||||
logD("Navigating to accent dialog")
|
||||
T.d("Navigating to accent dialog")
|
||||
findNavController().navigateSafe(UIPreferenceFragmentDirections.accentSettings())
|
||||
}
|
||||
}
|
||||
|
@ -50,25 +50,25 @@ class UIPreferenceFragment : BasePreferenceFragment(R.xml.preferences_ui) {
|
|||
override fun onSetupPreference(preference: Preference) {
|
||||
when (preference.key) {
|
||||
getString(R.string.set_key_theme) -> {
|
||||
logD("Configuring theme setting")
|
||||
T.d("Configuring theme setting")
|
||||
preference.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _, value ->
|
||||
logD("Theme changed, recreating")
|
||||
T.d("Theme changed, recreating")
|
||||
AppCompatDelegate.setDefaultNightMode(value as Int)
|
||||
true
|
||||
}
|
||||
}
|
||||
getString(R.string.set_key_accent) -> {
|
||||
logD("Configuring accent setting")
|
||||
T.d("Configuring accent setting")
|
||||
preference.summary = getString(uiSettings.accent.name)
|
||||
}
|
||||
getString(R.string.set_key_black_theme) -> {
|
||||
logD("Configuring black theme setting")
|
||||
T.d("Configuring black theme setting")
|
||||
preference.onPreferenceChangeListener =
|
||||
Preference.OnPreferenceChangeListener { _, _ ->
|
||||
val activity = requireActivity()
|
||||
if (activity.isNight) {
|
||||
logD("Black theme changed in night mode, recreating")
|
||||
T.d("Black theme changed in night mode, recreating")
|
||||
activity.recreate()
|
||||
}
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue