From f89b074d280d674d39121a1edfb3ff5eea6e2794 Mon Sep 17 00:00:00 2001 From: Kelvin Date: Tue, 18 Nov 2025 23:35:34 +0100 Subject: [PATCH] Various improvements to library and other fixes --- .../platformplayer/activities/MainActivity.kt | 19 +++++++ .../fragment/mainactivity/main/FeedView.kt | 5 +- .../main/LibraryArtistFragment.kt | 5 +- .../mainactivity/main/LibraryFilesFragment.kt | 29 ++++++++++ .../mainactivity/main/LibraryFragment.kt | 23 ++++---- .../mainactivity/main/VideoDetailView.kt | 50 +++++++++++++----- .../futo/platformplayer/models/Telemetry.kt | 3 +- .../platformplayer/states/StateLibrary.kt | 35 ++++++++---- .../platformplayer/states/StateTelemetry.kt | 3 +- .../viewholders/ArtistTileViewHolder.kt | 4 +- .../adapters/viewholders/FileViewHolder.kt | 4 +- .../views/buttons/ButtonsContainer.kt | 47 ++++++++++++++++ .../views/buttons/StandardButton.kt | 34 ++++++++++++ .../views/others/CreatorThumbnail.kt | 16 ++++-- .../platformplayer/views/pills/PillButton.kt | 2 +- .../views/segments/CommentsList.kt | 7 +++ app/src/main/res/drawable/ic_artist.png | Bin 0 -> 3401 bytes app/src/main/res/drawable/ic_folder.png | Bin 0 -> 462 bytes app/src/main/res/drawable/ic_song.png | Bin 0 -> 826 bytes app/src/main/res/layout/fragment_feed.xml | 18 +++++-- app/src/main/res/layout/list_file.xml | 6 +-- .../main/res/layout/view_button_standard.xml | 24 +++++++++ app/src/main/res/layout/view_buttons.xml | 28 ++++++++++ 23 files changed, 307 insertions(+), 55 deletions(-) create mode 100644 app/src/main/java/com/futo/platformplayer/views/buttons/ButtonsContainer.kt create mode 100644 app/src/main/java/com/futo/platformplayer/views/buttons/StandardButton.kt create mode 100644 app/src/main/res/drawable/ic_artist.png create mode 100644 app/src/main/res/drawable/ic_folder.png create mode 100644 app/src/main/res/drawable/ic_song.png create mode 100644 app/src/main/res/layout/view_button_standard.xml create mode 100644 app/src/main/res/layout/view_buttons.xml diff --git a/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt b/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt index bcda0ff8..de0519a7 100644 --- a/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt +++ b/app/src/main/java/com/futo/platformplayer/activities/MainActivity.kt @@ -252,6 +252,8 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { UIDialogs.toast(this, "Notification permission denied"); }; + + fun requestNotificationPermissions() { _notificationPermissionLauncher?.launch(_notifPermission); } @@ -1379,6 +1381,23 @@ class MainActivity : AppCompatActivity, IWithResultLauncher { ); } + var _callbackPermissionAudio: ((Boolean)->Unit)? = null; + var _callbackPermissionVideo: ((Boolean)->Unit)? = null; + val permissionReqAudio = registerForActivityResult(ActivityResultContracts.RequestPermission(), { isGranted -> + _callbackPermissionAudio?.invoke(isGranted); + }); + val permissionReqVideo = registerForActivityResult(ActivityResultContracts.RequestPermission(), { isGranted -> + _callbackPermissionVideo?.invoke(isGranted); + }); + fun requestPermissionAudio(cb: ((Boolean)->Unit)? = null) { + _callbackPermissionAudio = cb; + permissionReqAudio.launch(android.Manifest.permission.READ_MEDIA_AUDIO); + } + fun requestPermissionVideo(cb: ((Boolean)->Unit)? = null) { + _callbackPermissionVideo = cb; + permissionReqVideo.launch(android.Manifest.permission.READ_MEDIA_VIDEO); + } + val notifPermission = "android.permission.POST_NOTIFICATIONS"; val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted: Boolean -> diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/FeedView.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/FeedView.kt index 2a19fc6e..abf4ec7d 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/FeedView.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/FeedView.kt @@ -9,6 +9,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import android.widget.* +import androidx.constraintlayout.widget.ConstraintLayout import androidx.lifecycle.lifecycleScope import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.LinearLayoutManager @@ -39,7 +40,7 @@ import java.time.OffsetDateTime import kotlin.math.max abstract class FeedView : LinearLayout where TPager : IPager, TViewHolder : RecyclerView.ViewHolder, TFragment : MainFragment { - protected val _feedRoot: FrameLayout; + protected val _feedRoot: ConstraintLayout; protected val _recyclerResults: RecyclerView; protected val _overlayContainer: FrameLayout; protected val _swipeRefresh: SwipeRefreshLayout; @@ -52,6 +53,7 @@ abstract class FeedView : L private val _emptyPagerContainer: FrameLayout; protected val _toolbarContentView: LinearLayout; + protected val _bottomContentView: LinearLayout; private var _loading: Boolean = true; @@ -136,6 +138,7 @@ abstract class FeedView : L setActiveTags(null); _toolbarContentView = findViewById(R.id.container_toolbar_content); + _bottomContentView = findViewById(R.id.container_bottom); _nextPageHandler = TaskHandler>>({fragment.lifecycleScope}, { if (it is IAsyncPager<*>) diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/LibraryArtistFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/LibraryArtistFragment.kt index 878cc8a5..f51943fb 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/LibraryArtistFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/LibraryArtistFragment.kt @@ -506,7 +506,10 @@ class LibraryArtistFragment : MainFragment() { val playlist = _artist?.toPlaylist(); if (playlist != null) { - val index = playlist.videos.indexOf(c); + val sameVideo = playlist.videos.find { it.name == c.name }; + val index = sameVideo?.let { + playlist.videos.indexOf(sameVideo) + } ?: -1; if (index == -1) return@subscribe; diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/LibraryFilesFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/LibraryFilesFragment.kt index a50c047d..67c5bccd 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/LibraryFilesFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/LibraryFilesFragment.kt @@ -8,25 +8,32 @@ import android.view.View import android.view.ViewGroup import android.widget.ImageButton import android.widget.ImageView +import android.widget.LinearLayout import android.widget.TextView +import androidx.core.net.toUri import androidx.core.view.isVisible import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import com.bumptech.glide.Glide import com.futo.platformplayer.R +import com.futo.platformplayer.api.media.models.video.LocalVideoDetails +import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo import com.futo.platformplayer.api.media.structures.AdhocPager import com.futo.platformplayer.api.media.structures.EmptyPager import com.futo.platformplayer.api.media.structures.IPager import com.futo.platformplayer.constructs.Event1 import com.futo.platformplayer.fragment.mainactivity.topbar.FilesTopBarFragment +import com.futo.platformplayer.models.Playlist import com.futo.platformplayer.states.FileEntry import com.futo.platformplayer.states.StateLibrary +import com.futo.platformplayer.states.StatePlayer import com.futo.platformplayer.views.FeedStyle import com.futo.platformplayer.views.NoResultsView import com.futo.platformplayer.views.adapters.AnyAdapter import com.futo.platformplayer.views.adapters.InsertedViewAdapterWithLoader import com.futo.platformplayer.views.adapters.viewholders.FileViewHolder import com.futo.platformplayer.views.buttons.BigButton +import com.futo.platformplayer.views.buttons.ButtonsContainer class LibraryFilesFragment : MainFragment() { override val isMainView : Boolean = true; @@ -70,6 +77,7 @@ class LibraryFilesFragment : MainFragment() { private var root: FileEntry? = null; constructor(fragment: LibraryFilesFragment, inflater: LayoutInflater) : super(fragment, inflater) { + disableRefreshLayout(); } fun onShown(parameter: Any? = null) { @@ -139,6 +147,27 @@ class LibraryFilesFragment : MainFragment() { setPager(AdhocPager({ listOf(); }, stack.files)); setLoading(false); + val allSongs = stack.files.filter { !it.isDirectory }; + if(allSongs.any()) { + _bottomContentView.addView(ButtonsContainer(context, + listOf( + ButtonsContainer.Button("Play All", R.drawable.background_button_primary) { + StatePlayer.instance.setPlaylist(Playlist(stack.path.toUri().lastPathSegment ?: "", allSongs.map { + SerializedPlatformVideo.fromVideo(LocalVideoDetails.fromContent(it.path)) + }), focus = true, shuffle = false) + }, + ButtonsContainer.Button("Shuffle", R.drawable.background_button_accent) { + StatePlayer.instance.setPlaylist(Playlist(stack.path.toUri().lastPathSegment ?: "", allSongs.map { + SerializedPlatformVideo.fromVideo(LocalVideoDetails.fromContent(it.path)) + }), focus = true, shuffle = true) + } + )).apply { + this.layoutParams = LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT) + }) + } + else + _bottomContentView.removeAllViews(); + fragment.topBar?.let { if(it is FilesTopBarFragment) { if(navStack.size > 1) diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/LibraryFragment.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/LibraryFragment.kt index a28f32c9..1d58331a 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/LibraryFragment.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/LibraryFragment.kt @@ -93,14 +93,18 @@ class LibraryFragment : MainFragment() { UIDialogs.showDialog(requireContext(), R.drawable.ic_library, "Music permissions", "We require permissions to see your on-device music, denying this will hide the option to see local music.", null, 1, UIDialogs.Action("Ok", { - permissionReqAudio.launch(android.Manifest.permission.READ_MEDIA_AUDIO); + StateApp?.instance?.activity?.requestPermissionAudio { + setPermissionResultAudio(it); + } }, UIDialogs.ActionStyle.PRIMARY), UIDialogs.Action("Cancel", { }, UIDialogs.ActionStyle.NONE)); } else -> { - permissionReqAudio.launch(android.Manifest.permission.READ_MEDIA_AUDIO); + StateApp?.instance?.activity?.requestPermissionAudio { + setPermissionResultAudio(it); + } } } } @@ -113,24 +117,22 @@ class LibraryFragment : MainFragment() { UIDialogs.showDialog(requireContext(), R.drawable.ic_library, false, "Videos permissions", "We require permissions to see your on-device videos, denying this will hide the option to see local videos.", null, 1, UIDialogs.Action("Ok", { - permissionReqVideo.launch(android.Manifest.permission.READ_MEDIA_VIDEO); + StateApp?.instance?.activity?.requestPermissionVideo { + setPermissionResultVideo(it); + } }, UIDialogs.ActionStyle.PRIMARY), UIDialogs.Action("Cancel", { }, UIDialogs.ActionStyle.NONE)); } else -> { - permissionReqVideo.launch(android.Manifest.permission.READ_MEDIA_VIDEO); + StateApp?.instance?.activity?.requestPermissionVideo { + setPermissionResultVideo(it); + } } } } - val permissionReqAudio = registerForActivityResult(ActivityResultContracts.RequestPermission(), { isGranted -> - setPermissionResultAudio(isGranted); - }); - val permissionReqVideo = registerForActivityResult(ActivityResultContracts.RequestPermission(), { isGranted -> - setPermissionResultVideo(isGranted); - }); companion object { fun newInstance() = LibraryFragment().apply {} @@ -292,6 +294,7 @@ class LibraryFragment : MainFragment() { } fun onShown() { + UIDialogs.appToast("Library is in alpha\nImprovements are coming to local media playback.") } } } \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt index c7d012bf..1d5f0fab 100644 --- a/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt +++ b/app/src/main/java/com/futo/platformplayer/fragment/mainactivity/main/VideoDetailView.kt @@ -55,6 +55,7 @@ import com.futo.platformplayer.api.media.LiveChatManager import com.futo.platformplayer.api.media.PlatformID import com.futo.platformplayer.api.media.exceptions.ContentNotAvailableYetException import com.futo.platformplayer.api.media.exceptions.NoPlatformClientException +import com.futo.platformplayer.api.media.models.PlatformAuthorLink import com.futo.platformplayer.api.media.models.PlatformAuthorMembershipLink import com.futo.platformplayer.api.media.models.chapters.ChapterType import com.futo.platformplayer.api.media.models.chapters.IChapter @@ -77,6 +78,7 @@ import com.futo.platformplayer.api.media.models.streams.sources.LocalVideoSource import com.futo.platformplayer.api.media.models.subtitles.ISubtitleSource import com.futo.platformplayer.api.media.models.video.IPlatformVideo import com.futo.platformplayer.api.media.models.video.IPlatformVideoDetails +import com.futo.platformplayer.api.media.models.video.LocalVideoDetails import com.futo.platformplayer.api.media.models.video.SerializedPlatformVideo import com.futo.platformplayer.api.media.platforms.js.JSClient import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig @@ -175,6 +177,7 @@ import kotlinx.coroutines.launch import kotlinx.coroutines.sync.Mutex import kotlinx.coroutines.sync.withLock import kotlinx.coroutines.withContext +import kotlinx.serialization.json.Json import userpackage.Protocol import java.time.OffsetDateTime import java.util.Locale @@ -563,6 +566,18 @@ class VideoDetailView : ConstraintLayout { if (video is TutorialFragment.TutorialVideo) { return@setOnClickListener } + if(video is LocalVideoDetails) { + video?.author?.let { + if(it.url.startsWith("content://media/external/audio/artists")) { + fragment.navigate(it.url); + fragment.lifecycleScope.launch { + delay(100); + fragment.minimizeVideoDetail(); + }; + } + } + return@setOnClickListener; + } (video?.author ?: _searchVideo?.author)?.let { fragment.navigate(it); @@ -1035,7 +1050,7 @@ class VideoDetailView : ConstraintLayout { _slideUpOverlay?.hide(); } else null, - if(!isLimitedVersion && !(video?.isLive ?: false)) + if(!isLimitedVersion && !(video?.isLive ?: false) && !(video is LocalVideoDetails)) RoundButton(context, R.drawable.ic_download, context.getString(R.string.download), TAG_DOWNLOAD) { video?.let { _slideUpOverlay = UISlideOverlays.showDownloadVideoOverlay(it, _overlayContainer, context.contentResolver); @@ -1058,15 +1073,16 @@ class VideoDetailView : ConstraintLayout { _slideUpOverlay?.hide(); } else null, - RoundButton(context, R.drawable.ic_export, context.getString(R.string.page), TAG_OPEN) { + if(!(video is LocalVideoDetails)) + RoundButton(context, R.drawable.ic_export, context.getString(R.string.page), TAG_OPEN) { video?.let { val url = video?.shareUrl ?: _searchVideo?.shareUrl ?: _url; fragment.navigate(url); fragment.minimizeVideoDetail(); }; _slideUpOverlay?.hide(); - }, - if (StateSync.instance.hasAuthorizedDevice()) { + } else null, + if (StateSync.instance.hasAuthorizedDevice() && !(video is LocalVideoDetails)) { RoundButton(context, R.drawable.ic_device, context.getString(R.string.send_to_device), TAG_SEND_TO_DEVICE) { val devices = StateSync.instance.getAuthorizedSessions(); val videoToSend = video ?: return@RoundButton; @@ -1089,10 +1105,11 @@ class VideoDetailView : ConstraintLayout { }) } }} else null, - RoundButton(context, R.drawable.ic_refresh, context.getString(R.string.reload), "Reload") { + if(!(video is LocalVideoDetails)) + RoundButton(context, R.drawable.ic_refresh, context.getString(R.string.reload), "Reload") { reloadVideo(); _slideUpOverlay?.hide(); - }).filterNotNull(); + } else null).filterNotNull(); if(!_buttonPinStore.getAllValues().any()) _buttonPins.setButtons(*(buttons + listOf(_buttonMore)).toTypedArray()); else { @@ -1624,7 +1641,9 @@ class VideoDetailView : ConstraintLayout { _buttonSubscribe.setSubscribeChannel(video.author.url); setDescription(video.description.fixHtmlLinks()); - _creatorThumbnail.setThumbnail(video.author.thumbnail, false); + _creatorThumbnail.setThumbnail(video.author.thumbnail, false, + video is LocalVideoDetails + ); setPolycentricProfile(null, animate = false); _taskLoadPolycentricProfile.run(video.author.id); @@ -1652,7 +1671,7 @@ class VideoDetailView : ConstraintLayout { _rating.visibility = View.GONE; - if (StatePolycentric.instance.enabled) { + if (StatePolycentric.instance.enabled && !(video is LocalVideoDetails)) { fragment.lifecycleScope.launch(Dispatchers.IO) { try { val queryReferencesResponse = ApiMethods.getQueryReferences( @@ -1811,17 +1830,19 @@ class VideoDetailView : ConstraintLayout { _player.updateNextPrevious(); updateMoreButtons(); - if (videoDetail is TutorialFragment.TutorialVideo) { + if (videoDetail is TutorialFragment.TutorialVideo || videoDetail is LocalVideoDetails) { _buttonSubscribe.visibility = View.GONE - _buttonMore.visibility = View.GONE - _buttonPins.visibility = View.GONE + _buttonMore.visibility = if(videoDetail is LocalVideoDetails) View.VISIBLE else View.GONE; + _buttonPins.visibility = if(videoDetail is LocalVideoDetails) View.VISIBLE else View.GONE; _layoutRating.visibility = View.GONE + _rating.visibility = View.GONE; _layoutChangeBottomSection.visibility = View.GONE } else { _buttonSubscribe.visibility = View.VISIBLE _buttonMore.visibility = View.VISIBLE _buttonPins.visibility = View.VISIBLE _layoutRating.visibility = View.VISIBLE + _rating.visibility = View.VISIBLE; _layoutChangeBottomSection.visibility = View.VISIBLE } @@ -2685,7 +2706,11 @@ class VideoDetailView : ConstraintLayout { private fun fetchComments() { Logger.i(TAG, "fetchComments") video?.let { - _commentsList.load(true) { StatePlatform.instance.getComments(it); }; + if(video is LocalVideoDetails) { + _commentsList.clearComments(); + } + else + _commentsList.load(true) { StatePlatform.instance.getComments(it); }; } } private fun fetchPolycentricComments() { @@ -2972,6 +2997,7 @@ class VideoDetailView : ConstraintLayout { } onChannelClicked.subscribe { + Logger.i(TAG, "Opening channel url: ${it.url}"); if(it.url.isNotBlank()) { fragment.minimizeVideoDetail() fragment.navigate(it) diff --git a/app/src/main/java/com/futo/platformplayer/models/Telemetry.kt b/app/src/main/java/com/futo/platformplayer/models/Telemetry.kt index bf126caa..90da303e 100644 --- a/app/src/main/java/com/futo/platformplayer/models/Telemetry.kt +++ b/app/src/main/java/com/futo/platformplayer/models/Telemetry.kt @@ -12,5 +12,6 @@ data class Telemetry( val brand: String, val manufacturer: String, val model: String, - val sdkVersion: Int + val sdkVersion: Int, + val plugins: List? = null ) { } \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/states/StateLibrary.kt b/app/src/main/java/com/futo/platformplayer/states/StateLibrary.kt index b2d07e23..c3cf397a 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateLibrary.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateLibrary.kt @@ -7,6 +7,7 @@ import android.net.Uri import android.provider.MediaStore import android.provider.MediaStore.Audio.Artists import android.webkit.MimeTypeMap +import androidx.collection.emptyLongSet import androidx.core.database.getStringOrNull import androidx.core.net.toFile import androidx.core.net.toUri @@ -243,11 +244,12 @@ class StateLibrary { MediaStore.Audio.Media._ID, //0 MediaStore.Audio.Media.DISPLAY_NAME, //1 MediaStore.Audio.Media.ARTIST, //2 - MediaStore.Audio.Media.ALBUM_ID, //3 - MediaStore.Audio.Media.DURATION, //4 - MediaStore.Audio.Media.DATE_ADDED, //5 - MediaStore.Audio.Media.MIME_TYPE, //6 - MediaStore.Audio.Media.BUCKET_DISPLAY_NAME //7 + MediaStore.Audio.Media.ARTIST_ID, //3 + MediaStore.Audio.Media.ALBUM_ID, //4 + MediaStore.Audio.Media.DURATION, //5 + MediaStore.Audio.Media.DATE_ADDED, //6 + MediaStore.Audio.Media.MIME_TYPE, //7 + MediaStore.Audio.Media.BUCKET_DISPLAY_NAME //8 ); fun getDocumentTrack(url: String): IPlatformContentDetails? { @@ -359,11 +361,12 @@ class StateLibrary { val id = cursor.getString(0); val displayName = cursor.getString(1); val author = cursor.getString(2); - val albumId = cursor.getLong(3); - val duration = cursor.getLong(4).let { if(it > 0) it / 1000 else 0 }; - val date = cursor.getLong(5); - val contentType = cursor.getString(6); - val category = cursor.getString(7); + val authorId = cursor.getStringOrNull(3); + val albumId = cursor.getLong(4); + val duration = cursor.getLong(5).let { if(it > 0) it / 1000 else 0 }; + val date = cursor.getLong(6); + val contentType = cursor.getString(7); + val category = cursor.getString(8); val idLong = id.toLongOrNull(); val contentUrl = if(idLong != null ) @@ -371,6 +374,13 @@ class StateLibrary { else ""; + val authorIdLong = authorId?.toLongOrNull(); + val authorUrl = if(authorIdLong != null) + ContentUris.withAppendedId(MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, authorIdLong).toString(); + else + ""; + + val albumContentUrl = if(albumId > 0) ContentUris.withAppendedId(MediaStore.Audio.Albums.EXTERNAL_CONTENT_URI, albumId)?.toString() else null; @@ -380,7 +390,10 @@ class StateLibrary { else null; val authorObj = if(!author.isNullOrBlank()) - PlatformAuthorLink(PlatformID.NONE, author, "", null, null) + PlatformAuthorLink( + if(authorId != null) PlatformID("LOCAL", authorId) else PlatformID.NONE, + author, + authorUrl, null, null) else PlatformAuthorLink.UNKNOWN; return LocalVideoDetails( diff --git a/app/src/main/java/com/futo/platformplayer/states/StateTelemetry.kt b/app/src/main/java/com/futo/platformplayer/states/StateTelemetry.kt index ac353c55..ade30537 100644 --- a/app/src/main/java/com/futo/platformplayer/states/StateTelemetry.kt +++ b/app/src/main/java/com/futo/platformplayer/states/StateTelemetry.kt @@ -39,7 +39,8 @@ class StateTelemetry { Build.BRAND, Build.MANUFACTURER, Build.MODEL, - Build.VERSION.SDK_INT + Build.VERSION.SDK_INT, + StatePlatform.instance.getEnabledClients().map { it.id }.toList() ); val headers = hashMapOf( diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/ArtistTileViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/ArtistTileViewHolder.kt index ab4f4664..70fb0b4a 100644 --- a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/ArtistTileViewHolder.kt +++ b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/ArtistTileViewHolder.kt @@ -40,10 +40,10 @@ class ArtistTileViewHolder(val _viewGroup: ViewGroup) : AnyAdapter.AnyViewHolder if (artist.thumbnail != null) Glide.with(it) .load(artist.thumbnail) - .placeholder(R.drawable.unknown_music) + .placeholder(R.drawable.ic_artist) .into(it) else - Glide.with(it).load(R.drawable.unknown_music).into(it); + Glide.with(it).load(R.drawable.ic_artist).into(it); }; _textName.text = artist.name; diff --git a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/FileViewHolder.kt b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/FileViewHolder.kt index 04b94d0c..bb425af1 100644 --- a/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/FileViewHolder.kt +++ b/app/src/main/java/com/futo/platformplayer/views/adapters/viewholders/FileViewHolder.kt @@ -42,11 +42,11 @@ class FileViewHolder(private val _viewGroup: ViewGroup) : AnyAdapter.AnyViewHold _file = file; _imageThumbnail?.let { if(file.isDirectory) - it.setImageResource(R.drawable.ic_library); + it.setImageResource(R.drawable.ic_folder); else { Glide.with(it) .load(file.thumbnail) - .placeholder(R.drawable.ic_music) + .placeholder(R.drawable.ic_song) .into(it) } }; diff --git a/app/src/main/java/com/futo/platformplayer/views/buttons/ButtonsContainer.kt b/app/src/main/java/com/futo/platformplayer/views/buttons/ButtonsContainer.kt new file mode 100644 index 00000000..8077306d --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/views/buttons/ButtonsContainer.kt @@ -0,0 +1,47 @@ +package com.futo.platformplayer.views.buttons + +import android.content.Context +import android.util.AttributeSet +import android.view.View +import android.widget.ImageView +import android.widget.LinearLayout +import android.widget.TextView +import androidx.collection.emptyLongSet +import com.futo.platformplayer.R +import com.futo.platformplayer.constructs.Event0 +import com.futo.platformplayer.views.pills.PillButton + +class ButtonsContainer : LinearLayout { + + val container_buttons: LinearLayout + + var currentButtons: List