all: cleanup code

Clean up code and fits a bunch of miscellaneous issues.
This commit is contained in:
OxygenCobalt 2021-11-24 20:22:30 -07:00
parent 6b54d4b783
commit 4ccaa7c4bb
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
51 changed files with 192 additions and 289 deletions

View file

@ -66,11 +66,11 @@ dependencies {
// General
implementation "androidx.core:core-ktx:1.7.0"
implementation "androidx.activity:activity-ktx:1.4.0"
implementation 'androidx.fragment:fragment-ktx:1.3.6'
implementation 'androidx.fragment:fragment-ktx:1.4.0'
// UI
implementation "androidx.recyclerview:recyclerview:1.2.1"
implementation "androidx.constraintlayout:constraintlayout:2.1.1"
implementation "androidx.constraintlayout:constraintlayout:2.1.2"
implementation "androidx.dynamicanimation:dynamicanimation:1.0.0"
implementation "androidx.viewpager2:viewpager2:1.1.0-beta01"
@ -95,7 +95,7 @@ dependencies {
// --- THIRD PARTY ---
// ExoPlayer
implementation "com.google.android.exoplayer:exoplayer-core:2.16.0"
implementation "com.google.android.exoplayer:exoplayer-core:2.16.1"
// Image loading
implementation 'io.coil-kt:coil:2.0.0-alpha03'

View file

@ -24,7 +24,7 @@ import coil.ImageLoaderFactory
import coil.request.CachePolicy
import org.oxycblt.auxio.coil.AlbumArtFetcher
import org.oxycblt.auxio.coil.ArtistImageFetcher
import org.oxycblt.auxio.coil.CrossfadeTransition
import org.oxycblt.auxio.coil.ErrorCrossfadeFactory
import org.oxycblt.auxio.coil.GenreImageFetcher
import org.oxycblt.auxio.coil.MusicKeyer
import org.oxycblt.auxio.settings.SettingsManager
@ -48,7 +48,7 @@ class AuxioApp : Application(), ImageLoaderFactory {
add(GenreImageFetcher.Factory())
add(MusicKeyer())
}
.transitionFactory(CrossfadeTransition.Factory())
.transitionFactory(ErrorCrossfadeFactory())
.diskCachePolicy(CachePolicy.DISABLED) // Not downloading anything, so no disk-caching
.build()
}

View file

@ -40,6 +40,8 @@ import org.oxycblt.auxio.util.logD
/**
* A wrapper around the home fragment that shows the playback fragment and controls
* the more high-level navigation features.
* @author OxygenCobalt
* TODO: Handle backnav with playback view
*/
class MainFragment : Fragment(), PlaybackLayout.ActionCallback {
private val playbackModel: PlaybackViewModel by activityViewModels()

View file

@ -29,9 +29,18 @@ import org.oxycblt.auxio.util.logD
import java.io.ByteArrayInputStream
import java.io.InputStream
/**
* The base implementation for all image fetchers in Auxio.
* @author OxygenCobalt
*/
abstract class AuxioFetcher : Fetcher {
private val settingsManager = SettingsManager.getInstance()
/**
* Fetch the artwork of an [album].
* This call respects user configuration and has proper redundancy in the case that
* an API fails to load.
*/
protected suspend fun fetchArt(context: Context, album: Album): InputStream? {
if (!settingsManager.showCovers) {
return null
@ -44,62 +53,14 @@ abstract class AuxioFetcher : Fetcher {
}
}
/**
* Create a mosaic image from multiple streams of image data, Code adapted from Phonograph
* https://github.com/kabouzeid/Phonograph
*/
protected fun createMosaic(context: Context, streams: List<InputStream>): FetchResult? {
if (streams.size < 4) {
return streams.getOrNull(0)?.let { stream ->
return SourceResult(
source = ImageSource(stream.source().buffer(), context),
mimeType = null,
dataSource = DataSource.DISK
)
}
@Suppress("BlockingMethodInNonBlockingContext")
private suspend fun fetchMediaStoreCovers(context: Context, data: Album): InputStream? {
val uri = data.id.toAlbumArtURI()
// Eliminate any chance that this blocking call might mess up the cancellation process
return withContext(Dispatchers.IO) {
context.contentResolver.openInputStream(uri)
}
// Use a fixed 512x512 canvas for the mosaics. Preferably we would adapt this mosaic to
// target ImageView size, but Coil seems to start image loading before we can even get
// a width/height for the view, making that impractical.
val mosaicBitmap = Bitmap.createBitmap(
MOSAIC_BITMAP_SIZE, MOSAIC_BITMAP_SIZE, Bitmap.Config.ARGB_8888
)
val canvas = Canvas(mosaicBitmap)
var x = 0
var y = 0
// For each stream, create a bitmap scaled to 1/4th of the mosaics combined size
// and place it on a corner of the canvas.
for (stream in streams) {
if (y == MOSAIC_BITMAP_SIZE) {
break
}
val bitmap = Bitmap.createScaledBitmap(
BitmapFactory.decodeStream(stream),
MOSAIC_BITMAP_INCREMENT,
MOSAIC_BITMAP_INCREMENT,
true
)
canvas.drawBitmap(bitmap, x.toFloat(), y.toFloat(), null)
x += MOSAIC_BITMAP_INCREMENT
if (x == MOSAIC_BITMAP_SIZE) {
x = 0
y += MOSAIC_BITMAP_INCREMENT
}
}
return DrawableResult(
drawable = mosaicBitmap.toDrawable(context.resources),
isSampled = false,
dataSource = DataSource.DISK
)
}
private suspend fun fetchQualityCovers(context: Context, album: Album): InputStream? {
@ -139,22 +100,12 @@ abstract class AuxioFetcher : Fetcher {
return null
}
@Suppress("BlockingMethodInNonBlockingContext")
private suspend fun fetchMediaStoreCovers(context: Context, data: Album): InputStream? {
val uri = data.id.toAlbumArtURI()
// Eliminate any chance that this blocking call might mess up the cancellation process
return withContext(Dispatchers.IO) {
context.contentResolver.openInputStream(uri)
}
}
private suspend fun fetchAospMetadataCovers(context: Context, album: Album): InputStream? {
private fun fetchAospMetadataCovers(context: Context, album: Album): InputStream? {
val extractor = MediaMetadataRetriever()
extractor.use { ext ->
// To be safe, just make sure that this blocking call is wrapped so it doesn't
// cause problems
// This call is time-consuming but it also doesn't seem to hold up the main thread,
// so it's probably fine not to wrap it.
ext.setDataSource(context, album.songs[0].id.toURI())
// Get the embedded picture from MediaMetadataRetriever, which will return a full
@ -244,6 +195,64 @@ abstract class AuxioFetcher : Fetcher {
return stream
}
/**
* Create a mosaic image from multiple streams of image data, Code adapted from Phonograph
* https://github.com/kabouzeid/Phonograph
*/
protected fun createMosaic(context: Context, streams: List<InputStream>): FetchResult? {
if (streams.size < 4) {
return streams.getOrNull(0)?.let { stream ->
return SourceResult(
source = ImageSource(stream.source().buffer(), context),
mimeType = null,
dataSource = DataSource.DISK
)
}
}
// Use a fixed 512x512 canvas for the mosaics. Preferably we would adapt this mosaic to
// target ImageView size, but Coil seems to start image loading before we can even get
// a width/height for the view, making that impractical.
val mosaicBitmap = Bitmap.createBitmap(
MOSAIC_BITMAP_SIZE, MOSAIC_BITMAP_SIZE, Bitmap.Config.ARGB_8888
)
val canvas = Canvas(mosaicBitmap)
var x = 0
var y = 0
// For each stream, create a bitmap scaled to 1/4th of the mosaics combined size
// and place it on a corner of the canvas.
for (stream in streams) {
if (y == MOSAIC_BITMAP_SIZE) {
break
}
val bitmap = Bitmap.createScaledBitmap(
BitmapFactory.decodeStream(stream),
MOSAIC_BITMAP_INCREMENT,
MOSAIC_BITMAP_INCREMENT,
true
)
canvas.drawBitmap(bitmap, x.toFloat(), y.toFloat(), null)
x += MOSAIC_BITMAP_INCREMENT
if (x == MOSAIC_BITMAP_SIZE) {
x = 0
y += MOSAIC_BITMAP_INCREMENT
}
}
return DrawableResult(
drawable = mosaicBitmap.toDrawable(context.resources),
isSampled = false,
dataSource = DataSource.DISK
)
}
companion object {
private const val MOSAIC_BITMAP_SIZE = 512
private const val MOSAIC_BITMAP_INCREMENT = 256

View file

@ -1,88 +0,0 @@
package org.oxycblt.auxio.coil
import android.widget.ImageView
import coil.decode.DataSource
import coil.drawable.CrossfadeDrawable
import coil.request.ErrorResult
import coil.request.ImageResult
import coil.request.SuccessResult
import coil.size.Scale
import coil.transition.Transition
import coil.transition.TransitionTarget
/**
* A modified variant of coil's CrossfadeTransition that actually animates error results.
* You know. Like it used to.
*
* @author Coil Team
*/
class CrossfadeTransition @JvmOverloads constructor(
private val target: TransitionTarget,
private val result: ImageResult,
private val durationMillis: Int = CrossfadeDrawable.DEFAULT_DURATION,
private val preferExactIntrinsicSize: Boolean = false
) : Transition {
init {
require(durationMillis > 0) { "durationMillis must be > 0." }
}
override fun transition() {
val drawable = CrossfadeDrawable(
start = target.drawable,
end = result.drawable,
scale = (target.view as? ImageView)?.scale ?: Scale.FIT,
durationMillis = durationMillis,
fadeStart = !(result is SuccessResult && result.isPlaceholderCached),
preferExactIntrinsicSize = preferExactIntrinsicSize
)
when (result) {
is SuccessResult -> target.onSuccess(drawable)
is ErrorResult -> target.onError(drawable)
}
}
val ImageView.scale: Scale
get() = when (scaleType) {
ImageView.ScaleType.FIT_START, ImageView.ScaleType.FIT_CENTER,
ImageView.ScaleType.FIT_END, ImageView.ScaleType.CENTER_INSIDE -> Scale.FIT
else -> Scale.FILL
}
class Factory @JvmOverloads constructor(
val durationMillis: Int = CrossfadeDrawable.DEFAULT_DURATION,
val preferExactIntrinsicSize: Boolean = false
) : Transition.Factory {
init {
require(durationMillis > 0) { "durationMillis must be > 0." }
}
override fun create(target: TransitionTarget, result: ImageResult): Transition {
// !!!!!!!!!!!!!! MODIFICATION !!!!!!!!!!!!!!
// Remove the error check for this transition. Usually when something errors in
// Auxio it will stay erroring, so not crossfading on an error looks weird.
// Don't animate if the request was fulfilled by the memory cache.
if (result is SuccessResult && result.dataSource == DataSource.MEMORY_CACHE) {
return Transition.Factory.NONE.create(target, result)
}
return CrossfadeTransition(target, result, durationMillis, preferExactIntrinsicSize)
}
override fun equals(other: Any?): Boolean {
if (this === other) return true
return other is Factory &&
durationMillis == other.durationMillis &&
preferExactIntrinsicSize == other.preferExactIntrinsicSize
}
override fun hashCode(): Int {
var result = durationMillis
result = 31 * result + preferExactIntrinsicSize.hashCode()
return result
}
}
}

View file

@ -0,0 +1,25 @@
package org.oxycblt.auxio.coil
import coil.decode.DataSource
import coil.drawable.CrossfadeDrawable
import coil.request.ImageResult
import coil.request.SuccessResult
import coil.transition.CrossfadeTransition
import coil.transition.Transition
import coil.transition.TransitionTarget
/**
* A copy of [CrossfadeTransition.Factory] that applies a transition to error results.
* You know. Like they used to.
* @author Coil Team
*/
class ErrorCrossfadeFactory : Transition.Factory {
override fun create(target: TransitionTarget, result: ImageResult): Transition {
// Don't animate if the request was fulfilled by the memory cache.
if (result is SuccessResult && result.dataSource == DataSource.MEMORY_CACHE) {
return Transition.Factory.NONE.create(target, result)
}
return CrossfadeTransition(target, result, CrossfadeDrawable.DEFAULT_DURATION, false)
}
}

View file

@ -35,8 +35,7 @@ import org.oxycblt.auxio.music.Song
import kotlin.math.min
/**
* Fetcher that returns the album art for a given [Album]. Handles settings on whether to use
* quality covers or not.
* Fetcher that returns the album art for a given [Album] or [Song], depending on the factory used.
* @author OxygenCobalt
*/
class AlbumArtFetcher private constructor(
@ -54,18 +53,22 @@ class AlbumArtFetcher private constructor(
}
class SongFactory : Fetcher.Factory<Song> {
override fun create(data: Song, options: Options, imageLoader: ImageLoader): Fetcher? {
override fun create(data: Song, options: Options, imageLoader: ImageLoader): Fetcher {
return AlbumArtFetcher(options.context, data.album)
}
}
class AlbumFactory : Fetcher.Factory<Album> {
override fun create(data: Album, options: Options, imageLoader: ImageLoader): Fetcher? {
override fun create(data: Album, options: Options, imageLoader: ImageLoader): Fetcher {
return AlbumArtFetcher(options.context, data)
}
}
}
/**
* Fetcher that fetches the image for an [Artist]
* @author OxygenCobalt
*/
class ArtistImageFetcher private constructor(
private val context: Context,
private val artist: Artist
@ -79,12 +82,16 @@ class ArtistImageFetcher private constructor(
}
class Factory : Fetcher.Factory<Artist> {
override fun create(data: Artist, options: Options, imageLoader: ImageLoader): Fetcher? {
override fun create(data: Artist, options: Options, imageLoader: ImageLoader): Fetcher {
return ArtistImageFetcher(options.context, data)
}
}
}
/**
* Fetcher that fetches the image for a [Genre]
* @author OxygenCobalt
*/
class GenreImageFetcher private constructor(
private val context: Context,
private val genre: Genre
@ -99,7 +106,7 @@ class GenreImageFetcher private constructor(
}
class Factory : Fetcher.Factory<Genre> {
override fun create(data: Genre, options: Options, imageLoader: ImageLoader): Fetcher? {
override fun create(data: Genre, options: Options, imageLoader: ImageLoader): Fetcher {
return GenreImageFetcher(options.context, data)
}
}

View file

@ -3,12 +3,17 @@ package org.oxycblt.auxio.coil
import coil.key.Keyer
import coil.request.Options
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.Song
/**
* A basic keyer for music data.
*/
class MusicKeyer : Keyer<Music> {
override fun key(data: Music, options: Options): String? {
return "${data::class.simpleName}: ${data.id}"
override fun key(data: Music, options: Options): String {
return if (data is Song) {
key(data.album, options)
} else {
"${data::class.simpleName}: ${data.id}"
}
}
}

View file

@ -20,6 +20,7 @@ import org.oxycblt.auxio.ui.EdgeAppBarLayout
* recyclerview is scrolled beyond it's first item (a.k.a the header). This is used instead of
* CollapsingToolbarLayout since that thing is a mess with crippling bugs and state issues.
* This just works.
* @author OxygenCobalt
*/
class DetailAppBarLayout @JvmOverloads constructor(
context: Context,

View file

@ -72,7 +72,7 @@ class ExcludedDialog : LifecycleDialog() {
binding.excludedRecycler.adapter = adapter
// Now that the dialog exists, we get the view manually when the dialog is shown
// and override its click-listener so that the dialog does not auto-dismiss when we
// and override its click listener so that the dialog does not auto-dismiss when we
// click the "Add"/"Save" buttons. This prevents the dialog from disappearing in the former
// and the app from crashing in the latter.
val dialog = requireDialog() as AlertDialog

View file

@ -46,7 +46,7 @@ class ExcludedEntryAdapter(
@SuppressLint("NotifyDataSetChanged")
fun submitList(newPaths: MutableList<String>) {
paths = newPaths
notifyDataSetChanged() // TODO: Consider using remove/addition
notifyDataSetChanged()
}
inner class ViewHolder(

View file

@ -26,7 +26,7 @@ import androidx.core.view.postDelayed
import androidx.core.view.updatePadding
import com.google.android.material.color.MaterialColors
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.ViewCompactPlaybackBinding
import org.oxycblt.auxio.databinding.ViewPlaybackBarBinding
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.util.inflater
import org.oxycblt.auxio.util.resolveAttr
@ -34,14 +34,14 @@ import org.oxycblt.auxio.util.systemBarsCompat
/**
* A view displaying the playback state in a compact manner. This is only meant to be used
* by [PlaybackBarLayout].
* by [PlaybackLayout].
*/
class PlaybackBarView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = -1
) : ConstraintLayout(context, attrs, defStyleAttr) {
private val binding = ViewCompactPlaybackBinding.inflate(context.inflater, this, true)
private val binding = ViewPlaybackBarBinding.inflate(context.inflater, this, true)
private var mCallback: PlaybackLayout.ActionCallback? = null
init {

View file

@ -389,6 +389,11 @@ class PlaybackLayout @JvmOverloads constructor(
}
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
playbackBarView.clearCallback()
}
override fun onSaveInstanceState(): Parcelable = Bundle().apply {
putParcelable("superState", super.onSaveInstanceState())
putSerializable(
@ -525,15 +530,21 @@ class PlaybackLayout @JvmOverloads constructor(
* Update the view transitions done when the panel slides up.
*/
private fun updatePanelTransition() {
contentView.alpha = min(1 - panelOffset, 1f)
val outAlpha = min(1 - panelOffset, 1f)
val inAlpha = max(panelOffset, 0f)
contentView.apply {
alpha = outAlpha
isInvisible = alpha == 0f
}
// Slowly reduce the elevation as we slide up, eventually resulting in a neutral color
// instead of an elevated one when fully expanded.
(playbackContainerView.background as MaterialShapeDrawable).alpha = (min(1 - panelOffset, 1f) * 255).toInt()
(playbackContainerView.background as MaterialShapeDrawable).alpha = (outAlpha * 255).toInt()
// Fade out our bar view as we slide up
playbackBarView.apply {
alpha = min(1 - panelOffset, 1f)
alpha = outAlpha
isInvisible = alpha == 0f
// When edge-to-edge is enabled, the playback bar will not fade out into the
@ -546,7 +557,6 @@ class PlaybackLayout @JvmOverloads constructor(
// of the playback view. This seems to be the least obtrusive way to do this.
lastInsets?.systemBarsCompat?.let { bars ->
val params = layoutParams as FrameLayout.LayoutParams
val oldTopMargin = params.topMargin
params.setMargins(
@ -565,7 +575,7 @@ class PlaybackLayout @JvmOverloads constructor(
// Fade in our panel as we slide up
playbackPanelView.apply {
alpha = max(panelOffset, 0f)
alpha = inAlpha
isInvisible = alpha == 0f
}
}

View file

@ -34,7 +34,6 @@ import coil.imageLoader
import coil.request.ImageRequest
import coil.transform.RoundedCornersTransformation
import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.state.PlaybackStateManager
import org.oxycblt.auxio.util.isLandscape

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View file

@ -1,10 +0,0 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:tint="?attr/colorPrimary"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="@android:color/white"
android:pathData="M12 3v10.55C11.41 13.21 10.73 13 10 13c-2.21 0-4 1.79-4 4s1.79 4 4 4 4-1.79 4-4V7h4V3h-6z" />
</vector>

View file

@ -1,13 +0,0 @@
<?xml version="1.0" encoding="utf-8"?><!-- Hack to make MaterialShapeDrawable cooperate with RippleDrawable. See
CompactPlaybackView for more info. -->
<ripple xmlns:android="http://schemas.android.com/apk/res/android"
android:color="?attr/colorControlHighlight">
<item android:id="@android:id/mask">
<shape android:shape="rectangle">
<solid android:color="@android:color/white" />
</shape>
</item>
<item android:id="@android:id/background">
<shape android:shape="rectangle" />
</item>
</ripple>

View file

@ -185,4 +185,4 @@
app:tint="@color/sel_accented" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
</layout>

View file

@ -37,11 +37,11 @@
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full"
android:layout_margin="@dimen/spacing_mid_large"
android:layout_marginEnd="8dp"
android:contentDescription="@{@string/desc_album_cover(song.name)}"
app:albumArt="@{song}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/playback_song_container"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/playback_toolbar"
tools:src="@drawable/ic_album" />
@ -76,14 +76,12 @@
style="@style/Widget.Auxio.TextView.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_mid_large"
android:layout_marginEnd="@dimen/spacing_mid_large"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song.album.artist)}"
android:text="@{song.album.artist.resolvedName}"
app:layout_constraintBottom_toTopOf="@+id/playback_album"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/playback_cover"
app:layout_constraintStart_toStartOf="@+id/playback_song_container"
app:layout_constraintEnd_toEndOf="@+id/playback_song_container"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintTop_toBottomOf="@+id/playback_song_container"
tools:text="Artist Name" />
@ -92,14 +90,12 @@
style="@style/Widget.Auxio.TextView.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_mid_large"
android:layout_marginEnd="@dimen/spacing_mid_large"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song.album)}"
android:text="@{song.album.name}"
app:layout_constraintBottom_toTopOf="@+id/playback_seek_bar"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/playback_cover"
app:layout_constraintStart_toStartOf="@+id/playback_song_container"
app:layout_constraintEnd_toEndOf="@+id/playback_song_container"
app:layout_constraintTop_toBottomOf="@+id/playback_artist"
tools:text="Album Name" />
@ -107,12 +103,12 @@
android:id="@+id/playback_seek_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_small"
android:layout_marginEnd="@dimen/spacing_small"
android:layout_marginStart="-8dp"
android:layout_marginEnd="-8dp"
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/playback_cover"
app:layout_constraintStart_toStartOf="@+id/playback_song_container"
app:layout_constraintEnd_toEndOf="@+id/playback_song_container"
app:layout_constraintTop_toBottomOf="@+id/playback_album" />
<ImageButton
@ -152,8 +148,7 @@
android:src="@drawable/sel_playing_state"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="@+id/playback_seek_bar"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="@+id/playback_cover"
app:layout_constraintStart_toStartOf="@+id/playback_seek_bar"
app:layout_constraintTop_toBottomOf="@+id/playback_seek_bar"
tools:src="@drawable/ic_pause" />
@ -184,6 +179,5 @@
app:layout_constraintTop_toTopOf="@+id/playback_skip_next"
app:tint="@color/sel_accented" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>

View file

@ -36,7 +36,7 @@
<ImageView
android:id="@+id/playback_cover"
style="@style/Widget.Auxio.Image.Full"
android:layout_margin="@dimen/spacing_mid_large"
android:layout_margin="@dimen/spacing_large"
android:contentDescription="@{@string/desc_album_cover(song.name)}"
app:albumArt="@{song}"
app:layout_constraintBottom_toTopOf="@+id/playback_song"
@ -50,8 +50,8 @@
style="@style/Widget.Auxio.TextView.Primary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_mid_large"
android:layout_marginEnd="@dimen/spacing_mid_large"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song)}"
android:text="@{song.name}"
app:layout_constraintBottom_toTopOf="@+id/playback_artist"
@ -65,8 +65,8 @@
style="@style/Widget.Auxio.TextView.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_mid_large"
android:layout_marginEnd="@dimen/spacing_mid_large"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song.album.artist)}"
android:text="@{song.album.artist.resolvedName}"
app:layout_constraintBottom_toTopOf="@+id/playback_album"
@ -79,8 +79,8 @@
style="@style/Widget.Auxio.TextView.Secondary"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_mid_large"
android:layout_marginEnd="@dimen/spacing_mid_large"
android:layout_marginStart="@dimen/spacing_large"
android:layout_marginEnd="@dimen/spacing_large"
android:onClick="@{() -> detailModel.navToItem(playbackModel.song.album)}"
android:text="@{song.album.name}"
app:layout_constraintBottom_toTopOf="@+id/playback_seek_bar"
@ -92,8 +92,8 @@
android:id="@+id/playback_seek_bar"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_small"
android:layout_marginEnd="@dimen/spacing_small"
android:layout_marginStart="@dimen/spacing_medium"
android:layout_marginEnd="@dimen/spacing_medium"
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />

View file

@ -19,7 +19,6 @@
<TextView
android:id="@+id/detail_name"
style="@style/Widget.Auxio.TextView.Detail"
android:textAppearance="@style/TextAppearance.Auxio.HeadlineLarge"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
@ -39,7 +38,6 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
android:textAppearance="@style/TextAppearance.Auxio.HeadlineSmall"
android:clickable="true"
android:focusable="true"
app:layout_constraintBottom_toTopOf="@+id/detail_info"
@ -55,7 +53,6 @@
android:layout_height="wrap_content"
android:layout_marginStart="@dimen/spacing_medium"
app:layout_constraintEnd_toEndOf="parent"
android:textAppearance="@style/TextAppearance.Auxio.HeadlineSmall"
app:layout_constraintStart_toEndOf="@+id/detail_cover"
app:layout_constraintTop_toBottomOf="@+id/detail_subhead"
app:layout_constraintBottom_toTopOf="@+id/detail_play_button"

View file

@ -8,7 +8,6 @@
android:id="@+id/main_bar_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:orientation="vertical">
<androidx.fragment.app.FragmentContainerView

View file

@ -128,7 +128,7 @@
style="@style/Widget.Auxio.FloatingActionButton.PlayPause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="@dimen/spacing_medium"
android:layout_marginBottom="@dimen/spacing_mid_large"
android:contentDescription="@string/desc_play_pause"
android:onClick="@{() -> playbackModel.invertPlayingStatus()}"
android:src="@drawable/sel_playing_state"

View file

@ -8,7 +8,6 @@
android:id="@+id/queue_coordinator"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true"
android:background="?attr/colorSurface"
android:orientation="vertical">

View file

@ -4,7 +4,6 @@
<!-- Info namespace | App labels -->
<string name="info_app_desc">"Jednoduchý, rozumný hudební přehrávač pro Android."</string>
<string name="info_channel_name">"Přehrávání hudby"</string>
<string name="info_widget_name">"Nyní hraje"</string>
<string name="info_widget_desc">"Zobrazit a ovládat hrající hudbu"</string>
<!-- Label Namespace | Static Labels -->
@ -20,7 +19,6 @@
<string name="lbl_filter_all">"Vše"</string>
<string name="lbl_sort">"Řadit"</string>
<string name="lbl_sort_asc">"Vzestupně"</string>
<string name="lbl_sort_dsc">"Sestupně"</string>
<string name="lbl_sort_artist">"Umělec"</string>
<string name="lbl_sort_album">"Album"</string>
<string name="lbl_sort_year">"Rok"</string>
@ -30,7 +28,7 @@
<string name="lbl_play_album">"Přehrát z alba"</string>
<string name="lbl_play_artist">"Přehrát od umělce"</string>
<string name="lbl_play_genre">"Přehrát z žánru"</string>
<string name="lbl_playback">"Nyní hraje"</string>
<string name="info_widget_name">"Nyní hraje"</string>
<string name="lbl_queue">"Fronta"</string>
<string name="lbl_queue_add">"Přidat do fronty"</string>
<string name="lbl_queue_added">"Přidáno do fronty"</string>

View file

@ -19,7 +19,6 @@
<string name="lbl_sort">Sortierung</string>
<string name="lbl_sort_asc">Aufsteigend</string>
<string name="lbl_sort_dsc">Absteigend</string>
<string name="lbl_play">Abspielen</string>
<string name="lbl_shuffle">Zufällig</string>
@ -27,7 +26,7 @@
<string name="lbl_play_album">Von Album abspielen</string>
<string name="lbl_play_artist">Von Künstler abspielen</string>
<string name="lbl_play_genre">Von Genre abspielen</string>
<string name="lbl_playback">Aktuelle Wiedergabe</string>
<string name="info_widget_name">Aktuelle Wiedergabe</string>
<string name="lbl_queue">Warteschlange</string>
<string name="lbl_queue_add">Zur Warteschlange hinzufügen</string>
@ -150,7 +149,6 @@
<item quantity="other">%d Alben</item>
</plurals>
<string name="info_app_desc">Ein einfacher, rationaler Musikplayer für Android.</string>
<string name="info_widget_name">Aktuell Wiedergabe</string>
<string name="info_widget_desc">Spielende Musik anzeigen und kontrollieren</string>
<string name="lbl_sort_artist">Künstler</string>
<string name="lbl_sort_album">Album</string>

View file

@ -18,7 +18,7 @@
<string name="lbl_play">Αναπαραγωγή</string>
<string name="lbl_shuffle">Τυχαία</string>
<string name="lbl_playback">Παίζει τώρα</string>
<string name="info_widget_name">Παίζει τώρα</string>
<string name="lbl_queue">Ουρά αναπαραγωγής</string>
<string name="lbl_queue_add">Προσθήκη στην ουρά αναπ/γής</string>

View file

@ -20,7 +20,6 @@
<string name="lbl_sort">Ordenar</string>
<string name="lbl_sort_asc">Ascendente</string>
<string name="lbl_sort_dsc">Descendente</string>
<string name="lbl_play">Reproducir</string>
<string name="lbl_shuffle">Aleatorio</string>
@ -28,7 +27,7 @@
<string name="lbl_play_album">Reproducir por álbum</string>
<string name="lbl_play_artist">Reproducir por artista</string>
<string name="lbl_play_genre">Reproducir por género</string>
<string name="lbl_playback">Reproducción actual</string>
<string name="info_widget_name">Reproducción actual</string>
<string name="lbl_queue">Cola</string>
<string name="lbl_queue_add">Agregar a la cola</string>

View file

@ -16,11 +16,10 @@
<string name="lbl_sort">Tri</string>
<string name="lbl_sort_asc">Ascendant</string>
<string name="lbl_sort_dsc">Descendant</string>
<string name="lbl_play">Lecture</string>
<string name="lbl_shuffle">Aléatoire</string>
<string name="lbl_playback">Lecture en cours</string>
<string name="info_widget_name">Lecture en cours</string>
<string name="lbl_queue">File d\'attente</string>
<string name="lbl_queue_add">Ajouter à la file d\'attente</string>

View file

@ -16,11 +16,10 @@
<string name="lbl_sort">Összes</string>
<string name="lbl_sort_asc">Növekvő</string>
<string name="lbl_sort_dsc">Csökkenő</string>
<string name="lbl_play">Lejátszás</string>
<string name="lbl_shuffle">Keverés</string>
<string name="lbl_playback">Most Játszott</string>
<string name="info_widget_name">Most Játszott</string>
<string name="lbl_queue">Lejátszási sor</string>
<string name="lbl_queue_add">Lejátszás sorhoz adás</string>

View file

@ -16,11 +16,10 @@
<string name="lbl_sort">Urutan</string>
<string name="lbl_sort_asc">Naik</string>
<string name="lbl_sort_dsc">Turun</string>
<string name="lbl_play">Putar</string>
<string name="lbl_shuffle">Acak</string>
<string name="lbl_playback">Sedang Diputar</string>
<string name="info_widget_name">Sedang Diputar</string>
<string name="lbl_queue">Antrean</string>
<string name="lbl_queue_add">Tambahkan ke antrean</string>

View file

@ -16,11 +16,10 @@
<string name="lbl_sort">Ordine</string>
<string name="lbl_sort_asc">Ascendente</string>
<string name="lbl_sort_dsc">Discendente</string>
<string name="lbl_play">Riproduci</string>
<string name="lbl_shuffle">Casuale</string>
<string name="lbl_playback">Schermata di riproduzione</string>
<string name="info_widget_name">Schermata di riproduzione</string>
<string name="lbl_queue">Coda</string>
<string name="lbl_queue_add">Aggiungi alla coda</string>

View file

@ -16,11 +16,10 @@
<string name="lbl_sort">분류</string>
<string name="lbl_sort_asc">오름차순</string>
<string name="lbl_sort_dsc">내림차순</string>
<string name="lbl_play">재생</string>
<string name="lbl_shuffle">모든 곡 랜덤 재생</string>
<string name="lbl_playback">지금 재생 중</string>
<string name="info_widget_name">지금 재생 중</string>
<string name="lbl_queue">대기열</string>
<string name="lbl_queue_add">대기열에 추가</string>

View file

@ -20,7 +20,6 @@
<string name="lbl_sort">Sorteren</string>
<string name="lbl_sort_asc">Oplopend</string>
<string name="lbl_sort_dsc">Aflopend</string>
<string name="lbl_play">Afspelen</string>
<string name="lbl_shuffle">Shuffle</string>
@ -28,7 +27,7 @@
<string name="lbl_play_album">Speel af van album </string>
<string name="lbl_play_artist">Speel van artiest </string>
<string name="lbl_play_genre">Speel vanuit genre </string>
<string name="lbl_playback">Afspeelscherm</string>
<string name="info_widget_name">Afspeelscherm</string>
<string name="lbl_queue">Wachtrij</string>
<string name="lbl_queue_add">Toevoegen aan wachtrij</string>

View file

@ -16,11 +16,10 @@
<string name="lbl_sort">Sortowanie</string>
<string name="lbl_sort_asc">Rosnąco</string>
<string name="lbl_sort_dsc">Malejąco</string>
<string name="lbl_play">Graj</string>
<string name="lbl_shuffle">Losowo</string>
<string name="lbl_playback">Obecnie Grane</string>
<string name="info_widget_name">Obecnie Grane</string>
<string name="lbl_queue">Kolejka</string>
<string name="lbl_queue_add">Dodaj do kolejki</string>

View file

@ -15,11 +15,10 @@
<string name="lbl_filter_all">Tudo</string>
<string name="lbl_sort">Classificação</string>
<string name="lbl_sort_dsc">Descendente</string>
<string name="lbl_play">Reproduzir</string>
<string name="lbl_shuffle">Embaralhar</string>
<string name="lbl_playback">Tocando agora</string>
<string name="info_widget_name">Tocando agora</string>
<string name="lbl_queue">Fila</string>
<string name="lbl_queue_add">Adicionar à fila</string>

View file

@ -16,11 +16,10 @@
<string name="lbl_sort">Classificação</string>
<string name="lbl_sort_asc">Ascendente</string>
<string name="lbl_sort_dsc">Descendente</string>
<string name="lbl_play">Reproduzir</string>
<string name="lbl_shuffle">Embaralhar</string>
<string name="lbl_playback">A reproduzir</string>
<string name="info_widget_name">A reproduzir</string>
<string name="lbl_queue">Fila</string>
<string name="lbl_queue_add">Adicionar à fila</string>

View file

@ -16,11 +16,10 @@
<string name="lbl_sort">Sortare</string>
<string name="lbl_sort_asc">Crescător</string>
<string name="lbl_sort_dsc">Descrescător</string>
<string name="lbl_play">Redă</string>
<string name="lbl_shuffle">Amestecare</string>
<string name="lbl_playback">Redare Acum</string>
<string name="info_widget_name">Redare Acum</string>
<string name="lbl_queue">Fila de așteptare</string>
<string name="lbl_queue_add">Adăugați la lista de așteptare</string>

View file

@ -16,11 +16,10 @@
<string name="lbl_sort">Сортировка</string>
<string name="lbl_sort_asc">По возрастанию</string>
<string name="lbl_sort_dsc">По убыванию</string>
<string name="lbl_play">Воспроизвести</string>
<string name="lbl_shuffle">Перемешать</string>
<string name="lbl_playback">Сейчас воспроизводится</string>
<string name="info_widget_name">Сейчас воспроизводится</string>
<string name="lbl_queue">Очередь</string>
<string name="lbl_queue_add">Добавить в очередь</string>

View file

@ -16,11 +16,10 @@
<string name="lbl_sort">Sıralama</string>
<string name="lbl_sort_asc">Artan</string>
<string name="lbl_sort_dsc">Azalan</string>
<string name="lbl_play">Başlat</string>
<string name="lbl_shuffle">Karıştır</string>
<string name="lbl_playback">Şuan çalınan</string>
<string name="info_widget_name">Şuan çalınan</string>
<string name="lbl_queue">Kuyruk</string>
<string name="lbl_queue_add">Kuyruğa ekle</string>

View file

@ -18,7 +18,7 @@
<string name="lbl_play">Відтворити</string>
<string name="lbl_shuffle">Перемішати</string>
<string name="lbl_playback">Відтворюється</string>
<string name="info_widget_name">Відтворюється</string>
<string name="lbl_queue">Черга</string>
<string name="lbl_queue_add">Додати в чергу</string>

View file

@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="Widget.Auxio.Button.AppWidget.V31" parent="Widget.AppCompat.Button.Borderless">
<item name="android:background">@drawable/ui_unbounded_ripple</item>
</style>

View file

@ -16,11 +16,10 @@
<string name="lbl_sort">排序方式</string>
<string name="lbl_sort_asc">按首字符(正序)</string>
<string name="lbl_sort_dsc">按首字符(倒序)</string>
<string name="lbl_play">播放</string>
<string name="lbl_shuffle">随机播放</string>
<string name="lbl_playback">正在播放界面</string>
<string name="info_widget_name">正在播放界面</string>
<string name="lbl_queue">播放队列</string>
<string name="lbl_queue_add">加入播放队列</string>

View file

@ -16,11 +16,10 @@
<string name="lbl_sort">排序</string>
<string name="lbl_sort_asc">升序排列</string>
<string name="lbl_sort_dsc">降序排列</string>
<string name="lbl_play">播放</string>
<string name="lbl_shuffle">隨機播放</string>
<string name="lbl_playback">播放面板</string>
<string name="info_widget_name">播放面板</string>
<string name="lbl_queue">隊列</string>
<string name="lbl_queue_add">添加到隊列</string>

View file

@ -5,8 +5,6 @@
<dimen name="spacing_medium">16dp</dimen>
<dimen name="spacing_mid_large">24dp</dimen>
<dimen name="spacing_large">32dp</dimen>
<dimen name="spacing_huge">48dp</dimen>
<dimen name="spacing_insane">128dp</dimen>
<!-- Size Namespace | Width & Heights for UI elements -->
<dimen name="size_btn_small">48dp</dimen>

View file

@ -7,5 +7,4 @@
<string name="fmt_two" translatable="false">%1$s • %2$s</string>
<string name="fmt_three" translatable="false">%1$s • %2$s • %3$s</string>
<string name="fmt_counts" translatable="false">%1$s, %2$s</string>
<string name="fmt_accent_desc" translatable="false">&lt;b>%1$s&lt;/b>:&#160;%2$s</string>
</resources>

View file

@ -24,7 +24,6 @@
<string name="lbl_sort">Sort</string>
<string name="lbl_sort_name">Name</string>
<string name="lbl_sort_asc">Ascending</string>
<string name="lbl_sort_dsc">Descending</string>
<string name="lbl_sort_artist">Artist</string>
<string name="lbl_sort_album">Album</string>
<string name="lbl_sort_year">Year</string>
@ -35,7 +34,6 @@
<string name="lbl_play_album">Play from album</string>
<string name="lbl_play_artist">Play from artist</string>
<string name="lbl_play_genre">Play from genre</string>
<string name="lbl_playback">Now Playing</string>
<string name="lbl_queue">Queue</string>
<string name="lbl_queue_add">Add to queue</string>

View file

@ -161,7 +161,7 @@
<item name="android:textAppearance">@style/TextAppearance.Auxio.LabelLarger</item>
</style>
<style name="Widget.Auxio.FloatingActionButton.PlayPause" parent="Widget.Material3.FloatingActionButton.Primary">
<style name="Widget.Auxio.FloatingActionButton.PlayPause" parent="Widget.Material3.FloatingActionButton.Secondary">
<item name="maxImageSize">@dimen/size_play_fab_icon</item>
<item name="fabCustomSize">@dimen/size_btn_large</item>
@ -171,7 +171,6 @@
<item name="android:elevation">0dp</item>
<item name="elevation">0dp</item>
<item name="materialThemeOverlay">@style/ThemeOverlay.Auxio.FloatingActionButton.PlayPause</item>
<item name="shapeAppearanceOverlay">@style/ShapeAppearance.Auxio.FloatingActionButton.PlayPause</item>
</style>

View file

@ -483,11 +483,4 @@
<item name="colorOnSurfaceVariant">@color/grey_on_surface_variant</item>
</style>
<style name="Theme.Auxio.Neutral" parent="Theme.Auxio.App">
<item name="colorPrimary">?attr/colorControlNormal</item>
<item name="colorOnPrimary">?attr/colorControlNormal</item>
<item name="colorPrimaryInverse">?attr/colorControlNormal</item>
<item name="colorPrimaryContainer">?attr/colorControlNormal</item>
<item name="colorOnPrimaryContainer">?attr/colorControlNormal</item>
</style>
</resources>