From c342fb364bc872c8dc58e740b776107acf3d1c74 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Sat, 10 Sep 2022 19:36:59 -0600 Subject: [PATCH] all: merge display and playback modes Merge DisplayMode and PlaybackMode into a new class called MusicMode. Both of these datatypes represented similar things, and thus it's much easier to make them the same datatype. Moreover, it makes the forthcoming addition of the music selector much easier if the same datatype was tied to the representation of music. This commit also moves around things around the project to be slightly more coherent. --- .../main/java/org/oxycblt/auxio/AuxioApp.kt | 13 +- .../java/org/oxycblt/auxio/IntegerTable.kt | 16 +-- .../java/org/oxycblt/auxio/MainActivity.kt | 2 - .../java/org/oxycblt/auxio/MainFragment.kt | 2 +- .../auxio/detail/AlbumDetailFragment.kt | 2 +- .../auxio/detail/ArtistDetailFragment.kt | 2 +- .../oxycblt/auxio/detail/DetailViewModel.kt | 2 +- .../auxio/detail/GenreDetailFragment.kt | 2 +- .../org/oxycblt/auxio/home/HomeFragment.kt | 30 ++--- .../org/oxycblt/auxio/home/HomeViewModel.kt | 32 ++--- .../auxio/home/list/AlbumListFragment.kt | 6 +- .../auxio/home/list/ArtistListFragment.kt | 6 +- .../auxio/home/list/GenreListFragment.kt | 6 +- .../auxio/home/list/SongListFragment.kt | 6 +- .../java/org/oxycblt/auxio/home/tabs/Tab.kt | 20 +-- .../org/oxycblt/auxio/home/tabs/TabAdapter.kt | 4 +- .../auxio/home/tabs/TabCustomizeDialog.kt | 9 +- .../org/oxycblt/auxio/image/BitmapProvider.kt | 1 + .../org/oxycblt/auxio/image/IndicatorView.kt | 28 ++--- .../oxycblt/auxio/image/StyledImageView.kt | 1 + .../image/{ => extractor}/BaseFetcher.kt | 2 +- .../auxio/image/{ => extractor}/Components.kt | 4 +- .../CrossfadeTransitionFactory.kt | 2 +- .../{ => extractor}/SquareFrameTransform.kt | 2 +- .../java/org/oxycblt/auxio/music/Music.kt | 10 +- .../java/org/oxycblt/auxio/music/MusicMode.kt | 66 ++++++++++ .../org/oxycblt/auxio/{ui => music}/Sort.kt | 10 +- .../auxio/music/extractor/CacheLayer.kt | 2 - .../auxio/music/extractor/MediaStoreLayer.kt | 4 +- .../auxio/music/extractor/MetadataLayer.kt | 3 + .../org/oxycblt/auxio/music/system/Indexer.kt | 2 +- .../music/system/IndexerNotifications.kt | 2 +- .../oxycblt/auxio/playback/PlaybackMode.kt | 53 -------- .../auxio/playback/PlaybackPanelFragment.kt | 1 + .../auxio/playback/PlaybackViewModel.kt | 11 +- .../{ => ui}/AnimatedMaterialButton.kt | 2 +- .../playback/{ => ui}/ForcedLTRFrameLayout.kt | 2 +- .../{ => ui}/PlaybackSheetBehavior.kt | 2 +- .../auxio/playback/{ => ui}/StyledSeekBar.kt | 4 +- .../oxycblt/auxio/search/SearchFragment.kt | 11 +- .../oxycblt/auxio/search/SearchViewModel.kt | 22 ++-- .../org/oxycblt/auxio/settings/Settings.kt | 119 ++++++++++++------ .../java/org/oxycblt/auxio/ui/DisplayMode.kt | 87 ------------- .../oxycblt/auxio/widgets/WidgetComponent.kt | 2 +- .../layout-h480dp/fragment_playback_panel.xml | 8 +- .../fragment_playback_panel.xml | 8 +- .../res/layout-w600dp-land/fragment_main.xml | 2 +- app/src/main/res/layout/fragment_main.xml | 2 +- .../main/res/layout/fragment_playback_bar.xml | 8 +- .../res/layout/fragment_playback_panel.xml | 8 +- app/src/main/res/values/settings.xml | 12 +- info/ARCHITECTURE.md | 14 +-- 52 files changed, 322 insertions(+), 355 deletions(-) rename app/src/main/java/org/oxycblt/auxio/image/{ => extractor}/BaseFetcher.kt (99%) rename app/src/main/java/org/oxycblt/auxio/image/{ => extractor}/Components.kt (98%) rename app/src/main/java/org/oxycblt/auxio/image/{ => extractor}/CrossfadeTransitionFactory.kt (97%) rename app/src/main/java/org/oxycblt/auxio/image/{ => extractor}/SquareFrameTransform.kt (97%) create mode 100644 app/src/main/java/org/oxycblt/auxio/music/MusicMode.kt rename app/src/main/java/org/oxycblt/auxio/{ui => music}/Sort.kt (98%) delete mode 100644 app/src/main/java/org/oxycblt/auxio/playback/PlaybackMode.kt rename app/src/main/java/org/oxycblt/auxio/playback/{ => ui}/AnimatedMaterialButton.kt (98%) rename app/src/main/java/org/oxycblt/auxio/playback/{ => ui}/ForcedLTRFrameLayout.kt (97%) rename app/src/main/java/org/oxycblt/auxio/playback/{ => ui}/PlaybackSheetBehavior.kt (98%) rename app/src/main/java/org/oxycblt/auxio/playback/{ => ui}/StyledSeekBar.kt (97%) delete mode 100644 app/src/main/java/org/oxycblt/auxio/ui/DisplayMode.kt diff --git a/app/src/main/java/org/oxycblt/auxio/AuxioApp.kt b/app/src/main/java/org/oxycblt/auxio/AuxioApp.kt index b1d028463..c1fb348e8 100644 --- a/app/src/main/java/org/oxycblt/auxio/AuxioApp.kt +++ b/app/src/main/java/org/oxycblt/auxio/AuxioApp.kt @@ -25,16 +25,19 @@ import androidx.core.graphics.drawable.IconCompat import coil.ImageLoader import coil.ImageLoaderFactory import coil.request.CachePolicy -import org.oxycblt.auxio.image.AlbumCoverFetcher -import org.oxycblt.auxio.image.ArtistImageFetcher -import org.oxycblt.auxio.image.CrossfadeTransitionFactory -import org.oxycblt.auxio.image.GenreImageFetcher -import org.oxycblt.auxio.image.MusicKeyer +import org.oxycblt.auxio.image.extractor.AlbumCoverFetcher +import org.oxycblt.auxio.image.extractor.ArtistImageFetcher +import org.oxycblt.auxio.image.extractor.CrossfadeTransitionFactory +import org.oxycblt.auxio.image.extractor.GenreImageFetcher +import org.oxycblt.auxio.image.extractor.MusicKeyer +import org.oxycblt.auxio.settings.Settings class AuxioApp : Application(), ImageLoaderFactory { override fun onCreate() { super.onCreate() + Settings(this).migrate() + // Adding static shortcuts in a dynamic manner is better than declaring them // manually, as it will properly handle the difference between debug and release // Auxio instances. diff --git a/app/src/main/java/org/oxycblt/auxio/IntegerTable.kt b/app/src/main/java/org/oxycblt/auxio/IntegerTable.kt index 914ffbef8..6b13018e5 100644 --- a/app/src/main/java/org/oxycblt/auxio/IntegerTable.kt +++ b/app/src/main/java/org/oxycblt/auxio/IntegerTable.kt @@ -90,17 +90,17 @@ object IntegerTable { /** DisplayMode.NONE (No Longer used but still reserved) */ // const val DISPLAY_MODE_NONE = 0xA107 - /** DisplayMode.SHOW_GENRES */ - const val DISPLAY_MODE_SHOW_GENRES = 0xA108 + /** MusicMode._GENRES */ + const val MUSIC_MODE_GENRES = 0xA108 - /** DisplayMode.SHOW_ARTISTS */ - const val DISPLAY_MODE_SHOW_ARTISTS = 0xA109 + /** MusicMode._ARTISTS */ + const val MUSIC_MODE_ARTISTS = 0xA109 - /** DisplayMode.SHOW_ALBUMS */ - const val DISPLAY_MODE_SHOW_ALBUMS = 0xA10A + /** MusicMode._ALBUMS */ + const val MUSIC_MODE_ALBUMS = 0xA10A - /** DisplayMode.SHOW_SONGS */ - const val DISPLAY_MODE_SHOW_SONGS = 0xA10B + /** MusicMode._SONGS */ + const val MUSIC_MODE_SONGS = 0xA10B // Note: Sort integer codes are non-contiguous due to significant amounts of time // passing between the additions of new sort modes. diff --git a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt index 7549e4722..b35b28869 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainActivity.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainActivity.kt @@ -45,8 +45,6 @@ import org.oxycblt.auxio.util.systemBarInsetsCompat * * TODO: Add multi-select * - * TODO: Remove asterisk imports - * * @author OxygenCobalt */ class MainActivity : AppCompatActivity() { diff --git a/app/src/main/java/org/oxycblt/auxio/MainFragment.kt b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt index d9137f893..def7306ee 100644 --- a/app/src/main/java/org/oxycblt/auxio/MainFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/MainFragment.kt @@ -34,9 +34,9 @@ import com.google.android.material.transition.MaterialFadeThrough import org.oxycblt.auxio.databinding.FragmentMainBinding import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.playback.PlaybackSheetBehavior import org.oxycblt.auxio.playback.PlaybackViewModel import org.oxycblt.auxio.playback.queue.QueueSheetBehavior +import org.oxycblt.auxio.playback.ui.PlaybackSheetBehavior import org.oxycblt.auxio.ui.MainNavigationAction import org.oxycblt.auxio.ui.NavigationViewModel import org.oxycblt.auxio.ui.fragment.ViewBindingFragment diff --git a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt index 9dad5ccf9..7e4754e97 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/AlbumDetailFragment.kt @@ -37,8 +37,8 @@ import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.music.Sort import org.oxycblt.auxio.settings.Settings -import org.oxycblt.auxio.ui.Sort import org.oxycblt.auxio.ui.fragment.MenuFragment import org.oxycblt.auxio.ui.recycler.Item import org.oxycblt.auxio.util.canScroll diff --git a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt index 0514fe3b1..c2ba91fe4 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/ArtistDetailFragment.kt @@ -35,8 +35,8 @@ import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.music.Sort import org.oxycblt.auxio.settings.Settings -import org.oxycblt.auxio.ui.Sort import org.oxycblt.auxio.ui.fragment.MenuFragment import org.oxycblt.auxio.ui.recycler.Item import org.oxycblt.auxio.util.collect diff --git a/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt b/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt index 1196c02ad..907899caf 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/DetailViewModel.kt @@ -38,8 +38,8 @@ import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.ReleaseType import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.music.Sort import org.oxycblt.auxio.settings.Settings -import org.oxycblt.auxio.ui.Sort import org.oxycblt.auxio.ui.recycler.Header import org.oxycblt.auxio.ui.recycler.Item import org.oxycblt.auxio.util.application diff --git a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt index f086aac08..13cad1809 100644 --- a/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/detail/GenreDetailFragment.kt @@ -36,8 +36,8 @@ import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.music.Sort import org.oxycblt.auxio.settings.Settings -import org.oxycblt.auxio.ui.Sort import org.oxycblt.auxio.ui.fragment.MenuFragment import org.oxycblt.auxio.ui.recycler.Item import org.oxycblt.auxio.util.collect diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt index a2f7bd10c..dd68dd14f 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeFragment.kt @@ -47,14 +47,14 @@ 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.MusicViewModel import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.music.Sort import org.oxycblt.auxio.music.system.Indexer import org.oxycblt.auxio.playback.PlaybackViewModel -import org.oxycblt.auxio.ui.DisplayMode import org.oxycblt.auxio.ui.MainNavigationAction import org.oxycblt.auxio.ui.NavigationViewModel -import org.oxycblt.auxio.ui.Sort import org.oxycblt.auxio.ui.fragment.ViewBindingFragment import org.oxycblt.auxio.util.androidActivityViewModels import org.oxycblt.auxio.util.collect @@ -198,7 +198,7 @@ class HomeFragment : ViewBindingFragment(), Toolbar.OnMenuI item.isChecked = !item.isChecked homeModel.updateCurrentSort( homeModel - .getSortForDisplay(homeModel.currentTab.value) + .getSortForTab(homeModel.currentTab.value) .withAscending(item.isChecked) ) } @@ -207,7 +207,7 @@ class HomeFragment : ViewBindingFragment(), Toolbar.OnMenuI item.isChecked = true homeModel.updateCurrentSort( homeModel - .getSortForDisplay(homeModel.currentTab.value) + .getSortForTab(homeModel.currentTab.value) .withMode(requireNotNull(Sort.Mode.fromItemId(item.itemId))) ) } @@ -216,20 +216,20 @@ class HomeFragment : ViewBindingFragment(), Toolbar.OnMenuI return true } - private fun updateCurrentTab(tab: DisplayMode) { + private fun updateCurrentTab(tab: MusicMode) { // Make sure that we update the scrolling view and allowed menu items whenever // the tab changes. val binding = requireBinding() when (tab) { - DisplayMode.SHOW_SONGS -> { + MusicMode.SONGS -> { updateSortMenu(tab) { id -> id != R.id.option_sort_count } binding.homeAppbar.liftOnScrollTargetViewId = R.id.home_song_list } - DisplayMode.SHOW_ALBUMS -> { + MusicMode.ALBUMS -> { updateSortMenu(tab) { id -> id != R.id.option_sort_album } binding.homeAppbar.liftOnScrollTargetViewId = R.id.home_album_list } - DisplayMode.SHOW_ARTISTS -> { + MusicMode.ARTISTS -> { updateSortMenu(tab) { id -> id == R.id.option_sort_asc || id == R.id.option_sort_name || @@ -238,7 +238,7 @@ class HomeFragment : ViewBindingFragment(), Toolbar.OnMenuI } binding.homeAppbar.liftOnScrollTargetViewId = R.id.home_artist_list } - DisplayMode.SHOW_GENRES -> { + MusicMode.GENRES -> { updateSortMenu(tab) { id -> id == R.id.option_sort_asc || id == R.id.option_sort_name || @@ -250,9 +250,9 @@ class HomeFragment : ViewBindingFragment(), Toolbar.OnMenuI } } - private fun updateSortMenu(displayMode: DisplayMode, isVisible: (Int) -> Boolean) { + private fun updateSortMenu(mode: MusicMode, isVisible: (Int) -> Boolean) { val sortMenu = requireNotNull(sortItem.subMenu) - val toHighlight = homeModel.getSortForDisplay(displayMode) + val toHighlight = homeModel.getSortForTab(mode) for (option in sortMenu) { if (option.itemId == toHighlight.mode.itemId) { @@ -434,10 +434,10 @@ class HomeFragment : ViewBindingFragment(), Toolbar.OnMenuI override fun createFragment(position: Int): Fragment { return when (homeModel.tabs[position]) { - DisplayMode.SHOW_SONGS -> SongListFragment() - DisplayMode.SHOW_ALBUMS -> AlbumListFragment() - DisplayMode.SHOW_ARTISTS -> ArtistListFragment() - DisplayMode.SHOW_GENRES -> GenreListFragment() + MusicMode.SONGS -> SongListFragment() + MusicMode.ALBUMS -> AlbumListFragment() + MusicMode.ARTISTS -> ArtistListFragment() + MusicMode.GENRES -> GenreListFragment() } } } diff --git a/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt index 5d3154333..9238af08f 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt @@ -26,11 +26,11 @@ import org.oxycblt.auxio.home.tabs.Tab 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.MusicStore import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.music.Sort import org.oxycblt.auxio.settings.Settings -import org.oxycblt.auxio.ui.DisplayMode -import org.oxycblt.auxio.ui.Sort import org.oxycblt.auxio.util.application import org.oxycblt.auxio.util.logD @@ -59,15 +59,15 @@ class HomeViewModel(application: Application) : val genres: StateFlow> get() = _genres - var tabs: List = visibleTabs + var tabs: List = visibleTabs private set /** Internal getter for getting the visible library tabs */ - private val visibleTabs: List + private val visibleTabs: List get() = settings.libTabs.filterIsInstance().map { it.mode } private val _currentTab = MutableStateFlow(tabs[0]) - val currentTab: StateFlow = _currentTab + val currentTab: StateFlow = _currentTab /** * Marker to recreate all library tabs, usually initiated by a settings change. When this flag @@ -93,32 +93,32 @@ class HomeViewModel(application: Application) : _shouldRecreateTabs.value = false } - /** Get the specific sort for the given [DisplayMode]. */ - fun getSortForDisplay(displayMode: DisplayMode) = - when (displayMode) { - DisplayMode.SHOW_SONGS -> settings.libSongSort - DisplayMode.SHOW_ALBUMS -> settings.libAlbumSort - DisplayMode.SHOW_ARTISTS -> settings.libArtistSort - DisplayMode.SHOW_GENRES -> settings.libGenreSort + /** Get the specific sort for the given [MusicMode]. */ + fun getSortForTab(tabMode: MusicMode): Sort = + when (tabMode) { + MusicMode.SONGS -> settings.libSongSort + MusicMode.ALBUMS -> settings.libAlbumSort + MusicMode.ARTISTS -> settings.libArtistSort + MusicMode.GENRES -> settings.libGenreSort } /** Update the currently displayed item's [Sort]. */ fun updateCurrentSort(sort: Sort) { logD("Updating ${_currentTab.value} sort to $sort") when (_currentTab.value) { - DisplayMode.SHOW_SONGS -> { + MusicMode.SONGS -> { settings.libSongSort = sort _songs.value = sort.songs(_songs.value) } - DisplayMode.SHOW_ALBUMS -> { + MusicMode.ALBUMS -> { settings.libAlbumSort = sort _albums.value = sort.albums(_albums.value) } - DisplayMode.SHOW_ARTISTS -> { + MusicMode.ARTISTS -> { settings.libArtistSort = sort _artists.value = sort.artists(_artists.value) } - DisplayMode.SHOW_GENRES -> { + MusicMode.GENRES -> { settings.libGenreSort = sort _genres.value = sort.genres(_genres.value) } diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt index c3c0a6a6a..3ff5a0058 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/AlbumListFragment.kt @@ -24,11 +24,11 @@ import android.view.ViewGroup import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentHomeListBinding import org.oxycblt.auxio.music.Album +import org.oxycblt.auxio.music.MusicMode import org.oxycblt.auxio.music.MusicParent +import org.oxycblt.auxio.music.Sort import org.oxycblt.auxio.music.formatDurationMs import org.oxycblt.auxio.music.secsToMs -import org.oxycblt.auxio.ui.DisplayMode -import org.oxycblt.auxio.ui.Sort import org.oxycblt.auxio.ui.recycler.AlbumViewHolder import org.oxycblt.auxio.ui.recycler.IndicatorAdapter import org.oxycblt.auxio.ui.recycler.Item @@ -62,7 +62,7 @@ class AlbumListFragment : HomeListFragment() { val album = homeModel.albums.value[pos] // Change how we display the popup depending on the mode. - return when (homeModel.getSortForDisplay(DisplayMode.SHOW_ALBUMS).mode) { + return when (homeModel.getSortForTab(MusicMode.ALBUMS).mode) { // By Name -> Use Name is Sort.Mode.ByName -> album.collationKey?.run { sourceString.first().uppercase() } diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt index b7cef8180..ec77ca008 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/ArtistListFragment.kt @@ -23,10 +23,10 @@ import android.view.ViewGroup import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentHomeListBinding import org.oxycblt.auxio.music.Artist +import org.oxycblt.auxio.music.MusicMode import org.oxycblt.auxio.music.MusicParent +import org.oxycblt.auxio.music.Sort import org.oxycblt.auxio.music.formatDurationMs -import org.oxycblt.auxio.ui.DisplayMode -import org.oxycblt.auxio.ui.Sort import org.oxycblt.auxio.ui.recycler.ArtistViewHolder import org.oxycblt.auxio.ui.recycler.IndicatorAdapter import org.oxycblt.auxio.ui.recycler.Item @@ -57,7 +57,7 @@ class ArtistListFragment : HomeListFragment() { val artist = homeModel.artists.value[pos] // Change how we display the popup depending on the mode. - return when (homeModel.getSortForDisplay(DisplayMode.SHOW_ARTISTS).mode) { + return when (homeModel.getSortForTab(MusicMode.ARTISTS).mode) { // By Name -> Use Name is Sort.Mode.ByName -> artist.collationKey?.run { sourceString.first().uppercase() } diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt index 73d1d0c04..f64b19204 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/GenreListFragment.kt @@ -23,10 +23,10 @@ import android.view.ViewGroup import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentHomeListBinding import org.oxycblt.auxio.music.Genre +import org.oxycblt.auxio.music.MusicMode import org.oxycblt.auxio.music.MusicParent +import org.oxycblt.auxio.music.Sort import org.oxycblt.auxio.music.formatDurationMs -import org.oxycblt.auxio.ui.DisplayMode -import org.oxycblt.auxio.ui.Sort import org.oxycblt.auxio.ui.recycler.GenreViewHolder import org.oxycblt.auxio.ui.recycler.IndicatorAdapter import org.oxycblt.auxio.ui.recycler.Item @@ -57,7 +57,7 @@ class GenreListFragment : HomeListFragment() { val genre = homeModel.genres.value[pos] // Change how we display the popup depending on the mode. - return when (homeModel.getSortForDisplay(DisplayMode.SHOW_GENRES).mode) { + return when (homeModel.getSortForTab(MusicMode.GENRES).mode) { // By Name -> Use Name is Sort.Mode.ByName -> genre.collationKey?.run { sourceString.first().uppercase() } diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt b/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt index 845592583..90a14cbaa 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/list/SongListFragment.kt @@ -23,13 +23,13 @@ import android.view.View import android.view.ViewGroup import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentHomeListBinding +import org.oxycblt.auxio.music.MusicMode import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.music.Sort import org.oxycblt.auxio.music.formatDurationMs import org.oxycblt.auxio.music.secsToMs import org.oxycblt.auxio.settings.Settings -import org.oxycblt.auxio.ui.DisplayMode -import org.oxycblt.auxio.ui.Sort import org.oxycblt.auxio.ui.recycler.IndicatorAdapter import org.oxycblt.auxio.ui.recycler.Item import org.oxycblt.auxio.ui.recycler.MenuItemListener @@ -72,7 +72,7 @@ class SongListFragment : HomeListFragment() { // Change how we display the popup depending on the mode. // Note: We don't use the more correct individual artist name here, as sorts are largely // based off the names of the parent objects and not the child objects. - return when (homeModel.getSortForDisplay(DisplayMode.SHOW_SONGS).mode) { + return when (homeModel.getSortForTab(MusicMode.SONGS).mode) { // Name -> Use name is Sort.Mode.ByName -> song.collationKey?.run { sourceString.first().uppercase() } diff --git a/app/src/main/java/org/oxycblt/auxio/home/tabs/Tab.kt b/app/src/main/java/org/oxycblt/auxio/home/tabs/Tab.kt index c63cb77f2..e0726e3ff 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/tabs/Tab.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/tabs/Tab.kt @@ -21,7 +21,7 @@ import org.oxycblt.auxio.home.tabs.Tab.Companion.fromSequence import org.oxycblt.auxio.home.tabs.Tab.Companion.toSequence import org.oxycblt.auxio.home.tabs.Tab.Invisible import org.oxycblt.auxio.home.tabs.Tab.Visible -import org.oxycblt.auxio.ui.DisplayMode +import org.oxycblt.auxio.music.MusicMode import org.oxycblt.auxio.util.logE /** @@ -40,16 +40,16 @@ import org.oxycblt.auxio.util.logE * VTTT * * Where V is a bit representing the visibility and T is a 3-bit integer representing the - * [DisplayMode] ordinal for this tab. + * [MusicMode] ordinal for this tab. * * To serialize and deserialize a tab sequence, [toSequence] and [fromSequence] can be used * respectively. * * By default, the tab order will be SONGS, ALBUMS, ARTISTS, GENRES, PLAYLISTS */ -sealed class Tab(open val mode: DisplayMode) { - data class Visible(override val mode: DisplayMode) : Tab(mode) - data class Invisible(override val mode: DisplayMode) : Tab(mode) +sealed class Tab(open val mode: MusicMode) { + data class Visible(override val mode: MusicMode) : Tab(mode) + data class Invisible(override val mode: MusicMode) : Tab(mode) companion object { /** The length a well-formed tab sequence should be */ @@ -59,14 +59,14 @@ sealed class Tab(open val mode: DisplayMode) { const val SEQUENCE_DEFAULT = 0b1000_1001_1010_1011_0100 /** - * Maps between the integer code in the tab sequence and the actual [DisplayMode] instance. + * Maps between the integer code in the tab sequence and the actual [MusicMode] instance. */ private val MODE_TABLE = arrayOf( - DisplayMode.SHOW_SONGS, - DisplayMode.SHOW_ALBUMS, - DisplayMode.SHOW_ARTISTS, - DisplayMode.SHOW_GENRES + MusicMode.SONGS, + MusicMode.ALBUMS, + MusicMode.ARTISTS, + MusicMode.GENRES ) /** Convert an array [tabs] into a sequence of tabs. */ diff --git a/app/src/main/java/org/oxycblt/auxio/home/tabs/TabAdapter.kt b/app/src/main/java/org/oxycblt/auxio/home/tabs/TabAdapter.kt index 7ab2c9df0..35285905b 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/tabs/TabAdapter.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/tabs/TabAdapter.kt @@ -23,7 +23,7 @@ import android.view.View import android.view.ViewGroup import androidx.recyclerview.widget.RecyclerView import org.oxycblt.auxio.databinding.ItemTabBinding -import org.oxycblt.auxio.ui.DisplayMode +import org.oxycblt.auxio.music.MusicMode import org.oxycblt.auxio.ui.recycler.DialogViewHolder import org.oxycblt.auxio.util.inflater @@ -59,7 +59,7 @@ class TabAdapter(private val listener: Listener) : RecyclerView.Adapter(), TabAd binding.tabRecycler.adapter = null } - override fun onVisibilityToggled(displayMode: DisplayMode) { - // Tab viewholders bind with the initial tab state, which will drift from the actual - // state of the tabs over editing. So, this callback simply provides the displayMode - // for us to locate within the data and then update. - val index = tabAdapter.tabs.indexOfFirst { it.mode == displayMode } + override fun onVisibilityToggled(mode: MusicMode) { + val index = tabAdapter.tabs.indexOfFirst { it.mode == mode } if (index > -1) { val tab = tabAdapter.tabs[index] tabAdapter.setTab( diff --git a/app/src/main/java/org/oxycblt/auxio/image/BitmapProvider.kt b/app/src/main/java/org/oxycblt/auxio/image/BitmapProvider.kt index 330c423df..93faa7fcd 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/BitmapProvider.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/BitmapProvider.kt @@ -24,6 +24,7 @@ import coil.imageLoader import coil.request.Disposable import coil.request.ImageRequest import coil.size.Size +import org.oxycblt.auxio.image.extractor.SquareFrameTransform import org.oxycblt.auxio.music.Song /** diff --git a/app/src/main/java/org/oxycblt/auxio/image/IndicatorView.kt b/app/src/main/java/org/oxycblt/auxio/image/IndicatorView.kt index 5a980cfaf..e86a30ad1 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/IndicatorView.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/IndicatorView.kt @@ -66,6 +66,18 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr } } + var isPlaying: Boolean + get() = drawable == playingIndicatorDrawable + set(value) { + if (value) { + playingIndicatorDrawable.start() + setImageDrawable(playingIndicatorDrawable) + } else { + playingIndicatorDrawable.stop() + setImageDrawable(pausedIndicatorDrawable) + } + } + init { // Use clipToOutline and a background drawable to crop images. While Coil's transformation // could theoretically be used to round corners, the corner radius is dependent on the @@ -87,15 +99,13 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { super.onMeasure(widthMeasureSpec, heightMeasureSpec) + // Emulate StyledDrawable scaling with matrix scaling. val iconSize = max(measuredWidth, measuredHeight) / 2 imageMatrix = indicatorMatrix.apply { reset() drawable?.let { drawable -> - // Android is too good to allow us to set a fixed image size, so we instead need - // to define a matrix to scale an image directly. - // First scale the icon up to the desired size. indicatorMatrixSrc.set( 0f, @@ -119,16 +129,4 @@ constructor(context: Context, attrs: AttributeSet? = null, @AttrRes defStyleAttr } } } - - var isPlaying: Boolean - get() = drawable == playingIndicatorDrawable - set(value) { - if (value) { - playingIndicatorDrawable.start() - setImageDrawable(playingIndicatorDrawable) - } else { - playingIndicatorDrawable.stop() - setImageDrawable(pausedIndicatorDrawable) - } - } } diff --git a/app/src/main/java/org/oxycblt/auxio/image/StyledImageView.kt b/app/src/main/java/org/oxycblt/auxio/image/StyledImageView.kt index 213117291..90fab0acd 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/StyledImageView.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/StyledImageView.kt @@ -33,6 +33,7 @@ import coil.dispose import coil.load import com.google.android.material.shape.MaterialShapeDrawable import org.oxycblt.auxio.R +import org.oxycblt.auxio.image.extractor.SquareFrameTransform import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre diff --git a/app/src/main/java/org/oxycblt/auxio/image/BaseFetcher.kt b/app/src/main/java/org/oxycblt/auxio/image/extractor/BaseFetcher.kt similarity index 99% rename from app/src/main/java/org/oxycblt/auxio/image/BaseFetcher.kt rename to app/src/main/java/org/oxycblt/auxio/image/extractor/BaseFetcher.kt index 7e554ecae..921b11820 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/BaseFetcher.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/extractor/BaseFetcher.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.image +package org.oxycblt.auxio.image.extractor import android.content.Context import android.graphics.Bitmap diff --git a/app/src/main/java/org/oxycblt/auxio/image/Components.kt b/app/src/main/java/org/oxycblt/auxio/image/extractor/Components.kt similarity index 98% rename from app/src/main/java/org/oxycblt/auxio/image/Components.kt rename to app/src/main/java/org/oxycblt/auxio/image/extractor/Components.kt index df7d8e265..c7ba9fddb 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/Components.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/extractor/Components.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.image +package org.oxycblt.auxio.image.extractor import android.content.Context import coil.ImageLoader @@ -34,7 +34,7 @@ import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.Music import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.ui.Sort +import org.oxycblt.auxio.music.Sort import kotlin.math.min /** A basic keyer for music data. */ diff --git a/app/src/main/java/org/oxycblt/auxio/image/CrossfadeTransitionFactory.kt b/app/src/main/java/org/oxycblt/auxio/image/extractor/CrossfadeTransitionFactory.kt similarity index 97% rename from app/src/main/java/org/oxycblt/auxio/image/CrossfadeTransitionFactory.kt rename to app/src/main/java/org/oxycblt/auxio/image/extractor/CrossfadeTransitionFactory.kt index 7d15697d6..6d364a1bd 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/CrossfadeTransitionFactory.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/extractor/CrossfadeTransitionFactory.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.image +package org.oxycblt.auxio.image.extractor import coil.decode.DataSource import coil.drawable.CrossfadeDrawable diff --git a/app/src/main/java/org/oxycblt/auxio/image/SquareFrameTransform.kt b/app/src/main/java/org/oxycblt/auxio/image/extractor/SquareFrameTransform.kt similarity index 97% rename from app/src/main/java/org/oxycblt/auxio/image/SquareFrameTransform.kt rename to app/src/main/java/org/oxycblt/auxio/image/extractor/SquareFrameTransform.kt index f81fd962f..69ad651c0 100644 --- a/app/src/main/java/org/oxycblt/auxio/image/SquareFrameTransform.kt +++ b/app/src/main/java/org/oxycblt/auxio/image/extractor/SquareFrameTransform.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.image +package org.oxycblt.auxio.image.extractor import android.graphics.Bitmap import coil.size.Size diff --git a/app/src/main/java/org/oxycblt/auxio/music/Music.kt b/app/src/main/java/org/oxycblt/auxio/music/Music.kt index 79c7918ce..b649cc3cc 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/Music.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/Music.kt @@ -26,7 +26,6 @@ import kotlinx.parcelize.Parcelize import org.oxycblt.auxio.BuildConfig import org.oxycblt.auxio.R import org.oxycblt.auxio.music.Date.Companion.from -import org.oxycblt.auxio.ui.Sort import org.oxycblt.auxio.ui.recycler.Item import org.oxycblt.auxio.util.inRangeOrNull import org.oxycblt.auxio.util.nonZeroOrNull @@ -59,10 +58,12 @@ sealed class Music : Item { /** * A key used by the sorting system that takes into account the sort tags of this item, - * any (english) articles that prefix the names, and collation rules. Lazily generated - * since generating a collation key is non-trivial. + * any (english) articles that prefix the names, and collation rules. */ val collationKey: CollationKey? by lazy { + // Ideally, we would generate this on creation, but this is an abstract class, which + // requires us to generate it lazily instead. + val sortName = (rawSortName ?: rawName)?.run { when { length > 5 && startsWith("the ", ignoreCase = true) -> substring(4) @@ -125,7 +126,8 @@ sealed class Music : Item { */ fun hashed(clazz: KClass<*>, updates: MessageDigest.() -> Unit): UID { // Auxio hashes consist of the MD5 hash of the non-subjective, consistent - // tags in a music item. For easier use with MusicBrainz IDs, we + // tags in a music item. For easier use with MusicBrainz IDs, we transform + // this into a UUID too. val digest = MessageDigest.getInstance("MD5") updates(digest) val uuid = digest.digest().toUuid() diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicMode.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicMode.kt new file mode 100644 index 000000000..0054ce4e6 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicMode.kt @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2022 Auxio Project + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.oxycblt.auxio.music + +import org.oxycblt.auxio.IntegerTable +import org.oxycblt.auxio.R + +enum class MusicMode { + SONGS, + ALBUMS, + ARTISTS, + GENRES; + + val string: Int + get() = + when (this) { + SONGS -> R.string.lbl_songs + ALBUMS -> R.string.lbl_albums + ARTISTS -> R.string.lbl_artists + GENRES -> R.string.lbl_genres + } + + val icon: Int + get() = + when (this) { + SONGS -> R.drawable.ic_song_24 + ALBUMS -> R.drawable.ic_album_24 + ARTISTS -> R.drawable.ic_artist_24 + GENRES -> R.drawable.ic_genre_24 + } + + val intCode: Int + get() = + when (this) { + SONGS -> IntegerTable.MUSIC_MODE_SONGS + ALBUMS -> IntegerTable.MUSIC_MODE_ALBUMS + ARTISTS -> IntegerTable.MUSIC_MODE_ARTISTS + GENRES -> IntegerTable.MUSIC_MODE_GENRES + } + + companion object { + fun fromInt(value: Int) = + when (value) { + IntegerTable.MUSIC_MODE_SONGS -> SONGS + IntegerTable.MUSIC_MODE_ALBUMS -> ALBUMS + IntegerTable.MUSIC_MODE_ARTISTS -> ARTISTS + IntegerTable.MUSIC_MODE_GENRES -> GENRES + else -> null + } + } +} diff --git a/app/src/main/java/org/oxycblt/auxio/ui/Sort.kt b/app/src/main/java/org/oxycblt/auxio/music/Sort.kt similarity index 98% rename from app/src/main/java/org/oxycblt/auxio/ui/Sort.kt rename to app/src/main/java/org/oxycblt/auxio/music/Sort.kt index 7047bc01c..35ba7c4c2 100644 --- a/app/src/main/java/org/oxycblt/auxio/ui/Sort.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/Sort.kt @@ -15,18 +15,12 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.ui +package org.oxycblt.auxio.music import androidx.annotation.IdRes import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.R -import org.oxycblt.auxio.music.Album -import org.oxycblt.auxio.music.Artist -import org.oxycblt.auxio.music.Date -import org.oxycblt.auxio.music.Genre -import org.oxycblt.auxio.music.Music -import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.ui.Sort.Mode +import org.oxycblt.auxio.music.Sort.Mode /** * Represents the sort modes used in Auxio. diff --git a/app/src/main/java/org/oxycblt/auxio/music/extractor/CacheLayer.kt b/app/src/main/java/org/oxycblt/auxio/music/extractor/CacheLayer.kt index 25bf864e0..75965476f 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/extractor/CacheLayer.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/extractor/CacheLayer.kt @@ -22,14 +22,12 @@ import org.oxycblt.auxio.music.Song /** TODO: Stub class, not implemented yet */ class CacheLayer { fun init() { - // STUB: Add cache database } /** * Write a list of newly-indexed raw songs to the database. */ fun finalize(rawSongs: List) { - // STUB: Add cache database } /** diff --git a/app/src/main/java/org/oxycblt/auxio/music/extractor/MediaStoreLayer.kt b/app/src/main/java/org/oxycblt/auxio/music/extractor/MediaStoreLayer.kt index 8c691f2a9..6e8fb70e8 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/extractor/MediaStoreLayer.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/extractor/MediaStoreLayer.kt @@ -55,7 +55,7 @@ import java.io.File * straightforward for this contract that was dropped on it's head as a baby. So instead, you have * to query for each genre, query all the songs in each genre, and then iterate through those songs * to link every song with their genre. This is not documented anywhere, and the O(mom im scared) - * algorithm you have to run to get it working single-handedly DOUBLES Auxio's loading times. At no + * algorithm you have to run to get it working single-handedly DOUBLES Auxio's query times. At no * point have the devs considered that this system is absolutely insane, and instead focused on * adding infuriat- I mean nice proprietary extensions to MediaStore for their own Google Play * Music, and of course every Google Play Music user knew how great that turned out! @@ -347,6 +347,7 @@ abstract class MediaStoreLayer(private val context: Context, private val cacheLa raw.albumArtistNames = cursor.getStringOrNull(albumArtistIndex)?.maybeParseSeparators(settings) + // Get the genre value we had to query for in initialization raw.genreNames = genreNamesMap[raw.mediaStoreId] } @@ -381,6 +382,7 @@ abstract class MediaStoreLayer(private val context: Context, private val cacheLa /** * A [MediaStoreLayer] that completes the music loading process in a way compatible from + * API 21 onwards to API 29. * @author OxygenCobalt */ class Api21MediaStoreLayer(context: Context, cacheLayer: CacheLayer) : diff --git a/app/src/main/java/org/oxycblt/auxio/music/extractor/MetadataLayer.kt b/app/src/main/java/org/oxycblt/auxio/music/extractor/MetadataLayer.kt index f40debe8c..18496b517 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/extractor/MetadataLayer.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/extractor/MetadataLayer.kt @@ -247,6 +247,9 @@ class Task(context: Context, private val settings: Settings, private val raw: So tags["TORY"]?.run { get(0).toIntOrNull() } ?: tags["TYER"]?.run { get(0).toIntOrNull() } ?: return null + // Assume that TDAT/TIME can refer to TYER or TORY depending on if TORY + // is present. + val tdat = tags["TDAT"] return if (tdat != null && tdat[0].length == 4 && tdat[0].isDigitsOnly()) { val mm = tdat[0].substring(0..1).toInt() diff --git a/app/src/main/java/org/oxycblt/auxio/music/system/Indexer.kt b/app/src/main/java/org/oxycblt/auxio/music/system/Indexer.kt index 0a03487c5..e97c28388 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/system/Indexer.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/system/Indexer.kt @@ -32,12 +32,12 @@ import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre import org.oxycblt.auxio.music.MusicStore import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.music.Sort import org.oxycblt.auxio.music.extractor.Api21MediaStoreLayer import org.oxycblt.auxio.music.extractor.Api29MediaStoreLayer import org.oxycblt.auxio.music.extractor.Api30MediaStoreLayer import org.oxycblt.auxio.music.extractor.CacheLayer import org.oxycblt.auxio.music.extractor.MetadataLayer -import org.oxycblt.auxio.ui.Sort import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.logE import org.oxycblt.auxio.util.logW diff --git a/app/src/main/java/org/oxycblt/auxio/music/system/IndexerNotifications.kt b/app/src/main/java/org/oxycblt/auxio/music/system/IndexerNotifications.kt index 368eb4547..145df5c92 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/system/IndexerNotifications.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/system/IndexerNotifications.kt @@ -64,7 +64,7 @@ class IndexingNotification(private val context: Context) : lastUpdateTime = SystemClock.elapsedRealtime() - // Only update the notification every two seconds to prevent rate-limiting. + // Only update the notification every 1.5s to prevent rate-limiting. logD("Updating state to $indexing") setContentText( context.getString(R.string.fmt_indexing, indexing.current, indexing.total) diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackMode.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackMode.kt deleted file mode 100644 index 40d0ca545..000000000 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackMode.kt +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2021 Auxio Project - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.oxycblt.auxio.playback - -import org.oxycblt.auxio.IntegerTable - -/** - * Enum that indicates how the queue should be constructed. - * @author OxygenCobalt - */ -enum class PlaybackMode { - /** Construct the queue from the genre's songs */ - ALL_SONGS, - - /** Construct the queue from the artist's songs */ - IN_ALBUM, - - /** Construct the queue from the album's songs */ - IN_ARTIST, - - /** Construct the queue from all songs */ - IN_GENRE; - - companion object { - /** - * Get a [PlaybackMode] for an int [constant] - * @return The mode, null if there isn't one for this. - */ - fun fromInt(constant: Int) = - when (constant) { - IntegerTable.PLAYBACK_MODE_ALL_SONGS -> ALL_SONGS - IntegerTable.PLAYBACK_MODE_IN_ALBUM -> IN_ALBUM - IntegerTable.PLAYBACK_MODE_IN_ARTIST -> IN_ARTIST - IntegerTable.PLAYBACK_MODE_IN_GENRE -> IN_GENRE - else -> null - } - } -} diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt index 54f75c23b..c1cfd7ed8 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackPanelFragment.kt @@ -33,6 +33,7 @@ import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.music.msToDs import org.oxycblt.auxio.playback.state.RepeatMode +import org.oxycblt.auxio.playback.ui.StyledSeekBar import org.oxycblt.auxio.ui.MainNavigationAction import org.oxycblt.auxio.ui.fragment.MenuFragment import org.oxycblt.auxio.util.collectImmediately diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt index 4fb2888db..9e1d4f26f 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/PlaybackViewModel.kt @@ -28,6 +28,7 @@ import kotlinx.coroutines.launch 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.Song import org.oxycblt.auxio.music.dsToMs @@ -92,15 +93,15 @@ class PlaybackViewModel(application: Application) : // --- PLAYING FUNCTIONS --- /** Play a [song] with the [mode] specified, */ - fun play(song: Song, mode: PlaybackMode) { + fun play(song: Song, mode: MusicMode) { // TODO: Remove this function when selection is implemented val parent = when (mode) { - PlaybackMode.IN_ALBUM -> song.album - PlaybackMode.IN_ARTIST -> song.album.artist - PlaybackMode.IN_GENRE -> song.genres.maxBy { it.songs.size } - PlaybackMode.ALL_SONGS -> null + MusicMode.GENRES -> song.album + MusicMode.ARTISTS -> song.album.artist + MusicMode.ALBUMS -> song.genres.maxBy { it.songs.size } + MusicMode.SONGS -> null } playbackManager.play(song, parent, settings) diff --git a/app/src/main/java/org/oxycblt/auxio/playback/AnimatedMaterialButton.kt b/app/src/main/java/org/oxycblt/auxio/playback/ui/AnimatedMaterialButton.kt similarity index 98% rename from app/src/main/java/org/oxycblt/auxio/playback/AnimatedMaterialButton.kt rename to app/src/main/java/org/oxycblt/auxio/playback/ui/AnimatedMaterialButton.kt index 4531084ee..2ab20dbdd 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/AnimatedMaterialButton.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/ui/AnimatedMaterialButton.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.playback +package org.oxycblt.auxio.playback.ui import android.animation.ValueAnimator import android.content.Context diff --git a/app/src/main/java/org/oxycblt/auxio/playback/ForcedLTRFrameLayout.kt b/app/src/main/java/org/oxycblt/auxio/playback/ui/ForcedLTRFrameLayout.kt similarity index 97% rename from app/src/main/java/org/oxycblt/auxio/playback/ForcedLTRFrameLayout.kt rename to app/src/main/java/org/oxycblt/auxio/playback/ui/ForcedLTRFrameLayout.kt index 4cc33e656..9fb05e94c 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/ForcedLTRFrameLayout.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/ui/ForcedLTRFrameLayout.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.playback +package org.oxycblt.auxio.playback.ui import android.content.Context import android.util.AttributeSet diff --git a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackSheetBehavior.kt b/app/src/main/java/org/oxycblt/auxio/playback/ui/PlaybackSheetBehavior.kt similarity index 98% rename from app/src/main/java/org/oxycblt/auxio/playback/PlaybackSheetBehavior.kt rename to app/src/main/java/org/oxycblt/auxio/playback/ui/PlaybackSheetBehavior.kt index 04547a86b..de8dec70b 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/PlaybackSheetBehavior.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/ui/PlaybackSheetBehavior.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.playback +package org.oxycblt.auxio.playback.ui import android.content.Context import android.graphics.drawable.LayerDrawable diff --git a/app/src/main/java/org/oxycblt/auxio/playback/StyledSeekBar.kt b/app/src/main/java/org/oxycblt/auxio/playback/ui/StyledSeekBar.kt similarity index 97% rename from app/src/main/java/org/oxycblt/auxio/playback/StyledSeekBar.kt rename to app/src/main/java/org/oxycblt/auxio/playback/ui/StyledSeekBar.kt index 91f88ebd4..106c870f7 100644 --- a/app/src/main/java/org/oxycblt/auxio/playback/StyledSeekBar.kt +++ b/app/src/main/java/org/oxycblt/auxio/playback/ui/StyledSeekBar.kt @@ -15,7 +15,7 @@ * along with this program. If not, see . */ -package org.oxycblt.auxio.playback +package org.oxycblt.auxio.playback.ui import android.content.Context import android.util.AttributeSet @@ -67,7 +67,7 @@ constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 // this component. val from = max(value, 0) - // Sanity check: Ensure that this value is within the duration and will not crash + // Sanity check 2: Ensure that this value is within the duration and will not crash // the app, and that the user is not currently seeking (which would cause the SeekBar // to jump around). if (from <= durationDs && !isActivated) { diff --git a/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt b/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt index 12e3020f7..a8814b368 100644 --- a/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt @@ -35,6 +35,7 @@ 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.MusicParent import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.settings.Settings @@ -78,7 +79,15 @@ class SearchFragment : override fun onBindingCreated(binding: FragmentSearchBinding, savedInstanceState: Bundle?) { binding.searchToolbar.apply { - menu.findItem(searchModel.filterMode?.itemId ?: R.id.option_filter_all).isChecked = true + val itemIdToSelect = when (searchModel.filterMode) { + MusicMode.SONGS -> R.id.option_filter_songs + MusicMode.ALBUMS -> R.id.option_filter_albums + MusicMode.ARTISTS -> R.id.option_filter_artists + MusicMode.GENRES -> R.id.option_filter_genres + null -> R.id.option_filter_all + } + + menu.findItem(itemIdToSelect).isChecked = true setNavigationOnClickListener { imm.hide() diff --git a/app/src/main/java/org/oxycblt/auxio/search/SearchViewModel.kt b/app/src/main/java/org/oxycblt/auxio/search/SearchViewModel.kt index 34a5e3ee4..5eb802480 100644 --- a/app/src/main/java/org/oxycblt/auxio/search/SearchViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/search/SearchViewModel.kt @@ -33,11 +33,11 @@ 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.MusicStore import org.oxycblt.auxio.music.Song +import org.oxycblt.auxio.music.Sort import org.oxycblt.auxio.settings.Settings -import org.oxycblt.auxio.ui.DisplayMode -import org.oxycblt.auxio.ui.Sort import org.oxycblt.auxio.ui.recycler.Header import org.oxycblt.auxio.ui.recycler.Item import org.oxycblt.auxio.util.application @@ -59,7 +59,7 @@ class SearchViewModel(application: Application) : val searchResults: StateFlow> get() = _searchResults - val filterMode: DisplayMode? + val filterMode: MusicMode? get() = settings.searchFilterMode private var lastQuery: String? = null @@ -89,28 +89,28 @@ class SearchViewModel(application: Application) : // Note: a filter mode of null means to not filter at all. - if (filterMode == null || filterMode == DisplayMode.SHOW_ARTISTS) { + if (filterMode == null || filterMode == MusicMode.ARTISTS) { library.artists.filterArtistsBy(query)?.let { artists -> results.add(Header(R.string.lbl_artists)) results.addAll(sort.artists(artists)) } } - if (filterMode == null || filterMode == DisplayMode.SHOW_ALBUMS) { + if (filterMode == null || filterMode == MusicMode.ALBUMS) { library.albums.filterAlbumsBy(query)?.let { albums -> results.add(Header(R.string.lbl_albums)) results.addAll(sort.albums(albums)) } } - if (filterMode == null || filterMode == DisplayMode.SHOW_GENRES) { + if (filterMode == null || filterMode == MusicMode.GENRES) { library.genres.filterGenresBy(query)?.let { genres -> results.add(Header(R.string.lbl_genres)) results.addAll(sort.genres(genres)) } } - if (filterMode == null || filterMode == DisplayMode.SHOW_SONGS) { + if (filterMode == null || filterMode == MusicMode.SONGS) { library.songs.filterSongsBy(query)?.let { songs -> results.add(Header(R.string.lbl_songs)) results.addAll(sort.songs(songs)) @@ -128,10 +128,10 @@ class SearchViewModel(application: Application) : fun updateFilterModeWithId(@IdRes id: Int) { val newFilterMode = when (id) { - R.id.option_filter_songs -> DisplayMode.SHOW_SONGS - R.id.option_filter_albums -> DisplayMode.SHOW_ALBUMS - R.id.option_filter_artists -> DisplayMode.SHOW_ARTISTS - R.id.option_filter_genres -> DisplayMode.SHOW_GENRES + R.id.option_filter_songs -> MusicMode.SONGS + R.id.option_filter_albums -> MusicMode.ALBUMS + R.id.option_filter_artists -> MusicMode.ARTISTS + R.id.option_filter_genres -> MusicMode.GENRES else -> null } diff --git a/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt b/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt index 2345892b2..17e2a5558 100644 --- a/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt +++ b/app/src/main/java/org/oxycblt/auxio/settings/Settings.kt @@ -21,21 +21,21 @@ import android.content.Context import android.content.SharedPreferences import android.os.Build import android.os.storage.StorageManager -import android.util.Log import androidx.appcompat.app.AppCompatDelegate import androidx.core.content.edit import androidx.preference.PreferenceManager +import org.oxycblt.auxio.IntegerTable import org.oxycblt.auxio.R import org.oxycblt.auxio.home.tabs.Tab import org.oxycblt.auxio.music.Directory +import org.oxycblt.auxio.music.MusicMode +import org.oxycblt.auxio.music.Sort import org.oxycblt.auxio.music.dirs.MusicDirs import org.oxycblt.auxio.playback.BarAction -import org.oxycblt.auxio.playback.PlaybackMode import org.oxycblt.auxio.playback.replaygain.ReplayGainMode import org.oxycblt.auxio.playback.replaygain.ReplayGainPreAmp -import org.oxycblt.auxio.ui.DisplayMode -import org.oxycblt.auxio.ui.Sort import org.oxycblt.auxio.ui.accent.Accent +import org.oxycblt.auxio.util.logD import org.oxycblt.auxio.util.unlikelyToBeNull /** @@ -57,6 +57,67 @@ class Settings(private val context: Context, private val callback: Callback? = n } } + /** + * Try to migrate shared preference keys to their new versions. Only intended for use by + * AuxioApp. Compat code will persist for 6 months before being removed. + */ + fun migrate() { + if (inner.contains(OldKeys.KEY_ACCENT3)) { + logD("Migrating ${OldKeys.KEY_ACCENT3}") + + var accent = inner.getInt(OldKeys.KEY_ACCENT3, 5) + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + // Accents were previously frozen as soon as the OS was updated to android twelve, + // as dynamic colors were enabled by default. This is no longer the case, so we need + // to re-update the setting to dynamic colors here. + accent = 16 + } + + inner.edit { + putInt(context.getString(R.string.set_accent), accent) + remove(OldKeys.KEY_ACCENT3) + apply() + } + } + + fun Int.migratePlaybackMode() = + when (this) { + IntegerTable.PLAYBACK_MODE_ALL_SONGS -> MusicMode.SONGS + IntegerTable.PLAYBACK_MODE_IN_GENRE -> MusicMode.GENRES + IntegerTable.PLAYBACK_MODE_IN_ARTIST -> MusicMode.ARTISTS + IntegerTable.PLAYBACK_MODE_IN_ALBUM -> MusicMode.ALBUMS + else -> null + } + + if (inner.contains(OldKeys.KEY_LIB_PLAYBACK_MODE)) { + logD("Migrating ${OldKeys.KEY_LIB_PLAYBACK_MODE}") + + val mode = inner.getInt( + OldKeys.KEY_LIB_PLAYBACK_MODE, + IntegerTable.PLAYBACK_MODE_ALL_SONGS + ).migratePlaybackMode() ?: MusicMode.SONGS + + inner.edit { + putInt(context.getString(R.string.set_key_library_song_playback_mode), mode.intCode) + remove(OldKeys.KEY_LIB_PLAYBACK_MODE) + } + } + + if (inner.contains(OldKeys.KEY_DETAIL_PLAYBACK_MODE)) { + logD("Migrating ${OldKeys.KEY_DETAIL_PLAYBACK_MODE}") + + val mode = inner.getInt(OldKeys.KEY_DETAIL_PLAYBACK_MODE, Int.MIN_VALUE).migratePlaybackMode() + + inner.edit { + putInt( + context.getString(R.string.set_key_detail_song_playback_mode), + mode?.intCode ?: Int.MIN_VALUE + ) + remove(OldKeys.KEY_DETAIL_PLAYBACK_MODE) + } + } + } + fun release() { inner.unregisterOnSharedPreferenceChangeListener(this) } @@ -86,7 +147,7 @@ class Settings(private val context: Context, private val callback: Callback? = n /** The current accent. */ var accent: Accent - get() = handleAccentCompat(context, inner) + get() = Accent.from(inner.getInt(context.getString(R.string.set_accent), Accent.DEFAULT)) set(value) { inner.edit { putInt(context.getString(R.string.set_key_accent), value.index) @@ -163,23 +224,23 @@ class Settings(private val context: Context, private val callback: Callback? = n } /** What queue to create when a song is selected from the library or search */ - val libPlaybackMode: PlaybackMode + val libPlaybackMode: MusicMode get() = - PlaybackMode.fromInt( + MusicMode.fromInt( inner.getInt( context.getString(R.string.set_key_library_song_playback_mode), Int.MIN_VALUE ) ) - ?: PlaybackMode.ALL_SONGS + ?: MusicMode.SONGS /** * What queue t create when a song is selected from an album/artist/genre. Null means to default * to the currently shown item. */ - val detailPlaybackMode: PlaybackMode? + val detailPlaybackMode: MusicMode? get() = - PlaybackMode.fromInt( + MusicMode.fromInt( inner.getInt( context.getString(R.string.set_key_detail_song_playback_mode), Int.MIN_VALUE @@ -246,9 +307,9 @@ class Settings(private val context: Context, private val callback: Callback? = n } /** The current filter mode of the search tab */ - var searchFilterMode: DisplayMode? + var searchFilterMode: MusicMode? get() = - DisplayMode.fromInt( + MusicMode.fromInt( inner.getInt(context.getString(R.string.set_key_search_filter), Int.MIN_VALUE) ) set(value) { @@ -370,35 +431,11 @@ class Settings(private val context: Context, private val callback: Callback? = n apply() } } -} -// --- COMPAT --- - -fun handleAccentCompat(context: Context, prefs: SharedPreferences): Accent { - val currentKey = context.getString(R.string.set_key_accent) - - if (prefs.contains(OldKeys.KEY_ACCENT3)) { - Log.d("Auxio.SettingsCompat", "Migrating ${OldKeys.KEY_ACCENT3}") - - var accent = prefs.getInt(OldKeys.KEY_ACCENT3, 5) - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - // Accents were previously frozen as soon as the OS was updated to android twelve, - // as dynamic colors were enabled by default. This is no longer the case, so we need - // to re-update the setting to dynamic colors here. - accent = 16 - } - - prefs.edit { - putInt(currentKey, accent) - remove(OldKeys.KEY_ACCENT3) - apply() - } + /** Cache of the old keys used in Auxio. */ + private object OldKeys { + const val KEY_ACCENT3 = "auxio_accent" + const val KEY_LIB_PLAYBACK_MODE = "KEY_SONG_PLAY_MODE2" + const val KEY_DETAIL_PLAYBACK_MODE = "auxio_detail_song_play_mode" } - - return Accent.from(prefs.getInt(currentKey, Accent.DEFAULT)) -} - -/** Cache of the old keys used in Auxio. */ -private object OldKeys { - const val KEY_ACCENT3 = "auxio_accent" } diff --git a/app/src/main/java/org/oxycblt/auxio/ui/DisplayMode.kt b/app/src/main/java/org/oxycblt/auxio/ui/DisplayMode.kt deleted file mode 100644 index 2bdd1d94f..000000000 --- a/app/src/main/java/org/oxycblt/auxio/ui/DisplayMode.kt +++ /dev/null @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2021 Auxio Project - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package org.oxycblt.auxio.ui - -import org.oxycblt.auxio.IntegerTable -import org.oxycblt.auxio.R - -/** - * An enum for determining what items to show in a given list. Note: **DO NOT RE-ARRANGE THE ENUM**. - * The ordinals are used to store library tabs, so doing changing them would also change the meaning - * of tab instances. - * @author OxygenCobalt - */ -enum class DisplayMode { - SHOW_SONGS, - SHOW_ALBUMS, - SHOW_ARTISTS, - SHOW_GENRES; - - val string: Int - get() = - when (this) { - SHOW_SONGS -> R.string.lbl_songs - SHOW_ALBUMS -> R.string.lbl_albums - SHOW_ARTISTS -> R.string.lbl_artists - SHOW_GENRES -> R.string.lbl_genres - } - - val icon: Int - get() = - when (this) { - SHOW_SONGS -> R.drawable.ic_song_24 - SHOW_ALBUMS -> R.drawable.ic_album_24 - SHOW_ARTISTS -> R.drawable.ic_artist_24 - SHOW_GENRES -> R.drawable.ic_genre_24 - } - - val itemId: Int - get() = - when (this) { - SHOW_SONGS -> R.id.option_filter_songs - SHOW_ALBUMS -> R.id.option_filter_albums - SHOW_ARTISTS -> R.id.option_filter_artists - SHOW_GENRES -> R.id.option_filter_genres - } - - val intCode: Int - get() = - when (this) { - SHOW_SONGS -> IntegerTable.DISPLAY_MODE_SHOW_SONGS - SHOW_ALBUMS -> IntegerTable.DISPLAY_MODE_SHOW_ALBUMS - SHOW_ARTISTS -> IntegerTable.DISPLAY_MODE_SHOW_ARTISTS - SHOW_GENRES -> IntegerTable.DISPLAY_MODE_SHOW_GENRES - } - - companion object { - /** - * Convert a filtering integer to a [DisplayMode]. In this context, a null value means to - * filter nothing. - * @return A [DisplayMode] for this constant (including null) - */ - fun fromInt(value: Int): DisplayMode? { - return when (value) { - IntegerTable.DISPLAY_MODE_SHOW_SONGS -> SHOW_SONGS - IntegerTable.DISPLAY_MODE_SHOW_ALBUMS -> SHOW_ALBUMS - IntegerTable.DISPLAY_MODE_SHOW_ARTISTS -> SHOW_ARTISTS - IntegerTable.DISPLAY_MODE_SHOW_GENRES -> SHOW_GENRES - else -> null - } - } - } -} diff --git a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt index 8bae68a1b..730ddb8c1 100644 --- a/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt +++ b/app/src/main/java/org/oxycblt/auxio/widgets/WidgetComponent.kt @@ -24,7 +24,7 @@ import coil.request.ImageRequest import coil.transform.RoundedCornersTransformation import org.oxycblt.auxio.R import org.oxycblt.auxio.image.BitmapProvider -import org.oxycblt.auxio.image.SquareFrameTransform +import org.oxycblt.auxio.image.extractor.SquareFrameTransform import org.oxycblt.auxio.music.MusicParent import org.oxycblt.auxio.music.Song import org.oxycblt.auxio.playback.state.InternalPlayer diff --git a/app/src/main/res/layout-h480dp/fragment_playback_panel.xml b/app/src/main/res/layout-h480dp/fragment_playback_panel.xml index 18a8eafa9..5a813afae 100644 --- a/app/src/main/res/layout-h480dp/fragment_playback_panel.xml +++ b/app/src/main/res/layout-h480dp/fragment_playback_panel.xml @@ -64,7 +64,7 @@ tools:text="Album Name" /> - - - - + diff --git a/app/src/main/res/layout-sw600dp/fragment_playback_panel.xml b/app/src/main/res/layout-sw600dp/fragment_playback_panel.xml index 26ef927c7..8e0b14205 100644 --- a/app/src/main/res/layout-sw600dp/fragment_playback_panel.xml +++ b/app/src/main/res/layout-sw600dp/fragment_playback_panel.xml @@ -64,7 +64,7 @@ tools:text="Album Name" /> - - - - + diff --git a/app/src/main/res/layout-w600dp-land/fragment_main.xml b/app/src/main/res/layout-w600dp-land/fragment_main.xml index a4a0fd849..c757e7f93 100644 --- a/app/src/main/res/layout-w600dp-land/fragment_main.xml +++ b/app/src/main/res/layout-w600dp-land/fragment_main.xml @@ -20,7 +20,7 @@ android:id="@+id/playback_sheet" android:layout_width="match_parent" android:layout_height="match_parent" - app:layout_behavior="org.oxycblt.auxio.playback.PlaybackSheetBehavior"> + app:layout_behavior="org.oxycblt.auxio.playback.ui.PlaybackSheetBehavior"> + app:layout_behavior="org.oxycblt.auxio.playback.ui.PlaybackSheetBehavior"> - - + - - + diff --git a/app/src/main/res/layout/fragment_playback_panel.xml b/app/src/main/res/layout/fragment_playback_panel.xml index 0824b0b21..24700cb58 100644 --- a/app/src/main/res/layout/fragment_playback_panel.xml +++ b/app/src/main/res/layout/fragment_playback_panel.xml @@ -78,7 +78,7 @@ app:layout_constraintTop_toBottomOf="@+id/playback_artist" tools:text="Album Name" /> - - - - + diff --git a/app/src/main/res/values/settings.xml b/app/src/main/res/values/settings.xml index 7f518038c..3d5fcf691 100644 --- a/app/src/main/res/values/settings.xml +++ b/app/src/main/res/values/settings.xml @@ -20,8 +20,8 @@ auxio_pre_amp_with auxio_pre_amp_without - KEY_SONG_PLAY_MODE2 - auxio_detail_song_play_mode + auxio_library_playback_mode + auxio_detail_playback_mode KEY_KEEP_SHUFFLE KEY_PREV_REWIND KEY_LOOP_PAUSE @@ -127,10 +127,10 @@ 0xA11B -2147483648 - 0xA103 - 0xA104 - 0xA105 - 0xA106 + 0xA108 + 0xA109 + 0xA10A + 0xA10B 0xA111 0xA112 diff --git a/info/ARCHITECTURE.md b/info/ARCHITECTURE.md index 094af4a94..559f80bf0 100644 --- a/info/ARCHITECTURE.md +++ b/info/ARCHITECTURE.md @@ -120,7 +120,7 @@ also the `detail`-specific `DiscHeader` and `SortHeader`, however these are larg Other data types represent a specific UI configuration or state: - Data structures like `Sort` contain an ascending state that can be modified immutably. -- Enums like `DisplayMode` and `RepeatMode` only contain static data, such as a string resource. +- Enums like `MusicMode` and `RepeatMode` only contain static data, such as a string resource. Things to keep in mind while working with music data: - `id` is not derived from the `MediaStore` ID of the music data. It is actually a hash of the @@ -253,17 +253,15 @@ The major classes are: library should use this. - `Indexer`, which manages how music is loaded. This is only used by code that must manage or mirror the music loading state. +- The extractor system, which is Auxio's music parser. It's structured as several "Layer" classes +that build on eachother to implement version-specific functionality. Internally, there are several other major systems: - `IndexerService`, which does the indexer work in the background. -- `Indexer.Backend` implementations, which actually talk to the media database and load music. -As it stands, there are two classes of backend: - - Version-specific `MediaStoreBackend` implementations, which transform the (often insane) - music data from Android into a usable `Song`. - - `ExoPlayerBackend`, which mutates audio with extracted ID3v2 and Vorbis tags. This enables - some extra features and side-steps unfixable issues with `MediaStore` - `StorageFramework`, which is a group of utilities that allows Auxio to be volume-aware and to work with both extension-based and format-based mime types. +- Configuration models like `MusicMode` and `Sort`, which are tangentally related to operations +done on music The music loading process is roughly as follows: 1. Something triggers `IndexerService` to start indexing, either by the UI or by the service itself @@ -313,8 +311,6 @@ Shared views and view configuration models. This contains: - Important `Fragment` superclasses like `ViewBindingFragment` and `MenuFragment` - Customized views such as `AuxioAppBarLayout`, and others, which fix shortcomings with the default implementations. -- Configuration models like `DisplayMode` and `Sort`, which are used in many places but aren't tied -to a specific feature. - `ForegroundManager` and `ServiceNotification`, which remove boilerplate regarding service foreground instantiation. - The `RecyclerView` adapter framework described previously.