From c4ec9d03dab6558c4c7ce7e8556cb957f3ee0ff1 Mon Sep 17 00:00:00 2001 From: tomaThomas Date: Sat, 30 Nov 2024 12:58:15 +0100 Subject: [PATCH 1/8] Keep Shuffle status when selecting song --- .../retromusic/adapter/song/SongAdapter.kt | 2 +- .../retromusic/helper/MusicPlayerRemote.kt | 21 ++++++++++--------- 2 files changed, 12 insertions(+), 11 deletions(-) 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/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) } } From 54393ca88894634304fd65b04d8b9fe3f964bbc7 Mon Sep 17 00:00:00 2001 From: Valeri Gokadze Date: Wed, 4 Dec 2024 18:48:43 +0400 Subject: [PATCH 2/8] Add support for Android 14-15 --- app/build.gradle | 6 ++-- app/proguard-rules.pro | 5 ++++ .../base/AbsSlidingMusicPanelActivity.kt | 2 +- .../AppShortcutLauncherActivity.kt | 1 + .../retromusic/dialogs/SleepTimerDialog.kt | 23 +++++++++++++++ .../fragments/base/AbsPlayerFragment.kt | 2 +- .../fragments/player/CoverLyricsFragment.kt | 4 +-- .../fragments/player/normal/PlayerFragment.kt | 2 +- .../settings/NotificationSettingsFragment.kt | 2 +- .../settings/NowPlayingSettingsFragment.kt | 2 +- .../retromusic/glide/RetroGlideExtension.kt | 13 +++++---- .../helper/HorizontalAdapterHelper.kt | 3 +- .../retromusic/helper/menu/SongMenuHelper.kt | 3 +- .../retromusic/service/LocalPlayback.kt | 7 +++-- .../monkey/retromusic/service/MusicService.kt | 6 ++-- appthemehelper/build.gradle | 11 +++++--- gradle/libs.versions.toml | 28 +++++++++---------- 17 files changed, 81 insertions(+), 39 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index d71bbfdc3..dd2f699d4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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..49498d773 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -20,6 +20,11 @@ # debugging stack traces. -keepattributes SourceFile,LineNumberTable +# required after agp 8 made r8 full mode default +-keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken +-keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken +-keep,allowobfuscation,allowshrinking public class * implements java.lang.reflect.Type + # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile 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/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..a187a7f46 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 @@ -131,6 +131,29 @@ class SleepTimerDialog : DialogFragment() { SystemClock.elapsedRealtime() + minutes * 60 * 1000 PreferenceUtil.nextSleepTimerElapsedRealTime = nextSleepTimerElapsedTime.toInt() val am = requireContext().getSystemService() + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + if (am?.canScheduleExactAlarms() == false) { + Intent().also { intent -> + intent.action = Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM + context.startActivity(intent) + } + } else { + am?.setExact( + AlarmManager.ELAPSED_REALTIME_WAKEUP, + nextSleepTimerElapsedTime, + pi + ) + + Toast.makeText( + requireContext(), + requireContext().resources.getString( + R.string.sleep_timer_set, + minutes + ), + Toast.LENGTH_SHORT + ).show() + } + } if (VersionUtils.hasS() && am?.canScheduleExactAlarms() != true) { Toast.makeText( 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/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/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/appthemehelper/build.gradle b/appthemehelper/build.gradle index 480af3bcc..999c0efb4 100644 --- a/appthemehelper/build.gradle +++ b/appthemehelper/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' android { - compileSdk 35 + compileSdk 34 namespace "code.name.monkey.appthemehelper" defaultConfig { minSdk 21 - targetSdk 35 + targetSdk 34 } buildTypes { release { @@ -18,8 +18,11 @@ android { abortOnError false } compileOptions { - sourceCompatibility JavaVersion.VERSION_17 - targetCompatibility JavaVersion.VERSION_17 + sourceCompatibility JavaVersion.VERSION_21 + targetCompatibility JavaVersion.VERSION_21 + } + kotlinOptions { + jvmTarget = "21" } } diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 694e003d5..8e849818b 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -5,7 +5,7 @@ jetradarmobile_androidSnowfall_version = "1.2.1" tankery_circularSeekBar_version = "1.4.2" retrofit_version = "2.9.0" afollestad_dialog_version = "3.3.0" -coreSplashscreen = "1.0.0" +coreSplashscreen = "1.0.1" customactivityoncrash = "2.4.0" fadingedgelayout = "1.0.0" google_featureDelivery_version = "2.1.0" @@ -15,30 +15,30 @@ chrisbanes_insetter_version = "0.6.1" jaudiotagger = "2.3.15" yslibrary_keyboardvisibilityevent_version = "3.0.0-RC3" koinAndroid = "3.4.0" -kotlinGradlePlugin = "1.8.10" +kotlinGradlePlugin = "1.9.22" -kotlinxCoroutinesAndroid = "1.6.4" -android_tab_library_version = "2.0.3" +kotlinxCoroutinesAndroid = "1.7.3" +android_tab_library_version = "2.2.0" fast_scroll_libraryVersion = "1.2.0" -lifecycle_version = "2.6.1" +lifecycle_version = "2.7.0" okhttp3_loggingInterceptor_version = "5.0.0-alpha.9" afollestad_materialCab_version = "2.0.1" materialIntro = "2.0.0" -mediarouter = "1.3.1" +mediarouter = "1.6.0" nanohttpd = "2.3.1" -navigation_version = "2.5.3" -mdc_version = "1.9.0-beta01" +navigation_version = "2.7.6" +mdc_version = "1.9.0" glide_version = "4.15.1" orgEclipseEgitGithubCore = "2.1.5" playServicesCastFramework = "21.3.0" -preference_version = "1.2.0" +preference_version = "1.2.1" appcompat_version = "1.6.1" google_play_review_version = "2.0.1" -room_version = "2.5.1" -core_version = "1.10.0-rc01" +room_version = "2.6.1" +core_version = "1.12.0" #plugins -devTools_ksp_version = "1.8.10-1.0.9" +devTools_ksp_version = "1.9.22-1.0.17" ben_manes_versoin = "0.46.0" slidableactivity = "2.1.0" @@ -111,9 +111,9 @@ nanohttpd = { group = "org.nanohttpd", name = "nanohttpd", version.ref = "nanoht #androidx androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat_version" } -androidx-annotation = { group = "androidx.annotation", name = "annotation", version = "1.6.0" } +androidx-annotation = { group = "androidx.annotation", name = "annotation", version = "1.7.1" } androidx-constraintLayout = { group = "androidx.constraintlayout", name = "constraintlayout", version = "2.1.4" } -androidx-recyclerview = { group = "androidx.recyclerview", name = "recyclerview", version = "1.3.0" } +androidx-recyclerview = { group = "androidx.recyclerview", name = "recyclerview", version = "1.3.2" } androidx-preference-ktx = { group = "androidx.preference", name = "preference-ktx", version.ref = "preference_version" } androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "core_version" } androidx-core-splashscreen = { module = "androidx.core:core-splashscreen", version.ref = "coreSplashscreen" } From ee987b84fe2afeb454c845383f598cd1ababc477 Mon Sep 17 00:00:00 2001 From: Valeri Gokadze Date: Wed, 4 Dec 2024 19:12:17 +0400 Subject: [PATCH 3/8] Update builder workflow Java version --- .github/workflows/android.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) 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 From 24e9d6c5bf7ee92c5e84a12f12955bdf11a33807 Mon Sep 17 00:00:00 2001 From: Valeri Gokadze Date: Wed, 4 Dec 2024 22:52:27 +0400 Subject: [PATCH 4/8] Remove accidentally copied code --- app/proguard-rules.pro | 7 +----- .../retromusic/dialogs/SleepTimerDialog.kt | 25 +------------------ 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 49498d773..005f38ec7 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -20,11 +20,6 @@ # debugging stack traces. -keepattributes SourceFile,LineNumberTable -# required after agp 8 made r8 full mode default --keep,allowobfuscation,allowshrinking class com.google.gson.reflect.TypeToken --keep,allowobfuscation,allowshrinking class * extends com.google.gson.reflect.TypeToken --keep,allowobfuscation,allowshrinking public class * implements java.lang.reflect.Type - # If you keep the line number information, uncomment this to # hide the original source file name. #-renamesourcefileattribute SourceFile @@ -78,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/dialogs/SleepTimerDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/SleepTimerDialog.kt index a187a7f46..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 @@ -131,29 +131,6 @@ class SleepTimerDialog : DialogFragment() { SystemClock.elapsedRealtime() + minutes * 60 * 1000 PreferenceUtil.nextSleepTimerElapsedRealTime = nextSleepTimerElapsedTime.toInt() val am = requireContext().getSystemService() - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { - if (am?.canScheduleExactAlarms() == false) { - Intent().also { intent -> - intent.action = Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM - context.startActivity(intent) - } - } else { - am?.setExact( - AlarmManager.ELAPSED_REALTIME_WAKEUP, - nextSleepTimerElapsedTime, - pi - ) - - Toast.makeText( - requireContext(), - requireContext().resources.getString( - R.string.sleep_timer_set, - minutes - ), - Toast.LENGTH_SHORT - ).show() - } - } if (VersionUtils.hasS() && am?.canScheduleExactAlarms() != true) { Toast.makeText( @@ -221,4 +198,4 @@ class SleepTimerDialog : DialogFragment() { override fun onFinish() {} } -} +} \ No newline at end of file From 5a206e101f3aaaad8aa206be939bc80c97316afb Mon Sep 17 00:00:00 2001 From: Valeri Gokadze Date: Fri, 6 Dec 2024 13:56:59 +0400 Subject: [PATCH 5/8] Make target and compile sdk version 35 again --- app/build.gradle | 4 ++-- .../retromusic/util/PackageValidator.kt | 19 ++++++++++--------- appthemehelper/build.gradle | 4 ++-- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index dd2f699d4..b816bb147 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -5,12 +5,12 @@ 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 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/appthemehelper/build.gradle b/appthemehelper/build.gradle index 999c0efb4..910085347 100644 --- a/appthemehelper/build.gradle +++ b/appthemehelper/build.gradle @@ -1,12 +1,12 @@ apply plugin: 'com.android.library' apply plugin: 'kotlin-android' android { - compileSdk 34 + compileSdk 35 namespace "code.name.monkey.appthemehelper" defaultConfig { minSdk 21 - targetSdk 34 + targetSdk 35 } buildTypes { release { From 1c49bdcd727d9ac9bccd6b8bcc789b1049a675cf Mon Sep 17 00:00:00 2001 From: Hemanth Savarala Date: Fri, 6 Dec 2024 18:01:47 +0530 Subject: [PATCH 6/8] Update build.gradle --- app/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index b816bb147..fa673ac38 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -15,8 +15,8 @@ android { 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')}\"") } From b9d3ee6ddb092d09638059f510573d8adcba7607 Mon Sep 17 00:00:00 2001 From: tomaThomas Date: Fri, 11 Oct 2024 19:25:15 +0200 Subject: [PATCH 7/8] Add basic search in playlist --- .../song/OrderablePlaylistSongAdapter.kt | 38 ++++++++++++++++++- .../playlists/PlaylistDetailsFragment.kt | 19 ++++++++++ .../layout/fragment_playlist_detail_new.xml | 15 ++++++++ gradle/libs.versions.toml | 2 +- 4 files changed, 72 insertions(+), 2 deletions(-) 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..a9f9c0c2d 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.openQueue(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,23 @@ 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() + } } 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..c007c935b 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,6 +23,7 @@ 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 @@ -35,6 +38,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 +57,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 { @@ -119,6 +127,16 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli ArrayList(), R.layout.item_queue ) + binding.playlistSearchView.addTextChangedListener { text -> + lifecycleScope.launch { + _searchFlow.emit(text) + } + } + lifecycleScope.launch { + _searchFlow.debounce(300).collect { text -> + playlistSongAdapter.onFilter(text) + } + } val dragDropManager = RecyclerViewDragDropManager() @@ -160,6 +178,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/res/layout/fragment_playlist_detail_new.xml b/app/src/main/res/layout/fragment_playlist_detail_new.xml index 1d2003ee4..3761902e3 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,21 @@ android:paddingBottom="16dp" android:paddingHorizontal="16dp"> + + + Date: Fri, 11 Oct 2024 21:26:14 +0200 Subject: [PATCH 8/8] Add setting to hide search in playlist --- .../code/name/monkey/retromusic/Constants.kt | 3 +- .../song/OrderablePlaylistSongAdapter.kt | 6 ++- .../playlists/PlaylistDetailsFragment.kt | 53 ++++++++++++++----- .../monkey/retromusic/util/PreferenceUtil.kt | 3 ++ .../layout/fragment_playlist_detail_new.xml | 25 ++++++--- app/src/main/res/values/strings.xml | 3 ++ app/src/main/res/xml/pref_ui.xml | 7 +++ 7 files changed, 80 insertions(+), 20 deletions(-) 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/adapter/song/OrderablePlaylistSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/OrderablePlaylistSongAdapter.kt index a9f9c0c2d..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 @@ -107,7 +107,7 @@ class OrderablePlaylistSongAdapter( super.onClick(v) } else { val position = fullDataSet.indexOf(dataSet.get(layoutPosition)) - MusicPlayerRemote.openQueue(fullDataSet, position, true) + MusicPlayerRemote.openQueueKeepShuffleMode(fullDataSet, position, true) } } @@ -167,4 +167,8 @@ class OrderablePlaylistSongAdapter( } notifyDataSetChanged() } + + fun hasSongs(): Boolean { + return itemCount > 0 || (filtered && fullDataSet.size > 0) + } } 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 c007c935b..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 @@ -30,6 +30,7 @@ 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 @@ -79,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 @@ -120,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, @@ -127,16 +156,6 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli ArrayList(), R.layout.item_queue ) - binding.playlistSearchView.addTextChangedListener { text -> - lifecycleScope.launch { - _searchFlow.emit(text) - } - } - lifecycleScope.launch { - _searchFlow.debounce(300).collect { text -> - playlistSongAdapter.onFilter(text) - } - } val dragDropManager = RecyclerViewDragDropManager() @@ -168,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() { 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 3761902e3..a968a6989 100644 --- a/app/src/main/res/layout/fragment_playlist_detail_new.xml +++ b/app/src/main/res/layout/fragment_playlist_detail_new.xml @@ -35,16 +35,28 @@ android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintTop_toBottomOf="@id/play_button" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toLeftOf="@id/clear_search" android:background="@null" android:hint="@string/action_search" android:inputType="text|textAutoComplete" - android:paddingStart="16dp" - android:paddingEnd="16dp" - android:paddingTop="8dp" - android:paddingBottom="8dp" + android:padding="12dp" android:textAppearance="@style/TextViewSubtitle1"> + + 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" /> + +