all: update logging
Improve logging use across the app.
This commit is contained in:
parent
2f85d694d1
commit
3d8d2e0975
31 changed files with 142 additions and 95 deletions
|
@ -46,7 +46,7 @@ import org.oxycblt.auxio.util.canScroll
|
|||
import org.oxycblt.auxio.util.collectWith
|
||||
import org.oxycblt.auxio.util.launch
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.logEOrThrow
|
||||
import org.oxycblt.auxio.util.showToast
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
|
||||
|
@ -125,7 +125,7 @@ class AlbumDetailFragment :
|
|||
override fun onOpenMenu(item: Item, anchor: View) {
|
||||
when (item) {
|
||||
is Song -> musicMenu(anchor, R.menu.menu_album_song_actions, item)
|
||||
else -> logW("Unexpected datatype when opening menu: ${item::class.java}")
|
||||
else -> logEOrThrow("Unexpected datatype when opening menu: ${item::class.java}")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,7 +204,7 @@ class AlbumDetailFragment :
|
|||
.navigate(AlbumDetailFragmentDirections.actionShowArtist(item.id))
|
||||
}
|
||||
null -> {}
|
||||
else -> logW("Unsupported navigation item ${item::class.java}")
|
||||
else -> logEOrThrow("Unexpected navigation item ${item::class.java}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ import org.oxycblt.auxio.util.applySpans
|
|||
import org.oxycblt.auxio.util.collectWith
|
||||
import org.oxycblt.auxio.util.launch
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.logEOrThrow
|
||||
import org.oxycblt.auxio.util.showToast
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
|
||||
|
@ -119,7 +119,7 @@ class ArtistDetailFragment :
|
|||
when (item) {
|
||||
is Song -> musicMenu(anchor, R.menu.menu_artist_song_actions, item)
|
||||
is Album -> musicMenu(anchor, R.menu.menu_artist_album_actions, item)
|
||||
else -> logW("Unexpected datatype when opening menu: ${item::class.java}")
|
||||
else -> logEOrThrow("Unexpected datatype when opening menu: ${item::class.java}")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,7 +179,7 @@ class ArtistDetailFragment :
|
|||
}
|
||||
}
|
||||
null -> {}
|
||||
else -> logW("Unsupported navigation item ${item::class.java}")
|
||||
else -> logEOrThrow("Unexpected navigation item ${item::class.java}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -156,55 +156,55 @@ class DetailViewModel(application: Application) :
|
|||
|
||||
private fun generateDetailSong(song: Song) {
|
||||
viewModelScope.launch {
|
||||
_currentSong.value =
|
||||
withContext(Dispatchers.IO) {
|
||||
val extractor = MediaExtractor()
|
||||
_currentSong.value = withContext(Dispatchers.IO) { generateDetailSongImpl(song) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateDetailSongImpl(song: Song): DetailSong {
|
||||
val extractor = MediaExtractor()
|
||||
|
||||
try {
|
||||
extractor.setDataSource(application, song.uri, emptyMap())
|
||||
} catch (e: Exception) {
|
||||
logW("Unable to extract song attributes.")
|
||||
logW(e.stackTraceToString())
|
||||
return DetailSong(song, null, null, song.mimeType)
|
||||
}
|
||||
|
||||
val format = extractor.getTrackFormat(0)
|
||||
|
||||
val bitrate =
|
||||
try {
|
||||
format.getInteger(MediaFormat.KEY_BIT_RATE) / 1000 // bps -> kbps
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
val sampleRate =
|
||||
try {
|
||||
format.getInteger(MediaFormat.KEY_SAMPLE_RATE)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
val resolvedMimeType =
|
||||
if (song.mimeType.fromFormat != null) {
|
||||
// ExoPlayer was already able to populate the format.
|
||||
song.mimeType
|
||||
} else {
|
||||
val formatMimeType =
|
||||
try {
|
||||
@Suppress("BlockingMethodInNonBlockingContext")
|
||||
extractor.setDataSource(application, song.uri, emptyMap())
|
||||
format.getString(MediaFormat.KEY_MIME)
|
||||
} catch (e: Exception) {
|
||||
logW("Unable to extract song attributes.")
|
||||
logW(e.stackTraceToString())
|
||||
return@withContext DetailSong(song, null, null, song.mimeType)
|
||||
null
|
||||
}
|
||||
|
||||
val format = extractor.getTrackFormat(0)
|
||||
// Ensure that we don't include the functionally useless
|
||||
// "audio/raw" mime type
|
||||
MimeType(song.mimeType.fromExtension, formatMimeType)
|
||||
}
|
||||
|
||||
val bitrate =
|
||||
try {
|
||||
format.getInteger(MediaFormat.KEY_BIT_RATE) / 1000 // bps -> kbps
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
val sampleRate =
|
||||
try {
|
||||
format.getInteger(MediaFormat.KEY_SAMPLE_RATE)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
val resolvedMimeType =
|
||||
if (song.mimeType.fromFormat != null) {
|
||||
// ExoPlayer was already able to populate the format.
|
||||
song.mimeType
|
||||
} else {
|
||||
val formatMimeType =
|
||||
try {
|
||||
format.getString(MediaFormat.KEY_MIME)
|
||||
} catch (e: Exception) {
|
||||
null
|
||||
}
|
||||
|
||||
// Ensure that we don't include the functionally useless
|
||||
// "audio/raw" mime type
|
||||
MimeType(song.mimeType.fromExtension, formatMimeType)
|
||||
}
|
||||
|
||||
DetailSong(song, bitrate, sampleRate, resolvedMimeType)
|
||||
}
|
||||
}
|
||||
return DetailSong(song, bitrate, sampleRate, resolvedMimeType)
|
||||
}
|
||||
|
||||
private fun refreshAlbumData(album: Album) {
|
||||
|
@ -255,6 +255,7 @@ class DetailViewModel(application: Application) :
|
|||
if (library != null) {
|
||||
val song = currentSong.value
|
||||
if (song != null) {
|
||||
logD("Song changed, refreshing data")
|
||||
val newSong = library.sanitize(song.song)
|
||||
if (newSong != null) {
|
||||
generateDetailSong(newSong)
|
||||
|
@ -263,6 +264,7 @@ class DetailViewModel(application: Application) :
|
|||
|
||||
val album = currentAlbum.value
|
||||
if (album != null) {
|
||||
logD("Album changed, refreshing data")
|
||||
val newAlbum = library.sanitize(album).also { _currentAlbum.value = it }
|
||||
if (newAlbum != null) {
|
||||
refreshAlbumData(newAlbum)
|
||||
|
@ -271,6 +273,7 @@ class DetailViewModel(application: Application) :
|
|||
|
||||
val artist = currentArtist.value
|
||||
if (artist != null) {
|
||||
logD("Artist changed, refreshing data")
|
||||
val newArtist = library.sanitize(artist).also { _currentArtist.value = it }
|
||||
if (newArtist != null) {
|
||||
refreshArtistData(newArtist)
|
||||
|
|
|
@ -44,7 +44,7 @@ import org.oxycblt.auxio.util.applySpans
|
|||
import org.oxycblt.auxio.util.collectWith
|
||||
import org.oxycblt.auxio.util.launch
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.logEOrThrow
|
||||
import org.oxycblt.auxio.util.showToast
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
|
||||
|
@ -120,7 +120,7 @@ class GenreDetailFragment :
|
|||
override fun onOpenMenu(item: Item, anchor: View) {
|
||||
when (item) {
|
||||
is Song -> musicMenu(anchor, R.menu.menu_song_actions, item)
|
||||
else -> logW("Unexpected datatype when opening menu: ${item::class.java}")
|
||||
else -> logEOrThrow("Unexpected datatype when opening menu: ${item::class.java}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -60,7 +60,6 @@ import org.oxycblt.auxio.util.launch
|
|||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logE
|
||||
import org.oxycblt.auxio.util.logTraceOrThrow
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.textSafe
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
|
||||
|
@ -282,7 +281,7 @@ class HomeFragment : ViewBindingFragment<FragmentHomeBinding>(), Toolbar.OnMenuI
|
|||
is Indexer.State.Complete -> handleIndexerResponse(binding, state.response)
|
||||
is Indexer.State.Indexing -> handleIndexingState(binding, state.indexing)
|
||||
null -> {
|
||||
logW("Indexer is in indeterminate state, doing nothing")
|
||||
logD("Indexer is in indeterminate state, doing nothing")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -128,6 +128,7 @@ class HomeViewModel : ViewModel(), SettingsManager.Callback, MusicStore.Callback
|
|||
* begins to fast scroll.
|
||||
*/
|
||||
fun updateFastScrolling(scrolling: Boolean) {
|
||||
logD("Updating fast scrolling state: $scrolling")
|
||||
_isFastScrolling.value = scrolling
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.oxycblt.auxio.ui.Sort
|
|||
import org.oxycblt.auxio.ui.SyncBackingData
|
||||
import org.oxycblt.auxio.util.formatDuration
|
||||
import org.oxycblt.auxio.util.launch
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.logEOrThrow
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
|
||||
/**
|
||||
|
@ -86,7 +86,7 @@ class AlbumListFragment : HomeListFragment<Album>() {
|
|||
override fun onOpenMenu(item: Item, anchor: View) {
|
||||
when (item) {
|
||||
is Album -> musicMenu(anchor, R.menu.menu_album_actions, item)
|
||||
else -> logW("Unexpected datatype when opening menu: ${item::class.java}")
|
||||
else -> logEOrThrow("Unexpected datatype when opening menu: ${item::class.java}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.oxycblt.auxio.ui.Sort
|
|||
import org.oxycblt.auxio.ui.SyncBackingData
|
||||
import org.oxycblt.auxio.util.formatDuration
|
||||
import org.oxycblt.auxio.util.launch
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.logEOrThrow
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
|
||||
/**
|
||||
|
@ -80,7 +80,7 @@ class ArtistListFragment : HomeListFragment<Artist>() {
|
|||
override fun onOpenMenu(item: Item, anchor: View) {
|
||||
when (item) {
|
||||
is Artist -> musicMenu(anchor, R.menu.menu_genre_artist_actions, item)
|
||||
else -> logW("Unexpected datatype when opening menu: ${item::class.java}")
|
||||
else -> logEOrThrow("Unexpected datatype when opening menu: ${item::class.java}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ import org.oxycblt.auxio.ui.Sort
|
|||
import org.oxycblt.auxio.ui.SyncBackingData
|
||||
import org.oxycblt.auxio.util.formatDuration
|
||||
import org.oxycblt.auxio.util.launch
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.logEOrThrow
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
|
||||
/**
|
||||
|
@ -80,7 +80,7 @@ class GenreListFragment : HomeListFragment<Genre>() {
|
|||
override fun onOpenMenu(item: Item, anchor: View) {
|
||||
when (item) {
|
||||
is Genre -> musicMenu(anchor, R.menu.menu_genre_artist_actions, item)
|
||||
else -> logW("Unexpected datatype when opening menu: ${item::class.java}")
|
||||
else -> logEOrThrow("Unexpected datatype when opening menu: ${item::class.java}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,7 +31,7 @@ import org.oxycblt.auxio.ui.Sort
|
|||
import org.oxycblt.auxio.ui.SyncBackingData
|
||||
import org.oxycblt.auxio.util.formatDuration
|
||||
import org.oxycblt.auxio.util.launch
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.logEOrThrow
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
|
||||
/**
|
||||
|
@ -87,7 +87,7 @@ class SongListFragment : HomeListFragment<Song>() {
|
|||
override fun onOpenMenu(item: Item, anchor: View) {
|
||||
when (item) {
|
||||
is Song -> musicMenu(anchor, R.menu.menu_song_actions, item)
|
||||
else -> logW("Unexpected datatype when opening menu: ${item::class.java}")
|
||||
else -> logEOrThrow("Unexpected datatype when opening menu: ${item::class.java}")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.oxycblt.auxio.music.Genre
|
|||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.settings.SettingsManager
|
||||
import org.oxycblt.auxio.util.getColorStateListSafe
|
||||
import org.oxycblt.auxio.util.logD
|
||||
|
||||
/**
|
||||
* Effectively a super-charged [StyledImageView].
|
||||
|
|
|
@ -118,6 +118,7 @@ class Indexer {
|
|||
* the indexing process to re-index music.
|
||||
*/
|
||||
fun requestReindex() {
|
||||
logD("Requesting reindex")
|
||||
for (callback in callbacks) {
|
||||
callback.onRequestReindex()
|
||||
}
|
||||
|
@ -130,6 +131,7 @@ class Indexer {
|
|||
* corrupt the current state.
|
||||
*/
|
||||
fun cancelLast() {
|
||||
logD("Cancelling last job")
|
||||
synchronized(this) {
|
||||
currentGeneration++
|
||||
emitIndexing(null, currentGeneration)
|
||||
|
|
|
@ -90,6 +90,7 @@ class IndexerService : Service(), Indexer.Callback {
|
|||
is Indexer.State.Complete -> {
|
||||
if (state.response is Indexer.Response.Ok &&
|
||||
state.response.library != musicStore.library) {
|
||||
logD("Applying new library")
|
||||
// Load was completed successfully, so apply the new library if we
|
||||
// have not already.
|
||||
musicStore.library = state.response.library
|
||||
|
@ -174,6 +175,7 @@ private class IndexerNotification(private val context: Context) :
|
|||
fun updateIndexingState(indexing: Indexer.Indexing): Boolean {
|
||||
when (indexing) {
|
||||
is Indexer.Indexing.Indeterminate -> {
|
||||
logD("Updating state to $indexing")
|
||||
setContentText(context.getString(R.string.lbl_indexing))
|
||||
setProgress(0, 0, true)
|
||||
return true
|
||||
|
@ -181,6 +183,7 @@ private class IndexerNotification(private val context: Context) :
|
|||
is Indexer.Indexing.Songs -> {
|
||||
// Only update the notification every 50 songs to prevent excessive updates.
|
||||
if (indexing.current % 50 == 0) {
|
||||
logD("Updating state to $indexing")
|
||||
setContentText(
|
||||
context.getString(R.string.fmt_indexing, indexing.current, indexing.total))
|
||||
setProgress(indexing.total, indexing.current, false)
|
||||
|
|
|
@ -23,6 +23,7 @@ import android.database.Cursor
|
|||
import android.net.Uri
|
||||
import android.provider.MediaStore
|
||||
import androidx.core.text.isDigitsOnly
|
||||
import org.oxycblt.auxio.util.logD
|
||||
|
||||
/** Shortcut for making a [ContentResolver] query with less superfluous arguments. */
|
||||
fun ContentResolver.queryCursor(
|
||||
|
|
|
@ -113,9 +113,11 @@ val StorageVolume.directoryCompat: String?
|
|||
@SuppressLint("NewApi")
|
||||
fun StorageVolume.getDescriptionCompat(context: Context): String = getDescription(context)
|
||||
|
||||
/** If this volume is the primary volume. May still be removable storage. */
|
||||
val StorageVolume.isPrimaryCompat: Boolean
|
||||
@SuppressLint("NewApi") get() = isPrimary
|
||||
|
||||
/** If this volume is emulated. */
|
||||
val StorageVolume.isEmulatedCompat: Boolean
|
||||
@SuppressLint("NewApi") get() = isEmulated
|
||||
|
||||
|
|
|
@ -167,8 +167,6 @@ class MusicDirsDialog :
|
|||
DocumentsContract.buildDocumentUriUsingTree(
|
||||
uri, DocumentsContract.getTreeDocumentId(uri))
|
||||
|
||||
logD(uri)
|
||||
|
||||
// Turn it into a semi-usable path
|
||||
val treeUri = DocumentsContract.getTreeDocumentId(docUri)
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import kotlin.math.max
|
|||
import org.oxycblt.auxio.databinding.ViewSeekBarBinding
|
||||
import org.oxycblt.auxio.util.formatDuration
|
||||
import org.oxycblt.auxio.util.inflater
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.textSafe
|
||||
|
||||
/**
|
||||
|
@ -97,6 +98,7 @@ constructor(
|
|||
// 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 (positionSecs > to) {
|
||||
logD("Clamping invalid position [current: $positionSecs new max: $to]")
|
||||
binding.seekBarSlider.value = to.toFloat()
|
||||
}
|
||||
|
||||
|
@ -105,12 +107,14 @@ constructor(
|
|||
}
|
||||
|
||||
override fun onStartTrackingTouch(slider: Slider) {
|
||||
logD("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")
|
||||
// End of seek event, send off new value to callback.
|
||||
isActivated = false
|
||||
callback?.seekTo(slider.value.toLong())
|
||||
|
|
|
@ -30,7 +30,6 @@ import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
|||
import org.oxycblt.auxio.settings.SettingsManager
|
||||
import org.oxycblt.auxio.util.clamp
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.unlikelyToBeNull
|
||||
|
||||
/**
|
||||
|
@ -65,7 +64,7 @@ class ReplayGainAudioProcessor : BaseAudioProcessor() {
|
|||
*/
|
||||
fun applyReplayGain(metadata: Metadata?) {
|
||||
if (settingsManager.replayGainMode == ReplayGainMode.OFF) {
|
||||
logW("ReplayGain not enabled")
|
||||
logD("ReplayGain not enabled")
|
||||
volume = 1f
|
||||
return
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import android.database.sqlite.SQLiteDatabase
|
|||
import android.database.sqlite.SQLiteOpenHelper
|
||||
import android.os.Build
|
||||
import android.os.storage.StorageManager
|
||||
import android.util.Log
|
||||
import androidx.core.content.edit
|
||||
import org.oxycblt.auxio.music.Directory
|
||||
import org.oxycblt.auxio.music.directoryCompat
|
||||
|
@ -37,6 +38,8 @@ import org.oxycblt.auxio.util.queryAll
|
|||
|
||||
fun handleAccentCompat(prefs: SharedPreferences): Accent {
|
||||
if (prefs.contains(OldKeys.KEY_ACCENT2)) {
|
||||
Log.d("SettingsCompat", "Migrating ${OldKeys.KEY_ACCENT2}")
|
||||
|
||||
var accent = prefs.getInt(OldKeys.KEY_ACCENT2, 5)
|
||||
|
||||
// Blue grey was merged with Light Blue in 2.0.0
|
||||
|
@ -62,6 +65,8 @@ fun handleAccentCompat(prefs: SharedPreferences): Accent {
|
|||
}
|
||||
|
||||
if (prefs.contains(OldKeys.KEY_ACCENT3)) {
|
||||
Log.d("SettingsCompat", "Migrating ${OldKeys.KEY_ACCENT3}")
|
||||
|
||||
var accent = prefs.getInt(OldKeys.KEY_ACCENT3, 5)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
// Accents were previously frozen as soon as the OS was updated to android twelve,
|
||||
|
@ -82,7 +87,8 @@ fun handleAccentCompat(prefs: SharedPreferences): Accent {
|
|||
}
|
||||
|
||||
/**
|
||||
* Converts paths from the old excluded directory database to a list of modern [Dir] instances.
|
||||
* Converts paths from the old excluded directory database to a list of modern [Directory]
|
||||
* instances.
|
||||
*
|
||||
* Historically, Auxio used an excluded directory database shamelessly ripped from Phonograph. This
|
||||
* was a dumb idea, as the choice of a full-blown database for a few paths was overkill, version
|
||||
|
@ -93,6 +99,7 @@ fun handleAccentCompat(prefs: SharedPreferences): Accent {
|
|||
* rolled into this conversion.
|
||||
*/
|
||||
fun handleExcludedCompat(context: Context, storageManager: StorageManager): List<Directory> {
|
||||
Log.d("SettingsCompat", "Migrating old excluded database")
|
||||
val db = LegacyExcludedDatabase(context)
|
||||
// /storage/emulated/0 (the old path prefix) should correspond to primary *emulated* storage.
|
||||
val primaryVolume =
|
||||
|
|
|
@ -33,7 +33,7 @@ class SettingsFragment : ViewBindingFragment<FragmentSettingsBinding>() {
|
|||
FragmentSettingsBinding.inflate(inflater)
|
||||
|
||||
override fun onBindingCreated(binding: FragmentSettingsBinding, savedInstanceState: Bundle?) {
|
||||
binding.settingsToolbar.setNavigationOnClickListener { findNavController().navigateUp() }
|
||||
binding.settingsAppbar.liftOnScrollTargetViewId = androidx.preference.R.id.recycler_view
|
||||
binding.settingsToolbar.setNavigationOnClickListener { findNavController().navigateUp() }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -291,6 +291,8 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) :
|
|||
panelRange = measuredHeight - barView.measuredHeight
|
||||
|
||||
if (!isLaidOut) {
|
||||
logD("Doing initial panel layout")
|
||||
|
||||
// This is our first layout, so make sure we know what offset we should work with
|
||||
// before we measure our content
|
||||
panelOffset =
|
||||
|
@ -383,6 +385,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) :
|
|||
// not apply any window insets at all, which results in scroll desynchronization on
|
||||
// certain views. This is considered tolerable as the other options are to convert
|
||||
// the playback fragments to views, which is not nice.
|
||||
logD("Readjusting window insets")
|
||||
val bars = insets.getSystemBarInsetsCompat(this)
|
||||
val consumedByPanel = computePanelTopPosition(panelOffset) - measuredHeight
|
||||
val adjustedBottomInset = (consumedByPanel + bars.bottom).coerceAtLeast(0)
|
||||
|
@ -495,9 +498,11 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyle: Int = 0) :
|
|||
|
||||
private fun setPanelStateInternal(state: PanelState) {
|
||||
if (panelState == state) {
|
||||
logD("State is already $state, not applying")
|
||||
return
|
||||
}
|
||||
|
||||
logD("new state: $state")
|
||||
panelState = state
|
||||
|
||||
sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED)
|
||||
|
|
|
@ -51,18 +51,15 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
|||
add(topDivider)
|
||||
add(bottomDivider)
|
||||
}
|
||||
}
|
||||
|
||||
addOnScrollListener(
|
||||
object : RecyclerView.OnScrollListener() {
|
||||
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
|
||||
super.onScrolled(recyclerView, dx, dy)
|
||||
override fun onScrolled(dx: Int, dy: Int) {
|
||||
super.onScrolled(dx, dy)
|
||||
|
||||
val manager = recyclerView.layoutManager as LinearLayoutManager
|
||||
topDivider.isInvisible = manager.findFirstCompletelyVisibleItemPosition() < 1
|
||||
bottomDivider.isInvisible =
|
||||
manager.findLastCompletelyVisibleItemPosition() == (manager.itemCount - 1)
|
||||
}
|
||||
})
|
||||
val manager = layoutManager as LinearLayoutManager
|
||||
topDivider.isInvisible = manager.findFirstCompletelyVisibleItemPosition() < 1
|
||||
bottomDivider.isInvisible =
|
||||
manager.findLastCompletelyVisibleItemPosition() == (manager.itemCount - 1)
|
||||
}
|
||||
|
||||
override fun onMeasure(widthSpec: Int, heightSpec: Int) {
|
||||
|
|
|
@ -29,7 +29,6 @@ import androidx.core.content.res.ResourcesCompat
|
|||
import androidx.core.view.updatePadding
|
||||
import com.google.android.material.appbar.AppBarLayout
|
||||
import org.oxycblt.auxio.util.getSystemBarInsetsCompat
|
||||
import org.oxycblt.auxio.util.logW
|
||||
|
||||
/**
|
||||
* An [AppBarLayout] that fixes a bug with the default implementation where the lifted state will
|
||||
|
@ -90,7 +89,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
|
|||
if (liftOnScrollTargetViewId != ResourcesCompat.ID_NULL) {
|
||||
scrollingChild = (parent as ViewGroup).findViewById(liftOnScrollTargetViewId)
|
||||
} else {
|
||||
logW("liftOnScrollTargetViewId was not specified, ignoring scroll events")
|
||||
error("liftOnScrollTargetViewId was not specified")
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -29,7 +29,8 @@ import org.oxycblt.auxio.music.Artist
|
|||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.logD
|
||||
import org.oxycblt.auxio.util.logEOrThrow
|
||||
import org.oxycblt.auxio.util.showToast
|
||||
|
||||
abstract class MenuFragment<T : ViewBinding> : ViewBindingFragment<T>() {
|
||||
|
@ -39,6 +40,8 @@ abstract class MenuFragment<T : ViewBinding> : ViewBindingFragment<T>() {
|
|||
protected val navModel: NavigationViewModel by activityViewModels()
|
||||
|
||||
protected fun musicMenu(anchor: View, @MenuRes menuRes: Int, song: Song) {
|
||||
logD("Launching new song menu: ${song.rawName}")
|
||||
|
||||
musicMenuImpl(anchor, menuRes) { id ->
|
||||
when (id) {
|
||||
R.id.action_play_next -> {
|
||||
|
@ -59,7 +62,7 @@ abstract class MenuFragment<T : ViewBinding> : ViewBindingFragment<T>() {
|
|||
navModel.mainNavigateTo(MainNavigationAction.SongDetails(song))
|
||||
}
|
||||
else -> {
|
||||
logW("Unknown menu item selected")
|
||||
logEOrThrow("Unexpected menu item selected")
|
||||
return@musicMenuImpl false
|
||||
}
|
||||
}
|
||||
|
@ -69,6 +72,8 @@ abstract class MenuFragment<T : ViewBinding> : ViewBindingFragment<T>() {
|
|||
}
|
||||
|
||||
protected fun musicMenu(anchor: View, @MenuRes menuRes: Int, album: Album) {
|
||||
logD("Launching new album menu: ${album.rawName}")
|
||||
|
||||
musicMenuImpl(anchor, menuRes) { id ->
|
||||
when (id) {
|
||||
R.id.action_play -> {
|
||||
|
@ -89,7 +94,7 @@ abstract class MenuFragment<T : ViewBinding> : ViewBindingFragment<T>() {
|
|||
navModel.exploreNavigateTo(album.artist)
|
||||
}
|
||||
else -> {
|
||||
logW("Unknown menu item selected")
|
||||
logEOrThrow("Unexpected menu item selected")
|
||||
return@musicMenuImpl false
|
||||
}
|
||||
}
|
||||
|
@ -99,6 +104,8 @@ abstract class MenuFragment<T : ViewBinding> : ViewBindingFragment<T>() {
|
|||
}
|
||||
|
||||
protected fun musicMenu(anchor: View, @MenuRes menuRes: Int, artist: Artist) {
|
||||
logD("Launching new artist menu: ${artist.rawName}")
|
||||
|
||||
musicMenuImpl(anchor, menuRes) { id ->
|
||||
when (id) {
|
||||
R.id.action_play -> {
|
||||
|
@ -116,7 +123,7 @@ abstract class MenuFragment<T : ViewBinding> : ViewBindingFragment<T>() {
|
|||
requireContext().showToast(R.string.lbl_queue_added)
|
||||
}
|
||||
else -> {
|
||||
logW("Unknown menu item selected")
|
||||
logEOrThrow("Unexpected menu item selected")
|
||||
return@musicMenuImpl false
|
||||
}
|
||||
}
|
||||
|
@ -126,6 +133,8 @@ abstract class MenuFragment<T : ViewBinding> : ViewBindingFragment<T>() {
|
|||
}
|
||||
|
||||
protected fun musicMenu(anchor: View, @MenuRes menuRes: Int, genre: Genre) {
|
||||
logD("Launching new genre menu: ${genre.rawName}")
|
||||
|
||||
musicMenuImpl(anchor, menuRes) { id ->
|
||||
when (id) {
|
||||
R.id.action_play -> {
|
||||
|
@ -143,7 +152,7 @@ abstract class MenuFragment<T : ViewBinding> : ViewBindingFragment<T>() {
|
|||
requireContext().showToast(R.string.lbl_queue_added)
|
||||
}
|
||||
else -> {
|
||||
logW("Unknown menu item selected")
|
||||
logEOrThrow("Unexpected menu item selected")
|
||||
return@musicMenuImpl false
|
||||
}
|
||||
}
|
||||
|
@ -166,6 +175,7 @@ abstract class MenuFragment<T : ViewBinding> : ViewBindingFragment<T>() {
|
|||
|
||||
protected fun menu(anchor: View, @MenuRes menuRes: Int, block: PopupMenu.() -> Unit) {
|
||||
if (currentMenu != null) {
|
||||
logD("Menu already present, not launching")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import kotlinx.coroutines.flow.MutableStateFlow
|
|||
import kotlinx.coroutines.flow.StateFlow
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.util.logD
|
||||
|
||||
/**
|
||||
* A ViewModel that handles complicated navigation situations.
|
||||
|
@ -43,23 +44,35 @@ class NavigationViewModel : ViewModel() {
|
|||
|
||||
/** Notify MainFragment to navigate to the location outlined in [MainNavigationAction]. */
|
||||
fun mainNavigateTo(action: MainNavigationAction) {
|
||||
if (_mainNavigationAction.value != null) return
|
||||
if (_mainNavigationAction.value != null) {
|
||||
logD("Already navigating, not doing main action")
|
||||
return
|
||||
}
|
||||
|
||||
logD("Navigating with action $action")
|
||||
_mainNavigationAction.value = action
|
||||
}
|
||||
|
||||
/** Mark that the main navigation process is done. */
|
||||
fun finishMainNavigation() {
|
||||
logD("Finishing main navigation process")
|
||||
_mainNavigationAction.value = null
|
||||
}
|
||||
|
||||
/** Navigate to an item's detail menu, whether a song/album/artist */
|
||||
fun exploreNavigateTo(item: Music) {
|
||||
if (_exploreNavigationItem.value != null) return
|
||||
if (_exploreNavigationItem.value != null) {
|
||||
logD("Already navigation, not doing explore action")
|
||||
return
|
||||
}
|
||||
|
||||
logD("Navigating to ${item.rawName}")
|
||||
_exploreNavigationItem.value = item
|
||||
}
|
||||
|
||||
/** Mark that the item navigation process is done. */
|
||||
fun finishExploreNavigation() {
|
||||
logD("Finishing explore navigation process")
|
||||
_exploreNavigationItem.value = null
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,7 @@ import org.oxycblt.auxio.music.Artist
|
|||
import org.oxycblt.auxio.music.Genre
|
||||
import org.oxycblt.auxio.music.Music
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.util.logW
|
||||
import org.oxycblt.auxio.util.logEOrThrow
|
||||
|
||||
/**
|
||||
* A data class representing the sort modes used in Auxio.
|
||||
|
@ -74,19 +74,19 @@ sealed class Sort(open val isAscending: Boolean) {
|
|||
}
|
||||
|
||||
open fun songsInPlace(songs: MutableList<Song>) {
|
||||
logW("This sort is not supported for songs")
|
||||
logEOrThrow("This sort is not supported for songs")
|
||||
}
|
||||
|
||||
open fun albumsInPlace(albums: MutableList<Album>) {
|
||||
logW("This sort is not supported for albums")
|
||||
logEOrThrow("This sort is not supported for albums")
|
||||
}
|
||||
|
||||
open fun artistsInPlace(artists: MutableList<Artist>) {
|
||||
logW("This sort is not supported for artists")
|
||||
logEOrThrow("This sort is not supported for artists")
|
||||
}
|
||||
|
||||
open fun genresInPlace(genres: MutableList<Genre>) {
|
||||
logW("This sort is not supported for genres")
|
||||
logEOrThrow("This sort is not supported for genres")
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -131,7 +131,7 @@ class Accent private constructor(val index: Int) {
|
|||
companion object {
|
||||
fun from(index: Int): Accent {
|
||||
if (index > (MAX - 1)) {
|
||||
logW("Account outside of bounds [idx: $index, max: $MAX")
|
||||
logW("Account outside of bounds [idx: $index, max: $MAX]")
|
||||
return Accent(5)
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,6 @@ import org.oxycblt.auxio.R
|
|||
*/
|
||||
fun View.disableDropShadowCompat() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
|
||||
logD("Disabling drop shadows")
|
||||
val transparent = context.getColorSafe(android.R.color.transparent)
|
||||
outlineAmbientShadowColor = transparent
|
||||
outlineSpotShadowColor = transparent
|
||||
|
|
|
@ -52,7 +52,7 @@ fun Any.logE(msg: String) = Log.e(autoTag, msg)
|
|||
*/
|
||||
fun Any.logEOrThrow(msg: String) {
|
||||
if (BuildConfig.DEBUG) {
|
||||
error("${autoTag}: $msg")
|
||||
error(msg)
|
||||
} else {
|
||||
logE(msg)
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
|||
import org.oxycblt.auxio.playback.state.RepeatMode
|
||||
import org.oxycblt.auxio.settings.SettingsManager
|
||||
import org.oxycblt.auxio.util.getDimenSizeSafe
|
||||
import org.oxycblt.auxio.util.logD
|
||||
|
||||
/**
|
||||
* A wrapper around each [WidgetProvider] that plugs into the main Auxio process and updates the
|
||||
|
@ -67,6 +68,7 @@ class WidgetComponent(private val context: Context) :
|
|||
// possible.
|
||||
val song = playbackManager.song
|
||||
if (song == null) {
|
||||
logD("No song, resetting widget")
|
||||
widget.update(context, null)
|
||||
return
|
||||
}
|
||||
|
@ -87,6 +89,8 @@ class WidgetComponent(private val context: Context) :
|
|||
// - After Android 12, the widget has round edges, so we need to round out
|
||||
// the album art. I dislike this, but it's mainly for stylistic cohesion.
|
||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
this@WidgetComponent.logD("Doing API 31 cover load")
|
||||
|
||||
val metrics = context.resources.displayMetrics
|
||||
|
||||
// Use RoundedCornersTransformation. This is because our hack to get a 1:1
|
||||
|
@ -106,6 +110,7 @@ class WidgetComponent(private val context: Context) :
|
|||
// bitmap on very large screens.
|
||||
.size(minOf(metrics.widthPixels, metrics.heightPixels, 1024))
|
||||
} else {
|
||||
this@WidgetComponent.logD("Doing API 21 cover load")
|
||||
// Note: Explicitly use the "original" size as without it the scaling logic
|
||||
// in coil breaks down and results in an error.
|
||||
builder.size(Size.ORIGINAL)
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
app:liftOnScroll="true"
|
||||
app:liftOnScrollTargetViewId="@id/detail_recycler">
|
||||
|
||||
<!-- FIXME: Not every detail view has actions -->
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/detail_toolbar"
|
||||
|
|
Loading…
Reference in a new issue