Update code style

Heavily tweak the code style across the app, doing things such as fixing returns and giving names to lambda values.
This commit is contained in:
OxygenCobalt 2021-03-05 12:56:04 -07:00
parent fab377eba4
commit 2c93e3f362
No known key found for this signature in database
GPG key ID: 37DBE3621FE9AD47
41 changed files with 347 additions and 327 deletions

View file

@ -83,8 +83,8 @@ class MainFragment : Fragment() {
}
navController?.let { controller ->
binding.navBar.setOnNavigationItemSelectedListener {
navigateWithItem(controller, it)
binding.navBar.setOnNavigationItemSelectedListener { item ->
navigateWithItem(controller, item)
}
}
}
@ -94,12 +94,12 @@ class MainFragment : Fragment() {
// Change CompactPlaybackFragment's visibility here so that an animation occurs.
handleCompactPlaybackVisibility(binding, playbackModel.song.value)
playbackModel.song.observe(viewLifecycleOwner) {
handleCompactPlaybackVisibility(binding, it)
playbackModel.song.observe(viewLifecycleOwner) { song ->
handleCompactPlaybackVisibility(binding, song)
}
detailModel.navToItem.observe(viewLifecycleOwner) {
if (it != null && navController != null) {
detailModel.navToItem.observe(viewLifecycleOwner) { item ->
if (item != null && navController != null) {
val curDest = navController.currentDestination?.id
// SongsFragment and SettingsFragment have no navigation pathways, so correct

View file

@ -15,7 +15,6 @@ import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.toURI
import org.oxycblt.auxio.settings.SettingsManager
import java.io.ByteArrayInputStream
import java.io.InputStream
/**
* Fetcher that returns the album art for a given [Album]. Handles settings on whether to use
@ -39,11 +38,13 @@ class AlbumArtFetcher(private val context: Context) : Fetcher<Album> {
}
private fun loadMediaStoreCovers(data: Album): SourceResult {
val stream: InputStream? = context.contentResolver.openInputStream(data.coverUri)
val stream = context.contentResolver.openInputStream(data.coverUri)
stream?.let { stm ->
if (stream != null) {
// Don't close the stream here as it will cause an error later from an attempted read.
// This stream still seems to close itself at some point, so its fine.
return SourceResult(
source = stm.source().buffer(),
source = stream.source().buffer(),
mimeType = context.contentResolver.getType(data.coverUri),
dataSource = DataSource.DISK
)

View file

@ -34,6 +34,7 @@ class MosaicFetcher(private val context: Context) : Fetcher<Parent> {
size: Size,
options: Options
): FetchResult {
options.allowRgb565
// Get the URIs for either a genre or artist
val uris = mutableListOf<Uri>()

View file

@ -132,7 +132,6 @@ class PlaybackStateDatabase(context: Context) :
assertBackgroundThread()
val database = writableDatabase
var state: PlaybackState? = null
try {

View file

@ -55,16 +55,13 @@ class AlbumDetailFragment : DetailFragment() {
binding.lifecycleOwner = this
setupToolbar(R.menu.menu_album_detail) {
when (it) {
R.id.action_queue_add -> {
playbackModel.addToUserQueue(detailModel.currentAlbum.value!!)
getString(R.string.label_queue_added).createToast(requireContext())
true
}
else -> false
setupToolbar(R.menu.menu_album_detail) { itemId ->
if (itemId == R.id.action_queue_add) {
playbackModel.addToUserQueue(detailModel.currentAlbum.value!!)
getString(R.string.label_queue_added).createToast(requireContext())
true
} else {
false
}
}
@ -83,18 +80,18 @@ class AlbumDetailFragment : DetailFragment() {
detailAdapter.submitList(data)
}
detailModel.navToItem.observe(viewLifecycleOwner) {
when (it) {
detailModel.navToItem.observe(viewLifecycleOwner) { item ->
when (item) {
// Songs should be scrolled to if the album matches, or a new detail
// fragment should be launched otherwise.
is Song -> {
if (detailModel.currentAlbum.value!!.id == it.album.id) {
scrollToItem(it.id)
if (detailModel.currentAlbum.value!!.id == item.album.id) {
scrollToItem(item.id)
detailModel.doneWithNavToItem()
} else {
findNavController().navigate(
AlbumDetailFragmentDirections.actionShowAlbum(it.album.id)
AlbumDetailFragmentDirections.actionShowAlbum(item.album.id)
)
}
}
@ -102,12 +99,12 @@ class AlbumDetailFragment : DetailFragment() {
// If the album matches, no need to do anything. Otherwise launch a new
// detail fragment.
is Album -> {
if (detailModel.currentAlbum.value!!.id == it.id) {
if (detailModel.currentAlbum.value!!.id == item.id) {
binding.detailRecycler.scrollToPosition(0)
detailModel.doneWithNavToItem()
} else {
findNavController().navigate(
AlbumDetailFragmentDirections.actionShowAlbum(it.id)
AlbumDetailFragmentDirections.actionShowAlbum(item.id)
)
}
}
@ -115,7 +112,7 @@ class AlbumDetailFragment : DetailFragment() {
// Always launch a new ArtistDetailFragment.
is Artist -> {
findNavController().navigate(
AlbumDetailFragmentDirections.actionShowArtist(it.id)
AlbumDetailFragmentDirections.actionShowArtist(item.id)
)
}
@ -125,19 +122,19 @@ class AlbumDetailFragment : DetailFragment() {
// --- PLAYBACKVIEWMODEL SETUP ---
playbackModel.song.observe(viewLifecycleOwner) {
playbackModel.song.observe(viewLifecycleOwner) { song ->
if (playbackModel.mode.value == PlaybackMode.IN_ALBUM &&
playbackModel.parent.value?.id == detailModel.currentAlbum.value!!.id
) {
detailAdapter.highlightSong(playbackModel.song.value, binding.detailRecycler)
detailAdapter.highlightSong(song, binding.detailRecycler)
} else {
// Clear the viewholders if the mode isn't ALL_SONGS
detailAdapter.highlightSong(null, binding.detailRecycler)
}
}
playbackModel.isInUserQueue.observe(viewLifecycleOwner) {
if (it) {
playbackModel.isInUserQueue.observe(viewLifecycleOwner) { inUserQueue ->
if (inUserQueue) {
detailAdapter.highlightSong(null, binding.detailRecycler)
}
}

View file

@ -11,7 +11,6 @@ import org.oxycblt.auxio.logD
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
import org.oxycblt.auxio.music.BaseModel
import org.oxycblt.auxio.music.Genre
import org.oxycblt.auxio.music.MusicStore
import org.oxycblt.auxio.music.Song
import org.oxycblt.auxio.ui.ActionMenu
@ -44,16 +43,18 @@ class ArtistDetailFragment : DetailFragment() {
val detailAdapter = ArtistDetailAdapter(
detailModel, playbackModel, viewLifecycleOwner,
doOnClick = {
doOnClick = { album ->
if (!detailModel.isNavigating) {
detailModel.updateNavigationStatus(true)
detailModel.setNavigating(true)
findNavController().navigate(
ArtistDetailFragmentDirections.actionShowAlbum(it.id)
ArtistDetailFragmentDirections.actionShowAlbum(album.id)
)
}
},
doOnLongClick = { view, data -> newMenu(view, data, ActionMenu.FLAG_IN_ARTIST) }
doOnLongClick = { view, data ->
newMenu(view, data, ActionMenu.FLAG_IN_ARTIST)
}
)
// --- UI SETUP ---
@ -76,26 +77,28 @@ class ArtistDetailFragment : DetailFragment() {
detailAdapter.submitList(data)
}
detailModel.navToItem.observe(viewLifecycleOwner) {
if (it != null) {
// If the artist matches, no need to do anything, otherwise launch a new detail
if (it is Artist) {
if (it.id == detailModel.currentArtist.value!!.id) {
detailModel.navToItem.observe(viewLifecycleOwner) { item ->
when (item) {
is Artist -> {
if (item.id == detailModel.currentArtist.value!!.id) {
binding.detailRecycler.scrollToPosition(0)
detailModel.doneWithNavToItem()
} else {
findNavController().navigate(
ArtistDetailFragmentDirections.actionShowArtist(it.id)
ArtistDetailFragmentDirections.actionShowArtist(item.id)
)
}
} else if (it !is Genre) {
// Determine the album id of the song or album, and then launch it otherwise
val albumId = if (it is Song) it.album.id else it.id
findNavController().navigate(
ArtistDetailFragmentDirections.actionShowAlbum(albumId)
)
}
is Album -> findNavController().navigate(
ArtistDetailFragmentDirections.actionShowAlbum(item.id)
)
is Song -> findNavController().navigate(
ArtistDetailFragmentDirections.actionShowAlbum(item.album.id)
)
else -> {}
}
}

View file

@ -35,7 +35,7 @@ abstract class DetailFragment : Fragment() {
super.onResume()
callback.isEnabled = true
detailModel.updateNavigationStatus(false)
detailModel.setNavigating(false)
}
override fun onPause() {
@ -56,7 +56,7 @@ abstract class DetailFragment : Fragment() {
*/
protected fun setupToolbar(
@MenuRes menu: Int = -1,
onMenuClick: ((id: Int) -> Boolean)? = null
onMenuClick: ((itemId: Int) -> Boolean)? = null
) {
binding.detailToolbar.apply {
if (menu != -1) {
@ -67,9 +67,9 @@ abstract class DetailFragment : Fragment() {
findNavController().navigateUp()
}
onMenuClick?.let {
setOnMenuItemClickListener {
it(it.itemId)
onMenuClick?.let { onClick ->
setOnMenuItemClickListener { item ->
onClick(item.itemId)
}
}
}

View file

@ -16,26 +16,27 @@ import org.oxycblt.auxio.recycler.SortMode
*/
class DetailViewModel : ViewModel() {
private val mCurrentGenre = MutableLiveData<Genre?>()
private val mCurrentArtist = MutableLiveData<Artist?>()
private val mCurrentAlbum = MutableLiveData<Album?>()
private val mGenreSortMode = MutableLiveData(SortMode.ALPHA_DOWN)
private val mArtistSortMode = MutableLiveData(SortMode.NUMERIC_DOWN)
private val mAlbumSortMode = MutableLiveData(SortMode.NUMERIC_DOWN)
private val mNavToItem = MutableLiveData<BaseModel?>()
private var mIsNavigating = false
val currentGenre: LiveData<Genre?> get() = mCurrentGenre
private val mCurrentArtist = MutableLiveData<Artist?>()
val currentArtist: LiveData<Artist?> get() = mCurrentArtist
private val mCurrentAlbum = MutableLiveData<Album?>()
val currentAlbum: LiveData<Album?> get() = mCurrentAlbum
private val mGenreSortMode = MutableLiveData(SortMode.ALPHA_DOWN)
val genreSortMode: LiveData<SortMode> get() = mGenreSortMode
private val mArtistSortMode = MutableLiveData(SortMode.NUMERIC_DOWN)
val albumSortMode: LiveData<SortMode> get() = mAlbumSortMode
private val mAlbumSortMode = MutableLiveData(SortMode.NUMERIC_DOWN)
val artistSortMode: LiveData<SortMode> get() = mArtistSortMode
private var mIsNavigating = false
val isNavigating: Boolean get() = mIsNavigating
private val mNavToItem = MutableLiveData<BaseModel?>()
/** Flag for unified navigation. Observe this to coordinate navigation to an item's UI. */
val navToItem: LiveData<BaseModel?> get() = mNavToItem
@ -106,7 +107,7 @@ class DetailViewModel : ViewModel() {
/**
* Update the current navigation status to [isNavigating]
*/
fun updateNavigationStatus(isNavigating: Boolean) {
fun setNavigating(isNavigating: Boolean) {
mIsNavigating = isNavigating
}
}

View file

@ -43,10 +43,12 @@ class GenreDetailFragment : DetailFragment() {
val detailAdapter = GenreDetailAdapter(
detailModel, playbackModel, viewLifecycleOwner,
doOnClick = {
playbackModel.playSong(it, PlaybackMode.IN_GENRE)
doOnClick = { song ->
playbackModel.playSong(song, PlaybackMode.IN_GENRE)
},
doOnLongClick = { view, data -> newMenu(view, data, ActionMenu.FLAG_IN_GENRE) }
doOnLongClick = { view, data ->
newMenu(view, data, ActionMenu.FLAG_IN_GENRE)
}
)
// --- UI SETUP ---
@ -69,19 +71,19 @@ class GenreDetailFragment : DetailFragment() {
detailAdapter.submitList(data)
}
detailModel.navToItem.observe(viewLifecycleOwner) {
when (it) {
detailModel.navToItem.observe(viewLifecycleOwner) { item ->
when (item) {
// All items will launch new detail fragments.
is Artist -> findNavController().navigate(
GenreDetailFragmentDirections.actionShowArtist(it.id)
GenreDetailFragmentDirections.actionShowArtist(item.id)
)
is Album -> findNavController().navigate(
GenreDetailFragmentDirections.actionShowAlbum(it.id)
GenreDetailFragmentDirections.actionShowAlbum(item.id)
)
is Song -> findNavController().navigate(
GenreDetailFragmentDirections.actionShowAlbum(it.album.id)
GenreDetailFragmentDirections.actionShowAlbum(item.album.id)
)
else -> {}
@ -90,19 +92,19 @@ class GenreDetailFragment : DetailFragment() {
// --- PLAYBACKVIEWMODEL SETUP ---
playbackModel.song.observe(viewLifecycleOwner) {
playbackModel.song.observe(viewLifecycleOwner) { song ->
if (playbackModel.mode.value == PlaybackMode.IN_GENRE &&
playbackModel.parent.value?.id == detailModel.currentGenre.value!!.id
) {
detailAdapter.highlightSong(playbackModel.song.value, binding.detailRecycler)
detailAdapter.highlightSong(song, binding.detailRecycler)
} else {
// Clear the viewholders if the mode isn't ALL_SONGS
detailAdapter.highlightSong(null, binding.detailRecycler)
}
}
playbackModel.isInUserQueue.observe(viewLifecycleOwner) {
if (it) {
playbackModel.isInUserQueue.observe(viewLifecycleOwner) { inUserQueue ->
if (inUserQueue) {
detailAdapter.highlightSong(null, binding.detailRecycler)
}
}

View file

@ -89,8 +89,8 @@ class AlbumDetailAdapter(
if (song != null) {
// Use existing data instead of having to re-sort it.
val pos = currentList.indexOfFirst {
it.name == song.name && it is Song
val pos = currentList.indexOfFirst { item ->
item.name == song.name && item is Song
}
// Check if the ViewHolder for this song is visible, if it is then highlight it.

View file

@ -90,8 +90,8 @@ class ArtistDetailAdapter(
if (album != null) {
// Use existing data instead of having to re-sort it.
val pos = currentList.indexOfFirst {
it.name == album.name && it is Album
val pos = currentList.indexOfFirst { item ->
item.name == album.name && item is Album
}
// Check if the ViewHolder if this album is visible, and highlight it if so.

View file

@ -90,8 +90,8 @@ class GenreDetailAdapter(
if (song != null) {
// Use existing data instead of having to re-sort it.
val pos = currentList.indexOfFirst {
it.name == song.name && it is Song
val pos = currentList.indexOfFirst { item ->
item.name == song.name && item is Song
}
// Check if the ViewHolder for this song is visible, if it is then highlight it.

View file

@ -37,24 +37,23 @@ class LibraryFragment : Fragment() {
): View {
val binding = FragmentLibraryBinding.inflate(inflater)
val libraryAdapter = LibraryAdapter(::navToDetail) { view, data -> newMenu(view, data) }
val libraryAdapter = LibraryAdapter(::navToDetail) { view, data ->
newMenu(view, data)
}
// --- UI SETUP ---
binding.libraryToolbar.apply {
menu.findItem(libraryModel.sortMode.toMenuId()).isChecked = true
setOnMenuItemClickListener {
when (it.itemId) {
R.id.submenu_sorting -> {}
else -> {
it.isChecked = true
libraryModel.updateSortMode(it.itemId)
}
setOnMenuItemClickListener { item ->
if (item.itemId != R.id.submenu_sorting) {
libraryModel.updateSortMode(item.itemId)
item.isChecked = true
true
} else {
false
}
true
}
}
@ -70,18 +69,18 @@ class LibraryFragment : Fragment() {
// --- VIEWMODEL SETUP ---
libraryModel.libraryData.observe(viewLifecycleOwner) {
libraryAdapter.updateData(it)
libraryModel.libraryData.observe(viewLifecycleOwner) { data ->
libraryAdapter.updateData(data)
}
detailModel.navToItem.observe(viewLifecycleOwner) {
if (it != null) {
libraryModel.updateNavigationStatus(false)
detailModel.navToItem.observe(viewLifecycleOwner) { item ->
if (item != null) {
libraryModel.setNavigating(false)
if (it is Parent) {
navToDetail(it)
} else if (it is Song) {
navToDetail(it.album)
if (item is Parent) {
navToDetail(item)
} else if (item is Song) {
navToDetail(item.album)
}
}
}
@ -94,7 +93,7 @@ class LibraryFragment : Fragment() {
override fun onResume() {
super.onResume()
libraryModel.updateNavigationStatus(false)
libraryModel.setNavigating(false)
}
override fun onDestroyView() {
@ -110,7 +109,7 @@ class LibraryFragment : Fragment() {
requireView().rootView.clearFocus()
if (!libraryModel.isNavigating) {
libraryModel.updateNavigationStatus(true)
libraryModel.setNavigating(true)
logD("Navigating to the detail fragment for ${parent.name}")

View file

@ -64,7 +64,7 @@ class LibraryViewModel : ViewModel(), SettingsManager.Callback {
/**
* Update the current navigation status
*/
fun updateNavigationStatus(isNavigating: Boolean) {
fun setNavigating(isNavigating: Boolean) {
mIsNavigating = isNavigating
}

View file

@ -42,8 +42,8 @@ class LoadingFragment : Fragment() {
// --- VIEWMODEL SETUP ---
loadingModel.doGrant.observe(viewLifecycleOwner) {
if (it) {
loadingModel.doGrant.observe(viewLifecycleOwner) { doGrant ->
if (doGrant) {
permLauncher.launch(Manifest.permission.READ_EXTERNAL_STORAGE)
loadingModel.doneWithGrant()
}
@ -80,7 +80,9 @@ class LoadingFragment : Fragment() {
override fun onResume() {
super.onResume()
if (MusicStore.getInstance().loaded) {
// Navigate away if the music has already been loaded.
// This causes a memory leak, but there's nothing I can do about it.
if (loadingModel.loaded) {
findNavController().navigate(
LoadingFragmentDirections.actionToMain()
)
@ -106,8 +108,8 @@ class LoadingFragment : Fragment() {
private fun onPermResult(granted: Boolean) {
if (granted) {
// If granted, its now safe to load [Which will clear the NO_PERMS response we applied
// earlier]
// If granted, its now safe to load, which will clear the NO_PERMS response
// we applied earlier.
loadingModel.load()
}
}

View file

@ -17,11 +17,12 @@ class LoadingViewModel(private val app: Application) : ViewModel() {
private val mResponse = MutableLiveData<MusicStore.Response?>(null)
private val mDoGrant = MutableLiveData(false)
private var isBusy = false
/** The last response from [MusicStore]. Null if the loading process is occurring. */
val response: LiveData<MusicStore.Response?> = mResponse
val doGrant: LiveData<Boolean> = mDoGrant
private var isBusy = false
val loaded: Boolean get() = musicStore.loaded
private val musicStore = MusicStore.getInstance()

View file

@ -46,6 +46,7 @@ class MusicStore private constructor() {
*/
suspend fun load(app: Application): Response {
return withContext(Dispatchers.IO) {
// TODO: Move this to an internal function
this@MusicStore.logD("Starting initial music load...")
val start = System.currentTimeMillis()

View file

@ -5,12 +5,10 @@ import android.content.Context
import android.net.Uri
import android.provider.MediaStore
import android.text.format.DateUtils
import android.widget.ImageButton
import android.widget.TextView
import androidx.core.text.isDigitsOnly
import androidx.databinding.BindingAdapter
import org.oxycblt.auxio.R
import org.oxycblt.auxio.recycler.SortMode
import org.oxycblt.auxio.ui.getPlural
/**
@ -169,11 +167,3 @@ fun TextView.bindAlbumInfo(album: Album) {
fun TextView.bindAlbumYear(album: Album) {
text = album.year.toYear(context)
}
/**
* Bind the [SortMode] icon for an ImageButton.
*/
@BindingAdapter("sortIcon")
fun ImageButton.bindSortIcon(mode: SortMode) {
setImageResource(mode.iconRes)
}

View file

@ -64,8 +64,8 @@ class CompactPlaybackFragment : Fragment() {
}
}
playbackModel.isPlaying.observe(viewLifecycleOwner) {
binding.playbackPlayPause.setPlaying(it, playbackModel.canAnimate)
playbackModel.isPlaying.observe(viewLifecycleOwner) { isPlaying ->
binding.playbackPlayPause.setPlaying(isPlaying, playbackModel.canAnimate)
playbackModel.enableAnimation()
}

View file

@ -61,12 +61,14 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
findNavController().navigateUp()
}
setOnMenuItemClickListener {
if (it.itemId == R.id.action_queue) {
setOnMenuItemClickListener { item ->
if (item.itemId == R.id.action_queue) {
findNavController().navigate(PlaybackFragmentDirections.actionShowQueue())
true
} else false
} else {
false
}
}
queueItem = menu.findItem(R.id.action_queue)
@ -90,12 +92,16 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
}
}
playbackModel.isShuffling.observe(viewLifecycleOwner) {
binding.playbackShuffle.imageTintList = if (it) accentColor else controlColor
playbackModel.isShuffling.observe(viewLifecycleOwner) { isShuffling ->
binding.playbackShuffle.imageTintList = if (isShuffling) {
accentColor
} else {
controlColor
}
}
playbackModel.loopMode.observe(viewLifecycleOwner) {
when (it) {
playbackModel.loopMode.observe(viewLifecycleOwner) { loopMode ->
when (loopMode) {
LoopMode.NONE -> {
binding.playbackLoop.imageTintList = controlColor
binding.playbackLoop.setImageResource(R.drawable.ic_loop)
@ -115,17 +121,17 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
}
}
playbackModel.isSeeking.observe(viewLifecycleOwner) {
if (it) {
playbackModel.isSeeking.observe(viewLifecycleOwner) { isSeeking ->
if (isSeeking) {
binding.playbackDurationCurrent.setTextColor(accentColor)
} else {
binding.playbackDurationCurrent.setTextColor(normalTextColor)
}
}
playbackModel.positionAsProgress.observe(viewLifecycleOwner) {
playbackModel.positionAsProgress.observe(viewLifecycleOwner) { pos ->
if (!playbackModel.isSeeking.value!!) {
binding.playbackSeekBar.progress = it
binding.playbackSeekBar.progress = pos
}
}
@ -153,9 +159,9 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
}
}
playbackModel.isPlaying.observe(viewLifecycleOwner) {
playbackModel.isPlaying.observe(viewLifecycleOwner) { isPlaying ->
binding.playbackPlayPause.apply {
if (it) {
if (isPlaying) {
backgroundTintList = accentColor
setPlaying(true, playbackModel.canAnimate)
} else {
@ -167,8 +173,8 @@ class PlaybackFragment : Fragment(), SeekBar.OnSeekBarChangeListener {
playbackModel.enableAnimation()
}
detailModel.navToItem.observe(viewLifecycleOwner) {
if (it != null) {
detailModel.navToItem.observe(viewLifecycleOwner) { item ->
if (item != null) {
findNavController().navigateUp()
}
}

View file

@ -380,7 +380,7 @@ class PlaybackViewModel : ViewModel(), PlaybackStateManager.Callback {
mIntentUri = null
// Were not going to be restoring playbackManager after this, so mark it as such.
playbackManager.setRestored()
playbackManager.markRestored()
} else if (!playbackManager.isRestored) {
// Otherwise just restore
viewModelScope.launch {

View file

@ -61,23 +61,21 @@ class QueueAdapter(
ItemQueueSongBinding.inflate(parent.context.inflater)
)
else -> error("Someone messed with the ViewHolder item types.")
else -> error("Invalid viewholder item type $viewType.")
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (val item = data[position]) {
is Song -> (holder as QueueSongViewHolder).bind(item)
is Header ->
if (item.isAction) {
(holder as UserQueueHeaderViewHolder).bind(item)
} else {
(holder as HeaderViewHolder).bind(item)
}
else -> {
logE("Bad data fed to QueueAdapter.")
is Header -> if (item.isAction) {
(holder as UserQueueHeaderViewHolder).bind(item)
} else {
(holder as HeaderViewHolder).bind(item)
}
else -> logE("Bad data given to QueueAdapter.")
}
}
@ -95,7 +93,7 @@ class QueueAdapter(
/**
* Move Items.
* Used since [submitList] will cause QueueAdapter to freak-out here.
* Used since [submitList] will cause QueueAdapter to freak out.
*/
fun moveItems(adapterFrom: Int, adapterTo: Int) {
val item = data.removeAt(adapterFrom)
@ -106,7 +104,7 @@ class QueueAdapter(
/**
* Remove an item.
* Used since [submitList] will cause QueueAdapter to freak-out here.
* Used since [submitList] will cause QueueAdapter to freak out.
*/
fun removeItem(adapterIndex: Int) {
data.removeAt(adapterIndex)
@ -154,10 +152,8 @@ class QueueAdapter(
if (motionEvent.actionMasked == MotionEvent.ACTION_DOWN) {
touchHelper.startDrag(this)
return@setOnTouchListener true
}
false
true
} else false
}
}
}

View file

@ -49,10 +49,11 @@ class QueueFragment : Fragment() {
}
if (!requireActivity().isIrregularLandscape() && isEdgeOn()) {
setOnApplyWindowInsetsListener @Suppress("DEPRECATION") { _, insets ->
setOnApplyWindowInsetsListener { _, insets ->
val top = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
insets.getInsets(WindowInsets.Type.systemBars()).top
} else {
@Suppress("DEPRECATION")
insets.systemWindowInsetTop
}
@ -74,8 +75,8 @@ class QueueFragment : Fragment() {
// --- VIEWMODEL SETUP ----
playbackModel.userQueue.observe(viewLifecycleOwner) {
if (it.isEmpty() && playbackModel.nextItemsInQueue.value!!.isEmpty()) {
playbackModel.userQueue.observe(viewLifecycleOwner) { userQueue ->
if (userQueue.isEmpty() && playbackModel.nextItemsInQueue.value!!.isEmpty()) {
findNavController().navigateUp()
return@observe
@ -84,17 +85,17 @@ class QueueFragment : Fragment() {
queueAdapter.submitList(createQueueData())
}
playbackModel.nextItemsInQueue.observe(viewLifecycleOwner) {
if (it.isEmpty() && playbackModel.userQueue.value!!.isEmpty()) {
playbackModel.nextItemsInQueue.observe(viewLifecycleOwner) { nextQueue ->
if (nextQueue.isEmpty() && playbackModel.userQueue.value!!.isEmpty()) {
findNavController().navigateUp()
}
queueAdapter.submitList(createQueueData())
}
playbackModel.isShuffling.observe(viewLifecycleOwner) {
if (it != lastShuffle) {
lastShuffle = it
playbackModel.isShuffling.observe(viewLifecycleOwner) { isShuffling ->
if (isShuffling != lastShuffle) {
lastShuffle = isShuffling
binding.queueRecycler.scrollToPosition(0)
}
@ -109,21 +110,27 @@ class QueueFragment : Fragment() {
*/
private fun createQueueData(): MutableList<BaseModel> {
val queue = mutableListOf<BaseModel>()
val userQueue = playbackModel.userQueue.value!!
val nextQueue = playbackModel.nextItemsInQueue.value!!
if (playbackModel.userQueue.value!!.isNotEmpty()) {
queue.add(Header(id = -2, name = getString(R.string.label_next_user_queue), isAction = true))
queue.addAll(playbackModel.userQueue.value!!)
if (userQueue.isNotEmpty()) {
queue += Header(
id = -2,
name = getString(R.string.label_next_user_queue),
isAction = true
)
queue += userQueue
}
if (playbackModel.nextItemsInQueue.value!!.isNotEmpty()) {
queue.add(
Header(
id = -3,
name = getString(R.string.format_next_from, getParentName()),
isAction = false
)
if (nextQueue.isNotEmpty()) {
queue += Header(
id = -3,
name = getString(R.string.format_next_from, getParentName()),
isAction = false
)
queue.addAll(playbackModel.nextItemsInQueue.value!!)
queue += nextQueue
}
return queue

View file

@ -24,16 +24,16 @@ enum class LoopMode {
*/
fun toInt(): Int {
return when (this) {
NONE -> CONSTANT_NONE
ONCE -> CONSTANT_ONCE
INFINITE -> CONSTANT_INFINITE
NONE -> CONST_NONE
ONCE -> CONST_ONCE
INFINITE -> CONST_INFINITE
}
}
companion object {
const val CONSTANT_NONE = 0xA050
const val CONSTANT_ONCE = 0xA051
const val CONSTANT_INFINITE = 0xA052
private const val CONST_NONE = 0xA050
private const val CONST_ONCE = 0xA051
private const val CONST_INFINITE = 0xA052
/**
* Convert an int [constant] into a LoopMode
@ -41,9 +41,9 @@ enum class LoopMode {
*/
fun fromInt(constant: Int): LoopMode? {
return when (constant) {
CONSTANT_NONE -> NONE
CONSTANT_ONCE -> ONCE
CONSTANT_INFINITE -> INFINITE
CONST_NONE -> NONE
CONST_ONCE -> ONCE
CONST_INFINITE -> INFINITE
else -> null
}

View file

@ -20,18 +20,18 @@ enum class PlaybackMode {
*/
fun toInt(): Int {
return when (this) {
IN_ARTIST -> CONSTANT_IN_ARTIST
IN_GENRE -> CONSTANT_IN_GENRE
IN_ALBUM -> CONSTANT_IN_ALBUM
ALL_SONGS -> CONSTANT_ALL_SONGS
IN_ARTIST -> CONST_IN_ARTIST
IN_GENRE -> CONST_IN_GENRE
IN_ALBUM -> CONST_IN_ALBUM
ALL_SONGS -> CONST_ALL_SONGS
}
}
companion object {
const val CONSTANT_IN_ARTIST = 0xA040
const val CONSTANT_IN_GENRE = 0xA041
const val CONSTANT_IN_ALBUM = 0xA042
const val CONSTANT_ALL_SONGS = 0xA043
private const val CONST_IN_ARTIST = 0xA040
private const val CONST_IN_GENRE = 0xA041
private const val CONST_IN_ALBUM = 0xA042
private const val CONST_ALL_SONGS = 0xA043
/**
* Get a [PlaybackMode] for an int [constant]
@ -39,10 +39,10 @@ enum class PlaybackMode {
*/
fun fromInt(constant: Int): PlaybackMode? {
return when (constant) {
CONSTANT_IN_ARTIST -> IN_ARTIST
CONSTANT_IN_ALBUM -> IN_ALBUM
CONSTANT_IN_GENRE -> IN_GENRE
CONSTANT_ALL_SONGS -> ALL_SONGS
CONST_IN_ARTIST -> IN_ARTIST
CONST_IN_ALBUM -> IN_ALBUM
CONST_IN_GENRE -> IN_GENRE
CONST_ALL_SONGS -> ALL_SONGS
else -> null
}

View file

@ -185,6 +185,8 @@ class PlaybackStateManager private constructor() {
clearLoopMode()
updatePlayback(song)
// Keep shuffle on, if enabled
setShuffling(settingsManager.keepShuffle && mIsShuffling, keepSong = true)
}
@ -203,10 +205,12 @@ class PlaybackStateManager private constructor() {
mQueue = parent.songs.toMutableList()
mMode = PlaybackMode.IN_ALBUM
}
is Artist -> {
mQueue = parent.songs.toMutableList()
mMode = PlaybackMode.IN_ARTIST
}
is Genre -> {
mQueue = parent.songs.toMutableList()
mMode = PlaybackMode.IN_GENRE
@ -228,6 +232,8 @@ class PlaybackStateManager private constructor() {
setShuffling(true, keepSong = false)
updatePlayback(mQueue[0])
// FIXME: Add clearLoopMode here?
}
/**
@ -293,9 +299,7 @@ class PlaybackStateManager private constructor() {
}
clearLoopMode()
updatePlayback(mQueue[mIndex])
forceQueueUpdate()
}
}
@ -307,18 +311,18 @@ class PlaybackStateManager private constructor() {
when (settingsManager.doAtEnd) {
SettingsManager.EntryValues.AT_END_LOOP_PAUSE -> {
mIndex = 0
forceQueueUpdate()
mSong = mQueue[0]
mPosition = 0
setPlaying(false)
mIsInUserQueue = false
mSong = mQueue[0]
setPlaying(false)
forceQueueUpdate()
}
SettingsManager.EntryValues.AT_END_LOOP -> {
mIndex = 0
forceQueueUpdate()
forceQueueUpdate()
updatePlayback(mQueue[0])
}
@ -529,9 +533,9 @@ class PlaybackStateManager private constructor() {
* @see seekTo
*/
fun setPosition(position: Long) {
mSong?.let {
mSong?.let { song ->
// Don't accept any bugged positions that are over the duration of the song.
if (position <= it.duration) {
if (position <= song.duration) {
mPosition = position
}
}
@ -584,7 +588,7 @@ class PlaybackStateManager private constructor() {
/**
* Mark this instance as restored.
*/
fun setRestored() {
fun markRestored() {
mIsRestored = true
}
@ -620,32 +624,34 @@ class PlaybackStateManager private constructor() {
logD("Getting state from DB.")
val now: Long
val state: PlaybackState?
val playbackState: PlaybackState?
// The coroutine call is locked at queueItems so that this function does not
// go ahead until EVERYTHING is read.
// TODO: Improve this
val queueItems = withContext(Dispatchers.IO) {
now = System.currentTimeMillis()
val database = PlaybackStateDatabase.getInstance(context)
state = database.readState()
playbackState = database.readState()
database.readQueue()
}
// Get off the IO coroutine since it will cause LiveData updates to throw an exception
state?.let {
logD("Valid playback state $it")
logD("Valid queue size ${queueItems.size}")
if (playbackState != null) {
logD("Found playback state $playbackState")
logD("Found queue size ${queueItems.size}")
unpackFromPlaybackState(it)
unpackFromPlaybackState(playbackState)
unpackQueue(queueItems)
doParentSanityCheck()
}
logD("Restore finished in ${System.currentTimeMillis() - now}ms")
setRestored()
markRestored()
}
/**
@ -653,19 +659,14 @@ class PlaybackStateManager private constructor() {
* @return A [PlaybackState] reflecting the current state.
*/
private fun packToPlaybackState(): PlaybackState {
val songName = mSong?.name ?: ""
val parentName = mParent?.name ?: ""
val intMode = mMode.toInt()
val intLoopMode = mLoopMode.toInt()
return PlaybackState(
songName = songName,
songName = mSong?.name ?: "",
position = mPosition,
parentName = parentName,
parentName = mParent?.name ?: "",
index = mIndex,
mode = intMode,
mode = mMode.toInt(),
isShuffling = mIsShuffling,
loopMode = intLoopMode,
loopMode = mLoopMode.toInt(),
inUserQueue = mIsInUserQueue
)
}
@ -695,13 +696,13 @@ class PlaybackStateManager private constructor() {
var queueItemId = 0L
mUserQueue.forEach {
unified.add(QueueItem(queueItemId, it.name, it.album.name, true))
mUserQueue.forEach { song ->
unified.add(QueueItem(queueItemId, song.name, song.album.name, true))
queueItemId++
}
mQueue.forEach {
unified.add(QueueItem(queueItemId, it.name, it.album.name, false))
mQueue.forEach { song ->
unified.add(QueueItem(queueItemId, song.name, song.album.name, false))
queueItemId++
}
@ -714,15 +715,15 @@ class PlaybackStateManager private constructor() {
*/
private fun unpackQueue(queueItems: List<QueueItem>) {
// When unpacking, first traverse albums and then traverse album songs to reduce
// the amount of useless comparisons in large queues.
// the amount of comparisons in large queues.
queueItems.forEach { item ->
musicStore.albums.find { it.name == item.albumName }?.songs?.find {
it.name == item.songName
}?.let {
musicStore.albums.find {
it.name == item.albumName
}?.songs?.find { it.name == item.songName }?.let { song ->
if (item.isUserQueue) {
mUserQueue.add(it)
mUserQueue.add(song)
} else {
mQueue.add(it)
mQueue.add(song)
}
}
}
@ -731,8 +732,8 @@ class PlaybackStateManager private constructor() {
// to the db but are now deleted when the restore occurred.
// Not done if in user queue because that could result in a bad index being created.
if (!mIsInUserQueue) {
mSong?.let {
val index = mQueue.indexOf(it)
mSong?.let { song ->
val index = mQueue.indexOf(song)
mIndex = if (index != -1) index else mIndex
}
}

View file

@ -93,7 +93,7 @@ class AudioReactor(
onEnd = { player.volume = VOLUME_FULL }
)
addUpdateListener {
player.volume = it.animatedValue as Float
player.volume = animatedValue as Float
}
start()
}

View file

@ -77,14 +77,12 @@ class PlaybackNotification private constructor(
if (colorize) {
// loadBitmap() is concurrent, so only call back to the object calling this function when
// the loading is over.
loadBitmap(context, song) {
setLargeIcon(it)
loadBitmap(context, song) { bitmap ->
setLargeIcon(bitmap)
onDone()
}
} else {
setLargeIcon(null)
onDone()
}
}
@ -114,9 +112,7 @@ class PlaybackNotification private constructor(
* Apply the current [parent] to the header of the notification.
*/
fun setParent(context: Context, parent: Parent?) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
return
}
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) return
// A blank parent always means that the mode is ALL_SONGS
setSubText(parent?.displayName ?: context.getString(R.string.label_all_songs))

View file

@ -282,7 +282,7 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca
override fun onColorizeNotifUpdate(doColorize: Boolean) {
playbackManager.song?.let { song ->
notification.setMetadata(
this, song, settingsManager.colorizeNotif, {}
this, song, settingsManager.colorizeNotif, ::startForegroundOrNotify
)
}
}
@ -365,8 +365,8 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca
.putString(MediaMetadataCompat.METADATA_KEY_ALBUM, song.album.name)
.putLong(MediaMetadataCompat.METADATA_KEY_DURATION, song.duration)
loadBitmap(this, song) {
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, it)
loadBitmap(this, song) { bitmap ->
builder.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, bitmap)
mediaSession.setMetadata(builder.build())
}
}
@ -383,8 +383,8 @@ class PlaybackService : Service(), Player.EventListener, PlaybackStateManager.Ca
}.conflate()
serviceScope.launch {
pollFlow.takeWhile { player.isPlaying }.collect {
playbackManager.setPosition(it)
pollFlow.takeWhile { player.isPlaying }.collect { pos ->
playbackManager.setPosition(pos)
}
}
}

View file

@ -1,7 +1,9 @@
package org.oxycblt.auxio.recycler
import android.widget.ImageButton
import androidx.annotation.DrawableRes
import androidx.annotation.IdRes
import androidx.databinding.BindingAdapter
import org.oxycblt.auxio.R
import org.oxycblt.auxio.music.Album
import org.oxycblt.auxio.music.Artist
@ -163,20 +165,22 @@ enum class SortMode(@DrawableRes val iconRes: Int) {
*/
fun toInt(): Int {
return when (this) {
NONE -> CONSTANT_NONE
ALPHA_UP -> CONSTANT_ALPHA_UP
ALPHA_DOWN -> CONSTANT_ALPHA_DOWN
NUMERIC_UP -> CONSTANT_NUMERIC_UP
NUMERIC_DOWN -> CONSTANT_NUMERIC_DOWN
NONE -> CONST_NONE
ALPHA_UP -> CONST_ALPHA_UP
ALPHA_DOWN -> CONST_ALPHA_DOWN
NUMERIC_UP -> CONST_NUMERIC_UP
NUMERIC_DOWN -> CONST_NUMERIC_DOWN
}
}
companion object {
const val CONSTANT_NONE = 0xA060
const val CONSTANT_ALPHA_UP = 0xA061
const val CONSTANT_ALPHA_DOWN = 0xA062
const val CONSTANT_NUMERIC_UP = 0xA063
const val CONSTANT_NUMERIC_DOWN = 0xA065
private const val CONST_NONE = 0xA060
private const val CONST_ALPHA_UP = 0xA061
private const val CONST_ALPHA_DOWN = 0xA062
private const val CONST_NUMERIC_UP = 0xA063
private const val CONST_NUMERIC_DOWN = 0xA065
const val CONST_SORT_DEFAULT = CONST_ALPHA_DOWN
/**
* Get an enum for an int constant
@ -184,14 +188,22 @@ enum class SortMode(@DrawableRes val iconRes: Int) {
*/
fun fromInt(value: Int): SortMode? {
return when (value) {
CONSTANT_NONE -> NONE
CONSTANT_ALPHA_UP -> ALPHA_UP
CONSTANT_ALPHA_DOWN -> ALPHA_DOWN
CONSTANT_NUMERIC_UP -> NUMERIC_UP
CONSTANT_NUMERIC_DOWN -> NUMERIC_DOWN
CONST_NONE -> NONE
CONST_ALPHA_UP -> ALPHA_UP
CONST_ALPHA_DOWN -> ALPHA_DOWN
CONST_NUMERIC_UP -> NUMERIC_UP
CONST_NUMERIC_DOWN -> NUMERIC_DOWN
else -> null
}
}
}
}
/**
* Bind the [SortMode] icon for an ImageButton.
*/
@BindingAdapter("sortIcon")
fun ImageButton.bindSortIcon(mode: SortMode) {
setImageResource(mode.iconRes)
}

View file

@ -47,10 +47,13 @@ class SearchFragment : Fragment() {
): View {
val binding = FragmentSearchBinding.inflate(inflater)
val searchAdapter = SearchAdapter(::onItemSelection) { view, data ->
newMenu(view, data)
}
// Apply the accents manually. Not going through the mess of converting my app's
// styling to Material given all the second-and-third-order effects it has.
val accent = Accent.get().color.toColor(requireContext())
val searchAdapter = SearchAdapter(::onItemSelection) { view, data -> newMenu(view, data) }
val toolbarParams = binding.searchToolbar.layoutParams as AppBarLayout.LayoutParams
val defaultParams = toolbarParams.scrollFlags
@ -59,13 +62,14 @@ class SearchFragment : Fragment() {
binding.searchToolbar.apply {
menu.findItem(searchModel.filterMode.toId()).isChecked = true
setOnMenuItemClickListener {
if (it.itemId != R.id.submenu_filtering) {
it.isChecked = true
searchModel.updateFilterModeWithId(it.itemId, requireContext())
setOnMenuItemClickListener { item ->
if (item.itemId != R.id.submenu_filtering) {
searchModel.updateFilterModeWithId(item.itemId, requireContext())
item.isChecked = true
true
} else false
} else {
false
}
}
}
@ -75,9 +79,9 @@ class SearchFragment : Fragment() {
setEndIconTintList(R.color.control_color.toStateList(context))
}
binding.searchEditText.addTextChangedListener {
binding.searchEditText.addTextChangedListener { text ->
// Run the search with the updated text as the query
searchModel.doSearch(it?.toString() ?: "", requireContext())
searchModel.doSearch(text?.toString() ?: "", requireContext())
}
binding.searchRecycler.apply {
@ -96,12 +100,12 @@ class SearchFragment : Fragment() {
// --- VIEWMODEL SETUP ---
searchModel.searchResults.observe(viewLifecycleOwner) {
searchAdapter.submitList(it) {
searchModel.searchResults.observe(viewLifecycleOwner) { results ->
searchAdapter.submitList(results) {
binding.searchRecycler.scrollToPosition(0)
}
if (it.isEmpty()) {
if (results.isEmpty()) {
// If the data is empty, then the ability for the toolbar to collapse
// on scroll should be disabled.
binding.searchAppbar.setExpanded(true)
@ -113,18 +117,16 @@ class SearchFragment : Fragment() {
}
}
detailModel.navToItem.observe(viewLifecycleOwner) {
if (it != null) {
findNavController().navigate(
when (it) {
is Song -> SearchFragmentDirections.actionShowAlbum(it.album.id)
is Album -> SearchFragmentDirections.actionShowAlbum(it.id)
is Artist -> SearchFragmentDirections.actionShowArtist(it.id)
detailModel.navToItem.observe(viewLifecycleOwner) { item ->
findNavController().navigate(
when (item) {
is Song -> SearchFragmentDirections.actionShowAlbum(item.album.id)
is Album -> SearchFragmentDirections.actionShowAlbum(item.id)
is Artist -> SearchFragmentDirections.actionShowArtist(item.id)
else -> return@observe
}
)
}
else -> return@observe
}
)
}
logD("Fragment created.")
@ -135,7 +137,7 @@ class SearchFragment : Fragment() {
override fun onResume() {
super.onResume()
searchModel.updateNavigationStatus(false)
searchModel.setNavigating(false)
}
override fun onDestroyView() {
@ -159,7 +161,7 @@ class SearchFragment : Fragment() {
requireView().rootView.clearFocus()
if (!searchModel.isNavigating) {
searchModel.updateNavigationStatus(true)
searchModel.setNavigating(true)
logD("Navigating to the detail fragment for ${item.name}")
@ -172,7 +174,7 @@ class SearchFragment : Fragment() {
// If given model wasn't valid, then reset the navigation status
// and abort the navigation.
else -> {
searchModel.updateNavigationStatus(false)
searchModel.setNavigating(false)
return
}
}

View file

@ -53,30 +53,30 @@ class SearchViewModel : ViewModel() {
val results = mutableListOf<BaseModel>()
if (mFilterMode.isAllOr(DisplayMode.SHOW_ARTISTS)) {
musicStore.artists.filterByOrNull(query)?.let {
musicStore.artists.filterByOrNull(query)?.let { artists ->
results.add(Header(id = -2, name = context.getString(R.string.label_artists)))
results.addAll(it)
results.addAll(artists)
}
}
if (mFilterMode.isAllOr(DisplayMode.SHOW_ALBUMS)) {
musicStore.albums.filterByOrNull(query)?.let {
musicStore.albums.filterByOrNull(query)?.let { albums ->
results.add(Header(id = -3, name = context.getString(R.string.label_albums)))
results.addAll(it)
results.addAll(albums)
}
}
if (mFilterMode.isAllOr(DisplayMode.SHOW_GENRES)) {
musicStore.genres.filterByOrNull(query)?.let {
musicStore.genres.filterByOrNull(query)?.let { genres ->
results.add(Header(id = -4, name = context.getString(R.string.label_genres)))
results.addAll(it)
results.addAll(genres)
}
}
if (mFilterMode.isAllOr(DisplayMode.SHOW_SONGS)) {
musicStore.songs.filterByOrNull(query)?.let {
musicStore.songs.filterByOrNull(query)?.let { songs ->
results.add(Header(id = -5, name = context.getString(R.string.label_songs)))
results.addAll(it)
results.addAll(songs)
}
}
@ -101,7 +101,9 @@ class SearchViewModel : ViewModel() {
* a value if the resulting list is empty.
*/
private fun List<BaseModel>.filterByOrNull(value: String): List<BaseModel>? {
val filtered = filter { it.name.contains(value, ignoreCase = true) }
val filtered = filter {
it.name.contains(value, ignoreCase = true)
}
return if (filtered.isNotEmpty()) filtered else null
}
@ -109,7 +111,7 @@ class SearchViewModel : ViewModel() {
/**
* Update the current navigation status to [isNavigating]
*/
fun updateNavigationStatus(isNavigating: Boolean) {
fun setNavigating(isNavigating: Boolean) {
mIsNavigating = isNavigating
}
}

View file

@ -23,11 +23,17 @@ class SettingsFragment : Fragment() {
binding.settingsToolbar.setOnMenuItemClickListener {
if (it.itemId == R.id.action_open_about) {
AboutDialog().show(childFragmentManager, "DIALOG")
AboutDialog().show(childFragmentManager, ABOUT_DIALOG_TAG)
true
} else false
} else {
false
}
}
return binding.root
}
companion object {
private const val ABOUT_DIALOG_TAG = "TAG_ABOUT_DIALOG"
}
}

View file

@ -51,7 +51,9 @@ class SettingsListFragment : PreferenceFragmentCompat() {
private fun recursivelyHandleChildren(pref: Preference) {
if (pref is PreferenceCategory) {
// If this preference is a category of its own, handle its own children
pref.children.forEach { recursivelyHandleChildren(it) }
pref.children.forEach { pref ->
recursivelyHandleChildren(pref)
}
} else {
handlePreference(pref)
}
@ -151,9 +153,10 @@ class SettingsListFragment : PreferenceFragmentCompat() {
// has a bug where ugly dividers will show with the RecyclerView even if you disable them.
// This is why I hate using third party libraries.
val recycler = RecyclerView(requireContext()).apply {
adapter = AccentAdapter {
if (it != Accent.get()) {
settingsManager.accent = it
adapter = AccentAdapter { accent ->
if (accent != Accent.get()) {
// TODO: Move this to Accent.set?
settingsManager.accent = accent
requireActivity().recreate()
}
@ -179,11 +182,8 @@ class SettingsListFragment : PreferenceFragmentCompat() {
}
customView(view = recycler)
invalidateDividers(showTop = false, showBottom = false)
negativeButton(android.R.string.cancel)
show()
}
}

View file

@ -40,11 +40,10 @@ class SettingsManager private constructor(context: Context) :
)
// When converted, write them to the new accent pref and delete the old one.
sharedPrefs.edit {
putInt(Keys.KEY_ACCENT, newAccent)
remove(Keys.KEY_ACCENT_OLD)
apply()
}
sharedPrefs.edit()
.putInt(Keys.KEY_ACCENT, newAccent)
.remove(Keys.KEY_ACCENT_OLD)
.apply()
}
return ACCENTS[sharedPrefs.getInt(Keys.KEY_ACCENT, 5)]
@ -124,8 +123,7 @@ class SettingsManager private constructor(context: Context) :
var librarySortMode: SortMode
get() = SortMode.fromInt(
sharedPrefs.getInt(
Keys.KEY_LIBRARY_SORT_MODE,
SortMode.CONSTANT_ALPHA_DOWN
Keys.KEY_LIBRARY_SORT_MODE, SortMode.CONST_SORT_DEFAULT
)
) ?: SortMode.ALPHA_DOWN

View file

@ -68,14 +68,13 @@ class SongsFragment : Fragment() {
setHasFixedSize(true)
val spans = getSpans()
if (spans != 1) {
layoutManager = GridLayoutManager(requireContext(), spans)
}
post {
// Disable fast scrolling if there is nothing to scroll
if (!canScroll()) {
// Disable fast scrolling if there is nothing to scroll
binding.songFastScroll.visibility = View.GONE
binding.songFastScrollThumb.visibility = View.GONE
}

View file

@ -62,8 +62,8 @@ class ActionMenu(
}
inflate(menuRes)
setOnMenuItemClickListener {
onMenuClick(it.itemId)
setOnMenuItemClickListener { item ->
onMenuClick(item.itemId)
true
}
}

View file

@ -196,8 +196,7 @@ fun RecyclerView.canScroll() = computeVerticalScrollRange() > height
* @return True if we are in the irregular landscape mode, false if not.
*/
fun Activity.isIrregularLandscape(): Boolean {
return isLandscape(resources) &&
!isSystemBarOnBottom(this)
return isLandscape(resources) && !isSystemBarOnBottom(this)
}
/**

View file

@ -64,8 +64,8 @@ class SlideLinearLayout @JvmOverloads constructor(
// I dont even know what this does.
var consumed = false
children.forEach {
consumed = consumed or super.drawChild(canvas, it, drawingTime)
children.forEach { view ->
consumed = consumed or super.drawChild(canvas, view, drawingTime)
}
return consumed

View file

@ -1,5 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Animated icons derived from noice https://github.com/ashutoshgngwr/noice/ -->
<?xml version="1.0" encoding="utf-8"?><!-- Animated icons derived from noice https://github.com/ashutoshgngwr/noice/ -->
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:aapt="http://schemas.android.com/aapt"
android:drawable="@drawable/ic_pause_large">

View file

@ -132,9 +132,9 @@
android:id="@+id/playback_duration_current"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{playbackModel.formattedPosition}"
android:layout_marginStart="@dimen/margin_mid_huge"
android:layout_marginBottom="@dimen/margin_medium"
android:text="@{playbackModel.formattedPosition}"
app:layout_constraintBottom_toTopOf="@+id/playback_play_pause"
app:layout_constraintStart_toStartOf="parent"
tools:text="11:38" />