From 2a5e6d775699bf3bb7317ce361ea63a6be45102e Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Tue, 14 Jun 2022 23:05:59 +0530 Subject: [PATCH 01/19] Added F-Droid FOSS flavor --- app/build.gradle | 21 ++- .../activities/base/AbsCastActivity.kt | 5 + .../retromusic/billing/BillingManager.kt | 9 + .../monkey/retromusic/cast/RetroWebServer.kt | 6 + .../retromusic/extensions/extensions.kt | 15 ++ .../monkey/retromusic/service/CastPlayer.kt | 47 +++++ .../name/monkey/retromusic/util/AppRater.kt | 8 + app/src/main/AndroidManifest.xml | 1 - .../java/code/name/monkey/retromusic/App.kt | 30 +--- .../activities/SupportDevelopmentActivity.kt | 170 +----------------- .../activities/base/AbsThemeActivity.kt | 3 +- .../retromusic/dialogs/SleepTimerDialog.kt | 2 +- .../fragments/albums/AlbumsFragment.kt | 4 +- .../fragments/artists/ArtistsFragment.kt | 4 +- .../fragments/genres/GenresFragment.kt | 4 +- .../retromusic/fragments/home/HomeFragment.kt | 8 +- .../fragments/library/LibraryFragment.kt | 4 +- .../fragments/playlists/PlaylistsFragment.kt | 4 +- .../fragments/settings/AbsSettingsFragment.kt | 3 +- .../settings/MainSettingsFragment.kt | 5 +- .../settings/OtherSettingsFragment.kt | 20 +-- .../fragments/songs/SongsFragment.kt | 4 +- .../retromusic/helper/MusicPlayerRemote.kt | 6 +- .../AlbumCoverStylePreferenceDialog.kt | 2 +- .../NowPlayingScreenPreferenceDialog.kt | 2 +- .../service/MediaButtonIntentReceiver.kt | 5 +- .../monkey/retromusic/service/MusicService.kt | 5 +- .../retromusic/service/PlaybackManager.kt | 5 +- .../monkey/retromusic/util/NavigationUtil.kt | 6 - .../monkey/retromusic/util/PremiumShow.kt | 33 ---- app/src/main/res/layout/activity_donation.xml | 48 ----- app/src/normal/AndroidManifest.xml | 9 + .../retromusic/activities/PurchaseActivity.kt | 20 +-- .../activities/base/AbsCastActivity.kt | 5 +- .../retromusic/billing/BillingManager.kt | 37 ++++ .../name/monkey/retromusic/cast/CastHelper.kt | 0 .../retromusic/cast/CastOptionsProvider.kt | 0 .../cast/RetroSessionManagerListener.kt | 0 .../monkey/retromusic/cast/RetroWebServer.kt | 0 .../retromusic/extensions/extensions.kt | 42 +++++ .../monkey/retromusic/service/CastPlayer.kt | 0 .../name/monkey/retromusic/util/AppRater.kt | 1 - 42 files changed, 243 insertions(+), 360 deletions(-) create mode 100644 app/src/fdroid/java/code/name/monkey/retromusic/activities/base/AbsCastActivity.kt create mode 100644 app/src/fdroid/java/code/name/monkey/retromusic/billing/BillingManager.kt create mode 100644 app/src/fdroid/java/code/name/monkey/retromusic/cast/RetroWebServer.kt create mode 100644 app/src/fdroid/java/code/name/monkey/retromusic/extensions/extensions.kt create mode 100644 app/src/fdroid/java/code/name/monkey/retromusic/service/CastPlayer.kt create mode 100644 app/src/fdroid/java/code/name/monkey/retromusic/util/AppRater.kt delete mode 100644 app/src/main/java/code/name/monkey/retromusic/util/PremiumShow.kt create mode 100644 app/src/normal/AndroidManifest.xml rename app/src/{main => normal}/java/code/name/monkey/retromusic/activities/PurchaseActivity.kt (82%) rename app/src/{main => normal}/java/code/name/monkey/retromusic/activities/base/AbsCastActivity.kt (93%) create mode 100644 app/src/normal/java/code/name/monkey/retromusic/billing/BillingManager.kt rename app/src/{main => normal}/java/code/name/monkey/retromusic/cast/CastHelper.kt (100%) rename app/src/{main => normal}/java/code/name/monkey/retromusic/cast/CastOptionsProvider.kt (100%) rename app/src/{main => normal}/java/code/name/monkey/retromusic/cast/RetroSessionManagerListener.kt (100%) rename app/src/{main => normal}/java/code/name/monkey/retromusic/cast/RetroWebServer.kt (100%) create mode 100644 app/src/normal/java/code/name/monkey/retromusic/extensions/extensions.kt rename app/src/{main => normal}/java/code/name/monkey/retromusic/service/CastPlayer.kt (100%) rename app/src/{main => normal}/java/code/name/monkey/retromusic/util/AppRater.kt (99%) diff --git a/app/build.gradle b/app/build.gradle index f92862ea9..04138bfcf 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,6 +41,15 @@ android { versionNameSuffix ' DEBUG' } } + flavorDimensions "version" + productFlavors { + normal { + dimension "version" + } + fdroid { + dimension "version" + } + } buildFeatures{ viewBinding true @@ -95,11 +104,11 @@ dependencies { implementation 'androidx.core:core-ktx:1.8.0' implementation 'androidx.palette:palette-ktx:1.0.0' - //Cast Dependencies implementation 'androidx.mediarouter:mediarouter:1.3.0' - implementation 'com.google.android.gms:play-services-cast-framework:21.0.1' + //Cast Dependencies + normalImplementation 'com.google.android.gms:play-services-cast-framework:21.0.1' //WebServer by NanoHttpd - implementation "org.nanohttpd:nanohttpd:2.3.1" + normalImplementation "org.nanohttpd:nanohttpd:2.3.1" implementation "androidx.navigation:navigation-runtime-ktx:$navigation_version" implementation "androidx.navigation:navigation-fragment-ktx:$navigation_version" @@ -117,8 +126,8 @@ dependencies { implementation "androidx.core:core-splashscreen:1.0.0-rc01" - implementation 'com.google.android.play:feature-delivery:2.0.0' - implementation 'com.google.android.play:review:2.0.0' + normalImplementation 'com.google.android.play:feature-delivery:2.0.0' + normalImplementation 'com.google.android.play:review:2.0.0' implementation "com.google.android.material:material:$mdc_version" @@ -160,7 +169,7 @@ dependencies { implementation 'org.eclipse.mylyn.github:org.eclipse.egit.github.core:2.1.5' implementation 'com.github.Adonai:jaudiotagger:2.3.15' - implementation 'com.anjlab.android.iab.v3:library:2.0.3' + normalImplementation 'com.anjlab.android.iab.v3:library:2.0.3' implementation 'com.r0adkll:slidableactivity:2.1.0' implementation 'com.heinrichreimersoftware:material-intro:2.0.0' implementation 'com.github.dhaval2404:imagepicker:2.1' diff --git a/app/src/fdroid/java/code/name/monkey/retromusic/activities/base/AbsCastActivity.kt b/app/src/fdroid/java/code/name/monkey/retromusic/activities/base/AbsCastActivity.kt new file mode 100644 index 000000000..def9a7050 --- /dev/null +++ b/app/src/fdroid/java/code/name/monkey/retromusic/activities/base/AbsCastActivity.kt @@ -0,0 +1,5 @@ +package code.name.monkey.retromusic.activities.base + + +abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() { +} \ No newline at end of file diff --git a/app/src/fdroid/java/code/name/monkey/retromusic/billing/BillingManager.kt b/app/src/fdroid/java/code/name/monkey/retromusic/billing/BillingManager.kt new file mode 100644 index 000000000..fa2402ef0 --- /dev/null +++ b/app/src/fdroid/java/code/name/monkey/retromusic/billing/BillingManager.kt @@ -0,0 +1,9 @@ +package code.name.monkey.retromusic.billing + +class BillingManager { + + fun release() {} + + val isProVersion: Boolean + get() = true +} \ No newline at end of file diff --git a/app/src/fdroid/java/code/name/monkey/retromusic/cast/RetroWebServer.kt b/app/src/fdroid/java/code/name/monkey/retromusic/cast/RetroWebServer.kt new file mode 100644 index 000000000..03103dfb7 --- /dev/null +++ b/app/src/fdroid/java/code/name/monkey/retromusic/cast/RetroWebServer.kt @@ -0,0 +1,6 @@ +package code.name.monkey.retromusic.cast + +import android.content.Context + +@Suppress("UNUSED_PARAMETER") +class RetroWebServer(context: Context) \ No newline at end of file diff --git a/app/src/fdroid/java/code/name/monkey/retromusic/extensions/extensions.kt b/app/src/fdroid/java/code/name/monkey/retromusic/extensions/extensions.kt new file mode 100644 index 000000000..3d93f388c --- /dev/null +++ b/app/src/fdroid/java/code/name/monkey/retromusic/extensions/extensions.kt @@ -0,0 +1,15 @@ +@file:Suppress("UNUSED_PARAMETER", "unused") + +package code.name.monkey.retromusic.extensions + +import android.content.Context +import android.view.Menu +import androidx.fragment.app.FragmentActivity + +fun Context.setUpMediaRouteButton(menu: Menu) {} + +fun FragmentActivity.installLanguageAndRecreate(code: String) {} + +fun Context.goToProVersion() {} + +fun Context.installSplitCompat() {} \ No newline at end of file diff --git a/app/src/fdroid/java/code/name/monkey/retromusic/service/CastPlayer.kt b/app/src/fdroid/java/code/name/monkey/retromusic/service/CastPlayer.kt new file mode 100644 index 000000000..3a0eaca28 --- /dev/null +++ b/app/src/fdroid/java/code/name/monkey/retromusic/service/CastPlayer.kt @@ -0,0 +1,47 @@ +package code.name.monkey.retromusic.service + +import code.name.monkey.retromusic.model.Song +import code.name.monkey.retromusic.service.playback.Playback + +// Empty CastPlayer implementation +class CastPlayer : Playback { + override val isInitialized: Boolean + get() = true + override val isPlaying: Boolean + get() = true + override val audioSessionId: Int + get() = 0 + + override fun setDataSource( + song: Song, + force: Boolean, + completion: (success: Boolean) -> Unit, + ) { + } + + override fun setNextDataSource(path: String?) {} + + override var callbacks: Playback.PlaybackCallbacks? = null + + override fun start() = true + + override fun stop() {} + + override fun release() {} + + override fun pause(): Boolean = true + + override fun duration() = 0 + + override fun position() = 0 + + override fun seek(whereto: Int) = whereto + + override fun setVolume(vol: Float) = true + + override fun setAudioSessionId(sessionId: Int) = true + + override fun setCrossFadeDuration(duration: Int) {} + + override fun setPlaybackSpeedPitch(speed: Float, pitch: Float) {} +} \ No newline at end of file diff --git a/app/src/fdroid/java/code/name/monkey/retromusic/util/AppRater.kt b/app/src/fdroid/java/code/name/monkey/retromusic/util/AppRater.kt new file mode 100644 index 000000000..2691d70b2 --- /dev/null +++ b/app/src/fdroid/java/code/name/monkey/retromusic/util/AppRater.kt @@ -0,0 +1,8 @@ +package code.name.monkey.retromusic.util + +import android.content.Context + +@Suppress("UNUSED_PARAMETER") +object AppRater { + fun appLaunched(context: Context) {} +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index efbc081f6..b8eb2170a 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -120,7 +120,6 @@ - diff --git a/app/src/main/java/code/name/monkey/retromusic/App.kt b/app/src/main/java/code/name/monkey/retromusic/App.kt index f92442df4..b60870b52 100644 --- a/app/src/main/java/code/name/monkey/retromusic/App.kt +++ b/app/src/main/java/code/name/monkey/retromusic/App.kt @@ -19,20 +19,17 @@ import androidx.preference.PreferenceManager import cat.ereza.customactivityoncrash.config.CaocConfig import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.util.VersionUtils -import code.name.monkey.retromusic.Constants.PRO_VERSION_PRODUCT_ID import code.name.monkey.retromusic.activities.ErrorActivity import code.name.monkey.retromusic.activities.MainActivity import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager -import code.name.monkey.retromusic.extensions.showToast +import code.name.monkey.retromusic.billing.BillingManager import code.name.monkey.retromusic.helper.WallpaperAccentManager -import com.anjlab.android.iab.v3.BillingProcessor -import com.anjlab.android.iab.v3.PurchaseInfo import org.koin.android.ext.koin.androidContext import org.koin.core.context.startKoin class App : Application() { - lateinit var billingProcessor: BillingProcessor + lateinit var billingManager: BillingManager private val wallpaperAccentManager = WallpaperAccentManager(this) override fun onCreate() { @@ -55,33 +52,18 @@ class App : Application() { if (VersionUtils.hasNougatMR()) DynamicShortcutManager(this).initDynamicShortcuts() - // automatically restores purchases - billingProcessor = BillingProcessor( - this, BuildConfig.GOOGLE_PLAY_LICENSING_KEY, - object : BillingProcessor.IBillingHandler { - override fun onProductPurchased(productId: String, details: PurchaseInfo?) {} - - override fun onPurchaseHistoryRestored() { - showToast(R.string.restored_previous_purchase_please_restart) - } - - override fun onBillingError(errorCode: Int, error: Throwable?) {} - - override fun onBillingInitialized() {} - }) - // setting Error activity CaocConfig.Builder.create().errorActivity(ErrorActivity::class.java) .restartActivity(MainActivity::class.java).apply() // Set Default values for now playing preferences - // This will reduce start time for now playing settings fragment as Preference listener of AbsSlidingMusicPanelActivity won't be called + // This will reduce startup time for now playing settings fragment as Preference listener of AbsSlidingMusicPanelActivity won't be called PreferenceManager.setDefaultValues(this, R.xml.pref_now_playing_screen, false) } override fun onTerminate() { super.onTerminate() - billingProcessor.release() + billingManager.release() wallpaperAccentManager.release() } @@ -93,9 +75,7 @@ class App : Application() { } fun isProVersion(): Boolean { - return BuildConfig.DEBUG || instance?.billingProcessor!!.isPurchased( - PRO_VERSION_PRODUCT_ID - ) + return BuildConfig.DEBUG || instance?.billingManager!!.isProVersion } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/SupportDevelopmentActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/SupportDevelopmentActivity.kt index 377cbec93..e0d67a21f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/SupportDevelopmentActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/SupportDevelopmentActivity.kt @@ -14,41 +14,23 @@ */ package code.name.monkey.retromusic.activities -import android.graphics.Paint import android.os.Bundle -import android.util.Log -import android.view.LayoutInflater import android.view.MenuItem -import android.view.ViewGroup -import android.widget.TextView -import androidx.core.view.isVisible -import androidx.recyclerview.widget.DefaultItemAnimator -import androidx.recyclerview.widget.GridLayoutManager -import androidx.recyclerview.widget.RecyclerView -import code.name.monkey.appthemehelper.util.ATHUtil -import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper -import code.name.monkey.retromusic.BuildConfig -import code.name.monkey.retromusic.R import code.name.monkey.retromusic.activities.base.AbsThemeActivity import code.name.monkey.retromusic.databinding.ActivityDonationBinding -import code.name.monkey.retromusic.databinding.ItemDonationOptionBinding -import code.name.monkey.retromusic.extensions.* -import com.anjlab.android.iab.v3.BillingProcessor -import com.anjlab.android.iab.v3.PurchaseInfo -import com.anjlab.android.iab.v3.SkuDetails +import code.name.monkey.retromusic.extensions.setStatusBarColorAuto +import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto +import code.name.monkey.retromusic.extensions.surfaceColor -class SupportDevelopmentActivity : AbsThemeActivity(), BillingProcessor.IBillingHandler { +class SupportDevelopmentActivity : AbsThemeActivity() { lateinit var binding: ActivityDonationBinding companion object { val TAG: String = SupportDevelopmentActivity::class.java.simpleName - const val DONATION_PRODUCT_IDS = R.array.donation_ids } - var billingProcessor: BillingProcessor? = null - override fun onOptionsItemSelected(item: MenuItem): Boolean { if (item.itemId == android.R.id.home) { onBackPressed() @@ -57,11 +39,6 @@ class SupportDevelopmentActivity : AbsThemeActivity(), BillingProcessor.IBilling return super.onOptionsItemSelected(item) } - fun donate(i: Int) { - val ids = resources.getStringArray(DONATION_PRODUCT_IDS) - billingProcessor?.purchase(this, ids[i]) - } - override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) binding = ActivityDonationBinding.inflate(layoutInflater) @@ -72,148 +49,11 @@ class SupportDevelopmentActivity : AbsThemeActivity(), BillingProcessor.IBilling setupToolbar() - billingProcessor = BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSING_KEY, this) - TintHelper.setTint(binding.progress, accentColor()) - binding.donation.setTextColor(accentColor()) } private fun setupToolbar() { - val toolbarColor = surfaceColor() - binding.toolbar.setBackgroundColor(toolbarColor) + binding.toolbar.setBackgroundColor(surfaceColor()) ToolbarContentTintHelper.colorBackButton(binding.toolbar) setSupportActionBar(binding.toolbar) } - - override fun onBillingInitialized() { - loadSkuDetails() - } - - private fun loadSkuDetails() { - binding.progressContainer.isVisible = true - binding.recyclerView.isVisible = false - val ids = resources.getStringArray(DONATION_PRODUCT_IDS) - billingProcessor!!.getPurchaseListingDetailsAsync( - ArrayList(listOf(*ids)), - object : BillingProcessor.ISkuDetailsResponseListener { - override fun onSkuDetailsResponse(skuDetails: MutableList?) { - if (skuDetails == null || skuDetails.isEmpty()) { - binding.progressContainer.isVisible = false - return - } - - binding.progressContainer.isVisible = false - binding.recyclerView.apply { - itemAnimator = DefaultItemAnimator() - layoutManager = GridLayoutManager(this@SupportDevelopmentActivity, 2) - adapter = SkuDetailsAdapter(this@SupportDevelopmentActivity, skuDetails) - isVisible = true - } - } - - override fun onSkuDetailsError(error: String?) { - Log.e(TAG, error.toString()) - } - }) - } - - override fun onProductPurchased(productId: String, details: PurchaseInfo?) { - // loadSkuDetails(); - showToast(R.string.thank_you) - } - - override fun onBillingError(errorCode: Int, error: Throwable?) { - Log.e(TAG, "Billing error: code = $errorCode", error) - } - - override fun onPurchaseHistoryRestored() { - // loadSkuDetails(); - showToast(R.string.restored_previous_purchases) - } - - override fun onDestroy() { - billingProcessor?.release() - super.onDestroy() - } -} - -class SkuDetailsAdapter( - private var donationsDialog: SupportDevelopmentActivity, - objects: List, -) : RecyclerView.Adapter() { - - private var skuDetailsList: List = ArrayList() - - init { - skuDetailsList = objects - } - - private fun getIcon(position: Int): Int { - return when (position) { - 0 -> R.drawable.ic_cookie - 1 -> R.drawable.ic_take_away - 2 -> R.drawable.ic_take_away_coffe - 3 -> R.drawable.ic_beer - 4 -> R.drawable.ic_fast_food_meal - 5 -> R.drawable.ic_popcorn - 6 -> R.drawable.ic_card_giftcard - 7 -> R.drawable.ic_food_croissant - else -> R.drawable.ic_card_giftcard - } - } - - override fun onCreateViewHolder(viewGroup: ViewGroup, i: Int): ViewHolder { - return ViewHolder( - ItemDonationOptionBinding.inflate( - LayoutInflater.from(donationsDialog), - viewGroup, - false - ) - ) - } - - override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) { - val skuDetails = skuDetailsList[i] - with(viewHolder.binding) { - itemTitle.text = skuDetails.title.replace("(Retro Music Player MP3 Player)", "") - .trim { it <= ' ' } - itemText.text = skuDetails.description - itemText.isVisible = false - itemPrice.text = skuDetails.priceText - itemImage.setImageResource(getIcon(i)) - } - - val purchased = donationsDialog.billingProcessor!!.isPurchased(skuDetails.productId) - val titleTextColor = if (purchased) ATHUtil.resolveColor( - donationsDialog, - android.R.attr.textColorHint - ) else donationsDialog.textColorPrimary() - val contentTextColor = - if (purchased) titleTextColor else donationsDialog.textColorSecondary() - - with(viewHolder.binding) { - itemTitle.setTextColor(titleTextColor) - itemText.setTextColor(contentTextColor) - itemPrice.setTextColor(titleTextColor) - strikeThrough(itemTitle, purchased) - strikeThrough(itemText, purchased) - strikeThrough(itemPrice, purchased) - } - - viewHolder.itemView.isEnabled = !purchased - viewHolder.itemView.setOnClickListener { donationsDialog.donate(i) } - } - - override fun getItemCount(): Int { - return skuDetailsList.size - } - - class ViewHolder(val binding: ItemDonationOptionBinding) : RecyclerView.ViewHolder(binding.root) - - companion object { - private fun strikeThrough(textView: TextView, strikeThrough: Boolean) { - textView.paintFlags = - if (strikeThrough) textView.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG - else textView.paintFlags and Paint.STRIKE_THRU_TEXT_FLAG.inv() - } - } } diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsThemeActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsThemeActivity.kt index 772a8cc38..ca112a6d4 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsThemeActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsThemeActivity.kt @@ -31,7 +31,6 @@ import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.maybeShowAnnoyingToasts import code.name.monkey.retromusic.util.theme.getNightMode import code.name.monkey.retromusic.util.theme.getThemeResValue -import com.google.android.play.core.splitcompat.SplitCompat import java.util.* abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable { @@ -105,6 +104,6 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable { Locale.forLanguageTag(code) } super.attachBaseContext(LanguageContextWrapper.wrap(newBase, locale)) - SplitCompat.install(this) + installSplitCompat() } } diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/SleepTimerDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/SleepTimerDialog.kt index 6a44e4638..32de5ba6c 100755 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/SleepTimerDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/SleepTimerDialog.kt @@ -95,7 +95,7 @@ class SleepTimerDialog : DialogFragment() { shouldFinishLastSong.isVisible = false timerUpdater.start() setPositiveButton(android.R.string.ok, null) - setNegativeButton(R.string.cast_stop) { _, _ -> + setNegativeButton(R.string.action_cancel) { _, _ -> timerUpdater.cancel() val previous = makeTimerPendingIntent(PendingIntent.FLAG_NO_CREATE) if (previous != null) { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt index 55a8bb88d..ed00699a5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt @@ -24,6 +24,7 @@ import androidx.recyclerview.widget.GridLayoutManager import code.name.monkey.retromusic.EXTRA_ALBUM_ID import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.album.AlbumAdapter +import code.name.monkey.retromusic.extensions.setUpMediaRouteButton import code.name.monkey.retromusic.extensions.surfaceColor import code.name.monkey.retromusic.fragments.GridStyle import code.name.monkey.retromusic.fragments.ReloadType @@ -41,7 +42,6 @@ import com.afollestad.materialcab.attached.AttachedCab import com.afollestad.materialcab.attached.destroy import com.afollestad.materialcab.attached.isActive import com.afollestad.materialcab.createCab -import com.google.android.gms.cast.framework.CastButtonFactory class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment(), IAlbumClickListener, ICabHolder { @@ -169,7 +169,7 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment(), IArtistClickListener, IAlbumArtistClickListener, ICabHolder { @@ -180,7 +180,7 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment(), menu.removeItem(R.id.action_sort_order) menu.findItem(R.id.action_settings).setShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM) //Setting up cast button - CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast) + requireContext().setUpMediaRouteButton(menu) } override fun onResume() { 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 6d42e2801..4a915690e 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 @@ -35,10 +35,7 @@ import code.name.monkey.retromusic.adapter.HomeAdapter import code.name.monkey.retromusic.databinding.FragmentHomeBinding import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog import code.name.monkey.retromusic.dialogs.ImportPlaylistDialog -import code.name.monkey.retromusic.extensions.accentColor -import code.name.monkey.retromusic.extensions.dip -import code.name.monkey.retromusic.extensions.drawNextToNavbar -import code.name.monkey.retromusic.extensions.elevatedAccentColor +import code.name.monkey.retromusic.extensions.* import code.name.monkey.retromusic.fragments.ReloadType import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import code.name.monkey.retromusic.glide.GlideApp @@ -48,7 +45,6 @@ import code.name.monkey.retromusic.interfaces.IScrollHelper import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil.userName -import com.google.android.gms.cast.framework.CastButtonFactory import com.google.android.material.shape.MaterialShapeDrawable import com.google.android.material.transition.MaterialFadeThrough import com.google.android.material.transition.MaterialSharedAxis @@ -212,7 +208,7 @@ class HomeFragment : ATHToolbarActivity.getToolbarBackgroundColor(binding.toolbar) ) //Setting up cast button - CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast) + requireContext().setUpMediaRouteButton(menu) } override fun scrollToTop() { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt index eb66ca5b6..c5b02c973 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt @@ -30,11 +30,11 @@ import code.name.monkey.retromusic.R import code.name.monkey.retromusic.databinding.FragmentLibraryBinding import code.name.monkey.retromusic.dialogs.CreatePlaylistDialog import code.name.monkey.retromusic.dialogs.ImportPlaylistDialog +import code.name.monkey.retromusic.extensions.setUpMediaRouteButton import code.name.monkey.retromusic.extensions.whichFragment import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import code.name.monkey.retromusic.model.CategoryInfo import code.name.monkey.retromusic.util.PreferenceUtil -import com.google.android.gms.cast.framework.CastButtonFactory class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { @@ -99,7 +99,7 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) { getToolbarBackgroundColor(binding.toolbar) ) //Setting up cast button - CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast) + requireContext().setUpMediaRouteButton(menu) } override fun onMenuItemSelected(item: MenuItem): Boolean { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt index 2c212d039..bf74cee56 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt @@ -24,13 +24,13 @@ import code.name.monkey.retromusic.EXTRA_PLAYLIST import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.playlist.PlaylistAdapter import code.name.monkey.retromusic.db.PlaylistWithSongs +import code.name.monkey.retromusic.extensions.setUpMediaRouteButton import code.name.monkey.retromusic.fragments.ReloadType import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment import code.name.monkey.retromusic.helper.SortOrder.PlaylistSortOrder import code.name.monkey.retromusic.interfaces.IPlaylistClickListener import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.RetroUtil -import com.google.android.gms.cast.framework.CastButtonFactory import com.google.android.material.transition.MaterialSharedAxis class PlaylistsFragment : @@ -85,7 +85,7 @@ class PlaylistsFragment : setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu) MenuCompat.setGroupDividerEnabled(menu, true) //Setting up cast button - CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast) + requireContext().setUpMediaRouteButton(menu) } override fun onMenuItemSelected(item: MenuItem): Boolean { 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 af3e4a74b..b3688f609 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 @@ -26,6 +26,7 @@ import androidx.preference.PreferenceManager import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceFragmentCompat import code.name.monkey.retromusic.R import code.name.monkey.retromusic.extensions.dip +import code.name.monkey.retromusic.extensions.goToProVersion import code.name.monkey.retromusic.extensions.showToast import code.name.monkey.retromusic.preferences.* import code.name.monkey.retromusic.util.NavigationUtil @@ -39,7 +40,7 @@ abstract class AbsSettingsFragment : ATEPreferenceFragmentCompat() { internal fun showProToastAndNavigate(message: String) { showToast(getString(R.string.message_pro_feature, message)) - NavigationUtil.goToProVersion(requireActivity()) + requireContext().goToProVersion() } internal fun setSummary(preference: Preference, value: Any?) { 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 aff3f4779..fa58c0bd2 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 @@ -27,6 +27,7 @@ import code.name.monkey.retromusic.App import code.name.monkey.retromusic.R import code.name.monkey.retromusic.databinding.FragmentMainSettingsBinding import code.name.monkey.retromusic.extensions.drawAboveSystemBarsWithPadding +import code.name.monkey.retromusic.extensions.goToProVersion import code.name.monkey.retromusic.util.NavigationUtil class MainSettingsFragment : Fragment(), View.OnClickListener { @@ -77,11 +78,11 @@ class MainSettingsFragment : Fragment(), View.OnClickListener { binding.buyProContainer.apply { isGone = App.isProVersion() setOnClickListener { - NavigationUtil.goToProVersion(requireContext()) + requireContext().goToProVersion() } } binding.buyPremium.setOnClickListener { - NavigationUtil.goToProVersion(requireContext()) + requireContext().goToProVersion() } ThemeStore.accentColor(requireContext()).let { binding.buyPremium.setTextColor(it) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/OtherSettingsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/OtherSettingsFragment.kt index 9164b3156..554bc674a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/OtherSettingsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/OtherSettingsFragment.kt @@ -21,12 +21,10 @@ import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEListPreference import code.name.monkey.retromusic.LANGUAGE_NAME import code.name.monkey.retromusic.LAST_ADDED_CUTOFF import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.extensions.installLanguageAndRecreate import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.ReloadType.HomeSections -import com.google.android.play.core.splitinstall.SplitInstallManagerFactory -import com.google.android.play.core.splitinstall.SplitInstallRequest import org.koin.androidx.viewmodel.ext.android.sharedViewModel -import java.util.* /** * @author Hemanth S (h4h13). @@ -58,21 +56,7 @@ class OtherSettingsFragment : AbsSettingsFragment() { val languagePreference: Preference? = findPreference(LANGUAGE_NAME) languagePreference?.setOnPreferenceChangeListener { prefs, newValue -> setSummary(prefs, newValue) - val code = newValue.toString() - val manager = SplitInstallManagerFactory.create(requireContext()) - if (code != "auto") { - // Try to download language resources - val request = - SplitInstallRequest.newBuilder().addLanguage(Locale.forLanguageTag(code)) - .build() - manager.startInstall(request) - // Recreate the activity on download complete - .addOnCompleteListener { - restartActivity() - } - } else { - requireActivity().recreate() - } + requireActivity().installLanguageAndRecreate(newValue.toString()) true } } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt index a728e2828..e47efaa1d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt @@ -21,6 +21,7 @@ import androidx.annotation.LayoutRes import androidx.recyclerview.widget.GridLayoutManager import code.name.monkey.retromusic.R import code.name.monkey.retromusic.adapter.song.SongAdapter +import code.name.monkey.retromusic.extensions.setUpMediaRouteButton import code.name.monkey.retromusic.extensions.surfaceColor import code.name.monkey.retromusic.fragments.GridStyle import code.name.monkey.retromusic.fragments.ReloadType @@ -35,7 +36,6 @@ import com.afollestad.materialcab.attached.AttachedCab import com.afollestad.materialcab.attached.destroy import com.afollestad.materialcab.attached.isActive import com.afollestad.materialcab.createCab -import com.google.android.gms.cast.framework.CastButtonFactory class SongsFragment : AbsRecyclerViewCustomGridSizeFragment(), ICabHolder { @@ -136,7 +136,7 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment Unit, ) { playbackLocation = PlaybackLocation.REMOTE - switchToPlayback(CastPlayer(castSession), onChange) + switchToPlayback(castPlayer, onChange) } private fun switchToPlayback( diff --git a/app/src/main/java/code/name/monkey/retromusic/util/NavigationUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/NavigationUtil.kt index 2d960af00..bea599a00 100755 --- a/app/src/main/java/code/name/monkey/retromusic/util/NavigationUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/NavigationUtil.kt @@ -39,12 +39,6 @@ object NavigationUtil { ) } - fun goToProVersion(context: Context) { - context.startActivity( - Intent(context, PurchaseActivity::class.java), null - ) - } - fun goToSupportDevelopment(activity: Activity) { activity.startActivity( Intent(activity, SupportDevelopmentActivity::class.java), null diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PremiumShow.kt b/app/src/main/java/code/name/monkey/retromusic/util/PremiumShow.kt deleted file mode 100644 index adcf36971..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/util/PremiumShow.kt +++ /dev/null @@ -1,33 +0,0 @@ -package code.name.monkey.retromusic.util - -import android.content.Context -import android.content.Intent -import code.name.monkey.retromusic.App -import code.name.monkey.retromusic.activities.PurchaseActivity - -object PremiumShow { - private const val PREF_NAME = "premium_show" - private const val LAUNCH_COUNT = "launch_count" - private const val DATE_FIRST_LAUNCH = "date_first_launch" - - @JvmStatic - fun launch(context: Context) { - val pref = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE) - if (App.isProVersion()) { - return - } - val prefEditor = pref.edit() - val launchCount = pref.getLong(LAUNCH_COUNT, 0) + 1 - prefEditor.putLong(LAUNCH_COUNT, launchCount) - - var dateLaunched = pref.getLong(DATE_FIRST_LAUNCH, 0) - if (dateLaunched == 0L) { - dateLaunched = System.currentTimeMillis() - prefEditor.putLong(DATE_FIRST_LAUNCH, dateLaunched) - } - if (System.currentTimeMillis() >= dateLaunched + 2 * 24 * 60 * 60 * 1000) { - context.startActivity(Intent(context, PurchaseActivity::class.java), null) - } - prefEditor.apply() - } -} \ No newline at end of file diff --git a/app/src/main/res/layout/activity_donation.xml b/app/src/main/res/layout/activity_donation.xml index 9f2db5c0c..c69fa30cf 100644 --- a/app/src/main/res/layout/activity_donation.xml +++ b/app/src/main/res/layout/activity_donation.xml @@ -1,7 +1,6 @@ @@ -31,52 +30,5 @@ android:overScrollMode="@integer/overScrollMode" app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/normal/AndroidManifest.xml b/app/src/normal/AndroidManifest.xml new file mode 100644 index 000000000..855ade12b --- /dev/null +++ b/app/src/normal/AndroidManifest.xml @@ -0,0 +1,9 @@ + + + + + + + diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/PurchaseActivity.kt b/app/src/normal/java/code/name/monkey/retromusic/activities/PurchaseActivity.kt similarity index 82% rename from app/src/main/java/code/name/monkey/retromusic/activities/PurchaseActivity.kt rename to app/src/normal/java/code/name/monkey/retromusic/activities/PurchaseActivity.kt index accf2f880..b23e1d62d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/PurchaseActivity.kt +++ b/app/src/normal/java/code/name/monkey/retromusic/activities/PurchaseActivity.kt @@ -1,17 +1,3 @@ -/* - * Copyright (c) 2020 Hemanth Savarla. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - * - */ package code.name.monkey.retromusic.activities import android.content.res.ColorStateList @@ -22,7 +8,7 @@ import android.view.MenuItem import code.name.monkey.appthemehelper.util.MaterialUtil import code.name.monkey.retromusic.App import code.name.monkey.retromusic.BuildConfig -import code.name.monkey.retromusic.Constants.PRO_VERSION_PRODUCT_ID +import code.name.monkey.retromusic.Constants import code.name.monkey.retromusic.R import code.name.monkey.retromusic.activities.base.AbsThemeActivity import code.name.monkey.retromusic.databinding.ActivityProVersionBinding @@ -58,7 +44,7 @@ class PurchaseActivity : AbsThemeActivity(), BillingProcessor.IBillingHandler { restorePurchase() } binding.purchaseButton.setOnClickListener { - billingProcessor.purchase(this@PurchaseActivity, PRO_VERSION_PRODUCT_ID) + billingProcessor.purchase(this@PurchaseActivity, Constants.PRO_VERSION_PRODUCT_ID) } binding.bannerContainer.backgroundTintList = ColorStateList.valueOf(accentColor()) @@ -116,4 +102,4 @@ class PurchaseActivity : AbsThemeActivity(), BillingProcessor.IBillingHandler { companion object { private const val TAG: String = "PurchaseActivity" } -} +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsCastActivity.kt b/app/src/normal/java/code/name/monkey/retromusic/activities/base/AbsCastActivity.kt similarity index 93% rename from app/src/main/java/code/name/monkey/retromusic/activities/base/AbsCastActivity.kt rename to app/src/normal/java/code/name/monkey/retromusic/activities/base/AbsCastActivity.kt index 23d668a53..4a2f3aaea 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsCastActivity.kt +++ b/app/src/normal/java/code/name/monkey/retromusic/activities/base/AbsCastActivity.kt @@ -3,6 +3,7 @@ package code.name.monkey.retromusic.activities.base import code.name.monkey.retromusic.cast.RetroSessionManagerListener import code.name.monkey.retromusic.cast.RetroWebServer import code.name.monkey.retromusic.helper.MusicPlayerRemote +import code.name.monkey.retromusic.service.CastPlayer import com.google.android.gms.cast.framework.CastContext import com.google.android.gms.cast.framework.CastSession import com.google.android.gms.common.ConnectionResult @@ -37,7 +38,7 @@ abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() { override fun onSessionStarted(castSession: CastSession, p1: String) { invalidateOptionsMenu() mCastSession = castSession - MusicPlayerRemote.switchToRemotePlayback(castSession) + MusicPlayerRemote.switchToRemotePlayback(CastPlayer(castSession)) } override fun onSessionEnded(castSession: CastSession, p1: Int) { @@ -53,7 +54,7 @@ abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() { invalidateOptionsMenu() mCastSession = castSession webServer.start() - MusicPlayerRemote.switchToRemotePlayback(castSession) + MusicPlayerRemote.switchToRemotePlayback(CastPlayer(castSession)) } override fun onSessionSuspended(castSession: CastSession, p1: Int) { diff --git a/app/src/normal/java/code/name/monkey/retromusic/billing/BillingManager.kt b/app/src/normal/java/code/name/monkey/retromusic/billing/BillingManager.kt new file mode 100644 index 000000000..445044e73 --- /dev/null +++ b/app/src/normal/java/code/name/monkey/retromusic/billing/BillingManager.kt @@ -0,0 +1,37 @@ +package code.name.monkey.retromusic.billing + +import android.content.Context +import code.name.monkey.retromusic.BuildConfig +import code.name.monkey.retromusic.Constants +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.extensions.showToast +import com.anjlab.android.iab.v3.BillingProcessor +import com.anjlab.android.iab.v3.PurchaseInfo + +class BillingManager(context: Context) { + private val billingProcessor: BillingProcessor + + init { + // automatically restores purchases + billingProcessor = BillingProcessor( + context, BuildConfig.GOOGLE_PLAY_LICENSING_KEY, + object : BillingProcessor.IBillingHandler { + override fun onProductPurchased(productId: String, details: PurchaseInfo?) {} + + override fun onPurchaseHistoryRestored() { + context.showToast(R.string.restored_previous_purchase_please_restart) + } + + override fun onBillingError(errorCode: Int, error: Throwable?) {} + + override fun onBillingInitialized() {} + }) + } + + fun release() { + billingProcessor.release() + } + + val isProVersion: Boolean + get() = billingProcessor.isPurchased(Constants.PRO_VERSION_PRODUCT_ID) +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/cast/CastHelper.kt b/app/src/normal/java/code/name/monkey/retromusic/cast/CastHelper.kt similarity index 100% rename from app/src/main/java/code/name/monkey/retromusic/cast/CastHelper.kt rename to app/src/normal/java/code/name/monkey/retromusic/cast/CastHelper.kt diff --git a/app/src/main/java/code/name/monkey/retromusic/cast/CastOptionsProvider.kt b/app/src/normal/java/code/name/monkey/retromusic/cast/CastOptionsProvider.kt similarity index 100% rename from app/src/main/java/code/name/monkey/retromusic/cast/CastOptionsProvider.kt rename to app/src/normal/java/code/name/monkey/retromusic/cast/CastOptionsProvider.kt diff --git a/app/src/main/java/code/name/monkey/retromusic/cast/RetroSessionManagerListener.kt b/app/src/normal/java/code/name/monkey/retromusic/cast/RetroSessionManagerListener.kt similarity index 100% rename from app/src/main/java/code/name/monkey/retromusic/cast/RetroSessionManagerListener.kt rename to app/src/normal/java/code/name/monkey/retromusic/cast/RetroSessionManagerListener.kt diff --git a/app/src/main/java/code/name/monkey/retromusic/cast/RetroWebServer.kt b/app/src/normal/java/code/name/monkey/retromusic/cast/RetroWebServer.kt similarity index 100% rename from app/src/main/java/code/name/monkey/retromusic/cast/RetroWebServer.kt rename to app/src/normal/java/code/name/monkey/retromusic/cast/RetroWebServer.kt diff --git a/app/src/normal/java/code/name/monkey/retromusic/extensions/extensions.kt b/app/src/normal/java/code/name/monkey/retromusic/extensions/extensions.kt new file mode 100644 index 000000000..3ac58980f --- /dev/null +++ b/app/src/normal/java/code/name/monkey/retromusic/extensions/extensions.kt @@ -0,0 +1,42 @@ +package code.name.monkey.retromusic.extensions + +import android.content.Context +import android.content.Intent +import android.view.Menu +import androidx.fragment.app.FragmentActivity +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.activities.PurchaseActivity +import com.google.android.gms.cast.framework.CastButtonFactory +import com.google.android.play.core.splitcompat.SplitCompat +import com.google.android.play.core.splitinstall.SplitInstallManagerFactory +import com.google.android.play.core.splitinstall.SplitInstallRequest +import java.util.* + +fun Context.setUpMediaRouteButton(menu: Menu) { + CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.action_cast) +} + +fun FragmentActivity.installLanguageAndRecreate(code: String) { + val manager = SplitInstallManagerFactory.create(this) + if (code != "auto") { + // Try to download language resources + val request = + SplitInstallRequest.newBuilder().addLanguage(Locale.forLanguageTag(code)) + .build() + manager.startInstall(request) + // Recreate the activity on download complete + .addOnCompleteListener { + recreate() + } + } else { + recreate() + } +} + +fun Context.goToProVersion() { + startActivity(Intent(this, PurchaseActivity::class.java)) +} + +fun Context.installSplitCompat() { + SplitCompat.install(this) +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/service/CastPlayer.kt b/app/src/normal/java/code/name/monkey/retromusic/service/CastPlayer.kt similarity index 100% rename from app/src/main/java/code/name/monkey/retromusic/service/CastPlayer.kt rename to app/src/normal/java/code/name/monkey/retromusic/service/CastPlayer.kt diff --git a/app/src/main/java/code/name/monkey/retromusic/util/AppRater.kt b/app/src/normal/java/code/name/monkey/retromusic/util/AppRater.kt similarity index 99% rename from app/src/main/java/code/name/monkey/retromusic/util/AppRater.kt rename to app/src/normal/java/code/name/monkey/retromusic/util/AppRater.kt index d6d47270e..1e3423478 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/AppRater.kt +++ b/app/src/normal/java/code/name/monkey/retromusic/util/AppRater.kt @@ -28,7 +28,6 @@ object AppRater { private const val DAYS_UNTIL_PROMPT = 3//Min number of days private const val LAUNCHES_UNTIL_PROMPT = 5//Min number of launches - @JvmStatic fun appLaunched(context: Activity) { val prefs = context.getSharedPreferences(APP_RATING, 0) if (prefs.getBoolean(DO_NOT_SHOW_AGAIN, false)) { From a1e4916ae342b29f299ef322b5ac5219a2c23721 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Wed, 15 Jun 2022 14:09:37 +0530 Subject: [PATCH 02/19] Moved ChromeCast entries of normal flavor manifest --- app/src/main/AndroidManifest.xml | 10 ---------- app/src/normal/AndroidManifest.xml | 13 ++++++++++++- 2 files changed, 12 insertions(+), 11 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index b8eb2170a..987f89181 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -22,7 +22,6 @@ android:name="android.permission.WRITE_SETTINGS" tools:ignore="ProtectedPermissions" /> - - - - - - + From 0c8ed326bfa8787e2757e825937f88167aeeaca8 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Wed, 15 Jun 2022 15:29:58 +0530 Subject: [PATCH 03/19] [ChromeCast] Use default notification when casting --- .../fragments/other/LyricsFragment.kt | 3 +-- .../retromusic/cast/CastOptionsProvider.kt | 24 +++---------------- 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt index e2eaf6c9b..e27e31c06 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt @@ -35,7 +35,6 @@ import code.name.monkey.appthemehelper.common.ATHToolbarActivity import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.activities.MainActivity import code.name.monkey.retromusic.activities.tageditor.TagWriter import code.name.monkey.retromusic.databinding.FragmentLyricsBinding import code.name.monkey.retromusic.databinding.FragmentNormalLyricsBinding @@ -422,7 +421,7 @@ class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) { override fun onDestroyView() { super.onDestroyView() if (MusicPlayerRemote.playingQueue.isNotEmpty()) - (requireActivity() as MainActivity).expandPanel() + mainActivity.expandPanel() _binding = null } } diff --git a/app/src/normal/java/code/name/monkey/retromusic/cast/CastOptionsProvider.kt b/app/src/normal/java/code/name/monkey/retromusic/cast/CastOptionsProvider.kt index 35115dafb..6ebc71010 100644 --- a/app/src/normal/java/code/name/monkey/retromusic/cast/CastOptionsProvider.kt +++ b/app/src/normal/java/code/name/monkey/retromusic/cast/CastOptionsProvider.kt @@ -3,36 +3,18 @@ package code.name.monkey.retromusic.cast import android.content.Context -import code.name.monkey.retromusic.activities.MainActivity -import com.google.android.gms.cast.CastMediaControlIntent +import com.google.android.gms.cast.CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID import com.google.android.gms.cast.framework.CastOptions import com.google.android.gms.cast.framework.OptionsProvider import com.google.android.gms.cast.framework.SessionProvider import com.google.android.gms.cast.framework.media.CastMediaOptions -import com.google.android.gms.cast.framework.media.MediaIntentReceiver -import com.google.android.gms.cast.framework.media.NotificationOptions class CastOptionsProvider : OptionsProvider { override fun getCastOptions(context: Context): CastOptions { - val buttonActions: MutableList = ArrayList() - buttonActions.add(MediaIntentReceiver.ACTION_SKIP_PREV) - buttonActions.add(MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK) - buttonActions.add(MediaIntentReceiver.ACTION_SKIP_NEXT) - buttonActions.add(MediaIntentReceiver.ACTION_STOP_CASTING) - val compatButtonActionsIndices = intArrayOf(1, 3) - val notificationOptions = NotificationOptions.Builder() - .setActions(buttonActions, compatButtonActionsIndices) - .setTargetActivityClassName(MainActivity::class.java.name) - .build() - - val mediaOptions = CastMediaOptions.Builder() - .setNotificationOptions(notificationOptions) - .setExpandedControllerActivityClassName(MainActivity::class.java.name) - .build() - + val mediaOptions = CastMediaOptions.Builder().setNotificationOptions(null).build() return CastOptions.Builder() - .setReceiverApplicationId(CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID) + .setReceiverApplicationId(DEFAULT_MEDIA_RECEIVER_APPLICATION_ID) .setCastMediaOptions(mediaOptions) .build() } From 525c5f8aa48c7adcfa53ad470cd429362f3b297c Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Wed, 15 Jun 2022 11:42:48 +0530 Subject: [PATCH 04/19] Fixed Language download --- .../retromusic/extensions/extensions.kt | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/app/src/normal/java/code/name/monkey/retromusic/extensions/extensions.kt b/app/src/normal/java/code/name/monkey/retromusic/extensions/extensions.kt index 3ac58980f..59d05fb74 100644 --- a/app/src/normal/java/code/name/monkey/retromusic/extensions/extensions.kt +++ b/app/src/normal/java/code/name/monkey/retromusic/extensions/extensions.kt @@ -10,6 +10,8 @@ import com.google.android.gms.cast.framework.CastButtonFactory import com.google.android.play.core.splitcompat.SplitCompat import com.google.android.play.core.splitinstall.SplitInstallManagerFactory import com.google.android.play.core.splitinstall.SplitInstallRequest +import com.google.android.play.core.splitinstall.SplitInstallSessionState +import com.google.android.play.core.splitinstall.SplitInstallStateUpdatedListener import java.util.* fun Context.setUpMediaRouteButton(menu: Menu) { @@ -17,7 +19,19 @@ fun Context.setUpMediaRouteButton(menu: Menu) { } fun FragmentActivity.installLanguageAndRecreate(code: String) { + var mySessionId = 0 + val manager = SplitInstallManagerFactory.create(this) + val listener = object: SplitInstallStateUpdatedListener{ + override fun onStateUpdate(state: SplitInstallSessionState) { + if (state.sessionId() == mySessionId) { + recreate() + manager.unregisterListener(this) + } + } + } + manager.registerListener(listener) + if (code != "auto") { // Try to download language resources val request = @@ -25,8 +39,11 @@ fun FragmentActivity.installLanguageAndRecreate(code: String) { .build() manager.startInstall(request) // Recreate the activity on download complete - .addOnCompleteListener { - recreate() + .addOnSuccessListener { + mySessionId = it + } + .addOnFailureListener { + showToast("Language download failed.") } } else { recreate() From d2ce889962116ebbaa988bb8e468b8e8eda90f9e Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Wed, 15 Jun 2022 17:00:54 +0530 Subject: [PATCH 05/19] Initialize BillingManager --- app/src/main/java/code/name/monkey/retromusic/App.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/src/main/java/code/name/monkey/retromusic/App.kt b/app/src/main/java/code/name/monkey/retromusic/App.kt index b60870b52..705ce5ef7 100644 --- a/app/src/main/java/code/name/monkey/retromusic/App.kt +++ b/app/src/main/java/code/name/monkey/retromusic/App.kt @@ -52,6 +52,8 @@ class App : Application() { if (VersionUtils.hasNougatMR()) DynamicShortcutManager(this).initDynamicShortcuts() + billingManager = BillingManager(this) + // setting Error activity CaocConfig.Builder.create().errorActivity(ErrorActivity::class.java) .restartActivity(MainActivity::class.java).apply() From 17eb5bff05ddf591b9c25aaff73c590eb6d31b7d Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Thu, 16 Jun 2022 16:42:36 +0530 Subject: [PATCH 06/19] Update dependencies --- app/build.gradle | 3 +-- build.gradle | 3 ++- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 04138bfcf..75363dfcd 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -97,7 +97,7 @@ dependencies { implementation "androidx.gridlayout:gridlayout:1.0.0" implementation "androidx.appcompat:appcompat:$appcompat_version" - implementation 'androidx.annotation:annotation:1.3.0' + implementation 'androidx.annotation:annotation:1.4.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.recyclerview:recyclerview:1.2.1' implementation "androidx.preference:preference-ktx:$preference_version" @@ -119,7 +119,6 @@ dependencies { implementation "androidx.room:room-ktx:$room_version" kapt "androidx.room:room-compiler:$room_version" - def lifecycle_version = "2.5.0-rc01" implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version" implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version" diff --git a/build.gradle b/build.gradle index 431658a9a..539c8bf56 100644 --- a/build.gradle +++ b/build.gradle @@ -3,7 +3,8 @@ buildscript { ext { kotlin_version = '1.7.0' - navigation_version = '2.5.0-rc01' + lifecycle_version='2.5.0-rc02' + navigation_version = '2.5.0-rc02' mdc_version = '1.7.0-alpha02' preference_version = '1.2.0' appcompat_version = '1.4.2' From 2f818ce65fe3682516c3b0f8ccf0de27d2b43899 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Thu, 16 Jun 2022 16:43:10 +0530 Subject: [PATCH 07/19] Tint NavigationRailView --- .../retromusic/billing/BillingManager.kt | 5 +- .../retromusic/extensions/ViewExtensions.kt | 12 +++++ .../monkey/retromusic/util/PreferenceUtil.kt | 4 +- ...inted.kt => TintedBottomNavigationView.kt} | 16 ++---- .../views/TintedNavigationRailView.kt | 46 ++++++++++++++++ .../sliding_music_panel_layout.xml | 2 +- .../res/layout/sliding_music_panel_layout.xml | 2 +- .../appthemehelper/util/NavigationViewUtil.kt | 52 ------------------- 8 files changed, 69 insertions(+), 70 deletions(-) rename app/src/main/java/code/name/monkey/retromusic/views/{BottomNavigationBarTinted.kt => TintedBottomNavigationView.kt} (81%) create mode 100644 app/src/main/java/code/name/monkey/retromusic/views/TintedNavigationRailView.kt delete mode 100644 appthemehelper/src/main/java/code/name/monkey/appthemehelper/util/NavigationViewUtil.kt diff --git a/app/src/fdroid/java/code/name/monkey/retromusic/billing/BillingManager.kt b/app/src/fdroid/java/code/name/monkey/retromusic/billing/BillingManager.kt index fa2402ef0..51c350adc 100644 --- a/app/src/fdroid/java/code/name/monkey/retromusic/billing/BillingManager.kt +++ b/app/src/fdroid/java/code/name/monkey/retromusic/billing/BillingManager.kt @@ -1,6 +1,9 @@ package code.name.monkey.retromusic.billing -class BillingManager { +import android.content.Context + +@Suppress("UNUSED_PARAMETER") +class BillingManager(context: Context) { fun release() {} diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/ViewExtensions.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/ViewExtensions.kt index d9ce08d9c..02764b1a0 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/ViewExtensions.kt +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/ViewExtensions.kt @@ -14,9 +14,11 @@ */ package code.name.monkey.retromusic.extensions +import android.R import android.animation.Animator import android.animation.ObjectAnimator import android.animation.ValueAnimator +import android.content.res.ColorStateList import android.graphics.drawable.BitmapDrawable import android.view.LayoutInflater import android.view.View @@ -25,6 +27,7 @@ import android.view.ViewTreeObserver import android.view.animation.AnimationUtils import android.view.inputmethod.InputMethodManager import android.widget.EditText +import androidx.annotation.ColorInt import androidx.annotation.LayoutRes import androidx.annotation.Px import androidx.core.animation.doOnEnd @@ -67,6 +70,15 @@ fun EditText.appHandleColor(): EditText { return this } +fun NavigationBarView.setItemColors(@ColorInt normalColor: Int, @ColorInt selectedColor: Int) { + val csl = ColorStateList( + arrayOf(intArrayOf(-R.attr.state_checked), intArrayOf(R.attr.state_checked)), + intArrayOf(normalColor, selectedColor) + ) + itemIconTintList = csl + itemTextColor = csl +} + /** * Potentially animate showing a [BottomNavigationView]. * diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt index c2fe85c2b..3881e8833 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt @@ -472,10 +472,10 @@ object PreferenceUtil { val tabTitleMode: Int get() { return when (sharedPreferences.getStringOrDefault( - TAB_TEXT_MODE, "1" + TAB_TEXT_MODE, "0" ).toInt()) { - 1 -> BottomNavigationView.LABEL_VISIBILITY_LABELED 0 -> BottomNavigationView.LABEL_VISIBILITY_AUTO + 1 -> BottomNavigationView.LABEL_VISIBILITY_LABELED 2 -> BottomNavigationView.LABEL_VISIBILITY_SELECTED 3 -> BottomNavigationView.LABEL_VISIBILITY_UNLABELED else -> BottomNavigationView.LABEL_VISIBILITY_LABELED diff --git a/app/src/main/java/code/name/monkey/retromusic/views/BottomNavigationBarTinted.kt b/app/src/main/java/code/name/monkey/retromusic/views/TintedBottomNavigationView.kt similarity index 81% rename from app/src/main/java/code/name/monkey/retromusic/views/BottomNavigationBarTinted.kt rename to app/src/main/java/code/name/monkey/retromusic/views/TintedBottomNavigationView.kt index 0e5ddb455..116f3d0a3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/views/BottomNavigationBarTinted.kt +++ b/app/src/main/java/code/name/monkey/retromusic/views/TintedBottomNavigationView.kt @@ -19,14 +19,13 @@ import android.content.res.ColorStateList import android.util.AttributeSet import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.util.ATHUtil -import code.name.monkey.appthemehelper.util.ColorUtil -import code.name.monkey.appthemehelper.util.NavigationViewUtil import code.name.monkey.retromusic.extensions.addAlpha +import code.name.monkey.retromusic.extensions.setItemColors import code.name.monkey.retromusic.util.PreferenceUtil import com.google.android.material.bottomnavigation.BottomNavigationView import dev.chrisbanes.insetter.applyInsetter -class BottomNavigationBarTinted @JvmOverloads constructor( +class TintedBottomNavigationView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0, @@ -55,16 +54,7 @@ class BottomNavigationBarTinted @JvmOverloads constructor( if (!PreferenceUtil.materialYou) { val iconColor = ATHUtil.resolveColor(context, android.R.attr.colorControlNormal) val accentColor = ThemeStore.accentColor(context) - NavigationViewUtil.setItemIconColors( - this, - ColorUtil.withAlpha(iconColor, 0.5f), - accentColor - ) - NavigationViewUtil.setItemTextColors( - this, - ColorUtil.withAlpha(iconColor, 0.5f), - accentColor - ) + setItemColors(iconColor, accentColor) itemRippleColor = ColorStateList.valueOf(accentColor.addAlpha(0.08F)) itemActiveIndicatorColor = ColorStateList.valueOf(accentColor.addAlpha(0.12F)) } diff --git a/app/src/main/java/code/name/monkey/retromusic/views/TintedNavigationRailView.kt b/app/src/main/java/code/name/monkey/retromusic/views/TintedNavigationRailView.kt new file mode 100644 index 000000000..828e6fc2b --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/TintedNavigationRailView.kt @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2019 Hemanth Savarala. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + */ + +package code.name.monkey.retromusic.views + +import android.content.Context +import android.content.res.ColorStateList +import android.util.AttributeSet +import code.name.monkey.appthemehelper.util.ATHUtil +import code.name.monkey.retromusic.extensions.accentColor +import code.name.monkey.retromusic.extensions.addAlpha +import code.name.monkey.retromusic.extensions.setItemColors +import code.name.monkey.retromusic.util.PreferenceUtil +import com.google.android.material.navigationrail.NavigationRailView + +class TintedNavigationRailView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0, +) : NavigationRailView(context, attrs, defStyleAttr) { + + init { + if (!isInEditMode) { + labelVisibilityMode = PreferenceUtil.tabTitleMode + + if (!PreferenceUtil.materialYou) { + val iconColor = ATHUtil.resolveColor(context, android.R.attr.colorControlNormal) + val accentColor = context.accentColor() + setItemColors(iconColor, accentColor) + itemRippleColor = ColorStateList.valueOf(accentColor.addAlpha(0.08F)) + itemActiveIndicatorColor = ColorStateList.valueOf(accentColor.addAlpha(0.12F)) + } + } + } +} \ No newline at end of file diff --git a/app/src/main/res/layout-land/sliding_music_panel_layout.xml b/app/src/main/res/layout-land/sliding_music_panel_layout.xml index c314081d8..4d6074066 100644 --- a/app/src/main/res/layout-land/sliding_music_panel_layout.xml +++ b/app/src/main/res/layout-land/sliding_music_panel_layout.xml @@ -10,7 +10,7 @@ android:layout_width="match_parent" android:layout_height="match_parent"> - - Date: Sat, 18 Jun 2022 11:32:33 +0530 Subject: [PATCH 08/19] Fixed queue reset when a song is clicked in Playing queue fragment --- .../java/code/name/monkey/retromusic/Constants.kt | 1 - .../retromusic/adapter/song/PlayingQueueAdapter.kt | 12 ++++++++++-- .../monkey/retromusic/helper/MusicPlayerRemote.kt | 3 --- .../name/monkey/retromusic/util/PreferenceUtil.kt | 4 +--- app/src/main/res/xml/pref_audio.xml | 8 -------- 5 files changed, 11 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/code/name/monkey/retromusic/Constants.kt b/app/src/main/java/code/name/monkey/retromusic/Constants.kt index 3818186d3..d17b3194e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/Constants.kt +++ b/app/src/main/java/code/name/monkey/retromusic/Constants.kt @@ -136,7 +136,6 @@ const val ARTIST_DETAIL_SONG_SORT_ORDER = "artist_detail_song_sort_order" const val LYRICS_OPTIONS = "lyrics_tab_position" const val CHOOSE_EQUALIZER = "choose_equalizer" const val EQUALIZER = "equalizer" -const val TOGGLE_SHUFFLE = "toggle_shuffle" const val SONG_GRID_STYLE = "song_grid_style" const val PAUSE_ON_ZERO_VOLUME = "pause_on_zero_volume" const val FILTER_SONG = "filter_song" diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlayingQueueAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlayingQueueAdapter.kt index ae2de00c6..3ffad5efd 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlayingQueueAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/PlayingQueueAdapter.kt @@ -42,7 +42,7 @@ class PlayingQueueAdapter( activity: FragmentActivity, dataSet: MutableList, private var current: Int, - itemLayoutRes: Int + itemLayoutRes: Int, ) : SongAdapter( activity, dataSet, itemLayoutRes, null ), DraggableItemAdapter, @@ -153,6 +153,14 @@ class PlayingQueueAdapter( dragView?.isVisible = true } + override fun onClick(v: View?) { + if (isInQuickSelectMode) { + toggleChecked(layoutPosition) + } else { + MusicPlayerRemote.playSongAt(layoutPosition) + } + } + override fun onSongMenuItemClick(item: MenuItem): Boolean { when (item.itemId) { R.id.action_remove_from_playing_queue -> { @@ -209,7 +217,7 @@ class PlayingQueueAdapter( internal class SwipedResultActionRemoveItem( private val adapter: PlayingQueueAdapter, private val position: Int, - private val activity: FragmentActivity + private val activity: FragmentActivity, ) : SwipeResultActionRemoveItem() { private var songToRemove: Song? = null diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt b/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt index d3cb502da..a57af2a17 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt @@ -171,9 +171,6 @@ object MusicPlayerRemote : KoinComponent { return musicService?.playingQueue?.size ?: -1 } - /** - * Async - */ fun playSongAt(position: Int) { musicService?.playSongAt(position) } diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt index 3881e8833..92e01f567 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt @@ -115,7 +115,7 @@ object PreferenceUtil { putString(SAF_SDCARD_URI, value) } - val autoDownloadImagesPolicy + private val autoDownloadImagesPolicy get() = sharedPreferences.getStringOrDefault( AUTO_DOWNLOAD_IMAGES_POLICY, "only_wifi" @@ -242,8 +242,6 @@ object PreferenceUtil { val isScreenOnEnabled get() = sharedPreferences.getBoolean(KEEP_SCREEN_ON, false) - val isShuffleModeOn get() = sharedPreferences.getBoolean(TOGGLE_SHUFFLE, false) - val isSongInfo get() = sharedPreferences.getBoolean(EXTRA_SONG_INFO, false) val isPauseOnZeroVolume get() = sharedPreferences.getBoolean(PAUSE_ON_ZERO_VOLUME, false) diff --git a/app/src/main/res/xml/pref_audio.xml b/app/src/main/res/xml/pref_audio.xml index d25ba2063..749202ced 100755 --- a/app/src/main/res/xml/pref_audio.xml +++ b/app/src/main/res/xml/pref_audio.xml @@ -56,14 +56,6 @@ android:title="@string/pref_title_toggle_toggle_headset" app:icon="@drawable/ic_play_arrow" /> - - Date: Sun, 19 Jun 2022 10:38:33 +0530 Subject: [PATCH 09/19] Fixed a lyrics crash --- app/build.gradle | 4 ++-- .../fragments/player/PlayerAlbumCoverFragment.kt | 7 +++++-- build.gradle | 1 + 3 files changed, 8 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 75363dfcd..23217e553 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -101,7 +101,7 @@ dependencies { implementation 'androidx.constraintlayout:constraintlayout:2.1.4' implementation 'androidx.recyclerview:recyclerview:1.2.1' implementation "androidx.preference:preference-ktx:$preference_version" - implementation 'androidx.core:core-ktx:1.8.0' + implementation "androidx.core:core-ktx:$core_version" implementation 'androidx.palette:palette-ktx:1.0.0' implementation 'androidx.mediarouter:mediarouter:1.3.0' @@ -133,7 +133,7 @@ dependencies { def retrofit_version = '2.9.0' implementation "com.squareup.retrofit2:retrofit:$retrofit_version" implementation "com.squareup.retrofit2:converter-gson:$retrofit_version" - implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.8' + implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.9' def material_dialog_version = "3.3.0" implementation "com.afollestad.material-dialogs:core:$material_dialog_version" 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 3770da872..8cf022dca 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 @@ -52,6 +52,7 @@ import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import code.name.monkey.retromusic.util.logD import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_player_album_cover), ViewPager.OnPageChangeListener, MusicProgressViewUpdateHelper.Callback, @@ -95,8 +96,10 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe if (embeddedLyrics != null) { binding.lyricsView.loadLrc(embeddedLyrics) } else { - binding.lyricsView.reset() - binding.lyricsView.setLabel(context?.getString(R.string.no_lyrics_found)) + withContext(Dispatchers.Main) { + binding.lyricsView.reset() + binding.lyricsView.setLabel(context?.getString(R.string.no_lyrics_found)) + } } } } diff --git a/build.gradle b/build.gradle index 539c8bf56..47d09a145 100644 --- a/build.gradle +++ b/build.gradle @@ -8,6 +8,7 @@ buildscript { mdc_version = '1.7.0-alpha02' preference_version = '1.2.0' appcompat_version = '1.4.2' + core_version='1.8.0' } repositories { From e626803e9f689367fe2a2e508bae42f8f429acc6 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Sun, 19 Jun 2022 15:41:19 +0530 Subject: [PATCH 10/19] Initial fastlane structure --- README.md | 6 +++--- .../android/en-US/full_description.txt | 20 ++++++++++++++++++ .../metadata/android/en-US/images/logo.png | Bin 0 -> 13772 bytes .../en-US/images/phoneScreenshots/1.jpg | Bin .../en-US/images/phoneScreenshots/2.jpg | Bin .../en-US/images/phoneScreenshots/3.jpg | Bin .../en-US/images/phoneScreenshots/4.jpg | Bin .../en-US/images/phoneScreenshots/5.jpg | Bin .../en-US/images/phoneScreenshots/6.jpg | Bin .../en-US/images/phoneScreenshots/7.jpg | Bin .../en-US/images/phoneScreenshots/8.jpg | Bin .../android/en-US/short_description.txt | 1 + 12 files changed, 24 insertions(+), 3 deletions(-) create mode 100644 fastlane/metadata/android/en-US/full_description.txt create mode 100644 fastlane/metadata/android/en-US/images/logo.png rename screenshots/normal.jpg => fastlane/metadata/android/en-US/images/phoneScreenshots/1.jpg (100%) rename screenshots/home_light.jpg => fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg (100%) rename screenshots/home_dark.jpg => fastlane/metadata/android/en-US/images/phoneScreenshots/3.jpg (100%) rename screenshots/home_black.jpg => fastlane/metadata/android/en-US/images/phoneScreenshots/4.jpg (100%) rename screenshots/songs.jpg => fastlane/metadata/android/en-US/images/phoneScreenshots/5.jpg (100%) rename screenshots/albums.jpg => fastlane/metadata/android/en-US/images/phoneScreenshots/6.jpg (100%) rename screenshots/artists.jpg => fastlane/metadata/android/en-US/images/phoneScreenshots/7.jpg (100%) rename screenshots/settings.jpg => fastlane/metadata/android/en-US/images/phoneScreenshots/8.jpg (100%) create mode 100644 fastlane/metadata/android/en-US/short_description.txt diff --git a/README.md b/README.md index fd6e3edb7..f745eed01 100644 --- a/README.md +++ b/README.md @@ -38,12 +38,12 @@ ___ ## 📱 Screenshots ### App Themes -| | | | +| | | | |:---:|:---:|:---:| |Clearly white| Kinda dark | Just black| ### Player screen -| | | | | | +| | | | | | |:---:|:---:|:---:|:---:|:---:| | Home | Songs | Albums | Artists | Settings | @@ -58,7 +58,7 @@ ___ | Synced Replace Cover light | Synced Replace Cover dark | Synced Replace Cover black | ### 10+ Now playing themes -| || | | | +| || | | | |:-----: |:-----: |:-----: |:-----: |:-----: | | Normal | Fit | Flat | Color | Material | diff --git a/fastlane/metadata/android/en-US/full_description.txt b/fastlane/metadata/android/en-US/full_description.txt new file mode 100644 index 000000000..a39bbf5e4 --- /dev/null +++ b/fastlane/metadata/android/en-US/full_description.txt @@ -0,0 +1,20 @@ +Retro Music Player 🎵 + +📦 Included Features +
    +
  • Base 3 themes (Clearly White, Kinda Dark and Just Black)
  • +
  • Material You support on Android 12+
  • +
  • Gapless playback
  • +
  • Crossfade playback
  • +
  • Choose from 10+ now playing themes
  • +
  • Android auto support
  • +
  • Wallpaper accent picker on Android 8.1+
  • +
  • Home screen widgets
  • +
  • Lock screen playback controls
  • +
  • Sleep timer
  • +
  • Easy drag to sort playlist & play queue
  • +
  • Tag editor
  • +
  • Create, edit and import playlists
  • +
  • Browse and play your music by songs, albums, artists, playlists and genre
  • +
  • Smart Auto Playlists - Recently played, most played and history
  • +
\ No newline at end of file diff --git a/fastlane/metadata/android/en-US/images/logo.png b/fastlane/metadata/android/en-US/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..11a780e3127964864b01a4d2a3fc54aa08a4024a GIT binary patch literal 13772 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 Date: Sun, 19 Jun 2022 17:31:14 +0530 Subject: [PATCH 11/19] Changed lyrics icon --- app/src/main/res/drawable/ic_lyrics.xml | 5 ++--- app/src/main/res/drawable/ic_lyrics_outline.xml | 17 +++-------------- 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/app/src/main/res/drawable/ic_lyrics.xml b/app/src/main/res/drawable/ic_lyrics.xml index 6a2a3a724..2064cc4a6 100644 --- a/app/src/main/res/drawable/ic_lyrics.xml +++ b/app/src/main/res/drawable/ic_lyrics.xml @@ -5,6 +5,5 @@ android:viewportHeight="24"> - \ No newline at end of file + android:pathData="M2,22V4Q2,3.175 2.588,2.587Q3.175,2 4,2H15Q15.825,2 16.413,2.587Q17,3.175 17,4V4.425Q15.625,5.025 14.812,6.262Q14,7.5 14,9Q14,10.5 14.812,11.738Q15.625,12.975 17,13.575V16Q17,16.825 16.413,17.413Q15.825,18 15,18H6ZM6,14H10V12H6ZM19,12Q17.75,12 16.875,11.125Q16,10.25 16,9Q16,7.725 16.875,6.862Q17.75,6 19,6Q19.275,6 19.525,6.05Q19.775,6.1 20,6.175V1H24V3H22V9Q22,10.25 21.125,11.125Q20.25,12 19,12ZM6,11H13V9H6ZM6,8H13V6H6Z"/> + diff --git a/app/src/main/res/drawable/ic_lyrics_outline.xml b/app/src/main/res/drawable/ic_lyrics_outline.xml index f1d5843af..4a37173ef 100644 --- a/app/src/main/res/drawable/ic_lyrics_outline.xml +++ b/app/src/main/res/drawable/ic_lyrics_outline.xml @@ -3,18 +3,7 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> - - - - + From 5ac1b2bcc67b72105c0562f90847e2069d80902c Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Sun, 19 Jun 2022 19:33:35 +0530 Subject: [PATCH 12/19] Release 6.0.2 --- app/build.gradle | 4 +-- app/src/main/assets/retro-changelog.html | 8 ++++++ .../monkey/retromusic/service/MusicService.kt | 25 +++++++++++++------ .../android/en-US/changelogs/10596.txt | 1 + 4 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelogs/10596.txt diff --git a/app/build.gradle b/app/build.gradle index 23217e553..5dedc35c3 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,8 +14,8 @@ android { vectorDrawables.useSupportLibrary = true applicationId "code.name.monkey.retromusic" - versionCode 10592 - versionName '6.0.1-beta' + versionCode 10595 + versionName '6.0.2-beta' buildConfigField("String", "GOOGLE_PLAY_LICENSING_KEY", "\"${getProperty(getProperties('../public.properties'), 'GOOGLE_PLAY_LICENSE_KEY')}\"") } diff --git a/app/src/main/assets/retro-changelog.html b/app/src/main/assets/retro-changelog.html index 18f5605c2..6028889c1 100644 --- a/app/src/main/assets/retro-changelog.html +++ b/app/src/main/assets/retro-changelog.html @@ -62,6 +62,14 @@ +
+
June 21, 2022
+

v6.0.2Beta

+

What's New

+
    +
  • Added lyrics downloading
  • +
+
June 13, 2022

v6.0.1Beta

diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt index c31293f91..087f16dd9 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt @@ -285,12 +285,16 @@ class MusicService : MediaBrowserServiceCompat(), initNotification() mediaStoreObserver = MediaStoreObserver(this, playerHandler!!) throttledSeekHandler = ThrottledSeekHandler(this, Handler(mainLooper)) - contentResolver.registerContentObserver(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, + contentResolver.registerContentObserver( + MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, true, - mediaStoreObserver) - contentResolver.registerContentObserver(MediaStore.Audio.Media.INTERNAL_CONTENT_URI, + mediaStoreObserver + ) + contentResolver.registerContentObserver( + MediaStore.Audio.Media.INTERNAL_CONTENT_URI, true, - mediaStoreObserver) + mediaStoreObserver + ) val audioVolumeObserver = AudioVolumeObserver(this) audioVolumeObserver.register(AudioManager.STREAM_MUSIC, this) registerOnSharedPreferenceChangedListener(this) @@ -318,6 +322,7 @@ class MusicService : MediaBrowserServiceCompat(), mediaSession?.isActive = false quit() releaseResources() + serviceScope.cancel() contentResolver.unregisterContentObserver(mediaStoreObserver) unregisterOnSharedPreferenceChangedListener(this) wakeLock?.release() @@ -1013,8 +1018,10 @@ class MusicService : MediaBrowserServiceCompat(), .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, song.albumName) .putString(MediaMetadataCompat.METADATA_KEY_TITLE, song.title) .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, song.duration) - .putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, - (getPosition() + 1).toLong()) + .putLong( + MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, + (getPosition() + 1).toLong() + ) .putLong(MediaMetadataCompat.METADATA_KEY_YEAR, song.year.toLong()) .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, null) .putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, playingQueue.size.toLong()) @@ -1303,8 +1310,10 @@ class MusicService : MediaBrowserServiceCompat(), } private fun setupMediaSession() { - val mediaButtonReceiverComponentName = ComponentName(applicationContext, - MediaButtonIntentReceiver::class.java) + val mediaButtonReceiverComponentName = ComponentName( + applicationContext, + MediaButtonIntentReceiver::class.java + ) val mediaButtonIntent = Intent(Intent.ACTION_MEDIA_BUTTON) mediaButtonIntent.component = mediaButtonReceiverComponentName diff --git a/fastlane/metadata/android/en-US/changelogs/10596.txt b/fastlane/metadata/android/en-US/changelogs/10596.txt new file mode 100644 index 000000000..d2297558d --- /dev/null +++ b/fastlane/metadata/android/en-US/changelogs/10596.txt @@ -0,0 +1 @@ +Added lyrics downloading \ No newline at end of file From 0f66d005c719ab73c6454fed1a902dc39c3f9eea Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Mon, 20 Jun 2022 11:28:08 +0530 Subject: [PATCH 13/19] Fixed music playing automatically after setting playback speed and pitch --- .../code/name/monkey/retromusic/service/CrossFadePlayer.kt | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/src/main/java/code/name/monkey/retromusic/service/CrossFadePlayer.kt b/app/src/main/java/code/name/monkey/retromusic/service/CrossFadePlayer.kt index 7ce084f7c..3fd798351 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/CrossFadePlayer.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/CrossFadePlayer.kt @@ -333,6 +333,10 @@ internal fun crossFadeScope(): CoroutineScope = CoroutineScope(Job() + Dispatche fun MediaPlayer.setPlaybackSpeedPitch(speed: Float, pitch: Float) { if (hasMarshmallow()) { + val wasPlaying = isPlaying playbackParams = PlaybackParams().setSpeed(speed).setPitch(pitch) + if (!wasPlaying) { + pause() + } } } \ No newline at end of file From dd5945978605bc6e7f89049a2d7909d674698eb9 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Mon, 20 Jun 2022 14:42:59 +0530 Subject: [PATCH 14/19] Use Coroutines in LrcView --- .../monkey/retromusic/lyrics/CoverLrcView.kt | 142 +- .../monkey/retromusic/lyrics/LrcView.java | 1235 ++++++++--------- .../name/monkey/retromusic/util/LyricUtil.kt | 8 +- .../menu/{menu_search.xml => menu_lyrics.xml} | 0 4 files changed, 574 insertions(+), 811 deletions(-) rename app/src/main/res/menu/{menu_search.xml => menu_lyrics.xml} (100%) 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 c74c5bbdc..d772a1eb6 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 @@ -19,7 +19,6 @@ import android.content.Context import android.graphics.Canvas import android.graphics.Paint import android.graphics.drawable.Drawable -import android.os.AsyncTask import android.os.Looper import android.text.Layout import android.text.StaticLayout @@ -35,14 +34,15 @@ import android.widget.Scroller import androidx.core.content.ContextCompat import androidx.core.graphics.withSave import code.name.monkey.retromusic.R +import kotlinx.coroutines.* import java.io.File +import java.lang.Runnable import kotlin.math.abs /** * 歌词 Created by wcy on 2015/11/9. */ @SuppressLint("StaticFieldLeak") -@Suppress("deprecation") class CoverLrcView @JvmOverloads constructor( context: Context?, attrs: AttributeSet? = null, @@ -72,7 +72,6 @@ class CoverLrcView @JvmOverloads constructor( 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 @@ -85,9 +84,8 @@ class CoverLrcView @JvmOverloads constructor( } } - /** - * 手势监听器 - */ + private val viewScope = CoroutineScope(Dispatchers.Main + Job()) + private val mSimpleOnGestureListener: SimpleOnGestureListener = object : SimpleOnGestureListener() { override fun onDown(e: MotionEvent): Boolean { @@ -251,42 +249,31 @@ class CoverLrcView @JvmOverloads constructor( mScroller = Scroller(context) } - /** 设置非当前行歌词字体颜色 */ fun setNormalColor(normalColor: Int) { mNormalTextColor = normalColor postInvalidate() } - /** 设置当前行歌词的字体颜色 */ 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" } @@ -296,17 +283,6 @@ class CoverLrcView @JvmOverloads constructor( } } - /** - * 设置播放按钮点击监听器 - * - * @param onPlayClickListener 如果为非 null ,则激活歌词拖动功能,否则将将禁用歌词拖动功能 - */ - @Deprecated("use {@link #setDraggable(boolean, OnPlayClickListener)} instead") - fun setOnPlayClickListener(onPlayClickListener: OnPlayClickListener?) { - mOnPlayClickListener = onPlayClickListener - } - - /** 设置歌词为空时屏幕中央显示的文字,如“暂无歌词” */ fun setLabel(label: String?) { runOnUi { mDefaultLabel = label @@ -314,106 +290,40 @@ class CoverLrcView @JvmOverloads constructor( } } - /** - * 加载歌词文件 - * - * @param lrcFile 歌词文件 - */ fun loadLrc(lrcFile: File) { - loadLrc(lrcFile, null) - } - - /** - * 加载双语歌词文件,两种语言的歌词时间戳需要一致 - * - * @param mainLrcFile 第一种语言歌词文件 - * @param secondLrcFile 第二种语言歌词文件 - */ - private fun loadLrc(mainLrcFile: File, secondLrcFile: File?) { runOnUi { reset() - val sb = StringBuilder("file://") - sb.append(mainLrcFile.path) - if (secondLrcFile != null) { - sb.append("#").append(secondLrcFile.path) + viewScope.launch(Dispatchers.IO) { + val lrcEntries = LrcUtils.parseLrc(arrayOf(lrcFile, null)) + withContext(Dispatchers.Main) { + onLrcLoaded(lrcEntries) + } } - 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 第二种语言歌词文本 - */ - private fun loadLrc(mainLrcText: String?, secondLrcText: String?) { runOnUi { reset() - val sb = StringBuilder("file://") - sb.append(mainLrcText) - if (secondLrcText != null) { - sb.append("#").append(secondLrcText) + viewScope.launch(Dispatchers.IO) { + val lrcEntries = LrcUtils.parseLrc(arrayOf(lrcText, null)) + withContext(Dispatchers.Main) { + onLrcLoaded(lrcEntries) + } } - 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) } } - /** - * 歌词是否有效 - * - * @return true,如果歌词有效,否则false - */ fun hasLrc(): Boolean { return mLrcEntryList.isNotEmpty() } - /** - * 刷新歌词 - * - * @param time 当前播放时间 - */ fun updateTime(time: Long) { runOnUi { if (!hasLrc()) { return@runOnUi } - val line = findShowLine(time) + val line = findShowLine(time - 300L) if (line != mCurrentLine) { mCurrentLine = line if (!isShowTimeline) { @@ -441,9 +351,9 @@ class CoverLrcView @JvmOverloads constructor( super.onDraw(canvas) val centerY = height / 2 - // 无歌词文件 if (!hasLrc()) { mLrcPaint.color = mCurrentTextColor + @Suppress("Deprecation") @SuppressLint("DrawAllocation") val staticLayout = StaticLayout( mDefaultLabel, mLrcPaint, @@ -485,11 +395,6 @@ class CoverLrcView @JvmOverloads constructor( } } - /** - * 画一行歌词 - * - * @param y 歌词中心 Y 坐标 - */ private fun drawText(canvas: Canvas, staticLayout: StaticLayout, y: Float) { canvas.withSave { translate(mLrcPadding, y - (staticLayout.height shr 1)) @@ -539,6 +444,7 @@ class CoverLrcView @JvmOverloads constructor( override fun onDetachedFromWindow() { removeCallbacks(hideTimelineRunnable) + viewScope.cancel() super.onDetachedFromWindow() } @@ -582,12 +488,10 @@ class CoverLrcView @JvmOverloads constructor( invalidate() } - /** 将中心行微调至正中心 */ private fun adjustCenter() { smoothScrollTo(centerLine, ADJUST_DURATION) } - /** 滚动到某一行 */ private fun smoothScrollTo(line: Int, duration: Long = mAnimationDuration) { val offset = getOffset(line) endAnimation() @@ -602,14 +506,12 @@ class CoverLrcView @JvmOverloads constructor( } } - /** 结束滚动动画 */ private fun endAnimation() { if (mAnimator != null && mAnimator!!.isRunning) { mAnimator!!.end() } } - /** 二分法查找当前时间应该显示的行数(最后一个 <= time 的行数) */ private fun findShowLine(time: Long): Int { var left = 0 var right = mLrcEntryList.size @@ -628,7 +530,6 @@ class CoverLrcView @JvmOverloads constructor( return 0 } - /** 获取当前在视图中央的行数 */ private val centerLine: Int get() { var centerLine = 0 @@ -642,7 +543,6 @@ class CoverLrcView @JvmOverloads constructor( return centerLine } - /** 获取歌词距离视图顶部的距离 采用懒加载方式 */ private fun getOffset(line: Int): Float { if (mLrcEntryList.isEmpty()) return 0F if (mLrcEntryList[line].offset == Float.MIN_VALUE) { @@ -656,11 +556,9 @@ class CoverLrcView @JvmOverloads constructor( return mLrcEntryList[line].offset } - /** 获取歌词宽度 */ private val lrcWidth: Float get() = width - mLrcPadding * 2 - /** 在主线程中运行 */ private fun runOnUi(r: Runnable) { if (Looper.myLooper() == Looper.getMainLooper()) { r.run() @@ -669,13 +567,7 @@ class CoverLrcView @JvmOverloads constructor( } } - /** 播放按钮点击监听器,点击后应该跳转到指定播放位置 */ fun interface OnPlayClickListener { - /** - * 播放按钮被点击,应该跳转到指定播放位置 - * - * @return 是否成功消费该事件,如果成功消费,则会更新UI - */ fun onPlayClick(time: Long): Boolean } diff --git a/app/src/main/java/code/name/monkey/retromusic/lyrics/LrcView.java b/app/src/main/java/code/name/monkey/retromusic/lyrics/LrcView.java index ca450b621..64844828b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/lyrics/LrcView.java +++ b/app/src/main/java/code/name/monkey/retromusic/lyrics/LrcView.java @@ -35,6 +35,8 @@ import android.view.View; import android.view.animation.LinearInterpolator; import android.widget.Scroller; +import androidx.core.content.ContextCompat; + import java.io.File; import java.util.ArrayList; import java.util.Collections; @@ -48,731 +50,600 @@ import code.name.monkey.retromusic.R; */ @SuppressLint("StaticFieldLeak") public class LrcView extends View { - private static final long ADJUST_DURATION = 100; - private static final long TIMELINE_KEEP_TIME = 4 * DateUtils.SECOND_IN_MILLIS; + private static final long ADJUST_DURATION = 100; + private static final long TIMELINE_KEEP_TIME = 4 * DateUtils.SECOND_IN_MILLIS; - private final List mLrcEntryList = new ArrayList<>(); - private final TextPaint mLrcPaint = new TextPaint(); - private final TextPaint mTimePaint = new TextPaint(); - private Paint.FontMetrics mTimeFontMetrics; - private Drawable mPlayDrawable; - private float mDividerHeight; - private long mAnimationDuration; - private int mNormalTextColor; - private float mNormalTextSize; - private int mCurrentTextColor; - private float mCurrentTextSize; - private int mTimelineTextColor; - private int mTimelineColor; - private int mTimeTextColor; - private int mDrawableWidth; - private int mTimeTextWidth; - private String mDefaultLabel; - private float mLrcPadding; - private OnPlayClickListener mOnPlayClickListener; - private ValueAnimator mAnimator; - private GestureDetector mGestureDetector; - private Scroller mScroller; - private float mOffset; - private int mCurrentLine; - private Object mFlag; - private boolean isShowTimeline; - private boolean isTouching; - private boolean isFling; - private int mTextGravity; // 歌词显示位置,靠左/居中/靠右 - private final Runnable hideTimelineRunnable = - new Runnable() { - @Override - public void run() { - if (hasLrc() && isShowTimeline) { - isShowTimeline = false; - smoothScrollTo(mCurrentLine); - } - } - }; - /** - * 手势监听器 - */ - private final GestureDetector.SimpleOnGestureListener mSimpleOnGestureListener = - new GestureDetector.SimpleOnGestureListener() { - @Override - public boolean onDown(MotionEvent e) { - if (hasLrc() && mOnPlayClickListener != null) { - mScroller.forceFinished(true); - removeCallbacks(hideTimelineRunnable); - isTouching = true; - isShowTimeline = true; - invalidate(); - return true; - } - return super.onDown(e); - } + private final List mLrcEntryList = new ArrayList<>(); + private final TextPaint mLrcPaint = new TextPaint(); + private final TextPaint mTimePaint = new TextPaint(); + private Paint.FontMetrics mTimeFontMetrics; + private Drawable mPlayDrawable; + private float mDividerHeight; + private long mAnimationDuration; + private int mNormalTextColor; + private float mNormalTextSize; + private int mCurrentTextColor; + private float mCurrentTextSize; + private int mTimelineTextColor; + private int mTimelineColor; + private int mTimeTextColor; + private int mDrawableWidth; + private int mTimeTextWidth; + private String mDefaultLabel; + private float mLrcPadding; + private OnPlayClickListener mOnPlayClickListener; + private ValueAnimator mAnimator; + private GestureDetector mGestureDetector; + private Scroller mScroller; + private float mOffset; + private int mCurrentLine; + private Object mFlag; + private boolean isShowTimeline; + private boolean isTouching; + private boolean isFling; + private int mTextGravity; // 歌词显示位置,靠左/居中/靠右 + private final Runnable hideTimelineRunnable = + new Runnable() { + @Override + public void run() { + if (hasLrc() && isShowTimeline) { + isShowTimeline = false; + smoothScrollTo(mCurrentLine); + } + } + }; - @Override - public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { - if (hasLrc()) { - mOffset += -distanceY; - mOffset = Math.min(mOffset, getOffset(0)); - mOffset = Math.max(mOffset, getOffset(mLrcEntryList.size() - 1)); - invalidate(); - getParent().requestDisallowInterceptTouchEvent(true); - return true; - } - return super.onScroll(e1, e2, distanceX, distanceY); - } + private final GestureDetector.SimpleOnGestureListener mSimpleOnGestureListener = + new GestureDetector.SimpleOnGestureListener() { + @Override + public boolean onDown(MotionEvent e) { + if (hasLrc() && mOnPlayClickListener != null) { + mScroller.forceFinished(true); + removeCallbacks(hideTimelineRunnable); + isTouching = true; + isShowTimeline = true; + invalidate(); + return true; + } + return super.onDown(e); + } - @Override - public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { - if (hasLrc()) { - mScroller.fling( - 0, - (int) mOffset, - 0, - (int) velocityY, - 0, - 0, - (int) getOffset(mLrcEntryList.size() - 1), - (int) getOffset(0)); - isFling = true; - return true; - } - return super.onFling(e1, e2, velocityX, velocityY); - } + @Override + public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { + if (hasLrc()) { + mOffset -= distanceY; + mOffset = Math.min(mOffset, getOffset(0)); + mOffset = Math.max(mOffset, getOffset(mLrcEntryList.size() - 1)); + invalidate(); + getParent().requestDisallowInterceptTouchEvent(true); + return true; + } + return super.onScroll(e1, e2, distanceX, distanceY); + } - @Override - public boolean onSingleTapConfirmed(MotionEvent e) { - if (hasLrc() - && isShowTimeline - && mPlayDrawable.getBounds().contains((int) e.getX(), (int) e.getY())) { - int centerLine = getCenterLine(); - long centerLineTime = mLrcEntryList.get(centerLine).getTime(); - // onPlayClick 消费了才更新 UI - if (mOnPlayClickListener != null && mOnPlayClickListener.onPlayClick(centerLineTime)) { - isShowTimeline = false; - removeCallbacks(hideTimelineRunnable); - mCurrentLine = centerLine; - invalidate(); - return true; - } - } - return super.onSingleTapConfirmed(e); - } - }; + @Override + public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { + if (hasLrc()) { + mScroller.fling( + 0, + (int) mOffset, + 0, + (int) velocityY, + 0, + 0, + (int) getOffset(mLrcEntryList.size() - 1), + (int) getOffset(0)); + isFling = true; + return true; + } + return super.onFling(e1, e2, velocityX, velocityY); + } - public LrcView(Context context) { - this(context, null); - } + @Override + public boolean onSingleTapConfirmed(MotionEvent e) { + if (hasLrc() + && isShowTimeline + && mPlayDrawable.getBounds().contains((int) e.getX(), (int) e.getY())) { + int centerLine = getCenterLine(); + long centerLineTime = mLrcEntryList.get(centerLine).getTime(); + // onPlayClick 消费了才更新 UI + if (mOnPlayClickListener != null && mOnPlayClickListener.onPlayClick(centerLineTime)) { + isShowTimeline = false; + removeCallbacks(hideTimelineRunnable); + mCurrentLine = centerLine; + invalidate(); + return true; + } + } + return super.onSingleTapConfirmed(e); + } + }; - public LrcView(Context context, AttributeSet attrs) { - this(context, attrs, 0); - } - - public LrcView(Context context, AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(attrs); - } - - private void init(AttributeSet attrs) { - TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.LrcView); - mCurrentTextSize = - ta.getDimension( - R.styleable.LrcView_lrcTextSize, getResources().getDimension(R.dimen.lrc_text_size)); - mNormalTextSize = - ta.getDimension( - R.styleable.LrcView_lrcNormalTextSize, - getResources().getDimension(R.dimen.lrc_text_size)); - if (mNormalTextSize == 0) { - mNormalTextSize = mCurrentTextSize; + public LrcView(Context context) { + this(context, null); } - mDividerHeight = - ta.getDimension( - R.styleable.LrcView_lrcDividerHeight, - getResources().getDimension(R.dimen.lrc_divider_height)); - int defDuration = getResources().getInteger(R.integer.lrc_animation_duration); - mAnimationDuration = ta.getInt(R.styleable.LrcView_lrcAnimationDuration, defDuration); - mAnimationDuration = (mAnimationDuration < 0) ? defDuration : mAnimationDuration; - mNormalTextColor = - ta.getColor( - R.styleable.LrcView_lrcNormalTextColor, - getResources().getColor(R.color.lrc_normal_text_color)); - mCurrentTextColor = - ta.getColor( - R.styleable.LrcView_lrcCurrentTextColor, - getResources().getColor(R.color.lrc_current_text_color)); - mTimelineTextColor = - ta.getColor( - R.styleable.LrcView_lrcTimelineTextColor, - getResources().getColor(R.color.lrc_timeline_text_color)); - mDefaultLabel = ta.getString(R.styleable.LrcView_lrcLabel); - mDefaultLabel = - TextUtils.isEmpty(mDefaultLabel) ? getContext().getString(R.string.empty) : mDefaultLabel; - mLrcPadding = ta.getDimension(R.styleable.LrcView_lrcPadding, 0); - mTimelineColor = - ta.getColor( - R.styleable.LrcView_lrcTimelineColor, - getResources().getColor(R.color.lrc_timeline_color)); - float timelineHeight = - ta.getDimension( - R.styleable.LrcView_lrcTimelineHeight, - getResources().getDimension(R.dimen.lrc_timeline_height)); - mPlayDrawable = ta.getDrawable(R.styleable.LrcView_lrcPlayDrawable); - mPlayDrawable = - (mPlayDrawable == null) - ? getResources().getDrawable(R.drawable.ic_play_arrow) - : mPlayDrawable; - mTimeTextColor = - ta.getColor( - R.styleable.LrcView_lrcTimeTextColor, - getResources().getColor(R.color.lrc_time_text_color)); - float timeTextSize = - ta.getDimension( - R.styleable.LrcView_lrcTimeTextSize, - getResources().getDimension(R.dimen.lrc_time_text_size)); - mTextGravity = ta.getInteger(R.styleable.LrcView_lrcTextGravity, LrcEntry.GRAVITY_CENTER); - - ta.recycle(); - - mDrawableWidth = (int) getResources().getDimension(R.dimen.lrc_drawable_width); - mTimeTextWidth = (int) getResources().getDimension(R.dimen.lrc_time_width); - - mLrcPaint.setAntiAlias(true); - mLrcPaint.setTextSize(mCurrentTextSize); - mLrcPaint.setTextAlign(Paint.Align.LEFT); - mTimePaint.setAntiAlias(true); - mTimePaint.setTextSize(timeTextSize); - mTimePaint.setTextAlign(Paint.Align.CENTER); - //noinspection SuspiciousNameCombination - mTimePaint.setStrokeWidth(timelineHeight); - mTimePaint.setStrokeCap(Paint.Cap.ROUND); - mTimeFontMetrics = mTimePaint.getFontMetrics(); - - mGestureDetector = new GestureDetector(getContext(), mSimpleOnGestureListener); - mGestureDetector.setIsLongpressEnabled(false); - mScroller = new Scroller(getContext()); - } - - /** 设置非当前行歌词字体颜色 */ - public void setNormalColor(int normalColor) { - mNormalTextColor = normalColor; - postInvalidate(); - } - - /** 普通歌词文本字体大小 */ - public void setNormalTextSize(float size) { - mNormalTextSize = size; - } - - /** 当前歌词文本字体大小 */ - public void setCurrentTextSize(float size) { - mCurrentTextSize = size; - } - - /** 设置当前行歌词的字体颜色 */ - public void setCurrentColor(int currentColor) { - mCurrentTextColor = currentColor; - postInvalidate(); - } - - /** 设置拖动歌词时选中歌词的字体颜色 */ - public void setTimelineTextColor(int timelineTextColor) { - mTimelineTextColor = timelineTextColor; - postInvalidate(); - } - - /** 设置拖动歌词时时间线的颜色 */ - public void setTimelineColor(int timelineColor) { - mTimelineColor = timelineColor; - postInvalidate(); - } - - /** 设置拖动歌词时右侧时间字体颜色 */ - public void setTimeTextColor(int timeTextColor) { - mTimeTextColor = timeTextColor; - postInvalidate(); - } - - /** - * 设置歌词是否允许拖动 - * - * @param draggable 是否允许拖动 - * @param onPlayClickListener 设置歌词拖动后播放按钮点击监听器,如果允许拖动,则不能为 null - */ - public void setDraggable(boolean draggable, OnPlayClickListener onPlayClickListener) { - if (draggable) { - if (onPlayClickListener == null) { - throw new IllegalArgumentException( - "if draggable == true, onPlayClickListener must not be null"); - } - mOnPlayClickListener = onPlayClickListener; - } else { - mOnPlayClickListener = null; + public LrcView(Context context, AttributeSet attrs) { + this(context, attrs, 0); } - } - /** - * 设置播放按钮点击监听器 - * - * @param onPlayClickListener 如果为非 null ,则激活歌词拖动功能,否则将将禁用歌词拖动功能 - * @deprecated use {@link #setDraggable(boolean, OnPlayClickListener)} instead - */ - @Deprecated - public void setOnPlayClickListener(OnPlayClickListener onPlayClickListener) { - mOnPlayClickListener = onPlayClickListener; - } + public LrcView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(attrs); + } - /** 设置歌词为空时屏幕中央显示的文字,如“暂无歌词” */ - public void setLabel(String label) { - runOnUi( - () -> { - mDefaultLabel = label; - invalidate(); - }); - } - - /** - * 加载歌词文件 - * - * @param lrcFile 歌词文件 - */ - public void loadLrc(File lrcFile) { - loadLrc(lrcFile, null); - } - - /** - * 加载双语歌词文件,两种语言的歌词时间戳需要一致 - * - * @param mainLrcFile 第一种语言歌词文件 - * @param secondLrcFile 第二种语言歌词文件 - */ - public void loadLrc(File mainLrcFile, File secondLrcFile) { - runOnUi( - () -> { - reset(); - - StringBuilder sb = new StringBuilder("file://"); - sb.append(mainLrcFile.getPath()); - if (secondLrcFile != null) { - sb.append("#").append(secondLrcFile.getPath()); - } - String flag = sb.toString(); - setFlag(flag); - new AsyncTask>() { - @Override - protected List doInBackground(File... params) { - return LrcUtils.parseLrc(params); - } - - @Override - protected void onPostExecute(List lrcEntries) { - if (getFlag() == flag) { - onLrcLoaded(lrcEntries); - setFlag(null); - } - } - }.execute(mainLrcFile, secondLrcFile); - }); - } - - /** - * 加载歌词文本 - * - * @param lrcText 歌词文本 - */ - public void loadLrc(String lrcText) { - loadLrc(lrcText, null); - } - - /** - * 加载双语歌词文本,两种语言的歌词时间戳需要一致 - * - * @param mainLrcText 第一种语言歌词文本 - * @param secondLrcText 第二种语言歌词文本 - */ - public void loadLrc(String mainLrcText, String secondLrcText) { - runOnUi( - () -> { - reset(); - - StringBuilder sb = new StringBuilder("file://"); - sb.append(mainLrcText); - if (secondLrcText != null) { - sb.append("#").append(secondLrcText); - } - String flag = sb.toString(); - setFlag(flag); - new AsyncTask>() { - @Override - protected List doInBackground(String... params) { - return LrcUtils.parseLrc(params); - } - - @Override - protected void onPostExecute(List lrcEntries) { - if (getFlag() == flag) { - onLrcLoaded(lrcEntries); - setFlag(null); - } - } - }.execute(mainLrcText, secondLrcText); - }); - } - - /** - * 加载在线歌词,默认使用 utf-8 编码 - * - * @param lrcUrl 歌词文件的网络地址 - */ - public void loadLrcByUrl(String lrcUrl) { - loadLrcByUrl(lrcUrl, "utf-8"); - } - - /** - * 加载在线歌词 - * - * @param lrcUrl 歌词文件的网络地址 - * @param charset 编码格式 - */ - public void loadLrcByUrl(String lrcUrl, String charset) { - String flag = "url://" + lrcUrl; - setFlag(flag); - new AsyncTask() { - @Override - protected String doInBackground(String... params) { - return LrcUtils.getContentFromNetwork(params[0], params[1]); - } - - @Override - protected void onPostExecute(String lrcText) { - if (getFlag() == flag) { - loadLrc(lrcText); + private void init(AttributeSet attrs) { + TypedArray ta = getContext().obtainStyledAttributes(attrs, R.styleable.LrcView); + mCurrentTextSize = + ta.getDimension( + R.styleable.LrcView_lrcTextSize, getResources().getDimension(R.dimen.lrc_text_size)); + mNormalTextSize = + ta.getDimension( + R.styleable.LrcView_lrcNormalTextSize, + getResources().getDimension(R.dimen.lrc_text_size)); + if (mNormalTextSize == 0) { + mNormalTextSize = mCurrentTextSize; } - } - }.execute(lrcUrl, charset); - } - /** - * 歌词是否有效 - * - * @return true,如果歌词有效,否则false - */ - public boolean hasLrc() { - return !mLrcEntryList.isEmpty(); - } + mDividerHeight = + ta.getDimension( + R.styleable.LrcView_lrcDividerHeight, + getResources().getDimension(R.dimen.lrc_divider_height)); + int defDuration = getResources().getInteger(R.integer.lrc_animation_duration); + mAnimationDuration = ta.getInt(R.styleable.LrcView_lrcAnimationDuration, defDuration); + mAnimationDuration = (mAnimationDuration < 0) ? defDuration : mAnimationDuration; + mNormalTextColor = + ta.getColor( + R.styleable.LrcView_lrcNormalTextColor, + getResources().getColor(R.color.lrc_normal_text_color)); + mCurrentTextColor = + ta.getColor( + R.styleable.LrcView_lrcCurrentTextColor, + getResources().getColor(R.color.lrc_current_text_color)); + mTimelineTextColor = + ta.getColor( + R.styleable.LrcView_lrcTimelineTextColor, + getResources().getColor(R.color.lrc_timeline_text_color)); + mDefaultLabel = ta.getString(R.styleable.LrcView_lrcLabel); + mDefaultLabel = + TextUtils.isEmpty(mDefaultLabel) ? getContext().getString(R.string.empty) : mDefaultLabel; + mLrcPadding = ta.getDimension(R.styleable.LrcView_lrcPadding, 0); + mTimelineColor = + ta.getColor( + R.styleable.LrcView_lrcTimelineColor, + getResources().getColor(R.color.lrc_timeline_color)); + float timelineHeight = + ta.getDimension( + R.styleable.LrcView_lrcTimelineHeight, + getResources().getDimension(R.dimen.lrc_timeline_height)); + mPlayDrawable = ta.getDrawable(R.styleable.LrcView_lrcPlayDrawable); + mPlayDrawable = + (mPlayDrawable == null) + ? ContextCompat.getDrawable(getContext(), R.drawable.ic_play_arrow) + : mPlayDrawable; + mTimeTextColor = + ta.getColor( + R.styleable.LrcView_lrcTimeTextColor, + getResources().getColor(R.color.lrc_time_text_color)); + float timeTextSize = + ta.getDimension( + R.styleable.LrcView_lrcTimeTextSize, + getResources().getDimension(R.dimen.lrc_time_text_size)); + mTextGravity = ta.getInteger(R.styleable.LrcView_lrcTextGravity, LrcEntry.GRAVITY_CENTER); - /** - * 刷新歌词 - * - * @param time 当前播放时间 - */ - public void updateTime(long time) { - runOnUi( - () -> { - if (!hasLrc()) { - return; - } + ta.recycle(); - int line = findShowLine(time); - if (line != mCurrentLine) { - mCurrentLine = line; - if (!isShowTimeline) { - smoothScrollTo(line); - } else { - invalidate(); - } - } - }); - } + mDrawableWidth = (int) getResources().getDimension(R.dimen.lrc_drawable_width); + mTimeTextWidth = (int) getResources().getDimension(R.dimen.lrc_time_width); - /** - * 将歌词滚动到指定时间 - * - * @param time 指定的时间 - * @deprecated 请使用 {@link #updateTime(long)} 代替 - */ - @Deprecated - public void onDrag(long time) { - updateTime(time); - } - - @Override - protected void onLayout(boolean changed, int left, int top, int right, int bottom) { - super.onLayout(changed, left, top, right, bottom); - if (changed) { - initPlayDrawable(); - initEntryList(); - if (hasLrc()) { - smoothScrollTo(mCurrentLine, 0L); - } - } - } - - @Override - protected void onDraw(Canvas canvas) { - super.onDraw(canvas); - - int centerY = getHeight() / 2; - - // 无歌词文件 - if (!hasLrc()) { - mLrcPaint.setColor(mCurrentTextColor); - @SuppressLint("DrawAllocation") - StaticLayout staticLayout = - new StaticLayout( - mDefaultLabel, - mLrcPaint, - (int) getLrcWidth(), - Layout.Alignment.ALIGN_CENTER, - 1f, - 0f, - false); - drawText(canvas, staticLayout, centerY); - return; - } - - int centerLine = getCenterLine(); - - if (isShowTimeline) { - mPlayDrawable.draw(canvas); - - mTimePaint.setColor(mTimelineColor); - canvas.drawLine(mTimeTextWidth, centerY, getWidth() - mTimeTextWidth, centerY, mTimePaint); - - mTimePaint.setColor(mTimeTextColor); - String timeText = LrcUtils.formatTime(mLrcEntryList.get(centerLine).getTime()); - float timeX = getWidth() - mTimeTextWidth / 2; - float timeY = centerY - (mTimeFontMetrics.descent + mTimeFontMetrics.ascent) / 2; - canvas.drawText(timeText, timeX, timeY, mTimePaint); - } - - canvas.translate(0, mOffset); - - float y = 0; - for (int i = 0; i < mLrcEntryList.size(); i++) { - if (i > 0) { - y += - ((mLrcEntryList.get(i - 1).getHeight() + mLrcEntryList.get(i).getHeight()) >> 1) - + mDividerHeight; - } - if (BuildConfig.DEBUG) { - // mLrcPaint.setTypeface(ResourcesCompat.getFont(getContext(), R.font.sans)); - } - if (i == mCurrentLine) { + mLrcPaint.setAntiAlias(true); mLrcPaint.setTextSize(mCurrentTextSize); - mLrcPaint.setColor(mCurrentTextColor); - } else if (isShowTimeline && i == centerLine) { - mLrcPaint.setColor(mTimelineTextColor); - } else { - mLrcPaint.setTextSize(mNormalTextSize); - mLrcPaint.setColor(mNormalTextColor); - } - drawText(canvas, mLrcEntryList.get(i).getStaticLayout(), y); - } - } + mLrcPaint.setTextAlign(Paint.Align.LEFT); + mTimePaint.setAntiAlias(true); + mTimePaint.setTextSize(timeTextSize); + mTimePaint.setTextAlign(Paint.Align.CENTER); + //noinspection SuspiciousNameCombination + mTimePaint.setStrokeWidth(timelineHeight); + mTimePaint.setStrokeCap(Paint.Cap.ROUND); + mTimeFontMetrics = mTimePaint.getFontMetrics(); - /** - * 画一行歌词 - * - * @param y 歌词中心 Y 坐标 - */ - private void drawText(Canvas canvas, StaticLayout staticLayout, float y) { - canvas.save(); - canvas.translate(mLrcPadding, y - (staticLayout.getHeight() >> 1)); - staticLayout.draw(canvas); - canvas.restore(); - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (event.getAction() == MotionEvent.ACTION_UP - || event.getAction() == MotionEvent.ACTION_CANCEL) { - isTouching = false; - if (hasLrc() && !isFling) { - adjustCenter(); - postDelayed(hideTimelineRunnable, TIMELINE_KEEP_TIME); - } - } - return mGestureDetector.onTouchEvent(event); - } - - @Override - public void computeScroll() { - if (mScroller.computeScrollOffset()) { - mOffset = mScroller.getCurrY(); - invalidate(); + mGestureDetector = new GestureDetector(getContext(), mSimpleOnGestureListener); + mGestureDetector.setIsLongpressEnabled(false); + mScroller = new Scroller(getContext()); } - if (isFling && mScroller.isFinished()) { - isFling = false; - if (hasLrc() && !isTouching) { - adjustCenter(); - postDelayed(hideTimelineRunnable, TIMELINE_KEEP_TIME); - } - } - } - - @Override - protected void onDetachedFromWindow() { - removeCallbacks(hideTimelineRunnable); - super.onDetachedFromWindow(); - } - - private void onLrcLoaded(List entryList) { - if (entryList != null && !entryList.isEmpty()) { - mLrcEntryList.addAll(entryList); + public void setCurrentColor(int currentColor) { + mCurrentTextColor = currentColor; + postInvalidate(); } - Collections.sort(mLrcEntryList); - - initEntryList(); - invalidate(); - } - - private void initPlayDrawable() { - int l = (mTimeTextWidth - mDrawableWidth) / 2; - int t = getHeight() / 2 - mDrawableWidth / 2; - int r = l + mDrawableWidth; - int b = t + mDrawableWidth; - mPlayDrawable.setBounds(l, t, r, b); - } - - private void initEntryList() { - if (!hasLrc() || getWidth() == 0) { - return; + public void setTimelineTextColor(int timelineTextColor) { + mTimelineTextColor = timelineTextColor; + postInvalidate(); } - for (LrcEntry lrcEntry : mLrcEntryList) { - lrcEntry.init(mLrcPaint, (int) getLrcWidth(), mTextGravity); + public void setTimelineColor(int timelineColor) { + mTimelineColor = timelineColor; + postInvalidate(); } - mOffset = getHeight() / 2; - } - private void reset() { - endAnimation(); - mScroller.forceFinished(true); - isShowTimeline = false; - isTouching = false; - isFling = false; - removeCallbacks(hideTimelineRunnable); - mLrcEntryList.clear(); - mOffset = 0; - mCurrentLine = 0; - invalidate(); - } + public void setTimeTextColor(int timeTextColor) { + mTimeTextColor = timeTextColor; + postInvalidate(); + } - /** 将中心行微调至正中心 */ - private void adjustCenter() { - smoothScrollTo(getCenterLine(), ADJUST_DURATION); - } - /** 滚动到某一行 */ - private void smoothScrollTo(int line) { - smoothScrollTo(line, mAnimationDuration); - } + public void setDraggable(boolean draggable, OnPlayClickListener onPlayClickListener) { + if (draggable) { + if (onPlayClickListener == null) { + throw new IllegalArgumentException( + "if draggable == true, onPlayClickListener must not be null"); + } + mOnPlayClickListener = onPlayClickListener; + } else { + mOnPlayClickListener = null; + } + } - /** 滚动到某一行 */ - private void smoothScrollTo(int line, long duration) { - float offset = getOffset(line); - endAnimation(); + public void setLabel(String label) { + runOnUi( + () -> { + mDefaultLabel = label; + invalidate(); + }); + } - mAnimator = ValueAnimator.ofFloat(mOffset, offset); - mAnimator.setDuration(duration); - mAnimator.setInterpolator(new LinearInterpolator()); - mAnimator.addUpdateListener( - animation -> { - mOffset = (float) animation.getAnimatedValue(); - invalidate(); + public void loadLrc(File lrcFile) { + loadLrc(lrcFile, null); + } + + public void loadLrc(File mainLrcFile, File secondLrcFile) { + runOnUi(() -> { + reset(); + + StringBuilder sb = new StringBuilder("file://"); + sb.append(mainLrcFile.getPath()); + if (secondLrcFile != null) { + sb.append("#").append(secondLrcFile.getPath()); + } + String flag = sb.toString(); + setFlag(flag); + new AsyncTask>() { + @Override + protected List doInBackground(File... params) { + return LrcUtils.parseLrc(params); + } + + @Override + protected void onPostExecute(List lrcEntries) { + if (getFlag() == flag) { + onLrcLoaded(lrcEntries); + setFlag(null); + } + } + }.execute(mainLrcFile, secondLrcFile); }); - mAnimator.start(); - } - - /** 结束滚动动画 */ - private void endAnimation() { - if (mAnimator != null && mAnimator.isRunning()) { - mAnimator.end(); } - } - /** 二分法查找当前时间应该显示的行数(最后一个 <= time 的行数) */ - private int findShowLine(long time) { - int left = 0; - int right = mLrcEntryList.size(); - while (left <= right) { - int middle = (left + right) / 2; - long middleTime = mLrcEntryList.get(middle).getTime(); + public void loadLrc(String lrcText) { + loadLrc(lrcText, null); + } - if (time < middleTime) { - right = middle - 1; - } else { - if (middle + 1 >= mLrcEntryList.size() || time < mLrcEntryList.get(middle + 1).getTime()) { - return middle; + public void loadLrc(String mainLrcText, String secondLrcText) { + runOnUi( + () -> { + reset(); + + StringBuilder sb = new StringBuilder("file://"); + sb.append(mainLrcText); + if (secondLrcText != null) { + sb.append("#").append(secondLrcText); + } + String flag = sb.toString(); + setFlag(flag); + new AsyncTask>() { + @Override + protected List doInBackground(String... params) { + return LrcUtils.parseLrc(params); + } + + @Override + protected void onPostExecute(List lrcEntries) { + if (getFlag() == flag) { + onLrcLoaded(lrcEntries); + setFlag(null); + } + } + }.execute(mainLrcText, secondLrcText); + }); + } + + public boolean hasLrc() { + return !mLrcEntryList.isEmpty(); + } + + public void updateTime(long time) { + runOnUi( + () -> { + if (!hasLrc()) { + return; + } + + int line = findShowLine(time); + if (line != mCurrentLine) { + mCurrentLine = line; + if (!isShowTimeline) { + smoothScrollTo(line); + } else { + invalidate(); + } + } + }); + } + + @Deprecated + public void onDrag(long time) { + updateTime(time); + } + + @Override + protected void onLayout(boolean changed, int left, int top, int right, int bottom) { + super.onLayout(changed, left, top, right, bottom); + if (changed) { + initPlayDrawable(); + initEntryList(); + if (hasLrc()) { + smoothScrollTo(mCurrentLine, 0L); + } + } + } + + @Override + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + + int centerY = getHeight() / 2; + + if (!hasLrc()) { + mLrcPaint.setColor(mCurrentTextColor); + @SuppressLint("DrawAllocation") + StaticLayout staticLayout = + new StaticLayout( + mDefaultLabel, + mLrcPaint, + (int) getLrcWidth(), + Layout.Alignment.ALIGN_CENTER, + 1f, + 0f, + false); + drawText(canvas, staticLayout, centerY); + return; } - left = middle + 1; - } + int centerLine = getCenterLine(); + + if (isShowTimeline) { + mPlayDrawable.draw(canvas); + + mTimePaint.setColor(mTimelineColor); + canvas.drawLine(mTimeTextWidth, centerY, getWidth() - mTimeTextWidth, centerY, mTimePaint); + + mTimePaint.setColor(mTimeTextColor); + String timeText = LrcUtils.formatTime(mLrcEntryList.get(centerLine).getTime()); + float timeX = getWidth() - mTimeTextWidth / 2; + float timeY = centerY - (mTimeFontMetrics.descent + mTimeFontMetrics.ascent) / 2; + canvas.drawText(timeText, timeX, timeY, mTimePaint); + } + + canvas.translate(0, mOffset); + + float y = 0; + for (int i = 0; i < mLrcEntryList.size(); i++) { + if (i > 0) { + y += + ((mLrcEntryList.get(i - 1).getHeight() + mLrcEntryList.get(i).getHeight()) >> 1) + + mDividerHeight; + } + if (BuildConfig.DEBUG) { + // mLrcPaint.setTypeface(ResourcesCompat.getFont(getContext(), R.font.sans)); + } + if (i == mCurrentLine) { + mLrcPaint.setTextSize(mCurrentTextSize); + mLrcPaint.setColor(mCurrentTextColor); + } else if (isShowTimeline && i == centerLine) { + mLrcPaint.setColor(mTimelineTextColor); + } else { + mLrcPaint.setTextSize(mNormalTextSize); + mLrcPaint.setColor(mNormalTextColor); + } + drawText(canvas, mLrcEntryList.get(i).getStaticLayout(), y); + } } - return 0; - } - - /** 获取当前在视图中央的行数 */ - private int getCenterLine() { - int centerLine = 0; - float minDistance = Float.MAX_VALUE; - for (int i = 0; i < mLrcEntryList.size(); i++) { - if (Math.abs(mOffset - getOffset(i)) < minDistance) { - minDistance = Math.abs(mOffset - getOffset(i)); - centerLine = i; - } - } - return centerLine; - } - - /** 获取歌词距离视图顶部的距离 采用懒加载方式 */ - private float getOffset(int line) { - if (mLrcEntryList.get(line).getOffset() == Float.MIN_VALUE) { - float offset = getHeight() / 2; - for (int i = 1; i <= line; i++) { - offset -= - ((mLrcEntryList.get(i - 1).getHeight() + mLrcEntryList.get(i).getHeight()) >> 1) - + mDividerHeight; - } - mLrcEntryList.get(line).setOffset(offset); + private void drawText(Canvas canvas, StaticLayout staticLayout, float y) { + canvas.save(); + canvas.translate(mLrcPadding, y - (staticLayout.getHeight() >> 1)); + staticLayout.draw(canvas); + canvas.restore(); } - return mLrcEntryList.get(line).getOffset(); - } - - /** 获取歌词宽度 */ - private float getLrcWidth() { - return getWidth() - mLrcPadding * 2; - } - - /** 在主线程中运行 */ - private void runOnUi(Runnable r) { - if (Looper.myLooper() == Looper.getMainLooper()) { - r.run(); - } else { - post(r); + @Override + public boolean onTouchEvent(MotionEvent event) { + if (event.getAction() == MotionEvent.ACTION_UP + || event.getAction() == MotionEvent.ACTION_CANCEL) { + isTouching = false; + if (hasLrc() && !isFling) { + adjustCenter(); + postDelayed(hideTimelineRunnable, TIMELINE_KEEP_TIME); + } + } + return mGestureDetector.onTouchEvent(event); } - } - private Object getFlag() { - return mFlag; - } + @Override + public void computeScroll() { + if (mScroller.computeScrollOffset()) { + mOffset = mScroller.getCurrY(); + invalidate(); + } - private void setFlag(Object flag) { - this.mFlag = flag; - } + if (isFling && mScroller.isFinished()) { + isFling = false; + if (hasLrc() && !isTouching) { + adjustCenter(); + postDelayed(hideTimelineRunnable, TIMELINE_KEEP_TIME); + } + } + } - /** 播放按钮点击监听器,点击后应该跳转到指定播放位置 */ - public interface OnPlayClickListener { - /** - * 播放按钮被点击,应该跳转到指定播放位置 - * - * @return 是否成功消费该事件,如果成功消费,则会更新UI - */ - boolean onPlayClick(long time); - } + @Override + protected void onDetachedFromWindow() { + removeCallbacks(hideTimelineRunnable); + super.onDetachedFromWindow(); + } + + private void onLrcLoaded(List entryList) { + if (entryList != null && !entryList.isEmpty()) { + mLrcEntryList.addAll(entryList); + } + + Collections.sort(mLrcEntryList); + + initEntryList(); + invalidate(); + } + + private void initPlayDrawable() { + int l = (mTimeTextWidth - mDrawableWidth) / 2; + int t = getHeight() / 2 - mDrawableWidth / 2; + int r = l + mDrawableWidth; + int b = t + mDrawableWidth; + mPlayDrawable.setBounds(l, t, r, b); + } + + private void initEntryList() { + if (!hasLrc() || getWidth() == 0) { + return; + } + + for (LrcEntry lrcEntry : mLrcEntryList) { + lrcEntry.init(mLrcPaint, (int) getLrcWidth(), mTextGravity); + } + + mOffset = getHeight() / 2; + } + + private void reset() { + endAnimation(); + mScroller.forceFinished(true); + isShowTimeline = false; + isTouching = false; + isFling = false; + removeCallbacks(hideTimelineRunnable); + mLrcEntryList.clear(); + mOffset = 0; + mCurrentLine = 0; + invalidate(); + } + + private void adjustCenter() { + smoothScrollTo(getCenterLine(), ADJUST_DURATION); + } + + private void smoothScrollTo(int line) { + smoothScrollTo(line, mAnimationDuration); + } + + private void smoothScrollTo(int line, long duration) { + float offset = getOffset(line); + endAnimation(); + + mAnimator = ValueAnimator.ofFloat(mOffset, offset); + mAnimator.setDuration(duration); + mAnimator.setInterpolator(new LinearInterpolator()); + mAnimator.addUpdateListener( + animation -> { + mOffset = (float) animation.getAnimatedValue(); + invalidate(); + }); + mAnimator.start(); + } + + private void endAnimation() { + if (mAnimator != null && mAnimator.isRunning()) { + mAnimator.end(); + } + } + + private int findShowLine(long time) { + int left = 0; + int right = mLrcEntryList.size(); + while (left <= right) { + int middle = (left + right) / 2; + long middleTime = mLrcEntryList.get(middle).getTime(); + + if (time < middleTime) { + right = middle - 1; + } else { + if (middle + 1 >= mLrcEntryList.size() || time < mLrcEntryList.get(middle + 1).getTime()) { + return middle; + } + + left = middle + 1; + } + } + + return 0; + } + + private int getCenterLine() { + int centerLine = 0; + float minDistance = Float.MAX_VALUE; + for (int i = 0; i < mLrcEntryList.size(); i++) { + if (Math.abs(mOffset - getOffset(i)) < minDistance) { + minDistance = Math.abs(mOffset - getOffset(i)); + centerLine = i; + } + } + return centerLine; + } + + private float getOffset(int line) { + if (mLrcEntryList.get(line).getOffset() == Float.MIN_VALUE) { + float offset = getHeight() / 2; + for (int i = 1; i <= line; i++) { + offset -= + ((mLrcEntryList.get(i - 1).getHeight() + mLrcEntryList.get(i).getHeight()) >> 1) + + mDividerHeight; + } + mLrcEntryList.get(line).setOffset(offset); + } + + return mLrcEntryList.get(line).getOffset(); + } + + private float getLrcWidth() { + return getWidth() - mLrcPadding * 2; + } + + private void runOnUi(Runnable r) { + if (Looper.myLooper() == Looper.getMainLooper()) { + r.run(); + } else { + post(r); + } + } + + private Object getFlag() { + return mFlag; + } + + private void setFlag(Object flag) { + this.mFlag = flag; + } + + public interface OnPlayClickListener { + boolean onPlayClick(long time); + } } diff --git a/app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.kt index 6db2a55c1..2f7aff94c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.kt @@ -117,7 +117,7 @@ object LyricUtil { return "$lrcRootPath$title - $artist.lrc" } - fun getLrcOriginalPath(filePath: String): String { + private fun getLrcOriginalPath(filePath: String): String { return filePath.replace(filePath.substring(filePath.lastIndexOf(".") + 1), "lrc") } @@ -160,9 +160,9 @@ object LyricUtil { } fun getEmbeddedSyncedLyrics(data: String): String? { - val embeddedLyrics = try{ - AudioFileIO.read(File(data)).tagOrCreateDefault.getFirst(FieldKey.LYRICS) - } catch(e: Exception){ + val embeddedLyrics = try { + AudioFileIO.read(File(data)).tagOrCreateDefault.getFirst(FieldKey.LYRICS) + } catch (e: Exception) { return null } return if (AbsSynchronizedLyrics.isSynchronized(embeddedLyrics)) { diff --git a/app/src/main/res/menu/menu_search.xml b/app/src/main/res/menu/menu_lyrics.xml similarity index 100% rename from app/src/main/res/menu/menu_search.xml rename to app/src/main/res/menu/menu_lyrics.xml From 62372ec205b437151db0404f9afb1a92792752f0 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Mon, 20 Jun 2022 14:43:06 +0530 Subject: [PATCH 15/19] Common screen for Normal and Synced the later is preferred --- app/build.gradle | 2 +- .../base/AbsSlidingMusicPanelActivity.kt | 3 +- .../{other => lyrics}/LyricsFragment.kt | 299 +++++++----------- .../player/PlayerAlbumCoverFragment.kt | 9 +- .../playlists/PlaylistDetailsFragment.kt | 3 + .../monkey/retromusic/util/PreferenceUtil.kt | 8 +- app/src/main/res/layout/fragment_lyrics.xml | 63 ++-- .../res/layout/fragment_normal_lyrics.xml | 29 -- .../res/layout/fragment_synced_lyrics.xml | 18 -- app/src/main/res/navigation/main_graph.xml | 2 +- app/src/main/res/values/strings.xml | 2 +- 11 files changed, 177 insertions(+), 261 deletions(-) rename app/src/main/java/code/name/monkey/retromusic/fragments/{other => lyrics}/LyricsFragment.kt (58%) delete mode 100644 app/src/main/res/layout/fragment_normal_lyrics.xml delete mode 100644 app/src/main/res/layout/fragment_synced_lyrics.xml diff --git a/app/build.gradle b/app/build.gradle index 5dedc35c3..12cd27799 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -14,7 +14,7 @@ android { vectorDrawables.useSupportLibrary = true applicationId "code.name.monkey.retromusic" - versionCode 10595 + versionCode 10596 versionName '6.0.2-beta' buildConfigField("String", "GOOGLE_PLAY_LICENSING_KEY", "\"${getProperty(getProperties('../public.properties'), 'GOOGLE_PLAY_LICENSE_KEY')}\"") 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 2ac89e7e8..ab31dd814 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 @@ -234,8 +234,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(), navigationView.labelVisibilityMode = PreferenceUtil.tabTitleMode } TOGGLE_FULL_SCREEN -> { - if (!PreferenceUtil.isFullScreenMode) exitFullscreen() - setEdgeToEdgeOrImmersive() + recreate() } SCREEN_ON_LYRICS -> { keepScreenOn(bottomSheetBehavior.state == STATE_EXPANDED && PreferenceUtil.lyricsScreenOn && PreferenceUtil.showLyrics || PreferenceUtil.isScreenOnEnabled) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/lyrics/LyricsFragment.kt similarity index 58% rename from app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt rename to app/src/main/java/code/name/monkey/retromusic/fragments/lyrics/LyricsFragment.kt index e27e31c06..cd7bceb38 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/lyrics/LyricsFragment.kt @@ -12,11 +12,10 @@ * See the GNU General Public License for more details. * */ -package code.name.monkey.retromusic.fragments.other +package code.name.monkey.retromusic.fragments.lyrics import android.annotation.SuppressLint import android.app.Activity -import android.content.Intent import android.net.Uri import android.os.Bundle import android.provider.MediaStore @@ -26,22 +25,19 @@ import androidx.activity.result.ActivityResultLauncher import androidx.activity.result.IntentSenderRequest import androidx.activity.result.contract.ActivityResultContracts import androidx.core.view.isVisible -import androidx.fragment.app.Fragment -import androidx.fragment.app.FragmentActivity import androidx.navigation.fragment.findNavController import androidx.transition.Fade -import androidx.viewpager2.adapter.FragmentStateAdapter import code.name.monkey.appthemehelper.common.ATHToolbarActivity import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.retromusic.R import code.name.monkey.retromusic.activities.tageditor.TagWriter import code.name.monkey.retromusic.databinding.FragmentLyricsBinding -import code.name.monkey.retromusic.databinding.FragmentNormalLyricsBinding -import code.name.monkey.retromusic.databinding.FragmentSyncedLyricsBinding -import code.name.monkey.retromusic.extensions.* +import code.name.monkey.retromusic.extensions.accentColor +import code.name.monkey.retromusic.extensions.materialDialog +import code.name.monkey.retromusic.extensions.openUrl +import code.name.monkey.retromusic.extensions.uri import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment -import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper import code.name.monkey.retromusic.lyrics.LrcView @@ -51,7 +47,6 @@ import code.name.monkey.retromusic.util.FileUtils import code.name.monkey.retromusic.util.LyricUtil import code.name.monkey.retromusic.util.UriUtil import com.afollestad.materialdialogs.input.input -import com.google.android.material.tabs.TabLayoutMediator import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.launch import org.jaudiotagger.audio.AudioFileIO @@ -59,14 +54,23 @@ import org.jaudiotagger.tag.FieldKey import java.io.File import java.io.FileOutputStream import java.util.* +import kotlin.collections.set -class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) { +class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics), + MusicProgressViewUpdateHelper.Callback { private var _binding: FragmentLyricsBinding? = null private val binding get() = _binding!! private lateinit var song: Song - private lateinit var lyricsSectionsAdapter: LyricsSectionsAdapter + private lateinit var normalLyricsLauncher: ActivityResultLauncher + private lateinit var editSyncedLyricsLauncher: ActivityResultLauncher + + private lateinit var cacheFile: File + private var syncedLyrics: String = "" + private lateinit var syncedFileUri: Uri + + private var lyricsType: LyricsType = LyricsType.NORMAL_LYRICS private val googleSearchLrcUrl: String get() { @@ -77,13 +81,7 @@ class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) { return baseUrl } - private lateinit var normalLyricsLauncher: ActivityResultLauncher - private lateinit var newSyncedLyricsLauncher: ActivityResultLauncher - private lateinit var editSyncedLyricsLauncher: ActivityResultLauncher - - private lateinit var cacheFile: File - private var syncedLyrics: String = "" - private lateinit var syncedFileUri: Uri + private lateinit var updateHelper: MusicProgressViewUpdateHelper override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) @@ -94,14 +92,6 @@ class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) { FileUtils.copyFileToUri(requireContext(), cacheFile, song.uri) } } - newSyncedLyricsLauncher = - registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> - if (result.resultCode == Activity.RESULT_OK) { - context?.contentResolver?.openOutputStream(result.data?.data!!)?.use { - it.write(syncedLyrics.toByteArray()) - } - } - } editSyncedLyricsLauncher = registerForActivityResult(ActivityResultContracts.StartIntentSenderForResult()) { if (it.resultCode == Activity.RESULT_OK) { @@ -118,36 +108,42 @@ class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) { super.onViewCreated(view, savedInstanceState) enterTransition = Fade() exitTransition = Fade() - updateTitleSong() - lyricsSectionsAdapter = LyricsSectionsAdapter(requireActivity()) _binding = FragmentLyricsBinding.bind(view) - binding.container.transitionName = "lyrics" + updateHelper = MusicProgressViewUpdateHelper(this, 500, 1000) + updateTitleSong() + setupLyricsView() + loadLyrics() setupWakelock() setupViews() setupToolbar() } - private fun setupViews() { - binding.lyricsPager.adapter = lyricsSectionsAdapter - TabLayoutMediator(binding.tabLyrics, binding.lyricsPager) { tab, position -> - tab.text = when (position) { - 0 -> getString(R.string.synced_lyrics) - 1 -> getString(R.string.normal_lyrics) - else -> "" - } - }.attach() -// lyricsPager.isUserInputEnabled = false + private fun setupLyricsView() { + binding.lyricsView.apply { + setCurrentColor(accentColor()) + setTimeTextColor(accentColor()) + setTimelineColor(accentColor()) + setTimelineTextColor(accentColor()) + setDraggable(true, LrcView.OnPlayClickListener { + MusicPlayerRemote.seekTo(it.toInt()) + return@OnPlayClickListener true + }) + } + } - binding.tabLyrics.setSelectedTabIndicatorColor(accentColor()) - binding.tabLyrics.setTabTextColors(textColorSecondary(), accentColor()) + override fun onUpdateProgressViews(progress: Int, total: Int) { + binding.lyricsView.updateTime(progress.toLong()) + } + + private fun setupViews() { binding.editButton.accentColor() binding.editButton.setOnClickListener { - when (binding.lyricsPager.currentItem) { - 0 -> { + when (lyricsType) { + LyricsType.SYNCED_LYRICS -> { editSyncedLyrics() } - 1 -> { + LyricsType.NORMAL_LYRICS -> { editNormalLyrics() } } @@ -157,11 +153,13 @@ class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) { override fun onPlayingMetaChanged() { super.onPlayingMetaChanged() updateTitleSong() + loadLyrics() } override fun onServiceConnected() { super.onServiceConnected() updateTitleSong() + loadLyrics() } private fun updateTitleSong() { @@ -181,7 +179,7 @@ class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) { } override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { - inflater.inflate(R.menu.menu_search, menu) + inflater.inflate(R.menu.menu_lyrics, menu) ToolbarContentTintHelper.handleOnCreateOptionsMenu( requireContext(), binding.toolbar, @@ -197,17 +195,18 @@ class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) { return false } - @SuppressLint("CheckResult") - private fun editNormalLyrics() { - var content = "" - val file = File(MusicPlayerRemote.currentSong.data) - try { - content = AudioFileIO.read(file).tagOrCreateDefault.getFirst(FieldKey.LYRICS) + private fun editNormalLyrics(lyrics: String? = null) { + val file = File(song.data) + val content = lyrics ?: try { + AudioFileIO.read(file).tagOrCreateDefault.getFirst(FieldKey.LYRICS) } catch (e: Exception) { e.printStackTrace() + "" } + val song = song + materialDialog().show { title(res = R.string.edit_normal_lyrics) input( @@ -217,7 +216,6 @@ class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) { ) { _, input -> val fieldKeyValueMap = EnumMap(FieldKey::class.java) fieldKeyValueMap[FieldKey.LYRICS] = input.toString() - syncedLyrics = input.toString() GlobalScope.launch { if (VersionUtils.hasR()) { cacheFile = TagWriter.writeTagsToFilesR( @@ -244,7 +242,7 @@ class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) { } } positiveButton(res = R.string.save) { - (lyricsSectionsAdapter.fragments[1].first as NormalLyrics).loadNormalLyrics() + loadNormalLyrics() } negativeButton(res = android.R.string.cancel) } @@ -252,9 +250,10 @@ class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) { @SuppressLint("CheckResult") - private fun editSyncedLyrics() { - val content: String = LyricUtil.getStringFromLrc(LyricUtil.getSyncedLyricsFile(song)) + private fun editSyncedLyrics(lyrics: String? = null) { + val content = lyrics ?: LyricUtil.getStringFromLrc(LyricUtil.getSyncedLyricsFile(song)) + val song = song materialDialog().show { title(res = R.string.edit_synced_lyrics) input( @@ -277,145 +276,86 @@ class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) { IntentSenderRequest.Builder(pendingIntent).build() ) } else { - val intent = Intent(Intent.ACTION_CREATE_DOCUMENT) - intent.addCategory(Intent.CATEGORY_OPENABLE) - intent.type = "*/*" - intent.putExtra( - Intent.EXTRA_TITLE, - LyricUtil.getLrcOriginalPath(File(song.data).name) - ) - newSyncedLyricsLauncher.launch(intent) + val fieldKeyValueMap = EnumMap(FieldKey::class.java) + fieldKeyValueMap[FieldKey.LYRICS] = input.toString() + GlobalScope.launch { + cacheFile = TagWriter.writeTagsToFilesR( + requireContext(), + AudioTagInfo(listOf(song.data), fieldKeyValueMap, null) + )[0] + val pendingIntent = MediaStore.createWriteRequest( + requireContext().contentResolver, + listOf(song.uri) + ) + + normalLyricsLauncher.launch( + IntentSenderRequest.Builder(pendingIntent).build() + ) + } } } else { LyricUtil.writeLrc(song, input.toString()) } } positiveButton(res = R.string.save) { - (lyricsSectionsAdapter.fragments[0].first as SyncedLyrics).loadLRCLyrics() + loadLRCLyrics() } negativeButton(res = android.R.string.cancel) } } - class LyricsSectionsAdapter(fragmentActivity: FragmentActivity) : - FragmentStateAdapter(fragmentActivity) { - val fragments = listOf( - Pair(SyncedLyrics(), R.string.synced_lyrics), - Pair(NormalLyrics(), R.string.normal_lyrics) - ) - - - override fun getItemCount(): Int { - return fragments.size + private fun loadNormalLyrics() { + var lyrics: String? = null + val file = File(song.data) + try { + lyrics = AudioFileIO.read(file).tagOrCreateDefault.getFirst(FieldKey.LYRICS) + } catch (e: Exception) { + e.printStackTrace() } + binding.noLyricsFound.isVisible = lyrics.isNullOrEmpty() + binding.normalLyrics.text = lyrics + } - override fun createFragment(position: Int): Fragment { - return fragments[position].first + /** + * @return success + */ + private fun loadLRCLyrics(): Boolean { + binding.lyricsView.setLabel(getString(R.string.empty)) + val lrcFile = LyricUtil.getSyncedLyricsFile(song) + if (lrcFile != null) { + binding.lyricsView.loadLrc(lrcFile) + println("File: ${lrcFile.absolutePath}") + } else { + val embeddedLyrics = LyricUtil.getEmbeddedSyncedLyrics(song.data) + if (embeddedLyrics != null) { + binding.lyricsView.loadLrc(embeddedLyrics) + println("Lyrics: ${embeddedLyrics.substring(0..50)}") + } else { + return false + } + } + return true + } + + private fun loadLyrics() { + lyricsType = if (!loadLRCLyrics()) { + loadNormalLyrics() + LyricsType.SYNCED_LYRICS + } else { + binding.noLyricsFound.isVisible = false + binding.normalLyrics.text = "" + LyricsType.NORMAL_LYRICS } } - class NormalLyrics : AbsMusicServiceFragment(R.layout.fragment_normal_lyrics) { - - private var _binding: FragmentNormalLyricsBinding? = null - private val binding get() = _binding!! - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - _binding = FragmentNormalLyricsBinding.bind(view) - loadNormalLyrics() - super.onViewCreated(view, savedInstanceState) - } - - fun loadNormalLyrics() { - var lyrics: String? = null - val file = File(MusicPlayerRemote.currentSong.data) - try { - lyrics = AudioFileIO.read(file).tagOrCreateDefault.getFirst(FieldKey.LYRICS) - } catch (e: Exception) { - e.printStackTrace() - } - binding.noLyricsFound.isVisible = lyrics.isNullOrEmpty() - binding.normalLyrics.text = lyrics - } - - override fun onPlayingMetaChanged() { - super.onPlayingMetaChanged() - loadNormalLyrics() - } - - override fun onServiceConnected() { - super.onServiceConnected() - loadNormalLyrics() - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + override fun onResume() { + super.onResume() + updateHelper.start() } - class SyncedLyrics : AbsMusicServiceFragment(R.layout.fragment_synced_lyrics), - MusicProgressViewUpdateHelper.Callback { - - private var _binding: FragmentSyncedLyricsBinding? = null - private val binding get() = _binding!! - private lateinit var updateHelper: MusicProgressViewUpdateHelper - - override fun onViewCreated(view: View, savedInstanceState: Bundle?) { - updateHelper = MusicProgressViewUpdateHelper(this, 500, 1000) - _binding = FragmentSyncedLyricsBinding.bind(view) - setupLyricsView() - loadLRCLyrics() - super.onViewCreated(view, savedInstanceState) - } - - fun loadLRCLyrics() { - binding.lyricsView.setLabel(getString(R.string.empty)) - LyricUtil.getSyncedLyricsFile(MusicPlayerRemote.currentSong)?.let { - binding.lyricsView.loadLrc(it) - } - } - - private fun setupLyricsView() { - binding.lyricsView.apply { - setCurrentColor(accentColor()) - setTimeTextColor(accentColor()) - setTimelineColor(accentColor()) - setTimelineTextColor(accentColor()) - setDraggable(true, LrcView.OnPlayClickListener { - MusicPlayerRemote.seekTo(it.toInt()) - return@OnPlayClickListener true - }) - } - } - - override fun onUpdateProgressViews(progress: Int, total: Int) { - binding.lyricsView.updateTime(progress.toLong()) - } - - override fun onPlayingMetaChanged() { - super.onPlayingMetaChanged() - loadLRCLyrics() - } - - override fun onServiceConnected() { - super.onServiceConnected() - loadLRCLyrics() - } - - override fun onResume() { - super.onResume() - updateHelper.start() - } - - override fun onPause() { - super.onPause() - updateHelper.stop() - } - - override fun onDestroyView() { - super.onDestroyView() - _binding = null - } + override fun onPause() { + super.onPause() + updateHelper.stop() } override fun onDestroyView() { @@ -424,4 +364,9 @@ class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) { mainActivity.expandPanel() _binding = null } + + enum class LyricsType { + NORMAL_LYRICS, + SYNCED_LYRICS + } } 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 8cf022dca..06c15d504 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 @@ -46,7 +46,7 @@ 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.LyricsType +import code.name.monkey.retromusic.util.CoverLyricsType import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import code.name.monkey.retromusic.util.logD @@ -174,13 +174,11 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe } override fun onServiceConnected() { - logD("Service Connected") updatePlayingQueue() updateLyrics() } override fun onPlayingMetaChanged() { - logD("Playing Meta Changed") if (viewPager.currentItem != MusicPlayerRemote.position) { viewPager.setCurrentItem(MusicPlayerRemote.position, true) } @@ -188,7 +186,6 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe } override fun onQueueChanged() { - logD("Queue Changed") updatePlayingQueue() } @@ -222,7 +219,7 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe binding.coverLyrics.isVisible = false binding.lyricsView.isVisible = false binding.viewPager.isVisible = true - val lyrics: View = if (PreferenceUtil.lyricsType == LyricsType.REPLACE_COVER) { + val lyrics: View = if (PreferenceUtil.lyricsType == CoverLyricsType.REPLACE_COVER) { ObjectAnimator.ofFloat(viewPager, View.ALPHA, if (visible) 0F else 1F).start() lrcView } else { @@ -242,7 +239,7 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe // Don't show lyrics container for below conditions if (lyricViewNpsList.contains(nps) && PreferenceUtil.showLyrics) { showLyrics(true) - if (PreferenceUtil.lyricsType == LyricsType.REPLACE_COVER) { + if (PreferenceUtil.lyricsType == CoverLyricsType.REPLACE_COVER) { progressViewUpdateHelper?.start() } } else { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt index 1a71944c1..911d6f8ce 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt @@ -23,6 +23,7 @@ import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper import code.name.monkey.retromusic.interfaces.ICabCallback import code.name.monkey.retromusic.interfaces.ICabHolder import code.name.monkey.retromusic.model.Song +import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.RetroColorUtil import code.name.monkey.retromusic.util.ThemedFastScroller import com.afollestad.materialcab.attached.AttachedCab @@ -72,6 +73,8 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli binding.container.transitionName = "playlist" playlist = arguments.extraPlaylist binding.toolbar.title = playlist.playlistEntity.playlistName + binding.toolbar.subtitle = + MusicUtil.getPlaylistInfoString(requireContext(), playlist.songs.toSongs()) setUpRecyclerView() viewModel.getSongs().observe(viewLifecycleOwner) { songs(it.toSongs()) diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt index 92e01f567..2198d08ff 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt @@ -695,11 +695,11 @@ object PreferenceUtil { val isSnowFalling get() = sharedPreferences.getBoolean(SNOWFALL, false) - val lyricsType: LyricsType + val lyricsType: CoverLyricsType get() = if (sharedPreferences.getString(LYRICS_TYPE, "0") == "0") { - LyricsType.REPLACE_COVER + CoverLyricsType.REPLACE_COVER } else { - LyricsType.OVER_COVER + CoverLyricsType.OVER_COVER } var playbackSpeed @@ -738,6 +738,6 @@ object PreferenceUtil { get() = sharedPreferences.getBoolean(SWIPE_DOWN_DISMISS, true) } -enum class LyricsType { +enum class CoverLyricsType { REPLACE_COVER, OVER_COVER } \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_lyrics.xml b/app/src/main/res/layout/fragment_lyrics.xml index 00645d23c..6b3f8ea26 100644 --- a/app/src/main/res/layout/fragment_lyrics.xml +++ b/app/src/main/res/layout/fragment_lyrics.xml @@ -28,37 +28,56 @@ android:layout_height="match_parent" android:background="?attr/colorSurface" android:gravity="start" - app:contentInsetLeft="0dp" + app:contentInsetLeft="0dp" app:contentInsetStart="0dp" app:contentInsetStartWithNavigation="0dp" app:navigationIcon="@drawable/ic_keyboard_backspace_black" - app:subtitleTextAppearance="@style/TextViewCaption" + app:title="@string/lyrics" app:titleMargin="0dp" app:titleMarginStart="0dp" - app:titleTextAppearance="@style/TextViewSubtitle1"> - - - + app:titleTextAppearance="@style/ToolbarTextAppearanceNormal" /> - + android:layout_marginTop="?attr/actionBarSize"> + + + + + + + + + + - - - - - - - - - diff --git a/app/src/main/res/layout/fragment_synced_lyrics.xml b/app/src/main/res/layout/fragment_synced_lyrics.xml deleted file mode 100644 index 37dc17b02..000000000 --- a/app/src/main/res/layout/fragment_synced_lyrics.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - \ No newline at end of file diff --git a/app/src/main/res/navigation/main_graph.xml b/app/src/main/res/navigation/main_graph.xml index 721cab2ba..63abf5367 100644 --- a/app/src/main/res/navigation/main_graph.xml +++ b/app/src/main/res/navigation/main_graph.xml @@ -125,5 +125,5 @@ + android:name="code.name.monkey.retromusic.fragments.lyrics.LyricsFragment" /> \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index d56dbaa73..0e6eaba7a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -94,6 +94,7 @@ Just Black Blacklist The app needs nearby devices permission to check for bluetooth devices + Nearby devices Blur Blur Card Unable to send report @@ -561,5 +562,4 @@ You have to select at least one category. You will be forwarded to the issue tracker website. Your account data is only used for authentication. - Nearby devices From 0c6917c775fce7d5beaaa26be137dcb3e8123504 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Mon, 20 Jun 2022 15:37:57 +0530 Subject: [PATCH 16/19] Moved player toolbar for Blur Card theme to bottom --- .../player/cardblur/CardBlurFragment.kt | 12 +- .../res/layout/fragment_card_blur_player.xml | 115 ++++++++++-------- 2 files changed, 73 insertions(+), 54 deletions(-) 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 10db4df81..f3d26ed19 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 @@ -74,8 +74,8 @@ class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player), libraryViewModel.updateColor(color.backgroundColor) ToolbarContentTintHelper.colorizeToolbar(binding.playerToolbar, Color.WHITE, activity) - binding.playerToolbar.setTitleTextColor(Color.WHITE) - binding.playerToolbar.setSubtitleTextColor(Color.WHITE) + binding.title.setTextColor(Color.WHITE) + binding.text.setTextColor(Color.WHITE) } override fun toggleFavorite(song: Song) { @@ -94,7 +94,7 @@ class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player), _binding = FragmentCardBlurPlayerBinding.bind(view) setUpSubFragments() setUpPlayerToolbar() - binding.cardContainer?.drawAboveSystemBars() + binding.playerToolbar.drawAboveSystemBars() } private fun setUpSubFragments() { @@ -130,9 +130,9 @@ class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player), private fun updateSong() { val song = MusicPlayerRemote.currentSong - binding.playerToolbar.apply { - title = song.title - subtitle = song.artistName + binding.run { + title.text = song.title + text.text = song.artistName } } diff --git a/app/src/main/res/layout/fragment_card_blur_player.xml b/app/src/main/res/layout/fragment_card_blur_player.xml index 720a35c71..4938d801b 100644 --- a/app/src/main/res/layout/fragment_card_blur_player.xml +++ b/app/src/main/res/layout/fragment_card_blur_player.xml @@ -25,64 +25,83 @@ - + android:layout_height="match_parent" + android:orientation="vertical"> - + + + android:layout_marginTop="16dp" + android:clickable="true" + android:ellipsize="end" + android:focusable="true" + android:freezesText="true" + android:paddingHorizontal="24dp" + android:scrollHorizontally="true" + android:singleLine="true" + android:textAppearance="@style/TextViewHeadline6" + android:textColor="?android:attr/textColorPrimary" + android:textStyle="bold" + tools:text="@tools:sample/lorem" /> - + - + + + + + + + android:layout_gravity="bottom" + tools:layout="@layout/fragment_card_blur_player_playback_controls" /> + - - - - - - - - - - - + app:navigationIcon="@drawable/ic_keyboard_arrow_down_black" /> + \ No newline at end of file From c3309175a672b6b9dd09767a05adddbe0e93d0a3 Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Mon, 20 Jun 2022 16:36:56 +0530 Subject: [PATCH 17/19] Colored lyrics text for Full and Gradient themes --- .../fragments/player/CoverLyricsFragment.kt | 13 +++ .../player/full/FullPlayerFragment.kt | 2 + .../player/gradient/GradientPlayerFragment.kt | 17 ++-- .../monkey/retromusic/lyrics/CoverLrcView.kt | 2 +- .../transform/ParallaxPagerTransformer.kt | 15 +--- .../layout-land/fragment_card_blur_player.xml | 81 ------------------- .../main/res/layout/fragment_cover_lyrics.xml | 4 +- app/src/main/res/layout/fragment_full.xml | 5 +- .../res/layout/fragment_gradient_player.xml | 3 +- 9 files changed, 37 insertions(+), 105 deletions(-) delete mode 100644 app/src/main/res/layout-land/fragment_card_blur_player.xml diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/CoverLyricsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/CoverLyricsFragment.kt index 7a8b8aaf6..ee32e72d3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/CoverLyricsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/CoverLyricsFragment.kt @@ -11,6 +11,7 @@ import androidx.preference.PreferenceManager import code.name.monkey.retromusic.R import code.name.monkey.retromusic.SHOW_LYRICS import code.name.monkey.retromusic.databinding.FragmentCoverLyricsBinding +import code.name.monkey.retromusic.extensions.dipToPix import code.name.monkey.retromusic.fragments.NowPlayingScreen import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment @@ -21,6 +22,7 @@ import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics import code.name.monkey.retromusic.model.lyrics.Lyrics 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 org.jaudiotagger.audio.exceptions.CannotReadException @@ -56,6 +58,17 @@ class CoverLyricsFragment : AbsMusicServiceFragment(R.layout.fragment_cover_lyri } } + fun setColors(color: MediaNotificationProcessor) { + binding.run { + playerLyrics.background = null + playerLyricsLine1.setTextColor(color.primaryTextColor) + playerLyricsLine1.setShadowLayer(dipToPix(10f), 0f, 0f, color.backgroundColor) + playerLyricsLine2.setTextColor(color.primaryTextColor) + playerLyricsLine2.setShadowLayer(dipToPix(10f), 0f, 0f, color.backgroundColor) + } + + } + override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) { if (key == SHOW_LYRICS) { if (sharedPreferences?.getBoolean(key, false) == true) { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/full/FullPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/full/FullPlayerFragment.kt index 6e0cfa836..c2ebc9428 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/full/FullPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/full/FullPlayerFragment.kt @@ -28,6 +28,7 @@ import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.extensions.whichFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment import code.name.monkey.retromusic.fragments.base.goToArtist +import code.name.monkey.retromusic.fragments.player.CoverLyricsFragment import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment import code.name.monkey.retromusic.glide.GlideApp import code.name.monkey.retromusic.glide.RetroGlideExtension @@ -98,6 +99,7 @@ class FullPlayerFragment : AbsPlayerFragment(R.layout.fragment_full) { controlsFragment.setColor(color) libraryViewModel.updateColor(color.backgroundColor) ToolbarContentTintHelper.colorizeToolbar(binding.playerToolbar, Color.WHITE, activity) + binding.coverLyrics.getFragment().setColors(color) } override fun onFavoriteToggled() { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt index e79bd784d..d85101427 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt @@ -44,6 +44,7 @@ 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.fragments.other.VolumeFragment +import code.name.monkey.retromusic.fragments.player.CoverLyricsFragment import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler @@ -270,6 +271,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play updateRepeatState() updateShuffleState() updatePrevNextColor() + binding.coverLyrics.getFragment().setColors(color) } override fun onFavoriteToggled() { @@ -379,17 +381,22 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play private fun setUpPlayPauseFab() { binding.playbackControlsFragment.playPauseButton.setOnClickListener( - PlayPauseButtonOnClickHandler()) + PlayPauseButtonOnClickHandler() + ) } @SuppressLint("ClickableViewAccessibility") private fun setUpPrevNext() { updatePrevNextColor() - binding.playbackControlsFragment.nextButton.setOnTouchListener(MusicSeekSkipTouchListener( - requireActivity(), - true)) + binding.playbackControlsFragment.nextButton.setOnTouchListener( + MusicSeekSkipTouchListener( + requireActivity(), + true + ) + ) binding.playbackControlsFragment.previousButton.setOnTouchListener( - MusicSeekSkipTouchListener(requireActivity(), false)) + MusicSeekSkipTouchListener(requireActivity(), false) + ) } private fun updatePrevNextColor() { 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 d772a1eb6..891181c3d 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 @@ -323,7 +323,7 @@ class CoverLrcView @JvmOverloads constructor( if (!hasLrc()) { return@runOnUi } - val line = findShowLine(time - 300L) + val line = findShowLine(time + 300L) if (line != mCurrentLine) { mCurrentLine = line if (!isShowTimeline) { diff --git a/app/src/main/java/code/name/monkey/retromusic/transform/ParallaxPagerTransformer.kt b/app/src/main/java/code/name/monkey/retromusic/transform/ParallaxPagerTransformer.kt index fa454dfb7..0a7d40faf 100644 --- a/app/src/main/java/code/name/monkey/retromusic/transform/ParallaxPagerTransformer.kt +++ b/app/src/main/java/code/name/monkey/retromusic/transform/ParallaxPagerTransformer.kt @@ -22,7 +22,6 @@ import androidx.viewpager.widget.ViewPager */ class ParallaxPagerTransformer(private val id: Int) : ViewPager.PageTransformer { - private var border = 0 private var speed = 0.2f override fun transformPage(page: View, position: Float) { @@ -32,23 +31,13 @@ class ParallaxPagerTransformer(private val id: Int) : ViewPager.PageTransformer if (position > -1 && position < 1) { val width = parallaxView.width.toFloat() parallaxView.translationX = -(position * width * speed) - val sc = (width - border) / width - if (position == 0f) { - scaleX = 1f - scaleY = 1f - } else { - scaleX = sc - scaleY = sc - } + scaleX = 1f + scaleY = 1f } } } } - fun setBorder(px: Int) { - border = px - } - fun setSpeed(speed: Float) { this.speed = speed } diff --git a/app/src/main/res/layout-land/fragment_card_blur_player.xml b/app/src/main/res/layout-land/fragment_card_blur_player.xml deleted file mode 100644 index d3d152cc6..000000000 --- a/app/src/main/res/layout-land/fragment_card_blur_player.xml +++ /dev/null @@ -1,81 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_cover_lyrics.xml b/app/src/main/res/layout/fragment_cover_lyrics.xml index 50d442695..b90205a95 100644 --- a/app/src/main/res/layout/fragment_cover_lyrics.xml +++ b/app/src/main/res/layout/fragment_cover_lyrics.xml @@ -21,7 +21,7 @@ android:layout_gravity="center_vertical" android:gravity="center" android:shadowColor="@color/md_black_1000" - android:shadowRadius="4" + android:shadowRadius="10" android:textAppearance="@style/TextViewHeadline5" android:textColor="@color/md_white_1000" android:visibility="gone" @@ -34,7 +34,7 @@ android:layout_gravity="center_vertical" android:gravity="center" android:shadowColor="@color/md_black_1000" - android:shadowRadius="4" + android:shadowRadius="10" android:textAppearance="@style/TextViewHeadline5" android:textColor="@color/md_white_1000" tools:text="@tools:sample/full_names[5]" /> diff --git a/app/src/main/res/layout/fragment_full.xml b/app/src/main/res/layout/fragment_full.xml index 39fbd0acb..684bae35c 100644 --- a/app/src/main/res/layout/fragment_full.xml +++ b/app/src/main/res/layout/fragment_full.xml @@ -127,8 +127,9 @@ android:name="code.name.monkey.retromusic.fragments.player.CoverLyricsFragment" android:layout_width="match_parent" android:layout_height="wrap_content" + android:layout_marginBottom="16dp" android:elevation="20dp" + app:layout_constraintBottom_toTopOf="@+id/playbackControlsFragment" app:layout_constraintEnd_toEndOf="parent" - app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@id/playerToolbar" /> + app:layout_constraintStart_toStartOf="parent" /> diff --git a/app/src/main/res/layout/fragment_gradient_player.xml b/app/src/main/res/layout/fragment_gradient_player.xml index e4d569733..fc8e9c5f1 100644 --- a/app/src/main/res/layout/fragment_gradient_player.xml +++ b/app/src/main/res/layout/fragment_gradient_player.xml @@ -58,7 +58,8 @@ app:layout_constraintBottom_toBottomOf="@+id/playerAlbumCoverFragment" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" - app:layout_constraintTop_toBottomOf="@+id/status_bar" /> + android:layout_marginBottom="16dp" + tools:layout="@layout/fragment_cover_lyrics" /> From 88b0299ef9c4cb6d00b19a5f3931c5ddbd554c0a Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Mon, 20 Jun 2022 19:46:35 +0530 Subject: [PATCH 18/19] Update changelog --- app/src/main/assets/retro-changelog.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/main/assets/retro-changelog.html b/app/src/main/assets/retro-changelog.html index 6028889c1..da8a208f2 100644 --- a/app/src/main/assets/retro-changelog.html +++ b/app/src/main/assets/retro-changelog.html @@ -65,9 +65,9 @@
June 21, 2022

v6.0.2Beta

-

What's New

+

Fixed

    -
  • Added lyrics downloading
  • +
  • Minor bug fixes and improvements
From dba4edd8ef76c6b3eef836287520650cdf2a8e0d Mon Sep 17 00:00:00 2001 From: Prathamesh More Date: Mon, 20 Jun 2022 20:08:07 +0530 Subject: [PATCH 19/19] Fixed a rare crash because of notifyDataSetChanged in Now playing ViewPager --- .../retromusic/fragments/player/PlayerAlbumCoverFragment.kt | 5 +---- app/src/main/res/layout-land/fragment_adaptive_player.xml | 4 +++- app/src/main/res/layout/fragment_adaptive_player.xml | 6 ++++-- 3 files changed, 8 insertions(+), 7 deletions(-) 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 06c15d504..db1c641d5 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 @@ -49,7 +49,6 @@ import code.name.monkey.retromusic.util.LyricUtil import code.name.monkey.retromusic.util.CoverLyricsType import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.color.MediaNotificationProcessor -import code.name.monkey.retromusic.util.logD import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext @@ -250,8 +249,7 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe private fun updatePlayingQueue() { binding.viewPager.apply { - adapter = AlbumCoverPagerAdapter(childFragmentManager, MusicPlayerRemote.playingQueue) - adapter?.notifyDataSetChanged() + adapter = AlbumCoverPagerAdapter(parentFragmentManager, MusicPlayerRemote.playingQueue) setCurrentItem(MusicPlayerRemote.position, true) onPageSelected(MusicPlayerRemote.position) } @@ -260,7 +258,6 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe override fun onPageScrolled(position: Int, positionOffset: Float, positionOffsetPixels: Int) {} override fun onPageSelected(position: Int) { - logD("Page Selected $position") currentPosition = position if (binding.viewPager.adapter != null) { (binding.viewPager.adapter as AlbumCoverPagerAdapter).receiveColor( diff --git a/app/src/main/res/layout-land/fragment_adaptive_player.xml b/app/src/main/res/layout-land/fragment_adaptive_player.xml index 6a193abcb..b42e7aa2f 100644 --- a/app/src/main/res/layout-land/fragment_adaptive_player.xml +++ b/app/src/main/res/layout-land/fragment_adaptive_player.xml @@ -4,7 +4,9 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?colorSurface"> + android:background="?colorSurface" + android:clickable="true" + android:focusable="true"> diff --git a/app/src/main/res/layout/fragment_adaptive_player.xml b/app/src/main/res/layout/fragment_adaptive_player.xml index 3e0c27f1b..d6eca8bbe 100644 --- a/app/src/main/res/layout/fragment_adaptive_player.xml +++ b/app/src/main/res/layout/fragment_adaptive_player.xml @@ -4,7 +4,9 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?colorSurface"> + android:background="?colorSurface" + android:clickable="true" + android:focusable="true"> @@ -27,7 +29,7 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="0" - app:contentInsetLeft="0dp" + app:contentInsetLeft="0dp" app:contentInsetStart="0dp" app:contentInsetStartWithNavigation="0dp" app:navigationIcon="@drawable/ic_keyboard_arrow_down_black"