Merge branch 'dev' into feature/share

This commit is contained in:
Alexander Capehart 2023-05-24 15:49:53 +00:00 committed by GitHub
commit a5e01be34b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
106 changed files with 392 additions and 183 deletions

View file

@ -1,9 +1,9 @@
# Changelog
## dev
## 3.1.0
#### What's New
- **Playlists.** The long-awaited feature has arrived, with more functionality coming soon.
- Added playlist functionality
#### What's Improved
- Sorting now handles numbers of arbitrary length

View file

@ -2,8 +2,8 @@
<h1 align="center"><b>Auxio</b></h1>
<h4 align="center">A simple, rational music player for android.</h4>
<p align="center">
<a href="https://github.com/oxygencobalt/Auxio/releases/tag/v3.0.5">
<img alt="Latest Version" src="https://img.shields.io/static/v1?label=tag&message=v3.0.5&color=64B5F6&style=flat">
<a href="https://github.com/oxygencobalt/Auxio/releases/tag/v3.1.0">
<img alt="Latest Version" src="https://img.shields.io/static/v1?label=tag&message=v3.1.0&color=64B5F6&style=flat">
</a>
<a href="https://github.com/oxygencobalt/Auxio/releases/">
<img alt="Releases" src="https://img.shields.io/github/downloads/OxygenCobalt/Auxio/total.svg?color=4B95DE&style=flat">
@ -21,7 +21,7 @@
## About
Auxio is a local music player with a fast, reliable UI/UX without the many useless features present in other music players. Built off of <a href="https://exoplayer.dev/">Exoplayer</a>, Auxio has superior library support and listening quality compared to other apps that use outdated android functionality. In short, **It plays music.**
Auxio is a local music player with a fast, reliable UI/UX without the many useless features present in other music players. Built off of [ExoPlayer](https://exoplayer.dev/), Auxio has superior library support and listening quality compared to other apps that use outdated android functionality. In short, **It plays music.**
I primarily built Auxio for myself, but you can use it too, I guess.
@ -42,7 +42,7 @@ I primarily built Auxio for myself, but you can use it too, I guess.
## Features
- [ExoPlayer](https://exoplayer.dev/) based playback
- [ExoPlayer](https://exoplayer.dev/)-based playback
- Snappy UI derived from the latest Material Design guidelines
- Opinionated UX that prioritizes ease of use over edge cases
- Customizable behavior
@ -50,7 +50,8 @@ I primarily built Auxio for myself, but you can use it too, I guess.
precise/original dates, sort tags, and more
- Advanced artist system that unifies artists and album artists
- SD Card-aware folder management
- Reliable playback state persistence
- Reliable playlisting functionality
- Playback state persistence
- Full ReplayGain support (On MP3, FLAC, OGG, OPUS, and MP4 files)
- External equalizer support (ex. Wavelet)
- Edge-to-edge

View file

@ -20,8 +20,8 @@ android {
defaultConfig {
applicationId namespace
versionName "3.0.5"
versionCode 29
versionName "3.1.0"
versionCode 30
minSdk 21
targetSdk 33

View file

@ -16,8 +16,6 @@
package com.google.android.material.bottomsheet;
import com.google.android.material.R;
import static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;
import static java.lang.Math.max;
import static java.lang.Math.min;
@ -44,6 +42,7 @@ import android.view.ViewGroup;
import android.view.ViewGroup.MarginLayoutParams;
import android.view.ViewParent;
import android.view.accessibility.AccessibilityEvent;
import androidx.annotation.FloatRange;
import androidx.annotation.IntDef;
import androidx.annotation.NonNull;
@ -63,11 +62,14 @@ import androidx.core.view.accessibility.AccessibilityNodeInfoCompat.Accessibilit
import androidx.core.view.accessibility.AccessibilityViewCommand;
import androidx.customview.view.AbsSavedState;
import androidx.customview.widget.ViewDragHelper;
import com.google.android.material.R;
import com.google.android.material.internal.ViewUtils;
import com.google.android.material.internal.ViewUtils.RelativePadding;
import com.google.android.material.resources.MaterialResources;
import com.google.android.material.shape.MaterialShapeDrawable;
import com.google.android.material.shape.ShapeAppearanceModel;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;

View file

@ -16,20 +16,16 @@
package com.google.android.material.divider;
import com.google.android.material.R;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.ShapeDrawable;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ItemDecoration;
import android.util.AttributeSet;
import android.view.View;
import android.widget.LinearLayout;
import androidx.annotation.ColorInt;
import androidx.annotation.ColorRes;
import androidx.annotation.DimenRes;
@ -39,6 +35,11 @@ import androidx.annotation.Px;
import androidx.core.content.ContextCompat;
import androidx.core.graphics.drawable.DrawableCompat;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.ItemDecoration;
import com.google.android.material.R;
import com.google.android.material.internal.ThemeEnforcement;
import com.google.android.material.resources.MaterialResources;

View file

@ -51,10 +51,8 @@ object IntegerTable {
const val VIEW_TYPE_DISC_HEADER = 0xA00B
/** EditHeaderViewHolder */
const val VIEW_TYPE_EDIT_HEADER = 0xA00C
/** ConfirmHeaderViewHolder */
const val VIEW_TYPE_CONFIRM_HEADER = 0xA00D
/** EditableSongViewHolder */
const val VIEW_TYPE_EDITABLE_SONG = 0xA00E
/** PlaylistSongViewHolder */
const val VIEW_TYPE_PLAYLIST_SONG = 0xA00E
/** "Music playback" notification code */
const val PLAYBACK_NOTIFICATION_CODE = 0xA0A0
/** "Music loading" notification code */

View file

@ -31,6 +31,7 @@ import androidx.navigation.NavController
import androidx.navigation.NavDestination
import androidx.navigation.findNavController
import androidx.navigation.fragment.findNavController
import com.google.android.material.R as MR
import com.google.android.material.bottomsheet.BackportBottomSheetBehavior
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.transition.MaterialFadeThrough
@ -50,7 +51,15 @@ import org.oxycblt.auxio.playback.PlaybackBottomSheetBehavior
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.queue.QueueBottomSheetBehavior
import org.oxycblt.auxio.ui.ViewBindingFragment
import org.oxycblt.auxio.util.*
import org.oxycblt.auxio.util.collect
import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.context
import org.oxycblt.auxio.util.coordinatorLayoutBehavior
import org.oxycblt.auxio.util.getAttrColorCompat
import org.oxycblt.auxio.util.getDimen
import org.oxycblt.auxio.util.navigateSafe
import org.oxycblt.auxio.util.systemBarInsetsCompat
import org.oxycblt.auxio.util.unlikelyToBeNull
/**
* A wrapper around the home fragment that shows the playback fragment and controls the more
@ -122,7 +131,7 @@ class MainFragment :
// Emulate the elevated bottom sheet style.
background =
MaterialShapeDrawable.createWithElevationOverlay(context).apply {
fillColor = context.getAttrColorCompat(R.attr.colorSurface)
fillColor = context.getAttrColorCompat(MR.attr.colorSurface)
elevation = context.getDimen(R.dimen.elevation_normal)
}
// Apply bar insets for the queue's RecyclerView to usee.

View file

@ -51,7 +51,14 @@ import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.info.Disc
import org.oxycblt.auxio.navigation.NavigationViewModel
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.util.*
import org.oxycblt.auxio.util.canScroll
import org.oxycblt.auxio.util.collect
import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.navigateSafe
import org.oxycblt.auxio.util.setFullWidthLookup
import org.oxycblt.auxio.util.showToast
import org.oxycblt.auxio.util.unlikelyToBeNull
/**
* A [ListFragment] that shows information about an [Album].

View file

@ -49,7 +49,13 @@ import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.navigation.NavigationViewModel
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.util.*
import org.oxycblt.auxio.util.collect
import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.navigateSafe
import org.oxycblt.auxio.util.setFullWidthLookup
import org.oxycblt.auxio.util.showToast
import org.oxycblt.auxio.util.unlikelyToBeNull
/**
* A [ListFragment] that shows information about an [Artist].

View file

@ -37,12 +37,22 @@ import org.oxycblt.auxio.list.Divider
import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.adapter.UpdateInstructions
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.info.Disc
import org.oxycblt.auxio.music.info.ReleaseType
import org.oxycblt.auxio.music.metadata.AudioProperties
import org.oxycblt.auxio.playback.PlaybackSettings
import org.oxycblt.auxio.util.*
import org.oxycblt.auxio.util.Event
import org.oxycblt.auxio.util.MutableEvent
import org.oxycblt.auxio.util.logD
/**
* [ViewModel] that manages the Song, Album, Artist, and Genre detail views. Keeps track of the
@ -59,10 +69,10 @@ constructor(
private val musicSettings: MusicSettings,
private val playbackSettings: PlaybackSettings
) : ViewModel(), MusicRepository.UpdateListener {
private var currentSongJob: Job? = null
// --- SONG ---
private var currentSongJob: Job? = null
private val _currentSong = MutableStateFlow<Song?>(null)
/** The current [Song] to display. Null if there is nothing to show. */
val currentSong: StateFlow<Song?>
@ -279,7 +289,7 @@ constructor(
*
* @param uid The [Music.UID] of the [Playlist] to update [currentPlaylist] to. Must be valid.
*/
fun setPlaylistUid(uid: Music.UID) {
fun setPlaylist(uid: Music.UID) {
logD("Opening Playlist [uid: $uid]")
_currentPlaylist.value =
musicRepository.userLibrary?.findPlaylist(uid)?.also(::refreshPlaylistList)

View file

@ -41,10 +41,22 @@ import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.ListFragment
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.navigation.NavigationViewModel
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.util.*
import org.oxycblt.auxio.util.collect
import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.navigateSafe
import org.oxycblt.auxio.util.setFullWidthLookup
import org.oxycblt.auxio.util.showToast
import org.oxycblt.auxio.util.unlikelyToBeNull
/**
* A [ListFragment] that shows information for a particular [Genre].

View file

@ -44,10 +44,22 @@ import org.oxycblt.auxio.list.Header
import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.ListFragment
import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.navigation.NavigationViewModel
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.util.*
import org.oxycblt.auxio.util.collect
import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.navigateSafe
import org.oxycblt.auxio.util.setFullWidthLookup
import org.oxycblt.auxio.util.showToast
import org.oxycblt.auxio.util.unlikelyToBeNull
/**
* A [ListFragment] that shows information for a particular [Playlist].
@ -122,7 +134,7 @@ class PlaylistDetailFragment :
// --- VIEWMODEL SETUP ---
// DetailViewModel handles most initialization from the navigation argument.
detailModel.setPlaylistUid(args.playlistUid)
detailModel.setPlaylist(args.playlistUid)
collectImmediately(detailModel.currentPlaylist, ::updatePlaylist)
collectImmediately(detailModel.playlistList, ::updateList)
collectImmediately(detailModel.editedPlaylist, ::updateEditedPlaylist)

View file

@ -22,8 +22,8 @@ import android.content.Context
import android.os.Build
import android.util.AttributeSet
import android.view.View
import androidx.appcompat.R
import com.google.android.material.textfield.TextInputEditText
import org.oxycblt.auxio.R
/**
* A [TextInputEditText] that deliberately restricts all input except for selection. This will work

View file

@ -29,7 +29,10 @@ import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.SelectableListListener
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.adapter.SimpleDiffCallback
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.util.context
import org.oxycblt.auxio.util.inflater

View file

@ -26,13 +26,16 @@ import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.databinding.ItemSortHeaderBinding
import org.oxycblt.auxio.detail.list.DetailListAdapter.Listener
import org.oxycblt.auxio.list.BasicHeader
import org.oxycblt.auxio.list.Divider
import org.oxycblt.auxio.list.Header
import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.SelectableListListener
import org.oxycblt.auxio.list.adapter.*
import org.oxycblt.auxio.list.recycler.*
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.adapter.SimpleDiffCallback
import org.oxycblt.auxio.list.recycler.BasicHeaderViewHolder
import org.oxycblt.auxio.list.recycler.DividerViewHolder
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.util.context
import org.oxycblt.auxio.util.inflater

View file

@ -27,6 +27,7 @@ import androidx.appcompat.widget.TooltipCompat
import androidx.core.view.isInvisible
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.R as MR
import com.google.android.material.shape.MaterialShapeDrawable
import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R
@ -139,8 +140,7 @@ class PlaylistDetailListAdapter(private val listener: Listener) :
}
/**
* A [RecyclerView.ViewHolder] that displays a [SortHeader] and it's actions. Use [from] to create
* an instance.
* A [Header] variant that displays an edit button.
*
* @param titleRes The string resource to use as the header title
* @author Alexander Capehart (OxygenCobalt)
@ -214,7 +214,7 @@ private constructor(private val binding: ItemEditableSongBinding) :
override val delete = binding.background
override val background =
MaterialShapeDrawable.createWithElevationOverlay(binding.root.context).apply {
fillColor = binding.context.getAttrColorCompat(R.attr.colorSurface)
fillColor = binding.context.getAttrColorCompat(MR.attr.colorSurface)
elevation = binding.context.getDimen(R.dimen.elevation_normal)
alpha = 0
}
@ -224,7 +224,7 @@ private constructor(private val binding: ItemEditableSongBinding) :
LayerDrawable(
arrayOf(
MaterialShapeDrawable.createWithElevationOverlay(binding.context).apply {
fillColor = binding.context.getAttrColorCompat(R.attr.colorSurface)
fillColor = binding.context.getAttrColorCompat(MR.attr.colorSurface)
},
background))
}
@ -265,7 +265,7 @@ private constructor(private val binding: ItemEditableSongBinding) :
companion object {
/** A unique ID for this [RecyclerView.ViewHolder] type. */
const val VIEW_TYPE = IntegerTable.VIEW_TYPE_EDITABLE_SONG
const val VIEW_TYPE = IntegerTable.VIEW_TYPE_PLAYLIST_SONG
/**
* Create a new instance.

View file

@ -24,7 +24,8 @@ import androidx.annotation.StringRes
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.databinding.ItemSongPropertyBinding
import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.adapter.*
import org.oxycblt.auxio.list.adapter.FlexibleListAdapter
import org.oxycblt.auxio.list.adapter.SimpleDiffCallback
import org.oxycblt.auxio.list.recycler.DialogRecyclerView
import org.oxycblt.auxio.util.context
import org.oxycblt.auxio.util.inflater

View file

@ -22,8 +22,8 @@ import android.content.Context
import android.util.AttributeSet
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import com.google.android.material.R
import com.google.android.material.floatingactionbutton.FloatingActionButton
import org.oxycblt.auxio.R
import org.oxycblt.auxio.util.logD
/**

View file

@ -46,16 +46,38 @@ import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.MainFragmentDirections
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentHomeBinding
import org.oxycblt.auxio.home.list.*
import org.oxycblt.auxio.home.list.AlbumListFragment
import org.oxycblt.auxio.home.list.ArtistListFragment
import org.oxycblt.auxio.home.list.GenreListFragment
import org.oxycblt.auxio.home.list.PlaylistListFragment
import org.oxycblt.auxio.home.list.SongListFragment
import org.oxycblt.auxio.home.tabs.AdaptiveTabStrategy
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.selection.SelectionFragment
import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.IndexingProgress
import org.oxycblt.auxio.music.IndexingState
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.NoAudioPermissionException
import org.oxycblt.auxio.music.NoMusicException
import org.oxycblt.auxio.music.PERMISSION_READ_AUDIO
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.navigation.MainNavigationAction
import org.oxycblt.auxio.navigation.NavigationViewModel
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.util.*
import org.oxycblt.auxio.util.collect
import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.getColorCompat
import org.oxycblt.auxio.util.lazyReflectedField
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.navigateSafe
import org.oxycblt.auxio.util.unlikelyToBeNull
/**
* The starting [SelectionFragment] of Auxio. Shows the user's music library and enables navigation

View file

@ -26,7 +26,14 @@ import kotlinx.coroutines.flow.StateFlow
import org.oxycblt.auxio.home.tabs.Tab
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.adapter.UpdateInstructions
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.PlaybackSettings
import org.oxycblt.auxio.util.Event
import org.oxycblt.auxio.util.MutableEvent

View file

@ -33,6 +33,7 @@ import android.text.TextUtils
import android.util.AttributeSet
import android.view.Gravity
import androidx.core.widget.TextViewCompat
import com.google.android.material.R as MR
import com.google.android.material.textview.MaterialTextView
import org.oxycblt.auxio.R
import org.oxycblt.auxio.util.getAttrColorCompat
@ -53,7 +54,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleRes: Int = 0)
minimumHeight = context.getDimenPixels(R.dimen.fast_scroll_popup_min_height)
TextViewCompat.setTextAppearance(this, R.style.TextAppearance_Auxio_HeadlineLarge)
setTextColor(context.getAttrColorCompat(R.attr.colorOnSecondary))
setTextColor(context.getAttrColorCompat(MR.attr.colorOnSecondary))
ellipsize = TextUtils.TruncateAt.MIDDLE
gravity = Gravity.CENTER
includeFontPadding = false
@ -67,7 +68,10 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleRes: Int = 0)
private val paint: Paint =
Paint().apply {
isAntiAlias = true
color = context.getAttrColorCompat(R.attr.colorSecondary).defaultColor
color =
context
.getAttrColorCompat(com.google.android.material.R.attr.colorSecondary)
.defaultColor
style = Paint.Style.FILL
}

View file

@ -37,7 +37,12 @@ import androidx.recyclerview.widget.RecyclerView
import kotlin.math.abs
import org.oxycblt.auxio.R
import org.oxycblt.auxio.list.recycler.AuxioRecyclerView
import org.oxycblt.auxio.util.*
import org.oxycblt.auxio.util.getDimenPixels
import org.oxycblt.auxio.util.getDrawableCompat
import org.oxycblt.auxio.util.getInteger
import org.oxycblt.auxio.util.isRtl
import org.oxycblt.auxio.util.isUnder
import org.oxycblt.auxio.util.systemBarInsetsCompat
/**
* A [RecyclerView] that enables better fast-scrolling. This is fundamentally a implementation of

View file

@ -30,13 +30,17 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentHomeListBinding
import org.oxycblt.auxio.home.HomeViewModel
import org.oxycblt.auxio.home.fastscroll.FastScrollRecyclerView
import org.oxycblt.auxio.list.*
import org.oxycblt.auxio.list.ListFragment
import org.oxycblt.auxio.list.SelectableListListener
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.recycler.AlbumViewHolder
import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.navigation.NavigationViewModel
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.playback.formatDurationMs

View file

@ -28,8 +28,8 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentHomeListBinding
import org.oxycblt.auxio.home.HomeViewModel
import org.oxycblt.auxio.home.fastscroll.FastScrollRecyclerView
import org.oxycblt.auxio.list.*
import org.oxycblt.auxio.list.ListFragment
import org.oxycblt.auxio.list.SelectableListListener
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.recycler.ArtistViewHolder

View file

@ -28,8 +28,8 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentHomeListBinding
import org.oxycblt.auxio.home.HomeViewModel
import org.oxycblt.auxio.home.fastscroll.FastScrollRecyclerView
import org.oxycblt.auxio.list.*
import org.oxycblt.auxio.list.ListFragment
import org.oxycblt.auxio.list.SelectableListListener
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.recycler.GenreViewHolder

View file

@ -27,8 +27,8 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentHomeListBinding
import org.oxycblt.auxio.home.HomeViewModel
import org.oxycblt.auxio.home.fastscroll.FastScrollRecyclerView
import org.oxycblt.auxio.list.*
import org.oxycblt.auxio.list.ListFragment
import org.oxycblt.auxio.list.SelectableListListener
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.recycler.PlaylistViewHolder

View file

@ -30,8 +30,8 @@ import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentHomeListBinding
import org.oxycblt.auxio.home.HomeViewModel
import org.oxycblt.auxio.home.fastscroll.FastScrollRecyclerView
import org.oxycblt.auxio.list.*
import org.oxycblt.auxio.list.ListFragment
import org.oxycblt.auxio.list.SelectableListListener
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.recycler.SongViewHolder

View file

@ -28,9 +28,14 @@ import android.widget.FrameLayout
import android.widget.ImageView
import androidx.annotation.AttrRes
import androidx.core.view.updateMarginsRelative
import com.google.android.material.R as MR
import com.google.android.material.shape.MaterialShapeDrawable
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.util.getAttrColorCompat
import org.oxycblt.auxio.util.getColorCompat
import org.oxycblt.auxio.util.getDimenPixels
@ -80,7 +85,7 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr
PlaybackIndicatorView(context).apply { cornerRadius = this@ImageGroup.cornerRadius }
selectionIndicatorView =
ImageView(context).apply {
imageTintList = context.getAttrColorCompat(R.attr.colorOnPrimary)
imageTintList = context.getAttrColorCompat(MR.attr.colorOnPrimary)
setImageResource(R.drawable.ic_check_20)
setBackgroundResource(R.drawable.ui_selection_badge_bg)
}

View file

@ -22,7 +22,6 @@ import dagger.Binds
import dagger.Module
import dagger.hilt.InstallIn
import dagger.hilt.components.SingletonComponent
import org.oxycblt.auxio.image.extractor.*
@Module
@InstallIn(SingletonComponent::class)

View file

@ -38,7 +38,12 @@ import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
import org.oxycblt.auxio.R
import org.oxycblt.auxio.image.extractor.SquareFrameTransform
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.ui.UISettings
import org.oxycblt.auxio.util.getColorCompat
import org.oxycblt.auxio.util.getDrawableCompat

View file

@ -24,7 +24,7 @@ import coil.key.Keyer
import coil.request.Options
import coil.size.Size
import javax.inject.Inject
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Song
class SongKeyer @Inject constructor(private val coverExtractor: CoverExtractor) :
Keyer<List<Song>> {

View file

@ -50,7 +50,6 @@ import okio.buffer
import okio.source
import org.oxycblt.auxio.image.CoverMode
import org.oxycblt.auxio.image.ImageSettings
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.util.logD
@ -81,8 +80,8 @@ constructor(
}
}
fun computeAlbumOrdering(songs: List<Song>): Collection<Album> =
Sort(Sort.Mode.ByCount, Sort.Direction.DESCENDING).albums(songs.groupBy { it.album }.keys)
fun computeAlbumOrdering(songs: List<Song>) =
songs.groupBy { it.album }.entries.sortedByDescending { it.value.size }.map { it.key }
private suspend fun openInputStream(album: Album): InputStream? =
try {

View file

@ -28,7 +28,12 @@ import androidx.viewbinding.ViewBinding
import org.oxycblt.auxio.MainFragmentDirections
import org.oxycblt.auxio.R
import org.oxycblt.auxio.list.selection.SelectionFragment
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.navigation.MainNavigationAction
import org.oxycblt.auxio.navigation.NavigationViewModel
import org.oxycblt.auxio.util.logD

View file

@ -22,8 +22,15 @@ import androidx.annotation.IdRes
import kotlin.math.max
import org.oxycblt.auxio.IntegerTable
import org.oxycblt.auxio.R
import org.oxycblt.auxio.list.Sort.Direction
import org.oxycblt.auxio.list.Sort.Mode
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.info.Date
import org.oxycblt.auxio.music.info.Disc

View file

@ -20,7 +20,8 @@ package org.oxycblt.auxio.list.adapter
import android.os.Handler
import android.os.Looper
import androidx.recyclerview.widget.*
import androidx.recyclerview.widget.AdapterListUpdateCallback
import androidx.recyclerview.widget.AsyncDifferConfig
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import java.util.concurrent.Executor

View file

@ -29,6 +29,7 @@ import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.divider.MaterialDivider
import org.oxycblt.auxio.R
import org.oxycblt.auxio.list.recycler.DialogRecyclerView.ViewHolder
import org.oxycblt.auxio.util.getDimenPixels
/**

View file

@ -26,6 +26,7 @@ import androidx.core.view.isInvisible
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.R
import org.oxycblt.auxio.list.recycler.MaterialDragCallback.ViewHolder
import org.oxycblt.auxio.util.getDimen
import org.oxycblt.auxio.util.getInteger
import org.oxycblt.auxio.util.logD

View file

@ -31,7 +31,13 @@ import org.oxycblt.auxio.list.Divider
import org.oxycblt.auxio.list.SelectableListListener
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.adapter.SimpleDiffCallback
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.areNamesTheSame
import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.util.context
import org.oxycblt.auxio.util.getPlural
import org.oxycblt.auxio.util.inflater

View file

@ -23,7 +23,14 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
/**
* A [ViewModel] that manages the current selection.

View file

@ -21,12 +21,22 @@ package org.oxycblt.auxio.music
import android.content.Context
import android.content.pm.PackageManager
import androidx.core.content.ContextCompat
import java.util.*
import java.util.LinkedList
import javax.inject.Inject
import kotlin.coroutines.CoroutineContext
import kotlin.coroutines.EmptyCoroutineContext
import kotlinx.coroutines.*
import kotlinx.coroutines.CancellationException
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.async
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import kotlinx.coroutines.yield
import org.oxycblt.auxio.music.MusicRepository.IndexingListener
import org.oxycblt.auxio.music.MusicRepository.IndexingWorker
import org.oxycblt.auxio.music.MusicRepository.UpdateListener
import org.oxycblt.auxio.music.cache.CacheRepository
import org.oxycblt.auxio.music.device.DeviceLibrary
import org.oxycblt.auxio.music.device.RawSong

View file

@ -20,7 +20,7 @@ package org.oxycblt.auxio.music.cache
import javax.inject.Inject
import org.oxycblt.auxio.music.device.RawSong
import org.oxycblt.auxio.util.*
import org.oxycblt.auxio.util.logE
/**
* A repository allowing access to cached metadata obtained in prior music loading operations.

View file

@ -23,7 +23,13 @@ import android.net.Uri
import android.provider.OpenableColumns
import javax.inject.Inject
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.fs.contentResolverSafe
import org.oxycblt.auxio.music.fs.useQuery
import org.oxycblt.auxio.util.logD

View file

@ -20,13 +20,21 @@ package org.oxycblt.auxio.music.device
import org.oxycblt.auxio.R
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.fs.MimeType
import org.oxycblt.auxio.music.fs.Path
import org.oxycblt.auxio.music.fs.toAudioUri
import org.oxycblt.auxio.music.fs.toCoverUri
import org.oxycblt.auxio.music.info.*
import org.oxycblt.auxio.music.info.Date
import org.oxycblt.auxio.music.info.Disc
import org.oxycblt.auxio.music.info.Name
import org.oxycblt.auxio.music.info.ReleaseType
import org.oxycblt.auxio.music.metadata.parseId3GenreNames
import org.oxycblt.auxio.music.metadata.parseMultiValue
import org.oxycblt.auxio.util.nonZeroOrNull

View file

@ -19,11 +19,12 @@
package org.oxycblt.auxio.music.device
import java.util.UUID
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.fs.Directory
import org.oxycblt.auxio.music.info.Date
import org.oxycblt.auxio.music.info.ReleaseType
import org.oxycblt.auxio.music.metadata.*
/**
* Raw information about a [SongImpl] obtained from the filesystem/Extractor instances.

View file

@ -19,6 +19,7 @@
package org.oxycblt.auxio.music.info
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.info.ReleaseType.Album
/**
* The type of release an [Album] is considered. This includes EPs, Singles, Compilations, etc.

View file

@ -52,7 +52,7 @@ class RenamePlaylistDialog : ViewBindingDialogFragment<DialogPlaylistNameBinding
override fun onConfigDialog(builder: AlertDialog.Builder) {
builder
.setTitle(R.string.lbl_rename)
.setTitle(R.string.lbl_rename_playlist)
.setPositiveButton(R.string.lbl_ok) { _, _ ->
val playlist = unlikelyToBeNull(pickerModel.currentPlaylistToRename.value)
val chosenName = pickerModel.chosenName.value as ChosenName.Valid

View file

@ -28,12 +28,17 @@ import android.os.PowerManager
import android.provider.MediaStore
import coil.ImageLoader
import dagger.hilt.android.AndroidEntryPoint
import java.lang.Runnable
import java.util.*
import javax.inject.Inject
import kotlinx.coroutines.*
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.launch
import org.oxycblt.auxio.BuildConfig
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.IndexingProgress
import org.oxycblt.auxio.music.IndexingState
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.fs.contentResolverSafe
import org.oxycblt.auxio.playback.state.PlaybackStateManager
import org.oxycblt.auxio.service.ForegroundManager

View file

@ -18,7 +18,11 @@
package org.oxycblt.auxio.music.user
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.device.DeviceLibrary
import org.oxycblt.auxio.music.info.Name

View file

@ -18,7 +18,12 @@
package org.oxycblt.auxio.music.user
import androidx.room.*
import androidx.room.ColumnInfo
import androidx.room.Embedded
import androidx.room.Entity
import androidx.room.Junction
import androidx.room.PrimaryKey
import androidx.room.Relation
import org.oxycblt.auxio.music.Music
/**
@ -57,6 +62,6 @@ data class RawPlaylist(
@Entity
data class PlaylistSongCrossRef(
@PrimaryKey(autoGenerate = true) val id: Long = 0,
val playlistUid: Music.UID,
val songUid: Music.UID
@ColumnInfo(index = true) val playlistUid: Music.UID,
@ColumnInfo(index = true) val songUid: Music.UID
)

View file

@ -20,7 +20,11 @@ package org.oxycblt.auxio.music.user
import javax.inject.Inject
import kotlinx.coroutines.channels.Channel
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.device.DeviceLibrary
/**

View file

@ -18,7 +18,14 @@
package org.oxycblt.auxio.music.user
import androidx.room.*
import androidx.room.Dao
import androidx.room.Database
import androidx.room.Insert
import androidx.room.OnConflictStrategy
import androidx.room.Query
import androidx.room.RoomDatabase
import androidx.room.Transaction
import androidx.room.TypeConverters
import org.oxycblt.auxio.music.Music
/**
@ -106,7 +113,7 @@ interface PlaylistDao {
}
/**
* Replace the currently-stored [Song]s of the current playlist entry.
* Replace the currently stored songs of the given playlist entry.
*
* @param playlistUid The [Music.UID] of the playlist to update.
* @param songs The [PlaylistSong] representing the new list of songs to be placed in the

View file

@ -23,7 +23,11 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.Song
/**
* A [ViewModel] that stores the current information required for navigation picker dialogs

View file

@ -21,6 +21,7 @@ package org.oxycblt.auxio.playback
import android.os.Bundle
import android.view.LayoutInflater
import androidx.fragment.app.activityViewModels
import com.google.android.material.R as MR
import dagger.hilt.android.AndroidEntryPoint
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.FragmentPlaybackBarBinding
@ -95,7 +96,7 @@ class PlaybackBarFragment : ViewBindingFragment<FragmentPlaybackBarBinding>() {
binding.playbackSecondaryAction.apply {
setIconResource(R.drawable.ic_skip_next_24)
contentDescription = getString(R.string.desc_skip_next)
iconTint = context.getAttrColorCompat(R.attr.colorOnSurfaceVariant)
iconTint = context.getAttrColorCompat(MR.attr.colorOnSurfaceVariant)
setOnClickListener { playbackModel.next() }
}
}

View file

@ -24,6 +24,7 @@ import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.google.android.material.R as MR
import com.google.android.material.shape.MaterialShapeDrawable
import org.oxycblt.auxio.R
import org.oxycblt.auxio.ui.BaseBottomSheetBehavior
@ -39,7 +40,7 @@ class PlaybackBottomSheetBehavior<V : View>(context: Context, attributeSet: Attr
BaseBottomSheetBehavior<V>(context, attributeSet) {
val sheetBackgroundDrawable =
MaterialShapeDrawable.createWithElevationOverlay(context).apply {
fillColor = context.getAttrColorCompat(R.attr.colorSurface)
fillColor = context.getAttrColorCompat(MR.attr.colorSurface)
elevation = context.getDimen(R.dimen.elevation_normal)
}

View file

@ -27,10 +27,20 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.MusicSettings
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.persist.PersistenceRepository
import org.oxycblt.auxio.playback.queue.Queue
import org.oxycblt.auxio.playback.state.*
import org.oxycblt.auxio.playback.state.InternalPlayer
import org.oxycblt.auxio.playback.state.PlaybackStateManager
import org.oxycblt.auxio.playback.state.RepeatMode
import org.oxycblt.auxio.util.Event
import org.oxycblt.auxio.util.MutableEvent

View file

@ -126,6 +126,7 @@ interface QueueDao {
suspend fun insertMapping(mapping: List<QueueMappingItem>)
}
// TODO: Figure out how to get RepeatMode to map to an int instead of a string
@Entity(tableName = PlaybackState.TABLE_NAME)
data class PlaybackState(
@PrimaryKey val id: Int,

View file

@ -23,7 +23,10 @@ import dagger.hilt.android.lifecycle.HiltViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.Song
/**
* A [ViewModel] that stores the choices shown in the playback picker dialogs.

View file

@ -23,6 +23,8 @@ import kotlin.random.nextInt
import org.oxycblt.auxio.list.adapter.UpdateInstructions
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.queue.Queue.Change.Type
import org.oxycblt.auxio.playback.queue.Queue.SavedState
/**
* A heap-backed play queue.

View file

@ -24,16 +24,22 @@ import android.view.View
import android.view.ViewGroup
import androidx.core.view.isInvisible
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.R as MR
import com.google.android.material.shape.MaterialShapeDrawable
import org.oxycblt.auxio.R
import org.oxycblt.auxio.databinding.ItemEditableSongBinding
import org.oxycblt.auxio.list.EditClickListListener
import org.oxycblt.auxio.list.adapter.*
import org.oxycblt.auxio.list.adapter.FlexibleListAdapter
import org.oxycblt.auxio.list.adapter.PlayingIndicatorAdapter
import org.oxycblt.auxio.list.recycler.MaterialDragCallback
import org.oxycblt.auxio.list.recycler.SongViewHolder
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.util.*
import org.oxycblt.auxio.util.context
import org.oxycblt.auxio.util.getAttrColorCompat
import org.oxycblt.auxio.util.getDimen
import org.oxycblt.auxio.util.inflater
import org.oxycblt.auxio.util.logD
/**
* A [RecyclerView.Adapter] that shows an editable list of queue items.
@ -110,7 +116,7 @@ class QueueSongViewHolder private constructor(private val binding: ItemEditableS
override val delete = binding.background
override val background =
MaterialShapeDrawable.createWithElevationOverlay(binding.root.context).apply {
fillColor = binding.context.getAttrColorCompat(R.attr.colorSurface)
fillColor = binding.context.getAttrColorCompat(MR.attr.colorSurface)
elevation = binding.context.getDimen(R.dimen.elevation_normal) * 5
alpha = 0
}
@ -128,7 +134,7 @@ class QueueSongViewHolder private constructor(private val binding: ItemEditableS
LayerDrawable(
arrayOf(
MaterialShapeDrawable.createWithElevationOverlay(binding.context).apply {
fillColor = binding.context.getAttrColorCompat(R.attr.colorSurface)
fillColor = binding.context.getAttrColorCompat(MR.attr.colorSurface)
elevation = binding.context.getDimen(R.dimen.elevation_normal)
},
background))

View file

@ -23,6 +23,7 @@ import android.util.AttributeSet
import android.view.View
import android.view.WindowInsets
import androidx.coordinatorlayout.widget.CoordinatorLayout
import com.google.android.material.R as MR
import com.google.android.material.shape.MaterialShapeDrawable
import org.oxycblt.auxio.R
import org.oxycblt.auxio.ui.BaseBottomSheetBehavior
@ -64,7 +65,7 @@ class QueueBottomSheetBehavior<V : View>(context: Context, attributeSet: Attribu
override fun createBackground(context: Context) =
MaterialShapeDrawable.createWithElevationOverlay(context).apply {
// The queue sheet's background is a static elevated background.
fillColor = context.getAttrColorCompat(R.attr.colorSurface)
fillColor = context.getAttrColorCompat(MR.attr.colorSurface)
elevation = context.getDimen(R.dimen.elevation_normal)
}

View file

@ -24,6 +24,7 @@ import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.playback.queue.EditableQueue
import org.oxycblt.auxio.playback.queue.Queue
import org.oxycblt.auxio.playback.state.PlaybackStateManager.Listener
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logW

View file

@ -26,7 +26,11 @@ import android.content.IntentFilter
import android.media.AudioManager
import android.media.audiofx.AudioEffect
import android.os.IBinder
import androidx.media3.common.*
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.decoder.ffmpeg.FfmpegAudioRenderer
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.exoplayer.RenderersFactory

View file

@ -20,11 +20,25 @@ package org.oxycblt.auxio.search
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.list.*
import org.oxycblt.auxio.list.BasicHeader
import org.oxycblt.auxio.list.Divider
import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.SelectableListListener
import org.oxycblt.auxio.list.adapter.SelectionIndicatorAdapter
import org.oxycblt.auxio.list.adapter.SimpleDiffCallback
import org.oxycblt.auxio.list.recycler.*
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.list.recycler.AlbumViewHolder
import org.oxycblt.auxio.list.recycler.ArtistViewHolder
import org.oxycblt.auxio.list.recycler.BasicHeaderViewHolder
import org.oxycblt.auxio.list.recycler.DividerViewHolder
import org.oxycblt.auxio.list.recycler.GenreViewHolder
import org.oxycblt.auxio.list.recycler.PlaylistViewHolder
import org.oxycblt.auxio.list.recycler.SongViewHolder
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.util.logD
/**

View file

@ -39,10 +39,23 @@ import org.oxycblt.auxio.list.Header
import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.ListFragment
import org.oxycblt.auxio.list.selection.SelectionViewModel
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.MusicParent
import org.oxycblt.auxio.music.MusicViewModel
import org.oxycblt.auxio.music.Playlist
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.navigation.NavigationViewModel
import org.oxycblt.auxio.playback.PlaybackViewModel
import org.oxycblt.auxio.util.*
import org.oxycblt.auxio.util.collect
import org.oxycblt.auxio.util.collectImmediately
import org.oxycblt.auxio.util.context
import org.oxycblt.auxio.util.getSystemServiceCompat
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.navigateSafe
import org.oxycblt.auxio.util.setFullWidthLookup
/**
* The [ListFragment] providing search functionality for the music library.

View file

@ -33,7 +33,9 @@ import org.oxycblt.auxio.list.BasicHeader
import org.oxycblt.auxio.list.Divider
import org.oxycblt.auxio.list.Item
import org.oxycblt.auxio.list.Sort
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.MusicMode
import org.oxycblt.auxio.music.MusicRepository
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.music.device.DeviceLibrary
import org.oxycblt.auxio.music.user.UserLibrary
import org.oxycblt.auxio.playback.PlaybackSettings

View file

@ -25,8 +25,8 @@ import androidx.preference.PreferenceCategory
import androidx.preference.PreferenceGroupAdapter
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.google.android.material.R
import com.google.android.material.divider.BackportMaterialDividerItemDecoration
import org.oxycblt.auxio.R
/**
* A [BackportMaterialDividerItemDecoration] that sets up the divider configuration to correctly

View file

@ -21,8 +21,8 @@ package org.oxycblt.auxio.ui
import android.content.Context
import android.util.AttributeSet
import androidx.annotation.AttrRes
import com.google.android.material.R
import com.google.android.material.button.MaterialButton
import org.oxycblt.auxio.R
import org.oxycblt.auxio.util.fixDoubleRipple
/**

View file

@ -18,11 +18,12 @@
package org.oxycblt.auxio.ui.accent
import android.R as SR
import android.view.View
import android.view.ViewGroup
import androidx.appcompat.widget.TooltipCompat
import androidx.recyclerview.widget.RecyclerView
import org.oxycblt.auxio.R
import com.google.android.material.R as MR
import org.oxycblt.auxio.databinding.ItemAccentBinding
import org.oxycblt.auxio.list.ClickableListListener
import org.oxycblt.auxio.util.getAttrColorCompat
@ -118,9 +119,9 @@ class AccentViewHolder private constructor(private val binding: ItemAccentBindin
binding.accent.apply {
iconTint =
if (isSelected) {
context.getAttrColorCompat(R.attr.colorSurface)
context.getAttrColorCompat(MR.attr.colorSurface)
} else {
context.getColorCompat(android.R.color.transparent)
context.getColorCompat(SR.color.transparent)
}
}
}

View file

@ -34,7 +34,9 @@ import org.oxycblt.auxio.music.resolveNames
import org.oxycblt.auxio.playback.state.RepeatMode
import org.oxycblt.auxio.playback.system.PlaybackService
import org.oxycblt.auxio.ui.UISettings
import org.oxycblt.auxio.util.*
import org.oxycblt.auxio.util.logD
import org.oxycblt.auxio.util.logW
import org.oxycblt.auxio.util.newBroadcastPendingIntent
/**
* The [AppWidgetProvider] for the "Now Playing" widget. This widget shows the current playback

View file

@ -3,9 +3,9 @@
xmlns:aapt="http://schemas.android.com/aapt">
<!--
Yes, this whole file is all 30 frames of Spotify's equalizer animation
merged with the material equalizer icon, with each vector inlined using
aapt:attr so that it does not clutter the drawable folder.
Yes, this whole file is the material equalizer icon influenced by Spotify's
equalizer animation with each vector inlined using aapt:attr so that it does
not clutter the drawable folder.
-->
<!-- Frame 1 -->

View file

@ -1,4 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<com.google.android.material.divider.MaterialDivider xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content" />

View file

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:checkableBehavior="single"
android:id="@+id/sort_modes">
<item
android:id="@+id/option_sort_none"
android:title="@string/lbl_none" />
<item
android:id="@+id/option_sort_name"
android:title="@string/lbl_name" />
<item
android:id="@+id/option_sort_artist"
android:title="@string/lbl_artist" />
<item
android:id="@+id/option_sort_album"
android:title="@string/lbl_album" />
<item
android:id="@+id/option_sort_year"
android:title="@string/lbl_date" />
<item
android:id="@+id/option_sort_duration"
android:title="@string/lbl_duration" />
</group>
<group android:checkableBehavior="single"
android:id="@+id/sort_direction">
<item
android:id="@+id/option_sort_asc"
android:title="@string/lbl_sort_asc" />
<item
android:id="@+id/option_sort_dec"
android:title="@string/lbl_sort_dec" />
</group>
</menu>

View file

@ -274,7 +274,6 @@
<string name="desc_playlist_image">Вокладка плэйліст для %s</string>
<string name="lbl_playlist">Плэйліст</string>
<string name="lbl_playlists">Плэйлісты</string>
<string name="lbl_none">Адкл.</string>
<string name="desc_new_playlist">Стварыце новы плэйліст</string>
<string name="fmt_def_playlist">Плэйліст %d</string>
<string name="lbl_new_playlist">Новы плэйліст</string>

View file

@ -285,7 +285,6 @@
<string name="lbl_playlist">Seznam skladeb</string>
<string name="set_intelligent_sorting">Při řazení ignorovat předložky</string>
<string name="set_intelligent_sorting_desc">Ignorovat slova jako „the“ při řazení podle názvu (funguje nejlépe u hudby v angličtině)</string>
<string name="lbl_none">Žádné</string>
<string name="desc_new_playlist">Vytvořit nový playlist</string>
<string name="lbl_playlist_add">Přidat do seznamu skladeb</string>
<string name="lng_playlist_added">Přidáno do seznamu skladeb</string>

View file

@ -276,7 +276,6 @@
<string name="lbl_playlists">Wiedergabelisten</string>
<string name="set_intelligent_sorting">Artikel beim Sortieren ignorieren</string>
<string name="set_intelligent_sorting_desc">Wörter wie „the“ ignorieren (funktioniert am besten mit englischsprachiger Musik)</string>
<string name="lbl_none">Keine</string>
<string name="desc_new_playlist">Neue Wiedergabeliste erstellen</string>
<string name="lbl_new_playlist">Neue Wiedergabeliste</string>
<string name="lng_playlist_added">Zur Wiedergabeliste hinzugefügt</string>

View file

@ -278,7 +278,6 @@
<string name="lbl_playlists">Listas de reproducción</string>
<string name="desc_playlist_image">Imagen de la lista de reproducción para %s</string>
<string name="lbl_playlist">Lista de reproducción</string>
<string name="lbl_none">Ninguno</string>
<string name="set_intelligent_sorting">Ignorar artículos al ordenar</string>
<string name="set_intelligent_sorting_desc">Ignorar palabras como \"the\" al ordenar por nombre (funciona mejor con música en inglés)</string>
<string name="desc_new_playlist">Crear una nueva lista de reproducción</string>

View file

@ -28,7 +28,6 @@
<string name="lbl_search">Etsi</string>
<string name="lbl_filter">Suodata</string>
<string name="lbl_filter_all">Kaikki</string>
<string name="lbl_none">Ei mitään</string>
<string name="lbl_name">Nimi</string>
<string name="lbl_song_count">Kappalemäärä</string>
<string name="lbl_disc">Levy</string>

View file

@ -206,7 +206,6 @@
<string name="set_playback">Lecture</string>
<string name="set_state">Persistance</string>
<string name="set_wipe_state">Vider l\'état de lecture</string>
<string name="lbl_none">Aucun</string>
<string name="set_headset_autoplay_desc">Toujours commencer la lecture lorsqu\'un périphérique audio est connecté (pourrait ne pas fonctionner sur tous les appareils)</string>
<string name="set_replay_gain_mode">Stratégie de normalisation de volume</string>
<string name="set_replay_gain_mode_track">Par chanson</string>

View file

@ -268,5 +268,4 @@
<string name="desc_playlist_image">Imaxe da lista de reprodución para %s</string>
<string name="set_separators_and">ampersand</string>
<string name="set_replay_gain">ganancia da repetición</string>
<string name="lbl_none">Ningún</string>
</resources>

View file

@ -269,7 +269,6 @@
<string name="set_music">Glazba</string>
<string name="desc_playlist_image">Slika popisa pjesama za %s</string>
<string name="set_behavior">Ponašanje</string>
<string name="lbl_none">Ništa</string>
<string name="set_intelligent_sorting">Pametno razvrstavanje</string>
<string name="set_intelligent_sorting_desc">Ispravno razvrstaj imena koja počinju brojevima ili riječima poput „the” (najbolje radi s glazbom na engleskom jeziku)</string>
<string name="desc_new_playlist">Stvori novi popis pjesama</string>

View file

@ -287,5 +287,4 @@
<string name="lng_playlist_added">Aggiunto alla playlist</string>
<string name="def_song_count">Niente canzoni</string>
<string name="fmt_def_playlist">Playlist %d</string>
<string name="lbl_none">Nessuno</string>
</resources>

View file

@ -265,7 +265,6 @@
<string name="lbl_playlist">プレイリスト</string>
<string name="lbl_playlists">プレイリスト</string>
<string name="desc_playlist_image">%s のプレイリスト イメージ</string>
<string name="lbl_none">無し</string>
<string name="lbl_new_playlist">新規プレイリスト</string>
<string name="lbl_playlist_add">プレイリストに追加する</string>
<string name="lng_playlist_created">プレイリストが作成されました</string>

View file

@ -276,7 +276,6 @@
<string name="desc_playlist_image">%s의 재생 목록 이미지</string>
<string name="set_intelligent_sorting">정렬할 때 기사 무시</string>
<string name="set_intelligent_sorting_desc">이름으로 정렬할 때 \"the\"와 같은 단어 무시(영어 음악에서 가장 잘 작동함)</string>
<string name="lbl_none">없음</string>
<string name="desc_new_playlist">새 재생 목록 만들기</string>
<string name="lbl_new_playlist">새 재생목록</string>
<string name="lbl_playlist_add">재생목록에 추가</string>

View file

@ -274,6 +274,5 @@
<string name="lbl_playlist">Grojaraštis</string>
<string name="lbl_playlists">Grojaraščiai</string>
<string name="desc_playlist_image">Grojaraščio vaizdas %s</string>
<string name="lbl_none">Jokios</string>
<string name="desc_new_playlist">Sukurti naują grojaraštį</string>
</resources>

View file

@ -90,7 +90,6 @@
<string name="lbl_go_artist">കലാകാരനിലേക്ക് പോകുക</string>
<string name="lbl_song_detail">സവിശേഷതകൾ കാണുക</string>
<string name="lbl_state_saved">സ്ഥിതി സംരക്ഷിച്ചു</string>
<string name="lbl_none">ഒന്നുമില്ല</string>
<string name="lbl_sort_dec">അവരോഹണം</string>
<string name="lbl_state_restored">സ്ഥിതി പുനഃസ്ഥാപിച്ചു</string>
<string name="lbl_wiki">വിക്കി</string>

View file

@ -281,7 +281,6 @@
<string name="desc_playlist_image">Obraz playlisty %s</string>
<string name="set_intelligent_sorting">Inteligentne sortowanie</string>
<string name="set_intelligent_sorting_desc">Ignoruj słowa takie jak „the” oraz numery w tytule podczas sortowania (działa najlepiej z utworami w języku angielskim)</string>
<string name="lbl_none">Brak</string>
<string name="desc_new_playlist">Utwórz nową playlistę</string>
<string name="lbl_new_playlist">Nowa playlista</string>
<string name="lbl_playlist_add">Dodaj do playlisty</string>

View file

@ -142,7 +142,6 @@
<string name="set_action_mode_next">Treceți la următoarea</string>
<string name="set_playback_mode_artist">Redă de la artist</string>
<string name="set_playback_mode_genre">Redă din genul</string>
<string name="lbl_none">Nu există</string>
<string name="lbl_reset">Resetează</string>
<string name="lbl_wiki">Wiki</string>
<string name="lng_widget">Vizualizați și controlați redarea muzicii</string>

View file

@ -283,7 +283,6 @@
<string name="desc_playlist_image">Обложка плейлиста для %s</string>
<string name="set_intelligent_sorting">Игнорировать артикли при сортировке</string>
<string name="set_intelligent_sorting_desc">Игнорировать такие слова, как «the», при сортировке по имени (лучше всего работает с англоязычной музыкой)</string>
<string name="lbl_none">Откл.</string>
<string name="desc_new_playlist">Создать новый плейлист</string>
<string name="lbl_new_playlist">Новый плейлист</string>
<string name="fmt_def_playlist">Плейлист %d</string>

View file

@ -274,6 +274,5 @@
<string name="lbl_playlists">çalma listeleri</string>
<string name="set_intelligent_sorting">Sıralama yaparken makaleleri yoksay</string>
<string name="set_intelligent_sorting_desc">Ada göre sıralarken \"the\" gibi kelimeleri yok sayın (en iyi ingilizce müzikle çalışır)</string>
<string name="lbl_none">Hiçbiri</string>
<string name="desc_new_playlist">Yeni bir oynatma listesi oluştur</string>
</resources>

View file

@ -278,7 +278,6 @@
<string name="desc_playlist_image">Зображення списку відтворення для %s</string>
<string name="lbl_playlist">Список відтворення</string>
<string name="lbl_playlists">Списки відтворення</string>
<string name="lbl_none">Немає</string>
<string name="set_intelligent_sorting">Інтелектуальне сортування</string>
<string name="set_intelligent_sorting_desc">Ігнорування таких слів, як \"the\", або цифр під час сортування за назвою (найкраще працює з англомовною музикою)</string>
<string name="desc_new_playlist">Створити новий список відтворення</string>

View file

@ -272,7 +272,6 @@
<string name="lbl_playlist">播放列表</string>
<string name="lbl_playlists">播放列表</string>
<string name="desc_playlist_image">%s 的播放列表图片</string>
<string name="lbl_none"></string>
<string name="set_intelligent_sorting">排序时忽略冠词</string>
<string name="set_intelligent_sorting_desc">按名称排序时忽略类似“the”这样的冠词对英文歌曲的效果最好</string>
<string name="desc_new_playlist">创建新的播放列表</string>

View file

@ -52,7 +52,6 @@
<string name="set_key_album_songs_sort" translatable="false">auxio_album_sort</string>
<string name="set_key_artist_songs_sort" translatable="false">auxio_artist_sort</string>
<string name="set_key_genre_songs_sort" translatable="false">auxio_genre_sort</string>
<string name="set_key_playlist_songs_sort" translatable="false">auxio_playlist_sort</string>
<string-array name="entries_theme">
<item>@string/set_theme_auto</item>

View file

@ -92,7 +92,6 @@
<!-- As in to not filter -->
<string name="lbl_filter_all">All</string>
<string name="lbl_none">None</string>
<string name="lbl_name">Name</string>
<string name="lbl_date">Date</string>
<string name="lbl_duration">Duration</string>

View file

@ -18,7 +18,7 @@
package org.oxycblt.auxio.music.device
import java.util.*
import java.util.UUID
import org.junit.Assert.assertTrue
import org.junit.Test

View file

@ -20,7 +20,11 @@ package org.oxycblt.auxio.music.device
import android.content.Context
import android.net.Uri
import org.oxycblt.auxio.music.*
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.Music
import org.oxycblt.auxio.music.Song
open class FakeDeviceLibrary : DeviceLibrary {
override val songs: List<Song>

View file

@ -0,0 +1,2 @@
Auxio 3.1.0 introduces playlisting functionality, with more features coming soon.
For more information, see https://github.com/OxygenCobalt/Auxio/releases/tag/v3.1.0.

View file

@ -1,4 +1,4 @@
Auxio is a local music player with a fast, reliable UI/UX without the many useless features present in other music players. Built off of Exoplayer, Auxio has superior library support and listening quality compared to other apps that use outdated android functionality. In short, <b>It plays music</b>.
Auxio is a local music player with a fast, reliable UI/UX without the many useless features present in other music players. Built off of ExoPlayer, Auxio has superior library support and listening quality compared to other apps that use outdated android functionality. In short, <b>It plays music</b>.
<b>Features</b>
@ -10,7 +10,8 @@ Auxio is a local music player with a fast, reliable UI/UX without the many usele
precise/original dates, sort tags, and more
- Advanced artist system that unifies artists and album artists
- SD Card-aware folder management
- Reliable playback state persistence
- Reliable playlisting functionality
- Playback state persistence
- Full ReplayGain support (On MP3, FLAC, OGG, OPUS, and MP4 files)
- External equalizer support (ex. Wavelet)
- Edge-to-edge
@ -19,4 +20,4 @@ precise/original dates, sort tags, and more
- Headset autoplay
- Stylish widgets that automatically adapt to their size
- Completely private and offline
- No rounded album covers (Unless you want them. Then you can.)
- No rounded album covers (Unless you want them. Then you can.)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 KiB

After

Width:  |  Height:  |  Size: 181 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 154 KiB

After

Width:  |  Height:  |  Size: 145 KiB

Some files were not shown because too many files have changed in this diff Show more