From aac6d8ef4dc9d72137cd8f97e339d53f86f52ec1 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Mon, 17 Mar 2025 08:12:39 -0600 Subject: [PATCH] app: cleanup --- app/build.gradle | 4 +- .../BackportBottomSheetBehavior.java | 1 - .../java/org/oxycblt/auxio/MainFragment.kt | 3 - .../decision/DetailDecisionViewModel.kt | 2 +- .../org/oxycblt/auxio/home/HomeFragment.kt | 10 --- .../org/oxycblt/auxio/image/CoverProvider.kt | 2 +- .../java/org/oxycblt/auxio/image/CoverView.kt | 3 +- .../image/coil/CoverCollectionFetcher.kt | 5 +- .../oxycblt/auxio/image/coil/CoverFetcher.kt | 67 +---------------- .../image/coil/RoundedRectTransformation.kt | 4 +- .../image/coil/SquareCropTransformation.kt | 3 +- .../list/recycler/FastScrollRecyclerView.kt | 5 +- .../oxycblt/auxio/music/MusicRepository.kt | 10 +-- .../java/org/oxycblt/auxio/music/MusicType.kt | 5 -- .../music/locations/MusicSourcesDialog.kt | 3 +- .../locations/NewLocationFooterAdapter.kt | 2 +- .../oxycblt/auxio/playback/PlaybackUtil.kt | 7 -- .../playback/service/BetterShuffleOrder.kt | 3 + .../service/ExoPlaybackStateHolder.kt | 3 + .../auxio/playback/service/SystemModule.kt | 3 + .../oxycblt/auxio/settings/AboutFragment.kt | 4 +- .../java/org/oxycblt/auxio/ui/Animations.kt | 26 +++---- .../org/oxycblt/auxio/util/FrameworkUtil.kt | 8 +- .../java/org/oxycblt/auxio/util/StateUtil.kt | 75 ------------------- .../widgets/WidgetBitmapTransformation.kt | 3 +- .../org/oxycblt/auxio/widgets/WidgetUtil.kt | 6 -- .../res/layout-h360dp/fragment_detail.xml | 3 +- .../res/layout-h480dp/fragment_detail.xml | 3 +- .../res/layout-sw600dp/fragment_detail.xml | 3 +- .../res/layout-w600dp/fragment_detail.xml | 3 +- .../main/res/layout/fragment_home_list.xml | 1 + app/src/main/res/layout/view_scroll_thumb.xml | 3 +- app/src/main/res/layout/widget_wafer_thin.xml | 2 +- app/src/main/res/layout/widget_wafer_wide.xml | 3 +- app/src/main/res/values-sq/strings.xml | 2 +- app/src/main/res/values/themes_black.xml | 7 +- .../oxycblt/musikr/cache/db/CacheDatabase.kt | 3 +- .../main/java/org/oxycblt/musikr/tag/Name.kt | 4 + 38 files changed, 76 insertions(+), 228 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index d444f70c9..458c17774 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -18,8 +18,8 @@ android { defaultConfig { applicationId namespace - versionName "4.0.2" - versionCode 61 + versionName "4.0.3" + versionCode 62 minSdk min_sdk targetSdk target_sdk diff --git a/app/src/main/java/com/google/android/material/bottomsheet/BackportBottomSheetBehavior.java b/app/src/main/java/com/google/android/material/bottomsheet/BackportBottomSheetBehavior.java index 50ef29e94..c8c5ead47 100644 --- a/app/src/main/java/com/google/android/material/bottomsheet/BackportBottomSheetBehavior.java +++ b/app/src/main/java/com/google/android/material/bottomsheet/BackportBottomSheetBehavior.java @@ -1309,7 +1309,6 @@ public class BackportBottomSheetBehavior extends CoordinatorLayo + " should not be set externally."); } if (!hideable && state == STATE_HIDDEN) { - Log.w(TAG, "Cannot set state: " + state); return; } final int finalState; diff --git a/app/src/main/java/org/oxycblt/auxio/MainFragment.kt b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt index 911cd4db2..10342f1d1 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt @@ -18,7 +18,6 @@ package org.oxycblt.auxio -import android.animation.ValueAnimator import android.os.Bundle import android.view.LayoutInflater import android.view.ViewTreeObserver @@ -514,8 +513,6 @@ class MainFragment : } } - private var scrimAnimator: ValueAnimator? = null - private fun updateSpeedDial(open: Boolean) { requireNotNull(speedDialBackCallback) { "SpeedDialBackPressedCallback was not available" } .invalidateEnabled(open) diff --git a/app/src/main/java/org/oxycblt/auxio/detail/decision/DetailDecisionViewModel.kt b/app/src/main/java/org/oxycblt/auxio/detail/decision/DetailDecisionViewModel.kt index d57d18042..b3286983c 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/decision/DetailDecisionViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/decision/DetailDecisionViewModel.kt @@ -98,7 +98,7 @@ sealed interface ArtistShowChoices { val uid: Music.UID /** The current [Artist] choices. */ val choices: List - /** Sanitize this instance with a [DeviceLibrary]. */ + /** Sanitize this instance with a [Library]. */ fun sanitize(newLibrary: Library): ArtistShowChoices? /** Backing implementation of [ArtistShowChoices] that is based on a [Song]. */ diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt index a2a2495b8..adc2ea512 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt @@ -37,12 +37,10 @@ import androidx.recyclerview.widget.RecyclerView import androidx.viewpager2.adapter.FragmentStateAdapter import androidx.viewpager2.widget.ViewPager2 import com.google.android.material.appbar.AppBarLayout -import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.tabs.TabLayoutMediator import com.google.android.material.transition.MaterialSharedAxis import dagger.hilt.android.AndroidEntryPoint import java.lang.reflect.Field -import java.lang.reflect.Method import kotlin.math.abs import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentHomeBinding @@ -68,7 +66,6 @@ import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.util.collect import org.oxycblt.auxio.util.collectImmediately import org.oxycblt.auxio.util.lazyReflectedField -import org.oxycblt.auxio.util.lazyReflectedMethod import org.oxycblt.auxio.util.navigateSafe import org.oxycblt.auxio.util.showToast import org.oxycblt.musikr.IndexingProgress @@ -94,7 +91,6 @@ class HomeFragment : private var storagePermissionLauncher: ActivityResultLauncher? = null private var getContentLauncher: ActivityResultLauncher? = null private var pendingImportTarget: Playlist? = null - private var lastUpdateTime = -1L override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -512,11 +508,5 @@ class HomeFragment : private companion object { val VP_RECYCLER_FIELD: Field by lazyReflectedField(ViewPager2::class, "mRecyclerView") val RV_TOUCH_SLOP_FIELD: Field by lazyReflectedField(RecyclerView::class, "mTouchSlop") - val FAB_HIDE_FROM_USER_FIELD: Method by - lazyReflectedMethod( - FloatingActionButton::class, - "hide", - FloatingActionButton.OnVisibilityChangedListener::class, - Boolean::class) } } diff --git a/app/src/main/java/org/oxycblt/auxio/image/CoverProvider.kt b/app/src/main/java/org/oxycblt/auxio/image/CoverProvider.kt index 160267804..286d820a7 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/CoverProvider.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/CoverProvider.kt @@ -30,7 +30,7 @@ import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.image.covers.SettingCovers import org.oxycblt.musikr.covers.CoverResult -class CoverProvider() : ContentProvider() { +class CoverProvider : ContentProvider() { override fun onCreate(): Boolean = true override fun openFile(uri: Uri, mode: String): ParcelFileDescriptor? { diff --git a/app/src/main/java/org/oxycblt/auxio/image/CoverView.kt b/app/src/main/java/org/oxycblt/auxio/image/CoverView.kt index bab90cbe6..53362e0c1 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/CoverView.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/CoverView.kt @@ -37,6 +37,7 @@ import androidx.annotation.DrawableRes import androidx.annotation.Px import androidx.core.graphics.drawable.DrawableCompat import androidx.core.view.children +import androidx.core.view.isEmpty import androidx.core.view.updateMarginsRelative import androidx.core.widget.ImageViewCompat import coil3.ImageLoader @@ -172,7 +173,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr super.onFinishInflate() // The image isn't added if other children have populated the body. This is by design. - if (childCount == 0) { + if (isEmpty()) { addView(image) } diff --git a/app/src/main/java/org/oxycblt/auxio/image/coil/CoverCollectionFetcher.kt b/app/src/main/java/org/oxycblt/auxio/image/coil/CoverCollectionFetcher.kt index a6bc9475d..286e59a93 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/coil/CoverCollectionFetcher.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/coil/CoverCollectionFetcher.kt @@ -19,9 +19,9 @@ package org.oxycblt.auxio.image.coil import android.content.Context -import android.graphics.Bitmap import android.graphics.BitmapFactory import android.graphics.Canvas +import androidx.core.graphics.createBitmap import androidx.core.graphics.drawable.toDrawable import coil3.ImageLoader import coil3.asImage @@ -90,8 +90,7 @@ private constructor( val mosaicFrameSize = Size(Dimension(mosaicSize.width / 2), Dimension(mosaicSize.height / 2)) - val mosaicBitmap = - Bitmap.createBitmap(mosaicSize.width, mosaicSize.height, Bitmap.Config.ARGB_8888) + val mosaicBitmap = createBitmap(mosaicSize.width, mosaicSize.height) val canvas = Canvas(mosaicBitmap) var x = 0 diff --git a/app/src/main/java/org/oxycblt/auxio/image/coil/CoverFetcher.kt b/app/src/main/java/org/oxycblt/auxio/image/coil/CoverFetcher.kt index 4c0ed0c5c..bc6284ee5 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/coil/CoverFetcher.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/coil/CoverFetcher.kt @@ -18,32 +18,20 @@ package org.oxycblt.auxio.image.coil -import android.content.Context -import android.graphics.Bitmap -import android.graphics.BitmapFactory -import android.graphics.Canvas -import androidx.core.graphics.drawable.toDrawable import coil3.ImageLoader -import coil3.asImage import coil3.decode.DataSource import coil3.decode.ImageSource import coil3.fetch.FetchResult import coil3.fetch.Fetcher -import coil3.fetch.ImageFetchResult import coil3.fetch.SourceFetchResult import coil3.request.Options -import coil3.size.Dimension -import coil3.size.Size -import coil3.size.pxOrElse -import java.io.InputStream import javax.inject.Inject import okio.FileSystem import okio.buffer import okio.source import org.oxycblt.musikr.covers.Cover -class CoverFetcher private constructor(private val context: Context, private val cover: Cover) : - Fetcher { +class CoverFetcher private constructor(private val cover: Cover) : Fetcher { override suspend fun fetch(): FetchResult? { val stream = cover.open() ?: return null return SourceFetchResult( @@ -52,59 +40,8 @@ class CoverFetcher private constructor(private val context: Context, private val dataSource = DataSource.DISK) } - /** Derived from phonograph: https://github.com/kabouzeid/Phonograph */ - private suspend fun createMosaic(streams: List, size: Size): FetchResult { - // Use whatever size coil gives us to create the mosaic. - val mosaicSize = android.util.Size(size.width.mosaicSize(), size.height.mosaicSize()) - val mosaicFrameSize = - Size(Dimension(mosaicSize.width / 2), Dimension(mosaicSize.height / 2)) - - val mosaicBitmap = - Bitmap.createBitmap(mosaicSize.width, mosaicSize.height, 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 == mosaicSize.height) { - break - } - - // Crop the bitmap down to a square so it leaves no empty space - // TODO: Work around this - val bitmap = - SquareCropTransformation.INSTANCE.transform( - BitmapFactory.decodeStream(stream), mosaicFrameSize) - canvas.drawBitmap(bitmap, x.toFloat(), y.toFloat(), null) - - x += bitmap.width - if (x == mosaicSize.width) { - x = 0 - y += bitmap.height - } - } - - // It's way easier to map this into a drawable then try to serialize it into an - // BufferedSource. Just make sure we mark it as "sampled" so Coil doesn't try to - // load low-res mosaics into high-res ImageViews. - return ImageFetchResult( - image = mosaicBitmap.toDrawable(context.resources).asImage(), - isSampled = true, - dataSource = DataSource.DISK) - } - - private fun Dimension.mosaicSize(): Int { - // Since we want the mosaic to be perfectly divisible into two, we need to round any - // odd image sizes upwards to prevent the mosaic creation from failing. - val size = pxOrElse { 512 } - return if (size.mod(2) > 0) size + 1 else size - } - class Factory @Inject constructor() : Fetcher.Factory { override fun create(data: Cover, options: Options, imageLoader: ImageLoader) = - CoverFetcher(options.context, data) + CoverFetcher(data) } } diff --git a/app/src/main/java/org/oxycblt/auxio/image/coil/RoundedRectTransformation.kt b/app/src/main/java/org/oxycblt/auxio/image/coil/RoundedRectTransformation.kt index 214797ed3..6220f3bd7 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/coil/RoundedRectTransformation.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/coil/RoundedRectTransformation.kt @@ -38,8 +38,8 @@ import coil3.transform.Transformation import kotlin.math.roundToInt /** - * A vendoring of [coil.transform.RoundedCornersTransformation] that can handle non-1:1 aspect ratio - * images without cropping them. + * A vendoring of coil's RoundedCornersTransformation that can handle non-1:1 aspect ratio images + * without cropping them. * * @author Coil Team, Alexander Capehart (OxygenCobalt) */ diff --git a/app/src/main/java/org/oxycblt/auxio/image/coil/SquareCropTransformation.kt b/app/src/main/java/org/oxycblt/auxio/image/coil/SquareCropTransformation.kt index a7c780c92..cb06caffa 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/coil/SquareCropTransformation.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/coil/SquareCropTransformation.kt @@ -19,6 +19,7 @@ package org.oxycblt.auxio.image.coil import android.graphics.Bitmap +import androidx.core.graphics.scale import coil3.size.Size import coil3.size.pxOrElse import coil3.transform.Transformation @@ -46,7 +47,7 @@ class SquareCropTransformation : Transformation() { val desiredHeight = size.height.pxOrElse { dstSize } if (dstSize != desiredWidth || dstSize != desiredHeight) { // Image is not the desired size, upscale it. - return Bitmap.createScaledBitmap(dst, desiredWidth, desiredHeight, true) + return dst.scale(desiredWidth, desiredHeight) } return dst } diff --git a/app/src/main/java/org/oxycblt/auxio/list/recycler/FastScrollRecyclerView.kt b/app/src/main/java/org/oxycblt/auxio/list/recycler/FastScrollRecyclerView.kt index 4fe661b6d..04014c18b 100644 --- a/app/src/main/java/org/oxycblt/auxio/list/recycler/FastScrollRecyclerView.kt +++ b/app/src/main/java/org/oxycblt/auxio/list/recycler/FastScrollRecyclerView.kt @@ -34,6 +34,7 @@ import android.view.ViewGroup import android.view.WindowInsets import android.widget.FrameLayout import androidx.annotation.AttrRes +import androidx.core.view.isEmpty import androidx.core.view.isInvisible import androidx.core.view.updatePaddingRelative import androidx.core.widget.TextViewCompat @@ -91,7 +92,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr private var thumbAnimator: Animator? = null private val thumbView = - context.inflater.inflate(R.layout.view_scroll_thumb, null).apply { + context.inflater.inflate(R.layout.view_scroll_thumb, this).apply { thumbSlider.jumpOut(this) } private val thumbPadding = Rect(0, 0, 0, 0) @@ -339,7 +340,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr // [proportion of scroll position to scroll range] * [total thumb range] // This is somewhat adapted from the androidx RecyclerView FastScroller implementation. val offsetY = computeVerticalScrollOffset() - if (computeVerticalScrollRange() < height || childCount == 0) { + if (computeVerticalScrollRange() < height || isEmpty()) { fastScrollingPossible = false hideThumb() hidePopup() diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt index f1e1688d0..6b478c520 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicRepository.kt @@ -188,8 +188,8 @@ interface MusicRepository { /** * Flags indicating which kinds of music information changed. * - * @param deviceLibrary Whether the current [DeviceLibrary] has changed. - * @param library Whether the current [Playlist]s have changed. + * @param deviceLibrary Whether the current songs/albums/artists/genres has changed. + * @param userLibrary Whether the current playlists have changed. */ data class Changes(val deviceLibrary: Boolean, val userLibrary: Boolean) @@ -244,7 +244,7 @@ constructor( ) : MusicRepository { private val updateListeners = mutableListOf() private val indexingListeners = mutableListOf() - @Volatile private var indexingWorker: MusicRepository.IndexingWorker? = null + @Volatile private var indexingWorker: IndexingWorker? = null @Volatile override var library: MutableLibrary? = null @Volatile private var previousCompletedState: IndexingState.Completed? = null @@ -283,7 +283,7 @@ constructor( } @Synchronized - override fun registerWorker(worker: MusicRepository.IndexingWorker) { + override fun registerWorker(worker: IndexingWorker) { if (indexingWorker != null) { L.w("Worker is already registered") return @@ -293,7 +293,7 @@ constructor( } @Synchronized - override fun unregisterWorker(worker: MusicRepository.IndexingWorker) { + override fun unregisterWorker(worker: IndexingWorker) { if (indexingWorker !== worker) { L.w("Given worker did not match current worker") return diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicType.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicType.kt index 572280f8e..516dd1aa9 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicType.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicType.kt @@ -27,15 +27,10 @@ import org.oxycblt.auxio.R * @author Alexander Capehart (OxygenCobalt) */ enum class MusicType { - /** @see Song */ SONGS, - /** @see Album */ ALBUMS, - /** @see Artist */ ARTISTS, - /** @see Genre */ GENRES, - /** @see Playlist */ PLAYLISTS; /** diff --git a/app/src/main/java/org/oxycblt/auxio/music/locations/MusicSourcesDialog.kt b/app/src/main/java/org/oxycblt/auxio/music/locations/MusicSourcesDialog.kt index 3ca75b8f6..88a4132d5 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/locations/MusicSourcesDialog.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/locations/MusicSourcesDialog.kt @@ -25,6 +25,7 @@ import android.view.LayoutInflater import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.contract.ActivityResultContracts import androidx.appcompat.app.AlertDialog +import androidx.core.net.toUri import androidx.recyclerview.widget.ConcatAdapter import dagger.hilt.android.AndroidEntryPoint import javax.inject.Inject @@ -80,7 +81,7 @@ class MusicSourcesDialog : val locations = savedInstanceState?.getStringArrayList(KEY_PENDING_LOCATIONS)?.mapNotNull { - MusicLocation.existing(requireContext(), Uri.parse(it)) + MusicLocation.existing(requireContext(), it.toUri()) } ?: musicSettings.musicLocations locationAdapter.addAll(locations) diff --git a/app/src/main/java/org/oxycblt/auxio/music/locations/NewLocationFooterAdapter.kt b/app/src/main/java/org/oxycblt/auxio/music/locations/NewLocationFooterAdapter.kt index 156c4c049..4623db510 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/locations/NewLocationFooterAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/locations/NewLocationFooterAdapter.kt @@ -51,7 +51,7 @@ class NewLocationFooterAdapter(private val listener: Listener) : } /** - * A [RecyclerView.ViewHolder] that displays a "New Playlist" choice in [NewPlaylistFooterAdapter]. + * A [RecyclerView.ViewHolder] that displays a "New Playlist" choice in [NewLocationFooterAdapter]. * Use [from] to create an instance. * * @author Alexander Capehart (OxygenCobalt) diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackUtil.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackUtil.kt index 17b4fcc12..5ec328f91 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackUtil.kt @@ -48,13 +48,6 @@ fun Long.dsToMs() = times(100) */ fun Long.dsToSecs() = floorDiv(10) -/** - * Convert seconds into milliseconds. - * - * @return A converted millisecond value. - */ -fun Long.secsToMs() = times(1000) - /** * Convert a millisecond value into a string duration. * diff --git a/app/src/main/java/org/oxycblt/auxio/playback/service/BetterShuffleOrder.kt b/app/src/main/java/org/oxycblt/auxio/playback/service/BetterShuffleOrder.kt index 0f037a75a..0b95e4c4b 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/service/BetterShuffleOrder.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/service/BetterShuffleOrder.kt @@ -18,7 +18,9 @@ package org.oxycblt.auxio.playback.service +import androidx.annotation.OptIn import androidx.media3.common.C +import androidx.media3.common.util.UnstableApi import androidx.media3.exoplayer.source.ShuffleOrder /** @@ -28,6 +30,7 @@ import androidx.media3.exoplayer.source.ShuffleOrder * * @author media3 team, Alexander Capehart (OxygenCobalt) */ +@OptIn(UnstableApi::class) class BetterShuffleOrder(private val shuffled: IntArray) : ShuffleOrder { private val indexInShuffled: IntArray = IntArray(shuffled.size) diff --git a/app/src/main/java/org/oxycblt/auxio/playback/service/ExoPlaybackStateHolder.kt b/app/src/main/java/org/oxycblt/auxio/playback/service/ExoPlaybackStateHolder.kt index b2d89d5c6..491ae281c 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/service/ExoPlaybackStateHolder.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/service/ExoPlaybackStateHolder.kt @@ -22,11 +22,13 @@ import android.content.Context import android.content.Intent import android.media.audiofx.AudioEffect import android.provider.OpenableColumns +import androidx.annotation.OptIn import androidx.media3.common.AudioAttributes import androidx.media3.common.C import androidx.media3.common.MediaItem import androidx.media3.common.PlaybackException import androidx.media3.common.Player +import androidx.media3.common.util.UnstableApi import androidx.media3.decoder.ffmpeg.FfmpegAudioRenderer import androidx.media3.exoplayer.ExoPlayer import androidx.media3.exoplayer.RenderersFactory @@ -62,6 +64,7 @@ import org.oxycblt.musikr.MusicParent import org.oxycblt.musikr.Song import timber.log.Timber as L +@OptIn(UnstableApi::class) class ExoPlaybackStateHolder( private val context: Context, private val player: ExoPlayer, diff --git a/app/src/main/java/org/oxycblt/auxio/playback/service/SystemModule.kt b/app/src/main/java/org/oxycblt/auxio/playback/service/SystemModule.kt index cda467cfb..2854d4873 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/service/SystemModule.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/service/SystemModule.kt @@ -19,6 +19,8 @@ package org.oxycblt.auxio.playback.service import android.content.Context +import androidx.annotation.OptIn +import androidx.media3.common.util.UnstableApi import androidx.media3.datasource.ContentDataSource import androidx.media3.datasource.DataSource import androidx.media3.exoplayer.source.MediaSource @@ -41,6 +43,7 @@ import dagger.hilt.components.SingletonComponent @Module @InstallIn(SingletonComponent::class) +@OptIn(UnstableApi::class) class SystemModule { @Provides fun mediaSourceFactory( diff --git a/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt b/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt index 11f4b5175..7f278df5c 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/AboutFragment.kt @@ -20,9 +20,9 @@ package org.oxycblt.auxio.settings import android.content.Context import android.content.Intent -import android.net.Uri import android.os.Bundle import android.view.LayoutInflater +import androidx.core.net.toUri import androidx.core.view.updatePadding import androidx.fragment.app.activityViewModels import androidx.navigation.fragment.findNavController @@ -102,7 +102,7 @@ class AboutFragment : ViewBindingFragment() { } private fun Context.sendEmail(recipient: String) { - val intent = Intent(Intent.ACTION_SENDTO).apply { data = Uri.parse("mailto:$recipient") } + val intent = Intent(Intent.ACTION_SENDTO).apply { data = "mailto:$recipient".toUri() } startIntent(intent) } diff --git a/app/src/main/java/org/oxycblt/auxio/ui/Animations.kt b/app/src/main/java/org/oxycblt/auxio/ui/Animations.kt index edbaf01ef..986893cc3 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/Animations.kt +++ b/app/src/main/java/org/oxycblt/auxio/ui/Animations.kt @@ -46,25 +46,25 @@ class AnimConfig( companion object { val STANDARD = MR.attr.motionEasingStandardInterpolator - val EMPHASIZED = MR.attr.motionEasingEmphasizedInterpolator + // val EMPHASIZED = MR.attr.motionEasingEmphasizedInterpolator val EMPHASIZED_ACCELERATE = MR.attr.motionEasingEmphasizedAccelerateInterpolator val EMPHASIZED_DECELERATE = MR.attr.motionEasingEmphasizedDecelerateInterpolator val SHORT1 = MR.attr.motionDurationShort1 to 50 - val SHORT2 = MR.attr.motionDurationShort2 to 100 + // val SHORT2 = MR.attr.motionDurationShort2 to 100 val SHORT3 = MR.attr.motionDurationShort3 to 150 - val SHORT4 = MR.attr.motionDurationShort4 to 200 + // val SHORT4 = MR.attr.motionDurationShort4 to 200 val MEDIUM1 = MR.attr.motionDurationMedium1 to 250 val MEDIUM2 = MR.attr.motionDurationMedium2 to 300 val MEDIUM3 = MR.attr.motionDurationMedium3 to 350 - val MEDIUM4 = MR.attr.motionDurationMedium4 to 400 - val LONG1 = MR.attr.motionDurationLong1 to 450 - val LONG2 = MR.attr.motionDurationLong2 to 500 - val LONG3 = MR.attr.motionDurationLong3 to 550 - val LONG4 = MR.attr.motionDurationLong4 to 600 - val EXTRA_LONG1 = MR.attr.motionDurationExtraLong1 to 700 - val EXTRA_LONG2 = MR.attr.motionDurationExtraLong2 to 800 - val EXTRA_LONG3 = MR.attr.motionDurationExtraLong3 to 900 - val EXTRA_LONG4 = MR.attr.motionDurationExtraLong4 to 1000 + // val MEDIUM4 = MR.attr.motionDurationMedium4 to 400 + // val LONG1 = MR.attr.motionDurationLong1 to 450 + // val LONG2 = MR.attr.motionDurationLong2 to 500 + // val LONG3 = MR.attr.motionDurationLong3 to 550 + // val LONG4 = MR.attr.motionDurationLong4 to 600 + // val EXTRA_LONG1 = MR.attr.motionDurationExtraLong1 to 700 + // val EXTRA_LONG2 = MR.attr.motionDurationExtraLong2 to 800 + // val EXTRA_LONG3 = MR.attr.motionDurationExtraLong3 to 900 + // val EXTRA_LONG4 = MR.attr.motionDurationExtraLong4 to 1000 fun of(context: Context, @AttrRes interpolator: Int, duration: Pair) = AnimConfig(context, interpolator, duration.first, duration.second) @@ -122,7 +122,7 @@ private constructor( } } - fun jumpToFadeIn(view: View) { + private fun jumpToFadeIn(view: View) { view.apply { alpha = 1f scaleX = 1.0f diff --git a/app/src/main/java/org/oxycblt/auxio/util/FrameworkUtil.kt b/app/src/main/java/org/oxycblt/auxio/util/FrameworkUtil.kt index ec6091863..2322a196e 100644 --- a/app/src/main/java/org/oxycblt/auxio/util/FrameworkUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/util/FrameworkUtil.kt @@ -24,7 +24,6 @@ import android.content.Context import android.content.Intent import android.content.pm.PackageManager import android.graphics.PointF -import android.graphics.drawable.Drawable import android.os.Build import android.view.View import android.view.WindowInsets @@ -36,7 +35,6 @@ import androidx.appcompat.widget.Toolbar import androidx.coordinatorlayout.widget.CoordinatorLayout import androidx.core.app.ShareCompat import androidx.core.graphics.Insets -import androidx.core.graphics.drawable.DrawableCompat import androidx.core.net.toUri import androidx.core.view.children import androidx.navigation.NavController @@ -106,10 +104,6 @@ private fun isUnderImpl( val View.isRtl: Boolean get() = layoutDirection == View.LAYOUT_DIRECTION_RTL -/** Whether this [Drawable] is using an RTL layout direction. */ -val Drawable.isRtl: Boolean - get() = DrawableCompat.getLayoutDirection(this) == View.LAYOUT_DIRECTION_RTL - /** Get a [Context] from a [ViewBinding]'s root [View]. */ val ViewBinding.context: Context get() = root.context @@ -357,7 +351,7 @@ fun Context.startIntent(intent: Intent) { // No app installed to open the link showToast(R.string.err_no_app) } - } else if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R) { + } else { // On older versions of android, opening links from an ACTION_VIEW intent might // not work in all cases, especially when no default app was set. If that is the // case, we will try to manually handle these cases before we try to launch the diff --git a/app/src/main/java/org/oxycblt/auxio/util/StateUtil.kt b/app/src/main/java/org/oxycblt/auxio/util/StateUtil.kt index 7f9f4e9a5..eb74d8f15 100644 --- a/app/src/main/java/org/oxycblt/auxio/util/StateUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/util/StateUtil.kt @@ -22,18 +22,11 @@ import androidx.fragment.app.Fragment import androidx.lifecycle.Lifecycle import androidx.lifecycle.lifecycleScope import androidx.lifecycle.repeatOnLifecycle -import java.util.concurrent.TimeoutException import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.TimeoutCancellationException -import kotlinx.coroutines.channels.ReceiveChannel -import kotlinx.coroutines.channels.SendChannel import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.combine import kotlinx.coroutines.launch -import kotlinx.coroutines.withTimeout -import org.oxycblt.auxio.BuildConfig -import timber.log.Timber as L /** * A wrapper around [StateFlow] exposing a one-time consumable event. @@ -153,71 +146,3 @@ private fun Fragment.launch( ) { viewLifecycleOwner.lifecycleScope.launch { viewLifecycleOwner.repeatOnLifecycle(state, block) } } - -const val DEFAULT_TIMEOUT = 60000L - -/** - * Wraps [SendChannel.send] with a specified timeout. - * - * @param element The element to send. - * @param timeout The timeout in milliseconds. Defaults to 10 seconds. - * @throws TimeoutException If the timeout is reached, provides context on what element - * specifically. - */ -suspend fun SendChannel.sendWithTimeout(element: E, timeout: Long = DEFAULT_TIMEOUT) { - try { - withTimeout(timeout) { send(element) } - } catch (e: TimeoutCancellationException) { - L.e("Failed to send element to channel $e in ${timeout}ms.") - if (BuildConfig.DEBUG) { - throw TimeoutException("Timed out sending element to channel: $e") - } else { - L.e(e.stackTraceToString()) - send(element) - } - } -} - -/** - * Wraps a [ReceiveChannel] consumption with a specified timeout. Note that the timeout will only - * start on the first element received, as to prevent initialization of dependent coroutines being - * interpreted as a timeout. - * - * @param action The action to perform on each element received. - * @param timeout The timeout in milliseconds. Defaults to 10 seconds. - * @throws TimeoutException If the timeout is reached, provides context on what element - * specifically. - */ -suspend fun ReceiveChannel.forEachWithTimeout( - timeout: Long = DEFAULT_TIMEOUT, - action: suspend (E) -> Unit -) { - var exhausted = false - var subsequent = false - val handler: suspend () -> Unit = { - val value = receiveCatching() - if (value.isClosed && value.exceptionOrNull() == null) { - exhausted = true - } else { - action(value.getOrThrow()) - } - } - while (!exhausted) { - try { - if (subsequent) { - withTimeout(timeout) { handler() } - } else { - handler() - subsequent = true - } - } catch (e: TimeoutCancellationException) { - L.e("Failed to send element to channel $e in ${timeout}ms.") - if (BuildConfig.DEBUG) { - throw TimeoutException("Timed out sending element to channel: $e") - } else { - L.e(e.stackTraceToString()) - handler() - } - } - } -} diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetBitmapTransformation.kt b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetBitmapTransformation.kt index d844026af..7ad05b026 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetBitmapTransformation.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetBitmapTransformation.kt @@ -20,6 +20,7 @@ package org.oxycblt.auxio.widgets import android.content.res.Resources import android.graphics.Bitmap +import androidx.core.graphics.scale import coil3.size.Size import coil3.transform.Transformation import kotlin.math.sqrt @@ -49,7 +50,7 @@ class WidgetBitmapTransformation(reduce: Float) : Transformation() { val scale = sqrt(maxBitmapArea / inputArea.toDouble()) val newWidth = (input.width * scale).toInt() val newHeight = (input.height * scale).toInt() - return Bitmap.createScaledBitmap(input, newWidth, newHeight, true) + return input.scale(newWidth, newHeight) } return input } diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetUtil.kt b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetUtil.kt index 049531c88..a5e32881b 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetUtil.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetUtil.kt @@ -19,7 +19,6 @@ package org.oxycblt.auxio.widgets import android.appwidget.AppWidgetManager -import android.appwidget.AppWidgetProviderInfo import android.content.ComponentName import android.content.Context import android.os.Build @@ -66,11 +65,6 @@ fun RemoteViews.setLayoutDirection(@IdRes viewId: Int, layoutDirection: Int) { setInt(viewId, "setLayoutDirection", layoutDirection) } -fun AppWidgetManager.setWidgetPreviewCompat(component: ComponentName, remoteViews: RemoteViews) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) { - setWidgetPreview(component, AppWidgetProviderInfo.WIDGET_CATEGORY_HOME_SCREEN, remoteViews) - } -} /** * Update the app widget layouts corresponding to the given [WidgetProvider] [ComponentName] with an * adaptive layout, in a version-compatible manner. diff --git a/app/src/main/res/layout-h360dp/fragment_detail.xml b/app/src/main/res/layout-h360dp/fragment_detail.xml index 12bb1598b..8a980b1c0 100644 --- a/app/src/main/res/layout-h360dp/fragment_detail.xml +++ b/app/src/main/res/layout-h360dp/fragment_detail.xml @@ -119,7 +119,8 @@ app:layout_constraintEnd_toStartOf="@+id/detail_shuffle_button" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/detail_cover" /> + app:layout_constraintTop_toBottomOf="@+id/detail_cover" + tools:ignore="RtlSymmetry" /> + app:layout_constraintTop_toBottomOf="@+id/detail_info" + tools:ignore="RtlSymmetry"/> + app:layout_constraintTop_toTopOf="@+id/detail_play_button" + tools:ignore="RtlSymmetry" /> + app:layout_constraintTop_toTopOf="@+id/detail_play_button" + tools:ignore="RtlSymmetry" /> + xmlns:tools="http://schemas.android.com/tools"> \ No newline at end of file diff --git a/app/src/main/res/layout/widget_wafer_thin.xml b/app/src/main/res/layout/widget_wafer_thin.xml index 385a39fe7..86f1581ca 100644 --- a/app/src/main/res/layout/widget_wafer_thin.xml +++ b/app/src/main/res/layout/widget_wafer_thin.xml @@ -22,7 +22,7 @@ android:scaleType="centerCrop" android:background="@drawable/ui_widget_bg_round" android:clipToOutline="true" - tools:ignore="ContentDescription" /> + tools:ignore="ContentDescription,UnusedAttribute" /> + tools:ignore="ContentDescription,UnusedAttribute" /> Kafe -%.1f dB %d kbps - Duke ngarkuar bibliotekën tuaj muzikore... (%1$d/%2$d) + Duke ngarkuar bibliotekën tuaj muzikore… (%1$d/%2$d) Këngët e ngarkuara: %d Albumet e ngarkuara: %d Artistët e ngarkuar: %d diff --git a/app/src/main/res/values/themes_black.xml b/app/src/main/res/values/themes_black.xml index 75b8f6d24..ce5b0f676 100644 --- a/app/src/main/res/values/themes_black.xml +++ b/app/src/main/res/values/themes_black.xml @@ -1,6 +1,9 @@ - -