diff --git a/android/app/src/main/java/com/audiobookshelf/app/data/DataClasses.kt b/android/app/src/main/java/com/audiobookshelf/app/data/DataClasses.kt index e81e84cf..c00b3a50 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/data/DataClasses.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/data/DataClasses.kt @@ -7,6 +7,7 @@ import android.support.v4.media.MediaMetadataCompat import androidx.media.utils.MediaConstants import com.audiobookshelf.app.media.MediaManager import com.fasterxml.jackson.annotation.* +import com.audiobookshelf.app.media.getUriToAbsIconDrawable // This auto-detects whether it is a Book or Podcast @JsonTypeInfo(use=JsonTypeInfo.Id.DEDUCTION) @@ -348,7 +349,7 @@ data class Library( var stats: LibraryStats? ) { @JsonIgnore - fun getMediaMetadata(targetType: String? = null): MediaMetadataCompat { + fun getMediaMetadata(context: Context, targetType: String? = null): MediaMetadataCompat { var mediaId = id if (targetType !== null) { mediaId = "__RECENTLY__$id" @@ -357,6 +358,7 @@ data class Library( putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, mediaId) putString(MediaMetadataCompat.METADATA_KEY_DISPLAY_TITLE, name) putString(MediaMetadataCompat.METADATA_KEY_TITLE, name) + putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, getUriToAbsIconDrawable(context, icon).toString()) }.build() } } diff --git a/android/app/src/main/java/com/audiobookshelf/app/media/MediaManager.kt b/android/app/src/main/java/com/audiobookshelf/app/media/MediaManager.kt index 3506e777..970e1ab0 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/media/MediaManager.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/media/MediaManager.kt @@ -31,6 +31,8 @@ class MediaManager(private var apiHandler: ApiHandler, var ctx: Context) { private var cachedLibraryDiscovery : MutableMap> = hashMapOf() private var cachedLibraryPodcasts : MutableMap> = hashMapOf() private var isLibraryPodcastsCached : MutableMap = hashMapOf() + var allLibraryPersonalizationsDone : Boolean = false + private var libraryPersonalizationsDone : Int = 0 private var selectedPodcast:Podcast? = null private var selectedLibraryItemId:String? = null @@ -158,11 +160,16 @@ class MediaManager(private var apiHandler: ApiHandler, var ctx: Context) { fun populatePersonalizedDataForAllLibraries(cb: () -> Unit ) { serverLibraries.forEach { + libraryPersonalizationsDone++ Log.d(tag, "Loading personalization for library ${it.name} - ${it.id} - ${it.mediaType}") populatePersonalizedDataForLibrary(it.id) { Log.d(tag, "Loaded personalization for library ${it.name} - ${it.id} - ${it.mediaType}") + libraryPersonalizationsDone-- } } + while (libraryPersonalizationsDone > 0) { } + allLibraryPersonalizationsDone = true + cb() } private fun populatePersonalizedDataForLibrary(libraryId: String, cb: () -> Unit) { @@ -178,7 +185,9 @@ class MediaManager(private var apiHandler: ApiHandler, var ctx: Context) { if (!cachedLibraryRecentShelfs.containsKey(libraryId)) { cachedLibraryRecentShelfs[libraryId] = mutableListOf() } - cachedLibraryRecentShelfs[libraryId]!!.add(shelf) + if (cachedLibraryRecentShelfs[libraryId]?.find { it.id == shelf.id } == null) { + cachedLibraryRecentShelfs[libraryId]!!.add(shelf) + } } else if (shelf.id == "discover") { if (!cachedLibraryDiscovery.containsKey(libraryId)) { @@ -196,7 +205,9 @@ class MediaManager(private var apiHandler: ApiHandler, var ctx: Context) { if (!cachedLibraryRecentShelfs.containsKey(libraryId)) { cachedLibraryRecentShelfs[libraryId] = mutableListOf() } - cachedLibraryRecentShelfs[libraryId]!!.add(shelf) + if (cachedLibraryRecentShelfs[libraryId]?.find { it.id == shelf.id } == null) { + cachedLibraryRecentShelfs[libraryId]!!.add(shelf) + } } } else if (shelf.type == "episode") { if (shelf.id == "continue-listening") return@map @@ -205,7 +216,9 @@ class MediaManager(private var apiHandler: ApiHandler, var ctx: Context) { if (!cachedLibraryRecentShelfs.containsKey(libraryId)) { cachedLibraryRecentShelfs[libraryId] = mutableListOf() } - cachedLibraryRecentShelfs[libraryId]!!.add(shelf) + if (cachedLibraryRecentShelfs[libraryId]?.find { it.id == shelf.id } == null) { + cachedLibraryRecentShelfs[libraryId]!!.add(shelf) + } (shelf as LibraryShelfEpisodeEntity).entities?.forEach { libraryItem -> loadPodcastItem(libraryItem.libraryId, libraryItem.id) {} @@ -216,7 +229,9 @@ class MediaManager(private var apiHandler: ApiHandler, var ctx: Context) { if (!cachedLibraryRecentShelfs.containsKey(libraryId)) { cachedLibraryRecentShelfs[libraryId] = mutableListOf() } - cachedLibraryRecentShelfs[libraryId]!!.add(shelf) + if (cachedLibraryRecentShelfs[libraryId]?.find { it.id == shelf.id } == null) { + cachedLibraryRecentShelfs[libraryId]!!.add(shelf) + } } else if (shelf.id == "discover"){ return@map @@ -226,7 +241,9 @@ class MediaManager(private var apiHandler: ApiHandler, var ctx: Context) { if (!cachedLibraryRecentShelfs.containsKey(libraryId)) { cachedLibraryRecentShelfs[libraryId] = mutableListOf() } - cachedLibraryRecentShelfs[libraryId]!!.add(shelf) + if (cachedLibraryRecentShelfs[libraryId]?.find { it.id == shelf.id } == null) { + cachedLibraryRecentShelfs[libraryId]!!.add(shelf) + } } } @@ -503,13 +520,14 @@ class MediaManager(private var apiHandler: ApiHandler, var ctx: Context) { if (!cachedLibraryDiscovery.containsKey(libraryId)) { cb(listOf()) } - val libraryItemsWithAudio = cachedLibraryDiscovery[libraryId]!!.filter { li -> li.checkHasTracks() } - libraryItemsWithAudio.forEach { libraryItem -> addServerLibrary(libraryItem) } - cb(libraryItemsWithAudio) + val libraryItemsWithAudio = cachedLibraryDiscovery[libraryId]?.filter { li -> li.checkHasTracks() } + libraryItemsWithAudio?.forEach { libraryItem -> addServerLibrary(libraryItem) } + cb(libraryItemsWithAudio as List) } fun getLibraryRecentShelfs(libraryId: String, cb: (List) -> Unit) { if (!cachedLibraryRecentShelfs.containsKey(libraryId)) { + Log.d(tag, "getLibraryRecentShelfs: No shelves $libraryId") cb(listOf()) return } @@ -748,6 +766,25 @@ class MediaManager(private var apiHandler: ApiHandler, var ctx: Context) { } } + fun initializeInProgressItems(cb: () -> Unit) { + Log.d(tag, "Initializing inprogress items") + + loadItemsInProgressForAllLibraries { itemsInProgress -> + itemsInProgress.forEach { + val libraryItem = it.libraryItemWrapper as LibraryItem + if (serverLibraryItems.find { li -> li.id == libraryItem.id } == null) { + serverLibraryItems.add(libraryItem) + } + + if (it.episode != null) { + podcastEpisodeLibraryItemMap[it.episode.id] = LibraryItemWithEpisode(it.libraryItemWrapper, it.episode) + } + } + Log.d(tag, "Initializing inprogress items done") + cb() + } + } + fun loadAndroidAutoItems(cb: () -> Unit) { Log.d(tag, "Load android auto items") @@ -762,23 +799,7 @@ class MediaManager(private var apiHandler: ApiHandler, var ctx: Context) { Log.w(tag, "No libraries returned from server request") cb() } else { - val library = libraries[0] - Log.d(tag, "Loading categories for library ${library.name} - ${library.id} - ${library.mediaType}") - - loadItemsInProgressForAllLibraries { itemsInProgress -> - itemsInProgress.forEach { - val libraryItem = it.libraryItemWrapper as LibraryItem - if (serverLibraryItems.find { li -> li.id == libraryItem.id } == null) { - serverLibraryItems.add(libraryItem) - } - - if (it.episode != null) { - podcastEpisodeLibraryItemMap[it.episode.id] = LibraryItemWithEpisode(it.libraryItemWrapper, it.episode) - } - } - - cb() // Fully loaded - } + cb() // Fully loaded } } } else { // Not connected to server diff --git a/android/app/src/main/java/com/audiobookshelf/app/media/icons.kt b/android/app/src/main/java/com/audiobookshelf/app/media/icons.kt new file mode 100644 index 00000000..0cfaa941 --- /dev/null +++ b/android/app/src/main/java/com/audiobookshelf/app/media/icons.kt @@ -0,0 +1,55 @@ +package com.audiobookshelf.app.media + +import android.content.ContentResolver +import android.content.Context +import android.net.Uri +import androidx.annotation.AnyRes +import com.audiobookshelf.app.R + +/** + * get uri to drawable or any other resource type if u wish + * @param drawableId - drawable res id + * @return - uri + */ +fun getUriToDrawable(context: Context, @AnyRes drawableId: Int): Uri { + return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + + "://" + context.resources.getResourcePackageName(drawableId) + + '/' + context.resources.getResourceTypeName(drawableId) + + '/' + context.resources.getResourceEntryName(drawableId)) +} + + +/** + * get uri to drawable or any other resource type if u wish + * @param drawableId - drawable res id + * @return - uri + */ +fun getUriToAbsIconDrawable(context: Context, absIconName: String): Uri { + val drawableId = when(absIconName) { + "audiobookshelf" -> R.drawable.abs_audiobookshelf + "authors" -> R.drawable.abs_authors + "book-1" -> R.drawable.abs_book_1 + "books-1" -> R.drawable.abs_books_1 + "books-2" -> R.drawable.abs_books_2 + "columns" -> R.drawable.abs_columns + "database" -> R.drawable.abs_database + "file-picture" -> R.drawable.abs_file_picture + "headphones" -> R.drawable.abs_headphones + "heart" -> R.drawable.abs_heart + "microphone_1" -> R.drawable.abs_microphone_1 + "microphone_2" -> R.drawable.abs_microphone_2 + "microphone_3" -> R.drawable.abs_microphone_3 + "music" -> R.drawable.abs_music + "podcast" -> R.drawable.abs_podcast + "radio" -> R.drawable.abs_radio + "rocket" -> R.drawable.abs_rocket + "rss" -> R.drawable.abs_rss + "star" -> R.drawable.abs_star + else -> R.drawable.icon_library_folder + } + return Uri.parse( + ContentResolver.SCHEME_ANDROID_RESOURCE + + "://" + context.resources.getResourcePackageName(drawableId) + + '/' + context.resources.getResourceTypeName(drawableId) + + '/' + context.resources.getResourceEntryName(drawableId)) +} diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/BrowseTree.kt b/android/app/src/main/java/com/audiobookshelf/app/player/BrowseTree.kt index 9bc5c16e..126ed588 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/BrowseTree.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/BrowseTree.kt @@ -1,57 +1,45 @@ package com.audiobookshelf.app.player -import android.content.ContentResolver import android.content.Context -import android.net.Uri import android.support.v4.media.MediaMetadataCompat -import androidx.annotation.AnyRes +import android.util.Log import com.audiobookshelf.app.R import com.audiobookshelf.app.data.* +import com.audiobookshelf.app.media.getUriToDrawable class BrowseTree( val context: Context, itemsInProgress: List, - libraries: List + libraries: List, + recentsLoaded: Boolean ) { private val mediaIdToChildren = mutableMapOf>() - /** - * get uri to drawable or any other resource type if u wish - * @param drawableId - drawable res id - * @return - uri - */ - private fun getUriToDrawable(@AnyRes drawableId: Int): Uri { - return Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE - + "://" + context.resources.getResourcePackageName(drawableId) - + '/' + context.resources.getResourceTypeName(drawableId) - + '/' + context.resources.getResourceEntryName(drawableId)) - } - init { val rootList = mediaIdToChildren[AUTO_BROWSE_ROOT] ?: mutableListOf() val continueListeningMetadata = MediaMetadataCompat.Builder().apply { putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, CONTINUE_ROOT) putString(MediaMetadataCompat.METADATA_KEY_TITLE, "Continue") - putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, getUriToDrawable(R.drawable.exo_icon_localaudio).toString()) + putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, getUriToDrawable(context, R.drawable.exo_icon_localaudio).toString()) }.build() val recentMetadata = MediaMetadataCompat.Builder().apply { putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, RECENTLY_ROOT) putString(MediaMetadataCompat.METADATA_KEY_TITLE, "Recent") - putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, getUriToDrawable(R.drawable.md_clock_outline).toString()) + putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, getUriToDrawable(context, R.drawable.md_clock_outline).toString()) }.build() val downloadsMetadata = MediaMetadataCompat.Builder().apply { putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, DOWNLOADS_ROOT) putString(MediaMetadataCompat.METADATA_KEY_TITLE, "Downloads") - putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, getUriToDrawable(R.drawable.exo_icon_downloaddone).toString()) + putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, getUriToDrawable(context, R.drawable.exo_icon_downloaddone).toString()) }.build() val librariesMetadata = MediaMetadataCompat.Builder().apply { putString(MediaMetadataCompat.METADATA_KEY_MEDIA_ID, LIBRARIES_ROOT) putString(MediaMetadataCompat.METADATA_KEY_TITLE, "Libraries") - putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, getUriToDrawable(R.drawable.icon_library_folder).toString()) + putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ART_URI, getUriToDrawable(context, R.drawable.icon_library_folder).toString()) }.build() if (itemsInProgress.isNotEmpty()) { @@ -59,24 +47,28 @@ class BrowseTree( } if (libraries.isNotEmpty()) { - rootList += recentMetadata + if (recentsLoaded) { + rootList += recentMetadata + } rootList += librariesMetadata libraries.forEach { library -> // Skip libraries without audio content if (library.stats?.numAudioTracks == 0) return@forEach - + Log.d("BrowseTree", "Library $library | ${library.icon}") // Generate library list items for Libraries menu - val libraryMediaMetadata = library.getMediaMetadata() + val libraryMediaMetadata = library.getMediaMetadata(context) val children = mediaIdToChildren[LIBRARIES_ROOT] ?: mutableListOf() children += libraryMediaMetadata mediaIdToChildren[LIBRARIES_ROOT] = children - // Generate library list items for Recent menu - val recentlyMediaMetadata = library.getMediaMetadata("recently") - val childrenRecently = mediaIdToChildren[RECENTLY_ROOT] ?: mutableListOf() - childrenRecently += recentlyMediaMetadata - mediaIdToChildren[RECENTLY_ROOT] = childrenRecently + if (recentsLoaded) { + // Generate library list items for Recent menu + val recentlyMediaMetadata = library.getMediaMetadata(context,"recently") + val childrenRecently = mediaIdToChildren[RECENTLY_ROOT] ?: mutableListOf() + childrenRecently += recentlyMediaMetadata + mediaIdToChildren[RECENTLY_ROOT] = childrenRecently + } } } diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt index 36629c12..30b43ef7 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt @@ -35,6 +35,8 @@ import com.audiobookshelf.app.media.MediaManager import com.audiobookshelf.app.media.MediaProgressSyncer import com.audiobookshelf.app.server.ApiHandler import com.audiobookshelf.app.BuildConfig +import com.audiobookshelf.app.media.getUriToAbsIconDrawable +import com.audiobookshelf.app.media.getUriToDrawable import com.google.android.exoplayer2.* import com.google.android.exoplayer2.audio.AudioAttributes import com.google.android.exoplayer2.ext.mediasession.MediaSessionConnector @@ -120,8 +122,13 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { private var mShakeDetector: ShakeDetector? = null private var shakeSensorUnregisterTask:TimerTask? = null - // These are used to prevent things running multiple times or simultaneously - private var isLoadingAndroidAutoItems:Boolean = false + // These are used to trigger reloading if + private var forceReloadingAndroidAuto:Boolean = false + private var firstLoadDone:Boolean = false + + fun isBrowsetreeInitialized() : Boolean { + return this::browseTree.isInitialized + } // Cache latest search so it wont trigger again when returning from series for example private var cachedSearch : String = "" @@ -1098,21 +1105,39 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { result.sendResult(localBrowseItems) } else if (parentMediaId == AUTO_MEDIA_ROOT) { Log.d(tag, "Trying to initialize browseTree.") - if (!this::browseTree.isInitialized) { - isLoadingAndroidAutoItems = true + if (!this::browseTree.isInitialized || forceReloadingAndroidAuto) { + forceReloadingAndroidAuto = false mediaManager.loadAndroidAutoItems { - browseTree = BrowseTree(this, mediaManager.serverItemsInProgress, mediaManager.serverLibraries) - + Log.d(tag, "android auto loaded. Starting browseTree initialize") + browseTree = BrowseTree(this, mediaManager.serverItemsInProgress, mediaManager.serverLibraries, mediaManager.allLibraryPersonalizationsDone) val children = browseTree[parentMediaId]?.map { item -> Log.d(tag, "Found top menu item: ${item.description.title}") MediaBrowserCompat.MediaItem(item.description, MediaBrowserCompat.MediaItem.FLAG_BROWSABLE) } Log.d(tag, "browseTree initialize and android auto loaded") result.sendResult(children as MutableList?) - isLoadingAndroidAutoItems = false - Log.d(tag, "Starting personalization fetch") - mediaManager.populatePersonalizedDataForAllLibraries {} + firstLoadDone = true + if (mediaManager.serverLibraries.isNotEmpty()) { + Log.d(tag, "Starting personalization fetch") + mediaManager.populatePersonalizedDataForAllLibraries { + notifyChildrenChanged("/") + } + + Log.d(tag, "Initialize inprogress items") + mediaManager.initializeInProgressItems { + notifyChildrenChanged("/") + } + } } + } else { + Log.d(tag, "Starting browseTree refresh") + browseTree = BrowseTree(this, mediaManager.serverItemsInProgress, mediaManager.serverLibraries, mediaManager.allLibraryPersonalizationsDone) + val children = browseTree[parentMediaId]?.map { item -> + Log.d(tag, "Found top menu item: ${item.description.title}") + MediaBrowserCompat.MediaItem(item.description, MediaBrowserCompat.MediaItem.FLAG_BROWSABLE) + } + Log.d(tag, "browseTree initialize and android auto loaded") + result.sendResult(children as MutableList?) } } else if (parentMediaId == LIBRARIES_ROOT || parentMediaId == RECENTLY_ROOT) { while (!this::browseTree.isInitialized) {} @@ -1141,6 +1166,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { MediaDescriptionCompat.Builder() .setTitle("Authors") .setMediaId("__LIBRARY__${parentMediaId}__AUTHORS") + .setIconUri(getUriToAbsIconDrawable(ctx, "authors")) .build(), MediaBrowserCompat.MediaItem.FLAG_BROWSABLE ), @@ -1148,6 +1174,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { MediaDescriptionCompat.Builder() .setTitle("Series") .setMediaId("__LIBRARY__${parentMediaId}__SERIES_LIST") + .setIconUri(getUriToAbsIconDrawable(ctx, "columns")) .build(), MediaBrowserCompat.MediaItem.FLAG_BROWSABLE ), @@ -1155,6 +1182,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { MediaDescriptionCompat.Builder() .setTitle("Collections") .setMediaId("__LIBRARY__${parentMediaId}__COLLECTIONS") + .setIconUri(getUriToDrawable(ctx, R.drawable.md_book_multiple_outline)) .build(), MediaBrowserCompat.MediaItem.FLAG_BROWSABLE ) @@ -1165,6 +1193,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { MediaDescriptionCompat.Builder() .setTitle("Discovery") .setMediaId("__LIBRARY__${parentMediaId}__DISCOVERY") + .setIconUri(getUriToDrawable(ctx, R.drawable.md_telescope)) .build(), MediaBrowserCompat.MediaItem.FLAG_BROWSABLE ) @@ -1192,6 +1221,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { MediaDescriptionCompat.Builder() .setTitle("Books") .setMediaId("${parentMediaId}__BOOK") + .setIconUri(getUriToDrawable(ctx, R.drawable.md_book_open_blank_variant_outline)) .build(), MediaBrowserCompat.MediaItem.FLAG_BROWSABLE ) @@ -1202,6 +1232,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { MediaDescriptionCompat.Builder() .setTitle("Series") .setMediaId("${parentMediaId}__SERIES") + .setIconUri(getUriToAbsIconDrawable(ctx, "columns")) .build(), MediaBrowserCompat.MediaItem.FLAG_BROWSABLE ) @@ -1212,6 +1243,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { MediaDescriptionCompat.Builder() .setTitle("Episodes") .setMediaId("${parentMediaId}__EPISODE") + .setIconUri(getUriToAbsIconDrawable(ctx, "microphone_2")) .build(), MediaBrowserCompat.MediaItem.FLAG_BROWSABLE ) @@ -1222,6 +1254,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { MediaDescriptionCompat.Builder() .setTitle("Podcast") .setMediaId("${parentMediaId}__PODCAST") + .setIconUri(getUriToAbsIconDrawable(ctx, "podcast")) .build(), MediaBrowserCompat.MediaItem.FLAG_BROWSABLE ) @@ -1232,6 +1265,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { MediaDescriptionCompat.Builder() .setTitle("Authors") .setMediaId("${parentMediaId}__AUTHORS") + .setIconUri(getUriToAbsIconDrawable(ctx, "authors")) .build(), MediaBrowserCompat.MediaItem.FLAG_BROWSABLE ) @@ -1620,7 +1654,12 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { Log.i(tag, "Network capabilities changed. hasNetworkConnectivity=$hasNetworkConnectivity | isUnmeteredNetwork=$isUnmeteredNetwork") clientEventEmitter?.onNetworkMeteredChanged(isUnmeteredNetwork) if (hasNetworkConnectivity) { - // TODO: Trigger android auto loading if it is not loaded previously + // Force android auto loading if libraries are empty. + // Lack of network connectivity is most likely reason for libraries being empty + if (isBrowsetreeInitialized() && firstLoadDone && mediaManager.serverLibraries.isEmpty()) { + forceReloadingAndroidAuto = true + notifyChildrenChanged("/") + } } } } diff --git a/android/app/src/main/res/drawable/abs_audiobookshelf.xml b/android/app/src/main/res/drawable/abs_audiobookshelf.xml new file mode 100644 index 00000000..f6fef021 --- /dev/null +++ b/android/app/src/main/res/drawable/abs_audiobookshelf.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_authors.xml b/android/app/src/main/res/drawable/abs_authors.xml new file mode 100644 index 00000000..9f7e9a4d --- /dev/null +++ b/android/app/src/main/res/drawable/abs_authors.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_book_1.xml b/android/app/src/main/res/drawable/abs_book_1.xml new file mode 100644 index 00000000..fc946fae --- /dev/null +++ b/android/app/src/main/res/drawable/abs_book_1.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_books_1.xml b/android/app/src/main/res/drawable/abs_books_1.xml new file mode 100644 index 00000000..e9910594 --- /dev/null +++ b/android/app/src/main/res/drawable/abs_books_1.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_books_2.xml b/android/app/src/main/res/drawable/abs_books_2.xml new file mode 100644 index 00000000..64b308ef --- /dev/null +++ b/android/app/src/main/res/drawable/abs_books_2.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_columns.xml b/android/app/src/main/res/drawable/abs_columns.xml new file mode 100644 index 00000000..a51ab6ad --- /dev/null +++ b/android/app/src/main/res/drawable/abs_columns.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_database.xml b/android/app/src/main/res/drawable/abs_database.xml new file mode 100644 index 00000000..18fa4186 --- /dev/null +++ b/android/app/src/main/res/drawable/abs_database.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_file_picture.xml b/android/app/src/main/res/drawable/abs_file_picture.xml new file mode 100644 index 00000000..0d3f5344 --- /dev/null +++ b/android/app/src/main/res/drawable/abs_file_picture.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_headphones.xml b/android/app/src/main/res/drawable/abs_headphones.xml new file mode 100644 index 00000000..2e228cf4 --- /dev/null +++ b/android/app/src/main/res/drawable/abs_headphones.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_heart.xml b/android/app/src/main/res/drawable/abs_heart.xml new file mode 100644 index 00000000..06647dc6 --- /dev/null +++ b/android/app/src/main/res/drawable/abs_heart.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_microphone_1.xml b/android/app/src/main/res/drawable/abs_microphone_1.xml new file mode 100644 index 00000000..e2c07211 --- /dev/null +++ b/android/app/src/main/res/drawable/abs_microphone_1.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_microphone_2.xml b/android/app/src/main/res/drawable/abs_microphone_2.xml new file mode 100644 index 00000000..0db2ffe1 --- /dev/null +++ b/android/app/src/main/res/drawable/abs_microphone_2.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_microphone_3.xml b/android/app/src/main/res/drawable/abs_microphone_3.xml new file mode 100644 index 00000000..25d3a655 --- /dev/null +++ b/android/app/src/main/res/drawable/abs_microphone_3.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_music.xml b/android/app/src/main/res/drawable/abs_music.xml new file mode 100644 index 00000000..4f473bc8 --- /dev/null +++ b/android/app/src/main/res/drawable/abs_music.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_podcast.xml b/android/app/src/main/res/drawable/abs_podcast.xml new file mode 100644 index 00000000..261e3db6 --- /dev/null +++ b/android/app/src/main/res/drawable/abs_podcast.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_radio.xml b/android/app/src/main/res/drawable/abs_radio.xml new file mode 100644 index 00000000..980f938e --- /dev/null +++ b/android/app/src/main/res/drawable/abs_radio.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_rocket.xml b/android/app/src/main/res/drawable/abs_rocket.xml new file mode 100644 index 00000000..e6673308 --- /dev/null +++ b/android/app/src/main/res/drawable/abs_rocket.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_rss.xml b/android/app/src/main/res/drawable/abs_rss.xml new file mode 100644 index 00000000..21259ee4 --- /dev/null +++ b/android/app/src/main/res/drawable/abs_rss.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/abs_star.xml b/android/app/src/main/res/drawable/abs_star.xml new file mode 100644 index 00000000..6da979c9 --- /dev/null +++ b/android/app/src/main/res/drawable/abs_star.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/app/src/main/res/drawable/md_book_multiple_outline.xml b/android/app/src/main/res/drawable/md_book_multiple_outline.xml new file mode 100644 index 00000000..d215e9eb --- /dev/null +++ b/android/app/src/main/res/drawable/md_book_multiple_outline.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/md_book_open_blank_variant_outline.xml b/android/app/src/main/res/drawable/md_book_open_blank_variant_outline.xml new file mode 100644 index 00000000..09cb77a8 --- /dev/null +++ b/android/app/src/main/res/drawable/md_book_open_blank_variant_outline.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/android/app/src/main/res/drawable/md_telescope.xml b/android/app/src/main/res/drawable/md_telescope.xml new file mode 100644 index 00000000..8e8c5751 --- /dev/null +++ b/android/app/src/main/res/drawable/md_telescope.xml @@ -0,0 +1 @@ +