Cleanup code
Do some code cleanup.
This commit is contained in:
parent
824ac56bfa
commit
ba79ac0001
16 changed files with 51 additions and 40 deletions
|
@ -30,6 +30,7 @@ fun Any.logE(msg: String) {
|
|||
|
||||
/**
|
||||
* Get a non-nullable name, used so that logs will always show up in the console.
|
||||
* This also applies a special "Auxio" prefix so that messages can be filtered to just from the main codebase.
|
||||
* @return The name of the object, otherwise "Anonymous Object"
|
||||
*/
|
||||
private fun Any.getName(): String = this::class.simpleName ?: "Anonymous Object"
|
||||
private fun Any.getName(): String = "Auxio.${this::class.simpleName ?: "Anonymous Object"}"
|
||||
|
|
|
@ -38,6 +38,8 @@ class MainActivity : AppCompatActivity() {
|
|||
if (isEdgeOn()) {
|
||||
setupEdgeToEdge(binding)
|
||||
}
|
||||
|
||||
logD("Activity created.")
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
|
|
|
@ -16,7 +16,6 @@ import androidx.navigation.fragment.findNavController
|
|||
import com.google.android.material.bottomnavigation.LabelVisibilityMode
|
||||
import org.oxycblt.auxio.databinding.FragmentMainBinding
|
||||
import org.oxycblt.auxio.detail.DetailViewModel
|
||||
import org.oxycblt.auxio.music.MusicStore
|
||||
import org.oxycblt.auxio.music.Song
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.ui.Accent
|
||||
|
@ -36,18 +35,9 @@ class MainFragment : Fragment() {
|
|||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
savedInstanceState: Bundle?
|
||||
): View? {
|
||||
): View {
|
||||
val binding = FragmentMainBinding.inflate(inflater)
|
||||
|
||||
// If the music was cleared while the app was closed [Likely due to Auxio being suspended
|
||||
// in the background], then navigate back to LoadingFragment to reload the music.
|
||||
// This may actually not happen in normal use, but its a good failsafe.
|
||||
if (MusicStore.getInstance().songs.isEmpty()) {
|
||||
findNavController().navigate(MainFragmentDirections.actionReturnToLoading())
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
val colorActive = Accent.get().color.toColor(requireContext())
|
||||
val colorInactive = ColorUtils.setAlphaComponent(colorActive, 150)
|
||||
|
||||
|
|
|
@ -23,15 +23,15 @@ import org.oxycblt.auxio.settings.SettingsManager
|
|||
* Bind the album art for a [song].
|
||||
*/
|
||||
@BindingAdapter("albumArt")
|
||||
fun ImageView.bindAlbumArt(song: Song) {
|
||||
load(song.album, R.drawable.ic_song, AlbumArtFetcher(context))
|
||||
fun ImageView.bindAlbumArt(song: Song?) {
|
||||
load(song?.album, R.drawable.ic_song, AlbumArtFetcher(context))
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind the album art for an [album].
|
||||
*/
|
||||
@BindingAdapter("albumArt")
|
||||
fun ImageView.bindAlbumArt(album: Album) {
|
||||
fun ImageView.bindAlbumArt(album: Album?) {
|
||||
load(album, R.drawable.ic_album, AlbumArtFetcher(context))
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ fun ImageView.bindAlbumArt(album: Album) {
|
|||
* Bind the image for an [artist]
|
||||
*/
|
||||
@BindingAdapter("artistImage")
|
||||
fun ImageView.bindArtistImage(artist: Artist) {
|
||||
fun ImageView.bindArtistImage(artist: Artist?) {
|
||||
load(artist, R.drawable.ic_artist, MosaicFetcher(context))
|
||||
}
|
||||
|
||||
|
@ -47,20 +47,20 @@ fun ImageView.bindArtistImage(artist: Artist) {
|
|||
* Bind the image for a [genre]
|
||||
*/
|
||||
@BindingAdapter("genreImage")
|
||||
fun ImageView.bindGenreImage(genre: Genre) {
|
||||
fun ImageView.bindGenreImage(genre: Genre?) {
|
||||
load(genre, R.drawable.ic_genre, MosaicFetcher(context))
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom extension function similar to the stock coil load extensions, but handles whether
|
||||
* to show images and custom fetchers.
|
||||
* @param T Any datatype that inherits [BaseModel]
|
||||
* @param T Any datatype that inherits [BaseModel]. This can be null, but keep in mind that it will cause loading to fail.
|
||||
* @param data The data itself
|
||||
* @param error Drawable resource to use when loading failed/should not occur.
|
||||
* @param fetcher Required fetcher that uses [T] as its datatype
|
||||
*/
|
||||
inline fun <reified T : BaseModel> ImageView.load(
|
||||
data: T,
|
||||
data: T?,
|
||||
@DrawableRes error: Int,
|
||||
fetcher: Fetcher<T>,
|
||||
) {
|
||||
|
|
|
@ -34,7 +34,6 @@ class MosaicFetcher(private val context: Context) : Fetcher<Parent> {
|
|||
size: Size,
|
||||
options: Options
|
||||
): FetchResult {
|
||||
options.allowRgb565
|
||||
// Get the URIs for either a genre or artist
|
||||
val uris = mutableListOf<Uri>()
|
||||
|
||||
|
|
|
@ -77,7 +77,7 @@ class MusicStore private constructor() {
|
|||
/**
|
||||
* Find a song from this instance in a safe manner.
|
||||
* Using a normal search of the songs list runs the risk of getting the *wrong* song with
|
||||
* the same name, so the album name is used to fix the above problem.
|
||||
* the same name, so the album name is also used to fix the above problem.
|
||||
* @param name The name of the song
|
||||
* @param albumName The name of the song's album.
|
||||
* @return The song requested, null if there isnt one.
|
||||
|
|
|
@ -11,7 +11,6 @@ import org.oxycblt.auxio.MainFragmentDirections
|
|||
import org.oxycblt.auxio.databinding.FragmentCompactPlaybackBinding
|
||||
import org.oxycblt.auxio.detail.DetailViewModel
|
||||
import org.oxycblt.auxio.logD
|
||||
import org.oxycblt.auxio.music.MusicStore
|
||||
|
||||
/**
|
||||
* A [Fragment] that displays the currently played song at a glance, with some basic controls.
|
||||
|
@ -34,9 +33,6 @@ class CompactPlaybackFragment : Fragment() {
|
|||
// --- UI SETUP ---
|
||||
|
||||
binding.lifecycleOwner = viewLifecycleOwner
|
||||
|
||||
// Put a placeholder song in the binding & hide the playback fragment initially.
|
||||
binding.song = MusicStore.getInstance().songs[0]
|
||||
binding.playbackModel = playbackModel
|
||||
binding.executePendingBindings()
|
||||
|
||||
|
|
|
@ -52,12 +52,15 @@ class PlayPauseButton @JvmOverloads constructor(
|
|||
|
||||
/**
|
||||
* Hack that fixes an issue where a seam would display in the middle of the play button,
|
||||
* probably as a result of floating point precision errors. Gotta love IEEE 754.
|
||||
* probably as a result of floating point precision errors. Thanks IEEE 754.
|
||||
*/
|
||||
@RequiresApi(Build.VERSION_CODES.M)
|
||||
private fun fixSeams() {
|
||||
iconPauseToPlay.registerAnimationCallback(object : Animatable2.AnimationCallback() {
|
||||
override fun onAnimationEnd(drawable: Drawable?) {
|
||||
// ic_play_large is a unified vector, compared to the two paths on the
|
||||
// animated vector. So switch to that when the animation completes to prevent the
|
||||
// seam from displaying.
|
||||
setImageResource(R.drawable.ic_play_large)
|
||||
}
|
||||
})
|
||||
|
|
|
@ -54,7 +54,6 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
|
|||
binding.lifecycleOwner = viewLifecycleOwner
|
||||
binding.playbackModel = playbackModel
|
||||
binding.detailModel = detailModel
|
||||
binding.song = playbackModel.song.value!!
|
||||
|
||||
binding.playbackToolbar.apply {
|
||||
setNavigationOnClickListener {
|
||||
|
|
|
@ -7,6 +7,7 @@ import androidx.core.animation.addListener
|
|||
import androidx.media.AudioFocusRequestCompat
|
||||
import androidx.media.AudioManagerCompat
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer
|
||||
import org.oxycblt.auxio.logD
|
||||
import org.oxycblt.auxio.playback.state.PlaybackStateManager
|
||||
import org.oxycblt.auxio.settings.SettingsManager
|
||||
import org.oxycblt.auxio.ui.getSystemServiceSafe
|
||||
|
@ -61,9 +62,11 @@ class AudioReactor(
|
|||
}
|
||||
|
||||
private fun onGain() {
|
||||
if (player.volume == VOLUME_DUCK && playbackManager.isPlaying) {
|
||||
if (player.volume == VOLUME_DUCK) {
|
||||
unduck()
|
||||
} else if (pauseWasTransient) {
|
||||
logD("Gained focus after transient loss")
|
||||
|
||||
// Play again if the pause was only temporary [AudioManager.AUDIOFOCUS_LOSS_TRANSIENT]
|
||||
playbackManager.setPlaying(true)
|
||||
pauseWasTransient = false
|
||||
|
@ -73,20 +76,28 @@ class AudioReactor(
|
|||
private fun onLossTransient() {
|
||||
// Since this loss is only temporary, mark it as such if we had to pause playback.
|
||||
if (playbackManager.isPlaying) {
|
||||
pauseWasTransient = true
|
||||
logD("Pausing for transient loss")
|
||||
|
||||
playbackManager.setPlaying(false)
|
||||
pauseWasTransient = true
|
||||
}
|
||||
}
|
||||
|
||||
private fun onLossPermanent() {
|
||||
logD("Pausing for permanent loss")
|
||||
|
||||
playbackManager.setPlaying(false)
|
||||
}
|
||||
|
||||
private fun onDuck() {
|
||||
logD("Ducking, lowering volume")
|
||||
|
||||
player.volume = VOLUME_DUCK
|
||||
}
|
||||
|
||||
private fun unduck() {
|
||||
logD("Unducking, raising volume")
|
||||
|
||||
player.volume = VOLUME_DUCK
|
||||
|
||||
ValueAnimator().apply {
|
||||
|
|
|
@ -9,8 +9,10 @@ import android.content.Intent
|
|||
import android.content.IntentFilter
|
||||
import android.content.pm.ServiceInfo
|
||||
import android.media.AudioManager
|
||||
import android.media.audiofx.Visualizer
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.os.PowerManager
|
||||
import android.support.v4.media.MediaMetadataCompat
|
||||
import android.support.v4.media.session.MediaSessionCompat
|
||||
import android.view.KeyEvent
|
||||
|
|
|
@ -20,6 +20,7 @@ import org.oxycblt.auxio.ui.createToast
|
|||
|
||||
/**
|
||||
* The actual fragment containing the settings menu. Inherits [PreferenceFragmentCompat].
|
||||
* TODO: Roll your own ListPreference that supports int prefs [and is a bottom sheet]
|
||||
* @author OxygenCobalt
|
||||
*/
|
||||
@Suppress("UNUSED")
|
||||
|
|
|
@ -22,6 +22,7 @@ import com.google.android.material.bottomsheet.BottomSheetDialogFragment
|
|||
import org.oxycblt.auxio.MainActivity
|
||||
import org.oxycblt.auxio.R
|
||||
import org.oxycblt.auxio.databinding.FragmentBlacklistBinding
|
||||
import org.oxycblt.auxio.logD
|
||||
import org.oxycblt.auxio.playback.PlaybackViewModel
|
||||
import org.oxycblt.auxio.ui.createToast
|
||||
import java.io.File
|
||||
|
@ -78,6 +79,8 @@ class BlacklistDialog : BottomSheetDialogFragment() {
|
|||
binding.blacklistEmptyText.isVisible = paths.isEmpty()
|
||||
}
|
||||
|
||||
logD("Dialog created.")
|
||||
|
||||
return binding.root
|
||||
}
|
||||
|
||||
|
@ -139,6 +142,8 @@ class BlacklistDialog : BottomSheetDialogFragment() {
|
|||
}
|
||||
|
||||
private fun hardRestart() {
|
||||
logD("Performing hard-restart.")
|
||||
|
||||
// Instead of having to do a ton of cleanup and horrible code changes
|
||||
// to restart this application non-destructively, I just restart the UI task [There is only
|
||||
// one, after all] and then kill the application using exitProcess. Works well enough.
|
||||
|
|
|
@ -13,10 +13,10 @@ import org.oxycblt.auxio.ui.toStateList
|
|||
/**
|
||||
* An adapter that displays the list of all possible accents, and highlights the current one.
|
||||
* @author OxygenCobalt
|
||||
* @param doOnAccentConfirm What to do when an accent is confirmed.
|
||||
* @param onConfirm What to do when an accent is confirmed.
|
||||
*/
|
||||
class AccentAdapter(
|
||||
private val doOnAccentConfirm: (accent: Accent) -> Unit
|
||||
private val onConfirm: (accent: Accent) -> Unit
|
||||
) : RecyclerView.Adapter<AccentAdapter.ViewHolder>() {
|
||||
override fun getItemCount(): Int = ACCENTS.size
|
||||
|
||||
|
@ -51,7 +51,7 @@ class AccentAdapter(
|
|||
TooltipCompat.setTooltipText(this, contentDescription)
|
||||
|
||||
setOnClickListener {
|
||||
doOnAccentConfirm(accent)
|
||||
onConfirm(accent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,6 +13,11 @@ import org.oxycblt.auxio.settings.SettingsManager
|
|||
import org.oxycblt.auxio.ui.ACCENTS
|
||||
import org.oxycblt.auxio.ui.Accent
|
||||
|
||||
/**
|
||||
* Dialog responsible for showing the list of accents to select.
|
||||
* TODO: Move this to a Bottom Sheet and eliminate the MaterialDialogs dependency
|
||||
* @author OxygenCobalt
|
||||
*/
|
||||
class AccentDialog : DialogFragment() {
|
||||
private val settingsManager = SettingsManager.getInstance()
|
||||
|
||||
|
|
|
@ -34,14 +34,6 @@ class SongsFragment : Fragment() {
|
|||
private val playbackModel: PlaybackViewModel by activityViewModels()
|
||||
private val musicStore = MusicStore.getInstance()
|
||||
|
||||
// Lazy init the text size so that it doesn't have to be calculated every time.
|
||||
private val indicatorTextSize: Float by lazy {
|
||||
TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_SP, 14F,
|
||||
resources.displayMetrics
|
||||
)
|
||||
}
|
||||
|
||||
override fun onCreateView(
|
||||
inflater: LayoutInflater,
|
||||
container: ViewGroup?,
|
||||
|
@ -90,9 +82,14 @@ class SongsFragment : Fragment() {
|
|||
|
||||
/**
|
||||
* Perform the (Frustratingly Long and Complicated) FastScrollerView setup.
|
||||
* TODO: Roll FastScrollerView yourself and eliminate its dependency, you're already customizing it enough as it is.
|
||||
*/
|
||||
private fun FastScrollerView.setup(recycler: RecyclerView, thumb: CobaltScrollThumb) {
|
||||
var truncateInterval: Int = -1
|
||||
val indicatorTextSize = TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_SP, 14F,
|
||||
resources.displayMetrics
|
||||
)
|
||||
|
||||
// API 22 and below don't support the state color, so just use the accent.
|
||||
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.M) {
|
||||
|
|
Loading…
Reference in a new issue