Merge pull request #410 from SaintDubious/SelectMusicFolderView

Introduce the SelectMusicFolderView
This commit is contained in:
Nite 2021-04-13 09:52:10 +02:00 committed by GitHub
commit 9e16b69fc3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 232 additions and 119 deletions

View File

@ -76,6 +76,7 @@ public class CachedMusicService implements MusicService
private final TimeLimitedCache<List<Genre>> cachedGenres = new TimeLimitedCache<>(10 * 3600, TimeUnit.SECONDS);
private String restUrl;
private String cachedMusicFolderId;
public CachedMusicService(MusicService musicService)
{
@ -284,15 +285,15 @@ public class CachedMusicService implements MusicService
}
@Override
public MusicDirectory getAlbumList(String type, int size, int offset, Context context) throws Exception
public MusicDirectory getAlbumList(String type, int size, int offset, String musicFolderId, Context context) throws Exception
{
return musicService.getAlbumList(type, size, offset, context);
return musicService.getAlbumList(type, size, offset, musicFolderId, context);
}
@Override
public MusicDirectory getAlbumList2(String type, int size, int offset, Context context) throws Exception
public MusicDirectory getAlbumList2(String type, int size, int offset, String musicFolderId, Context context) throws Exception
{
return musicService.getAlbumList2(type, size, offset, context);
return musicService.getAlbumList2(type, size, offset, musicFolderId, context);
}
@Override
@ -370,7 +371,8 @@ public class CachedMusicService implements MusicService
private void checkSettingsChanged()
{
String newUrl = activeServerProvider.getValue().getRestUrl(null);
if (!Util.equals(newUrl, restUrl))
String newFolderId = activeServerProvider.getValue().getActiveServer().getMusicFolderId();
if (!Util.equals(newUrl, restUrl) || !Util.equals(cachedMusicFolderId,newFolderId))
{
cachedMusicFolders.clear();
cachedMusicDirectories.clear();
@ -382,6 +384,7 @@ public class CachedMusicService implements MusicService
cachedArtist.clear();
cachedUserInfo.clear();
restUrl = newUrl;
cachedMusicFolderId = newFolderId;
}
}

View File

@ -90,9 +90,9 @@ public interface MusicService
void scrobble(String id, boolean submission, Context context) throws Exception;
MusicDirectory getAlbumList(String type, int size, int offset, Context context) throws Exception;
MusicDirectory getAlbumList(String type, int size, int offset, String musicFolderId, Context context) throws Exception;
MusicDirectory getAlbumList2(String type, int size, int offset, Context context) throws Exception;
MusicDirectory getAlbumList2(String type, int size, int offset, String musicFolderId, Context context) throws Exception;
MusicDirectory getRandomSongs(int size, Context context) throws Exception;

View File

@ -702,7 +702,7 @@ public class OfflineMusicService implements MusicService
}
@Override
public MusicDirectory getAlbumList(String type, int size, int offset, Context context) throws Exception
public MusicDirectory getAlbumList(String type, int size, int offset, String musicFolderId, Context context) throws Exception
{
throw new OfflineException("Album lists not available in offline mode");
}
@ -809,7 +809,7 @@ public class OfflineMusicService implements MusicService
}
@Override
public MusicDirectory getAlbumList2(String type, int size, int offset, Context context) {
public MusicDirectory getAlbumList2(String type, int size, int offset, String musicFolderId, Context context) {
Timber.w("OfflineMusicService.getAlbumList2 was called but it isn't available");
return null;
}

View File

@ -24,7 +24,6 @@ import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.PopupMenu
import android.widget.RelativeLayout
import android.widget.TextView
@ -37,17 +36,16 @@ import org.moire.ultrasonic.domain.Artist
import org.moire.ultrasonic.domain.MusicDirectory
import org.moire.ultrasonic.util.ImageLoader
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.view.SelectMusicFolderView
/**
* Creates a Row in a RecyclerView which contains the details of an Artist
*/
class ArtistRowAdapter(
private var artistList: List<Artist>,
private var folderName: String,
private var shouldShowHeader: Boolean,
private var selectFolderHeader: SelectMusicFolderView?,
val onArtistClick: (Artist) -> Unit,
val onContextMenuClick: (MenuItem, Artist) -> Boolean,
val onFolderClick: (view: View) -> Unit,
private val imageLoader: ImageLoader
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), SectionedAdapter {
@ -59,14 +57,6 @@ class ArtistRowAdapter(
notifyDataSetChanged()
}
/**
* Sets the name of the folder to be displayed n the Header (first) row
*/
fun setFolderName(name: String) {
folderName = name
notifyDataSetChanged()
}
/**
* Holds the view properties of an Artist row
*/
@ -80,16 +70,6 @@ class ArtistRowAdapter(
var coverArtId: String? = null
}
/**
* Holds the view properties of the Header row
*/
class HeaderViewHolder(
itemView: View
) : RecyclerView.ViewHolder(itemView) {
var folderName: TextView = itemView.findViewById(R.id.select_artist_folder_2)
var layout: LinearLayout = itemView.findViewById(R.id.select_artist_folder)
}
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
@ -99,9 +79,7 @@ class ArtistRowAdapter(
.inflate(R.layout.artist_list_item, parent, false)
return ArtistViewHolder(row)
}
val header = LayoutInflater.from(parent.context)
.inflate(R.layout.select_artist_header, parent, false)
return HeaderViewHolder(header)
return selectFolderHeader!!
}
override fun onViewRecycled(holder: RecyclerView.ViewHolder) {
@ -113,7 +91,7 @@ class ArtistRowAdapter(
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
if (holder is ArtistViewHolder) {
val listPosition = if (shouldShowHeader) position - 1 else position
val listPosition = if (selectFolderHeader != null) position - 1 else position
holder.textView.text = artistList[listPosition].name
holder.section.text = getSectionForArtist(listPosition)
holder.layout.setOnClickListener { onArtistClick(artistList[listPosition]) }
@ -130,20 +108,20 @@ class ArtistRowAdapter(
} else {
holder.coverArt.visibility = View.GONE
}
} else if (holder is HeaderViewHolder) {
holder.folderName.text = folderName
holder.layout.setOnClickListener { onFolderClick(holder.layout) }
}
}
override fun getItemCount() = if (shouldShowHeader) artistList.size + 1 else artistList.size
override fun getItemCount() = if (selectFolderHeader != null)
artistList.size + 1
else
artistList.size
override fun getItemViewType(position: Int): Int {
return if (position == 0 && shouldShowHeader) TYPE_HEADER else TYPE_ITEM
return if (position == 0 && selectFolderHeader != null) TYPE_HEADER else TYPE_ITEM
}
override fun getSectionName(position: Int): String {
var listPosition = if (shouldShowHeader) position - 1 else position
var listPosition = if (selectFolderHeader != null) position - 1 else position
// Show the first artist's initial in the popup when the list is
// scrolled up to the "Select Folder" row

View File

@ -1,6 +1,8 @@
package org.moire.ultrasonic.fragment
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.ContextMenu
import android.view.ContextMenu.ContextMenuInfo
import android.view.LayoutInflater
@ -16,6 +18,9 @@ import android.widget.ImageView
import android.widget.ListView
import android.widget.TextView
import androidx.fragment.app.Fragment
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.Observer
import androidx.lifecycle.viewModelScope
import androidx.navigation.Navigation
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout.OnRefreshListener
@ -23,14 +28,23 @@ import java.security.SecureRandom
import java.util.Collections
import java.util.LinkedList
import java.util.Random
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.android.ext.android.inject
import org.koin.android.viewmodel.ext.android.viewModel
import org.moire.ultrasonic.R
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
import org.moire.ultrasonic.service.MusicServiceFactory.getMusicService
import org.moire.ultrasonic.subsonic.DownloadHandler
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
@ -45,6 +59,7 @@ import org.moire.ultrasonic.util.FragmentBackgroundTask
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.view.AlbumView
import org.moire.ultrasonic.view.EntryAdapter
import org.moire.ultrasonic.view.SelectMusicFolderView
import org.moire.ultrasonic.view.SongView
import timber.log.Timber
@ -57,6 +72,7 @@ class SelectAlbumFragment : Fragment() {
private var refreshAlbumListView: SwipeRefreshLayout? = null
private var albumListView: ListView? = null
private var header: View? = null
private var selectFolderHeader: SelectMusicFolderView? = null
private var albumButtons: View? = null
private var emptyView: View? = null
private var selectButton: ImageView? = null
@ -73,7 +89,9 @@ class SelectAlbumFragment : Fragment() {
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<List<MusicFolder>> = MutableLiveData()
private val mediaPlayerController: MediaPlayerController by inject()
private val videoPlayer: VideoPlayer by inject()
@ -82,6 +100,8 @@ class SelectAlbumFragment : Fragment() {
private val imageLoaderProvider: ImageLoaderProvider by inject()
private val shareHandler: ShareHandler by inject()
private var cancellationToken: CancellationToken? = null
private val activeServerProvider: ActiveServerProvider by inject()
private val serverSettingsModel: ServerSettingsModel by viewModel()
override fun onCreate(savedInstanceState: Bundle?) {
Util.applyTheme(this.context)
@ -117,6 +137,29 @@ class SelectAlbumFragment : Fragment() {
false
)
selectFolderHeader = SelectMusicFolderView(
requireContext(), view as ViewGroup,
{ selectedFolderId ->
if (!ActiveServerProvider.isOffline(context)) {
val currentSetting = activeServerProvider.getActiveServer()
currentSetting.musicFolderId = selectedFolderId
serverSettingsModel.updateItem(currentSetting)
}
this.updateDisplay(true)
}
)
musicFolders.observe(
viewLifecycleOwner,
Observer { changedFolders ->
if (changedFolders != null) {
selectFolderHeader!!.setData(
activeServerProvider.getActiveServer().musicFolderId,
changedFolders
)
}
}
)
albumListView!!.setChoiceMode(ListView.CHOICE_MODE_MULTIPLE)
albumListView!!.setOnItemClickListener(
OnItemClickListener
@ -269,6 +312,8 @@ class SelectAlbumFragment : Fragment() {
Constants.INTENT_EXTRA_NAME_ALBUM_LIST_OFFSET, 0
)
backgroundLoadMusicFolders(refresh)
if (playlistId != null) {
getPlaylist(playlistId, playlistName)
} else if (podcastChannelId != null) {
@ -298,6 +343,29 @@ class SelectAlbumFragment : Fragment() {
}
}
private fun backgroundLoadMusicFolders(refresh: Boolean) {
serverSettingsModel.viewModelScope.launch {
refreshAlbumListView!!.isRefreshing = true
loadMusicFolders(refresh)
refreshAlbumListView!!.isRefreshing = false
}
}
private suspend fun loadMusicFolders(refresh: Boolean) {
withContext(Dispatchers.IO) {
if (!isOffline(context)) {
val musicService = MusicServiceFactory.getMusicService(requireContext())
try {
musicFolders.postValue(musicService.getMusicFolders(refresh, context))
} catch (exception: Exception) {
Handler(Looper.getMainLooper()).post {
CommunicationErrorHandler.handleError(exception, requireContext())
}
}
}
}
}
override fun onCreateContextMenu(menu: ContextMenu, view: View, menuInfo: ContextMenuInfo?) {
super.onCreateContextMenu(menu, view, menuInfo)
val info = menuInfo as AdapterContextMenuInfo?
@ -735,6 +803,11 @@ class SelectAlbumFragment : Fragment() {
private 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);
@ -747,10 +820,15 @@ class SelectAlbumFragment : Fragment() {
}
override fun load(service: MusicService): MusicDirectory {
val musicFolderId = if (showSelectFolderHeader) {
this@SelectAlbumFragment.activeServerProvider.getActiveServer().musicFolderId
} else {
null
}
return if (Util.getShouldUseId3Tags(context))
service.getAlbumList2(albumListType, size, offset, context)
service.getAlbumList2(albumListType, size, offset, musicFolderId, context)
else
service.getAlbumList(albumListType, size, offset, context)
service.getAlbumList(albumListType, size, offset, musicFolderId, context)
}
override fun done(result: Pair<MusicDirectory, Boolean>) {
@ -1012,6 +1090,12 @@ class SelectAlbumFragment : Fragment() {
}
}
} 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

View File

@ -5,7 +5,6 @@ import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.PopupMenu
import androidx.fragment.app.Fragment
import androidx.lifecycle.Observer
import androidx.navigation.fragment.findNavController
@ -17,12 +16,12 @@ import org.koin.android.viewmodel.ext.android.viewModel
import org.moire.ultrasonic.R
import org.moire.ultrasonic.data.ActiveServerProvider
import org.moire.ultrasonic.domain.Artist
import org.moire.ultrasonic.domain.MusicFolder
import org.moire.ultrasonic.fragment.FragmentTitle.Companion.setTitle
import org.moire.ultrasonic.subsonic.DownloadHandler
import org.moire.ultrasonic.subsonic.ImageLoaderProvider
import org.moire.ultrasonic.util.Constants
import org.moire.ultrasonic.util.Util
import org.moire.ultrasonic.view.SelectMusicFolderView
/**
* Displays the list of Artists from the media library
@ -36,9 +35,9 @@ class SelectArtistFragment : Fragment() {
private var refreshArtistListView: SwipeRefreshLayout? = null
private var artistListView: RecyclerView? = null
private var musicFolders: List<MusicFolder>? = null
private lateinit var viewManager: RecyclerView.LayoutManager
private lateinit var viewAdapter: ArtistRowAdapter
private var selectFolderHeader: SelectMusicFolderView? = null
@Override
override fun onCreate(savedInstanceState: Bundle?) {
@ -60,10 +59,22 @@ class SelectArtistFragment : Fragment() {
artistListModel.refresh(refreshArtistListView!!)
}
val shouldShowHeader = (
!ActiveServerProvider.isOffline(this.context) &&
!Util.getShouldUseId3Tags(this.context)
if (!ActiveServerProvider.isOffline(this.context) &&
!Util.getShouldUseId3Tags(this.context)
) {
selectFolderHeader = SelectMusicFolderView(
requireContext(), view as ViewGroup,
{ selectedFolderId ->
if (!ActiveServerProvider.isOffline(context)) {
val currentSetting = activeServerProvider.getActiveServer()
currentSetting.musicFolderId = selectedFolderId
serverSettingsModel.updateItem(currentSetting)
}
viewAdapter.notifyDataSetChanged()
artistListModel.refresh(refreshArtistListView!!)
}
)
}
val title = arguments?.getString(Constants.INTENT_EXTRA_NAME_ALBUM_LIST_TITLE)
@ -78,8 +89,6 @@ class SelectArtistFragment : Fragment() {
setTitle(this, title)
}
musicFolders = null
val refresh = arguments?.getBoolean(Constants.INTENT_EXTRA_NAME_REFRESH) ?: false
artistListModel.getMusicFolders()
@ -87,8 +96,11 @@ class SelectArtistFragment : Fragment() {
viewLifecycleOwner,
Observer { changedFolders ->
if (changedFolders != null) {
musicFolders = changedFolders
viewAdapter.setFolderName(getMusicFolderName(changedFolders))
viewAdapter.notifyDataSetChanged()
selectFolderHeader!!.setData(
activeServerProvider.getActiveServer().musicFolderId,
changedFolders
)
}
}
)
@ -101,11 +113,9 @@ class SelectArtistFragment : Fragment() {
viewManager = LinearLayoutManager(this.context)
viewAdapter = ArtistRowAdapter(
artists.value ?: listOf(),
getText(R.string.select_artist_all_folders).toString(),
shouldShowHeader,
selectFolderHeader,
{ artist -> onItemClick(artist) },
{ menuItem, artist -> onArtistMenuItemSelected(menuItem, artist) },
{ onFolderClick(it) },
imageLoaderProvider.getImageLoader()
)
@ -117,18 +127,6 @@ class SelectArtistFragment : Fragment() {
super.onViewCreated(view, savedInstanceState)
}
private fun getMusicFolderName(musicFolders: List<MusicFolder>): String {
val musicFolderId = activeServerProvider.getActiveServer().musicFolderId
if (musicFolderId != null && musicFolderId != "") {
for ((id, name) in musicFolders) {
if (id == musicFolderId) {
return name
}
}
}
return getText(R.string.select_artist_all_folders).toString()
}
private fun onItemClick(artist: Artist) {
val bundle = Bundle()
bundle.putString(Constants.INTENT_EXTRA_NAME_ID, artist.id)
@ -138,31 +136,6 @@ class SelectArtistFragment : Fragment() {
findNavController().navigate(R.id.selectArtistToSelectAlbum, bundle)
}
private fun onFolderClick(view: View) {
val popup = PopupMenu(this.context, view)
val musicFolderId = activeServerProvider.getActiveServer().musicFolderId
var menuItem = popup.menu.add(
MENU_GROUP_MUSIC_FOLDER, -1, 0, R.string.select_artist_all_folders
)
if (musicFolderId == null || musicFolderId.isEmpty()) {
menuItem.isChecked = true
}
if (musicFolders != null) {
for (i in musicFolders!!.indices) {
val (id, name) = musicFolders!![i]
menuItem = popup.menu.add(MENU_GROUP_MUSIC_FOLDER, i, i + 1, name)
if (id == musicFolderId) {
menuItem.isChecked = true
}
}
}
popup.menu.setGroupCheckable(MENU_GROUP_MUSIC_FOLDER, true, true)
popup.setOnMenuItemClickListener { item -> onFolderMenuItemSelected(item) }
popup.show()
}
private fun onArtistMenuItemSelected(menuItem: MenuItem, artist: Artist): Boolean {
when (menuItem.itemId) {
R.id.artist_menu_play_now ->
@ -246,23 +219,4 @@ class SelectArtistFragment : Fragment() {
}
return true
}
private fun onFolderMenuItemSelected(menuItem: MenuItem): Boolean {
val selectedFolder = if (menuItem.itemId == -1) null else musicFolders!![menuItem.itemId]
val musicFolderId = selectedFolder?.id
val musicFolderName = selectedFolder?.name
?: getString(R.string.select_artist_all_folders)
if (!ActiveServerProvider.isOffline(this.context)) {
val currentSetting = activeServerProvider.getActiveServer()
currentSetting.musicFolderId = musicFolderId
serverSettingsModel.updateItem(currentSetting)
}
viewAdapter.setFolderName(musicFolderName)
artistListModel.refresh(refreshArtistListView!!)
return true
}
companion object {
private const val MENU_GROUP_MUSIC_FOLDER = 10
}
}

View File

@ -114,7 +114,9 @@ open class RESTMusicService(
refresh: Boolean,
context: Context
): Indexes {
val cachedIndexes = fileStorage.load(INDEXES_STORAGE_NAME, getIndexesSerializer())
val indexName = INDEXES_STORAGE_NAME + (musicFolderId ?: "")
val cachedIndexes = fileStorage.load(indexName, getIndexesSerializer())
if (cachedIndexes != null && !refresh) return cachedIndexes
val response = responseChecker.callWithResponseCheck { api ->
@ -122,7 +124,7 @@ open class RESTMusicService(
}
val indexes = response.body()!!.indexes.toDomainEntity()
fileStorage.store(INDEXES_STORAGE_NAME, indexes, getIndexesSerializer())
fileStorage.store(indexName, indexes, getIndexesSerializer())
return indexes
}
@ -445,10 +447,11 @@ open class RESTMusicService(
type: String,
size: Int,
offset: Int,
musicFolderId: String?,
context: Context
): MusicDirectory {
val response = responseChecker.callWithResponseCheck { api ->
api.getAlbumList(fromName(type), size, offset, null, null, null, null)
api.getAlbumList(fromName(type), size, offset, null, null, null, musicFolderId)
.execute()
}
@ -464,6 +467,7 @@ open class RESTMusicService(
type: String,
size: Int,
offset: Int,
musicFolderId: String?,
context: Context
): MusicDirectory {
val response = responseChecker.callWithResponseCheck { api ->
@ -474,7 +478,7 @@ open class RESTMusicService(
null,
null,
null,
null
musicFolderId
).execute()
}
@ -936,6 +940,7 @@ open class RESTMusicService(
companion object {
private const val MUSIC_FOLDER_STORAGE_NAME = "music_folder"
private const val INDEXES_STORAGE_NAME = "indexes"
private const val INDEXES_FOLDER_STORAGE_NAME = "indexes_folder"
private const val ARTISTS_STORAGE_NAME = "artists"
}
}

View File

@ -0,0 +1,89 @@
package org.moire.ultrasonic.view
import android.content.Context
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.PopupMenu
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import org.moire.ultrasonic.R
import org.moire.ultrasonic.domain.MusicFolder
/**
* This little view shows the currently selected Folder (or catalog) on the music server.
* When clicked it will drop down a list of all available Folders and allow you to
* select one. The intended usage is to supply a filter to lists of artists, albums, etc
*/
class SelectMusicFolderView(
private val context: Context,
root: ViewGroup,
private val onUpdate: (String?) -> Unit
) : RecyclerView.ViewHolder(
LayoutInflater.from(context).inflate(
R.layout.select_folder_header, root, false
)
) {
private var musicFolders: List<MusicFolder> = mutableListOf<MusicFolder>()
private var selectedFolderId: String? = null
private val folderName: TextView = itemView.findViewById(R.id.select_folder_name)
private val layout: LinearLayout = itemView.findViewById(R.id.select_folder_header)
private val MENU_GROUP_MUSIC_FOLDER = 10
init {
folderName.text = context.getString(R.string.select_artist_all_folders)
layout.setOnClickListener { onFolderClick() }
}
fun setData(selectedId: String?, folders: List<MusicFolder>) {
selectedFolderId = selectedId
musicFolders = folders
if (selectedFolderId != null) {
for ((id, name) in musicFolders) {
if (id == selectedFolderId) {
folderName.text = name
break
}
}
} else {
folderName.text = context.getString(R.string.select_artist_all_folders)
}
}
private fun onFolderClick() {
val popup = PopupMenu(context, layout)
var menuItem = popup.menu.add(
MENU_GROUP_MUSIC_FOLDER, -1, 0, R.string.select_artist_all_folders
)
if (selectedFolderId == null || selectedFolderId!!.isEmpty()) {
menuItem.isChecked = true
}
musicFolders.forEachIndexed { i, musicFolder ->
val (id, name) = musicFolder
menuItem = popup.menu.add(MENU_GROUP_MUSIC_FOLDER, i, i + 1, name)
if (id == selectedFolderId) {
menuItem.isChecked = true
}
}
popup.menu.setGroupCheckable(MENU_GROUP_MUSIC_FOLDER, true, true)
popup.setOnMenuItemClickListener { item -> onFolderMenuItemSelected(item) }
popup.show()
}
private fun onFolderMenuItemSelected(menuItem: MenuItem): Boolean {
val selectedFolder = if (menuItem.itemId == -1) null else musicFolders[menuItem.itemId]
val musicFolderName = selectedFolder?.name
?: context.getString(R.string.select_artist_all_folders)
selectedFolderId = selectedFolder?.id
menuItem.isChecked = true
folderName.text = musicFolderName
onUpdate(selectedFolderId)
return true
}
}

View File

@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:a="http://schemas.android.com/apk/res/android"
a:id="@+id/select_artist_folder"
a:id="@+id/select_folder_header"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:minHeight="?android:attr/listPreferredItemHeight"
@ -24,7 +24,7 @@
a:orientation="vertical" >
<TextView
a:id="@+id/select_artist_folder_1"
a:id="@+id/select_folder_title"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:layout_marginLeft="10dip"
@ -33,7 +33,7 @@
a:textAppearance="?android:attr/textAppearanceLarge" />
<TextView
a:id="@+id/select_artist_folder_2"
a:id="@+id/select_folder_name"
a:layout_width="fill_parent"
a:layout_height="wrap_content"
a:layout_marginLeft="10dip"