From 3832c4e525257f29ff221d785bfd907e2d7a1136 Mon Sep 17 00:00:00 2001 From: Alexander Capehart Date: Fri, 13 Sep 2024 13:35:37 -0600 Subject: [PATCH] home: mirror tabs to mediasession browser --- .../HomeListGenerator.kt => HomeGenerator.kt} | 51 +++++++------ .../org/oxycblt/auxio/home/HomeViewModel.kt | 46 ++++-------- .../auxio/home/tabs/AdaptiveTabStrategy.kt | 37 +++------- .../java/org/oxycblt/auxio/music/MusicType.kt | 11 +++ .../music/service/MediaItemTranslation.kt | 10 +-- .../auxio/music/service/MusicBrowser.kt | 74 +++++++++---------- .../oxycblt/auxio/music/service/TabNode.kt | 70 ++++++++++++++++++ 7 files changed, 175 insertions(+), 124 deletions(-) rename app/src/main/java/org/oxycblt/auxio/home/{list/HomeListGenerator.kt => HomeGenerator.kt} (67%) create mode 100644 app/src/main/java/org/oxycblt/auxio/music/service/TabNode.kt diff --git a/app/src/main/java/org/oxycblt/auxio/home/list/HomeListGenerator.kt b/app/src/main/java/org/oxycblt/auxio/home/HomeGenerator.kt similarity index 67% rename from app/src/main/java/org/oxycblt/auxio/home/list/HomeListGenerator.kt rename to app/src/main/java/org/oxycblt/auxio/home/HomeGenerator.kt index faca4bb56..2da76e2e7 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/list/HomeListGenerator.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeGenerator.kt @@ -1,6 +1,6 @@ -package org.oxycblt.auxio.home.list +package org.oxycblt.auxio.home -import org.oxycblt.auxio.home.HomeSettings +import org.oxycblt.auxio.home.tabs.Tab import org.oxycblt.auxio.list.ListSettings import org.oxycblt.auxio.list.adapter.UpdateInstructions import org.oxycblt.auxio.music.Album @@ -10,39 +10,46 @@ import org.oxycblt.auxio.music.MusicRepository import org.oxycblt.auxio.music.MusicType import org.oxycblt.auxio.music.Playlist import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.playback.PlaybackSettings import org.oxycblt.auxio.util.logD -import javax.inject.Inject -interface HomeListGenerator { +interface HomeGenerator { fun songs(): List fun albums(): List fun artists(): List fun genres(): List fun playlists(): List + fun tabs(): List fun release() interface Invalidator { - fun invalidate(type: MusicType, instructions: UpdateInstructions) + fun invalidateMusic(type: MusicType, instructions: UpdateInstructions) + fun invalidateTabs() } interface Factory { - fun create(invalidator: Invalidator): HomeListGenerator + fun create(invalidator: Invalidator): HomeGenerator } } -private class HomeListGeneratorImpl( - private val invalidator: HomeListGenerator.Invalidator, +private class HomeGeneratorImpl( + private val invalidator: HomeGenerator.Invalidator, private val homeSettings: HomeSettings, private val listSettings: ListSettings, private val musicRepository: MusicRepository, -) : HomeListGenerator, HomeSettings.Listener, ListSettings.Listener, MusicRepository.UpdateListener { +) : HomeGenerator, HomeSettings.Listener, ListSettings.Listener, MusicRepository.UpdateListener { override fun songs() = musicRepository.deviceLibrary?.let { listSettings.songSort.songs(it.songs) } ?: emptyList() override fun albums() = musicRepository.deviceLibrary?.let { listSettings.albumSort.albums(it.albums) } ?: emptyList() override fun artists() = musicRepository.deviceLibrary?.let { listSettings.artistSort.artists(it.artists) } ?: emptyList() override fun genres() = musicRepository.deviceLibrary?.let { listSettings.genreSort.genres(it.genres) } ?: emptyList() override fun playlists() = musicRepository.userLibrary?.let { listSettings.playlistSort.playlists(it.playlists) } ?: emptyList() + override fun tabs() = + homeSettings.homeTabs.filterIsInstance().map { it.type } + + + override fun onTabsChanged() { + invalidator.invalidateTabs() + } init { homeSettings.registerListener(this) @@ -51,9 +58,9 @@ private class HomeListGeneratorImpl( } override fun release() { - homeSettings.unregisterListener(this) - listSettings.unregisterListener(this) musicRepository.removeUpdateListener(this) + listSettings.unregisterListener(this) + homeSettings.unregisterListener(this) } override fun onHideCollaboratorsChanged() { @@ -65,27 +72,27 @@ private class HomeListGeneratorImpl( override fun onSongSortChanged() { super.onSongSortChanged() - invalidator.invalidate(MusicType.SONGS, UpdateInstructions.Replace(0)) + invalidator.invalidateMusic(MusicType.SONGS, UpdateInstructions.Replace(0)) } override fun onAlbumSortChanged() { super.onAlbumSortChanged() - invalidator.invalidate(MusicType.ALBUMS, UpdateInstructions.Replace(0)) + invalidator.invalidateMusic(MusicType.ALBUMS, UpdateInstructions.Replace(0)) } override fun onArtistSortChanged() { super.onArtistSortChanged() - invalidator.invalidate(MusicType.ARTISTS, UpdateInstructions.Replace(0)) + invalidator.invalidateMusic(MusicType.ARTISTS, UpdateInstructions.Replace(0)) } override fun onGenreSortChanged() { super.onGenreSortChanged() - invalidator.invalidate(MusicType.GENRES, UpdateInstructions.Replace(0)) + invalidator.invalidateMusic(MusicType.GENRES, UpdateInstructions.Replace(0)) } override fun onPlaylistSortChanged() { super.onPlaylistSortChanged() - invalidator.invalidate(MusicType.PLAYLISTS, UpdateInstructions.Replace(0)) + invalidator.invalidateMusic(MusicType.PLAYLISTS, UpdateInstructions.Replace(0)) } override fun onMusicChanges(changes: MusicRepository.Changes) { @@ -94,16 +101,16 @@ private class HomeListGeneratorImpl( logD("Refreshing library") // Get the each list of items in the library to use as our list data. // Applying the preferred sorting to them. - invalidator.invalidate(MusicType.SONGS, UpdateInstructions.Diff) - invalidator.invalidate(MusicType.ALBUMS, UpdateInstructions.Diff) - invalidator.invalidate(MusicType.ARTISTS, UpdateInstructions.Diff) - invalidator.invalidate(MusicType.GENRES, UpdateInstructions.Diff) + invalidator.invalidateMusic(MusicType.SONGS, UpdateInstructions.Diff) + invalidator.invalidateMusic(MusicType.ALBUMS, UpdateInstructions.Diff) + invalidator.invalidateMusic(MusicType.ARTISTS, UpdateInstructions.Diff) + invalidator.invalidateMusic(MusicType.GENRES, UpdateInstructions.Diff) } val userLibrary = musicRepository.userLibrary if (changes.userLibrary && userLibrary != null) { logD("Refreshing playlists") - invalidator.invalidate(MusicType.PLAYLISTS, UpdateInstructions.Diff) + invalidator.invalidateMusic(MusicType.PLAYLISTS, UpdateInstructions.Diff) } } 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 d681d9ac1..b2d62a6b6 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/HomeViewModel.kt @@ -23,15 +23,14 @@ import dagger.hilt.android.lifecycle.HiltViewModel import javax.inject.Inject import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow -import org.oxycblt.auxio.home.list.HomeListGenerator import org.oxycblt.auxio.home.tabs.Tab +import org.oxycblt.auxio.home.tabs.TabListGenerator import org.oxycblt.auxio.list.ListSettings import org.oxycblt.auxio.list.adapter.UpdateInstructions import org.oxycblt.auxio.list.sort.Sort import org.oxycblt.auxio.music.Album import org.oxycblt.auxio.music.Artist import org.oxycblt.auxio.music.Genre -import org.oxycblt.auxio.music.MusicRepository import org.oxycblt.auxio.music.MusicType import org.oxycblt.auxio.music.Playlist import org.oxycblt.auxio.music.Song @@ -50,12 +49,11 @@ import org.oxycblt.auxio.util.logD class HomeViewModel @Inject constructor( - private val homeSettings: HomeSettings, private val listSettings: ListSettings, private val playbackSettings: PlaybackSettings, - homeGeneratorFactory: HomeListGenerator.Factory -) : ViewModel(), HomeSettings.Listener, HomeListGenerator.Invalidator { - private val generator = homeGeneratorFactory.create(this) + homeGeneratorFactory: HomeGenerator.Factory +) : ViewModel(), HomeGenerator.Invalidator { + private val homeGenerator = homeGeneratorFactory.create(this) private val _songList = MutableStateFlow(listOf()) /** A list of [Song]s, sorted by the preferred [Sort], to be shown in the home view. */ @@ -138,7 +136,7 @@ constructor( * A list of [MusicType] corresponding to the current [Tab] configuration, excluding invisible * [Tab]s. */ - var currentTabTypes = makeTabTypes() + var currentTabTypes = homeGenerator.tabs() private set private val _currentTabType = MutableStateFlow(currentTabTypes[0]) @@ -166,45 +164,38 @@ constructor( val showOuter: Event get() = _showOuter - init { - homeSettings.registerListener(this) - } - override fun onCleared() { super.onCleared() - homeSettings.unregisterListener(this) - generator.release() + homeGenerator.release() } - override fun invalidate(type: MusicType, instructions: UpdateInstructions) { + override fun invalidateMusic(type: MusicType, instructions: UpdateInstructions) { when (type) { MusicType.SONGS -> { - _songList.value = generator.songs() + _songList.value = homeGenerator.songs() _songInstructions.put(instructions) } MusicType.ALBUMS -> { - _albumList.value = generator.albums() + _albumList.value = homeGenerator.albums() _albumInstructions.put(instructions) } MusicType.ARTISTS -> { - _artistList.value = generator.artists() + _artistList.value = homeGenerator.artists() _artistInstructions.put(instructions) } MusicType.GENRES -> { - _genreList.value = generator.genres() + _genreList.value = homeGenerator.genres() _genreInstructions.put(instructions) } MusicType.PLAYLISTS -> { - _playlistList.value = generator.playlists() + _playlistList.value = homeGenerator.playlists() _playlistInstructions.put(instructions) } } } - override fun onTabsChanged() { - // Tabs changed, update the current tabs and set up a re-create event. - currentTabTypes = makeTabTypes() - logD("Updating tabs: ${currentTabType.value}") + override fun invalidateTabs() { + currentTabTypes = homeGenerator.tabs() _shouldRecreate.put(Unit) } @@ -290,15 +281,6 @@ constructor( fun showAbout() { _showOuter.put(Outer.About) } - - /** - * Create a list of [MusicType]s representing a simpler version of the [Tab] configuration. - * - * @return A list of the [MusicType]s for each visible [Tab] in the configuration, ordered in - * the same way as the configuration. - */ - private fun makeTabTypes() = - homeSettings.homeTabs.filterIsInstance().map { it.type } } sealed interface Outer { diff --git a/app/src/main/java/org/oxycblt/auxio/home/tabs/AdaptiveTabStrategy.kt b/app/src/main/java/org/oxycblt/auxio/home/tabs/AdaptiveTabStrategy.kt index 73170ef4c..237d8edd6 100644 --- a/app/src/main/java/org/oxycblt/auxio/home/tabs/AdaptiveTabStrategy.kt +++ b/app/src/main/java/org/oxycblt/auxio/home/tabs/AdaptiveTabStrategy.kt @@ -37,40 +37,23 @@ class AdaptiveTabStrategy(context: Context, private val tabs: List) : private val width = context.resources.configuration.smallestScreenWidthDp override fun onConfigureTab(tab: TabLayout.Tab, position: Int) { - val icon: Int - val string: Int - - when (tabs[position]) { - MusicType.SONGS -> { - icon = R.drawable.ic_song_24 - string = R.string.lbl_songs - } - MusicType.ALBUMS -> { - icon = R.drawable.ic_album_24 - string = R.string.lbl_albums - } - MusicType.ARTISTS -> { - icon = R.drawable.ic_artist_24 - string = R.string.lbl_artists - } - MusicType.GENRES -> { - icon = R.drawable.ic_genre_24 - string = R.string.lbl_genres - } - MusicType.PLAYLISTS -> { - icon = R.drawable.ic_playlist_24 - string = R.string.lbl_playlists - } + val homeTab = tabs[position] + val icon = when (homeTab) { + MusicType.SONGS -> R.drawable.ic_song_24 + MusicType.ALBUMS -> R.drawable.ic_album_24 + MusicType.ARTISTS -> R.drawable.ic_artist_24 + MusicType.GENRES -> R.drawable.ic_genre_24 + MusicType.PLAYLISTS -> R.drawable.ic_playlist_24 } // Use expected sw* size thresholds when choosing a configuration. when { // On small screens, only display an icon. - width < 370 -> tab.setIcon(icon).setContentDescription(string) + width < 370 -> tab.setIcon(icon).setContentDescription(homeTab.nameRes) // On large screens, display an icon and text. - width < 600 -> tab.setText(string) + width < 600 -> tab.setText(homeTab.nameRes).setIcon(icon) // On medium-size screens, display text. - else -> tab.setIcon(icon).setText(string) + else -> tab.setIcon(icon).setText(homeTab.nameRes) } } } diff --git a/app/src/main/java/org/oxycblt/auxio/music/MusicType.kt b/app/src/main/java/org/oxycblt/auxio/music/MusicType.kt index 19f535af1..572280f8e 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/MusicType.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/MusicType.kt @@ -19,6 +19,7 @@ package org.oxycblt.auxio.music import org.oxycblt.auxio.IntegerTable +import org.oxycblt.auxio.R /** * General configuration enum to control what kind of music is being worked with. @@ -52,6 +53,16 @@ enum class MusicType { PLAYLISTS -> IntegerTable.MUSIC_MODE_PLAYLISTS } + val nameRes: Int + get() = + when (this) { + SONGS -> R.string.lbl_songs + ALBUMS -> R.string.lbl_albums + ARTISTS -> R.string.lbl_artists + GENRES -> R.string.lbl_genres + PLAYLISTS -> R.string.lbl_playlists + } + companion object { /** * Convert a [MusicType] integer representation into an instance. diff --git a/app/src/main/java/org/oxycblt/auxio/music/service/MediaItemTranslation.kt b/app/src/main/java/org/oxycblt/auxio/music/service/MediaItemTranslation.kt index 8fb340a01..624247f8e 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/service/MediaItemTranslation.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/service/MediaItemTranslation.kt @@ -44,8 +44,8 @@ import org.oxycblt.auxio.playback.formatDurationDs import org.oxycblt.auxio.util.getPlural sealed interface MediaSessionUID { - data class CategoryItem(val category: Category) : MediaSessionUID { - override fun toString() = "$ID_CATEGORY:${category.id}" + data class Tab(val node: TabNode) : MediaSessionUID { + override fun toString() = "$ID_CATEGORY:${node.id}" } data class SingleItem(val uid: Music.UID) : MediaSessionUID { @@ -66,7 +66,7 @@ sealed interface MediaSessionUID { return null } return when (parts[0]) { - ID_CATEGORY -> CategoryItem(Category.fromString(parts[1]) ?: return null) + ID_CATEGORY -> Tab(TabNode.fromString(parts[1]) ?: return null) ID_ITEM -> { val uids = parts[1].split(">", limit = 2) if (uids.size == 1) { @@ -148,12 +148,12 @@ private fun makeExtras(context: Context, vararg sugars: Sugar): Bundle { return Bundle().apply { sugars.forEach { this.it(context) } } } -fun Category.toMediaItem(context: Context): MediaItem { +fun TabNode.toMediaItem(context: Context): MediaItem { val extras = makeExtras( context, style(MediaConstants.DESCRIPTION_EXTRAS_VALUE_CONTENT_STYLE_CATEGORY_LIST_ITEM)) - val mediaSessionUID = MediaSessionUID.CategoryItem(this) + val mediaSessionUID = MediaSessionUID.Tab(this) val description = MediaDescriptionCompat.Builder() .setMediaId(mediaSessionUID.toString()) diff --git a/app/src/main/java/org/oxycblt/auxio/music/service/MusicBrowser.kt b/app/src/main/java/org/oxycblt/auxio/music/service/MusicBrowser.kt index c4d83f6f9..0ab9db8db 100644 --- a/app/src/main/java/org/oxycblt/auxio/music/service/MusicBrowser.kt +++ b/app/src/main/java/org/oxycblt/auxio/music/service/MusicBrowser.kt @@ -23,7 +23,7 @@ import android.support.v4.media.MediaBrowserCompat.MediaItem import dagger.hilt.android.qualifiers.ApplicationContext import javax.inject.Inject import org.oxycblt.auxio.R -import org.oxycblt.auxio.home.list.HomeListGenerator +import org.oxycblt.auxio.home.HomeGenerator import org.oxycblt.auxio.list.ListSettings import org.oxycblt.auxio.list.adapter.UpdateInstructions import org.oxycblt.auxio.list.sort.Sort @@ -35,8 +35,6 @@ import org.oxycblt.auxio.music.MusicRepository import org.oxycblt.auxio.music.MusicType import org.oxycblt.auxio.music.Playlist import org.oxycblt.auxio.music.Song -import org.oxycblt.auxio.music.device.DeviceLibrary -import org.oxycblt.auxio.music.user.UserLibrary import org.oxycblt.auxio.search.SearchEngine class MusicBrowser @@ -46,13 +44,13 @@ constructor( private val musicRepository: MusicRepository, private val searchEngine: SearchEngine, private val listSettings: ListSettings, - homeGeneratorFactory: HomeListGenerator.Factory -) : MusicRepository.UpdateListener, HomeListGenerator.Invalidator { + homeGeneratorFactory: HomeGenerator.Factory +) : MusicRepository.UpdateListener, HomeGenerator.Invalidator { interface Invalidator { fun invalidateMusic(ids: Set) } - private val generator = homeGeneratorFactory.create(this) + private val homeGenerator = homeGeneratorFactory.create(this) private var invalidator: Invalidator? = null fun attach(invalidator: Invalidator) { @@ -64,26 +62,24 @@ constructor( musicRepository.removeUpdateListener(this) } - override fun invalidate(type: MusicType, instructions: UpdateInstructions) { - val category = when (type) { - MusicType.SONGS -> Category.Songs - MusicType.ALBUMS -> Category.Albums - MusicType.ARTISTS -> Category.Artists - MusicType.GENRES -> Category.Genres - MusicType.PLAYLISTS -> Category.Playlists - } - val id = MediaSessionUID.CategoryItem(category).toString() + override fun invalidateMusic(type: MusicType, instructions: UpdateInstructions) { + val id = MediaSessionUID.Tab(TabNode.Home(type)).toString() invalidator?.invalidateMusic(setOf(id)) } + override fun invalidateTabs() { + for (i in 0..10) { + // TODO: Temporary bodge, move the amount parameter to a bundle extra + val rootId = MediaSessionUID.Tab(TabNode.Root(i)).toString() + val moreId = MediaSessionUID.Tab(TabNode.More(i)).toString() + invalidator?.invalidateMusic(setOf(rootId, moreId)) + } + } + override fun onMusicChanges(changes: MusicRepository.Changes) { val deviceLibrary = musicRepository.deviceLibrary val invalidate = mutableSetOf() if (changes.deviceLibrary && deviceLibrary != null) { - Category.DEVICE_MUSIC.forEach { - invalidate.add(MediaSessionUID.CategoryItem(it).toString()) - } - deviceLibrary.albums.forEach { val id = MediaSessionUID.SingleItem(it.uid).toString() invalidate.add(id) @@ -101,9 +97,6 @@ constructor( } val userLibrary = musicRepository.userLibrary if (changes.userLibrary && userLibrary != null) { - Category.USER_MUSIC.forEach { - invalidate.add(MediaSessionUID.CategoryItem(it).toString()) - } userLibrary.playlists.forEach { val id = MediaSessionUID.SingleItem(it.uid).toString() invalidate.add(id) @@ -118,7 +111,7 @@ constructor( fun getItem(mediaId: String): MediaItem? { val music = when (val uid = MediaSessionUID.fromString(mediaId)) { - is MediaSessionUID.CategoryItem -> return uid.category.toMediaItem(context) + is MediaSessionUID.Tab -> return uid.node.toMediaItem(context) is MediaSessionUID.SingleItem -> musicRepository.find(uid.uid)?.let { musicRepository.find(it.uid) } is MediaSessionUID.ChildItem -> @@ -186,8 +179,8 @@ constructor( id: String ): List? { return when (val mediaSessionUID = MediaSessionUID.fromString(id)) { - is MediaSessionUID.CategoryItem -> { - getCategoryMediaItems(mediaSessionUID.category) + is MediaSessionUID.Tab -> { + getCategoryMediaItems(mediaSessionUID.node) } is MediaSessionUID.SingleItem -> { getChildMediaItems(mediaSessionUID.uid) @@ -202,25 +195,30 @@ constructor( } private fun getCategoryMediaItems( - category: Category + node: TabNode ) = - when (category) { - is Category.Root -> { - val base = Category.MUSIC.take(category.amount - 1) - if (base.size < Category.MUSIC.size) { - base + Category.More(Category.MUSIC.size - base.size) + when (node) { + is TabNode.Root -> { + val tabs = homeGenerator.tabs() + val base = tabs.take(node.amount - 1).map { TabNode.Home(it) } + if (base.size < tabs.size) { + base + TabNode.More(Category.MUSIC.size - base.size) } else { base } .map { it.toMediaItem(context) } } - is Category.More -> - Category.MUSIC.takeLast(category.remainder).map { it.toMediaItem(context) } - is Category.Songs -> generator.songs().map { it.toMediaItem(context) } - is Category.Albums -> generator.albums().map { it.toMediaItem(context) } - is Category.Artists -> generator.artists().map { it.toMediaItem(context) } - is Category.Genres -> generator.genres().map { it.toMediaItem(context) } - is Category.Playlists -> generator.playlists().map { it.toMediaItem(context) } + is TabNode.More -> + homeGenerator.tabs().takeLast(node.remainder).map { + TabNode.Home(it).toMediaItem(context) } + is TabNode.Home -> + when (node.type) { + MusicType.SONGS -> homeGenerator.songs().map { it.toMediaItem(context, null) } + MusicType.ALBUMS -> homeGenerator.albums().map { it.toMediaItem(context) } + MusicType.ARTISTS -> homeGenerator.artists().map { it.toMediaItem(context) } + MusicType.GENRES -> homeGenerator.genres().map { it.toMediaItem(context) } + MusicType.PLAYLISTS -> homeGenerator.playlists().map { it.toMediaItem(context) } + } } private fun getChildMediaItems(uid: Music.UID): List? { diff --git a/app/src/main/java/org/oxycblt/auxio/music/service/TabNode.kt b/app/src/main/java/org/oxycblt/auxio/music/service/TabNode.kt new file mode 100644 index 000000000..02a4aa595 --- /dev/null +++ b/app/src/main/java/org/oxycblt/auxio/music/service/TabNode.kt @@ -0,0 +1,70 @@ +package org.oxycblt.auxio.music.service + +import org.oxycblt.auxio.R +import org.oxycblt.auxio.home.tabs.Tab +import org.oxycblt.auxio.music.MusicType + +sealed class TabNode { + abstract val id: String + abstract val data: Int + abstract val nameRes: Int + abstract val bitmapRes: Int? + + override fun toString() = "${id}/${data}" + + data class Root(val amount: Int) : TabNode() { + override val id = ID + override val data = amount + override val nameRes = R.string.info_app_name + override val bitmapRes = null + + companion object { + const val ID = "root" + } + } + + data class More(val remainder: Int) : TabNode() { + override val id = ID + override val data = remainder + override val nameRes = R.string.lbl_more + override val bitmapRes = null + + companion object { + const val ID = "more" + } + } + + data class Home(val type: MusicType) : TabNode() { + override val id = ID + override val data = type.intCode + override val bitmapRes: Int + get() = when (type) { + MusicType.SONGS -> R.drawable.ic_song_bitmap_24 + MusicType.ALBUMS -> R.drawable.ic_album_bitmap_24 + MusicType.ARTISTS -> R.drawable.ic_artist_bitmap_24 + MusicType.GENRES -> R.drawable.ic_genre_bitmap_24 + MusicType.PLAYLISTS -> R.drawable.ic_playlist_bitmap_24 + } + override val nameRes = type.nameRes + + companion object { + const val ID = "home" + } + } + + companion object { + fun fromString(str: String): TabNode? { + val split = str.split("/", limit = 2) + if (split.size != 2) { + return null + } + val data = split[1].toIntOrNull() ?: return null + return when (split[0]) { + Root.ID -> Root(data) + More.ID -> More(data) + Home.ID -> Home(MusicType.fromIntCode(data) ?: return null) + else -> null + } + } + } +} \ No newline at end of file