From 1f57fb334be87432a892bfb8ee38af11a982b94b Mon Sep 17 00:00:00 2001 From: tzugen Date: Wed, 21 Apr 2021 21:55:55 +0200 Subject: [PATCH 01/11] Refactor: LoadTask to Coroutines. --- .../fragment/SelectAlbumFragment.kt | 902 ++++++++++-------- 1 file changed, 482 insertions(+), 420 deletions(-) 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 6a9043aa..bcffa810 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt @@ -18,16 +18,13 @@ import android.widget.ImageView import android.widget.ListView import android.widget.TextView import androidx.fragment.app.Fragment +import androidx.lifecycle.LifecycleOwner 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 -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 @@ -44,7 +41,6 @@ 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 import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService import org.moire.ultrasonic.subsonic.DownloadHandler import org.moire.ultrasonic.subsonic.ImageLoaderProvider @@ -62,6 +58,10 @@ import org.moire.ultrasonic.view.EntryAdapter import org.moire.ultrasonic.view.SelectMusicFolderView import org.moire.ultrasonic.view.SongView import timber.log.Timber +import java.security.SecureRandom +import java.util.Collections +import java.util.LinkedList +import java.util.Random /** * Displays a group of playable media from the library, which can be an Album, a Playlist, etc. @@ -91,7 +91,15 @@ class SelectAlbumFragment : Fragment() { private var showHeader = true private var showSelectFolderHeader = false private val random: Random = SecureRandom() + + private val musicFolders: MutableLiveData> = MutableLiveData() + private val artists: MutableLiveData = MutableLiveData() + private val albumList: MutableLiveData = MutableLiveData() + private val currentDirectory: MutableLiveData = MutableLiveData() + private val songsForGenre: MutableLiveData = MutableLiveData() + private var currentDirectoryIsSortable = true + private val mediaPlayerController: MediaPlayerController by inject() private val videoPlayer: VideoPlayer by inject() @@ -148,17 +156,11 @@ class SelectAlbumFragment : Fragment() { this.updateDisplay(true) } ) - musicFolders.observe( - viewLifecycleOwner, - Observer { changedFolders -> - if (changedFolders != null) { - selectFolderHeader!!.setData( - activeServerProvider.getActiveServer().musicFolderId, - changedFolders - ) - } - } - ) + + musicFolders.observe(viewLifecycleOwner, musicFolderObserver) + currentDirectory.observe(viewLifecycleOwner, defaultObserver) + songsForGenre.observe(viewLifecycleOwner, songsForGenreObserver) + albumList.observe(viewLifecycleOwner, albumListObserver) albumListView!!.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE) albumListView!!.setOnItemClickListener( @@ -312,59 +314,69 @@ class SelectAlbumFragment : Fragment() { Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 ) - backgroundLoadMusicFolders(refresh) - if (playlistId != null) { - getPlaylist(playlistId, playlistName) - } else if (podcastChannelId != null) { - getPodcastEpisodes(podcastChannelId) - } else if (shareId != null) { - getShare(shareId, shareName) - } else if (albumListType != null) { - getAlbumList(albumListType, albumListTitle, albumListSize, albumListOffset) - } else if (genreName != null) { - getSongsForGenre(genreName, albumListSize, albumListOffset) - } else if (getStarredTracks != 0) { - starred - } else if (getVideos != 0) { - getVideos(refresh) - } else if (getRandomTracks != 0) { - getRandom(albumListSize) - } else { - if (!isOffline(activity) && Util.getShouldUseId3Tags(activity)) { - if (isAlbum) { - getAlbum(refresh, id, name, parentId) - } else { - getArtist(refresh, id, name) - } - } else { - getMusicDirectory(refresh, id, name, parentId) - } - } + triggerLoad(refresh, id, name, playlistId, playlistName, podcastChannelId, shareId, shareName, albumListType, albumListTitle, albumListSize, albumListOffset, genreName, getStarredTracks, getVideos, getRandomTracks, isAlbum, parentId) + + } - private fun backgroundLoadMusicFolders(refresh: Boolean) { + private fun triggerLoad( + refresh: Boolean, + id: String?, + name: String?, + playlistId: String?, + playlistName: String?, + podcastChannelId: String?, + shareId: String?, + shareName: String?, + albumListType: String?, + albumListTitle: Int, + albumListSize: Int, + albumListOffset: Int, + genreName: String?, + getStarredTracks: Int, + getVideos: Int, + getRandomTracks: Int, + isAlbum: Boolean, + parentId: String? + ) { serverSettingsModel.viewModelScope.launch { refreshAlbumListView!!.isRefreshing = true - loadMusicFolders(refresh) + + this@SelectAlbumFragment.getMusicFolders(refresh) + + if (playlistId != null) { + this@SelectAlbumFragment.getPlaylist(playlistId, playlistName) + } else if (podcastChannelId != null) { + this@SelectAlbumFragment.getPodcastEpisodes(podcastChannelId) + } else if (shareId != null) { + this@SelectAlbumFragment.getShare(shareId, shareName) + } else if (albumListType != null) { + this@SelectAlbumFragment.getAlbumList(albumListType, albumListTitle, albumListSize, albumListOffset) + } else if (genreName != null) { + this@SelectAlbumFragment.getSongsForGenre(genreName, albumListSize, albumListOffset) + } else if (getStarredTracks != 0) { + this@SelectAlbumFragment.getStarred() + } else if (getVideos != 0) { + this@SelectAlbumFragment.getVideos(refresh) + } else if (getRandomTracks != 0) { + this@SelectAlbumFragment.getRandom(albumListSize) + } else { + if (!isOffline(activity) && Util.getShouldUseId3Tags(activity)) { + if (isAlbum) { + this@SelectAlbumFragment.getAlbum(refresh, id, name, parentId) + } else { + this@SelectAlbumFragment.getArtist(refresh, id, name) + } + } else { + this@SelectAlbumFragment.getMusicDirectory(refresh, id, name, parentId) + } + } + 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) @@ -523,11 +535,52 @@ class SelectAlbumFragment : Fragment() { } } - private fun getMusicDirectory(refresh: Boolean, id: String?, name: String?, parentId: String?) { + + private suspend fun getMusicFolders(refresh: Boolean) { + withContext(Dispatchers.IO) { + if (!isOffline(context)) { + val musicService = getMusicService(requireContext()) + try { + musicFolders.postValue(musicService.getMusicFolders(refresh, context)) + } catch (exception: Exception) { + Handler(Looper.getMainLooper()).post { + CommunicationErrorHandler.handleError(exception, requireContext()) + } + } + } + } + } + + private suspend fun getMusicDirectory(refresh: Boolean, id: String?, name: String?, parentId: String?) { setTitle(this, name) - object : LoadTask() { - override fun load(service: MusicService): MusicDirectory { + withContext(Dispatchers.IO) { + if (!isOffline(context)) { + val service = getMusicService(requireContext()) + + fun getSongsRecursively( + parent: MusicDirectory, + songs: MutableList + ) { + for (song in parent.getChildren(false, true)) { + if (!song.isVideo && !song.isDirectory) { + songs.add(song) + } + } + + + for ((id1, _, _, title) in parent.getChildren(true, false)) { + var root: MusicDirectory + + if (allSongsId != id1) { + root = service.getMusicDirectory(id1, title, false, context) + + getSongsRecursively(root, songs) + } + } + } + + var root = MusicDirectory() if (allSongsId == id) { @@ -565,39 +618,19 @@ class SelectAlbumFragment : Fragment() { root = musicDirectory } } - return root + + currentDirectory.postValue(root) } - private fun getSongsRecursively( - parent: MusicDirectory, - songs: MutableList - ) { - for (song in parent.getChildren(false, true)) { - if (!song.isVideo && !song.isDirectory) { - songs.add(song) - } - } - - val musicService = getMusicService(context!!) - - for ((id1, _, _, title) in parent.getChildren(true, false)) { - var root: MusicDirectory - - if (allSongsId != id1) { - root = musicService.getMusicDirectory(id1, title, false, context) - - getSongsRecursively(root, songs) - } - } - } - }.execute() + } } - private fun getArtist(refresh: Boolean, id: String?, name: String?) { + private suspend fun getArtist(refresh: Boolean, id: String?, name: String?) { setTitle(this, name) - object : LoadTask() { - override fun load(service: MusicService): MusicDirectory { + withContext(Dispatchers.IO) { + if (!isOffline(context)) { + val service = getMusicService(requireContext()) var root = MusicDirectory() @@ -623,16 +656,18 @@ class SelectAlbumFragment : Fragment() { } else { root = musicDirectory } - return root + currentDirectory.postValue(root) } - }.execute() + } } - private fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?) { + private suspend fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?) { setTitle(this, name) - object : LoadTask() { - override fun load(service: MusicService): MusicDirectory { + withContext(Dispatchers.IO) { + if (!isOffline(context)) { + + val service = getMusicService(requireContext()) val musicDirectory: MusicDirectory @@ -640,7 +675,19 @@ class SelectAlbumFragment : Fragment() { val root = MusicDirectory() val songs: MutableCollection = LinkedList() - getSongsForArtist(parentId, songs) + val artist = service.getArtist(parentId, "", false, context) + + for ((id1) in artist.getChildren()) { + if (allSongsId != id1) { + val albumDirectory = service.getAlbum(id1, "", false, context) + + for (song in albumDirectory.getChildren()) { + if (!song.isVideo) { + songs.add(song) + } + } + } + } for (song in songs) { if (!song.isDirectory) { @@ -651,156 +698,131 @@ class SelectAlbumFragment : Fragment() { } else { service.getAlbum(id, name, refresh, context) } - return musicDirectory + currentDirectory.postValue(musicDirectory); } - private fun getSongsForArtist( - id: String?, - songs: MutableCollection - ) { - - val musicService = getMusicService(context!!) - val artist = musicService.getArtist(id, "", false, context) - - for ((id1) in artist.getChildren()) { - if (allSongsId != id1) { - val albumDirectory = musicService.getAlbum(id1, "", false, context) - - for (song in albumDirectory.getChildren()) { - if (!song.isVideo) { - songs.add(song) - } - } - } - } - } - }.execute() + } } - private fun getSongsForGenre(genre: String, count: Int, offset: Int) { + private suspend fun getSongsForGenre(genre: String, count: Int, offset: Int) { setTitle(this, genre) - object : LoadTask() { - override fun load(service: MusicService): MusicDirectory { - return service.getSongsByGenre(genre, count, offset, context) + withContext(Dispatchers.IO) { + if (!isOffline(context)) { + val service = getMusicService(requireContext()) + val musicDirectory: MusicDirectory + musicDirectory = service.getSongsByGenre(genre, count, offset, context) + songsForGenre.postValue(musicDirectory) } - - override fun done(result: Pair) { - // Hide more button when results are less than album list size - if (result.first.getChildren().size < arguments!!.getInt( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0 - ) - ) { - moreButton!!.visibility = View.GONE - } else { - moreButton!!.visibility = View.VISIBLE - } - - moreButton!!.setOnClickListener { - val theGenre = arguments!!.getString(Constants.INTENT_EXTRA_NAME_GENRE_NAME) - val size = arguments!!.getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0) - val theOffset = arguments!!.getInt( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 - ) + size - val bundle = Bundle() - bundle.putString(Constants.INTENT_EXTRA_NAME_GENRE_NAME, theGenre) - bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, size) - bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, theOffset) - Navigation.findNavController(view!!).navigate(R.id.selectAlbumFragment, bundle) - } - - super.done(result) - } - }.execute() - } - - private val starred: Unit - get() { - setTitle(this, R.string.main_songs_starred) - - object : LoadTask() { - override fun load(service: MusicService): MusicDirectory { - return if (Util.getShouldUseId3Tags(context)) - Util.getSongsFromSearchResult(service.getStarred2(context)) - else - Util.getSongsFromSearchResult(service.getStarred(context)) - } - }.execute() } - private fun getVideos(refresh: Boolean) { + } + + private suspend fun getStarred() { + setTitle(this, R.string.main_songs_starred) + + withContext(Dispatchers.IO) { + if (!isOffline(context)) { + + val service = getMusicService(requireContext()) + val musicDirectory: MusicDirectory + val context = requireContext() + + if (Util.getShouldUseId3Tags(context)) { + musicDirectory = Util.getSongsFromSearchResult(service.getStarred2(context)) + + } else { + musicDirectory = Util.getSongsFromSearchResult(service.getStarred(context)) + } + + currentDirectory.postValue(musicDirectory) + } + } + } + + private suspend fun getVideos(refresh: Boolean) { showHeader = false setTitle(this, R.string.main_videos) - object : LoadTask() { - override fun load(service: MusicService): MusicDirectory { - return service.getVideos(refresh, context) + withContext(Dispatchers.IO) { + if (!isOffline(context)) { + val service = getMusicService(requireContext()) + currentDirectory.postValue(service.getVideos(refresh, context)) } - }.execute() + } } - private fun getRandom(size: Int) { + private suspend fun getRandom(size: Int) { setTitle(this, R.string.main_songs_random) - object : LoadTask() { - override fun sortableCollection(): Boolean { - return false - } + withContext(Dispatchers.IO) { + if (!isOffline(context)) { + val service = getMusicService(requireContext()) + val musicDirectory = service.getRandomSongs(size, context) - override fun load(service: MusicService): MusicDirectory { - return service.getRandomSongs(size, context) + currentDirectoryIsSortable = false + currentDirectory.postValue(musicDirectory) } - }.execute() + } } - private fun getPlaylist(playlistId: String, playlistName: String?) { + private suspend fun getPlaylist(playlistId: String, playlistName: String?) { setTitle(this, playlistName) - object : LoadTask() { - override fun load(service: MusicService): MusicDirectory { - return service.getPlaylist(playlistId, playlistName, context) + withContext(Dispatchers.IO) { + if (!isOffline(context)) { + val service = getMusicService(requireContext()) + val musicDirectory: MusicDirectory + musicDirectory = service.getPlaylist(playlistId, playlistName, context) + + currentDirectory.postValue(musicDirectory) } - }.execute() + } } - private fun getPodcastEpisodes(podcastChannelId: String) { + private suspend fun getPodcastEpisodes(podcastChannelId: String) { setTitle(this, R.string.podcasts_label) - object : LoadTask() { - override fun load(service: MusicService): MusicDirectory { - return service.getPodcastEpisodes(podcastChannelId, context) + withContext(Dispatchers.IO) { + if (!isOffline(context)) { + val service = getMusicService(requireContext()) + val musicDirectory: MusicDirectory + musicDirectory = service.getPodcastEpisodes(podcastChannelId, context) + currentDirectory.postValue(musicDirectory) } - }.execute() + } } - private fun getShare(shareId: String, shareName: CharSequence?) { + private suspend fun getShare(shareId: String, shareName: CharSequence?) { setTitle(this, shareName) // setActionBarSubtitle(shareName); - object : LoadTask() { - override fun load(service: MusicService): MusicDirectory { + withContext(Dispatchers.IO) { + if (!isOffline(context)) { + val service = getMusicService(requireContext()) + val musicDirectory = MusicDirectory() + val shares = service.getShares(true, context) - val md = MusicDirectory() for (share in shares) { if (share.id == shareId) { for (entry in share.getEntries()) { - md.addChild(entry) + musicDirectory.addChild(entry) } break } } - return md + currentDirectory.postValue(musicDirectory) } - }.execute() + } } - private fun getAlbumList(albumListType: String, albumListTitle: Int, size: Int, offset: Int) { + private suspend fun getAlbumList(albumListType: String, albumListTitle: Int, size: Int, offset: Int) { showHeader = false showSelectFolderHeader = !isOffline(context) && !Util.getShouldUseId3Tags(context) && @@ -812,72 +834,35 @@ class SelectAlbumFragment : Fragment() { setTitle(this, albumListTitle) // setActionBarSubtitle(albumListTitle); - object : LoadTask() { - override fun sortableCollection(): Boolean { - return albumListType != "newest" && albumListType != "random" && + + fun sortableCollection(): Boolean { + return albumListType != "newest" && albumListType != "random" && albumListType != "highest" && albumListType != "recent" && albumListType != "frequent" - } + } - override fun load(service: MusicService): MusicDirectory { + + withContext(Dispatchers.IO) { + if (!isOffline(context)) { + val service = getMusicService(requireContext()) + val musicDirectory: MusicDirectory val musicFolderId = if (showSelectFolderHeader) { this@SelectAlbumFragment.activeServerProvider.getActiveServer().musicFolderId } else { null } - return if (Util.getShouldUseId3Tags(context)) - service.getAlbumList2(albumListType, size, offset, musicFolderId, context) - else - service.getAlbumList(albumListType, size, offset, musicFolderId, context) - } - override fun done(result: Pair) { - if (!result.first.getChildren().isEmpty()) { - pinButton!!.visibility = View.GONE - unpinButton!!.visibility = View.GONE - downloadButton!!.visibility = View.GONE - deleteButton!!.visibility = View.GONE - - // Hide more button when results are less than album list size - if (result.first.getChildren().size < arguments!!.getInt( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0 - ) - ) { - moreButton!!.visibility = View.GONE - } else { - moreButton!!.visibility = View.VISIBLE - moreButton!!.setOnClickListener { - val theAlbumListTitle = arguments!!.getInt( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, 0 - ) - val type = arguments!!.getString( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE - ) - val theSize = arguments!!.getInt( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0 - ) - val theOffset = arguments!!.getInt( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 - ) + theSize - - val bundle = Bundle() - bundle.putInt( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, theAlbumListTitle - ) - bundle.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type) - bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, theSize) - bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, theOffset) - Navigation.findNavController(view!!).navigate( - R.id.selectAlbumFragment, bundle - ) - } - } + if (Util.getShouldUseId3Tags(context)) { + musicDirectory = service.getAlbumList2(albumListType, size, offset, musicFolderId, context) } else { - moreButton!!.visibility = View.GONE + musicDirectory = service.getAlbumList(albumListType, size, offset, musicFolderId, context) } - super.done(result) + + currentDirectoryIsSortable = sortableCollection() + albumList.postValue(musicDirectory) + } - }.execute() + } } private fun selectAllOrNone() { @@ -1009,214 +994,291 @@ class SelectAlbumFragment : Fragment() { mediaPlayerController.unpin(songs) } - private abstract inner class LoadTask : FragmentBackgroundTask>( - this@SelectAlbumFragment.activity, true, refreshAlbumListView, - cancellationToken - ) { + val albumListObserver = Observer { musicDirectory -> + if (!musicDirectory.getChildren().isEmpty()) { + pinButton!!.visibility = View.GONE + unpinButton!!.visibility = View.GONE + downloadButton!!.visibility = View.GONE + deleteButton!!.visibility = View.GONE - protected abstract fun load(service: MusicService): MusicDirectory - protected open fun sortableCollection(): Boolean { - return true - } + // Hide more button when results are less than album list size + if (musicDirectory.getChildren().size < requireArguments().getInt( + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0 + ) + ) { + moreButton!!.visibility = View.GONE + } else { + moreButton!!.visibility = View.VISIBLE + moreButton!!.setOnClickListener { + val theAlbumListTitle = requireArguments().getInt( + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, 0 + ) + val type = requireArguments().getString( + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE + ) + val theSize = requireArguments().getInt( + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0 + ) + val theOffset = requireArguments().getInt( + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 + ) + theSize - override fun doInBackground(): Pair { - val musicService = getMusicService(context!!) - val dir = load(musicService) - val valid = musicService.isLicenseValid(context) - return Pair(dir, valid) - } - - protected override fun done(result: Pair) { - val musicDirectory = result.first - val entries = musicDirectory.getChildren() - - if (sortableCollection() && Util.getShouldSortByDisc(context)) { - Collections.sort(entries, EntryByDiscAndTrackComparator()) - } - - var allVideos = true - var songCount = 0 - - for (entry in entries) { - if (!entry.isVideo) { - allVideos = false - } - if (!entry.isDirectory) { - songCount++ + val bundle = Bundle() + bundle.putInt( + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, theAlbumListTitle + ) + bundle.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type) + bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, theSize) + bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, theOffset) + Navigation.findNavController(requireView()).navigate( + R.id.selectAlbumFragment, bundle + ) } } + } else { + moreButton!!.visibility = View.GONE + } - val listSize = arguments!!.getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0) + updateInterfaceWithEntries(musicDirectory) + } - if (songCount > 0) { - if (showHeader) { - val intentAlbumName = arguments!!.getString(Constants.INTENT_EXTRA_NAME_NAME) - val directoryName = musicDirectory.name - val header = createHeader( + val musicFolderObserver = Observer> { changedFolders -> + if (changedFolders != null) { + selectFolderHeader!!.setData( + activeServerProvider.getActiveServer().musicFolderId, + changedFolders + ) + } + } + + val songsForGenreObserver = Observer { musicDirectory -> + + // Hide more button when results are less than album list size + if (musicDirectory.getChildren().size < requireArguments().getInt( + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0 + ) + ) { + moreButton!!.visibility = View.GONE + } else { + moreButton!!.visibility = View.VISIBLE + } + + moreButton!!.setOnClickListener { + val theGenre = requireArguments().getString(Constants.INTENT_EXTRA_NAME_GENRE_NAME) + val size = requireArguments().getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0) + val theOffset = requireArguments().getInt( + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 + ) + size + val bundle = Bundle() + bundle.putString(Constants.INTENT_EXTRA_NAME_GENRE_NAME, theGenre) + bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, size) + bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, theOffset) + Navigation.findNavController(requireView()).navigate(R.id.selectAlbumFragment, bundle) + } + + updateInterfaceWithEntries(musicDirectory) + } + + // Our old "done" function + val defaultObserver = Observer(this::updateInterfaceWithEntries) + + private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory) { + val entries = musicDirectory.getChildren() + + // FIXME + if (sortableCollection() && Util.getShouldSortByDisc(context)) { + Collections.sort(entries, EntryByDiscAndTrackComparator()) + } + + var allVideos = true + var songCount = 0 + + for (entry in entries) { + if (!entry.isVideo) { + allVideos = false + } + if (!entry.isDirectory) { + songCount++ + } + } + + val listSize = requireArguments().getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0) + + if (songCount > 0) { + if (showHeader) { + val intentAlbumName = requireArguments().getString(Constants.INTENT_EXTRA_NAME_NAME) + val directoryName = musicDirectory.name + val header = createHeader( entries, intentAlbumName ?: directoryName, songCount - ) - if (header != null && albumListView!!.headerViewsCount == 0) { - albumListView!!.addHeaderView(header, null, false) - } - } - - pinButton!!.visibility = View.VISIBLE - unpinButton!!.visibility = View.VISIBLE - downloadButton!!.visibility = View.VISIBLE - deleteButton!!.visibility = View.VISIBLE - selectButton!!.visibility = if (allVideos) View.GONE else View.VISIBLE - playNowButton!!.visibility = View.VISIBLE - playNextButton!!.visibility = View.VISIBLE - playLastButton!!.visibility = View.VISIBLE - - if (listSize == 0 || songCount < listSize) { - moreButton!!.visibility = View.GONE - } else { - moreButton!!.visibility = View.VISIBLE - if (arguments!!.getInt(Constants.INTENT_EXTRA_NAME_RANDOM, 0) > 0) { - moreButton!!.setOnClickListener { - val offset = arguments!!.getInt( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 - ) + listSize - val bundle = Bundle() - bundle.putInt(Constants.INTENT_EXTRA_NAME_RANDOM, 1) - bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, listSize) - bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, offset) - Navigation.findNavController(view!!).navigate( - R.id.selectAlbumFragment, bundle - ) - } - } - } - } else { - if (showSelectFolderHeader) { - if (albumListView!!.headerViewsCount == 0) { - albumListView!!.addHeaderView(selectFolderHeader!!.itemView, null, false) - } - } - - pinButton!!.visibility = View.GONE - unpinButton!!.visibility = View.GONE - downloadButton!!.visibility = View.GONE - deleteButton!!.visibility = View.GONE - selectButton!!.visibility = View.GONE - playNowButton!!.visibility = View.GONE - playNextButton!!.visibility = View.GONE - playLastButton!!.visibility = View.GONE - - if (listSize == 0 || result.first.getChildren().size < listSize) { - albumButtons!!.visibility = View.GONE - } else { - moreButton!!.visibility = View.VISIBLE - } - } - - enableButtons() - - val isAlbumList = arguments!!.containsKey(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE) - playAllButtonVisible = !(isAlbumList || entries.isEmpty()) && !allVideos - shareButtonVisible = !isOffline(context) && songCount > 0 - - albumListView!!.removeHeaderView(emptyView!!) - if (entries.isEmpty()) { - emptyView!!.text = "No Media Found" - emptyView!!.setPadding(10, 10, 10, 10) - albumListView!!.addHeaderView(emptyView, null, false) - } - - if (playAllButton != null) { - playAllButton!!.isVisible = playAllButtonVisible - } - - if (shareButton != null) { - shareButton!!.isVisible = shareButtonVisible - } - - albumListView!!.adapter = EntryAdapter( - context, - imageLoaderProvider.getImageLoader(), entries, true - ) - - val playAll = arguments!!.getBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false) - if (playAll && songCount > 0) { - playAll( - arguments!!.getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, false), - false ) + if (header != null && albumListView!!.headerViewsCount == 0) { + albumListView!!.addHeaderView(header, null, false) + } + } + + pinButton!!.visibility = View.VISIBLE + unpinButton!!.visibility = View.VISIBLE + downloadButton!!.visibility = View.VISIBLE + deleteButton!!.visibility = View.VISIBLE + selectButton!!.visibility = if (allVideos) View.GONE else View.VISIBLE + playNowButton!!.visibility = View.VISIBLE + playNextButton!!.visibility = View.VISIBLE + playLastButton!!.visibility = View.VISIBLE + + if (listSize == 0 || songCount < listSize) { + moreButton!!.visibility = View.GONE + } else { + moreButton!!.visibility = View.VISIBLE + if (requireArguments().getInt(Constants.INTENT_EXTRA_NAME_RANDOM, 0) > 0) { + moreButton!!.setOnClickListener { + val offset = requireArguments().getInt( + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 + ) + listSize + val bundle = Bundle() + bundle.putInt(Constants.INTENT_EXTRA_NAME_RANDOM, 1) + bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, listSize) + bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, offset) + Navigation.findNavController(requireView()).navigate( + R.id.selectAlbumFragment, bundle + ) + } + } + } + } else { + if (showSelectFolderHeader) { + if (albumListView!!.headerViewsCount == 0) { + albumListView!!.addHeaderView(selectFolderHeader!!.itemView, null, false) + } + } + + pinButton!!.visibility = View.GONE + unpinButton!!.visibility = View.GONE + downloadButton!!.visibility = View.GONE + deleteButton!!.visibility = View.GONE + selectButton!!.visibility = View.GONE + playNowButton!!.visibility = View.GONE + playNextButton!!.visibility = View.GONE + playLastButton!!.visibility = View.GONE + + if (listSize == 0 || musicDirectory.getChildren().size < listSize) { + albumButtons!!.visibility = View.GONE + } else { + moreButton!!.visibility = View.VISIBLE } } - protected fun createHeader( + enableButtons() + + val isAlbumList = requireArguments().containsKey(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE) + playAllButtonVisible = !(isAlbumList || entries.isEmpty()) && !allVideos + shareButtonVisible = !isOffline(context) && songCount > 0 + + albumListView!!.removeHeaderView(emptyView!!) + if (entries.isEmpty()) { + emptyView!!.text = "No Media Found" + emptyView!!.setPadding(10, 10, 10, 10) + albumListView!!.addHeaderView(emptyView, null, false) + } + + if (playAllButton != null) { + playAllButton!!.isVisible = playAllButtonVisible + } + + if (shareButton != null) { + shareButton!!.isVisible = shareButtonVisible + } + + albumListView!!.adapter = EntryAdapter( + context, + imageLoaderProvider.getImageLoader(), entries, true + ) + + val playAll = requireArguments().getBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false) + if (playAll && songCount > 0) { + playAll( + requireArguments().getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, false), + false + ) + } + + currentDirectoryIsSortable = true + } + + protected fun createHeader( entries: List, name: CharSequence?, songCount: Int - ): View? { - val coverArtView = header!!.findViewById(R.id.select_album_art) as ImageView - val artworkSelection = random.nextInt(entries.size) - imageLoaderProvider.getImageLoader().loadImage( + ): View? { + val coverArtView = header!!.findViewById(R.id.select_album_art) as ImageView + val artworkSelection = random.nextInt(entries.size) + imageLoaderProvider.getImageLoader().loadImage( coverArtView, entries[artworkSelection], false, Util.getAlbumImageSize(context), false, true - ) + ) - val albumHeader = AlbumHeader.processEntries(context, entries) + val albumHeader = AlbumHeader.processEntries(context, entries) - val titleView = header!!.findViewById(R.id.select_album_title) as TextView - titleView.text = name ?: getTitle(this@SelectAlbumFragment) // getActionBarSubtitle()); + val titleView = header!!.findViewById(R.id.select_album_title) as TextView + titleView.text = name ?: getTitle(this@SelectAlbumFragment) // getActionBarSubtitle()); - // Don't show a header if all entries are videos - if (albumHeader.isAllVideo) { - return null - } + // Don't show a header if all entries are videos + if (albumHeader.isAllVideo) { + return null + } - val artistView = header!!.findViewById(R.id.select_album_artist) - val artist: String + val artistView = header!!.findViewById(R.id.select_album_artist) + val artist: String - artist = if (albumHeader.artists.size == 1) - albumHeader.artists.iterator().next() - else if (albumHeader.grandParents.size == 1) - albumHeader.grandParents.iterator().next() - else - resources.getString(R.string.common_various_artists) + artist = if (albumHeader.artists.size == 1) + albumHeader.artists.iterator().next() + else if (albumHeader.grandParents.size == 1) + albumHeader.grandParents.iterator().next() + else + resources.getString(R.string.common_various_artists) - artistView.text = artist + artistView.text = artist - val genreView = header!!.findViewById(R.id.select_album_genre) - val genre: String + val genreView = header!!.findViewById(R.id.select_album_genre) + val genre: String - genre = if (albumHeader.genres.size == 1) - albumHeader.genres.iterator().next() - else - resources.getString(R.string.common_multiple_genres) + genre = if (albumHeader.genres.size == 1) + albumHeader.genres.iterator().next() + else + resources.getString(R.string.common_multiple_genres) - genreView.text = genre + genreView.text = genre - val yearView = header!!.findViewById(R.id.select_album_year) - val year: String + val yearView = header!!.findViewById(R.id.select_album_year) + val year: String - year = if (albumHeader.years.size == 1) - albumHeader.years.iterator().next().toString() - else - resources.getString(R.string.common_multiple_years) + year = if (albumHeader.years.size == 1) + albumHeader.years.iterator().next().toString() + else + resources.getString(R.string.common_multiple_years) - yearView.text = year + yearView.text = year - val songCountView = header!!.findViewById(R.id.select_album_song_count) - val songs = resources.getQuantityString( + val songCountView = header!!.findViewById(R.id.select_album_song_count) + val songs = resources.getQuantityString( R.plurals.select_album_n_songs, songCount, songCount - ) - songCountView.text = songs + ) + songCountView.text = songs - val duration = Util.formatTotalDuration(albumHeader.totalDuration) + val duration = Util.formatTotalDuration(albumHeader.totalDuration) - val durationView = header!!.findViewById(R.id.select_album_duration) - durationView.text = duration + val durationView = header!!.findViewById(R.id.select_album_duration) + durationView.text = duration - return header - } + return header } + private fun sortableCollection(): Boolean { + return currentDirectoryIsSortable + } + + private fun getSelectedSongs(albumListView: ListView?): List { val songs: MutableList = ArrayList(10) From fa4f4d6c9c2fc9f56e793124459c0848de0ea65f Mon Sep 17 00:00:00 2001 From: tzugen Date: Wed, 21 Apr 2021 22:31:56 +0200 Subject: [PATCH 02/11] Move loading functions into ViewModel --- .../fragment/SelectAlbumFragment.kt | 426 ++---------------- .../ultrasonic/fragment/SelectAlbumModel.kt | 358 +++++++++++++++ 2 files changed, 404 insertions(+), 380 deletions(-) create mode 100644 ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumModel.kt 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 bcffa810..d6abd826 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt @@ -1,8 +1,13 @@ +/* + * SelectAlbumFragment.kt + * Copyright (C) 2009-2021 Ultrasonic developers + * + * Distributed under terms of the GNU GPLv3 license. + */ + 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 @@ -18,30 +23,23 @@ import android.widget.ImageView import android.widget.ListView import android.widget.TextView import androidx.fragment.app.Fragment -import androidx.lifecycle.LifecycleOwner -import androidx.lifecycle.MutableLiveData +import androidx.fragment.app.viewModels import androidx.lifecycle.Observer import androidx.lifecycle.viewModelScope import androidx.navigation.Navigation import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener -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 -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.getMusicService import org.moire.ultrasonic.subsonic.DownloadHandler import org.moire.ultrasonic.subsonic.ImageLoaderProvider import org.moire.ultrasonic.subsonic.NetworkAndStorageChecker @@ -51,7 +49,6 @@ import org.moire.ultrasonic.util.AlbumHeader import org.moire.ultrasonic.util.CancellationToken import org.moire.ultrasonic.util.Constants import org.moire.ultrasonic.util.EntryByDiscAndTrackComparator -import org.moire.ultrasonic.util.FragmentBackgroundTask import org.moire.ultrasonic.util.Util import org.moire.ultrasonic.view.AlbumView import org.moire.ultrasonic.view.EntryAdapter @@ -60,7 +57,6 @@ import org.moire.ultrasonic.view.SongView import timber.log.Timber import java.security.SecureRandom import java.util.Collections -import java.util.LinkedList import java.util.Random /** @@ -68,7 +64,6 @@ import java.util.Random */ class SelectAlbumFragment : Fragment() { - private val allSongsId = "-1" private var refreshAlbumListView: SwipeRefreshLayout? = null private var albumListView: ListView? = null private var header: View? = null @@ -88,18 +83,6 @@ class SelectAlbumFragment : Fragment() { private var shareButtonVisible = false private var playAllButton: MenuItem? = null private var shareButton: MenuItem? = null - private var showHeader = true - private var showSelectFolderHeader = false - private val random: Random = SecureRandom() - - - private val musicFolders: MutableLiveData> = MutableLiveData() - private val artists: MutableLiveData = MutableLiveData() - private val albumList: MutableLiveData = MutableLiveData() - private val currentDirectory: MutableLiveData = MutableLiveData() - private val songsForGenre: MutableLiveData = MutableLiveData() - private var currentDirectoryIsSortable = true - private val mediaPlayerController: MediaPlayerController by inject() private val videoPlayer: VideoPlayer by inject() @@ -111,6 +94,11 @@ class SelectAlbumFragment : Fragment() { private val activeServerProvider: ActiveServerProvider by inject() private val serverSettingsModel: ServerSettingsModel by viewModel() + private val model: SelectAlbumModel by viewModels() + + + private val random: Random = SecureRandom() + override fun onCreate(savedInstanceState: Bundle?) { Util.applyTheme(this.context) super.onCreate(savedInstanceState) @@ -157,10 +145,10 @@ class SelectAlbumFragment : Fragment() { } ) - musicFolders.observe(viewLifecycleOwner, musicFolderObserver) - currentDirectory.observe(viewLifecycleOwner, defaultObserver) - songsForGenre.observe(viewLifecycleOwner, songsForGenreObserver) - albumList.observe(viewLifecycleOwner, albumListObserver) + model.musicFolders.observe(viewLifecycleOwner, musicFolderObserver) + model.currentDirectory.observe(viewLifecycleOwner, defaultObserver) + model.songsForGenre.observe(viewLifecycleOwner, songsForGenreObserver) + model.albumList.observe(viewLifecycleOwner, albumListObserver) albumListView!!.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE) albumListView!!.setOnItemClickListener( @@ -314,10 +302,8 @@ class SelectAlbumFragment : Fragment() { Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 ) - triggerLoad(refresh, id, name, playlistId, playlistName, podcastChannelId, shareId, shareName, albumListType, albumListTitle, albumListSize, albumListOffset, genreName, getStarredTracks, getVideos, getRandomTracks, isAlbum, parentId) - } private fun triggerLoad( @@ -343,33 +329,42 @@ class SelectAlbumFragment : Fragment() { serverSettingsModel.viewModelScope.launch { refreshAlbumListView!!.isRefreshing = true - this@SelectAlbumFragment.getMusicFolders(refresh) + model.getMusicFolders(refresh) if (playlistId != null) { - this@SelectAlbumFragment.getPlaylist(playlistId, playlistName) + setTitle(playlistName) + model.getPlaylist(playlistId, playlistName) } else if (podcastChannelId != null) { - this@SelectAlbumFragment.getPodcastEpisodes(podcastChannelId) + setTitle(getString(R.string.podcasts_label)) + model.getPodcastEpisodes(podcastChannelId) } else if (shareId != null) { - this@SelectAlbumFragment.getShare(shareId, shareName) + setTitle(shareName) + model.getShare(shareId, shareName) } else if (albumListType != null) { - this@SelectAlbumFragment.getAlbumList(albumListType, albumListTitle, albumListSize, albumListOffset) + setTitle(this@SelectAlbumFragment, albumListTitle) + model.getAlbumList(albumListType, albumListSize, albumListOffset) } else if (genreName != null) { - this@SelectAlbumFragment.getSongsForGenre(genreName, albumListSize, albumListOffset) + setTitle(genreName) + model.getSongsForGenre(genreName, albumListSize, albumListOffset) } else if (getStarredTracks != 0) { - this@SelectAlbumFragment.getStarred() + setTitle(getString(R.string.main_songs_starred)) + model.getStarred() } else if (getVideos != 0) { - this@SelectAlbumFragment.getVideos(refresh) + setTitle(this@SelectAlbumFragment, R.string.main_videos) + model.getVideos(refresh) } else if (getRandomTracks != 0) { - this@SelectAlbumFragment.getRandom(albumListSize) + setTitle(this@SelectAlbumFragment, R.string.main_songs_random) + model.getRandom(albumListSize) } else { + setTitle(name) if (!isOffline(activity) && Util.getShouldUseId3Tags(activity)) { if (isAlbum) { - this@SelectAlbumFragment.getAlbum(refresh, id, name, parentId) + model.getAlbum(refresh, id, name, parentId) } else { - this@SelectAlbumFragment.getArtist(refresh, id, name) + model.getArtist(refresh, id, name) } } else { - this@SelectAlbumFragment.getMusicDirectory(refresh, id, name, parentId) + model.getMusicDirectory(refresh, id, name, parentId) } } @@ -377,6 +372,10 @@ class SelectAlbumFragment : Fragment() { } } + private fun setTitle(name: String?) { + setTitle(this@SelectAlbumFragment, name) + } + override fun onCreateContextMenu(menu: ContextMenu, view: View, menuInfo: ContextMenuInfo?) { super.onCreateContextMenu(menu, view, menuInfo) @@ -536,334 +535,6 @@ class SelectAlbumFragment : Fragment() { } - private suspend fun getMusicFolders(refresh: Boolean) { - withContext(Dispatchers.IO) { - if (!isOffline(context)) { - val musicService = getMusicService(requireContext()) - try { - musicFolders.postValue(musicService.getMusicFolders(refresh, context)) - } catch (exception: Exception) { - Handler(Looper.getMainLooper()).post { - CommunicationErrorHandler.handleError(exception, requireContext()) - } - } - } - } - } - - private suspend fun getMusicDirectory(refresh: Boolean, id: String?, name: String?, parentId: String?) { - setTitle(this, name) - - withContext(Dispatchers.IO) { - if (!isOffline(context)) { - val service = getMusicService(requireContext()) - - fun getSongsRecursively( - parent: MusicDirectory, - songs: MutableList - ) { - for (song in parent.getChildren(false, true)) { - if (!song.isVideo && !song.isDirectory) { - songs.add(song) - } - } - - - for ((id1, _, _, title) in parent.getChildren(true, false)) { - var root: MusicDirectory - - if (allSongsId != id1) { - root = service.getMusicDirectory(id1, title, false, context) - - getSongsRecursively(root, songs) - } - } - } - - - var root = MusicDirectory() - - if (allSongsId == id) { - val musicDirectory = service.getMusicDirectory(parentId, name, refresh, context) - - val songs: MutableList = LinkedList() - getSongsRecursively(musicDirectory, songs) - - for (song in songs) { - if (!song.isDirectory) { - root.addChild(song) - } - } - } else { - val musicDirectory = service.getMusicDirectory(id, name, refresh, context) - - if (Util.getShouldShowAllSongsByArtist(context) && - musicDirectory.findChild(allSongsId) == null && - musicDirectory.getChildren(true, false).size == - musicDirectory.getChildren(true, true).size - ) { - val allSongs = MusicDirectory.Entry() - - allSongs.isDirectory = true - allSongs.artist = name - allSongs.parent = id - allSongs.id = allSongsId - allSongs.title = String.format( - resources.getString(R.string.select_album_all_songs), name - ) - - root.addChild(allSongs) - root.addAll(musicDirectory.getChildren()) - } else { - root = musicDirectory - } - } - - currentDirectory.postValue(root) - } - - } - } - - private suspend fun getArtist(refresh: Boolean, id: String?, name: String?) { - setTitle(this, name) - - withContext(Dispatchers.IO) { - if (!isOffline(context)) { - val service = getMusicService(requireContext()) - - var root = MusicDirectory() - - val musicDirectory = service.getArtist(id, name, refresh, context) - - if (Util.getShouldShowAllSongsByArtist(context) && - musicDirectory.findChild(allSongsId) == null && - musicDirectory.getChildren(true, false).size == - musicDirectory.getChildren(true, true).size - ) { - val allSongs = MusicDirectory.Entry() - - allSongs.isDirectory = true - allSongs.artist = name - allSongs.parent = id - allSongs.id = allSongsId - allSongs.title = String.format( - resources.getString(R.string.select_album_all_songs), name - ) - - root.addFirst(allSongs) - root.addAll(musicDirectory.getChildren()) - } else { - root = musicDirectory - } - currentDirectory.postValue(root) - } - } - } - - private suspend fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?) { - setTitle(this, name) - - withContext(Dispatchers.IO) { - if (!isOffline(context)) { - - val service = getMusicService(requireContext()) - - val musicDirectory: MusicDirectory - - musicDirectory = if (allSongsId == id) { - val root = MusicDirectory() - - val songs: MutableCollection = LinkedList() - val artist = service.getArtist(parentId, "", false, context) - - for ((id1) in artist.getChildren()) { - if (allSongsId != id1) { - val albumDirectory = service.getAlbum(id1, "", false, context) - - for (song in albumDirectory.getChildren()) { - if (!song.isVideo) { - songs.add(song) - } - } - } - } - - for (song in songs) { - if (!song.isDirectory) { - root.addChild(song) - } - } - root - } else { - service.getAlbum(id, name, refresh, context) - } - currentDirectory.postValue(musicDirectory); - } - - } - } - - private suspend fun getSongsForGenre(genre: String, count: Int, offset: Int) { - setTitle(this, genre) - - withContext(Dispatchers.IO) { - if (!isOffline(context)) { - val service = getMusicService(requireContext()) - val musicDirectory: MusicDirectory - musicDirectory = service.getSongsByGenre(genre, count, offset, context) - songsForGenre.postValue(musicDirectory) - } - } - - } - - private suspend fun getStarred() { - setTitle(this, R.string.main_songs_starred) - - withContext(Dispatchers.IO) { - if (!isOffline(context)) { - - val service = getMusicService(requireContext()) - val musicDirectory: MusicDirectory - val context = requireContext() - - if (Util.getShouldUseId3Tags(context)) { - musicDirectory = Util.getSongsFromSearchResult(service.getStarred2(context)) - - } else { - musicDirectory = Util.getSongsFromSearchResult(service.getStarred(context)) - } - - currentDirectory.postValue(musicDirectory) - } - } - } - - private suspend fun getVideos(refresh: Boolean) { - showHeader = false - - setTitle(this, R.string.main_videos) - - withContext(Dispatchers.IO) { - if (!isOffline(context)) { - val service = getMusicService(requireContext()) - currentDirectory.postValue(service.getVideos(refresh, context)) - } - } - } - - private suspend fun getRandom(size: Int) { - setTitle(this, R.string.main_songs_random) - - withContext(Dispatchers.IO) { - if (!isOffline(context)) { - val service = getMusicService(requireContext()) - val musicDirectory = service.getRandomSongs(size, context) - - currentDirectoryIsSortable = false - currentDirectory.postValue(musicDirectory) - } - } - } - - private suspend fun getPlaylist(playlistId: String, playlistName: String?) { - - setTitle(this, playlistName) - - withContext(Dispatchers.IO) { - if (!isOffline(context)) { - val service = getMusicService(requireContext()) - val musicDirectory: MusicDirectory - musicDirectory = service.getPlaylist(playlistId, playlistName, context) - - currentDirectory.postValue(musicDirectory) - } - } - } - - private suspend fun getPodcastEpisodes(podcastChannelId: String) { - - setTitle(this, R.string.podcasts_label) - - withContext(Dispatchers.IO) { - if (!isOffline(context)) { - val service = getMusicService(requireContext()) - val musicDirectory: MusicDirectory - musicDirectory = service.getPodcastEpisodes(podcastChannelId, context) - currentDirectory.postValue(musicDirectory) - } - } - } - - private suspend fun getShare(shareId: String, shareName: CharSequence?) { - - setTitle(this, shareName) - // setActionBarSubtitle(shareName); - - withContext(Dispatchers.IO) { - if (!isOffline(context)) { - val service = getMusicService(requireContext()) - val musicDirectory = MusicDirectory() - - val shares = service.getShares(true, context) - - - for (share in shares) { - if (share.id == shareId) { - for (entry in share.getEntries()) { - musicDirectory.addChild(entry) - } - break - } - } - currentDirectory.postValue(musicDirectory) - } - } - } - - private suspend fun getAlbumList(albumListType: String, albumListTitle: Int, size: Int, offset: Int) { - - showHeader = false - showSelectFolderHeader = !isOffline(context) && !Util.getShouldUseId3Tags(context) && - ( - (albumListType == AlbumListType.SORTED_BY_NAME.toString()) || - (albumListType == AlbumListType.SORTED_BY_ARTIST.toString()) - ) - - setTitle(this, albumListTitle) - // setActionBarSubtitle(albumListTitle); - - - fun sortableCollection(): Boolean { - return albumListType != "newest" && albumListType != "random" && - albumListType != "highest" && albumListType != "recent" && - albumListType != "frequent" - } - - - withContext(Dispatchers.IO) { - if (!isOffline(context)) { - val service = getMusicService(requireContext()) - val musicDirectory: MusicDirectory - val musicFolderId = if (showSelectFolderHeader) { - this@SelectAlbumFragment.activeServerProvider.getActiveServer().musicFolderId - } else { - null - } - - if (Util.getShouldUseId3Tags(context)) { - musicDirectory = service.getAlbumList2(albumListType, size, offset, musicFolderId, context) - } else { - musicDirectory = service.getAlbumList(albumListType, size, offset, musicFolderId, context) - } - - currentDirectoryIsSortable = sortableCollection() - albumList.postValue(musicDirectory) - - } - } - } private fun selectAllOrNone() { var someUnselected = false @@ -1085,8 +756,7 @@ class SelectAlbumFragment : Fragment() { private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory) { val entries = musicDirectory.getChildren() - // FIXME - if (sortableCollection() && Util.getShouldSortByDisc(context)) { + if (model.currentDirectoryIsSortable && Util.getShouldSortByDisc(context)) { Collections.sort(entries, EntryByDiscAndTrackComparator()) } @@ -1105,7 +775,7 @@ class SelectAlbumFragment : Fragment() { val listSize = requireArguments().getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0) if (songCount > 0) { - if (showHeader) { + if (model.showHeader) { val intentAlbumName = requireArguments().getString(Constants.INTENT_EXTRA_NAME_NAME) val directoryName = musicDirectory.name val header = createHeader( @@ -1146,7 +816,7 @@ class SelectAlbumFragment : Fragment() { } } } else { - if (showSelectFolderHeader) { + if (model.showSelectFolderHeader) { if (albumListView!!.headerViewsCount == 0) { albumListView!!.addHeaderView(selectFolderHeader!!.itemView, null, false) } @@ -1202,7 +872,7 @@ class SelectAlbumFragment : Fragment() { ) } - currentDirectoryIsSortable = true + model.currentDirectoryIsSortable = true } protected fun createHeader( @@ -1274,10 +944,6 @@ class SelectAlbumFragment : Fragment() { return header } - private fun sortableCollection(): Boolean { - return currentDirectoryIsSortable - } - private fun getSelectedSongs(albumListView: ListView?): List { val songs: MutableList = ArrayList(10) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumModel.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumModel.kt new file mode 100644 index 00000000..2be09aec --- /dev/null +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumModel.kt @@ -0,0 +1,358 @@ +package org.moire.ultrasonic.fragment + +import android.app.Application +import android.os.Handler +import android.os.Looper +import androidx.lifecycle.AndroidViewModel +import androidx.lifecycle.MutableLiveData +import java.util.LinkedList +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.withContext +import org.koin.core.component.KoinApiExtension +import org.koin.core.component.KoinComponent +import org.koin.core.component.inject +import org.moire.ultrasonic.R +import org.moire.ultrasonic.api.subsonic.models.AlbumListType +import org.moire.ultrasonic.data.ActiveServerProvider +import org.moire.ultrasonic.domain.MusicDirectory +import org.moire.ultrasonic.domain.MusicFolder +import org.moire.ultrasonic.service.CommunicationErrorHandler +import org.moire.ultrasonic.service.MusicServiceFactory +import org.moire.ultrasonic.util.Util + +// TODO: Break up this class into smaller more specific classes, extending a base class if necessary +@KoinApiExtension +class SelectAlbumModel(application: Application) : AndroidViewModel(application), KoinComponent { + + private val context = getApplication().applicationContext + + private val activeServerProvider: ActiveServerProvider by inject() + + private val allSongsId = "-1" + + val musicFolders: MutableLiveData> = MutableLiveData() + val albumList: MutableLiveData = MutableLiveData() + val currentDirectory: MutableLiveData = MutableLiveData() + val songsForGenre: MutableLiveData = MutableLiveData() + + var currentDirectoryIsSortable = true + var showHeader = true + var showSelectFolderHeader = false + + suspend fun getMusicFolders(refresh: Boolean) { + withContext(Dispatchers.IO) { + if (!ActiveServerProvider.isOffline(context)) { + val musicService = MusicServiceFactory.getMusicService(context) + try { + musicFolders.postValue(musicService.getMusicFolders(refresh, context)) + } catch (exception: Exception) { + Handler(Looper.getMainLooper()).post { + CommunicationErrorHandler.handleError(exception, context) + } + } + } + } + } + + suspend fun getMusicDirectory( + refresh: Boolean, + id: String?, + name: String?, + parentId: String? + ) { + withContext(Dispatchers.IO) { + if (!ActiveServerProvider.isOffline(context)) { + val service = MusicServiceFactory.getMusicService(context) + + var root = MusicDirectory() + + if (allSongsId == id) { + val musicDirectory = service.getMusicDirectory( + parentId, name, refresh, context + ) + + val songs: MutableList = LinkedList() + getSongsRecursively(musicDirectory, songs) + + for (song in songs) { + if (!song.isDirectory) { + root.addChild(song) + } + } + } else { + val musicDirectory = service.getMusicDirectory(id, name, refresh, context) + + if (Util.getShouldShowAllSongsByArtist(context) && + musicDirectory.findChild(allSongsId) == null && + hasOnlyFolders(musicDirectory) + ) { + val allSongs = MusicDirectory.Entry() + + allSongs.isDirectory = true + allSongs.artist = name + allSongs.parent = id + allSongs.id = allSongsId + allSongs.title = String.format( + context.resources.getString(R.string.select_album_all_songs), name + ) + + root.addChild(allSongs) + root.addAll(musicDirectory.getChildren()) + } else { + root = musicDirectory + } + } + + currentDirectory.postValue(root) + } + } + } + + // Given a Music directory "songs" it recursively adds all children to "songs" + private fun getSongsRecursively( + parent: MusicDirectory, + songs: MutableList + ) { + val service = MusicServiceFactory.getMusicService(context) + + for (song in parent.getChildren(includeDirs = false, includeFiles = true)) { + if (!song.isVideo && !song.isDirectory) { + songs.add(song) + } + } + + for ((id1, _, _, title) in parent.getChildren(true, includeFiles = false)) { + var root: MusicDirectory + + if (allSongsId != id1) { + root = service.getMusicDirectory(id1, title, false, context) + + getSongsRecursively(root, songs) + } + } + } + + suspend fun getArtist(refresh: Boolean, id: String?, name: String?) { + + withContext(Dispatchers.IO) { + if (!ActiveServerProvider.isOffline(context)) { + val service = MusicServiceFactory.getMusicService(context) + + var root = MusicDirectory() + + val musicDirectory = service.getArtist(id, name, refresh, context) + + if (Util.getShouldShowAllSongsByArtist(context) && + musicDirectory.findChild(allSongsId) == null && + hasOnlyFolders(musicDirectory) + ) { + val allSongs = MusicDirectory.Entry() + + allSongs.isDirectory = true + allSongs.artist = name + allSongs.parent = id + allSongs.id = allSongsId + allSongs.title = String.format( + context.resources.getString(R.string.select_album_all_songs), name + ) + + root.addFirst(allSongs) + root.addAll(musicDirectory.getChildren()) + } else { + root = musicDirectory + } + currentDirectory.postValue(root) + } + } + } + + suspend fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?) { + + withContext(Dispatchers.IO) { + if (!ActiveServerProvider.isOffline(context)) { + + val service = MusicServiceFactory.getMusicService(context) + + val musicDirectory: MusicDirectory + + musicDirectory = if (allSongsId == id) { + val root = MusicDirectory() + + val songs: MutableCollection = LinkedList() + val artist = service.getArtist(parentId, "", false, context) + + for ((id1) in artist.getChildren()) { + if (allSongsId != id1) { + val albumDirectory = service.getAlbum( + id1, "", false, context + ) + + for (song in albumDirectory.getChildren()) { + if (!song.isVideo) { + songs.add(song) + } + } + } + } + + for (song in songs) { + if (!song.isDirectory) { + root.addChild(song) + } + } + root + } else { + service.getAlbum(id, name, refresh, context) + } + currentDirectory.postValue(musicDirectory) + } + } + } + + suspend fun getSongsForGenre(genre: String, count: Int, offset: Int) { + withContext(Dispatchers.IO) { + if (!ActiveServerProvider.isOffline(context)) { + val service = MusicServiceFactory.getMusicService(context) + val musicDirectory = service.getSongsByGenre(genre, count, offset, context) + songsForGenre.postValue(musicDirectory) + } + } + } + + suspend fun getStarred() { + + withContext(Dispatchers.IO) { + if (!ActiveServerProvider.isOffline(context)) { + + val service = MusicServiceFactory.getMusicService(context) + val musicDirectory: MusicDirectory + val context = context + + if (Util.getShouldUseId3Tags(context)) { + musicDirectory = Util.getSongsFromSearchResult(service.getStarred2(context)) + } else { + musicDirectory = Util.getSongsFromSearchResult(service.getStarred(context)) + } + + currentDirectory.postValue(musicDirectory) + } + } + } + + suspend fun getVideos(refresh: Boolean) { + showHeader = false + + withContext(Dispatchers.IO) { + if (!ActiveServerProvider.isOffline(context)) { + val service = MusicServiceFactory.getMusicService(context) + currentDirectory.postValue(service.getVideos(refresh, context)) + } + } + } + + suspend fun getRandom(size: Int) { + + withContext(Dispatchers.IO) { + if (!ActiveServerProvider.isOffline(context)) { + val service = MusicServiceFactory.getMusicService(context) + val musicDirectory = service.getRandomSongs(size, context) + + currentDirectoryIsSortable = false + currentDirectory.postValue(musicDirectory) + } + } + } + + suspend fun getPlaylist(playlistId: String, playlistName: String?) { + + withContext(Dispatchers.IO) { + if (!ActiveServerProvider.isOffline(context)) { + val service = MusicServiceFactory.getMusicService(context) + val musicDirectory = service.getPlaylist(playlistId, playlistName, context) + + currentDirectory.postValue(musicDirectory) + } + } + } + + suspend fun getPodcastEpisodes(podcastChannelId: String) { + + withContext(Dispatchers.IO) { + if (!ActiveServerProvider.isOffline(context)) { + val service = MusicServiceFactory.getMusicService(context) + val musicDirectory = service.getPodcastEpisodes(podcastChannelId, context) + currentDirectory.postValue(musicDirectory) + } + } + } + + suspend fun getShare(shareId: String, shareName: CharSequence?) { + + withContext(Dispatchers.IO) { + if (!ActiveServerProvider.isOffline(context)) { + val service = MusicServiceFactory.getMusicService(context) + val musicDirectory = MusicDirectory() + + val shares = service.getShares(true, context) + + for (share in shares) { + if (share.id == shareId) { + for (entry in share.getEntries()) { + musicDirectory.addChild(entry) + } + break + } + } + currentDirectory.postValue(musicDirectory) + } + } + } + + suspend fun getAlbumList(albumListType: String, size: Int, offset: Int) { + + showHeader = false + showSelectFolderHeader = !ActiveServerProvider.isOffline(context) && + !Util.getShouldUseId3Tags(context) && ( + (albumListType == AlbumListType.SORTED_BY_NAME.toString()) || + (albumListType == AlbumListType.SORTED_BY_ARTIST.toString()) + ) + + withContext(Dispatchers.IO) { + if (!ActiveServerProvider.isOffline(context)) { + val service = MusicServiceFactory.getMusicService(context) + val musicDirectory: MusicDirectory + val musicFolderId = if (showSelectFolderHeader) { + activeServerProvider.getActiveServer().musicFolderId + } else { + null + } + + if (Util.getShouldUseId3Tags(context)) { + musicDirectory = service.getAlbumList2( + albumListType, size, + offset, musicFolderId, context + ) + } else { + musicDirectory = service.getAlbumList( + albumListType, size, + offset, musicFolderId, context + ) + } + + currentDirectoryIsSortable = sortableCollection(albumListType) + albumList.postValue(musicDirectory) + } + } + } + + private fun sortableCollection(albumListType: String): Boolean { + return albumListType != "newest" && albumListType != "random" && + albumListType != "highest" && albumListType != "recent" && + albumListType != "frequent" + } + + // Returns true if the directory contains only folders + private fun hasOnlyFolders(musicDirectory: MusicDirectory) = + musicDirectory.getChildren(includeDirs = true, includeFiles = false).size == + musicDirectory.getChildren(includeDirs = true, includeFiles = true).size +} From 1802e91fa7cd9504254772a33d0c4174948852ac Mon Sep 17 00:00:00 2001 From: tzugen Date: Wed, 21 Apr 2021 22:36:19 +0200 Subject: [PATCH 03/11] Use lambdas in Listeners, fix various warnings --- .../fragment/SelectAlbumFragment.kt | 203 +++++++----------- 1 file changed, 81 insertions(+), 122 deletions(-) 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 d6abd826..66a27c82 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt @@ -17,8 +17,6 @@ import android.view.MenuItem import android.view.View import android.view.ViewGroup import android.widget.AdapterView.AdapterContextMenuInfo -import android.widget.AdapterView.OnItemClickListener -import android.widget.AdapterView.OnItemLongClickListener import android.widget.ImageView import android.widget.ListView import android.widget.TextView @@ -28,7 +26,6 @@ import androidx.lifecycle.Observer import androidx.lifecycle.viewModelScope import androidx.navigation.Navigation import androidx.swiperefreshlayout.widget.SwipeRefreshLayout -import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener import kotlinx.coroutines.launch import org.koin.android.ext.android.inject import org.koin.android.viewmodel.ext.android.viewModel @@ -121,12 +118,9 @@ class SelectAlbumFragment : Fragment() { refreshAlbumListView = view.findViewById(R.id.select_album_entries_refresh) albumListView = view.findViewById(R.id.select_album_entries_list) - refreshAlbumListView!!.setOnRefreshListener( - OnRefreshListener - { - updateDisplay(true) - } - ) + refreshAlbumListView!!.setOnRefreshListener { + updateDisplay(true) + } header = LayoutInflater.from(context).inflate( R.layout.select_album_header, albumListView, @@ -134,69 +128,61 @@ class SelectAlbumFragment : Fragment() { ) selectFolderHeader = SelectMusicFolderView( - requireContext(), view as ViewGroup, - { selectedFolderId -> - if (!ActiveServerProvider.isOffline(context)) { - val currentSetting = activeServerProvider.getActiveServer() - currentSetting.musicFolderId = selectedFolderId - serverSettingsModel.updateItem(currentSetting) - } - this.updateDisplay(true) + requireContext(), view as ViewGroup + ) { selectedFolderId -> + if (!isOffline(context)) { + val currentSetting = activeServerProvider.getActiveServer() + currentSetting.musicFolderId = selectedFolderId + serverSettingsModel.updateItem(currentSetting) } - ) + this.updateDisplay(true) + } model.musicFolders.observe(viewLifecycleOwner, musicFolderObserver) model.currentDirectory.observe(viewLifecycleOwner, defaultObserver) model.songsForGenre.observe(viewLifecycleOwner, songsForGenreObserver) model.albumList.observe(viewLifecycleOwner, albumListObserver) - albumListView!!.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE) - albumListView!!.setOnItemClickListener( - OnItemClickListener - { parent, theView, position, _ -> - if (position >= 0) { - val entry = parent.getItemAtPosition(position) as MusicDirectory.Entry? - if (entry != null && entry.isDirectory) { - val bundle = Bundle() - bundle.putString(Constants.INTENT_EXTRA_NAME_ID, entry.id) - bundle.putBoolean(Constants.INTENT_EXTRA_NAME_IS_ALBUM, entry.isDirectory) - bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.title) - bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, entry.parent) - Navigation.findNavController(theView).navigate( + albumListView!!.choiceMode = ListView.CHOICE_MODE_MULTIPLE + albumListView!!.setOnItemClickListener { parent, theView, position, _ -> + if (position >= 0) { + val entry = parent.getItemAtPosition(position) as MusicDirectory.Entry? + if (entry != null && entry.isDirectory) { + val bundle = Bundle() + bundle.putString(Constants.INTENT_EXTRA_NAME_ID, entry.id) + bundle.putBoolean(Constants.INTENT_EXTRA_NAME_IS_ALBUM, entry.isDirectory) + bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.title) + bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, entry.parent) + Navigation.findNavController(theView).navigate( R.id.selectAlbumFragment, bundle - ) - } else if (entry != null && entry.isVideo) { - videoPlayer.playVideo(requireContext(), entry) - } else { - enableButtons() - } + ) + } else if (entry != null && entry.isVideo) { + videoPlayer.playVideo(requireContext(), entry) + } else { + enableButtons() } } - ) + } // TODO Long click on an item will first try to maximize / collapse the item, even when it // fits inside the TextView. The context menu is only displayed on the second long click... // This may be improved somehow, e.g. checking first if the texts fit - albumListView!!.setOnItemLongClickListener( - OnItemLongClickListener - { _, theView, _, _ -> - if (theView is AlbumView) { - val albumView = theView - if (!albumView.isMaximized) { - albumView.maximizeOrMinimize() - return@OnItemLongClickListener true - } else { - return@OnItemLongClickListener false - } - } - if (theView is SongView) { + albumListView!!.setOnItemLongClickListener { _, theView, _, _ -> + if (theView is AlbumView) { + if (!theView.isMaximized) { theView.maximizeOrMinimize() - return@OnItemLongClickListener true + true + } else { + false } - false } - ) + if (theView is SongView) { + theView.maximizeOrMinimize() + true + } + false + } selectButton = view.findViewById(R.id.select_album_select) playNowButton = view.findViewById(R.id.select_album_play_now) @@ -209,63 +195,39 @@ class SelectAlbumFragment : Fragment() { moreButton = view.findViewById(R.id.select_album_more) emptyView = TextView(requireContext()) - selectButton!!.setOnClickListener( - View.OnClickListener - { - selectAllOrNone() - } - ) - playNowButton!!.setOnClickListener( - View.OnClickListener - { - playNow(false) - } - ) - playNextButton!!.setOnClickListener( - View.OnClickListener - { - downloadHandler.download( + selectButton!!.setOnClickListener { + selectAllOrNone() + } + playNowButton!!.setOnClickListener { + playNow(false) + } + playNextButton!!.setOnClickListener { + downloadHandler.download( this@SelectAlbumFragment, true, false, false, true, false, getSelectedSongs(albumListView) - ) - selectAll(false, false) - } - ) - playLastButton!!.setOnClickListener( - View.OnClickListener - { - playNow(true) - } - ) - pinButton!!.setOnClickListener( - View.OnClickListener - { - downloadBackground(true) - selectAll(false, false) - } - ) - unpinButton!!.setOnClickListener( - View.OnClickListener - { - unpin() - selectAll(false, false) - } - ) - downloadButton!!.setOnClickListener( - View.OnClickListener - { - downloadBackground(false) - selectAll(false, false) - } - ) - deleteButton!!.setOnClickListener( - View.OnClickListener - { - delete() - selectAll(false, false) - } - ) + ) + selectAll(false, false) + } + playLastButton!!.setOnClickListener { + playNow(true) + } + pinButton!!.setOnClickListener { + downloadBackground(true) + selectAll(false, false) + } + unpinButton!!.setOnClickListener { + unpin() + selectAll(false, false) + } + downloadButton!!.setOnClickListener { + downloadBackground(false) + selectAll(false, false) + } + deleteButton!!.setOnClickListener { + delete() + selectAll(false, false) + } registerForContextMenu(albumListView!!) setHasOptionsMenu(true) @@ -494,7 +456,7 @@ class SelectAlbumFragment : Fragment() { private fun playNow(append: Boolean) { val selectedSongs = getSelectedSongs(albumListView) - if (!selectedSongs.isEmpty()) { + if (selectedSongs.isNotEmpty()) { downloadHandler.download( this, append, false, !append, false, false, selectedSongs @@ -576,7 +538,7 @@ class SelectAlbumFragment : Fragment() { private fun enableButtons() { val selection = getSelectedSongs(albumListView) - val enabled = !selection.isEmpty() + val enabled = selection.isNotEmpty() var unpinEnabled = false var deleteEnabled = false @@ -665,8 +627,8 @@ class SelectAlbumFragment : Fragment() { mediaPlayerController.unpin(songs) } - val albumListObserver = Observer { musicDirectory -> - if (!musicDirectory.getChildren().isEmpty()) { + private val albumListObserver = Observer { musicDirectory -> + if (musicDirectory.getChildren().isNotEmpty()) { pinButton!!.visibility = View.GONE unpinButton!!.visibility = View.GONE downloadButton!!.visibility = View.GONE @@ -713,7 +675,7 @@ class SelectAlbumFragment : Fragment() { updateInterfaceWithEntries(musicDirectory) } - val musicFolderObserver = Observer> { changedFolders -> + private val musicFolderObserver = Observer> { changedFolders -> if (changedFolders != null) { selectFolderHeader!!.setData( activeServerProvider.getActiveServer().musicFolderId, @@ -722,7 +684,7 @@ class SelectAlbumFragment : Fragment() { } } - val songsForGenreObserver = Observer { musicDirectory -> + private val songsForGenreObserver = Observer { musicDirectory -> // Hide more button when results are less than album list size if (musicDirectory.getChildren().size < requireArguments().getInt( @@ -751,7 +713,7 @@ class SelectAlbumFragment : Fragment() { } // Our old "done" function - val defaultObserver = Observer(this::updateInterfaceWithEntries) + private val defaultObserver = Observer(this::updateInterfaceWithEntries) private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory) { val entries = musicDirectory.getChildren() @@ -875,7 +837,7 @@ class SelectAlbumFragment : Fragment() { model.currentDirectoryIsSortable = true } - protected fun createHeader( + private fun createHeader( entries: List, name: CharSequence?, songCount: Int @@ -898,9 +860,8 @@ class SelectAlbumFragment : Fragment() { } val artistView = header!!.findViewById(R.id.select_album_artist) - val artist: String - artist = if (albumHeader.artists.size == 1) + val artist: String = if (albumHeader.artists.size == 1) albumHeader.artists.iterator().next() else if (albumHeader.grandParents.size == 1) albumHeader.grandParents.iterator().next() @@ -910,9 +871,8 @@ class SelectAlbumFragment : Fragment() { artistView.text = artist val genreView = header!!.findViewById(R.id.select_album_genre) - val genre: String - genre = if (albumHeader.genres.size == 1) + val genre: String = if (albumHeader.genres.size == 1) albumHeader.genres.iterator().next() else resources.getString(R.string.common_multiple_genres) @@ -920,9 +880,8 @@ class SelectAlbumFragment : Fragment() { genreView.text = genre val yearView = header!!.findViewById(R.id.select_album_year) - val year: String - year = if (albumHeader.years.size == 1) + val year: String = if (albumHeader.years.size == 1) albumHeader.years.iterator().next().toString() else resources.getString(R.string.common_multiple_years) From dca26f14eb58e27bc7b7174306e84b0704f8b2d3 Mon Sep 17 00:00:00 2001 From: tzugen Date: Wed, 21 Apr 2021 22:42:52 +0200 Subject: [PATCH 04/11] Fix more compiler warnings --- .../fragment/SelectAlbumFragment.kt | 134 +++++++++--------- 1 file changed, 67 insertions(+), 67 deletions(-) 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 66a27c82..f7f08b32 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt @@ -165,23 +165,15 @@ class SelectAlbumFragment : Fragment() { } } - // TODO Long click on an item will first try to maximize / collapse the item, even when it - // fits inside the TextView. The context menu is only displayed on the second long click... - // This may be improved somehow, e.g. checking first if the texts fit albumListView!!.setOnItemLongClickListener { _, theView, _, _ -> if (theView is AlbumView) { - if (!theView.isMaximized) { - theView.maximizeOrMinimize() - true - } else { - false - } + return@setOnItemLongClickListener false } if (theView is SongView) { theView.maximizeOrMinimize() - true + return@setOnItemLongClickListener true } - false + return@setOnItemLongClickListener false } selectButton = view.findViewById(R.id.select_album_select) @@ -203,18 +195,18 @@ class SelectAlbumFragment : Fragment() { } playNextButton!!.setOnClickListener { downloadHandler.download( - this@SelectAlbumFragment, true, - false, false, true, false, - getSelectedSongs(albumListView) + this@SelectAlbumFragment, append = true, + save = false, autoPlay = false, playNext = true, shuffle = false, + songs = getSelectedSongs(albumListView) ) - selectAll(false, false) + selectAll(selected = false, toast = false) } playLastButton!!.setOnClickListener { playNow(true) } pinButton!!.setOnClickListener { downloadBackground(true) - selectAll(false, false) + selectAll(selected = false, toast = false) } unpinButton!!.setOnClickListener { unpin() @@ -371,43 +363,52 @@ class SelectAlbumFragment : Fragment() { val entryId = entry.id - val itemId = menuItem.itemId - if (itemId == R.id.album_menu_play_now) { - downloadHandler.downloadRecursively( - this, entryId, false, false, true, false, false, false, false, false - ) - } else if (itemId == R.id.album_menu_play_next) { - downloadHandler.downloadRecursively( - this, entryId, false, false, false, false, false, true, false, false - ) - } else if (itemId == R.id.album_menu_play_last) { - downloadHandler.downloadRecursively( - this, entryId, false, true, false, false, false, false, false, false - ) - } else if (itemId == R.id.album_menu_pin) { - downloadHandler.downloadRecursively( - this, entryId, true, true, false, false, false, false, false, false - ) - } else if (itemId == R.id.album_menu_unpin) { - downloadHandler.downloadRecursively( - this, entryId, false, false, false, false, false, false, true, false - ) - } else if (itemId == R.id.album_menu_download) { - downloadHandler.downloadRecursively( - this, entryId, false, false, false, false, true, false, false, false - ) - } else if (itemId == R.id.select_album_play_all) { - playAll() - } else if (itemId == R.id.menu_item_share) { - val entries: MutableList = ArrayList(1) - entries.add(entry) - shareHandler.createShare( - this, entries, refreshAlbumListView, - cancellationToken!! - ) - return true - } else { - return super.onContextItemSelected(menuItem) + when (menuItem.itemId) { + R.id.album_menu_play_now -> { + downloadHandler.downloadRecursively( + this, entryId, save = false, append = false, autoPlay = true, shuffle = false, background = false, playNext = false, unpin = false, isArtist = false + ) + } + R.id.album_menu_play_next -> { + downloadHandler.downloadRecursively( + this, entryId, save = false, append = false, autoPlay = false, shuffle = false, background = false, playNext = true, unpin = false, isArtist = false + ) + } + R.id.album_menu_play_last -> { + downloadHandler.downloadRecursively( + this, entryId, save = false, append = true, autoPlay = false, shuffle = false, background = false, playNext = false, unpin = false, isArtist = false + ) + } + R.id.album_menu_pin -> { + downloadHandler.downloadRecursively( + this, entryId, save = true, append = true, autoPlay = false, shuffle = false, background = false, playNext = false, unpin = false, isArtist = false + ) + } + R.id.album_menu_unpin -> { + downloadHandler.downloadRecursively( + this, entryId, save = false, append = false, autoPlay = false, shuffle = false, background = false, playNext = false, unpin = true, isArtist = false + ) + } + R.id.album_menu_download -> { + downloadHandler.downloadRecursively( + this, entryId, save = false, append = false, autoPlay = false, shuffle = false, background = true, playNext = false, unpin = false, isArtist = false + ) + } + R.id.select_album_play_all -> { + playAll() + } + R.id.menu_item_share -> { + val entries: MutableList = ArrayList(1) + entries.add(entry) + shareHandler.createShare( + this, entries, refreshAlbumListView, + cancellationToken!! + ) + return true + } + else -> { + return super.onContextItemSelected(menuItem) + } } return true } @@ -458,10 +459,10 @@ class SelectAlbumFragment : Fragment() { if (selectedSongs.isNotEmpty()) { downloadHandler.download( - this, append, false, !append, false, - false, selectedSongs + this, append, false, !append, playNext = false, + shuffle = false, songs = selectedSongs ) - selectAll(false, false) + selectAll(selected = false, toast = false) } else { playAll(false, append) } @@ -484,15 +485,15 @@ class SelectAlbumFragment : Fragment() { if (hasSubFolders && id != null) { downloadHandler.downloadRecursively( this, id, false, append, !append, - shuffle, false, false, false, isArtist + shuffle, background = false, playNext = false, unpin = false, isArtist = isArtist ) } else { - selectAll(true, false) + selectAll(selected = true, toast = false) downloadHandler.download( this, append, false, !append, false, shuffle, getSelectedSongs(albumListView) ) - selectAll(false, false) + selectAll(selected = false, toast = false) } } @@ -574,7 +575,7 @@ class SelectAlbumFragment : Fragment() { var songs = getSelectedSongs(albumListView) if (songs.isEmpty()) { - selectAll(true, false) + selectAll(selected = true, toast = false) songs = getSelectedSongs(albumListView) } @@ -808,7 +809,7 @@ class SelectAlbumFragment : Fragment() { albumListView!!.removeHeaderView(emptyView!!) if (entries.isEmpty()) { - emptyView!!.text = "No Media Found" + emptyView!!.text = getString(R.string.select_album_empty) emptyView!!.setPadding(10, 10, 10, 10) albumListView!!.addHeaderView(emptyView, null, false) } @@ -861,12 +862,11 @@ class SelectAlbumFragment : Fragment() { val artistView = header!!.findViewById(R.id.select_album_artist) - val artist: String = if (albumHeader.artists.size == 1) - albumHeader.artists.iterator().next() - else if (albumHeader.grandParents.size == 1) - albumHeader.grandParents.iterator().next() - else - resources.getString(R.string.common_various_artists) + val artist: String = when { + albumHeader.artists.size == 1 -> albumHeader.artists.iterator().next() + albumHeader.grandParents.size == 1 -> albumHeader.grandParents.iterator().next() + else -> resources.getString(R.string.common_various_artists) + } artistView.text = artist From 25f072a5d5043e9ee29c81555e43b60947afa955 Mon Sep 17 00:00:00 2001 From: tzugen Date: Wed, 21 Apr 2021 22:55:58 +0200 Subject: [PATCH 05/11] Cleanup some methods + Ktlint WS fixes --- .../fragment/SelectAlbumFragment.kt | 183 +++++++++--------- 1 file changed, 87 insertions(+), 96 deletions(-) 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 f7f08b32..8d9cf740 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt @@ -26,9 +26,12 @@ import androidx.lifecycle.Observer import androidx.lifecycle.viewModelScope import androidx.navigation.Navigation import androidx.swiperefreshlayout.widget.SwipeRefreshLayout +import java.security.SecureRandom +import java.util.Collections +import java.util.Random import kotlinx.coroutines.launch import org.koin.android.ext.android.inject -import org.koin.android.viewmodel.ext.android.viewModel +import org.koin.core.component.KoinApiExtension import org.moire.ultrasonic.R import org.moire.ultrasonic.data.ActiveServerProvider import org.moire.ultrasonic.data.ActiveServerProvider.Companion.isOffline @@ -52,13 +55,12 @@ import org.moire.ultrasonic.view.EntryAdapter import org.moire.ultrasonic.view.SelectMusicFolderView import org.moire.ultrasonic.view.SongView import timber.log.Timber -import java.security.SecureRandom -import java.util.Collections -import java.util.Random /** * Displays a group of playable media from the library, which can be an Album, a Playlist, etc. + * TODO: Break up this class into smaller more specific classes, extending a base class if necessary */ +@KoinApiExtension class SelectAlbumFragment : Fragment() { private var refreshAlbumListView: SwipeRefreshLayout? = null @@ -89,11 +91,10 @@ class SelectAlbumFragment : Fragment() { private val shareHandler: ShareHandler by inject() private var cancellationToken: CancellationToken? = null private val activeServerProvider: ActiveServerProvider by inject() - private val serverSettingsModel: ServerSettingsModel by viewModel() + private val serverSettingsModel: ServerSettingsModel by viewModels() private val model: SelectAlbumModel by viewModels() - private val random: Random = SecureRandom() override fun onCreate(savedInstanceState: Bundle?) { @@ -154,8 +155,8 @@ class SelectAlbumFragment : Fragment() { bundle.putString(Constants.INTENT_EXTRA_NAME_NAME, entry.title) bundle.putString(Constants.INTENT_EXTRA_NAME_PARENT_ID, entry.parent) Navigation.findNavController(theView).navigate( - R.id.selectAlbumFragment, - bundle + R.id.selectAlbumFragment, + bundle ) } else if (entry != null && entry.isVideo) { videoPlayer.playVideo(requireContext(), entry) @@ -167,7 +168,7 @@ class SelectAlbumFragment : Fragment() { albumListView!!.setOnItemLongClickListener { _, theView, _, _ -> if (theView is AlbumView) { - return@setOnItemLongClickListener false + return@setOnItemLongClickListener false } if (theView is SongView) { theView.maximizeOrMinimize() @@ -195,9 +196,9 @@ class SelectAlbumFragment : Fragment() { } playNextButton!!.setOnClickListener { downloadHandler.download( - this@SelectAlbumFragment, append = true, - save = false, autoPlay = false, playNext = true, shuffle = false, - songs = getSelectedSongs(albumListView) + this@SelectAlbumFragment, append = true, + save = false, autoPlay = false, playNext = true, shuffle = false, + songs = getSelectedSongs(albumListView) ) selectAll(selected = false, toast = false) } @@ -210,15 +211,15 @@ class SelectAlbumFragment : Fragment() { } unpinButton!!.setOnClickListener { unpin() - selectAll(false, false) + selectAll(selected = false, toast = false) } downloadButton!!.setOnClickListener { downloadBackground(false) - selectAll(false, false) + selectAll(selected = false, toast = false) } deleteButton!!.setOnClickListener { delete() - selectAll(false, false) + selectAll(selected = false, toast = false) } registerForContextMenu(albumListView!!) @@ -256,30 +257,14 @@ class SelectAlbumFragment : Fragment() { Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 ) - triggerLoad(refresh, id, name, playlistId, playlistName, podcastChannelId, shareId, shareName, albumListType, albumListTitle, albumListSize, albumListOffset, genreName, getStarredTracks, getVideos, getRandomTracks, isAlbum, parentId) + fun setTitle(name: String?) { + setTitle(this@SelectAlbumFragment, name) + } - } + fun setTitle(name: Int) { + setTitle(this@SelectAlbumFragment, name) + } - private fun triggerLoad( - refresh: Boolean, - id: String?, - name: String?, - playlistId: String?, - playlistName: String?, - podcastChannelId: String?, - shareId: String?, - shareName: String?, - albumListType: String?, - albumListTitle: Int, - albumListSize: Int, - albumListOffset: Int, - genreName: String?, - getStarredTracks: Int, - getVideos: Int, - getRandomTracks: Int, - isAlbum: Boolean, - parentId: String? - ) { serverSettingsModel.viewModelScope.launch { refreshAlbumListView!!.isRefreshing = true @@ -295,7 +280,7 @@ class SelectAlbumFragment : Fragment() { setTitle(shareName) model.getShare(shareId, shareName) } else if (albumListType != null) { - setTitle(this@SelectAlbumFragment, albumListTitle) + setTitle(albumListTitle) model.getAlbumList(albumListType, albumListSize, albumListOffset) } else if (genreName != null) { setTitle(genreName) @@ -304,10 +289,10 @@ class SelectAlbumFragment : Fragment() { setTitle(getString(R.string.main_songs_starred)) model.getStarred() } else if (getVideos != 0) { - setTitle(this@SelectAlbumFragment, R.string.main_videos) + setTitle(R.string.main_videos) model.getVideos(refresh) } else if (getRandomTracks != 0) { - setTitle(this@SelectAlbumFragment, R.string.main_songs_random) + setTitle(R.string.main_songs_random) model.getRandom(albumListSize) } else { setTitle(name) @@ -326,11 +311,6 @@ class SelectAlbumFragment : Fragment() { } } - private fun setTitle(name: String?) { - setTitle(this@SelectAlbumFragment, name) - } - - override fun onCreateContextMenu(menu: ContextMenu, view: View, menuInfo: ContextMenuInfo?) { super.onCreateContextMenu(menu, view, menuInfo) val info = menuInfo as AdapterContextMenuInfo? @@ -366,32 +346,44 @@ class SelectAlbumFragment : Fragment() { when (menuItem.itemId) { R.id.album_menu_play_now -> { downloadHandler.downloadRecursively( - this, entryId, save = false, append = false, autoPlay = true, shuffle = false, background = false, playNext = false, unpin = false, isArtist = false + this, entryId, save = false, append = false, + autoPlay = true, shuffle = false, background = false, + playNext = false, unpin = false, isArtist = false ) } R.id.album_menu_play_next -> { downloadHandler.downloadRecursively( - this, entryId, save = false, append = false, autoPlay = false, shuffle = false, background = false, playNext = true, unpin = false, isArtist = false + this, entryId, save = false, append = false, + autoPlay = false, shuffle = false, background = false, + playNext = true, unpin = false, isArtist = false ) } R.id.album_menu_play_last -> { downloadHandler.downloadRecursively( - this, entryId, save = false, append = true, autoPlay = false, shuffle = false, background = false, playNext = false, unpin = false, isArtist = false + this, entryId, save = false, append = true, + autoPlay = false, shuffle = false, background = false, + playNext = false, unpin = false, isArtist = false ) } R.id.album_menu_pin -> { downloadHandler.downloadRecursively( - this, entryId, save = true, append = true, autoPlay = false, shuffle = false, background = false, playNext = false, unpin = false, isArtist = false + this, entryId, save = true, append = true, + autoPlay = false, shuffle = false, background = false, + playNext = false, unpin = false, isArtist = false ) } R.id.album_menu_unpin -> { downloadHandler.downloadRecursively( - this, entryId, save = false, append = false, autoPlay = false, shuffle = false, background = false, playNext = false, unpin = true, isArtist = false + this, entryId, save = false, append = false, + autoPlay = false, shuffle = false, background = false, + playNext = false, unpin = true, isArtist = false ) } R.id.album_menu_download -> { downloadHandler.downloadRecursively( - this, entryId, save = false, append = false, autoPlay = false, shuffle = false, background = true, playNext = false, unpin = false, isArtist = false + this, entryId, save = false, append = false, + autoPlay = false, shuffle = false, background = true, + playNext = false, unpin = false, isArtist = false ) } R.id.select_album_play_all -> { @@ -401,8 +393,8 @@ class SelectAlbumFragment : Fragment() { val entries: MutableList = ArrayList(1) entries.add(entry) shareHandler.createShare( - this, entries, refreshAlbumListView, - cancellationToken!! + this, entries, refreshAlbumListView, + cancellationToken!! ) return true } @@ -460,7 +452,7 @@ class SelectAlbumFragment : Fragment() { if (selectedSongs.isNotEmpty()) { downloadHandler.download( this, append, false, !append, playNext = false, - shuffle = false, songs = selectedSongs + shuffle = false, songs = selectedSongs ) selectAll(selected = false, toast = false) } else { @@ -497,8 +489,6 @@ class SelectAlbumFragment : Fragment() { } } - - private fun selectAllOrNone() { var someUnselected = false val count = albumListView!!.count @@ -610,7 +600,7 @@ class SelectAlbumFragment : Fragment() { var songs = getSelectedSongs(albumListView) if (songs.isEmpty()) { - selectAll(true, false) + selectAll(selected = true, toast = false) songs = getSelectedSongs(albumListView) } @@ -628,7 +618,16 @@ class SelectAlbumFragment : Fragment() { mediaPlayerController.unpin(songs) } - private val albumListObserver = Observer { musicDirectory -> + private val musicFolderObserver = Observer> { changedFolders -> + if (changedFolders != null) { + selectFolderHeader!!.setData( + activeServerProvider.getActiveServer().musicFolderId, + changedFolders + ) + } + } + + private val albumListObserver = Observer { musicDirectory -> if (musicDirectory.getChildren().isNotEmpty()) { pinButton!!.visibility = View.GONE unpinButton!!.visibility = View.GONE @@ -637,35 +636,35 @@ class SelectAlbumFragment : Fragment() { // Hide more button when results are less than album list size if (musicDirectory.getChildren().size < requireArguments().getInt( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0 - ) + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0 + ) ) { moreButton!!.visibility = View.GONE } else { moreButton!!.visibility = View.VISIBLE moreButton!!.setOnClickListener { val theAlbumListTitle = requireArguments().getInt( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, 0 + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, 0 ) val type = requireArguments().getString( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE ) val theSize = requireArguments().getInt( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0 + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0 ) val theOffset = requireArguments().getInt( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 ) + theSize val bundle = Bundle() bundle.putInt( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, theAlbumListTitle + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE, theAlbumListTitle ) bundle.putString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE, type) bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, theSize) bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, theOffset) Navigation.findNavController(requireView()).navigate( - R.id.selectAlbumFragment, bundle + R.id.selectAlbumFragment, bundle ) } } @@ -676,21 +675,12 @@ class SelectAlbumFragment : Fragment() { updateInterfaceWithEntries(musicDirectory) } - private val musicFolderObserver = Observer> { changedFolders -> - if (changedFolders != null) { - selectFolderHeader!!.setData( - activeServerProvider.getActiveServer().musicFolderId, - changedFolders - ) - } - } - private val songsForGenreObserver = Observer { musicDirectory -> // Hide more button when results are less than album list size if (musicDirectory.getChildren().size < requireArguments().getInt( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0 - ) + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0 + ) ) { moreButton!!.visibility = View.GONE } else { @@ -701,7 +691,7 @@ class SelectAlbumFragment : Fragment() { val theGenre = requireArguments().getString(Constants.INTENT_EXTRA_NAME_GENRE_NAME) val size = requireArguments().getInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, 0) val theOffset = requireArguments().getInt( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 ) + size val bundle = Bundle() bundle.putString(Constants.INTENT_EXTRA_NAME_GENRE_NAME, theGenre) @@ -713,7 +703,6 @@ class SelectAlbumFragment : Fragment() { updateInterfaceWithEntries(musicDirectory) } - // Our old "done" function private val defaultObserver = Observer(this::updateInterfaceWithEntries) private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory) { @@ -742,8 +731,8 @@ class SelectAlbumFragment : Fragment() { val intentAlbumName = requireArguments().getString(Constants.INTENT_EXTRA_NAME_NAME) val directoryName = musicDirectory.name val header = createHeader( - entries, intentAlbumName ?: directoryName, - songCount + entries, intentAlbumName ?: directoryName, + songCount ) if (header != null && albumListView!!.headerViewsCount == 0) { albumListView!!.addHeaderView(header, null, false) @@ -766,14 +755,14 @@ class SelectAlbumFragment : Fragment() { if (requireArguments().getInt(Constants.INTENT_EXTRA_NAME_RANDOM, 0) > 0) { moreButton!!.setOnClickListener { val offset = requireArguments().getInt( - Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0 ) + listSize val bundle = Bundle() bundle.putInt(Constants.INTENT_EXTRA_NAME_RANDOM, 1) bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_SIZE, listSize) bundle.putInt(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, offset) Navigation.findNavController(requireView()).navigate( - R.id.selectAlbumFragment, bundle + R.id.selectAlbumFragment, bundle ) } } @@ -803,7 +792,10 @@ class SelectAlbumFragment : Fragment() { enableButtons() - val isAlbumList = requireArguments().containsKey(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE) + val isAlbumList = requireArguments().containsKey( + Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TYPE + ) + playAllButtonVisible = !(isAlbumList || entries.isEmpty()) && !allVideos shareButtonVisible = !isOffline(context) && songCount > 0 @@ -823,15 +815,15 @@ class SelectAlbumFragment : Fragment() { } albumListView!!.adapter = EntryAdapter( - context, - imageLoaderProvider.getImageLoader(), entries, true + context, + imageLoaderProvider.getImageLoader(), entries, true ) val playAll = requireArguments().getBoolean(Constants.INTENT_EXTRA_NAME_AUTOPLAY, false) if (playAll && songCount > 0) { playAll( - requireArguments().getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, false), - false + requireArguments().getBoolean(Constants.INTENT_EXTRA_NAME_SHUFFLE, false), + false ) } @@ -839,15 +831,15 @@ class SelectAlbumFragment : Fragment() { } private fun createHeader( - entries: List, - name: CharSequence?, - songCount: Int + entries: List, + name: CharSequence?, + songCount: Int ): View? { val coverArtView = header!!.findViewById(R.id.select_album_art) as ImageView val artworkSelection = random.nextInt(entries.size) imageLoaderProvider.getImageLoader().loadImage( - coverArtView, entries[artworkSelection], false, - Util.getAlbumImageSize(context), false, true + coverArtView, entries[artworkSelection], false, + Util.getAlbumImageSize(context), false, true ) val albumHeader = AlbumHeader.processEntries(context, entries) @@ -890,8 +882,8 @@ class SelectAlbumFragment : Fragment() { val songCountView = header!!.findViewById(R.id.select_album_song_count) val songs = resources.getQuantityString( - R.plurals.select_album_n_songs, songCount, - songCount + R.plurals.select_album_n_songs, songCount, + songCount ) songCountView.text = songs @@ -903,7 +895,6 @@ class SelectAlbumFragment : Fragment() { return header } - private fun getSelectedSongs(albumListView: ListView?): List { val songs: MutableList = ArrayList(10) From fe69141e19cd78a643378b3a72757a7dd89ae4df Mon Sep 17 00:00:00 2001 From: tzugen Date: Wed, 21 Apr 2021 23:01:59 +0200 Subject: [PATCH 06/11] Don't leak context in model --- .../org/moire/ultrasonic/di/AppPermanentStorageModule.kt | 2 +- .../org/moire/ultrasonic/fragment/ServerSettingsModel.kt | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt index e22dd105..4aab32b1 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/di/AppPermanentStorageModule.kt @@ -31,5 +31,5 @@ val appPermanentStorage = module { single { get().serverSettingDao() } - viewModel { ServerSettingsModel(get(), get(), androidContext()) } + viewModel { ServerSettingsModel(get(), get(), get()) } } diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ServerSettingsModel.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ServerSettingsModel.kt index 0e1e9f79..02386b5e 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ServerSettingsModel.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/ServerSettingsModel.kt @@ -1,9 +1,9 @@ package org.moire.ultrasonic.fragment -import android.content.Context +import android.app.Application import android.content.SharedPreferences +import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.LiveData -import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.preference.PreferenceManager import kotlinx.coroutines.CoroutineScope @@ -22,8 +22,8 @@ import timber.log.Timber class ServerSettingsModel( private val repository: ServerSettingDao, private val activeServerProvider: ActiveServerProvider, - private val context: Context -) : ViewModel() { + application: Application +) : AndroidViewModel(application) { companion object { private const val PREFERENCES_KEY_SERVER_MIGRATED = "serverMigrated" @@ -54,6 +54,7 @@ class ServerSettingsModel( if (rowCount == null || rowCount == 0) { // First time load up the server settings from the Preferences val dbServerList = mutableListOf() + val context = getApplication().applicationContext val settings = PreferenceManager.getDefaultSharedPreferences(context) val serverNum = settings.getInt(PREFERENCES_KEY_ACTIVE_SERVERS, 0) From 237f7ab181d94d24ab497cae306f67ca73b6b190 Mon Sep 17 00:00:00 2001 From: tzugen Date: Tue, 27 Apr 2021 20:03:45 +0200 Subject: [PATCH 07/11] Update baseline files. I have moved several methods, which now get triggered again. To keep this PR manageable, I don't intent to split up the classes now. --- detekt-baseline-debug.xml | 22 ++++++++++------------ detekt-baseline-release.xml | 24 ++++++++++++------------ detekt-config.yml | 2 -- 3 files changed, 22 insertions(+), 26 deletions(-) diff --git a/detekt-baseline-debug.xml b/detekt-baseline-debug.xml index fff5d6ce..bc6e7b45 100644 --- a/detekt-baseline-debug.xml +++ b/detekt-baseline-debug.xml @@ -33,7 +33,7 @@ ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$enabled && !deleteEnabled && !isOffline(context) ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$enabled && !isOffline(context) && selection.size > pinnedCount ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$entry != null && !entry.isDirectory && !entry.isVideo - ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment.<no name provided>$Util.getShouldShowAllSongsByArtist(context) && musicDirectory.findChild(allSongsId) == null && musicDirectory.getChildren(true, false).size == musicDirectory.getChildren(true, true).size + ComplexCondition:SelectAlbumModel.kt$SelectAlbumModel$Util.getShouldShowAllSongsByArtist(context) && musicDirectory.findChild(allSongsId) == null && musicDirectory.getChildren(true, false).size == musicDirectory.getChildren(true, true).size ComplexCondition:ServerSettingsModel.kt$ServerSettingsModel$url.isNullOrEmpty() || userName.isNullOrEmpty() || isMigrated ComplexCondition:SongView.kt$SongView$TextUtils.isEmpty(transcodedSuffix) || transcodedSuffix == suffix || song.isVideo && Util.getVideoPlayerType(this.context) !== VideoPlayerType.FLASH ComplexCondition:SubsonicImageLoaderProxy.kt$SubsonicImageLoaderProxy$id != null && view != null && view is ImageView @@ -49,10 +49,9 @@ ComplexMethod:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler() ComplexMethod:RestErrorMapper.kt$ fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean - ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?) ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun enableButtons() ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateDisplay(refresh: Boolean) - ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected override fun done(result: Pair<MusicDirectory, Boolean>) + ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory) ComplexMethod:SelectArtistFragment.kt$SelectArtistFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?) ComplexMethod:ServerRowAdapter.kt$ServerRowAdapter$ override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? ComplexMethod:SongView.kt$SongView$fun setSong(song: MusicDirectory.Entry, checkable: Boolean, draggable: Boolean) @@ -85,9 +84,9 @@ LargeClass:NavigationActivity.kt$NavigationActivity : AppCompatActivity LargeClass:RESTMusicService.kt$RESTMusicService : MusicService LargeClass:SelectAlbumFragment.kt$SelectAlbumFragment : Fragment - LargeClass:SelectAlbumFragment.kt$SelectAlbumFragment$LoadTask : FragmentBackgroundTask + LargeClass:SelectAlbumModel.kt$SelectAlbumModel : AndroidViewModelKoinComponent LargeClass:SelectArtistFragment.kt$SelectArtistFragment : Fragment - LargeClass:ServerSettingsModel.kt$ServerSettingsModel : ViewModel + LargeClass:ServerSettingsModel.kt$ServerSettingsModel : AndroidViewModel LargeClass:SongView.kt$SongView : UpdateViewCheckable LongMethod:APIMusicDirectoryConverter.kt$fun MusicDirectoryChild.toDomainEntity(): MusicDirectory.Entry LongMethod:ActiveServerProvider.kt$ActiveServerProvider$ fun getActiveServer(): ServerSetting @@ -140,14 +139,16 @@ LongMethod:RestErrorMapper.kt$ fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?) + LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun createHeader( entries: List<MusicDirectory.Entry>, name: CharSequence?, songCount: Int ): View? LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun downloadBackground(save: Boolean, songs: List<MusicDirectory.Entry?>) LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun enableButtons() LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun playAll(shuffle: Boolean = false, append: Boolean = false) LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateDisplay(refresh: Boolean) - LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.<no name provided>$override fun done(result: Pair<MusicDirectory, Boolean>) - LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.<no name provided>$override fun load(service: MusicService): MusicDirectory - LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected fun createHeader( entries: List<MusicDirectory.Entry>, name: CharSequence?, songCount: Int ): View? - LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected override fun done(result: Pair<MusicDirectory, Boolean>) + LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory) + LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?) + LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getAlbumList(albumListType: String, size: Int, offset: Int) + LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getArtist(refresh: Boolean, id: String?, name: String?) + LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getMusicDirectory( refresh: Boolean, id: String?, name: String?, parentId: String? ) LongMethod:SelectArtistFragment.kt$SelectArtistFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?) LongMethod:SelectArtistFragment.kt$SelectArtistFragment$private fun onArtistMenuItemSelected(menuItem: MenuItem, artist: Artist): Boolean LongMethod:ServerRowAdapter.kt$ServerRowAdapter$ override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? @@ -204,7 +205,6 @@ MagicNumber:RESTMusicService.kt$RESTMusicService$206 MagicNumber:RESTMusicService.kt$RESTMusicService$5 MagicNumber:SelectAlbumFragment.kt$SelectAlbumFragment$10 - MagicNumber:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$10 MagicNumber:SelectMusicFolderView.kt$SelectMusicFolderView$10 MagicNumber:SongView.kt$SongView$3 MagicNumber:SongView.kt$SongView$4 @@ -212,7 +212,6 @@ NestedBlockDepth:DownloadFile.kt$DownloadFile.DownloadTask$override fun execute() NestedBlockDepth:DownloadHandler.kt$DownloadHandler$private fun downloadRecursively( fragment: Fragment, id: String, name: String?, isShare: Boolean, isDirectory: Boolean, save: Boolean, append: Boolean, autoPlay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean, isArtist: Boolean ) NestedBlockDepth:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler() - NestedBlockDepth:SelectAlbumFragment.kt$SelectAlbumFragment$private fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?) ReturnCount:ActiveServerProvider.kt$ActiveServerProvider$ fun getActiveServer(): ServerSetting ReturnCount:CommunicationErrorHandler.kt$CommunicationErrorHandler.Companion$fun getErrorMessage(error: Throwable, context: Context): String ReturnCount:FileLoggerTree.kt$FileLoggerTree$ private fun getNextLogFile() @@ -241,7 +240,6 @@ TooGenericExceptionCaught:LocalMediaPlayer.kt$LocalMediaPlayer.PositionCache$e: Exception TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$e: Exception TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$x: IndexOutOfBoundsException - TooGenericExceptionCaught:SelectAlbumFragment.kt$SelectAlbumFragment$exception: Exception TooGenericExceptionCaught:SongView.kt$SongView$e: Exception TooGenericExceptionCaught:SubsonicUncaughtExceptionHandler.kt$SubsonicUncaughtExceptionHandler$x: Throwable TooGenericExceptionCaught:VideoPlayer.kt$VideoPlayer$e: Exception diff --git a/detekt-baseline-release.xml b/detekt-baseline-release.xml index fff5d6ce..2e0abd55 100644 --- a/detekt-baseline-release.xml +++ b/detekt-baseline-release.xml @@ -33,7 +33,7 @@ ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$enabled && !deleteEnabled && !isOffline(context) ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$enabled && !isOffline(context) && selection.size > pinnedCount ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment$entry != null && !entry.isDirectory && !entry.isVideo - ComplexCondition:SelectAlbumFragment.kt$SelectAlbumFragment.<no name provided>$Util.getShouldShowAllSongsByArtist(context) && musicDirectory.findChild(allSongsId) == null && musicDirectory.getChildren(true, false).size == musicDirectory.getChildren(true, true).size + ComplexCondition:SelectAlbumModel.kt$SelectAlbumModel$Util.getShouldShowAllSongsByArtist(context) && musicDirectory.findChild(allSongsId) == null && musicDirectory.getChildren(true, false).size == musicDirectory.getChildren(true, true).size ComplexCondition:ServerSettingsModel.kt$ServerSettingsModel$url.isNullOrEmpty() || userName.isNullOrEmpty() || isMigrated ComplexCondition:SongView.kt$SongView$TextUtils.isEmpty(transcodedSuffix) || transcodedSuffix == suffix || song.isVideo && Util.getVideoPlayerType(this.context) !== VideoPlayerType.FLASH ComplexCondition:SubsonicImageLoaderProxy.kt$SubsonicImageLoaderProxy$id != null && view != null && view is ImageView @@ -49,10 +49,11 @@ ComplexMethod:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler() ComplexMethod:RestErrorMapper.kt$ fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean - ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?) ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun enableButtons() ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateDisplay(refresh: Boolean) - ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected override fun done(result: Pair<MusicDirectory, Boolean>) + ComplexMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory) + ComplexMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getAlbumList(albumListType: String, size: Int, offset: Int) + ComplexMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getMusicDirectory( refresh: Boolean, id: String?, name: String?, parentId: String? ) ComplexMethod:SelectArtistFragment.kt$SelectArtistFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?) ComplexMethod:ServerRowAdapter.kt$ServerRowAdapter$ override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? ComplexMethod:SongView.kt$SongView$fun setSong(song: MusicDirectory.Entry, checkable: Boolean, draggable: Boolean) @@ -85,9 +86,9 @@ LargeClass:NavigationActivity.kt$NavigationActivity : AppCompatActivity LargeClass:RESTMusicService.kt$RESTMusicService : MusicService LargeClass:SelectAlbumFragment.kt$SelectAlbumFragment : Fragment - LargeClass:SelectAlbumFragment.kt$SelectAlbumFragment$LoadTask : FragmentBackgroundTask + LargeClass:SelectAlbumModel.kt$SelectAlbumModel : AndroidViewModelKoinComponent LargeClass:SelectArtistFragment.kt$SelectArtistFragment : Fragment - LargeClass:ServerSettingsModel.kt$ServerSettingsModel : ViewModel + LargeClass:ServerSettingsModel.kt$ServerSettingsModel : AndroidViewModel LargeClass:SongView.kt$SongView : UpdateViewCheckable LongMethod:APIMusicDirectoryConverter.kt$fun MusicDirectoryChild.toDomainEntity(): MusicDirectory.Entry LongMethod:ActiveServerProvider.kt$ActiveServerProvider$ fun getActiveServer(): ServerSetting @@ -140,14 +141,16 @@ LongMethod:RestErrorMapper.kt$ fun SubsonicRESTException.getLocalizedErrorMessage(context: Context): String LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onContextItemSelected(menuItem: MenuItem): Boolean LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?) + LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun createHeader( entries: List<MusicDirectory.Entry>, name: CharSequence?, songCount: Int ): View? LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun downloadBackground(save: Boolean, songs: List<MusicDirectory.Entry?>) LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun enableButtons() LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun playAll(shuffle: Boolean = false, append: Boolean = false) LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateDisplay(refresh: Boolean) - LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.<no name provided>$override fun done(result: Pair<MusicDirectory, Boolean>) - LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.<no name provided>$override fun load(service: MusicService): MusicDirectory - LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected fun createHeader( entries: List<MusicDirectory.Entry>, name: CharSequence?, songCount: Int ): View? - LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$protected override fun done(result: Pair<MusicDirectory, Boolean>) + LongMethod:SelectAlbumFragment.kt$SelectAlbumFragment$private fun updateInterfaceWithEntries(musicDirectory: MusicDirectory) + LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?) + LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getAlbumList(albumListType: String, size: Int, offset: Int) + LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getArtist(refresh: Boolean, id: String?, name: String?) + LongMethod:SelectAlbumModel.kt$SelectAlbumModel$suspend fun getMusicDirectory( refresh: Boolean, id: String?, name: String?, parentId: String? ) LongMethod:SelectArtistFragment.kt$SelectArtistFragment$override fun onViewCreated(view: View, savedInstanceState: Bundle?) LongMethod:SelectArtistFragment.kt$SelectArtistFragment$private fun onArtistMenuItemSelected(menuItem: MenuItem, artist: Artist): Boolean LongMethod:ServerRowAdapter.kt$ServerRowAdapter$ override fun getView(position: Int, convertView: View?, parent: ViewGroup?): View? @@ -204,7 +207,6 @@ MagicNumber:RESTMusicService.kt$RESTMusicService$206 MagicNumber:RESTMusicService.kt$RESTMusicService$5 MagicNumber:SelectAlbumFragment.kt$SelectAlbumFragment$10 - MagicNumber:SelectAlbumFragment.kt$SelectAlbumFragment.LoadTask$10 MagicNumber:SelectMusicFolderView.kt$SelectMusicFolderView$10 MagicNumber:SongView.kt$SongView$3 MagicNumber:SongView.kt$SongView$4 @@ -212,7 +214,6 @@ NestedBlockDepth:DownloadFile.kt$DownloadFile.DownloadTask$override fun execute() NestedBlockDepth:DownloadHandler.kt$DownloadHandler$private fun downloadRecursively( fragment: Fragment, id: String, name: String?, isShare: Boolean, isDirectory: Boolean, save: Boolean, append: Boolean, autoPlay: Boolean, shuffle: Boolean, background: Boolean, playNext: Boolean, unpin: Boolean, isArtist: Boolean ) NestedBlockDepth:MediaPlayerService.kt$MediaPlayerService$private fun setupOnSongCompletedHandler() - NestedBlockDepth:SelectAlbumFragment.kt$SelectAlbumFragment$private fun getAlbum(refresh: Boolean, id: String?, name: String?, parentId: String?) ReturnCount:ActiveServerProvider.kt$ActiveServerProvider$ fun getActiveServer(): ServerSetting ReturnCount:CommunicationErrorHandler.kt$CommunicationErrorHandler.Companion$fun getErrorMessage(error: Throwable, context: Context): String ReturnCount:FileLoggerTree.kt$FileLoggerTree$ private fun getNextLogFile() @@ -241,7 +242,6 @@ TooGenericExceptionCaught:LocalMediaPlayer.kt$LocalMediaPlayer.PositionCache$e: Exception TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$e: Exception TooGenericExceptionCaught:MediaPlayerService.kt$MediaPlayerService$x: IndexOutOfBoundsException - TooGenericExceptionCaught:SelectAlbumFragment.kt$SelectAlbumFragment$exception: Exception TooGenericExceptionCaught:SongView.kt$SongView$e: Exception TooGenericExceptionCaught:SubsonicUncaughtExceptionHandler.kt$SubsonicUncaughtExceptionHandler$x: Throwable TooGenericExceptionCaught:VideoPlayer.kt$VideoPlayer$e: Exception diff --git a/detekt-config.yml b/detekt-config.yml index 34c3446c..855e94ac 100644 --- a/detekt-config.yml +++ b/detekt-config.yml @@ -49,8 +49,6 @@ complexity: thresholdInFiles: 20 thresholdInClasses: 20 thresholdInInterfaces: 20 - ComplexCondition: - threshold: 3 LabeledExpression: active: false From ce2f5a95d97cf13845d6e5370325a5efcfe0d139 Mon Sep 17 00:00:00 2001 From: tzugen Date: Tue, 27 Apr 2021 18:24:32 +0200 Subject: [PATCH 08/11] Remove unused parameter --- .../ultrasonic/fragment/SelectAlbumFragment.kt | 2 +- .../ultrasonic/fragment/SelectAlbumModel.kt | 17 +++++------------ 2 files changed, 6 insertions(+), 13 deletions(-) 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 8d9cf740..ee80d0a7 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt @@ -278,7 +278,7 @@ class SelectAlbumFragment : Fragment() { model.getPodcastEpisodes(podcastChannelId) } else if (shareId != null) { setTitle(shareName) - model.getShare(shareId, shareName) + model.getShare(shareId) } else if (albumListType != null) { setTitle(albumListTitle) model.getAlbumList(albumListType, albumListSize, albumListOffset) diff --git a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumModel.kt b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumModel.kt index 2be09aec..1cbdc1c6 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumModel.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumModel.kt @@ -1,8 +1,7 @@ package org.moire.ultrasonic.fragment import android.app.Application -import android.os.Handler -import android.os.Looper +import android.content.Context import androidx.lifecycle.AndroidViewModel import androidx.lifecycle.MutableLiveData import java.util.LinkedList @@ -16,7 +15,6 @@ import org.moire.ultrasonic.api.subsonic.models.AlbumListType import org.moire.ultrasonic.data.ActiveServerProvider import org.moire.ultrasonic.domain.MusicDirectory import org.moire.ultrasonic.domain.MusicFolder -import org.moire.ultrasonic.service.CommunicationErrorHandler import org.moire.ultrasonic.service.MusicServiceFactory import org.moire.ultrasonic.util.Util @@ -24,7 +22,8 @@ import org.moire.ultrasonic.util.Util @KoinApiExtension class SelectAlbumModel(application: Application) : AndroidViewModel(application), KoinComponent { - private val context = getApplication().applicationContext + private val context: Context + get() = getApplication().applicationContext private val activeServerProvider: ActiveServerProvider by inject() @@ -43,13 +42,7 @@ class SelectAlbumModel(application: Application) : AndroidViewModel(application) withContext(Dispatchers.IO) { if (!ActiveServerProvider.isOffline(context)) { val musicService = MusicServiceFactory.getMusicService(context) - try { - musicFolders.postValue(musicService.getMusicFolders(refresh, context)) - } catch (exception: Exception) { - Handler(Looper.getMainLooper()).post { - CommunicationErrorHandler.handleError(exception, context) - } - } + musicFolders.postValue(musicService.getMusicFolders(refresh, context)) } } } @@ -286,7 +279,7 @@ class SelectAlbumModel(application: Application) : AndroidViewModel(application) } } - suspend fun getShare(shareId: String, shareName: CharSequence?) { + suspend fun getShare(shareId: String) { withContext(Dispatchers.IO) { if (!ActiveServerProvider.isOffline(context)) { From d385cf271eaf2e3a5a4974799d5a89e46fd5ef26 Mon Sep 17 00:00:00 2001 From: tzugen Date: Sun, 11 Apr 2021 08:39:01 +0200 Subject: [PATCH 09/11] Add comments and deprecation notices --- .../main/java/org/moire/ultrasonic/view/EntryAdapter.java | 2 ++ .../src/main/java/org/moire/ultrasonic/view/UpdateView.java | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/view/EntryAdapter.java b/ultrasonic/src/main/java/org/moire/ultrasonic/view/EntryAdapter.java index 5f655a7f..bd05bff8 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/view/EntryAdapter.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/view/EntryAdapter.java @@ -33,6 +33,8 @@ import org.moire.ultrasonic.util.ImageLoader; import java.util.List; /** + * This is the adapter for the display of a single list item (song, album, etc) + * * @author Sindre Mehus */ public class EntryAdapter extends ArrayAdapter diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/view/UpdateView.java b/ultrasonic/src/main/java/org/moire/ultrasonic/view/UpdateView.java index 5236726b..8603b8a8 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/view/UpdateView.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/view/UpdateView.java @@ -14,6 +14,12 @@ import java.util.ArrayList; import java.util.Collection; import java.util.WeakHashMap; +/** + * A View that is periodically refreshed + * @deprecated + * Use LiveData to ensure that the content is up-to-date + **/ +@Deprecated public class UpdateView extends LinearLayout { private static final WeakHashMap INSTANCES = new WeakHashMap(); From adc350b5c4438232f9d4577607c19be004277c87 Mon Sep 17 00:00:00 2001 From: tzugen Date: Sat, 1 May 2021 09:22:45 +0200 Subject: [PATCH 10/11] Fix wrong injection method after rebase --- .../org/moire/ultrasonic/fragment/SelectAlbumFragment.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) 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 ee80d0a7..bc059dfa 100644 --- a/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt +++ b/ultrasonic/src/main/kotlin/org/moire/ultrasonic/fragment/SelectAlbumFragment.kt @@ -31,6 +31,7 @@ import java.util.Collections import java.util.Random import kotlinx.coroutines.launch import org.koin.android.ext.android.inject +import org.koin.android.viewmodel.ext.android.viewModel import org.koin.core.component.KoinApiExtension import org.moire.ultrasonic.R import org.moire.ultrasonic.data.ActiveServerProvider @@ -92,7 +93,7 @@ class SelectAlbumFragment : Fragment() { private var cancellationToken: CancellationToken? = null private val activeServerProvider: ActiveServerProvider by inject() - private val serverSettingsModel: ServerSettingsModel by viewModels() + private val serverSettingsModel: ServerSettingsModel by viewModel() private val model: SelectAlbumModel by viewModels() private val random: Random = SecureRandom() @@ -265,7 +266,7 @@ class SelectAlbumFragment : Fragment() { setTitle(this@SelectAlbumFragment, name) } - serverSettingsModel.viewModelScope.launch { + model.viewModelScope.launch { refreshAlbumListView!!.isRefreshing = true model.getMusicFolders(refresh) From f6a8ee7241f31e69749011f935d6de884a79e1a8 Mon Sep 17 00:00:00 2001 From: tzugen Date: Sat, 1 May 2021 09:58:58 +0200 Subject: [PATCH 11/11] Remove @Deprecated tag (keep it in JDoc because it doesn't generate a warning) --- .../src/main/java/org/moire/ultrasonic/view/UpdateView.java | 1 - 1 file changed, 1 deletion(-) diff --git a/ultrasonic/src/main/java/org/moire/ultrasonic/view/UpdateView.java b/ultrasonic/src/main/java/org/moire/ultrasonic/view/UpdateView.java index 8603b8a8..96338d01 100644 --- a/ultrasonic/src/main/java/org/moire/ultrasonic/view/UpdateView.java +++ b/ultrasonic/src/main/java/org/moire/ultrasonic/view/UpdateView.java @@ -19,7 +19,6 @@ import java.util.WeakHashMap; * @deprecated * Use LiveData to ensure that the content is up-to-date **/ -@Deprecated public class UpdateView extends LinearLayout { private static final WeakHashMap INSTANCES = new WeakHashMap();