From 5e08b889c143f73c2ed1a9dae6c0d1c725b493d0 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Mon, 13 Dec 2021 10:53:40 +0530 Subject: [PATCH 01/29] Fixed some crashes - Import playlist crash - Create new backup crash --- .../monkey/retromusic/dialogs/ImportPlaylistDialog.kt | 7 ++++++- .../name/monkey/retromusic/extensions/CursorExtensions.kt | 8 ++++---- .../retromusic/fragments/settings/MainSettingsFragment.kt | 1 + 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylistDialog.kt index 1429aa5a1..058bdfe74 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/ImportPlaylistDialog.kt @@ -22,6 +22,7 @@ import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.materialDialog import code.name.monkey.retromusic.fragments.LibraryViewModel import org.koin.androidx.viewmodel.ext.android.sharedViewModel +import java.lang.Exception class ImportPlaylistDialog : DialogFragment() { private val libraryViewModel by sharedViewModel() @@ -30,7 +31,11 @@ class ImportPlaylistDialog : DialogFragment() { return materialDialog(R.string.import_playlist) .setMessage(R.string.import_playlist_message) .setPositiveButton(R.string.import_label) { _, _ -> - libraryViewModel.importPlaylists() + try { + libraryViewModel.importPlaylists() + } catch (e: Exception) { + e.printStackTrace() + } } .create() .colorButtons() diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/CursorExtensions.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/CursorExtensions.kt index a72eb155c..531c2e0bb 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/CursorExtensions.kt +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/CursorExtensions.kt @@ -20,7 +20,7 @@ import android.database.Cursor internal fun Cursor.getInt(columnName: String): Int { try { - return this.getInt(this.getColumnIndex(columnName)) + return getInt(getColumnIndexOrThrow(columnName)) } catch (ex: Throwable) { throw IllegalStateException("invalid column $columnName", ex) } @@ -28,7 +28,7 @@ internal fun Cursor.getInt(columnName: String): Int { internal fun Cursor.getLong(columnName: String): Long { try { - return this.getLong(this.getColumnIndex(columnName)) + return getLong(getColumnIndexOrThrow(columnName)) } catch (ex: Throwable) { throw IllegalStateException("invalid column $columnName", ex) } @@ -36,7 +36,7 @@ internal fun Cursor.getLong(columnName: String): Long { internal fun Cursor.getString(columnName: String): String { try { - return this.getString(this.getColumnIndex(columnName)) + return getString(getColumnIndexOrThrow(columnName)) } catch (ex: Throwable) { throw IllegalStateException("invalid column $columnName", ex) } @@ -44,7 +44,7 @@ internal fun Cursor.getString(columnName: String): String { internal fun Cursor.getStringOrNull(columnName: String): String? { try { - return this.getString(this.getColumnIndex(columnName)) + return getString(getColumnIndexOrThrow(columnName)) } catch (ex: Throwable) { throw IllegalStateException("invalid column $columnName", ex) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/MainSettingsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/MainSettingsFragment.kt index 2a1d5fd22..5742d2950 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/MainSettingsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/MainSettingsFragment.kt @@ -99,5 +99,6 @@ class MainSettingsFragment : Fragment(), View.OnClickListener { override fun onDestroyView() { super.onDestroyView() _binding = null + ViewCompat.setOnApplyWindowInsetsListener(requireActivity().window.decorView, null) } } From aaabd8a20a66417ef233bb94b117b60231ef724c Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Mon, 13 Dec 2021 12:01:26 +0530 Subject: [PATCH 02/29] Set overScrollMode to never for API lower than S --- .../retromusic/fragments/settings/AbsSettingsFragment.kt | 6 ++++++ .../retromusic/fragments/settings/MainSettingsFragment.kt | 1 + app/src/main/res/layout-land/activity_album_tag_editor.xml | 1 + app/src/main/res/layout-land/fragment_album_details.xml | 1 + app/src/main/res/layout-land/fragment_artist_details.xml | 1 + app/src/main/res/layout-land/fragment_banner_home.xml | 1 + app/src/main/res/layout-land/fragment_home.xml | 1 + app/src/main/res/layout-sw600dp/fragment_playing_queue.xml | 1 + app/src/main/res/layout/activity_album_tag_editor.xml | 3 ++- app/src/main/res/layout/activity_bug_report.xml | 1 + app/src/main/res/layout/activity_donation.xml | 1 + app/src/main/res/layout/activity_song_tag_editor.xml | 1 + app/src/main/res/layout/fragment_about.xml | 1 + app/src/main/res/layout/fragment_album_content.xml | 1 + app/src/main/res/layout/fragment_album_details.xml | 1 + app/src/main/res/layout/fragment_artist_content.xml | 1 + app/src/main/res/layout/fragment_artist_details.xml | 1 + app/src/main/res/layout/fragment_banner_home.xml | 1 + app/src/main/res/layout/fragment_classic_player.xml | 3 ++- app/src/main/res/layout/fragment_folder.xml | 1 + app/src/main/res/layout/fragment_gradient_player.xml | 1 + app/src/main/res/layout/fragment_home.xml | 1 + .../res/layout/fragment_main_activity_recycler_view.xml | 1 + app/src/main/res/layout/fragment_main_recycler.xml | 3 ++- app/src/main/res/layout/fragment_main_settings.xml | 3 ++- app/src/main/res/layout/fragment_player_album_cover.xml | 1 + app/src/main/res/layout/fragment_playing_queue.xml | 1 + app/src/main/res/layout/fragment_playlist_detail.xml | 1 + app/src/main/res/layout/fragment_search.xml | 4 +++- app/src/main/res/layout/home_content.xml | 3 ++- app/src/main/res/layout/section_recycler_view.xml | 1 + app/src/main/res/values-v31/donottranslate.xml | 1 + app/src/main/res/values/donottranslate.xml | 1 + 33 files changed, 45 insertions(+), 6 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/AbsSettingsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/AbsSettingsFragment.kt index ab3987a37..87960912e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/AbsSettingsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/AbsSettingsFragment.kt @@ -16,6 +16,7 @@ package code.name.monkey.retromusic.fragments.settings import android.graphics.Color import android.graphics.drawable.ColorDrawable +import android.os.Build import android.os.Bundle import android.view.View import android.widget.Toast @@ -25,6 +26,7 @@ import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.PreferenceManager import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceFragmentCompat +import code.name.monkey.retromusic.BuildConfig import code.name.monkey.retromusic.activities.OnThemeChangedListener import code.name.monkey.retromusic.extensions.safeGetBottomInsets import code.name.monkey.retromusic.preferences.* @@ -67,6 +69,10 @@ abstract class AbsSettingsFragment : ATEPreferenceFragmentCompat() { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) setDivider(ColorDrawable(Color.TRANSPARENT)) + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { + listView.overScrollMode = View.OVER_SCROLL_NEVER + } + // CollapsingToolbarLayout consumes insets and insets are not passed to child views // So we get insets from decor view // https://github.com/material-components/material-components-android/issues/1310 diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/MainSettingsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/MainSettingsFragment.kt index 5742d2950..722b654ac 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/MainSettingsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/MainSettingsFragment.kt @@ -15,6 +15,7 @@ package code.name.monkey.retromusic.fragments.settings import android.content.res.ColorStateList +import android.os.Build import android.os.Bundle import android.view.LayoutInflater import android.view.View diff --git a/app/src/main/res/layout-land/activity_album_tag_editor.xml b/app/src/main/res/layout-land/activity_album_tag_editor.xml index 43b99d6aa..e474eec0b 100644 --- a/app/src/main/res/layout-land/activity_album_tag_editor.xml +++ b/app/src/main/res/layout-land/activity_album_tag_editor.xml @@ -53,6 +53,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1" + android:overScrollMode="@integer/overScrollMode" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> diff --git a/app/src/main/res/layout-land/fragment_home.xml b/app/src/main/res/layout-land/fragment_home.xml index 2ab398e4c..7d68937a5 100644 --- a/app/src/main/res/layout-land/fragment_home.xml +++ b/app/src/main/res/layout-land/fragment_home.xml @@ -61,6 +61,7 @@ android:layout_height="match_parent" android:descendantFocusability="beforeDescendants" android:focusableInTouchMode="true" + android:overScrollMode="@integer/overScrollMode" android:transitionGroup="true" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> diff --git a/app/src/main/res/layout-sw600dp/fragment_playing_queue.xml b/app/src/main/res/layout-sw600dp/fragment_playing_queue.xml index bdd18ae3c..7dae61e77 100644 --- a/app/src/main/res/layout-sw600dp/fragment_playing_queue.xml +++ b/app/src/main/res/layout-sw600dp/fragment_playing_queue.xml @@ -42,6 +42,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false" + android:overScrollMode="@integer/overScrollMode" android:paddingBottom="96dp" android:scrollbars="none" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" diff --git a/app/src/main/res/layout/activity_album_tag_editor.xml b/app/src/main/res/layout/activity_album_tag_editor.xml index 5a40e8ee1..e3c4e3745 100755 --- a/app/src/main/res/layout/activity_album_tag_editor.xml +++ b/app/src/main/res/layout/activity_album_tag_editor.xml @@ -26,7 +26,8 @@ android:id="@+id/content" android:layout_width="match_parent" android:layout_height="wrap_content" - app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" + android:overScrollMode="@integer/overScrollMode"> + android:overScrollMode="@integer/overScrollMode" + tools:listitem="@layout/item_list" /> diff --git a/app/src/main/res/layout/fragment_folder.xml b/app/src/main/res/layout/fragment_folder.xml index 56b086604..6521a4a0a 100644 --- a/app/src/main/res/layout/fragment_folder.xml +++ b/app/src/main/res/layout/fragment_folder.xml @@ -82,6 +82,7 @@ android:layout_width="match_parent" android:layout_height="match_parent" android:clipToPadding="false" + android:overScrollMode="@integer/overScrollMode" android:scrollbars="none" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" /> \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_gradient_player.xml b/app/src/main/res/layout/fragment_gradient_player.xml index ea2e8b1e5..e9aad0649 100644 --- a/app/src/main/res/layout/fragment_gradient_player.xml +++ b/app/src/main/res/layout/fragment_gradient_player.xml @@ -150,6 +150,7 @@ android:layout_width="0dp" android:layout_height="0dp" android:background="?attr/colorSurface" + android:overScrollMode="@integer/overScrollMode" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" diff --git a/app/src/main/res/layout/fragment_home.xml b/app/src/main/res/layout/fragment_home.xml index 618ed3995..1c8cf07d8 100755 --- a/app/src/main/res/layout/fragment_home.xml +++ b/app/src/main/res/layout/fragment_home.xml @@ -61,6 +61,7 @@ android:layout_height="wrap_content" android:descendantFocusability="beforeDescendants" android:focusableInTouchMode="true" + android:overScrollMode="@integer/overScrollMode" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> + android:overScrollMode="@integer/overScrollMode" + android:transitionGroup="true" /> + android:layout_height="wrap_content" + android:overScrollMode="@integer/overScrollMode"> diff --git a/app/src/main/res/layout/fragment_search.xml b/app/src/main/res/layout/fragment_search.xml index b3667fda7..70452fb5a 100644 --- a/app/src/main/res/layout/fragment_search.xml +++ b/app/src/main/res/layout/fragment_search.xml @@ -73,7 +73,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:padding="5dp" - android:scrollbarSize="0dp"> + android:scrollbars="none" + android:overScrollMode="@integer/overScrollMode"> diff --git a/app/src/main/res/layout/home_content.xml b/app/src/main/res/layout/home_content.xml index 10f38720b..133954bcf 100644 --- a/app/src/main/res/layout/home_content.xml +++ b/app/src/main/res/layout/home_content.xml @@ -66,7 +66,8 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:nestedScrollingEnabled="false" - tools:itemCount="10" + android:overScrollMode="@integer/overScrollMode" + tools:itemCount="10" tools:layoutManager="androidx.recyclerview.widget.GridLayoutManager" tools:listitem="@layout/item_album_card" tools:spanCount="3" /> diff --git a/app/src/main/res/layout/section_recycler_view.xml b/app/src/main/res/layout/section_recycler_view.xml index f554b90dd..5840f9afc 100644 --- a/app/src/main/res/layout/section_recycler_view.xml +++ b/app/src/main/res/layout/section_recycler_view.xml @@ -41,6 +41,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:nestedScrollingEnabled="false" + android:overScrollMode="@integer/overScrollMode" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/clickable_area" diff --git a/app/src/main/res/values-v31/donottranslate.xml b/app/src/main/res/values-v31/donottranslate.xml index f4981725e..f39fb68c1 100644 --- a/app/src/main/res/values-v31/donottranslate.xml +++ b/app/src/main/res/values-v31/donottranslate.xml @@ -4,4 +4,5 @@ true false + 0 \ No newline at end of file diff --git a/app/src/main/res/values/donottranslate.xml b/app/src/main/res/values/donottranslate.xml index eff1e1c7d..8b950ef3e 100755 --- a/app/src/main/res/values/donottranslate.xml +++ b/app/src/main/res/values/donottranslate.xml @@ -28,4 +28,5 @@ false true + 2 \ No newline at end of file From 305b0753654733d60a3586da7694f2d3bcbeced3 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Mon, 13 Dec 2021 15:01:44 +0530 Subject: [PATCH 03/29] [Tag Editor] Changed JAudioTagger to https://github.com/Kaned1as/jaudiotagger - We should be able to read and write to opus files - We should be able to set artwork to Flac and other files --- app/build.gradle | 2 +- .../retromusic/activities/tageditor/TagWriter.kt | 14 +++++++------- .../glide/audiocover/AudioFileCoverUtils.java | 3 ++- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 8c2e9fda6..9fa7b981c 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -153,7 +153,7 @@ dependencies { implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0' implementation 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:2.1.5' - implementation 'com.github.AdrienPoupa:jaudiotagger:2.2.3' + implementation 'com.github.Adonai:jaudiotagger:2.3.14' implementation 'com.anjlab.android.iab.v3:library:2.0.3' implementation 'com.r0adkll:slidableactivity:2.1.0' implementation 'com.heinrichreimersoftware:material-intro:2.0.0' diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/TagWriter.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/TagWriter.kt index 4fcea20f2..9bc20f100 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/TagWriter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/TagWriter.kt @@ -21,8 +21,8 @@ import org.jaudiotagger.audio.exceptions.CannotWriteException import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException import org.jaudiotagger.audio.exceptions.ReadOnlyFileException import org.jaudiotagger.tag.TagException +import org.jaudiotagger.tag.images.AndroidArtwork import org.jaudiotagger.tag.images.Artwork -import org.jaudiotagger.tag.images.ArtworkFactory import java.io.File import java.io.FileOutputStream import java.io.IOException @@ -58,11 +58,11 @@ class TagWriter { try { albumArtFile = createAlbumArtFile(context).canonicalFile info.artworkInfo.artwork.compress( - Bitmap.CompressFormat.PNG, - 0, + Bitmap.CompressFormat.JPEG, + 100, FileOutputStream(albumArtFile) ) - artwork = ArtworkFactory.createArtworkFromFile(albumArtFile) + artwork = AndroidArtwork.createArtworkFromFile(albumArtFile) } catch (e: IOException) { e.printStackTrace() } @@ -131,11 +131,11 @@ class TagWriter { try { albumArtFile = createAlbumArtFile(context).canonicalFile info.artworkInfo.artwork.compress( - Bitmap.CompressFormat.PNG, - 0, + Bitmap.CompressFormat.JPEG, + 100, FileOutputStream(albumArtFile) ) - artwork = ArtworkFactory.createArtworkFromFile(albumArtFile) + artwork = AndroidArtwork.createArtworkFromFile(albumArtFile) } catch (e: IOException) { e.printStackTrace() } diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverUtils.java b/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverUtils.java index 5ffe040cc..5c7fa7aad 100644 --- a/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverUtils.java +++ b/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverUtils.java @@ -14,6 +14,7 @@ package code.name.monkey.retromusic.glide.audiocover; +import org.jaudiotagger.audio.exceptions.CannotReadException; import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException; import org.jaudiotagger.audio.exceptions.ReadOnlyFileException; import org.jaudiotagger.audio.mp3.MP3File; @@ -45,7 +46,7 @@ public class AudioFileCoverUtils { } } // If there are any exceptions, we ignore them and continue to the other fallback method - } catch (ReadOnlyFileException | InvalidAudioFrameException | TagException | IOException ignored) { + } catch (ReadOnlyFileException | InvalidAudioFrameException | TagException | IOException | CannotReadException ignored) { } // Method 2: look for album art in external files From 4211ed1a9be2b22c60c1ac5148a41438470ad9cc Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Mon, 13 Dec 2021 16:06:48 +0530 Subject: [PATCH 04/29] [Tag Editor] Added artwork chooser for Song tag editor --- .../tageditor/AbsTagEditorActivity.kt | 21 +- .../tageditor/AlbumTagEditorActivity.kt | 70 ++--- .../tageditor/SongTagEditorActivity.kt | 90 +++++- .../layout-land/activity_album_tag_editor.xml | 28 +- .../layout-land/activity_song_tag_editor.xml | 291 ++++++++++++++++++ .../res/layout/activity_song_tag_editor.xml | 23 ++ 6 files changed, 452 insertions(+), 71 deletions(-) create mode 100644 app/src/main/res/layout-land/activity_song_tag_editor.xml diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt index cee65c013..cadbe840b 100755 --- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt @@ -34,7 +34,6 @@ import androidx.appcompat.app.AlertDialog import androidx.lifecycle.lifecycleScope import androidx.viewbinding.ViewBinding import code.name.monkey.appthemehelper.ThemeStore -import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.retromusic.R @@ -60,14 +59,13 @@ import java.io.File import java.util.* abstract class AbsTagEditorActivity : AbsBaseActivity() { - abstract val editorImage: ImageView? + abstract val editorImage: ImageView val repository by inject() lateinit var saveFab: MaterialButton protected var id: Long = 0 private set private var paletteColorPrimary: Int = 0 - private var isInNoImageMode: Boolean = false private var songPaths: List? = null private var savedSongPaths: List? = null private val currentSongPath: String? = null @@ -239,7 +237,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() { getString(R.string.web_search), getString(R.string.remove_cover) ) - editorImage?.setOnClickListener { show } + editorImage.setOnClickListener { show } } private fun startImagePicker() { @@ -306,17 +304,6 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() { return super.onOptionsItemSelected(item) } - protected fun setNoImageMode() { - isInNoImageMode = true - setColors( - intent.getIntExtra( - EXTRA_PALETTE, - ATHUtil.resolveColor(this, R.attr.colorPrimary) - ) - ) - } - - protected fun dataChanged() { showFab() } @@ -335,9 +322,9 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() { protected fun setImageBitmap(bitmap: Bitmap?, bgColor: Int) { if (bitmap == null) { - editorImage?.setImageResource(drawable.default_audio_art) + editorImage.setImageResource(drawable.default_audio_art) } else { - editorImage?.setImageBitmap(bitmap) + editorImage.setImageBitmap(bitmap) } setColors(bgColor) } diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt index 18b73ed29..79a954055 100755 --- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt @@ -63,41 +63,6 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(binding.editorImage) { - override fun onResourceReady( - resource: BitmapPaletteWrapper, - transition: Transition? - ) { - getColor(resource.palette, Color.TRANSPARENT) - albumArtBitmap = resource.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) } - setImageBitmap( - albumArtBitmap, - getColor( - resource.palette, - ATHUtil.resolveColor( - this@AlbumTagEditorActivity, - R.attr.defaultFooterColor - ) - ) - ) - deleteAlbumArt = false - dataChanged() - setResult(Activity.RESULT_OK) - } - - override fun onLoadFailed(errorDrawable: Drawable?) { - super.onLoadFailed(errorDrawable) - Toast.makeText(this@AlbumTagEditorActivity, "Load Failed", Toast.LENGTH_LONG) - .show() - } - - override fun setResource(resource: BitmapPaletteWrapper?) {} - }) - } - private var albumArtBitmap: Bitmap? = null private var deleteAlbumArt: Boolean = false @@ -171,6 +136,41 @@ class AlbumTagEditorActivity : AbsTagEditorActivity(binding.editorImage) { + override fun onResourceReady( + resource: BitmapPaletteWrapper, + transition: Transition? + ) { + getColor(resource.palette, Color.TRANSPARENT) + albumArtBitmap = resource.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) } + setImageBitmap( + albumArtBitmap, + getColor( + resource.palette, + ATHUtil.resolveColor( + this@AlbumTagEditorActivity, + R.attr.defaultFooterColor + ) + ) + ) + deleteAlbumArt = false + dataChanged() + setResult(Activity.RESULT_OK) + } + + override fun onLoadFailed(errorDrawable: Drawable?) { + super.onLoadFailed(errorDrawable) + Toast.makeText(this@AlbumTagEditorActivity, "Load Failed", Toast.LENGTH_LONG) + .show() + } + + override fun setResource(resource: BitmapPaletteWrapper?) {} + }) + } + override fun save() { val fieldKeyValueMap = EnumMap(FieldKey::class.java) fieldKeyValueMap[FieldKey.ALBUM] = binding.albumText.text.toString() diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/SongTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/SongTagEditorActivity.kt index 69c4c7cdc..cca36e9e0 100755 --- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/SongTagEditorActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/SongTagEditorActivity.kt @@ -15,17 +15,33 @@ package code.name.monkey.retromusic.activities.tageditor import android.annotation.SuppressLint +import android.app.Activity +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import android.graphics.Color +import android.graphics.drawable.Drawable import android.net.Uri import android.os.Bundle import android.text.Editable import android.text.TextWatcher import android.view.LayoutInflater import android.widget.ImageView +import android.widget.Toast +import code.name.monkey.appthemehelper.util.ATHUtil +import code.name.monkey.retromusic.R import code.name.monkey.retromusic.databinding.ActivitySongTagEditorBinding import code.name.monkey.retromusic.extensions.appHandleColor import code.name.monkey.retromusic.extensions.setTint +import code.name.monkey.retromusic.glide.GlideApp +import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper +import code.name.monkey.retromusic.model.ArtworkInfo import code.name.monkey.retromusic.repository.SongRepository +import code.name.monkey.retromusic.util.ImageUtil import code.name.monkey.retromusic.util.MusicUtil +import code.name.monkey.retromusic.util.RetroColorUtil +import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.request.target.ImageViewTarget +import com.bumptech.glide.request.transition.Transition import com.google.android.material.shape.MaterialShapeDrawable import org.jaudiotagger.tag.FieldKey import org.koin.android.ext.android.inject @@ -39,12 +55,14 @@ class SongTagEditorActivity : AbsTagEditorActivity private val songRepository by inject() + private var albumArtBitmap: Bitmap? = null + private var deleteAlbumArt: Boolean = false + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setUpViews() - setNoImageMode() setSupportActionBar(binding.toolbar) - binding.appBarLayout.statusBarForeground = + binding.appBarLayout?.statusBarForeground = MaterialShapeDrawable.createWithElevationOverlay(this) } @@ -90,11 +108,30 @@ class SongTagEditorActivity : AbsTagEditorActivity println(songTitle + songYear) } - override fun loadCurrentImage() {} + override fun loadCurrentImage() { + val bitmap = albumArt + setImageBitmap( + bitmap, + RetroColorUtil.getColor( + RetroColorUtil.generatePalette(bitmap), + ATHUtil.resolveColor(this, R.attr.defaultFooterColor) + ) + ) + deleteAlbumArt = false + } - override fun searchImageOnWeb() {} + override fun searchImageOnWeb() { + searchWebFor(binding.songText.text.toString(), binding.artistText.text.toString()) + } - override fun deleteImage() {} + override fun deleteImage() { + setImageBitmap( + BitmapFactory.decodeResource(resources, R.drawable.default_audio_art), + ATHUtil.resolveColor(this, R.attr.defaultFooterColor) + ) + deleteAlbumArt = true + dataChanged() + } override fun save() { val fieldKeyValueMap = EnumMap(FieldKey::class.java) @@ -107,7 +144,12 @@ class SongTagEditorActivity : AbsTagEditorActivity fieldKeyValueMap[FieldKey.LYRICS] = binding.lyricsText.text.toString() fieldKeyValueMap[FieldKey.ALBUM_ARTIST] = binding.albumArtistText.text.toString() fieldKeyValueMap[FieldKey.COMPOSER] = binding.songComposerText.text.toString() - writeValuesToFiles(fieldKeyValueMap, null) + writeValuesToFiles(fieldKeyValueMap, when { + deleteAlbumArt -> ArtworkInfo(id, null) + albumArtBitmap == null -> null + else -> ArtworkInfo(id, albumArtBitmap!!) + } + ) } override fun getSongPaths(): List = listOf(songRepository.song(id).data) @@ -115,6 +157,38 @@ class SongTagEditorActivity : AbsTagEditorActivity override fun getSongUris(): List = listOf(MusicUtil.getSongFileUri(id)) override fun loadImageFromFile(selectedFile: Uri?) { + GlideApp.with(this@SongTagEditorActivity).asBitmapPalette().load(selectedFile) + .diskCacheStrategy(DiskCacheStrategy.NONE).skipMemoryCache(true) + .into(object : ImageViewTarget(binding.editorImage) { + override fun onResourceReady( + resource: BitmapPaletteWrapper, + transition: Transition? + ) { + RetroColorUtil.getColor(resource.palette, Color.TRANSPARENT) + albumArtBitmap = resource.bitmap?.let { ImageUtil.resizeBitmap(it, 2048) } + setImageBitmap( + albumArtBitmap, + RetroColorUtil.getColor( + resource.palette, + ATHUtil.resolveColor( + this@SongTagEditorActivity, + R.attr.defaultFooterColor + ) + ) + ) + deleteAlbumArt = false + dataChanged() + setResult(Activity.RESULT_OK) + } + + override fun onLoadFailed(errorDrawable: Drawable?) { + super.onLoadFailed(errorDrawable) + Toast.makeText(this@SongTagEditorActivity, "Load Failed", Toast.LENGTH_LONG) + .show() + } + + override fun setResource(resource: BitmapPaletteWrapper?) {} + }) } override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) { @@ -131,6 +205,6 @@ class SongTagEditorActivity : AbsTagEditorActivity val TAG: String = SongTagEditorActivity::class.java.simpleName } - override val editorImage: ImageView? - get() = null + override val editorImage: ImageView + get() = binding.editorImage } diff --git a/app/src/main/res/layout-land/activity_album_tag_editor.xml b/app/src/main/res/layout-land/activity_album_tag_editor.xml index e474eec0b..18b98d1dc 100644 --- a/app/src/main/res/layout-land/activity_album_tag_editor.xml +++ b/app/src/main/res/layout-land/activity_album_tag_editor.xml @@ -3,7 +3,8 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface"> + android:background="?attr/colorSurface" + android:fitsSystemWindows="true"> - + android:layout_height="match_parent"> + app:cardElevation="8dp" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintDimensionRatio="1:1" + app:layout_constraintStart_toStartOf="parent" + app:layout_constraintTop_toTopOf="parent"> + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" + app:layout_constraintBottom_toBottomOf="parent" + app:layout_constraintEnd_toEndOf="parent" + app:layout_constraintStart_toEndOf="@+id/imageContainer" + app:layout_constraintTop_toTopOf="parent"> - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_song_tag_editor.xml b/app/src/main/res/layout/activity_song_tag_editor.xml index cf6bea679..a6abea9ec 100755 --- a/app/src/main/res/layout/activity_song_tag_editor.xml +++ b/app/src/main/res/layout/activity_song_tag_editor.xml @@ -2,6 +2,7 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" + xmlns:tools="http://schemas.android.com/tools" android:fitsSystemWindows="true" android:focusable="true" android:focusableInTouchMode="true"> @@ -33,6 +34,28 @@ android:orientation="vertical" android:padding="16dp"> + + + + + + Date: Mon, 13 Dec 2021 17:49:31 +0530 Subject: [PATCH 05/29] Clearing SearchView also clears the search results --- .../monkey/retromusic/fragments/search/SearchFragment.kt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchFragment.kt index 4cd181288..9e909e4d0 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchFragment.kt @@ -70,7 +70,10 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), TextWa setupRecyclerView() binding.voiceSearch.setOnClickListener { startMicSearch() } - binding.clearText.setOnClickListener { binding.searchView.clearText() } + binding.clearText.setOnClickListener { + binding.searchView.clearText() + searchAdapter.swapDataSet(listOf()) + } binding.searchView.apply { addTextChangedListener(this@SearchFragment) focusAndShowKeyboard() From 87eb3c08c3cb0309a00d1b62e2800a581e17caee Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Tue, 14 Dec 2021 19:34:26 +0530 Subject: [PATCH 06/29] [Now Playing: Circle] Added Circular rotating album cover to Circle theme --- .../player/circle/CirclePlayerFragment.kt | 32 +++++++++++++++--- .../layout-land/fragment_circle_player.xml | 25 ++++++++++++++ .../res/layout/fragment_circle_player.xml | 33 +++++++++++++++---- 3 files changed, 79 insertions(+), 11 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/circle/CirclePlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/circle/CirclePlayerFragment.kt index 0d934398f..70a420d02 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/circle/CirclePlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/circle/CirclePlayerFragment.kt @@ -23,6 +23,7 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import android.view.animation.Animation import android.view.animation.LinearInterpolator import android.widget.SeekBar import androidx.appcompat.widget.Toolbar @@ -38,6 +39,8 @@ import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment import code.name.monkey.retromusic.fragments.base.goToAlbum import code.name.monkey.retromusic.fragments.base.goToArtist +import code.name.monkey.retromusic.glide.GlideApp +import code.name.monkey.retromusic.glide.RetroGlideExtension import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper.Callback @@ -69,6 +72,8 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player), private var _binding: FragmentCirclePlayerBinding? = null private val binding get() = _binding!! + private var rotateAnimator: ObjectAnimator? = null + override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) progressViewUpdateHelper = MusicProgressViewUpdateHelper(this) @@ -144,6 +149,17 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player), binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler()) } + private fun setupRotateAnimation() { + rotateAnimator = ObjectAnimator.ofFloat(binding.albumCover, View.ROTATION, 360F).apply { + interpolator = LinearInterpolator() + repeatCount = Animation.INFINITE + duration = 10000 + if (MusicPlayerRemote.isPlaying){ + start() + } + } + } + override fun onResume() { super.onResume() progressViewUpdateHelper.start() @@ -153,10 +169,8 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player), audioVolumeObserver?.register(AudioManager.STREAM_MUSIC, this) val audioManager = audioManager - if (audioManager != null) { - binding.volumeSeekBar.max = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) - binding.volumeSeekBar.progress = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) - } + binding.volumeSeekBar.max = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC) + binding.volumeSeekBar.progress = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) binding.volumeSeekBar.setOnSeekArcChangeListener(this) } @@ -191,6 +205,11 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player), override fun onPlayStateChanged() { updatePlayPauseDrawableState() + if (MusicPlayerRemote.isPlaying) { + if (rotateAnimator?.isStarted == true) rotateAnimator?.resume() else rotateAnimator?.start() + } else { + rotateAnimator?.pause() + } } override fun onPlayingMetaChanged() { @@ -202,6 +221,7 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player), super.onServiceConnected() updateSong() updatePlayPauseDrawableState() + setupRotateAnimation() } private fun updateSong() { @@ -215,6 +235,10 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player), } else { binding.songInfo.hide() } + GlideApp.with(this) + .load(RetroGlideExtension.getSongModel(song)) + .songCoverOptions(song) + .into(binding.albumCover) } private fun updatePlayPauseDrawableState() { diff --git a/app/src/main/res/layout-land/fragment_circle_player.xml b/app/src/main/res/layout-land/fragment_circle_player.xml index 07d734c6c..a13ac76fe 100644 --- a/app/src/main/res/layout-land/fragment_circle_player.xml +++ b/app/src/main/res/layout-land/fragment_circle_player.xml @@ -54,6 +54,31 @@ app:navigationIcon="@drawable/ic_keyboard_arrow_down_black" tools:layout_editor_absoluteY="24dp" /> + + + - - + + + + + app:layout_constraintStart_toStartOf="@+id/volumeSeekBar" + app:layout_constraintTop_toBottomOf="@+id/album_cover" /> Date: Tue, 14 Dec 2021 22:48:48 +0530 Subject: [PATCH 07/29] [Now Playing: Circle] Replaced SeekArc with Circular Seekbar [Now Playing: Circle] Replaced SeekArc with Circular Seekbar --- app/build.gradle | 1 + app/src/debug/res/values/donottranslate.xml | 1 + app/src/main/AndroidManifest.xml | 2 +- .../player/circle/CirclePlayerFragment.kt | 44 ++++++------ .../layout-land/fragment_circle_player.xml | 68 ++++++++----------- .../res/layout/fragment_circle_player.xml | 64 ++++++++--------- app/src/main/res/values/donottranslate.xml | 1 + 7 files changed, 91 insertions(+), 90 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 9fa7b981c..1c5c52c52 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -160,5 +160,6 @@ dependencies { implementation 'com.github.dhaval2404:imagepicker:2.1' implementation 'me.zhanghai.android.fastscroll:library:1.1.7' implementation 'cat.ereza:customactivityoncrash:2.3.0' + implementation 'me.tankery.lib:circularSeekBar:1.3.2' debugImplementation 'com.github.amitshekhariitbhu:Android-Debug-Database:1.0.6' } \ No newline at end of file diff --git a/app/src/debug/res/values/donottranslate.xml b/app/src/debug/res/values/donottranslate.xml index 879226a34..7d3f0ee62 100644 --- a/app/src/debug/res/values/donottranslate.xml +++ b/app/src/debug/res/values/donottranslate.xml @@ -1,4 +1,5 @@ true + false \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 377342a16..20108f3d1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -22,7 +22,7 @@ - + android:padding="10dp" + app:layout_constraintBottom_toBottomOf="@id/volumeSeekBar" + app:layout_constraintEnd_toEndOf="@id/volumeSeekBar" + app:layout_constraintStart_toStartOf="@id/volumeSeekBar" + app:layout_constraintTop_toTopOf="@id/volumeSeekBar"> - + - + + + - + - + - + + + + app:layout_constraintTop_toBottomOf="@+id/volumeSeekBar" /> true 2 + true \ No newline at end of file From 4d31c4ccc3f0a9a6ecfe0c571b1de57337a61534 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Tue, 14 Dec 2021 23:18:42 +0530 Subject: [PATCH 08/29] Updated Open Source Licenses --- app/src/main/assets/oldindex.html | 38 +++++++++------ .../retromusic/activities/LicenseActivity.kt | 31 ++++++------ .../retromusic/activities/WhatsNewActivity.kt | 12 +++-- .../monkey/retromusic/helper/M3UWriter.kt | 48 +++++++++---------- app/src/main/res/layout/activity_license.xml | 19 ++++---- 5 files changed, 78 insertions(+), 70 deletions(-) diff --git a/app/src/main/assets/oldindex.html b/app/src/main/assets/oldindex.html index 367da632a..7f6f8d8f8 100644 --- a/app/src/main/assets/oldindex.html +++ b/app/src/main/assets/oldindex.html @@ -24,40 +24,48 @@ padding-top: 8px; } - - -

Phonograph by Karim Abou Zeid

-

Material Dialogs and Cab - by Aidan Michael Follestad

AOSP Support Librariesby AOSP contributors

+ title="AOSP Support Libraries">AOSP Support Libraries by AOSP contributors

Glide by Sam Judd

Retrofit by Square team

+

OkHttp by Square team

+

Koin by Arnaud Giuliani

+

Material Dialogs and Cab + by Aidan Michael Follestad

Material Contextual Action Bar by Aidan Michael Follestad

-

OkHttp by Square team

-

- CircleImageView by Henning Dodenhof

-

- MaterialProgressBar by Zhang Hai

Android In-App Billing v3 Library by Henning Dodenhof

Advanced RecyclerView by Haruki Hasegawa

-

Android-ObservableScrollView by Soichiro - Kashima

+

Custom Activity on Crash by Eduard Ereza Martínez +

+

NanoHttpd by NanoHttpd Team

+

Circular Seekbar by Tankery

+

jAudioTagger by Kanedias

+

Android Fast Scroll by Zhang Hai

+

Image Picker by Dhaval Patel

+

Material Intro by Jan Heinrich Reimer

+

Slidr by Drew Heavner

Icons by Austin Andrews

Material Design City Wallpaper

- diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/LicenseActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/LicenseActivity.kt index 11cd201ca..52498d447 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/LicenseActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/LicenseActivity.kt @@ -16,8 +16,6 @@ package code.name.monkey.retromusic.activities import android.graphics.Color import android.os.Bundle import android.view.MenuItem -import android.webkit.WebView -import androidx.appcompat.widget.Toolbar import code.name.monkey.appthemehelper.ThemeStore.Companion.accentColor import code.name.monkey.appthemehelper.util.ATHUtil.isWindowBackgroundDark import code.name.monkey.appthemehelper.util.ATHUtil.resolveColor @@ -25,29 +23,31 @@ import code.name.monkey.appthemehelper.util.ColorUtil.lightenColor import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.R import code.name.monkey.retromusic.activities.base.AbsThemeActivity +import code.name.monkey.retromusic.databinding.ActivityLicenseBinding +import code.name.monkey.retromusic.extensions.drawAboveSystemBars +import code.name.monkey.retromusic.extensions.drawAboveSystemBarsWithPadding import java.io.BufferedReader import java.io.InputStreamReader import java.nio.charset.StandardCharsets /** Created by hemanths on 2019-09-27. */ class LicenseActivity : AbsThemeActivity() { + private lateinit var binding: ActivityLicenseBinding override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) - setContentView(R.layout.activity_license) - val toolbar = findViewById(R.id.toolbar) - setSupportActionBar(toolbar) - ToolbarContentTintHelper.colorBackButton(toolbar) - toolbar.setBackgroundColor(resolveColor(this, R.attr.colorSurface)) - val webView = findViewById(R.id.license) + binding = ActivityLicenseBinding.inflate(layoutInflater) + setContentView(binding.root) + setSupportActionBar(binding.toolbar) + ToolbarContentTintHelper.colorBackButton(binding.toolbar) try { val buf = StringBuilder() val json = assets.open("oldindex.html") - val br = BufferedReader(InputStreamReader(json, StandardCharsets.UTF_8)) - var str: String? - while (br.readLine().also { str = it } != null) { - buf.append(str) + BufferedReader(InputStreamReader(json, StandardCharsets.UTF_8)).use { br -> + var str: String? + while (br.readLine().also { str = it } != null) { + buf.append(str) + } } - br.close() // Inject color values for WebView body background and links val isDark = isWindowBackgroundDark(this) @@ -72,12 +72,13 @@ class LicenseActivity : AbsThemeActivity() { lightenColor(accentColor(this)) ) ) - webView.loadData(changeLog, "text/html", "UTF-8") + binding.license.loadData(changeLog, "text/html", "UTF-8") } catch (e: Throwable) { - webView.loadData( + binding.license.loadData( "

Unable to load

" + e.localizedMessage + "

", "text/html", "UTF-8" ) } + binding.license.drawAboveSystemBars() } override fun onOptionsItemSelected(item: MenuItem): Boolean { diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewActivity.kt index 40200eba0..b1c979076 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewActivity.kt @@ -17,6 +17,7 @@ import code.name.monkey.retromusic.R import code.name.monkey.retromusic.activities.base.AbsThemeActivity import code.name.monkey.retromusic.databinding.ActivityWhatsNewBinding import code.name.monkey.retromusic.extensions.accentColor +import code.name.monkey.retromusic.extensions.drawAboveSystemBars import code.name.monkey.retromusic.extensions.setLightStatusBarAuto import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto import code.name.monkey.retromusic.util.PreferenceUtil.lastVersion @@ -38,12 +39,12 @@ class WhatsNewActivity : AbsThemeActivity() { try { val buf = StringBuilder() val json = assets.open("retro-changelog.html") - val br = BufferedReader(InputStreamReader(json, StandardCharsets.UTF_8)) - var str: String? - while (br.readLine().also { str = it } != null) { - buf.append(str) + BufferedReader(InputStreamReader(json, StandardCharsets.UTF_8)).use { br -> + var str: String? + while (br.readLine().also { str = it } != null) { + buf.append(str) + } } - br.close() // Inject color values for WebView body background and links val isDark = isWindowBackgroundDark(this) @@ -100,6 +101,7 @@ class WhatsNewActivity : AbsThemeActivity() { binding.tgFab.extend() } } + binding.webView.drawAboveSystemBars() } companion object { diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/M3UWriter.kt b/app/src/main/java/code/name/monkey/retromusic/helper/M3UWriter.kt index f6044b2de..c1b6cfee3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/M3UWriter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/M3UWriter.kt @@ -31,15 +31,15 @@ object M3UWriter : M3UConstants { val file = File(dir, playlist.name + "." + M3UConstants.EXTENSION) val songs = playlist.getSongs() if (songs.isNotEmpty()) { - val bw = BufferedWriter(FileWriter(file)) - bw.write(M3UConstants.HEADER) - for (song in songs) { - bw.newLine() - bw.write(M3UConstants.ENTRY + song.duration + M3UConstants.DURATION_SEPARATOR + song.artistName + " - " + song.title) - bw.newLine() - bw.write(song.data) + BufferedWriter(FileWriter(file)).use { bw -> + bw.write(M3UConstants.HEADER) + for (song in songs) { + bw.newLine() + bw.write(M3UConstants.ENTRY + song.duration + M3UConstants.DURATION_SEPARATOR + song.artistName + " - " + song.title) + bw.newLine() + bw.write(song.data) + } } - bw.close() } return file } @@ -54,15 +54,15 @@ object M3UWriter : M3UConstants { it.songPrimaryKey }.toSongs() if (songs.isNotEmpty()) { - val bufferedWriter = BufferedWriter(FileWriter(file)) - bufferedWriter.write(M3UConstants.HEADER) - songs.forEach { - bufferedWriter.newLine() - bufferedWriter.write(M3UConstants.ENTRY + it.duration + M3UConstants.DURATION_SEPARATOR + it.artistName + " - " + it.title) - bufferedWriter.newLine() - bufferedWriter.write(it.data) + BufferedWriter(FileWriter(file)).use { bw-> + bw.write(M3UConstants.HEADER) + songs.forEach { + bw.newLine() + bw.write(M3UConstants.ENTRY + it.duration + M3UConstants.DURATION_SEPARATOR + it.artistName + " - " + it.title) + bw.newLine() + bw.write(it.data) + } } - bufferedWriter.close() } return file } @@ -72,15 +72,15 @@ object M3UWriter : M3UConstants { it.songPrimaryKey }.toSongs() if (songs.isNotEmpty()) { - val bufferedWriter = outputStream.bufferedWriter() - bufferedWriter.write(M3UConstants.HEADER) - songs.forEach { - bufferedWriter.newLine() - bufferedWriter.write(M3UConstants.ENTRY + it.duration + M3UConstants.DURATION_SEPARATOR + it.artistName + " - " + it.title) - bufferedWriter.newLine() - bufferedWriter.write(it.data) + outputStream.bufferedWriter().use{ bw-> + bw.write(M3UConstants.HEADER) + songs.forEach { + bw.newLine() + bw.write(M3UConstants.ENTRY + it.duration + M3UConstants.DURATION_SEPARATOR + it.artistName + " - " + it.title) + bw.newLine() + bw.write(it.data) + } } - bufferedWriter.close() } outputStream.flush() outputStream.close() diff --git a/app/src/main/res/layout/activity_license.xml b/app/src/main/res/layout/activity_license.xml index 25569ea28..57555118e 100644 --- a/app/src/main/res/layout/activity_license.xml +++ b/app/src/main/res/layout/activity_license.xml @@ -6,23 +6,17 @@ android:layout_height="match_parent" android:orientation="vertical"> - - + android:background="?attr/colorSurface" + android:fitsSystemWindows="true"> + android:layout_height="wrap_content" + android:scrollbars="none" + android:fitsSystemWindows="true" + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />
From c919033a2c3a1bf2915516bdd0f2f3d0229cce6d Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Wed, 15 Dec 2021 00:45:30 +0530 Subject: [PATCH 09/29] Added CrossFade effect to Blur, Blur Card & Circle player --- .../player/blur/BlurPlayerFragment.kt | 39 +++++++++---------- .../player/cardblur/CardBlurFragment.kt | 35 ++++++++--------- .../player/circle/CirclePlayerFragment.kt | 17 +++++--- .../retromusic/glide/RetroGlideExtension.kt | 37 ++++++++++++++++++ 4 files changed, 84 insertions(+), 44 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/blur/BlurPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/blur/BlurPlayerFragment.kt index aec5f2e57..6f9b3798d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/blur/BlurPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/blur/BlurPlayerFragment.kt @@ -16,6 +16,7 @@ package code.name.monkey.retromusic.fragments.player.blur import android.content.SharedPreferences import android.graphics.Color +import android.graphics.drawable.Drawable import android.os.Bundle import android.view.View import androidx.appcompat.widget.Toolbar @@ -27,18 +28,18 @@ import code.name.monkey.retromusic.databinding.FragmentBlurBinding import code.name.monkey.retromusic.extensions.drawAboveSystemBars import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment -import code.name.monkey.retromusic.glide.BlurTransformation -import code.name.monkey.retromusic.glide.GlideApp -import code.name.monkey.retromusic.glide.RetroGlideExtension -import code.name.monkey.retromusic.glide.RetroMusicColoredTarget +import code.name.monkey.retromusic.glide.* import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.PreferenceUtil.blurAmount import code.name.monkey.retromusic.util.color.MediaNotificationProcessor + class BlurPlayerFragment : AbsPlayerFragment(R.layout.fragment_blur), SharedPreferences.OnSharedPreferenceChangeListener { + private var lastRequest: GlideRequest? = null + override fun playerToolbar(): Toolbar { return binding.playerToolbar } @@ -111,23 +112,21 @@ class BlurPlayerFragment : AbsPlayerFragment(R.layout.fragment_blur), get() = lastColor private fun updateBlur() { - binding.colorBackground.clearColorFilter() - GlideApp.with(requireActivity()).asBitmapPalette() - .songCoverOptions(MusicPlayerRemote.currentSong) + // https://github.com/bumptech/glide/issues/527#issuecomment-148840717 + GlideApp.with(this) .load(RetroGlideExtension.getSongModel(MusicPlayerRemote.currentSong)) - .dontAnimate() - .transform( - BlurTransformation.Builder(requireContext()) - .blurRadius(blurAmount.toFloat()) - .build() - ) - .into(object : RetroMusicColoredTarget(binding.colorBackground) { - override fun onColorReady(colors: MediaNotificationProcessor) { - if (colors.backgroundColor == defaultFooterColor) { - binding.colorBackground.setColorFilter(colors.backgroundColor) - } - } - }) + .songCoverOptions(MusicPlayerRemote.currentSong).apply { + thumbnail(lastRequest) + .crossfadeListener() + .transform( + BlurTransformation.Builder(requireContext()) + .blurRadius(blurAmount.toFloat()) + .build() + ) + .into(binding.colorBackground) + lastRequest = this + } + } override fun onServiceConnected() { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/cardblur/CardBlurFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/cardblur/CardBlurFragment.kt index bec78c7e5..dc78a10cd 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/cardblur/CardBlurFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/cardblur/CardBlurFragment.kt @@ -16,6 +16,7 @@ package code.name.monkey.retromusic.fragments.player.cardblur import android.content.SharedPreferences import android.graphics.Color +import android.graphics.drawable.Drawable import android.os.Bundle import android.view.View import androidx.appcompat.widget.Toolbar @@ -28,10 +29,7 @@ import code.name.monkey.retromusic.extensions.drawAboveSystemBars import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment import code.name.monkey.retromusic.fragments.player.normal.PlayerFragment -import code.name.monkey.retromusic.glide.BlurTransformation -import code.name.monkey.retromusic.glide.GlideApp -import code.name.monkey.retromusic.glide.RetroGlideExtension -import code.name.monkey.retromusic.glide.RetroMusicColoredTarget +import code.name.monkey.retromusic.glide.* import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.PreferenceUtil.blurAmount @@ -50,6 +48,7 @@ class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player), private var _binding: FragmentCardBlurPlayerBinding? = null private val binding get() = _binding!! + private var lastRequest: GlideRequest? = null override fun onShow() { playbackControlsFragment.show() @@ -136,22 +135,20 @@ class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player), } private fun updateBlur() { - binding.colorBackground.clearColorFilter() - GlideApp.with(requireActivity()).asBitmapPalette() - .songCoverOptions(MusicPlayerRemote.currentSong) + // https://github.com/bumptech/glide/issues/527#issuecomment-148840717 + GlideApp.with(this) .load(RetroGlideExtension.getSongModel(MusicPlayerRemote.currentSong)) - .dontAnimate() - .transform( - BlurTransformation.Builder(requireContext()).blurRadius(blurAmount.toFloat()) - .build() - ) - .into(object : RetroMusicColoredTarget(binding.colorBackground) { - override fun onColorReady(colors: MediaNotificationProcessor) { - if (colors.backgroundColor == defaultFooterColor) { - binding.colorBackground.setColorFilter(colors.backgroundColor) - } - } - }) + .songCoverOptions(MusicPlayerRemote.currentSong).apply { + thumbnail(lastRequest) + .crossfadeListener() + .transform( + BlurTransformation.Builder(requireContext()) + .blurRadius(blurAmount.toFloat()) + .build() + ) + .into(binding.colorBackground) + lastRequest = this + } } override fun onResume() { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/circle/CirclePlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/circle/CirclePlayerFragment.kt index 10de5dc26..1e68528bd 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/circle/CirclePlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/circle/CirclePlayerFragment.kt @@ -19,6 +19,7 @@ import android.content.Context import android.graphics.Color import android.graphics.PorterDuff import android.graphics.drawable.ColorDrawable +import android.graphics.drawable.Drawable import android.media.AudioManager import android.os.Bundle import android.view.LayoutInflater @@ -37,8 +38,7 @@ import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment import code.name.monkey.retromusic.fragments.base.goToAlbum import code.name.monkey.retromusic.fragments.base.goToArtist -import code.name.monkey.retromusic.glide.GlideApp -import code.name.monkey.retromusic.glide.RetroGlideExtension +import code.name.monkey.retromusic.glide.* import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper.Callback @@ -70,6 +70,7 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player), private val binding get() = _binding!! private var rotateAnimator: ObjectAnimator? = null + private var lastRequest: GlideRequest? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -241,9 +242,15 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player), binding.songInfo.hide() } GlideApp.with(this) - .load(RetroGlideExtension.getSongModel(song)) - .songCoverOptions(song) - .into(binding.albumCover) + .load(RetroGlideExtension.getSongModel(MusicPlayerRemote.currentSong)) + .songCoverOptions(MusicPlayerRemote.currentSong).apply { + thumbnail(lastRequest) + .crossfadeListener() + .fitCenter() + .into(binding.albumCover) + lastRequest = this + } + } private fun updatePlayPauseDrawableState() { 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 9db983669..e16971768 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 @@ -1,8 +1,10 @@ package code.name.monkey.retromusic.glide import android.graphics.drawable.Drawable +import androidx.core.graphics.drawable.toDrawable import code.name.monkey.appthemehelper.ThemeStore.Companion.accentColor import code.name.monkey.appthemehelper.util.TintHelper +import code.name.monkey.retromusic.App import code.name.monkey.retromusic.App.Companion.getContext import code.name.monkey.retromusic.Constants.USER_BANNER import code.name.monkey.retromusic.Constants.USER_PROFILE @@ -23,9 +25,15 @@ import com.bumptech.glide.RequestBuilder import com.bumptech.glide.annotation.GlideExtension import com.bumptech.glide.annotation.GlideOption import com.bumptech.glide.annotation.GlideType +import com.bumptech.glide.load.DataSource import com.bumptech.glide.load.Key import com.bumptech.glide.load.engine.DiskCacheStrategy +import com.bumptech.glide.load.engine.GlideException import com.bumptech.glide.request.BaseRequestOptions +import com.bumptech.glide.request.RequestListener +import com.bumptech.glide.request.target.Target +import com.bumptech.glide.request.transition.DrawableCrossFadeFactory +import com.bumptech.glide.request.transition.Transition import com.bumptech.glide.signature.MediaStoreSignature import java.io.File @@ -194,4 +202,33 @@ object RetroGlideExtension { fun getDefaultTransition(): GenericTransitionOptions { return GenericTransitionOptions().transition(DEFAULT_ANIMATION) } +} + +// https://github.com/bumptech/glide/issues/527#issuecomment-148840717 +fun GlideRequest.crossfadeListener(): GlideRequest { + return listener(object : RequestListener { + override fun onLoadFailed( + e: GlideException?, + model: Any?, + target: Target?, + isFirstResource: Boolean + ): Boolean { + return false + } + + override fun onResourceReady( + resource: Drawable?, + model: Any?, + target: Target?, + dataSource: DataSource?, + isFirstResource: Boolean + ): Boolean { + return if (isFirstResource) { + false // thumbnail was not shown, do as usual + } else DrawableCrossFadeFactory.Builder() + .setCrossFadeEnabled(true).build() + .build(dataSource, isFirstResource) + .transition(resource, target as Transition.ViewAdapter) + } + }) } \ No newline at end of file From 5a204b3653735a89a01ef0a038a38e7d0dbe58d3 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Wed, 15 Dec 2021 12:03:01 +0530 Subject: [PATCH 10/29] [Lockscreen Controls] Fixed glitchy Lockscreen Slide --- .../res/layout/fragment_lock_screen_playback_controls.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/res/layout/fragment_lock_screen_playback_controls.xml b/app/src/main/res/layout/fragment_lock_screen_playback_controls.xml index a8f9a71a5..95fe798f5 100644 --- a/app/src/main/res/layout/fragment_lock_screen_playback_controls.xml +++ b/app/src/main/res/layout/fragment_lock_screen_playback_controls.xml @@ -10,7 +10,7 @@ Date: Wed, 15 Dec 2021 12:06:43 +0530 Subject: [PATCH 11/29] [Tag Editor] Readable text color for Tag Editor save button --- .../tageditor/AlbumTagEditorActivity.kt | 8 ++++++++ .../tageditor/SongTagEditorActivity.kt | 19 ++++++++++++++----- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt index 79a954055..404f505a7 100755 --- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt @@ -29,9 +29,11 @@ import android.view.LayoutInflater import android.widget.ImageView import android.widget.Toast import code.name.monkey.appthemehelper.util.ATHUtil +import code.name.monkey.appthemehelper.util.MaterialValueHelper import code.name.monkey.retromusic.R import code.name.monkey.retromusic.databinding.ActivityAlbumTagEditorBinding import code.name.monkey.retromusic.extensions.appHandleColor +import code.name.monkey.retromusic.extensions.isColorLight import code.name.monkey.retromusic.extensions.setTint import code.name.monkey.retromusic.glide.GlideApp import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper @@ -213,6 +215,12 @@ class AlbumTagEditorActivity : AbsTagEditorActivity binding.trackNumberText.appHandleColor().addTextChangedListener(this) binding.lyricsText.appHandleColor().addTextChangedListener(this) binding.songComposerText.appHandleColor().addTextChangedListener(this) - - binding.lyricsText.setOnTouchListener { view, _ -> - view.parent.requestDisallowInterceptTouchEvent(true) - return@setOnTouchListener false - } } private fun fillViewsWithFileTags() { @@ -133,6 +131,17 @@ class SongTagEditorActivity : AbsTagEditorActivity dataChanged() } + override fun setColors(color: Int) { + super.setColors(color) + saveFab.backgroundTintList = ColorStateList.valueOf(color) + saveFab.iconTint = ColorStateList.valueOf( + MaterialValueHelper.getPrimaryTextColor( + this, + color.isColorLight + ) + ) + } + override fun save() { val fieldKeyValueMap = EnumMap(FieldKey::class.java) fieldKeyValueMap[FieldKey.TITLE] = binding.songText.text.toString() From 9806e2119af191a8ff36b797c1ca802ca41b8271 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Wed, 15 Dec 2021 13:37:25 +0530 Subject: [PATCH 12/29] Updated dependencies --- app/build.gradle | 2 +- appthemehelper/build.gradle | 1 - build.gradle | 2 +- 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 1c5c52c52..a97588114 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -138,7 +138,7 @@ dependencies { implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" - def kotlin_coroutines_version = '1.6.0-RC' + def kotlin_coroutines_version = '1.6.0-RC2' implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version" diff --git a/appthemehelper/build.gradle b/appthemehelper/build.gradle index 407e90903..10c0f52e5 100644 --- a/appthemehelper/build.gradle +++ b/appthemehelper/build.gradle @@ -20,7 +20,6 @@ android { } dependencies { - implementation fileTree(include: ['*.jar'], dir: 'libs') implementation 'androidx.appcompat:appcompat:1.4.0' implementation 'com.google.android.material:material:1.5.0-beta01' implementation 'androidx.preference:preference-ktx:1.2.0-beta01' diff --git a/build.gradle b/build.gradle index 42064114f..1c7975412 100644 --- a/build.gradle +++ b/build.gradle @@ -1,7 +1,7 @@ // Top-level build file where you can add configuration options common to all sub-projects/modules. buildscript { - ext.kotlin_version = '1.6.0' + ext.kotlin_version = '1.6.10' repositories { mavenCentral() google() From e4a309af664cd992fc6cec2928524a039e9c2c4d Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Wed, 15 Dec 2021 15:05:45 +0530 Subject: [PATCH 13/29] [Now Playing] Replaced old lyrics with LrcView, this replaces Album Cover with LrcView when enabled [Now Playing] Replaced old lyrics with LrcView, this replaces Album Cover with LrcView when enabled --- .../fragments/other/UserInfoFragment.kt | 3 +- .../player/PlayerAlbumCoverFragment.kt | 203 ++--- .../player/adaptive/AdaptiveFragment.kt | 2 +- .../monkey/retromusic/lyrics/CoverLrcView.kt | 718 ++++++++++++++++++ ...fragment_flat_player_playback_controls.xml | 1 - .../layout/fragment_player_album_cover.xml | 59 +- app/src/main/res/values/lrc_dimens.xml | 4 +- 7 files changed, 818 insertions(+), 172 deletions(-) create mode 100644 app/src/main/java/code/name/monkey/retromusic/lyrics/CoverLrcView.kt diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/other/UserInfoFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/other/UserInfoFragment.kt index ea3653eba..38b040b6c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/other/UserInfoFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/other/UserInfoFragment.kt @@ -134,12 +134,11 @@ class UserInfoFragment : Fragment() { private fun loadProfile() { binding.bannerImage.let { GlideApp.with(this) - .asBitmap() .load(RetroGlideExtension.getBannerModel()) .profileBannerOptions(RetroGlideExtension.getBannerModel()) .into(it) } - GlideApp.with(this).asBitmap() + GlideApp.with(this) .load(RetroGlideExtension.getUserModel()) .userProfileOptions(RetroGlideExtension.getUserModel()) .into(binding.userImage) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/PlayerAlbumCoverFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/PlayerAlbumCoverFragment.kt index e75ab76cb..027a773e0 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/PlayerAlbumCoverFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/PlayerAlbumCoverFragment.kt @@ -14,42 +14,36 @@ */ package code.name.monkey.retromusic.fragments.player +import android.annotation.SuppressLint import android.content.SharedPreferences +import android.graphics.Color import android.os.Bundle -import android.text.TextUtils import android.view.View -import android.widget.FrameLayout -import android.widget.TextView +import androidx.core.view.isInvisible import androidx.core.view.isVisible -import androidx.lifecycle.lifecycleScope import androidx.preference.PreferenceManager import androidx.viewpager.widget.ViewPager +import code.name.monkey.appthemehelper.util.MaterialValueHelper import code.name.monkey.retromusic.R import code.name.monkey.retromusic.SHOW_LYRICS import code.name.monkey.retromusic.adapter.album.AlbumCoverPagerAdapter import code.name.monkey.retromusic.adapter.album.AlbumCoverPagerAdapter.AlbumCoverFragment import code.name.monkey.retromusic.databinding.FragmentPlayerAlbumCoverBinding +import code.name.monkey.retromusic.extensions.isColorLight +import code.name.monkey.retromusic.extensions.surfaceColor import code.name.monkey.retromusic.fragments.NowPlayingScreen.* import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment import code.name.monkey.retromusic.fragments.base.goToLyrics import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper -import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics +import code.name.monkey.retromusic.lyrics.CoverLrcView import code.name.monkey.retromusic.model.lyrics.Lyrics import code.name.monkey.retromusic.transform.CarousalPagerTransformer import code.name.monkey.retromusic.transform.ParallaxPagerTransformer import code.name.monkey.retromusic.util.LyricUtil import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.color.MediaNotificationProcessor -import kotlinx.coroutines.Dispatchers -import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import org.jaudiotagger.audio.AudioFileIO -import org.jaudiotagger.audio.exceptions.CannotReadException -import org.jaudiotagger.tag.FieldKey -import java.io.File -import java.io.FileNotFoundException class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_player_album_cover), ViewPager.OnPageChangeListener, MusicProgressViewUpdateHelper.Callback, @@ -70,9 +64,7 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe } private var progressViewUpdateHelper: MusicProgressViewUpdateHelper? = null - private val lyricsLayout: FrameLayout get() = binding.playerLyrics - private val lyricsLine1: TextView get() = binding.playerLyricsLine1 - private val lyricsLine2: TextView get() = binding.playerLyricsLine2 + private val lrcView: CoverLrcView get() = binding.lyricsView var lyrics: Lyrics? = null @@ -82,102 +74,28 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe } private fun updateLyrics() { - lyrics = null - lifecycleScope.launch(Dispatchers.IO) { - val song = MusicPlayerRemote.currentSong - val lyrics = try { - var lrcFile: File? = null - if (LyricUtil.isLrcOriginalFileExist(song.data)) { - lrcFile = LyricUtil.getLocalLyricOriginalFile(song.data) - } else if (LyricUtil.isLrcFileExist(song.title, song.artistName)) { - lrcFile = LyricUtil.getLocalLyricFile(song.title, song.artistName) - } - val data: String = LyricUtil.getStringFromLrc(lrcFile) - if (!TextUtils.isEmpty(data)) { - Lyrics.parse(song, data) - } else { - // Get Embedded Lyrics and check if they are Synchronized - val embeddedLyrics = try{ - AudioFileIO.read(File(song.data)).tagOrCreateDefault.getFirst(FieldKey.LYRICS) - } catch(e: Exception){ - null - } - if (AbsSynchronizedLyrics.isSynchronized(embeddedLyrics)) { - Lyrics.parse(song, embeddedLyrics) - } else { - null - } - } - } catch (err: FileNotFoundException) { - null - } catch (e: CannotReadException){ - null + binding.lyricsView.setLabel("Empty") + val song = MusicPlayerRemote.currentSong + when { + LyricUtil.isLrcOriginalFileExist(song.data) -> { + LyricUtil.getLocalLyricOriginalFile(song.data) + ?.let { binding.lyricsView.loadLrc(it) } } - withContext(Dispatchers.Main) { - this@PlayerAlbumCoverFragment.lyrics = lyrics + LyricUtil.isLrcFileExist(song.title, song.artistName) -> { + LyricUtil.getLocalLyricFile(song.title, song.artistName) + ?.let { binding.lyricsView.loadLrc(it) } + } + else -> { + binding.lyricsView.reset() } } } override fun onUpdateProgressViews(progress: Int, total: Int) { - if (_binding == null) return - - if (!isLyricsLayoutVisible()) { - hideLyricsLayout() - return - } - - if (lyrics !is AbsSynchronizedLyrics) return - val synchronizedLyrics = lyrics as AbsSynchronizedLyrics - - lyricsLayout.visibility = View.VISIBLE - lyricsLayout.alpha = 1f - - val oldLine = lyricsLine2.text.toString() - val line = synchronizedLyrics.getLine(progress) - - if (oldLine != line || oldLine.isEmpty()) { - lyricsLine1.text = oldLine - lyricsLine2.text = line - - lyricsLine1.visibility = View.VISIBLE - lyricsLine2.visibility = View.VISIBLE - - lyricsLine2.measure( - View.MeasureSpec.makeMeasureSpec( - lyricsLine2.measuredWidth, - View.MeasureSpec.EXACTLY - ), - View.MeasureSpec.UNSPECIFIED - ) - val h: Float = lyricsLine2.measuredHeight.toFloat() - - lyricsLine1.alpha = 1f - lyricsLine1.translationY = 0f - lyricsLine1.animate().alpha(0f).translationY(-h).duration = - AbsPlayerFragment.VISIBILITY_ANIM_DURATION - - lyricsLine2.alpha = 0f - lyricsLine2.translationY = h - lyricsLine2.animate().alpha(1f).translationY(0f).duration = - AbsPlayerFragment.VISIBILITY_ANIM_DURATION - } - } - - private fun isLyricsLayoutVisible(): Boolean { - return lyrics != null && lyrics!!.isSynchronized && lyrics!!.isValid - } - - private fun hideLyricsLayout() { - lyricsLayout.animate().alpha(0f).setDuration(AbsPlayerFragment.VISIBILITY_ANIM_DURATION) - .withEndAction { - if (_binding == null) return@withEndAction - lyricsLayout.visibility = View.GONE - lyricsLine1.text = null - lyricsLine2.text = null - } + binding.lyricsView.updateTime(progress.toLong()) } + @SuppressLint("ClickableViewAccessibility") override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) _binding = FragmentPlayerAlbumCoverBinding.bind(view) @@ -210,14 +128,25 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe progressViewUpdateHelper = MusicProgressViewUpdateHelper(this, 500, 1000) // Don't show lyrics container for below conditions if (!(nps == Circle || nps == Peak || nps == Tiny || !PreferenceUtil.showLyrics)) { - lyricsLayout.isVisible = false + lrcView.isVisible = false + viewPager.isInvisible = false progressViewUpdateHelper?.stop() } else { - lyricsLayout.isVisible = true + lrcView.isVisible = true + viewPager.isInvisible = true progressViewUpdateHelper?.start() } + lrcView.apply { + setDraggable(true, object : CoverLrcView.OnPlayClickListener { + override fun onPlayClick(time: Long): Boolean { + MusicPlayerRemote.seekTo(time.toInt()) + MusicPlayerRemote.resumePlaying() + return true + } + }) + } // Go to lyrics activity when clicked lyrics - binding.playerLyricsLine2.setOnClickListener { + lrcView.setOnClickListener { goToLyrics(requireActivity()) } } @@ -227,10 +156,12 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe val nps = PreferenceUtil.nowPlayingScreen // Don't show lyrics container for below conditions if (nps == Circle || nps == Peak || nps == Tiny || !PreferenceUtil.showLyrics) { - lyricsLayout.isVisible = false + lrcView.isVisible = false + viewPager.isInvisible = false progressViewUpdateHelper?.stop() } else { - lyricsLayout.isVisible = true + lrcView.isVisible = true + viewPager.isInvisible = true progressViewUpdateHelper?.start() } PreferenceManager.getDefaultSharedPreferences(requireContext()) @@ -266,30 +197,42 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe val nps = PreferenceUtil.nowPlayingScreen // Don't show lyrics container for below conditions if (!(nps == Circle || nps == Peak || nps == Tiny || !PreferenceUtil.showLyrics)) { - lyricsLayout.isVisible = false - progressViewUpdateHelper?.stop() - } else { - lyricsLayout.isVisible = true + lrcView.isVisible = true + viewPager.isInvisible = true progressViewUpdateHelper?.start() - lyricsLayout.animate().alpha(1f).duration = + lrcView.animate().alpha(1f).duration = AbsPlayerFragment.VISIBILITY_ANIM_DURATION - binding.playerLyrics.isVisible = true + } else { + lrcView.isVisible = false + viewPager.isInvisible = false + progressViewUpdateHelper?.stop() } } else { + lrcView.isVisible = false + viewPager.isInvisible = false progressViewUpdateHelper?.stop() - lyricsLayout.animate().alpha(0f) - .setDuration(AbsPlayerFragment.VISIBILITY_ANIM_DURATION) - .withEndAction { - if (_binding != null) { - binding.playerLyrics.isVisible = false - lyricsLine1.text = null - lyricsLine2.text = null - } - } } } } + private fun setLRCViewColors(backgroundColor: Int) { + val primaryColor = MaterialValueHelper.getPrimaryTextColor( + requireContext(), + backgroundColor.isColorLight + ) + val secondaryColor = MaterialValueHelper.getSecondaryDisabledTextColor( + requireContext(), + backgroundColor.isColorLight + ) + lrcView.apply { + setCurrentColor(primaryColor) + setTimeTextColor(primaryColor) + setTimelineColor(primaryColor) + setNormalColor(secondaryColor) + setTimelineTextColor(primaryColor) + } + } + private fun updatePlayingQueue() { binding.viewPager.apply { adapter = AlbumCoverPagerAdapter(childFragmentManager, MusicPlayerRemote.playingQueue) @@ -321,6 +264,18 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe private fun notifyColorChange(color: MediaNotificationProcessor) { callbacks?.onColorChanged(color) + setLRCViewColors( + when (PreferenceUtil.nowPlayingScreen) { + Adaptive, Fit, Plain, Simple -> surfaceColor() + Flat, Normal -> if (PreferenceUtil.isAdaptiveColor) { + color.backgroundColor + } else { + surfaceColor() + } + Color ->color.backgroundColor + Blur -> Color.BLACK + else -> color.backgroundColor + }) } fun setCallbacks(listener: Callbacks) { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/adaptive/AdaptiveFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/adaptive/AdaptiveFragment.kt index 225d7b208..32bb5c259 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/adaptive/AdaptiveFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/adaptive/AdaptiveFragment.kt @@ -47,7 +47,7 @@ class AdaptiveFragment : AbsPlayerFragment(R.layout.fragment_adaptive_player) { _binding = FragmentAdaptivePlayerBinding.bind(view) setUpSubFragments() setUpPlayerToolbar() - binding.root.drawAboveSystemBars() + binding.playbackControlsFragment.drawAboveSystemBars() } private fun setUpSubFragments() { diff --git a/app/src/main/java/code/name/monkey/retromusic/lyrics/CoverLrcView.kt b/app/src/main/java/code/name/monkey/retromusic/lyrics/CoverLrcView.kt new file mode 100644 index 000000000..1173632c8 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/lyrics/CoverLrcView.kt @@ -0,0 +1,718 @@ +/* + * Copyright (C) 2017 wangchenyan + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software distributed under the + * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language governing + * permissions and limitations under the License. + */ +package code.name.monkey.retromusic.lyrics + +import android.annotation.SuppressLint +import kotlin.jvm.JvmOverloads +import android.text.TextPaint +import android.graphics.drawable.Drawable +import android.animation.ValueAnimator +import android.view.GestureDetector +import android.widget.Scroller +import android.view.GestureDetector.SimpleOnGestureListener +import android.view.MotionEvent +import code.name.monkey.retromusic.R +import android.text.TextUtils +import android.os.AsyncTask +import android.text.StaticLayout +import android.view.animation.LinearInterpolator +import android.content.Context +import android.graphics.Canvas +import android.graphics.Paint +import android.os.Looper +import android.text.Layout +import android.text.format.DateUtils +import android.util.AttributeSet +import android.view.View +import androidx.core.content.ContextCompat +import androidx.core.content.res.ResourcesCompat +import code.name.monkey.retromusic.BuildConfig +import java.io.File +import java.lang.StringBuilder +import java.util.* +import kotlin.math.abs + +/** + * 歌词 Created by wcy on 2015/11/9. + */ +@SuppressLint("StaticFieldLeak") +class CoverLrcView @JvmOverloads constructor( + context: Context?, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : View(context, attrs, defStyleAttr) { + private val mLrcEntryList: MutableList = ArrayList() + private val mLrcPaint = TextPaint() + private val mTimePaint = TextPaint() + private var mTimeFontMetrics: Paint.FontMetrics? = null + private var mPlayDrawable: Drawable? = null + private var mDividerHeight = 0f + private var mAnimationDuration: Long = 0 + private var mNormalTextColor = 0 + private var mNormalTextSize = 0f + private var mCurrentTextColor = 0 + private var mCurrentTextSize = 0f + private var mTimelineTextColor = 0 + private var mTimelineColor = 0 + private var mTimeTextColor = 0 + private var mDrawableWidth = 0 + private var mTimeTextWidth = 0 + private var mDefaultLabel: String? = null + private var mLrcPadding = 0f + private var mOnPlayClickListener: OnPlayClickListener? = null + private var mAnimator: ValueAnimator? = null + private var mGestureDetector: GestureDetector? = null + private var mScroller: Scroller? = null + private var mOffset = 0f + private var mCurrentLine = 0 + private var flag: Any? = null + private var isShowTimeline = false + private var isTouching = false + private var isFling = false + private var mTextGravity // 歌词显示位置,靠左/居中/靠右 + = 0 + private val hideTimelineRunnable = Runnable { + if (hasLrc() && isShowTimeline) { + isShowTimeline = false + smoothScrollTo(mCurrentLine) + } + } + + /** + * 手势监听器 + */ + private val mSimpleOnGestureListener: SimpleOnGestureListener = + object : SimpleOnGestureListener() { + override fun onDown(e: MotionEvent): Boolean { + if (mOffset != getOffset(0)) { + parent.requestDisallowInterceptTouchEvent(true) + } + if (hasLrc() && mOnPlayClickListener != null) { + mScroller!!.forceFinished(true) + removeCallbacks(hideTimelineRunnable) + isTouching = true + isShowTimeline = true + invalidate() + return true + } + return super.onDown(e) + } + + override fun onScroll( + e1: MotionEvent, + e2: MotionEvent, + distanceX: Float, + distanceY: Float + ): Boolean { + if (mOffset == getOffset(0) && distanceY < 0F) { + return super.onScroll(e1, e2, distanceX, distanceY) + } + if (hasLrc()) { + mOffset += -distanceY + mOffset = mOffset.coerceAtMost(getOffset(0)) + mOffset = mOffset.coerceAtLeast(getOffset(mLrcEntryList.size - 1)) + invalidate() + parent.requestDisallowInterceptTouchEvent(true) + return true + } + return super.onScroll(e1, e2, distanceX, distanceY) + } + + override fun onFling( + e1: MotionEvent, + e2: MotionEvent, + velocityX: Float, + velocityY: Float + ): Boolean { + if (hasLrc()) { + mScroller!!.fling( + 0, + mOffset.toInt(), + 0, + velocityY.toInt(), + 0, + 0, + getOffset(mLrcEntryList.size - 1).toInt(), + getOffset(0).toInt() + ) + isFling = true + return true + } + return super.onFling(e1, e2, velocityX, velocityY) + } + + override fun onSingleTapConfirmed(e: MotionEvent): Boolean { + if (hasLrc() + && isShowTimeline + && mPlayDrawable!!.bounds.contains(e.x.toInt(), e.y.toInt()) + ) { + val centerLine = centerLine + val centerLineTime = mLrcEntryList[centerLine].time + // onPlayClick 消费了才更新 UI + if (mOnPlayClickListener != null && mOnPlayClickListener!!.onPlayClick( + centerLineTime + ) + ) { + isShowTimeline = false + removeCallbacks(hideTimelineRunnable) + mCurrentLine = centerLine + invalidate() + return true + } + } + return super.onSingleTapConfirmed(e) + } + } + + private fun init(attrs: AttributeSet?) { + val ta = context.obtainStyledAttributes(attrs, R.styleable.LrcView) + mCurrentTextSize = ta.getDimension( + R.styleable.LrcView_lrcTextSize, resources.getDimension(R.dimen.lrc_text_size) + ) + mNormalTextSize = ta.getDimension( + R.styleable.LrcView_lrcNormalTextSize, + resources.getDimension(R.dimen.lrc_text_size) + ) + if (mNormalTextSize == 0f) { + mNormalTextSize = mCurrentTextSize + } + mDividerHeight = ta.getDimension( + R.styleable.LrcView_lrcDividerHeight, + resources.getDimension(R.dimen.lrc_divider_height) + ) + val defDuration = resources.getInteger(R.integer.lrc_animation_duration) + mAnimationDuration = + ta.getInt(R.styleable.LrcView_lrcAnimationDuration, defDuration).toLong() + mAnimationDuration = + if (mAnimationDuration < 0) defDuration.toLong() else mAnimationDuration + mNormalTextColor = ta.getColor( + R.styleable.LrcView_lrcNormalTextColor, + ContextCompat.getColor(context, R.color.lrc_normal_text_color) + ) + mCurrentTextColor = ta.getColor( + R.styleable.LrcView_lrcCurrentTextColor, + ContextCompat.getColor(context, R.color.lrc_current_text_color) + ) + mTimelineTextColor = ta.getColor( + R.styleable.LrcView_lrcTimelineTextColor, + ContextCompat.getColor(context, R.color.lrc_timeline_text_color) + ) + mDefaultLabel = ta.getString(R.styleable.LrcView_lrcLabel) + mDefaultLabel = + if (TextUtils.isEmpty(mDefaultLabel)) context.getString(R.string.empty) else mDefaultLabel + mLrcPadding = ta.getDimension(R.styleable.LrcView_lrcPadding, 0f) + mTimelineColor = ta.getColor( + R.styleable.LrcView_lrcTimelineColor, + ContextCompat.getColor(context, R.color.lrc_timeline_color) + ) + val timelineHeight = ta.getDimension( + R.styleable.LrcView_lrcTimelineHeight, + resources.getDimension(R.dimen.lrc_timeline_height) + ) + mPlayDrawable = ta.getDrawable(R.styleable.LrcView_lrcPlayDrawable) + mPlayDrawable = + if (mPlayDrawable == null) ContextCompat.getDrawable( + context, + R.drawable.ic_play_arrow + ) else mPlayDrawable + mTimeTextColor = ta.getColor( + R.styleable.LrcView_lrcTimeTextColor, + ContextCompat.getColor(context, R.color.lrc_time_text_color) + ) + val timeTextSize = ta.getDimension( + R.styleable.LrcView_lrcTimeTextSize, + resources.getDimension(R.dimen.lrc_time_text_size) + ) + mTextGravity = ta.getInteger(R.styleable.LrcView_lrcTextGravity, LrcEntry.GRAVITY_CENTER) + ta.recycle() + mDrawableWidth = resources.getDimension(R.dimen.lrc_drawable_width).toInt() + mTimeTextWidth = resources.getDimension(R.dimen.lrc_time_width).toInt() + mLrcPaint.isAntiAlias = true + mLrcPaint.textSize = mCurrentTextSize + mLrcPaint.textAlign = Paint.Align.LEFT + mTimePaint.isAntiAlias = true + mTimePaint.textSize = timeTextSize + mTimePaint.textAlign = Paint.Align.CENTER + mTimePaint.strokeWidth = timelineHeight + mTimePaint.strokeCap = Paint.Cap.ROUND + mTimeFontMetrics = mTimePaint.fontMetrics + mGestureDetector = GestureDetector(context, mSimpleOnGestureListener) + mGestureDetector!!.setIsLongpressEnabled(false) + mScroller = Scroller(context) + } + + /** 设置非当前行歌词字体颜色 */ + fun setNormalColor(normalColor: Int) { + mNormalTextColor = normalColor + postInvalidate() + } + + /** 普通歌词文本字体大小 */ + fun setNormalTextSize(size: Float) { + mNormalTextSize = size + } + + /** 当前歌词文本字体大小 */ + fun setCurrentTextSize(size: Float) { + mCurrentTextSize = size + } + + /** 设置当前行歌词的字体颜色 */ + fun setCurrentColor(currentColor: Int) { + mCurrentTextColor = currentColor + postInvalidate() + } + + /** 设置拖动歌词时选中歌词的字体颜色 */ + fun setTimelineTextColor(timelineTextColor: Int) { + mTimelineTextColor = timelineTextColor + postInvalidate() + } + + /** 设置拖动歌词时时间线的颜色 */ + fun setTimelineColor(timelineColor: Int) { + mTimelineColor = timelineColor + postInvalidate() + } + + /** 设置拖动歌词时右侧时间字体颜色 */ + fun setTimeTextColor(timeTextColor: Int) { + mTimeTextColor = timeTextColor + postInvalidate() + } + + /** + * 设置歌词是否允许拖动 + * + * @param draggable 是否允许拖动 + * @param onPlayClickListener 设置歌词拖动后播放按钮点击监听器,如果允许拖动,则不能为 null + */ + fun setDraggable(draggable: Boolean, onPlayClickListener: OnPlayClickListener?) { + mOnPlayClickListener = if (draggable) { + requireNotNull(onPlayClickListener) { "if draggable == true, onPlayClickListener must not be null" } + onPlayClickListener + } else { + null + } + } + + /** + * 设置播放按钮点击监听器 + * + * @param onPlayClickListener 如果为非 null ,则激活歌词拖动功能,否则将将禁用歌词拖动功能 + */ + @Deprecated("use {@link #setDraggable(boolean, OnPlayClickListener)} instead") + fun setOnPlayClickListener(onPlayClickListener: OnPlayClickListener?) { + mOnPlayClickListener = onPlayClickListener + } + + /** 设置歌词为空时屏幕中央显示的文字,如“暂无歌词” */ + fun setLabel(label: String?) { + runOnUi { + mDefaultLabel = label + invalidate() + } + } + + /** + * 加载歌词文件 + * + * @param lrcFile 歌词文件 + */ + fun loadLrc(lrcFile: File) { + loadLrc(lrcFile, null) + } + + /** + * 加载双语歌词文件,两种语言的歌词时间戳需要一致 + * + * @param mainLrcFile 第一种语言歌词文件 + * @param secondLrcFile 第二种语言歌词文件 + */ + fun loadLrc(mainLrcFile: File, secondLrcFile: File?) { + runOnUi { + reset() + val sb = StringBuilder("file://") + sb.append(mainLrcFile.path) + if (secondLrcFile != null) { + sb.append("#").append(secondLrcFile.path) + } + val flag = sb.toString() + this.flag = flag + object : AsyncTask>() { + override fun doInBackground(vararg params: File?): List? { + return LrcUtils.parseLrc(params) + } + + override fun onPostExecute(lrcEntries: List) { + if (flag === flag) { + onLrcLoaded(lrcEntries) + this@CoverLrcView.flag = null + } + } + }.execute(mainLrcFile, secondLrcFile) + } + } + + /** + * 加载歌词文本 + * + * @param lrcText 歌词文本 + */ + fun loadLrc(lrcText: String?) { + loadLrc(lrcText, null) + } + + /** + * 加载双语歌词文本,两种语言的歌词时间戳需要一致 + * + * @param mainLrcText 第一种语言歌词文本 + * @param secondLrcText 第二种语言歌词文本 + */ + fun loadLrc(mainLrcText: String?, secondLrcText: String?) { + runOnUi { + reset() + val sb = StringBuilder("file://") + sb.append(mainLrcText) + if (secondLrcText != null) { + sb.append("#").append(secondLrcText) + } + val flag = sb.toString() + this.flag = flag + object : AsyncTask>() { + override fun doInBackground(vararg params: String?): List? { + return LrcUtils.parseLrc(params) + } + + override fun onPostExecute(lrcEntries: List) { + if (flag === flag) { + onLrcLoaded(lrcEntries) + this@CoverLrcView.flag = null + } + } + }.execute(mainLrcText, secondLrcText) + } + } + /** + * 加载在线歌词 + * + * @param lrcUrl 歌词文件的网络地址 + * @param charset 编码格式 + */ + /** + * 加载在线歌词,默认使用 utf-8 编码 + * + * @param lrcUrl 歌词文件的网络地址 + */ + @JvmOverloads + fun loadLrcByUrl(lrcUrl: String, charset: String? = "utf-8") { + val flag = "url://$lrcUrl" + this.flag = flag + object : AsyncTask() { + override fun doInBackground(vararg params: String?): String? { + return LrcUtils.getContentFromNetwork(params[0], params[1]) + } + + override fun onPostExecute(lrcText: String) { + if (flag === flag) { + loadLrc(lrcText) + } + } + }.execute(lrcUrl, charset) + } + + /** + * 歌词是否有效 + * + * @return true,如果歌词有效,否则false + */ + fun hasLrc(): Boolean { + return mLrcEntryList.isNotEmpty() + } + + /** + * 刷新歌词 + * + * @param time 当前播放时间 + */ + fun updateTime(time: Long) { + runOnUi { + if (!hasLrc()) { + return@runOnUi + } + val line = findShowLine(time) + if (line != mCurrentLine) { + mCurrentLine = line + if (!isShowTimeline) { + smoothScrollTo(line) + } else { + invalidate() + } + } + } + } + + override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) { + super.onLayout(changed, left, top, right, bottom) + if (changed) { + initPlayDrawable() + initEntryList() + if (hasLrc()) { + smoothScrollTo(mCurrentLine, 0L) + } + } + } + + override fun onDraw(canvas: Canvas) { + super.onDraw(canvas) + val centerY = height / 2 + + // 无歌词文件 + if (!hasLrc()) { + mLrcPaint.color = mCurrentTextColor + @SuppressLint("DrawAllocation") val staticLayout = StaticLayout( + mDefaultLabel, + mLrcPaint, + lrcWidth.toInt(), + Layout.Alignment.ALIGN_CENTER, + 1f, + 0f, + false + ) + drawText(canvas, staticLayout, centerY.toFloat()) + return + } + val centerLine = centerLine + if (isShowTimeline) { + mPlayDrawable?.draw(canvas) + mTimePaint.color = mTimeTextColor + val timeText = LrcUtils.formatTime(mLrcEntryList[centerLine].time) + val timeX = (width - mTimeTextWidth / 2).toFloat() + val timeY = centerY - (mTimeFontMetrics!!.descent + mTimeFontMetrics!!.ascent) / 2 + canvas.drawText(timeText, timeX, timeY, mTimePaint) + } + canvas.translate(0f, mOffset) + var y = 0f + for (i in mLrcEntryList.indices) { + if (i > 0) { + y += ((mLrcEntryList[i - 1].height + mLrcEntryList[i].height shr 1) + + mDividerHeight) + } + if (BuildConfig.DEBUG) { + mLrcPaint.typeface = ResourcesCompat.getFont(context, R.font.sans) + } + if (i == mCurrentLine) { + mLrcPaint.textSize = mCurrentTextSize + mLrcPaint.color = mCurrentTextColor + } else if (isShowTimeline && i == centerLine) { + mLrcPaint.color = mTimelineTextColor + } else { + mLrcPaint.textSize = mNormalTextSize + mLrcPaint.color = mNormalTextColor + } + drawText(canvas, mLrcEntryList[i].staticLayout, y) + } + } + + /** + * 画一行歌词 + * + * @param y 歌词中心 Y 坐标 + */ + private fun drawText(canvas: Canvas, staticLayout: StaticLayout, y: Float) { + canvas.save() + canvas.translate(mLrcPadding, y - (staticLayout.height shr 1)) + staticLayout.draw(canvas) + canvas.restore() + } + + @SuppressLint("ClickableViewAccessibility") + override fun onTouchEvent(event: MotionEvent): Boolean { + if (event.action == MotionEvent.ACTION_UP + || event.action == MotionEvent.ACTION_CANCEL + ) { + isTouching = false + if (hasLrc() && !isFling) { + adjustCenter() + postDelayed(hideTimelineRunnable, TIMELINE_KEEP_TIME) + } + } + return mGestureDetector!!.onTouchEvent(event) + } + + override fun computeScroll() { + if (mScroller!!.computeScrollOffset()) { + mOffset = mScroller!!.currY.toFloat() + invalidate() + } + if (isFling && mScroller!!.isFinished) { + isFling = false + if (hasLrc() && !isTouching) { + adjustCenter() + postDelayed(hideTimelineRunnable, TIMELINE_KEEP_TIME) + } + } + } + + override fun onDetachedFromWindow() { + removeCallbacks(hideTimelineRunnable) + super.onDetachedFromWindow() + } + + private fun onLrcLoaded(entryList: List?) { + if (entryList != null && entryList.isNotEmpty()) { + mLrcEntryList.addAll(entryList) + } + mLrcEntryList.sort() + initEntryList() + invalidate() + } + + private fun initPlayDrawable() { + val l = (mTimeTextWidth - mDrawableWidth) / 2 + val t = height / 2 - mDrawableWidth / 2 + val r = l + mDrawableWidth + val b = t + mDrawableWidth + mPlayDrawable!!.setBounds(l, t, r, b) + } + + private fun initEntryList() { + if (!hasLrc() || width == 0) { + return + } + for (lrcEntry in mLrcEntryList) { + lrcEntry.init(mLrcPaint, lrcWidth.toInt(), mTextGravity) + } + mOffset = (height / 2).toFloat() + } + + fun reset() { + endAnimation() + mScroller!!.forceFinished(true) + isShowTimeline = false + isTouching = false + isFling = false + removeCallbacks(hideTimelineRunnable) + mLrcEntryList.clear() + mOffset = 0f + mCurrentLine = 0 + invalidate() + } + + /** 将中心行微调至正中心 */ + private fun adjustCenter() { + smoothScrollTo(centerLine, ADJUST_DURATION) + } + /** 滚动到某一行 */ + /** 滚动到某一行 */ + private fun smoothScrollTo(line: Int, duration: Long = mAnimationDuration) { + val offset = getOffset(line) + endAnimation() + mAnimator = ValueAnimator.ofFloat(mOffset, offset).apply { + this.duration = duration + interpolator = LinearInterpolator() + addUpdateListener { animation: ValueAnimator -> + mOffset = animation.animatedValue as Float + invalidate() + } + LrcUtils.resetDurationScale() + start() + } + } + + /** 结束滚动动画 */ + private fun endAnimation() { + if (mAnimator != null && mAnimator!!.isRunning) { + mAnimator!!.end() + } + } + + /** 二分法查找当前时间应该显示的行数(最后一个 <= time 的行数) */ + private fun findShowLine(time: Long): Int { + var left = 0 + var right = mLrcEntryList.size + while (left <= right) { + val middle = (left + right) / 2 + val middleTime = mLrcEntryList[middle].time + if (time < middleTime) { + right = middle - 1 + } else { + if (middle + 1 >= mLrcEntryList.size || time < mLrcEntryList[middle + 1].time) { + return middle + } + left = middle + 1 + } + } + return 0 + } + + /** 获取当前在视图中央的行数 */ + private val centerLine: Int + get() { + var centerLine = 0 + var minDistance = Float.MAX_VALUE + for (i in mLrcEntryList.indices) { + if (abs(mOffset - getOffset(i)) < minDistance) { + minDistance = abs(mOffset - getOffset(i)) + centerLine = i + } + } + return centerLine + } + + /** 获取歌词距离视图顶部的距离 采用懒加载方式 */ + private fun getOffset(line: Int): Float { + if (mLrcEntryList[line].offset == Float.MIN_VALUE) { + var offset = (height / 2).toFloat() + for (i in 1..line) { + offset -= ((mLrcEntryList[i - 1].height + mLrcEntryList[i].height shr 1) + + mDividerHeight) + } + mLrcEntryList[line].offset = offset + } + return mLrcEntryList[line].offset + } + + /** 获取歌词宽度 */ + private val lrcWidth: Float + get() = width - mLrcPadding * 2 + + /** 在主线程中运行 */ + private fun runOnUi(r: Runnable) { + if (Looper.myLooper() == Looper.getMainLooper()) { + r.run() + } else { + post(r) + } + } + + /** 播放按钮点击监听器,点击后应该跳转到指定播放位置 */ + interface OnPlayClickListener { + /** + * 播放按钮被点击,应该跳转到指定播放位置 + * + * @return 是否成功消费该事件,如果成功消费,则会更新UI + */ + fun onPlayClick(time: Long): Boolean + } + + companion object { + private const val ADJUST_DURATION: Long = 100 + private const val TIMELINE_KEEP_TIME = 4 * DateUtils.SECOND_IN_MILLIS + } + + init { + init(attrs) + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_flat_player_playback_controls.xml b/app/src/main/res/layout/fragment_flat_player_playback_controls.xml index 283b1868e..bee59f8f8 100644 --- a/app/src/main/res/layout/fragment_flat_player_playback_controls.xml +++ b/app/src/main/res/layout/fragment_flat_player_playback_controls.xml @@ -153,7 +153,6 @@ android:layout_height="52dp" android:layout_centerVertical="true" android:background="?colorAccent" - android:foreground="?attr/rectSelector" android:padding="12dp" android:scaleType="fitCenter" tools:ignore="MissingPrefix" diff --git a/app/src/main/res/layout/fragment_player_album_cover.xml b/app/src/main/res/layout/fragment_player_album_cover.xml index 3789feebc..90aa7633c 100644 --- a/app/src/main/res/layout/fragment_player_album_cover.xml +++ b/app/src/main/res/layout/fragment_player_album_cover.xml @@ -1,5 +1,6 @@ @@ -7,50 +8,24 @@ + android:layout_height="match_parent" + android:overScrollMode="@integer/overScrollMode"> - + + + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" + app:lrcLabel="@string/no_lyrics_found" + app:lrcNormalTextSize="28sp" + app:lrcPadding="24dp" + app:lrcTextGravity="center" + app:lrcTextSize="32sp" + app:lrcTimelineColor="@color/transparent" + tools:visibility="visible" /> - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/values/lrc_dimens.xml b/app/src/main/res/values/lrc_dimens.xml index 4a5c994f4..b022d846b 100644 --- a/app/src/main/res/values/lrc_dimens.xml +++ b/app/src/main/res/values/lrc_dimens.xml @@ -1,8 +1,8 @@ 1000 - 16sp - 12sp + 20sp + 16sp 16dp 1dp 30dp From adab132bf3214414426ca1ae13ddca304ab45f5a Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Thu, 16 Dec 2021 00:36:28 +0530 Subject: [PATCH 14/29] [Home] Consistent no. of lines for Home playlist buttons --- .../retromusic/fragments/home/HomeFragment.kt | 16 ++++++++++++++++ app/src/main/res/layout/abs_playlists.xml | 1 - app/src/main/res/values/styles.xml | 3 ++- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt index 647361a84..3390621d4 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt @@ -23,6 +23,7 @@ import android.view.View import androidx.activity.addCallback import androidx.core.os.bundleOf import androidx.core.text.HtmlCompat +import androidx.core.view.doOnLayout import androidx.core.view.doOnPreDraw import androidx.navigation.fragment.FragmentNavigatorExtras import androidx.navigation.fragment.findNavController @@ -87,6 +88,21 @@ class HomeFragment : remove() mainActivity.finish() } + view.doOnLayout { + adjustPlaylistButtons() + } + } + + private fun adjustPlaylistButtons() { + val buttons = + listOf(binding.history, binding.lastAdded, binding.topPlayed, binding.actionShuffle) + buttons.maxOf { it.lineCount }.let { maxLineCount-> + buttons.forEach { button -> + // Set the highest line count to every button for consistency + button.setLines(maxLineCount) + } + } + } private fun setupListeners() { diff --git a/app/src/main/res/layout/abs_playlists.xml b/app/src/main/res/layout/abs_playlists.xml index bf4b5e80c..ee11757cd 100644 --- a/app/src/main/res/layout/abs_playlists.xml +++ b/app/src/main/res/layout/abs_playlists.xml @@ -43,7 +43,6 @@ android:layout_marginEnd="16dp" android:text="@string/my_top_tracks" app:icon="@drawable/ic_trending_up" - app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toStartOf="@+id/actionShuffle" app:layout_constraintHorizontal_bias="0.5" app:layout_constraintStart_toStartOf="@+id/history" diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index d1fbc9261..159bd3f86 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -223,7 +223,8 @@ + + + + + + + From 0544db11743d096b123e936beb6c19d40a051503 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Sun, 19 Dec 2021 16:11:50 +0530 Subject: [PATCH 26/29] Disabled EditText of Restore Activity --- app/src/main/res/layout/activity_restore.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/app/src/main/res/layout/activity_restore.xml b/app/src/main/res/layout/activity_restore.xml index fb38360b5..5f5224af6 100644 --- a/app/src/main/res/layout/activity_restore.xml +++ b/app/src/main/res/layout/activity_restore.xml @@ -16,7 +16,7 @@ android:id="@+id/backupName" android:layout_width="match_parent" android:layout_height="wrap_content" - android:inputType="none"/> + android:enabled="false" /> + Date: Mon, 20 Dec 2021 16:03:02 +0530 Subject: [PATCH 27/29] Use proguard-android-optimize.txt --- app/build.gradle | 2 +- appthemehelper/build.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 021f48dae..d67b927b9 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -33,7 +33,7 @@ android { versionNameSuffix "_" + getDate() shrinkResources true minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' signingConfig signingConfigs.release } debug { diff --git a/appthemehelper/build.gradle b/appthemehelper/build.gradle index 898a58e25..383b4637d 100644 --- a/appthemehelper/build.gradle +++ b/appthemehelper/build.gradle @@ -10,7 +10,7 @@ android { buildTypes { release { minifyEnabled true - proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } } compileOptions { From a26f08127cc26ec498856563111322e2af1ab0a8 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Mon, 20 Dec 2021 16:03:46 +0530 Subject: [PATCH 28/29] Fixed navigation bar color pre Oreo --- .../base/AbsSlidingMusicPanelActivity.kt | 14 ++++++++------ .../name/monkey/retromusic/lyrics/CoverLrcView.kt | 5 ----- 2 files changed, 8 insertions(+), 11 deletions(-) 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 2f1c2acd4..62b23ec8d 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 @@ -31,7 +31,6 @@ import androidx.core.view.isGone import androidx.core.view.isVisible import androidx.fragment.app.Fragment import androidx.fragment.app.commit -import code.name.monkey.appthemehelper.util.ATHUtil import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.retromusic.R import code.name.monkey.retromusic.RetroBottomSheetBehavior @@ -83,6 +82,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() { private var nowPlayingScreen: NowPlayingScreen? = null private var taskColor: Int = 0 private var paletteColor: Int = Color.WHITE + private var navigationBarColor = 0 protected abstract fun createContentView(): SlidingMusicPanelLayoutBinding private val panelState: Int get() = bottomSheetBehavior.state @@ -100,7 +100,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() { argbEvaluator.evaluate( slideOffset, surfaceColor(), - playerFragment!!.paletteColor + navigationBarColor ) as Int ) } @@ -148,6 +148,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() { updateColor() binding.slidingPanel.backgroundTintList = ColorStateList.valueOf(darkAccentColor()) bottomNavigationView.backgroundTintList = ColorStateList.valueOf(darkAccentColor()) + navigationBarColor = surfaceColor() } private fun setupBottomSheet() { @@ -285,6 +286,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() { private fun onPaletteColorChanged() { if (panelState == STATE_EXPANDED) { + navigationBarColor = surfaceColor() setTaskDescColor(paletteColor) val isColorLight = ColorUtil.isColorLight(paletteColor) if (PreferenceUtil.isAdaptiveColor && (nowPlayingScreen == Normal || nowPlayingScreen == Flat)) { @@ -292,14 +294,17 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() { setLightStatusBar(isColorLight) } else if (nowPlayingScreen == Card || nowPlayingScreen == Blur || nowPlayingScreen == BlurCard) { animateNavigationBarColor(Color.BLACK) + navigationBarColor = Color.BLACK setLightStatusBar(false) setLightNavigationBar(true) } else if (nowPlayingScreen == Color || nowPlayingScreen == Tiny || nowPlayingScreen == Gradient) { animateNavigationBarColor(paletteColor) + navigationBarColor = paletteColor setLightNavigationBar(isColorLight) setLightStatusBar(isColorLight) } else if (nowPlayingScreen == Full) { animateNavigationBarColor(paletteColor) + navigationBarColor = paletteColor setLightNavigationBar(isColorLight) setLightStatusBar(false) } else if (nowPlayingScreen == Classic) { @@ -309,10 +314,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() { } else { setLightStatusBar( ColorUtil.isColorLight( - ATHUtil.resolveColor( - this, - android.R.attr.windowBackground - ) + surfaceColor() ) ) setLightNavigationBar(true) diff --git a/app/src/main/java/code/name/monkey/retromusic/lyrics/CoverLrcView.kt b/app/src/main/java/code/name/monkey/retromusic/lyrics/CoverLrcView.kt index 28a0b8de6..d722668dc 100644 --- a/app/src/main/java/code/name/monkey/retromusic/lyrics/CoverLrcView.kt +++ b/app/src/main/java/code/name/monkey/retromusic/lyrics/CoverLrcView.kt @@ -34,8 +34,6 @@ import android.view.View import android.view.animation.LinearInterpolator import android.widget.Scroller import androidx.core.content.ContextCompat -import androidx.core.content.res.ResourcesCompat -import code.name.monkey.retromusic.BuildConfig import code.name.monkey.retromusic.R import java.io.File import java.util.* @@ -507,9 +505,6 @@ class CoverLrcView @JvmOverloads constructor( y += ((mLrcEntryList[i - 1].height + mLrcEntryList[i].height shr 1) + mDividerHeight) } - if (BuildConfig.DEBUG) { - mLrcPaint.typeface = ResourcesCompat.getFont(context, R.font.sans) - } if (i == mCurrentLine) { mLrcPaint.textSize = mCurrentTextSize mLrcPaint.color = mCurrentTextColor From 0dd5663e9e61dfeca6527fb71aa0761a2e7ad734 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Mon, 20 Dec 2021 16:42:49 +0530 Subject: [PATCH 29/29] Added fade in layout animation for DetailListFragment --- .../fragments/other/DetailListFragment.kt | 13 +++++-------- app/src/main/res/anim/layout_anim_fade.xml | 5 +++++ .../main/res/layout/fragment_playlist_detail.xml | 1 + 3 files changed, 11 insertions(+), 8 deletions(-) create mode 100644 app/src/main/res/anim/layout_anim_fade.xml diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/other/DetailListFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/other/DetailListFragment.kt index b28d903c0..14df3272c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/other/DetailListFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/other/DetailListFragment.kt @@ -64,14 +64,6 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de returnTransition = MaterialSharedAxis(MaterialSharedAxis.Y, false) } } - binding.appBarLayout.statusBarForeground = - MaterialShapeDrawable.createWithElevationOverlay(requireContext()) - postponeEnterTransition() - view.doOnPreDraw { startPostponedEnterTransition() } - } - - override fun onActivityCreated(savedInstanceState: Bundle?) { - super.onActivityCreated(savedInstanceState) mainActivity.setSupportActionBar(binding.toolbar) binding.progressIndicator.hide() when (args.type) { @@ -92,6 +84,10 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de binding.recyclerView.updatePadding(bottom = height.toInt()) } }) + binding.appBarLayout.statusBarForeground = + MaterialShapeDrawable.createWithElevationOverlay(requireContext()) + postponeEnterTransition() + view.doOnPreDraw { startPostponedEnterTransition() } } private fun lastAddedSongs() { @@ -104,6 +100,7 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de binding.recyclerView.apply { adapter = songAdapter layoutManager = linearLayoutManager() + scheduleLayoutAnimation() } libraryViewModel.recentSongs().observe(viewLifecycleOwner, { songs -> songAdapter.swapDataSet(songs) diff --git a/app/src/main/res/anim/layout_anim_fade.xml b/app/src/main/res/anim/layout_anim_fade.xml new file mode 100644 index 000000000..ba154e91e --- /dev/null +++ b/app/src/main/res/anim/layout_anim_fade.xml @@ -0,0 +1,5 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_playlist_detail.xml b/app/src/main/res/layout/fragment_playlist_detail.xml index 2b6d68a26..ffaf5985d 100644 --- a/app/src/main/res/layout/fragment_playlist_detail.xml +++ b/app/src/main/res/layout/fragment_playlist_detail.xml @@ -37,6 +37,7 @@ android:clipToPadding="false" android:overScrollMode="@integer/overScrollMode" android:scrollbars="none" + android:layoutAnimation="@anim/layout_anim_fade" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" />