loads music folder list

Signed-off-by: James Wells <james@jameswells.net>
This commit is contained in:
James Wells 2021-04-09 22:41:38 -04:00
parent 580fc1aa89
commit f00a487b51
No known key found for this signature in database
GPG Key ID: 7A9AB99C0B899FB7
6 changed files with 74 additions and 50 deletions

View File

@ -76,7 +76,7 @@ public class CachedMusicService implements MusicService
private final TimeLimitedCache<List<Genre>> cachedGenres = new TimeLimitedCache<>(10 * 3600, TimeUnit.SECONDS); private final TimeLimitedCache<List<Genre>> cachedGenres = new TimeLimitedCache<>(10 * 3600, TimeUnit.SECONDS);
private String restUrl; private String restUrl;
private String musicFolderId; private String cachedMusicFolderId;
public CachedMusicService(MusicService musicService) public CachedMusicService(MusicService musicService)
{ {
@ -372,7 +372,7 @@ public class CachedMusicService implements MusicService
{ {
String newUrl = activeServerProvider.getValue().getRestUrl(null); String newUrl = activeServerProvider.getValue().getRestUrl(null);
String newFolderId = activeServerProvider.getValue().getActiveServer().getMusicFolderId(); 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(); cachedMusicFolders.clear();
cachedMusicDirectories.clear(); cachedMusicDirectories.clear();
@ -384,7 +384,7 @@ public class CachedMusicService implements MusicService
cachedArtist.clear(); cachedArtist.clear();
cachedUserInfo.clear(); cachedUserInfo.clear();
restUrl = newUrl; restUrl = newUrl;
musicFolderId = newFolderId; cachedMusicFolderId = newFolderId;
} }
} }

View File

@ -43,7 +43,6 @@ import org.moire.ultrasonic.view.SelectMusicFolderView
*/ */
class ArtistRowAdapter( class ArtistRowAdapter(
private var artistList: List<Artist>, private var artistList: List<Artist>,
private var folderName: String,
private var selectFolderHeader: SelectMusicFolderView?, private var selectFolderHeader: SelectMusicFolderView?,
val onArtistClick: (Artist) -> Unit, val onArtistClick: (Artist) -> Unit,
val onContextMenuClick: (MenuItem, Artist) -> Boolean, val onContextMenuClick: (MenuItem, Artist) -> Boolean,
@ -58,14 +57,6 @@ class ArtistRowAdapter(
notifyDataSetChanged() 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 * Holds the view properties of an Artist row
*/ */

View File

@ -1,6 +1,8 @@
package org.moire.ultrasonic.fragment package org.moire.ultrasonic.fragment
import android.os.Bundle import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.ContextMenu import android.view.ContextMenu
import android.view.ContextMenu.ContextMenuInfo import android.view.ContextMenu.ContextMenuInfo
import android.view.LayoutInflater import android.view.LayoutInflater
@ -16,6 +18,9 @@ import android.widget.ImageView
import android.widget.ListView import android.widget.ListView
import android.widget.TextView import android.widget.TextView
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.viewModelScope
import androidx.navigation.Navigation import androidx.navigation.Navigation
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
@ -23,6 +28,9 @@ import java.security.SecureRandom
import java.util.Collections import java.util.Collections
import java.util.LinkedList import java.util.LinkedList
import java.util.Random 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.ext.android.inject
import org.koin.android.viewmodel.ext.android.viewModel import org.koin.android.viewmodel.ext.android.viewModel
import org.moire.ultrasonic.R 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
import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline
import org.moire.ultrasonic.domain.MusicDirectory 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.getTitle
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle 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.MediaPlayerController
import org.moire.ultrasonic.service.MusicService import org.moire.ultrasonic.service.MusicService
import org.moire.ultrasonic.service.MusicServiceFactory import org.moire.ultrasonic.service.MusicServiceFactory
@ -81,6 +91,7 @@ class SelectAlbumFragment : Fragment() {
private var showHeader = true private var showHeader = true
private var showSelectFolderHeader = false private var showSelectFolderHeader = false
private val random: Random = SecureRandom() private val random: Random = SecureRandom()
private val musicFolders: MutableLiveData<List<MusicFolder>> = MutableLiveData()
private val mediaPlayerController: MediaPlayerController by inject() private val mediaPlayerController: MediaPlayerController by inject()
private val videoPlayer: VideoPlayer by inject() private val videoPlayer: VideoPlayer by inject()
@ -128,11 +139,7 @@ class SelectAlbumFragment : Fragment() {
selectFolderHeader = SelectMusicFolderView( selectFolderHeader = SelectMusicFolderView(
requireContext(), albumListView!!, requireContext(), albumListView!!,
MusicServiceFactory.getMusicService(requireContext()).getMusicFolders( { selectedFolderId ->
false, requireContext()
),
activeServerProvider.getActiveServer().musicFolderId,
{ _, selectedFolderId ->
if (!ActiveServerProvider.isOffline(context)) { if (!ActiveServerProvider.isOffline(context)) {
val currentSetting = activeServerProvider.getActiveServer() val currentSetting = activeServerProvider.getActiveServer()
currentSetting.musicFolderId = selectedFolderId currentSetting.musicFolderId = selectedFolderId
@ -141,6 +148,17 @@ class SelectAlbumFragment : Fragment() {
this.updateDisplay(true) this.updateDisplay(true)
} }
) )
musicFolders.observe(
viewLifecycleOwner,
Observer { changedFolders ->
if (changedFolders != null) {
selectFolderHeader!!.setData(
activeServerProvider.getActiveServer().musicFolderId,
changedFolders
)
}
}
)
albumListView!!.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE) albumListView!!.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE)
albumListView!!.setOnItemClickListener( albumListView!!.setOnItemClickListener(
@ -294,6 +312,8 @@ class SelectAlbumFragment : Fragment() {
Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0
) )
backgroundLoadMusicFolders(refresh)
if (playlistId != null) { if (playlistId != null) {
getPlaylist(playlistId, playlistName) getPlaylist(playlistId, playlistName)
} else if (podcastChannelId != null) { } 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?) { override fun onCreateContextMenu(menu: ContextMenu, view: View, menuInfo: ContextMenuInfo?) {
super.onCreateContextMenu(menu, view, menuInfo) super.onCreateContextMenu(menu, view, menuInfo)
val info = menuInfo as AdapterContextMenuInfo? val info = menuInfo as AdapterContextMenuInfo?

View File

@ -16,9 +16,7 @@ import org.koin.android.viewmodel.ext.android.viewModel
import org.moire.ultrasonic.R import org.moire.ultrasonic.R
import org.moire.ultrasonic.data.ActiveServerProvider import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.domain.Artist import org.moire.ultrasonic.domain.Artist
import org.moire.ultrasonic.domain.MusicFolder
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle 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.DownloadHandler
import org.moire.ultrasonic.subsonic.ImageLoaderProvider import org.moire.ultrasonic.subsonic.ImageLoaderProvider
import org.moire.ultrasonic.util.Constants import org.moire.ultrasonic.util.Constants
@ -37,7 +35,6 @@ class SelectArtistFragment : Fragment() {
private var refreshArtistListView: SwipeRefreshLayout? = null private var refreshArtistListView: SwipeRefreshLayout? = null
private var artistListView: RecyclerView? = null private var artistListView: RecyclerView? = null
private var musicFolders: List<MusicFolder>? = null
private lateinit var viewManager: RecyclerView.LayoutManager private lateinit var viewManager: RecyclerView.LayoutManager
private lateinit var viewAdapter: ArtistRowAdapter private lateinit var viewAdapter: ArtistRowAdapter
private var selectFolderHeader: SelectMusicFolderView? = null private var selectFolderHeader: SelectMusicFolderView? = null
@ -67,17 +64,13 @@ class SelectArtistFragment : Fragment() {
) { ) {
selectFolderHeader = SelectMusicFolderView( selectFolderHeader = SelectMusicFolderView(
requireContext(), view as ViewGroup, requireContext(), view as ViewGroup,
MusicServiceFactory.getMusicService(requireContext()).getMusicFolders( { selectedFolderId ->
false, requireContext()
),
activeServerProvider.getActiveServer().musicFolderId,
{ musicFolderName, selectedFolderId ->
if (!ActiveServerProvider.isOffline(context)) { if (!ActiveServerProvider.isOffline(context)) {
val currentSetting = activeServerProvider.getActiveServer() val currentSetting = activeServerProvider.getActiveServer()
currentSetting.musicFolderId = selectedFolderId currentSetting.musicFolderId = selectedFolderId
serverSettingsModel.updateItem(currentSetting) serverSettingsModel.updateItem(currentSetting)
} }
viewAdapter.setFolderName(musicFolderName) viewAdapter.notifyDataSetChanged()
artistListModel.refresh(refreshArtistListView!!) artistListModel.refresh(refreshArtistListView!!)
} }
) )
@ -96,8 +89,6 @@ class SelectArtistFragment : Fragment() {
setTitle(this, title) setTitle(this, title)
} }
musicFolders = null
val refresh = arguments?.getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH) ?: false val refresh = arguments?.getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH) ?: false
artistListModel.getMusicFolders() artistListModel.getMusicFolders()
@ -105,8 +96,11 @@ class SelectArtistFragment : Fragment() {
viewLifecycleOwner, viewLifecycleOwner,
Observer { changedFolders -> Observer { changedFolders ->
if (changedFolders != null) { if (changedFolders != null) {
musicFolders = changedFolders viewAdapter.notifyDataSetChanged()
viewAdapter.setFolderName(getMusicFolderName(changedFolders)) selectFolderHeader!!.setData(
activeServerProvider.getActiveServer().musicFolderId,
changedFolders
)
} }
} }
) )
@ -119,7 +113,6 @@ class SelectArtistFragment : Fragment() {
viewManager = LinearLayoutManager(this.context) viewManager = LinearLayoutManager(this.context)
viewAdapter = ArtistRowAdapter( viewAdapter = ArtistRowAdapter(
artists.value ?: listOf(), artists.value ?: listOf(),
getText(R.string.select_artist_all_folders).toString(),
selectFolderHeader, selectFolderHeader,
{ artist -> onItemClick(artist) }, { artist -> onItemClick(artist) },
{ menuItem, artist -> onArtistMenuItemSelected(menuItem, artist) }, { menuItem, artist -> onArtistMenuItemSelected(menuItem, artist) },
@ -134,18 +127,6 @@ class SelectArtistFragment : Fragment() {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
} }
private fun getMusicFolderName(musicFolders: List<MusicFolder>): 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) { private fun onItemClick(artist: Artist) {
val bundle = Bundle() val bundle = Bundle()
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, artist.id) bundle.putString(Constants.INTENT_EXTRA_NAME_ID, artist.id)

View File

@ -114,7 +114,9 @@ open class RESTMusicService(
refresh: Boolean, refresh: Boolean,
context: Context context: Context
): Indexes { ): 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 if (cachedIndexes != null && !refresh) return cachedIndexes
val response = responseChecker.callWithResponseCheck { api -> val response = responseChecker.callWithResponseCheck { api ->
@ -122,7 +124,7 @@ open class RESTMusicService(
} }
val indexes = response.body()!!.indexes.toDomainEntity() val indexes = response.body()!!.indexes.toDomainEntity()
fileStorage.store(INDEXES_STORAGE_NAME, indexes, getIndexesSerializer()) fileStorage.store(indexName, indexes, getIndexesSerializer())
return indexes return indexes
} }
@ -938,6 +940,7 @@ open class RESTMusicService(
companion object { companion object {
private const val MUSIC_FOLDER_STORAGE_NAME = "music_folder" private const val MUSIC_FOLDER_STORAGE_NAME = "music_folder"
private const val INDEXES_STORAGE_NAME = "indexes" private const val INDEXES_STORAGE_NAME = "indexes"
private const val INDEXES_FOLDER_STORAGE_NAME = "indexes_folder"
private const val ARTISTS_STORAGE_NAME = "artists" private const val ARTISTS_STORAGE_NAME = "artists"
} }
} }

View File

@ -19,19 +19,26 @@ import org.moire.ultrasonic.domain.MusicFolder
class SelectMusicFolderView( class SelectMusicFolderView(
private val context: Context, private val context: Context,
root: ViewGroup, root: ViewGroup,
private val musicFolders: List<MusicFolder>, private val onUpdate: (String?) -> Unit
private var selectedFolderId: String?,
private val onUpdate: (String, String?) -> Unit
) : RecyclerView.ViewHolder( ) : RecyclerView.ViewHolder(
LayoutInflater.from(context).inflate( LayoutInflater.from(context).inflate(
R.layout.select_folder_header, root, false R.layout.select_folder_header, root, false
) )
) { ) {
private var musicFolders: List<MusicFolder> = mutableListOf<MusicFolder>()
private var selectedFolderId: String? = null
private val folderName: TextView = itemView.findViewById(R.id.select_folder_name) private val folderName: TextView = itemView.findViewById(R.id.select_folder_name)
private val layout: LinearLayout = itemView.findViewById(R.id.select_folder_header) private val layout: LinearLayout = itemView.findViewById(R.id.select_folder_header)
private val MENU_GROUP_MUSIC_FOLDER = 10 private val MENU_GROUP_MUSIC_FOLDER = 10
init { init {
folderName.text = context.getString(R.string.select_artist_all_folders)
layout.setOnClickListener { onFolderClick() }
}
fun setData(selectedId: String?, folders: List<MusicFolder>) {
selectedFolderId = selectedId
musicFolders = folders
if (selectedFolderId != null) { if (selectedFolderId != null) {
for ((id, name) in musicFolders) { for ((id, name) in musicFolders) {
if (id == selectedFolderId) { if (id == selectedFolderId) {
@ -42,7 +49,6 @@ class SelectMusicFolderView(
} else { } else {
folderName.text = context.getString(R.string.select_artist_all_folders) folderName.text = context.getString(R.string.select_artist_all_folders)
} }
layout.setOnClickListener { onFolderClick() }
} }
private fun onFolderClick() { private fun onFolderClick() {
@ -76,7 +82,7 @@ class SelectMusicFolderView(
menuItem.isChecked = true menuItem.isChecked = true
folderName.text = musicFolderName folderName.text = musicFolderName
onUpdate(musicFolderName, selectedFolderId) onUpdate(selectedFolderId)
return true return true
} }