diff --git a/.github/workflows/android.yml b/.github/workflows/android.yml index 18fa46ae9..92cabb430 100644 --- a/.github/workflows/android.yml +++ b/.github/workflows/android.yml @@ -2,9 +2,9 @@ name: Android CI on: push: - branches: [ dev ] + branches: [dev] pull_request: - branches: [ dev ] + branches: [dev] jobs: check: @@ -16,7 +16,7 @@ jobs: - uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 17 + java-version: 21 - uses: gradle/actions/setup-gradle@v3 - name: Lint Android run: ./gradlew lint @@ -28,7 +28,7 @@ jobs: - uses: actions/setup-java@v4 with: distribution: 'zulu' - java-version: 17 + java-version: 21 - uses: gradle/actions/setup-gradle@v3 - name: Build run: ./gradlew app:assemble diff --git a/app/build.gradle b/app/build.gradle index d71bbfdc3..fa673ac38 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,18 +5,18 @@ apply plugin: 'kotlin-parcelize' apply plugin: 'com.google.devtools.ksp' android { - compileSdk 34 + compileSdk 35 namespace "code.name.monkey.retromusic" defaultConfig { minSdk 21 - targetSdk 34 + targetSdk 35 vectorDrawables.useSupportLibrary = true applicationId namespace - versionCode 10603 - versionName '6.1.0' + versionCode 10620 + versionName '6.2.0' buildConfigField("String", "GOOGLE_PLAY_LICENSING_KEY", "\"${getProperty(getProperties('../public.properties'), 'GOOGLE_PLAY_LICENSE_KEY')}\"") } @@ -69,11 +69,11 @@ android { warning 'ImpliedQuantity', 'Instantiatable', 'MissingQuantity', 'MissingTranslation', 'StringFormatInvalid' } compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 } kotlinOptions { - jvmTarget = "17" + jvmTarget = "21" } dependenciesInfo { includeInApk = false diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 7aa3313de..005f38ec7 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -73,4 +73,4 @@ # TypeToken https://stackoverflow.com/questions/70969756/caused-by-java-lang-runtimeexception-missing-type-parameter -keep class com.google.gson.reflect.TypeToken -keep class * extends com.google.gson.reflect.TypeToken --keep public class * implements java.lang.reflect.Type +-keep public class * implements java.lang.reflect.Type \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/Constants.kt b/app/src/main/java/code/name/monkey/retromusic/Constants.kt index 4cb587575..400b1c473 100644 --- a/app/src/main/java/code/name/monkey/retromusic/Constants.kt +++ b/app/src/main/java/code/name/monkey/retromusic/Constants.kt @@ -161,4 +161,5 @@ const val CIRCLE_PLAY_BUTTON = "circle_play_button" const val SWIPE_ANYWHERE_NOW_PLAYING = "swipe_anywhere_now_playing" const val PAUSE_HISTORY = "pause_history" const val MANAGE_AUDIO_FOCUS = "manage_audio_focus" -const val SWIPE_DOWN_DISMISS = "swipe_to_dismiss" \ No newline at end of file +const val SWIPE_DOWN_DISMISS = "swipe_to_dismiss" +const val ENABLE_SEARCH_PLAYLIST= "enable_search_playlist" \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt index a7ac69397..67c61ca5a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt @@ -252,7 +252,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(), PreferenceUtil.unregisterOnSharedPreferenceChangedListener(this) } - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) { when (key) { SWIPE_DOWN_DISMISS -> { bottomSheetBehavior.isHideable = PreferenceUtil.swipeDownToDismiss diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt index bf85fe28b..78f2f53f6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt @@ -25,6 +25,7 @@ import code.name.monkey.retromusic.db.toSongEntity import code.name.monkey.retromusic.db.toSongsEntity import code.name.monkey.retromusic.dialogs.RemoveSongFromPlaylistDialog import code.name.monkey.retromusic.fragments.LibraryViewModel +import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.ViewUtil import com.h6ah4i.android.widget.advrecyclerview.draggable.DraggableItemAdapter @@ -43,9 +44,20 @@ class OrderablePlaylistSongAdapter( val libraryViewModel: LibraryViewModel by activity.viewModel() + private var filtered = false + private var filter: CharSequence? = null + private var fullDataSet: MutableList + init { this.setHasStableIds(true) this.setMultiSelectMenuRes(R.menu.menu_playlists_songs_selection) + fullDataSet = dataSet.toMutableList() + } + + override fun swapDataSet(dataSet: List) { + super.swapDataSet(dataSet) + fullDataSet = dataSet.toMutableList() + onFilter(filter) } override fun getItemId(position: Int): Long { @@ -90,13 +102,22 @@ class OrderablePlaylistSongAdapter( return super.onSongMenuItemClick(item) } + override fun onClick(v: View?) { + if (isInQuickSelectMode || !filtered) { + super.onClick(v) + } else { + val position = fullDataSet.indexOf(dataSet.get(layoutPosition)) + MusicPlayerRemote.openQueueKeepShuffleMode(fullDataSet, position, true) + } + } + init { dragView?.isVisible = true } } override fun onCheckCanStartDrag(holder: ViewHolder, position: Int, x: Int, y: Int): Boolean { - if (isInQuickSelectMode) { + if (isInQuickSelectMode || filtered) { return false } return ViewUtil.hitTest(holder.imageText!!, x, y) || ViewUtil.hitTest( @@ -127,8 +148,27 @@ class OrderablePlaylistSongAdapter( } fun saveSongs(playlistEntity: PlaylistEntity) { + onFilter(null) activity.lifecycleScope.launch(Dispatchers.IO) { libraryViewModel.insertSongs(dataSet.toSongsEntity(playlistEntity)) } } + + + fun onFilter(text: CharSequence?) { + filter = text + if (text.isNullOrEmpty()) { + filtered = false + dataSet = fullDataSet + } else { + filtered = true + dataSet = fullDataSet.filter { song -> song.title.contains(text, ignoreCase = true) } + .toMutableList() + } + notifyDataSetChanged() + } + + fun hasSongs(): Boolean { + return itemCount > 0 || (filtered && fullDataSet.size > 0) + } } diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/SongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/SongAdapter.kt index 7b7b7bf99..772cc7ada 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/SongAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/SongAdapter.kt @@ -216,7 +216,7 @@ open class SongAdapter( if (isInQuickSelectMode) { toggleChecked(layoutPosition) } else { - MusicPlayerRemote.openQueue(dataSet, layoutPosition, true) + MusicPlayerRemote.openQueueKeepShuffleMode(dataSet, layoutPosition, true) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutLauncherActivity.kt b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutLauncherActivity.kt index 502ff0e71..3c551c17b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutLauncherActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutLauncherActivity.kt @@ -68,6 +68,7 @@ class AppShortcutLauncherActivity : Activity() { INTENT_EXTRA_PLAYLIST to playlist, INTENT_EXTRA_SHUFFLE_MODE to shuffleMode ) + intent.setPackage(this.packageName) intent.putExtras(bundle) diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/SleepTimerDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/SleepTimerDialog.kt index 75bc9b436..90e3a7572 100755 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/SleepTimerDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/SleepTimerDialog.kt @@ -198,4 +198,4 @@ class SleepTimerDialog : DialogFragment() { override fun onFinish() {} } -} +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt index 91f8b9921..bb0950950 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt @@ -374,7 +374,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme e1: MotionEvent?, e2: MotionEvent, distanceX: Float, - distanceY: Float + distanceY: Float, ): Boolean { return when { abs(distanceX) > abs(distanceY) -> { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/CoverLyricsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/CoverLyricsFragment.kt index ee32e72d3..afd18c347 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/CoverLyricsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/CoverLyricsFragment.kt @@ -69,9 +69,9 @@ class CoverLyricsFragment : AbsMusicServiceFragment(R.layout.fragment_cover_lyri } - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) { if (key == SHOW_LYRICS) { - if (sharedPreferences?.getBoolean(key, false) == true) { + if (sharedPreferences.getBoolean(key, false) == true) { progressViewUpdateHelper?.start() binding.root.isVisible = true updateLyrics() diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerFragment.kt index 45bbac39d..7d0fef4a8 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerFragment.kt @@ -152,7 +152,7 @@ class PlayerFragment : AbsPlayerFragment(R.layout.fragment_player), ) } - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) { if (key == SNOWFALL) { startOrStopSnow(PreferenceUtil.isSnowFalling) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt index 352bf453b..a02cb3dde 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt @@ -8,6 +8,8 @@ import android.view.MenuItem import android.view.View import androidx.core.view.doOnPreDraw import androidx.core.view.isVisible +import androidx.core.widget.addTextChangedListener +import androidx.lifecycle.lifecycleScope import androidx.navigation.fragment.findNavController import androidx.navigation.fragment.navArgs import androidx.recyclerview.widget.LinearLayoutManager @@ -21,12 +23,14 @@ import code.name.monkey.retromusic.extensions.accentColor import code.name.monkey.retromusic.extensions.elevatedAccentColor import code.name.monkey.retromusic.extensions.surfaceColor import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment +import code.name.monkey.retromusic.fragments.search.clearText import code.name.monkey.retromusic.glide.RetroGlideExtension.playlistOptions import code.name.monkey.retromusic.glide.playlistPreview.PlaylistPreview import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.MusicUtil +import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.ThemedFastScroller import com.bumptech.glide.Glide import com.google.android.material.shape.MaterialShapeDrawable @@ -35,6 +39,9 @@ import com.google.android.material.transition.MaterialContainerTransform import com.google.android.material.transition.MaterialSharedAxis import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager +import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.debounce +import kotlinx.coroutines.launch import org.koin.androidx.viewmodel.ext.android.viewModel import org.koin.core.parameter.parametersOf @@ -51,6 +58,8 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli private lateinit var playlist: PlaylistWithSongs private lateinit var playlistSongAdapter: OrderablePlaylistSongAdapter + private val _searchFlow = MutableSharedFlow() + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) sharedElementEnterTransition = MaterialContainerTransform(requireContext(), true).apply { @@ -71,6 +80,7 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli // binding.container.transitionName = playlist.playlistEntity.playlistName setUpRecyclerView() + setUpSearch() setupButtons() viewModel.getPlaylist().observe(viewLifecycleOwner) { playlistWithSongs -> playlist = playlistWithSongs @@ -112,6 +122,33 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli } } + private fun setUpSearch() { + if (!PreferenceUtil.enableSearchPlaylist) { + binding.playlistSearchView.visibility = View.GONE + } else { + binding.playlistSearchView.visibility = View.VISIBLE + } + binding.playlistSearchView.addTextChangedListener { text -> + lifecycleScope.launch { + _searchFlow.emit(text) + binding.clearSearch.visibility = + if (text.isNullOrBlank()) View.GONE else View.VISIBLE + } + } + binding.clearSearch.setOnClickListener { + lifecycleScope.launch { + _searchFlow.emit(null) + binding.playlistSearchView.clearText() + binding.clearSearch.visibility = View.GONE + } + } + lifecycleScope.launch { + _searchFlow.debounce(300).collect { text -> + playlistSongAdapter.onFilter(text) + } + } + } + private fun setUpRecyclerView() { playlistSongAdapter = OrderablePlaylistSongAdapter( arguments.extraPlaylistId, @@ -150,8 +187,18 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli } private fun checkIsEmpty() { - binding.empty.isVisible = playlistSongAdapter.itemCount == 0 - binding.emptyText.isVisible = playlistSongAdapter.itemCount == 0 + if (_binding != null) { + if (playlistSongAdapter.itemCount != 0) { + binding.empty.isVisible = false + } else { + binding.empty.isVisible = true + if (playlistSongAdapter.hasSongs()) { + binding.emptyText.text = getString(R.string.no_search_results) + } else { + binding.emptyText.text = getString(R.string.no_songs) + } + } + } } override fun onDestroy() { @@ -160,6 +207,7 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli } override fun onPause() { + binding.playlistSearchView.clearText() playlistSongAdapter.saveSongs(playlist.playlistEntity) super.onPause() } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/NotificationSettingsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/NotificationSettingsFragment.kt index 2abffa6b0..d18f3430a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/NotificationSettingsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/NotificationSettingsFragment.kt @@ -31,7 +31,7 @@ import code.name.monkey.retromusic.util.PreferenceUtil class NotificationSettingsFragment : AbsSettingsFragment(), SharedPreferences.OnSharedPreferenceChangeListener { - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) { if (key == CLASSIC_NOTIFICATION) { if (VERSION.SDK_INT >= VERSION_CODES.O) { findPreference(COLORED_NOTIFICATION)?.isEnabled = diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/NowPlayingSettingsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/NowPlayingSettingsFragment.kt index 753707659..586312974 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/NowPlayingSettingsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/NowPlayingSettingsFragment.kt @@ -72,7 +72,7 @@ class NowPlayingSettingsFragment : AbsSettingsFragment(), PreferenceUtil.unregisterOnSharedPreferenceChangedListener(this) } - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) { when (key) { NOW_PLAYING_SCREEN_ID -> updateNowPlayingScreenSummary() ALBUM_COVER_STYLE -> updateAlbumCoverStyleSummary() diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/RetroGlideExtension.kt b/app/src/main/java/code/name/monkey/retromusic/glide/RetroGlideExtension.kt index 11439ace9..fa12ad39a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/glide/RetroGlideExtension.kt +++ b/app/src/main/java/code/name/monkey/retromusic/glide/RetroGlideExtension.kt @@ -39,11 +39,14 @@ import java.io.File object RetroGlideExtension { - private const val DEFAULT_ARTIST_IMAGE = - R.drawable.default_artist_art - private const val DEFAULT_SONG_IMAGE: Int = R.drawable.default_audio_art - private const val DEFAULT_ALBUM_IMAGE = R.drawable.default_album_art - private const val DEFAULT_ERROR_IMAGE_BANNER = R.drawable.material_design_default + private val DEFAULT_ARTIST_IMAGE + get() = R.drawable.default_artist_art + private val DEFAULT_SONG_IMAGE: Int + get() = R.drawable.default_audio_art + private val DEFAULT_ALBUM_IMAGE + get() = R.drawable.default_album_art + private val DEFAULT_ERROR_IMAGE_BANNER + get() = R.drawable.material_design_default private val DEFAULT_DISK_CACHE_STRATEGY_ARTIST = DiskCacheStrategy.RESOURCE private val DEFAULT_DISK_CACHE_STRATEGY = DiskCacheStrategy.NONE diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/HorizontalAdapterHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/HorizontalAdapterHelper.kt index f98508bf8..56b6990cf 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/HorizontalAdapterHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/HorizontalAdapterHelper.kt @@ -20,7 +20,8 @@ import code.name.monkey.retromusic.R object HorizontalAdapterHelper { - const val LAYOUT_RES = R.layout.item_image + val LAYOUT_RES + get() = R.layout.item_image private const val TYPE_FIRST = 1 private const val TYPE_MIDDLE = 2 diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt b/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt index c2d3627c7..338af9f07 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt @@ -211,15 +211,7 @@ object MusicPlayerRemote : KoinComponent { */ @JvmStatic fun openQueue(queue: List, startPosition: Int, startPlaying: Boolean) { - if (!tryToHandleOpenPlayingQueue( - queue, - startPosition, - startPlaying - ) && musicService != null - ) { - musicService?.openQueue(queue, startPosition, startPlaying) - setShuffleMode(MusicService.SHUFFLE_MODE_NONE) - } + doOpenQueue(queue, startPosition, startPlaying, MusicService.SHUFFLE_MODE_NONE) } @JvmStatic @@ -229,6 +221,15 @@ object MusicPlayerRemote : KoinComponent { startPosition = Random().nextInt(queue.size) } + doOpenQueue(queue, startPosition, startPlaying, MusicService.SHUFFLE_MODE_SHUFFLE) + } + + @JvmStatic + fun openQueueKeepShuffleMode(queue: List, startPosition: Int, startPlaying: Boolean) { + doOpenQueue(queue, startPosition, startPlaying, shuffleMode) + } + + private fun doOpenQueue(queue: List, startPosition: Int, startPlaying: Boolean, shuffleMode: Int) { if (!tryToHandleOpenPlayingQueue( queue, startPosition, @@ -236,7 +237,7 @@ object MusicPlayerRemote : KoinComponent { ) && musicService != null ) { musicService?.openQueue(queue, startPosition, startPlaying) - setShuffleMode(MusicService.SHUFFLE_MODE_SHUFFLE) + setShuffleMode(shuffleMode) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt index 801c2b209..59b1d0eb0 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt @@ -48,7 +48,8 @@ import org.koin.core.component.get import java.io.File object SongMenuHelper : KoinComponent { - const val MENU_RES = R.menu.menu_item_song + val MENU_RES + get() = R.menu.menu_item_song fun handleMenuClick(activity: FragmentActivity, song: Song, menuItemId: Int): Boolean { val libraryViewModel = activity.getViewModel() as LibraryViewModel diff --git a/app/src/main/java/code/name/monkey/retromusic/service/LocalPlayback.kt b/app/src/main/java/code/name/monkey/retromusic/service/LocalPlayback.kt index 429867051..07ab35fcb 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/LocalPlayback.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/LocalPlayback.kt @@ -9,6 +9,7 @@ import android.media.AudioManager import android.media.MediaPlayer import android.media.PlaybackParams import androidx.annotation.CallSuper +import androidx.core.content.ContextCompat import androidx.core.content.getSystemService import androidx.core.net.toUri import androidx.media.AudioAttributesCompat @@ -157,9 +158,11 @@ abstract class LocalPlayback(val context: Context) : Playback, MediaPlayer.OnErr private fun registerBecomingNoisyReceiver() { if (!becomingNoisyReceiverRegistered) { - context.registerReceiver( + ContextCompat.registerReceiver( + context, becomingNoisyReceiver, - becomingNoisyReceiverIntentFilter + becomingNoisyReceiverIntentFilter, + ContextCompat.RECEIVER_EXPORTED ) becomingNoisyReceiverRegistered = true } diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt index 77cabfc87..078c8d575 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt @@ -633,7 +633,9 @@ class MusicService : MediaBrowserServiceCompat(), } } - override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { + override fun onSharedPreferenceChanged( + sharedPreferences: SharedPreferences, key: String?, + ) { when (key) { PLAYBACK_SPEED, PLAYBACK_PITCH -> { updateMediaSessionPlaybackState() @@ -1276,7 +1278,7 @@ class MusicService : MediaBrowserServiceCompat(), private fun registerHeadsetEvents() { if (!headsetReceiverRegistered && isHeadsetPlugged) { - registerReceiver(headsetReceiver, headsetReceiverIntentFilter) + ContextCompat.registerReceiver(this, headsetReceiver, headsetReceiverIntentFilter, ContextCompat.RECEIVER_EXPORTED) headsetReceiverRegistered = true } } diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PackageValidator.kt b/app/src/main/java/code/name/monkey/retromusic/util/PackageValidator.kt index 012dfc85a..468c77d7c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/PackageValidator.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/PackageValidator.kt @@ -167,14 +167,14 @@ class PackageValidator( private fun buildCallerInfo(callingPackage: String): CallerPackageInfo? { val packageInfo = getPackageInfo(callingPackage) ?: return null - val appName = packageInfo.applicationInfo.loadLabel(packageManager).toString() - val uid = packageInfo.applicationInfo.uid + val appName = packageInfo.applicationInfo?.loadLabel(packageManager)?.toString() ?: return null + val uid = packageInfo.applicationInfo?.uid ?: return null val signature = getSignature(packageInfo) - val requestedPermissions = packageInfo.requestedPermissions - val permissionFlags = packageInfo.requestedPermissionsFlags + val requestedPermissions = packageInfo.requestedPermissions ?: emptyArray() + val permissionFlags = packageInfo.requestedPermissionsFlags ?: IntArray(requestedPermissions.size) val activePermissions = mutableSetOf() - requestedPermissions?.forEachIndexed { index, permission -> + requestedPermissions.forEachIndexed { index, permission -> if (permissionFlags[index] and REQUESTED_PERMISSION_GRANTED != 0) { activePermissions += permission } @@ -207,12 +207,13 @@ class PackageValidator( */ @Suppress("deprecation") private fun getSignature(packageInfo: PackageInfo): String? { - // Security best practices dictate that an app should be signed with exactly one (1) - // signature. Because of this, if there are multiple signatures, reject it. - return if (packageInfo.signatures == null || packageInfo.signatures.size != 1) { + val signatures = packageInfo.signatures + return if (signatures == null || signatures.size != 1) { + // Security best practices dictate that an app should be signed with exactly one (1) + // signature. Because of this, if there are multiple signatures, reject it. null } else { - val certificate = packageInfo.signatures[0].toByteArray() + val certificate = signatures[0].toByteArray() getSignatureSha256(certificate) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt index 6613c22ab..f01bb0346 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt @@ -680,6 +680,9 @@ object PreferenceUtil { val rememberLastTab: Boolean get() = sharedPreferences.getBoolean(REMEMBER_LAST_TAB, true) + val enableSearchPlaylist: Boolean + get() = sharedPreferences.getBoolean(ENABLE_SEARCH_PLAYLIST, true) + var lastTab: Int get() = sharedPreferences .getInt(LAST_USED_TAB, 0) diff --git a/app/src/main/res/layout/fragment_playlist_detail_new.xml b/app/src/main/res/layout/fragment_playlist_detail_new.xml index 1d2003ee4..a968a6989 100644 --- a/app/src/main/res/layout/fragment_playlist_detail_new.xml +++ b/app/src/main/res/layout/fragment_playlist_detail_new.xml @@ -30,6 +30,33 @@ android:paddingBottom="16dp" android:paddingHorizontal="16dp"> + + + + + No purchase found. No results You have no songs + No search results Normal Normal lyrics %s is not listed in the media store.]]> @@ -365,6 +366,7 @@ License details for open source software When enabled, newly played songs won\'t show in history Navigate to the last used tab on start + Show a search field in a playlist Display synced lyrics over album cover Show New Music Mix on homescreen Enables changing song by swiping anywhere on the now playing screen @@ -412,6 +414,7 @@ Open source licences Pause history Remember last tab + Enable search in playlist Show lyrics Show suggestions Swipe anywhere to change song diff --git a/app/src/main/res/xml/pref_ui.xml b/app/src/main/res/xml/pref_ui.xml index 3517e949b..58020fa24 100644 --- a/app/src/main/res/xml/pref_ui.xml +++ b/app/src/main/res/xml/pref_ui.xml @@ -67,6 +67,13 @@ android:summary="@string/pref_summary_remember_tab" android:title="@string/pref_title_remember_tab" /> + +