diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/service/CachedMusicService.java b/ultrasonic/src/main/java/org/moire/ultrasonic/service/CachedMusicService.java index d294df64..d8033ceb 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/service/CachedMusicService.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/service/CachedMusicService.java @@ -76,7 +76,7 @@ public class CachedMusicService implements MusicService private final TimeLimitedCache> cachedGenres = new TimeLimitedCache<>(10 * 3600, TimeUnit.SECONDS); private String restUrl; - private String musicFolderId; + private String cachedMusicFolderId; public CachedMusicService(MusicService musicService) { @@ -372,7 +372,7 @@ public class CachedMusicService implements MusicService { String newUrl = activeServerProvider.getValue().getRestUrl(null); String newFolderId = activeServerProvider.getValue().getActiveServer().getMusicFolderId(); - if (!Util.equals(newUrl, restUrl) || !Util.equals(musicFolderId,newFolderId)) + if (!Util.equals(newUrl, restUrl) || !Util.equals(cachedMusicFolderId,newFolderId)) { cachedMusicFolders.clear(); cachedMusicDirectories.clear(); @@ -384,7 +384,7 @@ public class CachedMusicService implements MusicService cachedArtist.clear(); cachedUserInfo.clear(); restUrl = newUrl; - musicFolderId = newFolderId; + cachedMusicFolderId = newFolderId; } } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ArtistRowAdapter.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ArtistRowAdapter.kt index 40d439ff..6a56e1d2 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ArtistRowAdapter.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ArtistRowAdapter.kt @@ -43,7 +43,6 @@ import org.moire.ultrasonic.view.SelectMusicFolderView */ class ArtistRowAdapter( private var artistList: List, - private var folderName: String, private var selectFolderHeader: SelectMusicFolderView?, val onArtistClick: (Artist) -> Unit, val onContextMenuClick: (MenuItem, Artist) -> Boolean, @@ -58,14 +57,6 @@ class ArtistRowAdapter( notifyDataSetChanged() } - /** - * Sets the name of the folder to be displayed n the Header (first) row - */ - fun setFolderName(name: String) { - folderName = name - notifyDataSetChanged() - } - /** * Holds the view properties of an Artist row */ diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt index 2d0da70f..7a25a207 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt @@ -1,6 +1,8 @@ package org.moire.ultrasonic.fragment import android.os.Bundle +import android.os.Handler +import android.os.Looper import android.view.ContextMenu import android.view.ContextMenu.ContextMenuInfo import android.view.LayoutInflater @@ -16,6 +18,9 @@ import android.widget.ImageView import android.widget.ListView import android.widget.TextView import androidx.fragment.app.Fragment +import androidx.lifecycle.MutableLiveData +import androidx.lifecycle.Observer +import androidx.lifecycle.viewModelScope import androidx.navigation.Navigation import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener @@ -23,6 +28,9 @@ import java.security.SecureRandom import java.util.Collections import java.util.LinkedList import java.util.Random +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.koin.android.ext.android.inject import org.koin.android.viewmodel.ext.android.viewModel import org.moire.ultrasonic.R @@ -30,8 +38,10 @@ import org.moire.ultrasonic.api.subsonic.models.AlbumListType import org.moire.ultrasonic.data.ActiveServerProvider import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline import org.moire.ultrasonic.domain.MusicDirectory +import org.moire.ultrasonic.domain.MusicFolder import org.moire.ultrasonic.fragment.FragmentTitle.Companion.getTitle import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle +import org.moire.ultrasonic.service.CommunicationErrorHandler import org.moire.ultrasonic.service.MediaPlayerController import org.moire.ultrasonic.service.MusicService import org.moire.ultrasonic.service.MusicServiceFactory @@ -81,6 +91,7 @@ class SelectAlbumFragment : Fragment() { private var showHeader = true private var showSelectFolderHeader = false private val random: Random = SecureRandom() + private val musicFolders: MutableLiveData> = MutableLiveData() private val mediaPlayerController: MediaPlayerController by inject() private val videoPlayer: VideoPlayer by inject() @@ -128,11 +139,7 @@ class SelectAlbumFragment : Fragment() { selectFolderHeader = SelectMusicFolderView( requireContext(), albumListView!!, - MusicServiceFactory.getMusicService(requireContext()).getMusicFolders( - false, requireContext() - ), - activeServerProvider.getActiveServer().musicFolderId, - { _, selectedFolderId -> + { selectedFolderId -> if (!ActiveServerProvider.isOffline(context)) { val currentSetting = activeServerProvider.getActiveServer() currentSetting.musicFolderId = selectedFolderId @@ -141,6 +148,17 @@ class SelectAlbumFragment : Fragment() { this.updateDisplay(true) } ) + musicFolders.observe( + viewLifecycleOwner, + Observer { changedFolders -> + if (changedFolders != null) { + selectFolderHeader!!.setData( + activeServerProvider.getActiveServer().musicFolderId, + changedFolders + ) + } + } + ) albumListView!!.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE) albumListView!!.setOnItemClickListener( @@ -294,6 +312,8 @@ class SelectAlbumFragment : Fragment() { Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 ) + backgroundLoadMusicFolders(refresh) + if (playlistId != null) { getPlaylist(playlistId, playlistName) } else if (podcastChannelId != null) { @@ -323,6 +343,29 @@ class SelectAlbumFragment : Fragment() { } } + private fun backgroundLoadMusicFolders(refresh: Boolean) { + serverSettingsModel.viewModelScope.launch { + refreshAlbumListView!!.isRefreshing = true + loadMusicFolders(refresh) + refreshAlbumListView!!.isRefreshing = false + } + } + + private suspend fun loadMusicFolders(refresh: Boolean) { + withContext(Dispatchers.IO) { + if (!isOffline(context)) { + val musicService = MusicServiceFactory.getMusicService(requireContext()) + try { + musicFolders.postValue(musicService.getMusicFolders(refresh, context)) + } catch (exception: Exception) { + Handler(Looper.getMainLooper()).post { + CommunicationErrorHandler.handleError(exception, requireContext()) + } + } + } + } + } + override fun onCreateContextMenu(menu: ContextMenu, view: View, menuInfo: ContextMenuInfo?) { super.onCreateContextMenu(menu, view, menuInfo) val info = menuInfo as AdapterContextMenuInfo? diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectArtistFragment.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectArtistFragment.kt index 2aba479b..39b2ebac 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectArtistFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectArtistFragment.kt @@ -16,9 +16,7 @@ import org.koin.android.viewmodel.ext.android.viewModel import org.moire.ultrasonic.R import org.moire.ultrasonic.data.ActiveServerProvider import org.moire.ultrasonic.domain.Artist -import org.moire.ultrasonic.domain.MusicFolder import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle -import org.moire.ultrasonic.service.MusicServiceFactory import org.moire.ultrasonic.subsonic.DownloadHandler import org.moire.ultrasonic.subsonic.ImageLoaderProvider import org.moire.ultrasonic.util.Constants @@ -37,7 +35,6 @@ class SelectArtistFragment : Fragment() { private var refreshArtistListView: SwipeRefreshLayout? = null private var artistListView: RecyclerView? = null - private var musicFolders: List? = null private lateinit var viewManager: RecyclerView.LayoutManager private lateinit var viewAdapter: ArtistRowAdapter private var selectFolderHeader: SelectMusicFolderView? = null @@ -67,17 +64,13 @@ class SelectArtistFragment : Fragment() { ) { selectFolderHeader = SelectMusicFolderView( requireContext(), view as ViewGroup, - MusicServiceFactory.getMusicService(requireContext()).getMusicFolders( - false, requireContext() - ), - activeServerProvider.getActiveServer().musicFolderId, - { musicFolderName, selectedFolderId -> + { selectedFolderId -> if (!ActiveServerProvider.isOffline(context)) { val currentSetting = activeServerProvider.getActiveServer() currentSetting.musicFolderId = selectedFolderId serverSettingsModel.updateItem(currentSetting) } - viewAdapter.setFolderName(musicFolderName) + viewAdapter.notifyDataSetChanged() artistListModel.refresh(refreshArtistListView!!) } ) @@ -96,8 +89,6 @@ class SelectArtistFragment : Fragment() { setTitle(this, title) } - musicFolders = null - val refresh = arguments?.getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH) ?: false artistListModel.getMusicFolders() @@ -105,8 +96,11 @@ class SelectArtistFragment : Fragment() { viewLifecycleOwner, Observer { changedFolders -> if (changedFolders != null) { - musicFolders = changedFolders - viewAdapter.setFolderName(getMusicFolderName(changedFolders)) + viewAdapter.notifyDataSetChanged() + selectFolderHeader!!.setData( + activeServerProvider.getActiveServer().musicFolderId, + changedFolders + ) } } ) @@ -119,7 +113,6 @@ class SelectArtistFragment : Fragment() { viewManager = LinearLayoutManager(this.context) viewAdapter = ArtistRowAdapter( artists.value ?: listOf(), - getText(R.string.select_artist_all_folders).toString(), selectFolderHeader, { artist -> onItemClick(artist) }, { menuItem, artist -> onArtistMenuItemSelected(menuItem, artist) }, @@ -134,18 +127,6 @@ class SelectArtistFragment : Fragment() { super.onViewCreated(view, savedInstanceState) } - private fun getMusicFolderName(musicFolders: List): String { - val musicFolderId = activeServerProvider.getActiveServer().musicFolderId - if (musicFolderId != null && musicFolderId != "") { - for ((id, name) in musicFolders) { - if (id == musicFolderId) { - return name - } - } - } - return getText(R.string.select_artist_all_folders).toString() - } - private fun onItemClick(artist: Artist) { val bundle = Bundle() bundle.putString(Constants.INTENT_EXTRA_NAME_ID, artist.id) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/RESTMusicService.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/RESTMusicService.kt index a0226118..8f380d9e 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/RESTMusicService.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/service/RESTMusicService.kt @@ -114,7 +114,9 @@ open class RESTMusicService( refresh: Boolean, context: Context ): Indexes { - val cachedIndexes = fileStorage.load(INDEXES_STORAGE_NAME, getIndexesSerializer()) + val indexName = INDEXES_STORAGE_NAME + (musicFolderId ?: "") + + val cachedIndexes = fileStorage.load(indexName, getIndexesSerializer()) if (cachedIndexes != null && !refresh) return cachedIndexes val response = responseChecker.callWithResponseCheck { api -> @@ -122,7 +124,7 @@ open class RESTMusicService( } val indexes = response.body()!!.indexes.toDomainEntity() - fileStorage.store(INDEXES_STORAGE_NAME, indexes, getIndexesSerializer()) + fileStorage.store(indexName, indexes, getIndexesSerializer()) return indexes } @@ -938,6 +940,7 @@ open class RESTMusicService( companion object { private const val MUSIC_FOLDER_STORAGE_NAME = "music_folder" private const val INDEXES_STORAGE_NAME = "indexes" + private const val INDEXES_FOLDER_STORAGE_NAME = "indexes_folder" private const val ARTISTS_STORAGE_NAME = "artists" } } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/view/SelectMusicFolderView.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/view/SelectMusicFolderView.kt index ea3d77ef..7c2e530a 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/view/SelectMusicFolderView.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/view/SelectMusicFolderView.kt @@ -19,19 +19,26 @@ import org.moire.ultrasonic.domain.MusicFolder class SelectMusicFolderView( private val context: Context, root: ViewGroup, - private val musicFolders: List, - private var selectedFolderId: String?, - private val onUpdate: (String, String?) -> Unit + private val onUpdate: (String?) -> Unit ) : RecyclerView.ViewHolder( LayoutInflater.from(context).inflate( R.layout.select_folder_header, root, false ) ) { + private var musicFolders: List = mutableListOf() + private var selectedFolderId: String? = null private val folderName: TextView = itemView.findViewById(R.id.select_folder_name) private val layout: LinearLayout = itemView.findViewById(R.id.select_folder_header) private val MENU_GROUP_MUSIC_FOLDER = 10 init { + folderName.text = context.getString(R.string.select_artist_all_folders) + layout.setOnClickListener { onFolderClick() } + } + + fun setData(selectedId: String?, folders: List) { + selectedFolderId = selectedId + musicFolders = folders if (selectedFolderId != null) { for ((id, name) in musicFolders) { if (id == selectedFolderId) { @@ -42,7 +49,6 @@ class SelectMusicFolderView( } else { folderName.text = context.getString(R.string.select_artist_all_folders) } - layout.setOnClickListener { onFolderClick() } } private fun onFolderClick() { @@ -76,7 +82,7 @@ class SelectMusicFolderView( menuItem.isChecked = true folderName.text = musicFolderName - onUpdate(musicFolderName, selectedFolderId) + onUpdate(selectedFolderId) return true }