|
@ -38,12 +38,12 @@ ___
|
|||
|
||||
## 📱 Screenshots
|
||||
### App Themes
|
||||
| <img src="screenshots/home_light.jpg" width="200"/> | <img src="screenshots/home_dark.jpg" width="200"/> | <img src="screenshots/home_black.jpg" width="200"/> |
|
||||
| <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg" width="200"/> | <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/3.jpg" width="200"/> | <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/4.jpg" width="200"/> |
|
||||
|:---:|:---:|:---:|
|
||||
|Clearly white| Kinda dark | Just black|
|
||||
|
||||
### Player screen
|
||||
| <img src="screenshots/home_light.jpg" width="200"/>| <img src="screenshots/songs.jpg" width="200"/>| <img src="screenshots/albums.jpg" width="200"/>| <img src="screenshots/artists.jpg" width="200"/>| <img src="screenshots/settings.jpg" width="200"/>|
|
||||
| <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/2.jpg" width="200"/>| <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/5.jpg" width="200"/>| <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/6.jpg" width="200"/>| <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/7.jpg" width="200"/>| <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/8.jpg" width="200"/>|
|
||||
|:---:|:---:|:---:|:---:|:---:|
|
||||
| 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
|
||||
| <img src="screenshots/normal.jpg" width="200"/> |<img src="screenshots/fit.jpg" width="200"/>| <img src="screenshots/flat.jpg" width="200"/> | <img src="screenshots/color.jpg" width="200"/> | <img src="screenshots/material.jpg" width="200"/> |
|
||||
| <img src="fastlane/metadata/android/en-US/images/phoneScreenshots/1.jpg" width="200"/> |<img src="screenshots/fit.jpg" width="200"/>| <img src="screenshots/flat.jpg" width="200"/> | <img src="screenshots/color.jpg" width="200"/> | <img src="screenshots/material.jpg" width="200"/> |
|
||||
|:-----: |:-----: |:-----: |:-----: |:-----: |
|
||||
| Normal | Fit | Flat | Color | Material |
|
||||
|
||||
|
|
|
@ -14,8 +14,8 @@ android {
|
|||
vectorDrawables.useSupportLibrary = true
|
||||
|
||||
applicationId "code.name.monkey.retromusic"
|
||||
versionCode 10592
|
||||
versionName '6.0.1-beta'
|
||||
versionCode 10596
|
||||
versionName '6.0.2-beta'
|
||||
|
||||
buildConfigField("String", "GOOGLE_PLAY_LICENSING_KEY", "\"${getProperty(getProperties('../public.properties'), 'GOOGLE_PLAY_LICENSE_KEY')}\"")
|
||||
}
|
||||
|
@ -41,6 +41,15 @@ android {
|
|||
versionNameSuffix ' DEBUG'
|
||||
}
|
||||
}
|
||||
flavorDimensions "version"
|
||||
productFlavors {
|
||||
normal {
|
||||
dimension "version"
|
||||
}
|
||||
fdroid {
|
||||
dimension "version"
|
||||
}
|
||||
}
|
||||
|
||||
buildFeatures{
|
||||
viewBinding true
|
||||
|
@ -88,18 +97,18 @@ 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"
|
||||
implementation 'androidx.core:core-ktx:1.8.0'
|
||||
implementation "androidx.core:core-ktx:$core_version"
|
||||
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"
|
||||
|
@ -110,22 +119,21 @@ 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"
|
||||
|
||||
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"
|
||||
|
||||
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"
|
||||
|
@ -160,7 +168,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'
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
package code.name.monkey.retromusic.activities.base
|
||||
|
||||
|
||||
abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() {
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package code.name.monkey.retromusic.billing
|
||||
|
||||
import android.content.Context
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
class BillingManager(context: Context) {
|
||||
|
||||
fun release() {}
|
||||
|
||||
val isProVersion: Boolean
|
||||
get() = true
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package code.name.monkey.retromusic.cast
|
||||
|
||||
import android.content.Context
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
class RetroWebServer(context: Context)
|
|
@ -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() {}
|
|
@ -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) {}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
package code.name.monkey.retromusic.util
|
||||
|
||||
import android.content.Context
|
||||
|
||||
@Suppress("UNUSED_PARAMETER")
|
||||
object AppRater {
|
||||
fun appLaunched(context: Context) {}
|
||||
}
|
|
@ -22,7 +22,6 @@
|
|||
android:name="android.permission.WRITE_SETTINGS"
|
||||
tools:ignore="ProtectedPermissions" />
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
|
||||
<uses-permission android:name="com.android.vending.BILLING" />
|
||||
<uses-permission
|
||||
android:name="android.permission.BLUETOOTH_CONNECT"
|
||||
android:usesPermissionFlags="neverForLocation"
|
||||
|
@ -120,7 +119,6 @@
|
|||
<activity android:name=".activities.tageditor.SongTagEditorActivity" />
|
||||
<activity android:name=".activities.SupportDevelopmentActivity" />
|
||||
<activity android:name=".activities.LicenseActivity" />
|
||||
<activity android:name=".activities.PurchaseActivity" />
|
||||
<activity android:name=".activities.bugreport.BugReportActivity" />
|
||||
<activity android:name=".activities.ShareInstagramStory" />
|
||||
<activity android:name=".activities.DriveModeActivity" />
|
||||
|
@ -315,10 +313,6 @@
|
|||
android:name="com.lge.support.SPLIT_WINDOW"
|
||||
android:value="true" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.android.vending.splits.required"
|
||||
android:value="true" />
|
||||
|
||||
<!-- Android Auto -->
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.car.application"
|
||||
|
@ -329,11 +323,6 @@
|
|||
<meta-data
|
||||
android:name="com.google.android.gms.car.notification.SmallIcon"
|
||||
android:resource="@drawable/ic_notification" />
|
||||
|
||||
<!-- ChromeCast -->
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
|
||||
android:value="code.name.monkey.retromusic.cast.CastOptionsProvider" />
|
||||
</application>
|
||||
|
||||
<!--
|
||||
|
|
|
@ -62,6 +62,14 @@
|
|||
</head>
|
||||
|
||||
<body>
|
||||
<div>
|
||||
<h5>June 21, 2022</h5>
|
||||
<h2>v6.0.2<span class="tag"><i>Beta</i></span></h2>
|
||||
<h3>Fixed</h3>
|
||||
<ul>
|
||||
<li>Minor bug fixes and improvements</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div>
|
||||
<h5>June 13, 2022</h5>
|
||||
<h2>v6.0.1<span class="tag"><i>Beta</i></span></h2>
|
||||
|
|
|
@ -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,20 @@ 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() {}
|
||||
})
|
||||
billingManager = BillingManager(this)
|
||||
|
||||
// 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 +77,7 @@ class App : Application() {
|
|||
}
|
||||
|
||||
fun isProVersion(): Boolean {
|
||||
return BuildConfig.DEBUG || instance?.billingProcessor!!.isPurchased(
|
||||
PRO_VERSION_PRODUCT_ID
|
||||
)
|
||||
return BuildConfig.DEBUG || instance?.billingManager!!.isProVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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<SkuDetails>?) {
|
||||
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<SkuDetails>,
|
||||
) : RecyclerView.Adapter<SkuDetailsAdapter.ViewHolder>() {
|
||||
|
||||
private var skuDetailsList: List<SkuDetails> = 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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -42,7 +42,7 @@ class PlayingQueueAdapter(
|
|||
activity: FragmentActivity,
|
||||
dataSet: MutableList<Song>,
|
||||
private var current: Int,
|
||||
itemLayoutRes: Int
|
||||
itemLayoutRes: Int,
|
||||
) : SongAdapter(
|
||||
activity, dataSet, itemLayoutRes, null
|
||||
), DraggableItemAdapter<PlayingQueueAdapter.ViewHolder>,
|
||||
|
@ -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
|
||||
|
|
|
@ -1,43 +0,0 @@
|
|||
@file:Suppress("unused")
|
||||
|
||||
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.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<String> = 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()
|
||||
|
||||
return CastOptions.Builder()
|
||||
.setReceiverApplicationId(CastMediaControlIntent.DEFAULT_MEDIA_RECEIVER_APPLICATION_ID)
|
||||
.setCastMediaOptions(mediaOptions)
|
||||
.build()
|
||||
}
|
||||
|
||||
override fun getAdditionalSessionProviders(context: Context): MutableList<SessionProvider>? {
|
||||
return null
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -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].
|
||||
*
|
||||
|
|
|
@ -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<AlbumAdapter, GridLayoutManager>(),
|
||||
IAlbumClickListener, ICabHolder {
|
||||
|
@ -169,7 +169,7 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
|
|||
setupLayoutMenu(layoutItem.subMenu)
|
||||
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu)
|
||||
//Setting up cast button
|
||||
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
|
||||
requireContext().setUpMediaRouteButton(menu)
|
||||
}
|
||||
|
||||
private fun setUpSortOrderMenu(
|
||||
|
|
|
@ -25,6 +25,7 @@ import code.name.monkey.retromusic.EXTRA_ARTIST_ID
|
|||
import code.name.monkey.retromusic.EXTRA_ARTIST_NAME
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.adapter.artist.ArtistAdapter
|
||||
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
|
||||
|
@ -43,7 +44,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 ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, GridLayoutManager>(),
|
||||
IArtistClickListener, IAlbumArtistClickListener, ICabHolder {
|
||||
|
@ -180,7 +180,7 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
|
|||
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu)
|
||||
setupAlbumArtistMenu(menu)
|
||||
//Setting up cast button
|
||||
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
|
||||
requireContext().setUpMediaRouteButton(menu)
|
||||
}
|
||||
|
||||
private fun setupAlbumArtistMenu(menu: Menu) {
|
||||
|
|
|
@ -26,12 +26,12 @@ import androidx.recyclerview.widget.LinearLayoutManager
|
|||
import code.name.monkey.retromusic.EXTRA_GENRE
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.adapter.GenreAdapter
|
||||
import code.name.monkey.retromusic.extensions.setUpMediaRouteButton
|
||||
import code.name.monkey.retromusic.fragments.ReloadType
|
||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
|
||||
import code.name.monkey.retromusic.interfaces.IGenreClickListener
|
||||
import code.name.monkey.retromusic.model.Genre
|
||||
import code.name.monkey.retromusic.util.RetroUtil
|
||||
import com.google.android.gms.cast.framework.CastButtonFactory
|
||||
import com.google.android.material.transition.MaterialSharedAxis
|
||||
|
||||
class
|
||||
|
@ -67,7 +67,7 @@ GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager>(),
|
|||
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() {
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,23 +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.MainActivity
|
||||
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
|
||||
|
@ -52,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
|
||||
|
@ -60,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<IntentSenderRequest>
|
||||
private lateinit var editSyncedLyricsLauncher: ActivityResultLauncher<IntentSenderRequest>
|
||||
|
||||
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() {
|
||||
|
@ -78,13 +81,7 @@ class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) {
|
|||
return baseUrl
|
||||
}
|
||||
|
||||
private lateinit var normalLyricsLauncher: ActivityResultLauncher<IntentSenderRequest>
|
||||
private lateinit var newSyncedLyricsLauncher: ActivityResultLauncher<Intent>
|
||||
private lateinit var editSyncedLyricsLauncher: ActivityResultLauncher<IntentSenderRequest>
|
||||
|
||||
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)
|
||||
|
@ -95,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) {
|
||||
|
@ -119,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()
|
||||
}
|
||||
}
|
||||
|
@ -158,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() {
|
||||
|
@ -182,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,
|
||||
|
@ -198,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(
|
||||
|
@ -218,7 +216,6 @@ class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) {
|
|||
) { _, input ->
|
||||
val fieldKeyValueMap = EnumMap<FieldKey, String>(FieldKey::class.java)
|
||||
fieldKeyValueMap[FieldKey.LYRICS] = input.toString()
|
||||
syncedLyrics = input.toString()
|
||||
GlobalScope.launch {
|
||||
if (VersionUtils.hasR()) {
|
||||
cacheFile = TagWriter.writeTagsToFilesR(
|
||||
|
@ -245,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)
|
||||
}
|
||||
|
@ -253,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(
|
||||
|
@ -278,151 +276,97 @@ 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, String>(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() {
|
||||
super.onDestroyView()
|
||||
if (MusicPlayerRemote.playingQueue.isNotEmpty())
|
||||
(requireActivity() as MainActivity).expandPanel()
|
||||
mainActivity.expandPanel()
|
||||
_binding = null
|
||||
}
|
||||
|
||||
enum class LyricsType {
|
||||
NORMAL_LYRICS,
|
||||
SYNCED_LYRICS
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
|
|
|
@ -46,12 +46,12 @@ 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
|
||||
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 +95,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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -171,13 +173,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)
|
||||
}
|
||||
|
@ -185,7 +185,6 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
|||
}
|
||||
|
||||
override fun onQueueChanged() {
|
||||
logD("Queue Changed")
|
||||
updatePlayingQueue()
|
||||
}
|
||||
|
||||
|
@ -219,7 +218,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 {
|
||||
|
@ -239,7 +238,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 {
|
||||
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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<CoverLyricsFragment>().setColors(color)
|
||||
}
|
||||
|
||||
override fun onFavoriteToggled() {
|
||||
|
|
|
@ -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<CoverLyricsFragment>().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() {
|
||||
|
|
|
@ -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())
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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?) {
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<SongAdapter, GridLayoutManager>(),
|
||||
ICabHolder {
|
||||
|
@ -136,7 +136,7 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLay
|
|||
setupLayoutMenu(layoutItem.subMenu)
|
||||
setUpSortOrderMenu(menu.findItem(R.id.action_sort_order).subMenu)
|
||||
//Setting up cast button
|
||||
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
|
||||
requireContext().setUpMediaRouteButton(menu)
|
||||
}
|
||||
|
||||
private fun setUpSortOrderMenu(sortOrderMenu: SubMenu) {
|
||||
|
|
|
@ -27,10 +27,10 @@ import code.name.monkey.retromusic.R
|
|||
import code.name.monkey.retromusic.extensions.showToast
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
import code.name.monkey.retromusic.repository.SongRepository
|
||||
import code.name.monkey.retromusic.service.CastPlayer
|
||||
import code.name.monkey.retromusic.service.MusicService
|
||||
import code.name.monkey.retromusic.util.getExternalStorageDirectory
|
||||
import code.name.monkey.retromusic.util.logE
|
||||
import com.google.android.gms.cast.framework.CastSession
|
||||
import org.koin.core.component.KoinComponent
|
||||
import org.koin.core.component.inject
|
||||
import java.io.File
|
||||
|
@ -171,9 +171,6 @@ object MusicPlayerRemote : KoinComponent {
|
|||
return musicService?.playingQueue?.size ?: -1
|
||||
}
|
||||
|
||||
/**
|
||||
* Async
|
||||
*/
|
||||
fun playSongAt(position: Int) {
|
||||
musicService?.playSongAt(position)
|
||||
}
|
||||
|
@ -456,8 +453,8 @@ object MusicPlayerRemote : KoinComponent {
|
|||
.dropLastWhile { it.isEmpty() }.toTypedArray()[1]
|
||||
}
|
||||
|
||||
fun switchToRemotePlayback(castSession: CastSession) {
|
||||
musicService?.switchToRemotePlayback(castSession)
|
||||
fun switchToRemotePlayback(castPlayer: CastPlayer) {
|
||||
musicService?.switchToRemotePlayback(castPlayer)
|
||||
}
|
||||
|
||||
fun switchToLocalPlayback() {
|
||||
|
|
|
@ -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<File?, Int?, List<LrcEntry>>() {
|
||||
override fun doInBackground(vararg params: File?): List<LrcEntry>? {
|
||||
return LrcUtils.parseLrc(params)
|
||||
}
|
||||
|
||||
override fun onPostExecute(lrcEntries: List<LrcEntry>) {
|
||||
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<String?, Int?, List<LrcEntry>>() {
|
||||
override fun doInBackground(vararg params: String?): List<LrcEntry>? {
|
||||
return LrcUtils.parseLrc(params)
|
||||
}
|
||||
|
||||
override fun onPostExecute(lrcEntries: List<LrcEntry>) {
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -81,7 +81,7 @@ class AlbumCoverStylePreferenceDialog : DialogFragment(),
|
|||
if (isAlbumCoverStyle(coverStyle)) {
|
||||
val result = getString(coverStyle.titleRes) + " theme is Pro version feature."
|
||||
showToast(result)
|
||||
NavigationUtil.goToProVersion(requireActivity())
|
||||
requireContext().goToProVersion()
|
||||
} else {
|
||||
PreferenceUtil.albumCoverStyle = coverStyle
|
||||
}
|
||||
|
|
|
@ -91,7 +91,7 @@ class NowPlayingScreenPreferenceDialog : DialogFragment(), ViewPager.OnPageChang
|
|||
val result =
|
||||
"${getString(nowPlayingScreen.titleRes)} theme is Pro version feature."
|
||||
showToast(result)
|
||||
NavigationUtil.goToProVersion(requireContext())
|
||||
requireContext().goToProVersion()
|
||||
} else {
|
||||
PreferenceUtil.nowPlayingScreen = nowPlayingScreen
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -15,10 +15,10 @@
|
|||
|
||||
package code.name.monkey.retromusic.service
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.Message
|
||||
import android.os.PowerManager
|
||||
import android.os.PowerManager.WakeLock
|
||||
|
@ -62,8 +62,7 @@ class MediaButtonIntentReceiver : MediaButtonReceiver() {
|
|||
private var mClickCounter = 0
|
||||
private var mLastClickTime: Long = 0
|
||||
|
||||
@SuppressLint("HandlerLeak") // false alarm, handler is already static
|
||||
private val mHandler = object : Handler() {
|
||||
private val mHandler = object : Handler(Looper.getMainLooper()) {
|
||||
|
||||
override fun handleMessage(msg: Message) {
|
||||
when (msg.what) {
|
||||
|
|
|
@ -86,7 +86,6 @@ import code.name.monkey.retromusic.volume.OnAudioVolumeChangedListener
|
|||
import com.bumptech.glide.request.target.CustomTarget
|
||||
import com.bumptech.glide.request.target.Target
|
||||
import com.bumptech.glide.request.transition.Transition
|
||||
import com.google.android.gms.cast.framework.CastSession
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.Dispatchers.Default
|
||||
import kotlinx.coroutines.Dispatchers.IO
|
||||
|
@ -286,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)
|
||||
|
@ -319,6 +322,7 @@ class MusicService : MediaBrowserServiceCompat(),
|
|||
mediaSession?.isActive = false
|
||||
quit()
|
||||
releaseResources()
|
||||
serviceScope.cancel()
|
||||
contentResolver.unregisterContentObserver(mediaStoreObserver)
|
||||
unregisterOnSharedPreferenceChangedListener(this)
|
||||
wakeLock?.release()
|
||||
|
@ -1014,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())
|
||||
|
@ -1171,8 +1177,8 @@ class MusicService : MediaBrowserServiceCompat(),
|
|||
playbackManager.switchToLocalPlayback(this::restorePlaybackState)
|
||||
}
|
||||
|
||||
fun switchToRemotePlayback(castSession: CastSession) {
|
||||
playbackManager.switchToRemotePlayback(castSession, this::restorePlaybackState)
|
||||
fun switchToRemotePlayback(castPlayer: CastPlayer) {
|
||||
playbackManager.switchToRemotePlayback(castPlayer, this::restorePlaybackState)
|
||||
}
|
||||
|
||||
private fun restorePlaybackState(wasPlaying: Boolean, progress: Int) {
|
||||
|
@ -1304,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
|
||||
|
|
|
@ -8,7 +8,6 @@ import code.name.monkey.retromusic.service.playback.Playback
|
|||
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil.playbackPitch
|
||||
import code.name.monkey.retromusic.util.PreferenceUtil.playbackSpeed
|
||||
import com.google.android.gms.cast.framework.CastSession
|
||||
|
||||
|
||||
class PlaybackManager(val context: Context) {
|
||||
|
@ -160,11 +159,11 @@ class PlaybackManager(val context: Context) {
|
|||
}
|
||||
|
||||
fun switchToRemotePlayback(
|
||||
castSession: CastSession,
|
||||
castPlayer: CastPlayer,
|
||||
onChange: (wasPlaying: Boolean, progress: Int) -> Unit,
|
||||
) {
|
||||
playbackLocation = PlaybackLocation.REMOTE
|
||||
switchToPlayback(CastPlayer(castSession), onChange)
|
||||
switchToPlayback(castPlayer, onChange)
|
||||
}
|
||||
|
||||
private fun switchToPlayback(
|
||||
|
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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)) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
@ -472,10 +470,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
|
||||
|
@ -697,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
|
||||
|
@ -740,6 +738,6 @@ object PreferenceUtil {
|
|||
get() = sharedPreferences.getBoolean(SWIPE_DOWN_DISMISS, true)
|
||||
}
|
||||
|
||||
enum class LyricsType {
|
||||
enum class CoverLyricsType {
|
||||
REPLACE_COVER, OVER_COVER
|
||||
}
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
}
|
|
@ -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))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,6 +5,5 @@
|
|||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="#fff"
|
||||
android:fillType="evenOdd"
|
||||
android:pathData="M5,3C3.8954,3 3,3.8954 3,5V19C3,20.1046 3.8954,21 5,21H19C20.1046,21 21,20.1046 21,19V5C21,3.8954 20.1046,3 19,3H5ZM6,7C6,6.4477 6.4477,6 7,6H17C17.5523,6 18,6.4477 18,7C18,7.5523 17.5523,8 17,8H7C6.4477,8 6,7.5523 6,7ZM6,12C6,11.4477 6.4477,11 7,11H17C17.5523,11 18,11.4477 18,12C18,12.5523 17.5523,13 17,13H7C6.4477,13 6,12.5523 6,12ZM7,16C6.4477,16 6,16.4477 6,17C6,17.5523 6.4477,18 7,18H11C11.5523,18 12,17.5523 12,17C12,16.4477 11.5523,16 11,16H7Z" />
|
||||
</vector>
|
||||
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"/>
|
||||
</vector>
|
||||
|
|
|
@ -3,18 +3,7 @@
|
|||
android:height="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:pathData="M5,3L19,3A2,2 0,0 1,21 5L21,19A2,2 0,0 1,19 21L5,21A2,2 0,0 1,3 19L3,5A2,2 0,0 1,5 3z"
|
||||
android:strokeWidth="2"
|
||||
android:fillColor="#00000000"
|
||||
android:strokeColor="#fff"/>
|
||||
<path
|
||||
android:pathData="M7,6L17,6A1,1 0,0 1,18 7L18,7A1,1 0,0 1,17 8L7,8A1,1 0,0 1,6 7L6,7A1,1 0,0 1,7 6z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="M7,11L17,11A1,1 0,0 1,18 12L18,12A1,1 0,0 1,17 13L7,13A1,1 0,0 1,6 12L6,12A1,1 0,0 1,7 11z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:pathData="M7,16L11,16A1,1 0,0 1,12 17L12,17A1,1 0,0 1,11 18L7,18A1,1 0,0 1,6 17L6,17A1,1 0,0 1,7 16z"
|
||||
android:fillColor="#fff"/>
|
||||
<path
|
||||
android:fillColor="#fff"
|
||||
android:pathData="M2,22V4Q2,3.175 2.588,2.587Q3.175,2 4,2H15Q15.825,2 16.413,2.587Q17,3.175 17,4V4.425Q16.4,4.7 15.9,5.1Q15.4,5.5 15,6V4Q15,4 15,4Q15,4 15,4H4Q4,4 4,4Q4,4 4,4V16.175L4.175,16H15Q15,16 15,16Q15,16 15,16V12Q15.4,12.5 15.9,12.9Q16.4,13.3 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.75 16.875,6.875Q17.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,8H13V6H6ZM4,16.175V4Q4,4 4,4Q4,4 4,4Q4,4 4,4Q4,4 4,4V6Q4,6.625 4,7.387Q4,8.15 4,9Q4,9.85 4,10.613Q4,11.375 4,12V16Q4,16 4,16Q4,16 4,16Z" />
|
||||
</vector>
|
||||
|
|
|
@ -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">
|
||||
|
||||
<include layout="@layout/shadow_statusbar_toolbar" />
|
||||
|
||||
|
|
|
@ -1,81 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:clickable="true"
|
||||
android:focusable="true">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatImageView
|
||||
android:id="@+id/colorBackground"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="centerCrop"
|
||||
app:srcCompat="@color/black_color" />
|
||||
|
||||
<View
|
||||
android:id="@+id/mask"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:background="@drawable/shadow_up_strong" />
|
||||
|
||||
<include layout="@layout/shadow_statusbar_toolbar" />
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<include layout="@layout/status_bar" />
|
||||
</FrameLayout>
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/playerToolbar"
|
||||
style="@style/Toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
app:contentInsetLeft="0dp"
|
||||
app:contentInsetStart="0dp"
|
||||
app:contentInsetStartWithNavigation="0dp"
|
||||
app:navigationIcon="@drawable/ic_keyboard_arrow_down_black"
|
||||
app:subtitleTextAppearance="@style/TextAppearance.AppCompat.Caption"
|
||||
app:titleMargin="0dp"
|
||||
app:titleMarginStart="0dp"
|
||||
app:titleTextAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
|
||||
<FrameLayout
|
||||
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginStart="64dp"
|
||||
android:layout_marginEnd="64dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/playerAlbumCoverFragment"
|
||||
android:name="code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:layout="@layout/fragment_album_card_cover" />
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/playbackControlsFragment"
|
||||
android:name="code.name.monkey.retromusic.fragments.player.cardblur.CardBlurPlaybackControlsFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
android:layout_marginStart="96dp"
|
||||
android:layout_marginEnd="96dp"
|
||||
tools:layout="@layout/fragment_card_blur_player_playback_controls" />
|
||||
|
||||
</FrameLayout>
|
|
@ -10,7 +10,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<com.google.android.material.navigationrail.NavigationRailView
|
||||
<code.name.monkey.retromusic.views.TintedNavigationRailView
|
||||
android:id="@+id/navigationView"
|
||||
style="@style/Widget.Material3.NavigationRailView"
|
||||
android:layout_width="wrap_content"
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:fitsSystemWindows="true">
|
||||
|
@ -31,52 +30,5 @@
|
|||
android:overScrollMode="@integer/overScrollMode"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/donation"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="16dp"
|
||||
android:text="@string/donation_header"
|
||||
android:textAppearance="@style/TextViewSubtitle2"
|
||||
android:textColor="?attr/colorAccent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/progressContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:padding="12dp">
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/progress"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:indeterminate="true" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="start"
|
||||
android:paddingLeft="16dp"
|
||||
android:text="@string/loading_products"
|
||||
android:textAppearance="@style/TextViewCaption"
|
||||
tools:ignore="RtlHardcoded,RtlSymmetry" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/recyclerView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:paddingStart="6dp"
|
||||
android:paddingEnd="6dp"
|
||||
android:scrollbarStyle="outsideOverlay" />
|
||||
</LinearLayout>
|
||||
</androidx.core.widget.NestedScrollView>
|
||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
|
@ -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">
|
||||
|
||||
<include layout="@layout/shadow_statusbar_toolbar" />
|
||||
|
||||
|
@ -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"
|
||||
|
|
|
@ -25,64 +25,83 @@
|
|||
<include layout="@layout/shadow_statusbar_toolbar" />
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/cardContainer"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
<include layout="@layout/status_bar" />
|
||||
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
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" />
|
||||
|
||||
<include layout="@layout/status_bar" />
|
||||
<com.google.android.material.textview.MaterialTextView
|
||||
android:id="@+id/text"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="8dp"
|
||||
android:clickable="true"
|
||||
android:ellipsize="end"
|
||||
android:focusable="true"
|
||||
android:freezesText="true"
|
||||
android:paddingHorizontal="24dp"
|
||||
android:scrollHorizontally="true"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="@style/TextViewBody1"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
tools:text="@tools:sample/lorem" />
|
||||
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/playerToolbar"
|
||||
style="@style/Toolbar"
|
||||
<FrameLayout
|
||||
android:id="@+id/cardContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1">
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/playerAlbumCoverFragment"
|
||||
android:name="code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:layout="@layout/fragment_album_full_card_cover" />
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/cover_lyrics"
|
||||
android:name="code.name.monkey.retromusic.fragments.player.CoverLyricsFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
tools:layout="@layout/fragment_cover_lyrics" />
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/playbackControlsFragment"
|
||||
android:name="code.name.monkey.retromusic.fragments.player.cardblur.CardBlurPlaybackControlsFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="0"
|
||||
app:contentInsetLeft="0dp"
|
||||
app:contentInsetStart="0dp"
|
||||
app:contentInsetStartWithNavigation="0dp"
|
||||
app:navigationIcon="@drawable/ic_keyboard_arrow_down_black"
|
||||
app:subtitleTextAppearance="@style/TextAppearance.AppCompat.Caption"
|
||||
app:titleMargin="0dp"
|
||||
app:titleMarginStart="0dp"
|
||||
app:titleTextAppearance="@style/TextAppearance.AppCompat.Subhead" />
|
||||
android:layout_gravity="bottom"
|
||||
tools:layout="@layout/fragment_card_blur_player_playback_controls" />
|
||||
</FrameLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:layout_weight="1">
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/playerAlbumCoverFragment"
|
||||
android:name="code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
tools:layout="@layout/fragment_album_card_cover" />
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/cover_lyrics"
|
||||
android:name="code.name.monkey.retromusic.fragments.player.CoverLyricsFragment"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center"
|
||||
tools:layout="@layout/fragment_cover_lyrics" />
|
||||
</FrameLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<androidx.fragment.app.FragmentContainerView
|
||||
android:id="@+id/playbackControlsFragment"
|
||||
android:name="code.name.monkey.retromusic.fragments.player.cardblur.CardBlurPlaybackControlsFragment"
|
||||
<com.google.android.material.appbar.MaterialToolbar
|
||||
android:id="@+id/playerToolbar"
|
||||
style="@style/Toolbar"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="bottom"
|
||||
tools:layout="@layout/fragment_card_blur_player_playback_controls" />
|
||||
</FrameLayout>
|
||||
app:navigationIcon="@drawable/ic_keyboard_arrow_down_black" />
|
||||
</LinearLayout>
|
||||
|
||||
</FrameLayout>
|
|
@ -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]" />
|
||||
|
|
|
@ -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" />
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
|
|
@ -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" />
|
||||
|
||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||
|
||||
|
|
|
@ -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">
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tabLyrics"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent"
|
||||
app:tabIndicator="@drawable/tab_lyrics_indicator"
|
||||
app:tabIndicatorAnimationMode="elastic"
|
||||
app:tabIndicatorFullWidth="false"
|
||||
app:tabIndicatorHeight="5dp" />
|
||||
</com.google.android.material.appbar.MaterialToolbar>
|
||||
app:titleTextAppearance="@style/ToolbarTextAppearanceNormal" />
|
||||
</com.google.android.material.appbar.AppBarLayout>
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/lyricsPager"
|
||||
<FrameLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="?attr/actionBarSize"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent" />
|
||||
android:layout_marginTop="?attr/actionBarSize">
|
||||
|
||||
<ScrollView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/normalLyrics"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/normal_lyrics_padding"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="@dimen/lyrics_text_size"
|
||||
tools:text="@tools:sample/lorem[100]" />
|
||||
</ScrollView>
|
||||
|
||||
<code.name.monkey.retromusic.lyrics.LrcView
|
||||
android:id="@+id/lyricsView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||
app:lrcLabel="@string/no_lyrics_found"
|
||||
app:lrcNormalTextSize="24sp"
|
||||
app:lrcPadding="24dp"
|
||||
app:lrcTextGravity="left"
|
||||
app:lrcTextSize="28sp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/noLyricsFound"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:text="@string/no_lyrics_found"
|
||||
android:textSize="24sp"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/edit_button"
|
||||
|
|
|
@ -1,29 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<ScrollView
|
||||
android:id="@+id/nomal_lyrics_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scrollbars="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/normalLyrics"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:padding="@dimen/normal_lyrics_padding"
|
||||
android:textIsSelectable="true"
|
||||
android:textSize="@dimen/lyrics_text_size" />
|
||||
</ScrollView>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/noLyricsFound"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:gravity="center"
|
||||
android:text="@string/no_lyrics_found"
|
||||
android:textSize="24sp"
|
||||
android:visibility="gone" />
|
||||
</FrameLayout>
|
|
@ -1,18 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/synced_lyrics_container"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<code.name.monkey.retromusic.lyrics.LrcView
|
||||
android:id="@+id/lyricsView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"
|
||||
app:lrcLabel="@string/no_lyrics_found"
|
||||
app:lrcNormalTextSize="24sp"
|
||||
app:lrcPadding="24dp"
|
||||
app:lrcTextGravity="left"
|
||||
app:lrcTextSize="28sp" />
|
||||
</FrameLayout>
|
|
@ -42,7 +42,7 @@
|
|||
|
||||
</FrameLayout>
|
||||
|
||||
<code.name.monkey.retromusic.views.BottomNavigationBarTinted
|
||||
<code.name.monkey.retromusic.views.TintedBottomNavigationView
|
||||
android:id="@+id/navigationView"
|
||||
style="@style/Widget.Material3.BottomNavigationView"
|
||||
android:layout_width="match_parent"
|
||||
|
|
|
@ -125,5 +125,5 @@
|
|||
|
||||
<fragment
|
||||
android:id="@+id/lyrics_fragment"
|
||||
android:name="code.name.monkey.retromusic.fragments.other.LyricsFragment" />
|
||||
android:name="code.name.monkey.retromusic.fragments.lyrics.LyricsFragment" />
|
||||
</navigation>
|
|
@ -94,6 +94,7 @@
|
|||
<string name="black_theme_name">Just Black</string>
|
||||
<string name="blacklist">Blacklist</string>
|
||||
<string name="bluetooth_summary">The app needs nearby devices permission to check for bluetooth devices</string>
|
||||
<string name="bluetooth_title">Nearby devices</string>
|
||||
<string name="blur">Blur</string>
|
||||
<string name="blur_card">Blur Card</string>
|
||||
<string name="bug_report_failed">Unable to send report</string>
|
||||
|
@ -561,5 +562,4 @@
|
|||
<string name="you_have_to_select_at_least_one_category">You have to select at least one category.</string>
|
||||
<string name="you_will_be_forwarded_to_the_issue_tracker_website">You will be forwarded to the issue tracker website.</string>
|
||||
<string name="your_account_data_is_only_used_for_authentication">Your account data is only used for authentication.</string>
|
||||
<string name="bluetooth_title">Nearby devices</string>
|
||||
</resources>
|
||||
|
|
|
@ -56,14 +56,6 @@
|
|||
android:title="@string/pref_title_toggle_toggle_headset"
|
||||
app:icon="@drawable/ic_play_arrow" />
|
||||
|
||||
<code.name.monkey.appthemehelper.common.prefs.supportv7.ATESwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="toggle_shuffle"
|
||||
android:layout="@layout/list_item_view_switch"
|
||||
android:summary="@string/pref_summary_toggle_shuffle"
|
||||
android:title="@string/pref_title_toggle_toggle_shuffle"
|
||||
app:icon="@drawable/ic_shuffle" />
|
||||
|
||||
<code.name.monkey.appthemehelper.common.prefs.supportv7.ATESwitchPreference
|
||||
android:defaultValue="false"
|
||||
android:key="bluetooth_playback"
|
||||
|
|
20
app/src/normal/AndroidManifest.xml
Normal file
|
@ -0,0 +1,20 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
package="code.name.monkey.retromusic">
|
||||
|
||||
<uses-permission android:name="com.android.vending.BILLING" />
|
||||
|
||||
<application tools:ignore="MissingApplicationIcon">
|
||||
<activity android:name=".activities.PurchaseActivity" />
|
||||
|
||||
<meta-data
|
||||
android:name="com.android.vending.splits.required"
|
||||
android:value="true" />
|
||||
|
||||
<!-- ChromeCast -->
|
||||
<meta-data
|
||||
android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
|
||||
android:value="code.name.monkey.retromusic.cast.CastOptionsProvider" />
|
||||
</application>
|
||||
</manifest>
|
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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) {
|
|
@ -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)
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
@file:Suppress("unused")
|
||||
|
||||
package code.name.monkey.retromusic.cast
|
||||
|
||||
import android.content.Context
|
||||
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
|
||||
|
||||
|
||||
class CastOptionsProvider : OptionsProvider {
|
||||
override fun getCastOptions(context: Context): CastOptions {
|
||||
val mediaOptions = CastMediaOptions.Builder().setNotificationOptions(null).build()
|
||||
return CastOptions.Builder()
|
||||
.setReceiverApplicationId(DEFAULT_MEDIA_RECEIVER_APPLICATION_ID)
|
||||
.setCastMediaOptions(mediaOptions)
|
||||
.build()
|
||||
}
|
||||
|
||||
override fun getAdditionalSessionProviders(context: Context): MutableList<SessionProvider>? {
|
||||
return null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
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 com.google.android.play.core.splitinstall.SplitInstallSessionState
|
||||
import com.google.android.play.core.splitinstall.SplitInstallStateUpdatedListener
|
||||
import java.util.*
|
||||
|
||||
fun Context.setUpMediaRouteButton(menu: Menu) {
|
||||
CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.action_cast)
|
||||
}
|
||||
|
||||
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 =
|
||||
SplitInstallRequest.newBuilder().addLanguage(Locale.forLanguageTag(code))
|
||||
.build()
|
||||
manager.startInstall(request)
|
||||
// Recreate the activity on download complete
|
||||
.addOnSuccessListener {
|
||||
mySessionId = it
|
||||
}
|
||||
.addOnFailureListener {
|
||||
showToast("Language download failed.")
|
||||
}
|
||||
} else {
|
||||
recreate()
|
||||
}
|
||||
}
|
||||
|
||||
fun Context.goToProVersion() {
|
||||
startActivity(Intent(this, PurchaseActivity::class.java))
|
||||
}
|
||||
|
||||
fun Context.installSplitCompat() {
|
||||
SplitCompat.install(this)
|
||||
}
|
|
@ -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)) {
|
|
@ -1,52 +0,0 @@
|
|||
package code.name.monkey.appthemehelper.util
|
||||
|
||||
import android.content.res.ColorStateList
|
||||
import androidx.annotation.ColorInt
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import com.google.android.material.bottomnavigation.BottomNavigationView
|
||||
import com.google.android.material.navigation.NavigationView
|
||||
|
||||
/**
|
||||
* @author Karim Abou Zeid (kabouzeid)
|
||||
*/
|
||||
object NavigationViewUtil {
|
||||
|
||||
fun setItemIconColors(navigationView: NavigationView, @ColorInt normalColor: Int, @ColorInt selectedColor: Int) {
|
||||
val iconSl = ColorStateList(
|
||||
arrayOf(
|
||||
intArrayOf(-android.R.attr.state_checked),
|
||||
intArrayOf(android.R.attr.state_checked)
|
||||
), intArrayOf(normalColor, selectedColor)
|
||||
)
|
||||
navigationView.itemIconTintList = iconSl
|
||||
val drawable = navigationView.itemBackground
|
||||
navigationView.itemBackground = TintHelper.createTintedDrawable(
|
||||
drawable,
|
||||
ColorUtil.withAlpha(ThemeStore.accentColor(navigationView.context), 0.2f)
|
||||
)
|
||||
}
|
||||
|
||||
fun setItemTextColors(navigationView: NavigationView, @ColorInt normalColor: Int, @ColorInt selectedColor: Int) {
|
||||
val textSl = ColorStateList(
|
||||
arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked)),
|
||||
intArrayOf(normalColor, selectedColor)
|
||||
)
|
||||
navigationView.itemTextColor = textSl
|
||||
}
|
||||
|
||||
fun setItemIconColors(bottomNavigationView: BottomNavigationView, @ColorInt normalColor: Int, @ColorInt selectedColor: Int) {
|
||||
val iconSl = ColorStateList(
|
||||
arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked)),
|
||||
intArrayOf(normalColor, selectedColor)
|
||||
)
|
||||
bottomNavigationView.itemIconTintList = iconSl
|
||||
}
|
||||
|
||||
fun setItemTextColors(bottomNavigationView: BottomNavigationView, @ColorInt normalColor: Int, @ColorInt selectedColor: Int) {
|
||||
val textSl = ColorStateList(
|
||||
arrayOf(intArrayOf(-android.R.attr.state_checked), intArrayOf(android.R.attr.state_checked)),
|
||||
intArrayOf(normalColor, selectedColor)
|
||||
)
|
||||
bottomNavigationView.itemTextColor = textSl
|
||||
}
|
||||
}
|
|
@ -3,10 +3,12 @@
|
|||
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'
|
||||
core_version='1.8.0'
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
|
1
fastlane/metadata/android/en-US/changelogs/10596.txt
Normal file
|
@ -0,0 +1 @@
|
|||
Added lyrics downloading
|
20
fastlane/metadata/android/en-US/full_description.txt
Normal file
|
@ -0,0 +1,20 @@
|
|||
Retro Music Player 🎵
|
||||
|
||||
<b>📦 Included Features</b>
|
||||
<ul>
|
||||
<li>Base 3 themes (Clearly White, Kinda Dark and Just Black)</li>
|
||||
<li>Material You support on Android 12+</li>
|
||||
<li>Gapless playback</li>
|
||||
<li>Crossfade playback</li>
|
||||
<li>Choose from 10+ now playing themes</li>
|
||||
<li>Android auto support</li>
|
||||
<li>Wallpaper accent picker on Android 8.1+</li>
|
||||
<li>Home screen widgets</li>
|
||||
<li>Lock screen playback controls</li>
|
||||
<li>Sleep timer</li>
|
||||
<li>Easy drag to sort playlist & play queue</li>
|
||||
<li>Tag editor</li>
|
||||
<li>Create, edit and import playlists</li>
|
||||
<li>Browse and play your music by songs, albums, artists, playlists and genre</li>
|
||||
<li>Smart Auto Playlists - Recently played, most played and history</li>
|
||||
</ul>
|
BIN
fastlane/metadata/android/en-US/images/logo.png
Normal file
After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 578 KiB After Width: | Height: | Size: 578 KiB |
Before Width: | Height: | Size: 692 KiB After Width: | Height: | Size: 692 KiB |
Before Width: | Height: | Size: 687 KiB After Width: | Height: | Size: 687 KiB |
Before Width: | Height: | Size: 688 KiB After Width: | Height: | Size: 688 KiB |
Before Width: | Height: | Size: 355 KiB After Width: | Height: | Size: 355 KiB |
Before Width: | Height: | Size: 928 KiB After Width: | Height: | Size: 928 KiB |
Before Width: | Height: | Size: 985 KiB After Width: | Height: | Size: 985 KiB |
Before Width: | Height: | Size: 328 KiB After Width: | Height: | Size: 328 KiB |
1
fastlane/metadata/android/en-US/short_description.txt
Normal file
|
@ -0,0 +1 @@
|
|||
Material You Design Music player for Android
|