Created
May 16, 2025 21:13
-
-
Save ColeMurray/44f2ed90e5e589470582ab3e7c3716fe to your computer and use it in GitHub Desktop.
auxio.patch
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/app/src/main/java/org/oxycblt/auxio/MainFragment.kt b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt | |
| index 10342f1d..1500a57e 100644 | |
| --- a/app/src/main/java/org/oxycblt/auxio/MainFragment.kt | |
| +++ b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt | |
| @@ -133,66 +133,68 @@ class MainFragment : | |
| SelectionBackPressedCallback(listModel).also { selectionBackCallback = it } | |
| speedDialBackCallback = SpeedDialBackPressedCallback() | |
| navigationListener = DialogAwareNavigationListener(::onExploreNavigate) | |
| // --- UI SETUP --- | |
| val context = requireActivity() | |
| binding.root.setOnApplyWindowInsetsListener { _, insets -> | |
| lastInsets = insets | |
| insets | |
| } | |
| // Send meaningful accessibility events for bottom sheets | |
| ViewCompat.setAccessibilityPaneTitle( | |
| binding.playbackSheet, context.getString(R.string.lbl_playback)) | |
| ViewCompat.setAccessibilityPaneTitle( | |
| binding.queueSheet, context.getString(R.string.lbl_queue)) | |
| if (queueSheetBehavior != null) { | |
| // In portrait mode, set up click listeners on the stacked sheets. | |
| L.d("Configuring stacked bottom sheets") | |
| unlikelyToBeNull(binding.queueHandleWrapper).setOnClickListener { | |
| playbackModel.openQueue() | |
| } | |
| + binding.queueClear?.setOnClickListener { playbackModel.clearQueue() } | |
| } else { | |
| // Dual-pane mode, manually style the static queue sheet. | |
| L.d("Configuring dual-pane bottom sheet") | |
| binding.queueSheet.apply { | |
| // Emulate the elevated bottom sheet style. | |
| background = | |
| MaterialShapeDrawable.createWithElevationOverlay(context).apply { | |
| shapeAppearanceModel = | |
| ShapeAppearanceModel.builder( | |
| context, | |
| MR.style.ShapeAppearance_Material3_Corner_ExtraLarge, | |
| MR.style.ShapeAppearanceOverlay_Material3_Corner_Top) | |
| .build() | |
| fillColor = context.getAttrColorCompat(MR.attr.colorSurfaceContainerHigh) | |
| } | |
| } | |
| + binding.queueClear?.setOnClickListener { playbackModel.clearQueue() } | |
| } | |
| normalCornerSize = playbackSheetBehavior.sheetBackgroundDrawable.topLeftCornerResolvedSize | |
| maxScaleXDistance = | |
| context.getDimen(MR.dimen.m3_back_progress_bottom_container_max_scale_x_distance) | |
| binding.playbackSheet.elevation = 0f | |
| binding.mainScrim.setOnClickListener { binding.homeNewPlaylistFab.close() } | |
| binding.sheetScrim.setOnClickListener { binding.homeNewPlaylistFab.close() } | |
| binding.homeShuffleFab.setOnClickListener { playbackModel.shuffleAll() } | |
| binding.homeNewPlaylistFab.apply { | |
| inflate(R.menu.new_playlist_actions) | |
| setOnActionSelectedListener(this@MainFragment) | |
| setChangeListener(::updateSpeedDial) | |
| } | |
| forceHideAllFabs() | |
| updateSpeedDial(false) | |
| updateFabVisibility( | |
| binding, | |
| homeModel.songList.value, | |
| homeModel.isFastScrolling.value, | |
| homeModel.currentTabType.value) | |
| diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt | |
| index 67d8160f..eec41628 100644 | |
| --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt | |
| +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt | |
| @@ -536,50 +536,56 @@ constructor( | |
| fun addToQueue(genre: Genre) { | |
| L.d("Adding $genre to queue") | |
| playbackManager.addToQueue(listSettings.genreSongSort.songs(genre.songs)) | |
| } | |
| /** | |
| * Add a [Playlist] to the end of the queue. | |
| * | |
| * @param playlist The [Playlist] to add. | |
| */ | |
| fun addToQueue(playlist: Playlist) { | |
| L.d("Adding $playlist to queue") | |
| playbackManager.addToQueue(playlist.songs) | |
| } | |
| /** | |
| * Add [Song]s to the end of the queue. | |
| * | |
| * @param songs The [Song]s to add. | |
| */ | |
| fun addToQueue(songs: List<Song>) { | |
| L.d("Adding ${songs.size} songs to queue") | |
| playbackManager.addToQueue(songs) | |
| } | |
| + /** Remove all songs from the queue except the one currently playing. */ | |
| + fun clearQueue() { | |
| + L.d("Clearing queue") | |
| + playbackManager.clearQueue() | |
| + } | |
| + | |
| // --- STATUS FUNCTIONS --- | |
| /** Toggle [isPlaying] (i.e from playing to paused) */ | |
| fun togglePlaying() { | |
| L.d("Toggling playing state") | |
| playbackManager.playing(!playbackManager.progression.isPlaying) | |
| } | |
| /** Toggle [isShuffled] (ex. from on to off) */ | |
| fun toggleShuffled() { | |
| L.d("Toggling shuffled state") | |
| playbackManager.shuffled(!playbackManager.isShuffled) | |
| } | |
| /** | |
| * Toggle [repeatMode] (ex. from [RepeatMode.NONE] to [RepeatMode.TRACK]) | |
| * | |
| * @see RepeatMode.increment | |
| */ | |
| fun toggleRepeatMode() { | |
| L.d("Toggling repeat mode") | |
| playbackManager.repeatMode(playbackManager.repeatMode.increment()) | |
| } | |
| // --- UI CONTROL --- | |
| diff --git a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt | |
| index e0aede3a..a3018fdc 100644 | |
| --- a/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt | |
| +++ b/app/src/main/java/org/oxycblt/auxio/playback/state/PlaybackStateManager.kt | |
| @@ -155,50 +155,55 @@ interface PlaybackStateManager { | |
| */ | |
| fun addToQueue(songs: List<Song>) | |
| /** | |
| * Add a [Song] to the end of the queue. | |
| * | |
| * @param song The [Song] to add. | |
| */ | |
| fun addToQueue(song: Song) = addToQueue(listOf(song)) | |
| /** | |
| * Move a [Song] in the queue. | |
| * | |
| * @param src The position of the [Song] to move in the queue. | |
| * @param dst The destination position in the queue. | |
| */ | |
| fun moveQueueItem(src: Int, dst: Int) | |
| /** | |
| * Remove a [Song] from the queue. | |
| * | |
| * @param at The position of the [Song] to remove in the queue. | |
| */ | |
| fun removeQueueItem(at: Int) | |
| + /** | |
| + * Remove all songs from the queue except the one currently playing. | |
| + */ | |
| + fun clearQueue() | |
| + | |
| /** | |
| * (Re)shuffle or (Re)order this instance. | |
| * | |
| * @param shuffled Whether to shuffle the queue or not. | |
| */ | |
| fun shuffled(shuffled: Boolean) | |
| /** | |
| * Acknowledges that an event has happened that modified the state held by the current | |
| * [PlaybackStateHolder]. | |
| * | |
| * @param stateHolder The [PlaybackStateHolder] to synchronize with. Must be the current | |
| * [PlaybackStateHolder]. Does nothing if invoked by another [PlaybackStateHolder] | |
| * implementation. | |
| * @param ack The [StateAck] to acknowledge. | |
| */ | |
| fun ack(stateHolder: PlaybackStateHolder, ack: StateAck) | |
| /** | |
| * Start a [DeferredPlayback] for the current [PlaybackStateHolder] to handle eventually. | |
| * | |
| * @param action The [DeferredPlayback] to perform. | |
| */ | |
| fun playDeferred(action: DeferredPlayback) | |
| @@ -494,50 +499,61 @@ class PlaybackStateManagerImpl @Inject constructor() : PlaybackStateManager { | |
| L.d("Adding ${songs.size} songs to end of queue") | |
| stateHolder.addToQueue(songs, StateAck.AddToQueue(queue.size, songs.size)) | |
| } | |
| } | |
| private class QueueCommand(override val queue: List<Song>) : PlaybackCommand { | |
| override val song: Song? = null | |
| override val parent: MusicParent? = null | |
| override val shuffled = false | |
| } | |
| @Synchronized | |
| override fun moveQueueItem(src: Int, dst: Int) { | |
| val stateHolder = stateHolder ?: return | |
| L.d("Moving item $src to position $dst") | |
| stateHolder.move(src, dst, StateAck.Move(src, dst)) | |
| } | |
| @Synchronized | |
| override fun removeQueueItem(at: Int) { | |
| val stateHolder = stateHolder ?: return | |
| L.d("Removing item at $at") | |
| stateHolder.remove(at, StateAck.Remove(at)) | |
| } | |
| + @Synchronized | |
| + override fun clearQueue() { | |
| + val stateHolder = stateHolder ?: return | |
| + L.d("Clearing queue except current song") | |
| + for (i in stateMirror.queue.indices.reversed()) { | |
| + if (i != stateMirror.index) { | |
| + stateHolder.remove(i, StateAck.Remove(i)) | |
| + } | |
| + } | |
| + } | |
| + | |
| @Synchronized | |
| override fun shuffled(shuffled: Boolean) { | |
| val stateHolder = stateHolder ?: return | |
| L.d("Reordering queue [shuffled=$shuffled]") | |
| stateHolder.shuffled(shuffled) | |
| } | |
| // --- INTERNAL PLAYER FUNCTIONS --- | |
| @Synchronized | |
| override fun playDeferred(action: DeferredPlayback) { | |
| val stateHolder = stateHolder | |
| if (stateHolder == null || !stateHolder.handleDeferred(action)) { | |
| L.d("Internal player not present or did not consume action, waiting") | |
| pendingDeferredPlayback = action | |
| } | |
| } | |
| @Synchronized | |
| override fun requestAction(stateHolder: PlaybackStateHolder) { | |
| if (BuildConfig.DEBUG && this.stateHolder !== stateHolder) { | |
| L.w("Given internal player did not match current internal player") | |
| return | |
| } | |
| diff --git a/app/src/main/res/layout-w720dp/fragment_main.xml b/app/src/main/res/layout-w720dp/fragment_main.xml | |
| index c7cd805f..90aa551f 100644 | |
| --- a/app/src/main/res/layout-w720dp/fragment_main.xml | |
| +++ b/app/src/main/res/layout-w720dp/fragment_main.xml | |
| @@ -86,54 +86,75 @@ | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" /> | |
| <androidx.constraintlayout.widget.ConstraintLayout | |
| style="@style/Widget.Auxio.DisableDropShadows" | |
| android:layout_width="match_parent" | |
| android:layout_height="match_parent" | |
| android:orientation="horizontal"> | |
| <androidx.fragment.app.FragmentContainerView | |
| android:id="@+id/playback_panel_fragment" | |
| android:name="org.oxycblt.auxio.playback.PlaybackPanelFragment" | |
| android:layout_width="0dp" | |
| android:layout_height="match_parent" | |
| app:layout_constraintEnd_toStartOf="@+id/queue_sheet" | |
| app:layout_constraintStart_toStartOf="parent" /> | |
| <LinearLayout | |
| android:id="@+id/queue_sheet" | |
| android:layout_width="0dp" | |
| android:layout_height="match_parent" | |
| android:orientation="vertical" | |
| app:layout_constraintEnd_toEndOf="parent" | |
| app:layout_constraintStart_toEndOf="@+id/playback_panel_fragment"> | |
| - <TextView | |
| + <androidx.constraintlayout.widget.ConstraintLayout | |
| + android:id="@+id/queue_header" | |
| android:layout_width="match_parent" | |
| - android:layout_height="64dp" | |
| - android:gravity="center" | |
| - android:text="@string/lbl_queue" | |
| - android:textAppearance="@style/TextAppearance.Auxio.LabelLarge" | |
| - android:textColor="?attr/colorOnSurfaceVariant" | |
| - app:layout_constraintBottom_toBottomOf="@+id/handle" | |
| - app:layout_constraintEnd_toEndOf="@+id/handle" | |
| - app:layout_constraintStart_toStartOf="parent" /> | |
| + android:layout_height="64dp"> | |
| + | |
| + <TextView | |
| + android:id="@+id/queue_title" | |
| + android:layout_width="wrap_content" | |
| + android:layout_height="wrap_content" | |
| + android:layout_marginStart="@dimen/spacing_small" | |
| + android:layout_gravity="center_vertical" | |
| + android:text="@string/lbl_queue" | |
| + android:textAppearance="@style/TextAppearance.Auxio.LabelLarge" | |
| + android:textColor="?attr/colorOnSurfaceVariant" | |
| + app:layout_constraintBottom_toBottomOf="parent" | |
| + app:layout_constraintStart_toStartOf="parent" | |
| + app:layout_constraintTop_toTopOf="parent" /> | |
| + | |
| + <org.oxycblt.auxio.ui.RippleFixMaterialButton | |
| + android:id="@+id/queue_clear" | |
| + style="@style/Widget.Auxio.Button.Icon.Small.Secondary" | |
| + android:layout_width="wrap_content" | |
| + android:layout_height="wrap_content" | |
| + android:layout_marginEnd="@dimen/spacing_small" | |
| + android:contentDescription="@string/desc_clear_queue" | |
| + app:icon="@drawable/ic_delete_24" | |
| + app:layout_constraintBottom_toBottomOf="parent" | |
| + app:layout_constraintEnd_toEndOf="parent" | |
| + app:layout_constraintTop_toTopOf="parent" /> | |
| + | |
| + </androidx.constraintlayout.widget.ConstraintLayout> | |
| <androidx.fragment.app.FragmentContainerView | |
| android:id="@+id/queue_fragment" | |
| android:name="org.oxycblt.auxio.playback.queue.QueueFragment" | |
| android:layout_width="match_parent" | |
| android:layout_height="0dp" | |
| android:layout_weight="1" /> | |
| </LinearLayout> | |
| </androidx.constraintlayout.widget.ConstraintLayout> | |
| <View | |
| android:id="@+id/sheet_scrim" | |
| android:layout_width="match_parent" | |
| android:layout_height="match_parent" /> | |
| </androidx.coordinatorlayout.widget.CoordinatorLayout> | |
| </androidx.coordinatorlayout.widget.CoordinatorLayout> | |
| diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml | |
| index 9c4de0ad..cb6223e2 100644 | |
| --- a/app/src/main/res/layout/fragment_main.xml | |
| +++ b/app/src/main/res/layout/fragment_main.xml | |
| @@ -101,48 +101,60 @@ | |
| android:focusable="true" | |
| android:orientation="vertical" | |
| app:layout_behavior="org.oxycblt.auxio.playback.queue.QueueBottomSheetBehavior"> | |
| <androidx.constraintlayout.widget.ConstraintLayout | |
| android:id="@+id/queue_handle_wrapper" | |
| android:layout_width="match_parent" | |
| android:layout_height="@dimen/size_touchable_large" | |
| android:contentDescription="@string/desc_queue_bar"> | |
| <com.google.android.material.bottomsheet.BottomSheetDragHandleView | |
| android:id="@+id/queue_handle" | |
| android:layout_width="match_parent" | |
| android:layout_height="wrap_content" | |
| android:paddingBottom="@dimen/spacing_medium" | |
| app:layout_constraintTop_toTopOf="parent" /> | |
| <TextView | |
| android:id="@+id/queue_title" | |
| android:layout_width="wrap_content" | |
| android:layout_height="wrap_content" | |
| android:text="@string/lbl_queue" | |
| android:textAppearance="@style/TextAppearance.Auxio.LabelLarge" | |
| android:textColor="?attr/colorOnSurfaceVariant" | |
| app:layout_constraintBottom_toBottomOf="@+id/queue_handle" | |
| - app:layout_constraintEnd_toEndOf="@+id/queue_handle" | |
| + app:layout_constraintEnd_toStartOf="@id/queue_clear" | |
| app:layout_constraintStart_toStartOf="parent" /> | |
| + <org.oxycblt.auxio.ui.RippleFixMaterialButton | |
| + android:id="@+id/queue_clear" | |
| + style="@style/Widget.Auxio.Button.Icon.Small.Secondary" | |
| + android:layout_width="wrap_content" | |
| + android:layout_height="wrap_content" | |
| + android:layout_marginEnd="@dimen/spacing_small" | |
| + android:contentDescription="@string/desc_clear_queue" | |
| + app:icon="@drawable/ic_delete_24" | |
| + app:layout_constraintBottom_toBottomOf="@+id/queue_handle" | |
| + app:layout_constraintEnd_toEndOf="@+id/queue_handle" | |
| + app:layout_constraintTop_toTopOf="@+id/queue_handle" /> | |
| + | |
| </androidx.constraintlayout.widget.ConstraintLayout> | |
| <androidx.fragment.app.FragmentContainerView | |
| android:id="@+id/queue_fragment" | |
| android:name="org.oxycblt.auxio.playback.queue.QueueFragment" | |
| android:layout_width="match_parent" | |
| android:layout_height="0dp" | |
| android:layout_weight="1" /> | |
| </LinearLayout> | |
| <View | |
| android:id="@+id/sheet_scrim" | |
| android:layout_width="match_parent" | |
| android:layout_height="match_parent" | |
| android:visibility="invisible" /> | |
| </androidx.coordinatorlayout.widget.CoordinatorLayout> | |
| </androidx.coordinatorlayout.widget.CoordinatorLayout> | |
| diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml | |
| index 0b5830db..cae8d340 100644 | |
| --- a/app/src/main/res/values/strings.xml | |
| +++ b/app/src/main/res/values/strings.xml | |
| @@ -106,50 +106,51 @@ | |
| <!-- As in to not filter --> | |
| <string name="lbl_filter_all">All</string> | |
| <string name="lbl_name">Name</string> | |
| <string name="lbl_date">Date</string> | |
| <string name="lbl_duration">Duration</string> | |
| <string name="lbl_song_count">Song count</string> | |
| <string name="lbl_disc">Disc</string> | |
| <string name="lbl_track">Track</string> | |
| <string name="lbl_date_added">Date added</string> | |
| <string name="lbl_sort">Sort</string> | |
| <string name="lbl_sort_mode">Sort by</string> | |
| <string name="lbl_sort_direction">Direction</string> | |
| <string name="lbl_sort_asc">Ascending</string> | |
| <string name="lbl_sort_dsc">Descending</string> | |
| <string name="lbl_playback">Now playing</string> | |
| <string name="lbl_equalizer">Equalizer</string> | |
| <string name="lbl_play">Play</string> | |
| <string name="lbl_shuffle">Shuffle</string> | |
| <string name="lbl_queue">Queue</string> | |
| <string name="lbl_play_next">Play next</string> | |
| <string name="lbl_queue_add">Add to queue</string> | |
| + <string name="lbl_clear_queue">Clear queue</string> | |
| <string name="lbl_playlist_add">Add to playlist</string> | |
| <string name="lbl_artist_details">Go to artist</string> | |
| <string name="lbl_album_details">Go to album</string> | |
| <string name="lbl_song_detail">View properties</string> | |
| <string name="lbl_parent_detail">View</string> | |
| <string name="lbl_share">Share</string> | |
| <string name="lbl_props">Song properties</string> | |
| <string name="lbl_path">Path</string> | |
| <!-- As in audio format --> | |
| <string name="lbl_format">Format</string> | |
| <!-- As in file size --> | |
| <string name="lbl_size">Size</string> | |
| <string name="lbl_bitrate">Bit rate</string> | |
| <string name="lbl_sample_rate">Sample rate</string> | |
| <string name="lbl_replaygain_track">ReplayGain Track Adjustment</string> | |
| <string name="lbl_replaygain_album">ReplayGain Album Adjustment</string> | |
| <!-- Limit to 10 characters --> | |
| <string name="lbl_shuffle_shortcut_short">Shuffle</string> | |
| <!-- Limit to 25 characters --> | |
| <string name="lbl_shuffle_shortcut_long">Shuffle all</string> | |
| <string name="lbl_start_playback">Start playback</string> | |
| @@ -323,50 +324,51 @@ | |
| <!-- Error Namespace | Error Labels --> | |
| <string name="err_index_failed">Music loading failed</string> | |
| <string name="err_import_failed">Unable to import a playlist from this file</string> | |
| <string name="err_export_failed">Unable to export the playlist to this file</string> | |
| <string name="err_no_app">No app found that can handle this task</string> | |
| <!-- No folders in the "Music Folders" setting --> | |
| <string name="err_bad_location">This folder is not supported</string> | |
| <!-- Description Namespace | Accessibility Strings --> | |
| <string name="desc_track_number">Track %d</string> | |
| <string name="desc_play_pause">Play or pause</string> | |
| <string name="desc_skip_next">Skip to next song</string> | |
| <string name="desc_skip_prev">Skip to last song</string> | |
| <string name="desc_change_repeat">Change repeat mode</string> | |
| <string name="desc_shuffle">Turn shuffle on or off</string> | |
| <string name="desc_exit">Stop playback</string> | |
| <string name="desc_remove_song">Remove this song</string> | |
| <string name="desc_song_handle">Move this song</string> | |
| <string name="desc_queue_bar">Open the queue</string> | |
| <string name="desc_tab_handle">Move this tab</string> | |
| <string name="desc_clear_search">Clear search query</string> | |
| + <string name="desc_clear_queue">Clear queue</string> | |
| <string name="desc_music_location_delete">Remove folder</string> | |
| <string name="desc_auxio_icon">Auxio icon</string> | |
| <string name="desc_no_cover">Album cover</string> | |
| <string name="desc_album_cover">Album cover for %s</string> | |
| <string name="desc_artist_image">Artist image for %s</string> | |
| <string name="desc_genre_image">Genre image for %s</string> | |
| <string name="desc_playlist_image">Playlist image for %s</string> | |
| <string name="desc_selection_image">Selection image</string> | |
| <!-- Default Namespace | Placeholder values --> | |
| <eat-comment /> | |
| <string name="def_album">Unknown album</string> | |
| <string name="def_artist">Unknown artist</string> | |
| <string name="def_genre">Unknown genre</string> | |
| <string name="def_date">No date</string> | |
| <string name="def_disc">No disc</string> | |
| <string name="def_track">No track</string> | |
| <string name="def_song_count">No songs</string> | |
| <string name="def_album_count">No albums</string> | |
| <string name="def_playback">No music playing</string> | |
| <!-- Codec Namespace | Format names --> | |
| <eat-comment /> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment