diff --git a/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt b/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt index 8462a6521..99d853e90 100644 --- a/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/library/LibraryFragment.kt @@ -54,10 +54,7 @@ class LibraryFragment : Fragment() { savedInstanceState: Bundle? ): View { val binding = FragmentLibraryBinding.inflate(inflater) - - val libraryAdapter = LibraryAdapter(::navToDetail) { view, data -> - newMenu(view, data) - } + val libraryAdapter = LibraryAdapter(::navToDetail, ::newMenu) // --- UI SETUP --- diff --git a/app/src/main/java/org/oxycblt/auxio/loading/LoadingFragment.kt b/app/src/main/java/org/oxycblt/auxio/loading/LoadingFragment.kt index 4e2eb89da..f9f69c31d 100644 --- a/app/src/main/java/org/oxycblt/auxio/loading/LoadingFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/loading/LoadingFragment.kt @@ -33,6 +33,7 @@ import org.oxycblt.auxio.R import org.oxycblt.auxio.databinding.FragmentLoadingBinding import org.oxycblt.auxio.logD import org.oxycblt.auxio.music.MusicStore +import org.oxycblt.auxio.ui.isLandscape /** * Fragment that handles what to display during the loading process. @@ -58,6 +59,10 @@ class LoadingFragment : Fragment() { binding.lifecycleOwner = viewLifecycleOwner binding.loadingModel = loadingModel + // The loading panel shouldn't fit the system window on landscape as that will cause it + // to be mis-aligned with the Auxio icon. + binding.loadingPanel.fitsSystemWindows = !isLandscape(resources) + // --- VIEWMODEL SETUP --- loadingModel.doGrant.observe(viewLifecycleOwner) { doGrant -> @@ -141,7 +146,6 @@ class LoadingFragment : Fragment() { */ private fun showLoading(binding: FragmentLoadingBinding) { binding.apply { - loadingErrorIcon.visibility = View.INVISIBLE loadingErrorText.visibility = View.INVISIBLE loadingActionButton.visibility = View.INVISIBLE loadingCircle.visibility = View.VISIBLE @@ -155,7 +159,6 @@ class LoadingFragment : Fragment() { */ private fun showError(binding: FragmentLoadingBinding, error: MusicStore.Response) { binding.loadingCircle.visibility = View.GONE - binding.loadingErrorIcon.visibility = View.VISIBLE binding.loadingErrorText.visibility = View.VISIBLE binding.loadingActionButton.visibility = View.VISIBLE diff --git a/app/src/main/java/org/oxycblt/auxio/music/Models.kt b/app/src/main/java/org/oxycblt/auxio/music/Models.kt index 80fc7e121..ec14021e6 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/Models.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/Models.kt @@ -32,16 +32,34 @@ sealed class BaseModel { abstract val name: String } +/** + * Provides a versatile static hash for a music item that will not change when + * MediaStore changes. + * + * The reason why this is used is down a couple of reasons: + * - MediaStore will refresh the unique ID of a piece of media whenever the library + * changes, which creates bad UX + * - Using song names makes collisions too common to be reliable + * - Hashing into an integer makes databases both smaller and more efficent + * + * This does lock me into a "Load everything at once, lol" architecture for Auxio, but I + * think its worth it. + * + * @property hash A unique-ish hash for this media item + * + * TODO: Make this hash stronger + */ +sealed interface Hashable { + val hash: Int +} + /** * [BaseModel] variant that denotes that this object is a parent of other data objects, such * as an [Album] or [Artist] - * @property hash A versatile, unique(ish) hash used for databases * @property displayName Name that handles the usage of [Genre.resolvedName] * and the normal [BaseModel.name] */ -sealed class Parent : BaseModel() { - abstract val hash: Int - +sealed class Parent : BaseModel(), Hashable { val displayName: String get() = if (this is Genre) { resolvedName } else { @@ -61,7 +79,6 @@ sealed class Parent : BaseModel() { * These are not ensured to be linked due to possible quirks in the genre loading system. * @property seconds The Song's duration in seconds * @property formattedDuration The Song's duration as a duration string. - * @property hash A versatile, unique(ish) hash used for databases */ data class Song( override val id: Long, @@ -70,7 +87,7 @@ data class Song( val albumId: Long, val track: Int, val duration: Long -) : BaseModel() { +) : BaseModel(), Hashable { private var mAlbum: Album? = null private var mGenre: Genre? = null @@ -80,7 +97,12 @@ data class Song( val seconds = duration / 1000 val formattedDuration = seconds.toDuration() - val hash = songHash() + override val hash: Int get() { + var result = name.hashCode() + result = 31 * result + track + result = 31 * result + duration.hashCode() + return result + } fun linkAlbum(album: Album) { if (mAlbum == null) { @@ -93,13 +115,6 @@ data class Song( mGenre = genre } } - - private fun songHash(): Int { - var result = name.hashCode() - result = 31 * result + track - result = 31 * result + duration.hashCode() - return result - } } /** @@ -127,7 +142,12 @@ data class Album( val totalDuration: String get() = songs.sumOf { it.seconds }.toDuration() - override val hash = albumHash() + override val hash: Int get() { + var result = name.hashCode() + result = 31 * result + artistName.hashCode() + result = 31 * result + year + return result + } fun linkArtist(artist: Artist) { mArtist = artist @@ -139,13 +159,6 @@ data class Album( mSongs.add(song) } } - - private fun albumHash(): Int { - var result = name.hashCode() - result = 31 * result + artistName.hashCode() - result = 31 * result + year - return result - } } /** 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 ece93cb43..8ae0ee32b 100644 --- a/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/search/SearchFragment.kt @@ -60,9 +60,7 @@ class SearchFragment : Fragment() { ): View { val binding = FragmentSearchBinding.inflate(inflater) - val searchAdapter = SearchAdapter(::onItemSelection) { view, data -> - newMenu(view, data) - } + val searchAdapter = SearchAdapter(::onItemSelection, ::newMenu) val toolbarParams = binding.searchToolbar.layoutParams as AppBarLayout.LayoutParams val defaultParams = toolbarParams.scrollFlags diff --git a/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt b/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt index 7d78913bb..4185cca48 100644 --- a/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt +++ b/app/src/main/java/org/oxycblt/auxio/songs/SongsFragment.kt @@ -49,9 +49,7 @@ class SongsFragment : Fragment() { savedInstanceState: Bundle? ): View { val binding = FragmentSongsBinding.inflate(inflater) - val songAdapter = SongsAdapter(musicStore.songs, playbackModel::playSong) { view, data -> - newMenu(view, data) - } + val songAdapter = SongsAdapter(musicStore.songs, playbackModel::playSong, ::newMenu) // --- UI SETUP --- diff --git a/app/src/main/res/layout/fragment_loading.xml b/app/src/main/res/layout/fragment_loading.xml index 24032b656..db43f6af4 100644 --- a/app/src/main/res/layout/fragment_loading.xml +++ b/app/src/main/res/layout/fragment_loading.xml @@ -16,73 +16,61 @@ android:gravity="center" android:orientation="vertical"> - + - + app:layout_constraintTop_toTopOf="parent" /> - - + app:layout_constraintStart_toStartOf="parent" /> diff --git a/app/src/main/res/values/dimens.xml b/app/src/main/res/values/dimens.xml index a6f1393ae..988ea6876 100644 --- a/app/src/main/res/values/dimens.xml +++ b/app/src/main/res/values/dimens.xml @@ -8,6 +8,7 @@ 24dp 32dp 48dp + 64dp 128dp diff --git a/app/src/main/res/values/styles_component.xml b/app/src/main/res/values/styles_component.xml index b394598fb..736d583b2 100644 --- a/app/src/main/res/values/styles_component.xml +++ b/app/src/main/res/values/styles_component.xml @@ -2,7 +2,6 @@ - - + + \ No newline at end of file