Merge branch 'Better_Player' into dev

# Conflicts:
#	app/build.gradle
This commit is contained in:
Prathamesh More 2022-05-26 20:16:44 +05:30
commit 5d0b5b91b0
175 changed files with 2308 additions and 2845 deletions

View file

@ -15,7 +15,7 @@ android {
applicationId "code.name.monkey.retromusic"
versionCode 10584
versionName '5.8.4'
versionName '5.9.0'
buildConfigField("String", "GOOGLE_PLAY_LICENSING_KEY", "\"${getProperty(getProperties('../public.properties'), 'GOOGLE_PLAY_LICENSE_KEY')}\"")
}
@ -51,8 +51,7 @@ android {
}
}
lint {
abortOnError false
disable 'MissingTranslation', 'InvalidPackage'
disable 'MissingTranslation', 'ImpliedQuantity'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
@ -90,7 +89,7 @@ dependencies {
implementation "androidx.cardview:cardview:1.0.0"
implementation "androidx.appcompat:appcompat:$appcompat_version"
implementation 'androidx.annotation:annotation:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
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.7.0'
@ -116,9 +115,11 @@ dependencies {
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
implementation "androidx.core:core-splashscreen:1.0.0-beta02"
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'
implementation 'com.google.android.play:core-ktx:1.8.1'
implementation "com.google.android.material:material:$mdc_version"
def retrofit_version = '2.9.0'
@ -165,6 +166,6 @@ dependencies {
implementation 'com.github.dhaval2404:imagepicker:2.1'
implementation 'me.zhanghai.android.fastscroll:library:1.1.8'
implementation 'cat.ereza:customactivityoncrash:2.3.0'
implementation 'me.tankery.lib:circularSeekBar:1.3.2'
implementation 'me.tankery.lib:circularSeekBar:1.4.0'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
}

View file

@ -23,7 +23,10 @@
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" />
<uses-permission
android:name="android.permission.BLUETOOTH_CONNECT"
android:usesPermissionFlags="neverForLocation"
tools:targetApi="s" />
<application
android:name=".App"
@ -113,7 +116,6 @@
<data android:mimeType="vnd.android.cursor.dir/audio" />
</intent-filter>
</activity>
<activity android:name=".activities.SettingsActivity" />
<activity android:name=".activities.tageditor.AlbumTagEditorActivity" />
<activity android:name=".activities.tageditor.SongTagEditorActivity" />
<activity android:name=".activities.SupportDevelopmentActivity" />
@ -123,7 +125,10 @@
<activity android:name=".activities.ShareInstagramStory" />
<activity android:name=".activities.DriveModeActivity" />
<activity android:name=".activities.PermissionActivity" />
<activity android:name=".activities.LockScreenActivity" />
<activity
android:name=".activities.LockScreenActivity"
android:launchMode="singleTop"
android:showOnLockScreen="true" />
<activity
android:name=".fragments.backup.RestoreActivity"
android:excludeFromRecents="false"
@ -170,20 +175,6 @@
android:name=".activities.saf.SAFGuideActivity"
android:theme="@style/Theme.Intro" />
<activity
android:name=".cast.ExpandedControlsActivity"
android:exported="true"
android:launchMode="singleTask"
android:screenOrientation="portrait"
android:theme="@style/Theme.AppCompat.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
</intent-filter>
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".activities.MainActivity" />
</activity>
<activity
android:name=".activities.ErrorActivity"
android:exported="true">
@ -192,16 +183,6 @@
</intent-filter>
</activity>
<provider
android:name=".misc.GenericFileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="${applicationId}"

View file

@ -62,6 +62,19 @@
</head>
<body>
<div>
<h5>May 14, 2022</h5>
<h2>v5.9.0</h2>
<h3>What's New</h3>
<ul>
<li>Better Cast</li>
<li>Mini player in settings screen</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fixed Top/Recent Artists/Albums not updating (Wrong sort order)</li>
</ul>
</div>
<div>
<h5>May 13, 2022</h5>
<h2>v5.8.4</h2>

View file

@ -20,6 +20,7 @@ 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.helper.WallpaperAccentManager
@ -69,7 +70,7 @@ class App : Application() {
})
// setting Error activity
CaocConfig.Builder.create().errorActivity(ErrorActivity::class.java).apply()
CaocConfig.Builder.create().errorActivity(ErrorActivity::class.java).restartActivity(MainActivity::class.java).apply()
}
override fun onTerminate() {

View file

@ -88,12 +88,7 @@ const val CIRCULAR_ALBUM_ART = "circular_album_art"
const val USER_NAME = "user_name"
const val TOGGLE_FULL_SCREEN = "toggle_full_screen"
const val TOGGLE_VOLUME = "toggle_volume"
const val ROUND_CORNERS = "corner_window"
const val TOGGLE_GENRE = "toggle_genre"
const val PROFILE_IMAGE_PATH = "profile_image_path"
const val BANNER_IMAGE_PATH = "banner_image_path"
const val ADAPTIVE_COLOR_APP = "adaptive_color_app"
const val TOGGLE_SEPARATE_LINE = "toggle_separate_line"
const val HOME_ARTIST_GRID_STYLE = "home_artist_grid_style"
const val HOME_ALBUM_GRID_STYLE = "home_album_grid_style"
const val TOGGLE_ADD_CONTROLS = "toggle_add_controls"
@ -108,7 +103,6 @@ const val SAF_SDCARD_URI = "saf_sdcard_uri"
const val SONG_SORT_ORDER = "song_sort_order"
const val SONG_GRID_SIZE = "song_grid_size"
const val GENRE_SORT_ORDER = "genre_sort_order"
const val LAST_PAGE = "last_start_page"
const val BLUETOOTH_PLAYBACK = "bluetooth_playback"
const val INITIALIZED_BLACKLIST = "initialized_blacklist"
const val ARTIST_SORT_ORDER = "artist_sort_order"

View file

@ -3,17 +3,15 @@ package code.name.monkey.retromusic
import android.content.Context
import android.content.ContextWrapper
import android.os.LocaleList
import code.name.monkey.appthemehelper.util.VersionUtils.hasNougatMR
import com.google.android.gms.common.annotation.KeepName
import code.name.monkey.appthemehelper.util.VersionUtils.hasNougat
import java.util.*
class LanguageContextWrapper(base: Context?) : ContextWrapper(base) {
companion object {
@KeepName
fun wrap(context: Context?, newLocale: Locale?): LanguageContextWrapper {
if (context == null) return LanguageContextWrapper(context)
val configuration = context.resources.configuration
if (hasNougatMR()) {
if (hasNougat()) {
configuration.setLocale(newLocale)
val localeList = LocaleList(newLocale)
LocaleList.setDefault(localeList)

View file

@ -1,12 +1,9 @@
package code.name.monkey.retromusic
import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import code.name.monkey.retromusic.auto.AutoMusicProvider
import code.name.monkey.retromusic.cast.RetroWebServer
import code.name.monkey.retromusic.db.BlackListStoreDao
import code.name.monkey.retromusic.db.BlackListStoreEntity
import code.name.monkey.retromusic.db.MIGRATION_23_24
import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.db.RetroDatabase
import code.name.monkey.retromusic.fragments.LibraryViewModel
@ -20,10 +17,6 @@ import code.name.monkey.retromusic.network.provideLastFmRest
import code.name.monkey.retromusic.network.provideLastFmRetrofit
import code.name.monkey.retromusic.network.provideOkHttp
import code.name.monkey.retromusic.repository.*
import code.name.monkey.retromusic.util.FilePathUtil
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.koin.android.ext.koin.androidContext
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.bind
@ -49,32 +42,14 @@ private val roomModule = module {
single {
Room.databaseBuilder(androidContext(), RetroDatabase::class.java, "playlist.db")
.allowMainThreadQueries()
.addCallback(object : RoomDatabase.Callback() {
override fun onOpen(db: SupportSQLiteDatabase) {
super.onOpen(db)
GlobalScope.launch(IO) {
FilePathUtil.blacklistFilePaths().map {
get<BlackListStoreDao>().insertBlacklistPath(BlackListStoreEntity(it))
}
}
}
})
.fallbackToDestructiveMigration()
.addMigrations(MIGRATION_23_24)
.build()
}
factory {
get<RetroDatabase>().lyricsDao()
}
factory {
get<RetroDatabase>().playlistDao()
}
factory {
get<RetroDatabase>().blackListStore()
}
factory {
get<RetroDatabase>().playCountDao()
}
@ -84,7 +59,7 @@ private val roomModule = module {
}
single {
RealRoomRepository(get(), get(), get(), get(), get())
RealRoomRepository(get(), get(), get())
} bind RoomRepository::class
}
private val autoModule = module {

View file

@ -20,7 +20,6 @@ import android.graphics.Color
import android.graphics.PorterDuff
import android.os.Bundle
import android.view.animation.LinearInterpolator
import android.widget.SeekBar
import androidx.lifecycle.lifecycleScope
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
@ -36,11 +35,11 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper.Callback
import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler
import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.repository.RealRepository
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.MusicUtil
import com.google.android.material.slider.Slider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -113,17 +112,15 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
}
private fun setUpProgressSlider() {
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
onUpdateProgressViews(
MusicPlayerRemote.songProgressMillis,
MusicPlayerRemote.songDurationMillis
)
}
binding.progressSlider.addOnChangeListener { _: Slider, progress: Float, fromUser: Boolean ->
if (fromUser) {
MusicPlayerRemote.seekTo(progress.toInt())
onUpdateProgressViews(
MusicPlayerRemote.songProgressMillis,
MusicPlayerRemote.songDurationMillis
)
}
})
}
}
override fun onPause() {
@ -249,9 +246,9 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
binding.progressSlider.max = total
binding.progressSlider.valueTo = total.toFloat()
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
val animator = ObjectAnimator.ofFloat(binding.progressSlider, "value", progress.toFloat())
animator.duration = AbsPlayerControlsFragment.SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()

View file

@ -3,19 +3,19 @@ package code.name.monkey.retromusic.activities
import android.os.Bundle
import android.widget.Button
import android.widget.ImageView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import cat.ereza.customactivityoncrash.CustomActivityOnCrash
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.util.FileUtils.createFile
import code.name.monkey.retromusic.util.Share.shareFile
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import java.text.DateFormat
import java.text.SimpleDateFormat
import java.util.*
class ErrorActivity : AppCompatActivity() {
private val dayFormat: DateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
private val ReportPrefix = "bug_report-"
private val reportPrefix = "bug_report-"
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.customactivityoncrash_default_error_activity)
@ -39,7 +39,7 @@ class ErrorActivity : AppCompatActivity() {
findViewById<Button>(R.id.customactivityoncrash_error_activity_more_info_button)
moreInfoButton.setOnClickListener { //We retrieve all the error data and show it
AlertDialog.Builder(this@ErrorActivity)
MaterialAlertDialogBuilder(this@ErrorActivity)
.setTitle(R.string.customactivityoncrash_error_activity_error_details_title)
.setMessage(
CustomActivityOnCrash.getAllErrorDetailsFromIntent(
@ -58,13 +58,13 @@ class ErrorActivity : AppCompatActivity() {
val bugReport = createFile(
context = this,
"Bug Report",
"$ReportPrefix${dayFormat.format(Date())}",
"$reportPrefix${dayFormat.format(Date())}",
CustomActivityOnCrash.getAllErrorDetailsFromIntent(
this@ErrorActivity,
intent
), ".txt"
)
shareFile(this, bugReport)
shareFile(this, bugReport, "text/*")
}
.show()
}

View file

@ -15,18 +15,16 @@
package code.name.monkey.retromusic.activities
import android.content.Intent
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.net.Uri
import android.os.Bundle
import android.provider.MediaStore
import androidx.lifecycle.lifecycleScope
import androidx.navigation.contains
import androidx.navigation.ui.setupWithNavController
import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsCastActivity
import code.name.monkey.retromusic.databinding.SlidingMusicPanelLayoutBinding
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.settings.OnThemeChangedListener
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.SearchQueryHelper.getSongs
import code.name.monkey.retromusic.interfaces.IScrollHelper
@ -36,20 +34,17 @@ import code.name.monkey.retromusic.repository.PlaylistSongsLoader
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.AppRater
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.logE
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
import org.koin.android.ext.android.get
class MainActivity : AbsCastActivity(), OnSharedPreferenceChangeListener {
class MainActivity : AbsCastActivity(), OnThemeChangedListener {
companion object {
const val TAG = "MainActivity"
const val EXPAND_PANEL = "expand_panel"
}
override fun createContentView(): SlidingMusicPanelLayoutBinding {
return wrapSlidingMusicPanel()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setTaskDescriptionColorAuto()
@ -58,9 +53,7 @@ class MainActivity : AbsCastActivity(), OnSharedPreferenceChangeListener {
AppRater.appLaunched(this)
setupNavigationController()
if (!hasPermissions()) {
findNavController(R.id.fragment_container).navigate(R.id.permissionFragment)
}
WhatsNewFragment.showChangeLog(this)
}
@ -137,20 +130,18 @@ class MainActivity : AbsCastActivity(), OnSharedPreferenceChangeListener {
}
}
override fun onResume() {
super.onResume()
PreferenceUtil.registerOnSharedPreferenceChangedListener(this)
override fun onThemeValuesChanged() {
restart()
}
override fun onDestroy() {
super.onDestroy()
PreferenceUtil.unregisterOnSharedPreferenceChangedListener(this)
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
if (key == GENERAL_THEME || key == MATERIAL_YOU || key == WALLPAPER_ACCENT || key == BLACK_THEME || key == ADAPTIVE_COLOR_APP || key == USER_NAME || key == TOGGLE_FULL_SCREEN || key == TOGGLE_VOLUME || key == ROUND_CORNERS || key == CAROUSEL_EFFECT || key == NOW_PLAYING_SCREEN_ID || key == TOGGLE_GENRE || key == BANNER_IMAGE_PATH || key == PROFILE_IMAGE_PATH || key == CIRCULAR_ALBUM_ART || key == KEEP_SCREEN_ON || key == TOGGLE_SEPARATE_LINE || key == TOGGLE_HOME_BANNER || key == TOGGLE_ADD_CONTROLS || key == ALBUM_COVER_STYLE || key == HOME_ARTIST_GRID_STYLE || key == ALBUM_COVER_TRANSFORM || key == DESATURATED_COLOR || key == EXTRA_SONG_INFO || key == TAB_TEXT_MODE || key == LANGUAGE_NAME || key == LIBRARY_CATEGORIES || key == CUSTOM_FONT || key == APPBAR_MODE || key == CIRCLE_PLAY_BUTTON || key == SWIPE_DOWN_DISMISS) {
postRecreate()
private fun restart() {
val savedInstanceState = Bundle().apply {
onSaveInstanceState(this)
}
finish()
val intent = Intent(this, this::class.java).putExtra(TAG, savedInstanceState)
startActivity(intent)
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
}
override fun onServiceConnected() {
@ -220,7 +211,7 @@ class MainActivity : AbsCastActivity(), OnSharedPreferenceChangeListener {
private fun parseLongFromIntent(
intent: Intent,
longKey: String,
stringKey: String
stringKey: String,
): Long {
var id = intent.getLongExtra(longKey, -1)
if (id < 0) {
@ -229,7 +220,7 @@ class MainActivity : AbsCastActivity(), OnSharedPreferenceChangeListener {
try {
id = idString.toLong()
} catch (e: NumberFormatException) {
println(e.message)
logE(e)
}
}
}

View file

@ -63,7 +63,7 @@ class PermissionActivity : AbsMusicServiceActivity() {
binding.bluetoothPermission.setButtonClick {
ActivityCompat.requestPermissions(this,
arrayOf(BLUETOOTH_CONNECT),
PERMISSION_REQUEST)
BLUETOOTH_PERMISSION_REQUEST)
}
}

View file

@ -24,7 +24,7 @@ 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.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.activities.base.AbsThemeActivity
import code.name.monkey.retromusic.databinding.ActivityProVersionBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.setLightStatusBar
@ -33,7 +33,7 @@ import code.name.monkey.retromusic.extensions.showToast
import com.anjlab.android.iab.v3.BillingProcessor
import com.anjlab.android.iab.v3.PurchaseInfo
class PurchaseActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler {
class PurchaseActivity : AbsThemeActivity(), BillingProcessor.IBillingHandler {
private lateinit var binding: ActivityProVersionBinding
private lateinit var billingProcessor: BillingProcessor

View file

@ -25,7 +25,7 @@ import androidx.core.net.toUri
import androidx.core.view.drawToBitmap
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.activities.base.AbsThemeActivity
import code.name.monkey.retromusic.databinding.ActivityShareInstagramBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.setLightStatusBar
@ -41,7 +41,7 @@ import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
* Created by hemanths on 2020-02-02.
*/
class ShareInstagramStory : AbsBaseActivity() {
class ShareInstagramStory : AbsThemeActivity() {
private lateinit var binding: ActivityShareInstagramBinding

View file

@ -30,7 +30,7 @@ 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.AbsBaseActivity
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.*
@ -38,7 +38,7 @@ import com.anjlab.android.iab.v3.BillingProcessor
import com.anjlab.android.iab.v3.PurchaseInfo
import com.anjlab.android.iab.v3.SkuDetails
class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler {
class SupportDevelopmentActivity : AbsThemeActivity(), BillingProcessor.IBillingHandler {
lateinit var binding: ActivityDonationBinding
@ -91,8 +91,7 @@ class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingH
private fun loadSkuDetails() {
binding.progressContainer.isVisible = true
binding.recyclerView.isVisible = false
val ids =
resources.getStringArray(DONATION_PRODUCT_IDS)
val ids = resources.getStringArray(DONATION_PRODUCT_IDS)
billingProcessor!!.getPurchaseListingDetailsAsync(
ArrayList(listOf(*ids)),
object : BillingProcessor.ISkuDetailsResponseListener {
@ -139,7 +138,7 @@ class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingH
class SkuDetailsAdapter(
private var donationsDialog: SupportDevelopmentActivity,
objects: List<SkuDetails>
objects: List<SkuDetails>,
) : RecyclerView.Adapter<SkuDetailsAdapter.ViewHolder>() {
private var skuDetailsList: List<SkuDetails> = ArrayList()
@ -175,7 +174,7 @@ class SkuDetailsAdapter(
override fun onBindViewHolder(viewHolder: ViewHolder, i: Int) {
val skuDetails = skuDetailsList[i]
with(viewHolder.binding) {
itemTitle.text = skuDetails.title.replace("Music Player - MP3 Player - Retro", "")
itemTitle.text = skuDetails.title.replace("Retro Music Player MP3 Player", "")
.trim { it <= ' ' }
itemText.text = skuDetails.description
itemText.isVisible = false
@ -200,7 +199,7 @@ class SkuDetailsAdapter(
strikeThrough(itemPrice, purchased)
}
viewHolder.itemView.setOnTouchListener { _, _ -> purchased }
viewHolder.itemView.isEnabled = !purchased
viewHolder.itemView.setOnClickListener { donationsDialog.donate(i) }
}

View file

@ -32,6 +32,8 @@ import androidx.core.content.getSystemService
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.rootView
import code.name.monkey.retromusic.util.logD
import com.google.android.material.snackbar.Snackbar
abstract class AbsBaseActivity : AbsThemeActivity() {
@ -52,7 +54,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
}
private val snackBarContainer: View
get() = window.decorView
get() = rootView
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@ -75,7 +77,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
protected open fun onHasPermissionsChanged(hasPermissions: Boolean) {
// implemented by sub classes
println(hasPermissions)
logD(hasPermissions)
}
override fun dispatchKeyEvent(event: KeyEvent): Boolean {
@ -114,33 +116,19 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
for (grantResult in grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(
this@AbsBaseActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE
this@AbsBaseActivity, Manifest.permission.READ_EXTERNAL_STORAGE,
) || ActivityCompat.shouldShowRequestPermissionRationale(
this@AbsBaseActivity, Manifest.permission.WRITE_EXTERNAL_STORAGE,
)
) {
// User has deny from permission dialog
Snackbar.make(
snackBarContainer,
permissionDeniedMessage!!,
Snackbar.LENGTH_INDEFINITE
Snackbar.LENGTH_SHORT
)
.setAction(R.string.action_grant) { requestPermissions() }
.setActionTextColor(accentColor()).show()
} else if (ActivityCompat.shouldShowRequestPermissionRationale(
this@AbsBaseActivity, Manifest.permission.BLUETOOTH_CONNECT
)
) {
// User has deny from permission dialog
Snackbar.make(
snackBarContainer,
R.string.permission_bluetooth_denied,
Snackbar.LENGTH_INDEFINITE
)
.setAction(R.string.action_grant) {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.BLUETOOTH_CONNECT),
PERMISSION_REQUEST)
}
.setActionTextColor(accentColor()).show()
} else {
// User has deny permission and checked never show permission dialog so you can redirect to Application settings page
Snackbar.make(
@ -165,11 +153,34 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
}
hadPermissions = true
onHasPermissionsChanged(true)
} else if (requestCode == BLUETOOTH_PERMISSION_REQUEST) {
for (grantResult in grantResults) {
if (grantResult != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.shouldShowRequestPermissionRationale(
this@AbsBaseActivity, Manifest.permission.BLUETOOTH_CONNECT
)
) {
// User has deny from permission dialog
Snackbar.make(
snackBarContainer,
R.string.permission_bluetooth_denied,
Snackbar.LENGTH_SHORT
)
.setAction(R.string.action_grant) {
ActivityCompat.requestPermissions(this,
arrayOf(Manifest.permission.BLUETOOTH_CONNECT),
BLUETOOTH_PERMISSION_REQUEST)
}
.setActionTextColor(accentColor()).show()
}
}
}
}
}
companion object {
const val PERMISSION_REQUEST = 100
const val BLUETOOTH_PERMISSION_REQUEST = 101
}
// this lets keyboard close when clicked in background

View file

@ -1,13 +1,10 @@
package code.name.monkey.retromusic.activities.base
import android.os.Bundle
import code.name.monkey.retromusic.cast.CastHelper
import code.name.monkey.retromusic.cast.RetroSessionManagerListener
import code.name.monkey.retromusic.cast.RetroWebServer
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import com.google.android.gms.cast.framework.CastContext
import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.cast.framework.SessionManager
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
import org.koin.android.ext.android.inject
@ -16,10 +13,20 @@ import org.koin.android.ext.android.inject
abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() {
private var mCastSession: CastSession? = null
private lateinit var sessionManager: SessionManager
private val sessionManager by lazy {
CastContext.getSharedInstance(this).sessionManager
}
private val webServer: RetroWebServer by inject()
private var playServicesAvailable: Boolean = false
private val playServicesAvailable: Boolean by lazy {
try {
GoogleApiAvailability
.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS
} catch (e: Exception) {
false
}
}
private val sessionManagerListener by lazy {
object : RetroSessionManagerListener {
@ -30,20 +37,7 @@ abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() {
override fun onSessionStarted(castSession: CastSession, p1: String) {
invalidateOptionsMenu()
mCastSession = castSession
loadCastQueue()
MusicPlayerRemote.isCasting = true
setAllowDragging(false)
collapsePanel()
}
override fun onSessionEnding(castSession: CastSession) {
MusicPlayerRemote.isCasting = false
castSession.remoteMediaClient?.let {
val position = it.mediaQueue.indexOfItemWithId(it.currentItem?.itemId ?: 0)
val progress = it.approximateStreamPosition
MusicPlayerRemote.position = position
MusicPlayerRemote.seekTo(progress.toInt())
}
MusicPlayerRemote.switchToRemotePlayback(castSession)
}
override fun onSessionEnded(castSession: CastSession, p1: Int) {
@ -51,7 +45,7 @@ abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() {
if (mCastSession == castSession) {
mCastSession = null
}
setAllowDragging(true)
MusicPlayerRemote.switchToLocalPlayback()
webServer.stop()
}
@ -59,14 +53,7 @@ abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() {
invalidateOptionsMenu()
mCastSession = castSession
webServer.start()
mCastSession?.remoteMediaClient?.let {
loadCastQueue(it.mediaQueue.indexOfItemWithId(it.currentItem?.itemId ?: 0),
it.approximateStreamPosition)
}
MusicPlayerRemote.isCasting = true
setAllowDragging(false)
collapsePanel()
MusicPlayerRemote.switchToRemotePlayback(castSession)
}
override fun onSessionSuspended(castSession: CastSession, p1: Int) {
@ -74,30 +61,12 @@ abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() {
if (mCastSession == castSession) {
mCastSession = null
}
MusicPlayerRemote.isCasting = false
setAllowDragging(true)
MusicPlayerRemote.switchToLocalPlayback()
webServer.stop()
}
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
playServicesAvailable = try {
GoogleApiAvailability
.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS
} catch (e: Exception) {
false
}
if (playServicesAvailable) {
setupCast()
}
}
private fun setupCast() {
sessionManager = CastContext.getSharedInstance(this).sessionManager
}
override fun onResume() {
super.onResume()
if (playServicesAvailable) {
@ -121,27 +90,4 @@ abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() {
mCastSession = null
}
}
fun loadCastQueue(
position: Int = MusicPlayerRemote.position,
progress: Long = MusicPlayerRemote.songProgressMillis.toLong(),
) {
mCastSession?.let {
if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
CastHelper.castQueue(
it,
MusicPlayerRemote.playingQueue,
position,
progress
)
}
}
}
override fun onQueueChanged() {
super.onQueueChanged()
if (playServicesAvailable) {
loadCastQueue()
}
}
}

View file

@ -33,6 +33,7 @@ import code.name.monkey.retromusic.service.MusicService.Companion.QUEUE_CHANGED
import code.name.monkey.retromusic.service.MusicService.Companion.REPEAT_MODE_CHANGED
import code.name.monkey.retromusic.service.MusicService.Companion.SHUFFLE_MODE_CHANGED
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.logD
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.koin.android.ext.android.inject
@ -185,7 +186,7 @@ abstract class AbsMusicServiceActivity : AbsBaseActivity(), IMusicServiceEventLi
true
) // just in case we need to know this at some point
sendBroadcast(intent)
println("sendBroadcast $hasPermissions")
logD("sendBroadcast $hasPermissions")
}
override fun getPermissionsToRequest(): Array<String> {

View file

@ -16,6 +16,8 @@ package code.name.monkey.retromusic.activities.base
import android.animation.ArgbEvaluator
import android.animation.ValueAnimator
import android.content.Intent
import android.content.SharedPreferences
import android.content.res.ColorStateList
import android.graphics.Color
import android.os.Bundle
@ -25,11 +27,14 @@ import android.view.ViewTreeObserver
import android.view.animation.PathInterpolator
import android.widget.FrameLayout
import androidx.core.animation.doOnEnd
import androidx.core.view.*
import androidx.fragment.app.Fragment
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isGone
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.commit
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.activities.PermissionActivity
import code.name.monkey.retromusic.databinding.SlidingMusicPanelLayoutBinding
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.LibraryViewModel
@ -60,12 +65,14 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.CategoryInfo
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.ViewUtil
import code.name.monkey.retromusic.util.logD
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.*
import org.koin.androidx.viewmodel.ext.android.viewModel
abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity(),
SharedPreferences.OnSharedPreferenceChangeListener {
companion object {
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
}
@ -74,13 +81,13 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
private var windowInsets: WindowInsetsCompat? = null
protected val libraryViewModel by viewModel<LibraryViewModel>()
private lateinit var bottomSheetBehavior: BottomSheetBehavior<FrameLayout>
private var playerFragment: AbsPlayerFragment? = null
private lateinit var playerFragment: AbsPlayerFragment
private var miniPlayerFragment: MiniPlayerFragment? = null
private var nowPlayingScreen: NowPlayingScreen? = null
private var taskColor: Int = 0
private var paletteColor: Int = Color.WHITE
private var navigationBarColor = 0
protected abstract fun createContentView(): SlidingMusicPanelLayoutBinding
private val panelState: Int
get() = bottomSheetBehavior.state
private lateinit var binding: SlidingMusicPanelLayoutBinding
@ -89,45 +96,47 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
private var navigationBarColorAnimator: ValueAnimator? = null
private val argbEvaluator: ArgbEvaluator = ArgbEvaluator()
private val bottomSheetCallbackList = object : BottomSheetCallback() {
private val bottomSheetCallbackList by lazy {
object : BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
setMiniPlayerAlphaProgress(slideOffset)
navigationBarColorAnimator?.cancel()
setNavigationBarColorPreOreo(
argbEvaluator.evaluate(
slideOffset,
surfaceColor(),
navigationBarColor
) as Int
)
}
override fun onSlide(bottomSheet: View, slideOffset: Float) {
setMiniPlayerAlphaProgress(slideOffset)
navigationBarColorAnimator?.cancel()
setNavigationBarColorPreOreo(
argbEvaluator.evaluate(
slideOffset,
surfaceColor(),
navigationBarColor
) as Int
)
}
override fun onStateChanged(bottomSheet: View, newState: Int) {
when (newState) {
STATE_EXPANDED -> {
onPanelExpanded()
if (PreferenceUtil.lyricsScreenOn && PreferenceUtil.showLyrics) {
keepScreenOn(true)
override fun onStateChanged(bottomSheet: View, newState: Int) {
when (newState) {
STATE_EXPANDED -> {
onPanelExpanded()
if (PreferenceUtil.lyricsScreenOn && PreferenceUtil.showLyrics) {
keepScreenOn(true)
}
}
}
STATE_COLLAPSED -> {
onPanelCollapsed()
if ((PreferenceUtil.lyricsScreenOn && PreferenceUtil.showLyrics) || !PreferenceUtil.isScreenOnEnabled) {
keepScreenOn(false)
STATE_COLLAPSED -> {
onPanelCollapsed()
if ((PreferenceUtil.lyricsScreenOn && PreferenceUtil.showLyrics) || !PreferenceUtil.isScreenOnEnabled) {
keepScreenOn(false)
}
}
}
STATE_SETTLING, STATE_DRAGGING -> {
if (fromNotification) {
binding.bottomNavigationView.bringToFront()
fromNotification = false
STATE_SETTLING, STATE_DRAGGING -> {
if (fromNotification) {
binding.bottomNavigationView.bringToFront()
fromNotification = false
}
}
STATE_HIDDEN -> {
MusicPlayerRemote.clearQueue()
}
else -> {
logD("Do a flip")
}
}
STATE_HIDDEN -> {
MusicPlayerRemote.clearQueue()
}
else -> {
println("Do a flip")
}
}
}
@ -137,12 +146,14 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = createContentView()
if (!hasPermissions()) {
startActivity(Intent(this, PermissionActivity::class.java))
finish()
}
binding = SlidingMusicPanelLayoutBinding.inflate(layoutInflater)
setContentView(binding.root)
ViewCompat.setOnApplyWindowInsetsListener(
binding.root
) { _, insets ->
windowInsets = insets
binding.root.setOnApplyWindowInsetsListener { _, insets ->
windowInsets = WindowInsetsCompat.toWindowInsetsCompat(insets)
insets
}
chooseFragmentForTheme()
@ -166,6 +177,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
override fun onResume() {
super.onResume()
PreferenceUtil.registerOnSharedPreferenceChangedListener(this)
if (nowPlayingScreen != PreferenceUtil.nowPlayingScreen) {
postRecreate()
}
@ -177,10 +189,49 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
override fun onDestroy() {
super.onDestroy()
bottomSheetBehavior.removeBottomSheetCallback(bottomSheetCallbackList)
PreferenceUtil.unregisterOnSharedPreferenceChangedListener(this)
}
protected fun wrapSlidingMusicPanel(): SlidingMusicPanelLayoutBinding {
return SlidingMusicPanelLayoutBinding.inflate(layoutInflater)
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences?, key: String?) {
when (key) {
SWIPE_DOWN_DISMISS -> {
bottomSheetBehavior.isHideable = PreferenceUtil.swipeDownToDismiss
}
TOGGLE_ADD_CONTROLS -> {
miniPlayerFragment?.setUpButtons()
}
NOW_PLAYING_SCREEN_ID, ALBUM_COVER_TRANSFORM, CAROUSEL_EFFECT,
ALBUM_COVER_STYLE, TOGGLE_VOLUME, EXTRA_SONG_INFO, CIRCLE_PLAY_BUTTON,
-> {
chooseFragmentForTheme()
onServiceConnected()
}
SWIPE_ANYWHERE_NOW_PLAYING -> {
playerFragment.addSwipeDetector()
}
ADAPTIVE_COLOR_APP -> {
if (PreferenceUtil.nowPlayingScreen in listOf(Normal, Material, Flat)) {
chooseFragmentForTheme()
onServiceConnected()
}
}
LIBRARY_CATEGORIES -> {
updateTabs()
}
TAB_TEXT_MODE -> {
bottomNavigationView.labelVisibilityMode = PreferenceUtil.tabTitleMode
}
TOGGLE_FULL_SCREEN -> {
if (!PreferenceUtil.isFullScreenMode) exitFullscreen()
setEdgeToEdgeOrImmersive()
}
SCREEN_ON_LYRICS -> {
keepScreenOn(bottomSheetBehavior.state == STATE_EXPANDED && PreferenceUtil.lyricsScreenOn && PreferenceUtil.showLyrics || PreferenceUtil.isScreenOnEnabled)
}
KEEP_SCREEN_ON -> {
maybeSetScreenOn()
}
}
}
fun collapsePanel() {
@ -224,13 +275,13 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
setLightStatusBarAuto()
setLightNavigationBarAuto()
setTaskDescriptionColor(taskColor)
playerFragment?.onHide()
//playerFragment?.onHide()
}
open fun onPanelExpanded() {
setMiniPlayerAlphaProgress(1F)
onPaletteColorChanged()
playerFragment?.onShow()
//playerFragment?.onShow()
}
private fun setupSlidingUpPanel() {
@ -260,15 +311,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
override fun onServiceConnected() {
super.onServiceConnected()
if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
binding.slidingPanel.viewTreeObserver.addOnGlobalLayoutListener(object :
ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
binding.slidingPanel.viewTreeObserver.removeOnGlobalLayoutListener(this)
hideBottomSheet(false)
}
})
} // don't call hideBottomSheet(true) here as it causes a bug with the SlidingUpPanelLayout
hideBottomSheet(false)
}
override fun onQueueChanged() {
@ -285,7 +328,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
}
private fun handleBackPress(): Boolean {
if (bottomSheetBehavior.peekHeight != 0 && playerFragment!!.onBackPressed()) return true
if (bottomSheetBehavior.peekHeight != 0 && playerFragment.onBackPressed()) return true
if (panelState == STATE_EXPANDED) {
collapsePanel()
return true
@ -343,7 +386,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
}
if (binding.bottomNavigationView.menu.size() == 1) {
isInOneTabMode = true
binding.bottomNavigationView.hide()
binding.bottomNavigationView.isVisible = false
}
}
@ -367,18 +410,20 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
)
return
}
val mAnimate = animate && bottomSheetBehavior.state == STATE_COLLAPSED
if (mAnimate) {
if (visible) {
binding.bottomNavigationView.bringToFront()
binding.bottomNavigationView.show()
if (visible xor bottomNavigationView.isVisible) {
val mAnimate = animate && bottomSheetBehavior.state == STATE_COLLAPSED
if (mAnimate) {
if (visible) {
binding.bottomNavigationView.bringToFront()
binding.bottomNavigationView.show()
} else {
binding.bottomNavigationView.hide()
}
} else {
binding.bottomNavigationView.hide()
}
} else {
binding.bottomNavigationView.isVisible = false
if (visible && bottomSheetBehavior.state != STATE_EXPANDED) {
binding.bottomNavigationView.bringToFront()
binding.bottomNavigationView.isVisible = false
if (visible && bottomSheetBehavior.state != STATE_EXPANDED) {
binding.bottomNavigationView.bringToFront()
}
}
}
hideBottomSheet(
@ -393,12 +438,10 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
animate: Boolean = false,
isBottomNavVisible: Boolean = bottomNavigationView.isVisible,
) {
val heightOfBar =
windowInsets.safeGetBottomInsets() +
if (MusicPlayerRemote.isCasting) dip(R.dimen.cast_mini_player_height) else dip(R.dimen.mini_player_height)
val heightOfBar = windowInsets.getBottomInsets() + dip(R.dimen.mini_player_height)
val heightOfBarWithTabs = heightOfBar + dip(R.dimen.bottom_nav_height)
if (hide) {
bottomSheetBehavior.peekHeight = -windowInsets.safeGetBottomInsets()
bottomSheetBehavior.peekHeight = -windowInsets.getBottomInsets()
bottomSheetBehavior.state = STATE_COLLAPSED
libraryViewModel.setFabMargin(
this,
@ -409,7 +452,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
binding.slidingPanel.elevation = 0F
binding.bottomNavigationView.elevation = 5F
if (isBottomNavVisible) {
println("List")
logD("List")
if (animate) {
bottomSheetBehavior.peekHeightAnimate(heightOfBarWithTabs)
} else {
@ -417,7 +460,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
}
libraryViewModel.setFabMargin(this, dip(R.dimen.mini_player_height_expanded))
} else {
println("Details")
logD("Details")
if (animate) {
bottomSheetBehavior.peekHeightAnimate(heightOfBar).doOnEnd {
binding.slidingPanel.bringToFront()
@ -440,7 +483,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
private fun chooseFragmentForTheme() {
nowPlayingScreen = PreferenceUtil.nowPlayingScreen
val fragment: Fragment = when (nowPlayingScreen) {
val fragment: AbsPlayerFragment = when (nowPlayingScreen) {
Blur -> BlurPlayerFragment()
Adaptive -> AdaptiveFragment()
Normal -> PlayerFragment()
@ -460,12 +503,12 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
Classic -> ClassicPlayerFragment()
MD3 -> MD3PlayerFragment()
else -> PlayerFragment()
} // must implement AbsPlayerFragment
} // must extend AbsPlayerFragment
supportFragmentManager.commit {
replace(R.id.playerFragmentContainer, fragment)
}
supportFragmentManager.executePendingTransactions()
playerFragment = whichFragment<AbsPlayerFragment>(R.id.playerFragmentContainer)
playerFragment = whichFragment(R.id.playerFragmentContainer)
miniPlayerFragment = whichFragment<MiniPlayerFragment>(R.id.miniPlayerFragment)
miniPlayerFragment?.view?.setOnClickListener { expandPanel() }
}

View file

@ -20,7 +20,6 @@ import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.KeyEvent
import android.view.View
import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode
import androidx.core.os.ConfigurationCompat
import code.name.monkey.appthemehelper.common.ATHToolbarActivity
@ -29,6 +28,7 @@ import code.name.monkey.retromusic.LanguageContextWrapper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.*
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
@ -42,14 +42,15 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
updateTheme()
hideStatusBar()
super.onCreate(savedInstanceState)
println("OnCreate")
setEdgeToEdgeOrImmersive()
registerSystemUiVisibility()
toggleScreenOn()
maybeSetScreenOn()
setLightNavigationBarAuto()
setLightStatusBarAuto(surfaceColor())
if (VersionUtils.hasQ()) {
window.decorView.isForceDarkAllowed = false
}
maybeShowAnnoyingToasts()
}
private fun updateTheme() {
@ -61,9 +62,6 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
if (PreferenceUtil.isCustomFont) {
setTheme(R.style.FontThemeOverlay)
}
if (PreferenceUtil.circlePlayButton) {
setTheme(R.style.CircleFABOverlay)
}
}
override fun onWindowFocusChanged(hasFocus: Boolean) {
@ -77,20 +75,6 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
}
}
private fun registerSystemUiVisibility() {
val decorView = window.decorView
decorView.setOnSystemUiVisibilityChangeListener { visibility ->
if (visibility and View.SYSTEM_UI_FLAG_FULLSCREEN == 0) {
setImmersiveFullscreen()
}
}
}
private fun unregisterSystemUiVisibility() {
val decorView = window.decorView
decorView.setOnSystemUiVisibilityChangeListener(null)
}
override fun run() {
setImmersiveFullscreen()
}
@ -102,7 +86,6 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
public override fun onDestroy() {
super.onDestroy()
unregisterSystemUiVisibility()
exitFullscreen()
}

View file

@ -33,8 +33,6 @@ import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.lifecycle.lifecycleScope
import androidx.viewbinding.ViewBinding
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.R.drawable
@ -48,6 +46,7 @@ import code.name.monkey.retromusic.model.ArtworkInfo
import code.name.monkey.retromusic.model.AudioTagInfo
import code.name.monkey.retromusic.repository.Repository
import code.name.monkey.retromusic.util.SAFUtil
import code.name.monkey.retromusic.util.logD
import com.google.android.material.button.MaterialButton
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.GlobalScope
@ -223,7 +222,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
getIntentExtras()
songPaths = getSongPaths()
println(songPaths?.size)
logD(songPaths?.size)
if (songPaths!!.isEmpty()) {
finish()
}
@ -276,7 +275,6 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
scaleY = 0f
isEnabled = false
setOnClickListener { save() }
TintHelper.setTintAuto(this, ThemeStore.accentColor(this@AbsTagEditorActivity), true)
}
}
@ -352,7 +350,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
hideSoftKeyboard()
hideFab()
println(fieldKeyValueMap)
logD(fieldKeyValueMap)
GlobalScope.launch {
if (VersionUtils.hasR()) {
cacheFiles = TagWriter.writeTagsToFilesR(

View file

@ -39,6 +39,7 @@ import code.name.monkey.retromusic.util.ImageUtil
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.RetroColorUtil.generatePalette
import code.name.monkey.retromusic.util.RetroColorUtil.getColor
import code.name.monkey.retromusic.util.logD
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.target.ImageViewTarget
import com.bumptech.glide.request.transition.Transition
@ -98,7 +99,7 @@ class AlbumTagEditorActivity : AbsTagEditorActivity<ActivityAlbumTagEditorBindin
binding.albumArtistText.setText(albumArtistName)
binding.genreTitle.setText(genreName)
binding.yearTitle.setText(songYear)
println(albumTitle + albumArtistName)
logD(albumTitle + albumArtistName)
}
override fun loadCurrentImage() {

View file

@ -38,6 +38,7 @@ import code.name.monkey.retromusic.repository.SongRepository
import code.name.monkey.retromusic.util.ImageUtil
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.logD
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.request.target.ImageViewTarget
import com.bumptech.glide.request.transition.Transition
@ -102,7 +103,7 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
binding.discNumberText.setText(discNumber)
binding.lyricsText.setText(lyrics)
binding.songComposerText.setText(composer)
println(songTitle + songYear)
logD(songTitle + songYear)
}
override fun loadCurrentImage() {

View file

@ -18,7 +18,6 @@ import android.annotation.SuppressLint
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.ImageView
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.AppCompatTextView
import androidx.core.os.bundleOf
@ -35,14 +34,14 @@ import code.name.monkey.retromusic.adapter.song.SongAdapter
import code.name.monkey.retromusic.fragments.home.HomeFragment
import code.name.monkey.retromusic.interfaces.IAlbumClickListener
import code.name.monkey.retromusic.interfaces.IArtistClickListener
import code.name.monkey.retromusic.interfaces.IGenreClickListener
import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.model.Album
import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.model.Home
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil
class HomeAdapter(
private val activity: AppCompatActivity
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), IArtistClickListener, IAlbumClickListener,
IGenreClickListener {
class HomeAdapter(private val activity: AppCompatActivity) :
RecyclerView.Adapter<RecyclerView.ViewHolder>(), IArtistClickListener, IAlbumClickListener {
private var list = listOf<Home>()
@ -134,6 +133,7 @@ class HomeAdapter(
notifyDataSetChanged()
}
@Suppress("UNCHECKED_CAST")
private inner class AlbumViewHolder(view: View) : AbsHomeViewItem(view) {
fun bindView(home: Home) {
title.setText(home.titleRes)
@ -144,6 +144,7 @@ class HomeAdapter(
}
}
@Suppress("UNCHECKED_CAST")
private inner class ArtistViewHolder(view: View) : AbsHomeViewItem(view) {
fun bindView(home: Home) {
title.setText(home.titleRes)
@ -154,6 +155,7 @@ class HomeAdapter(
}
}
@Suppress("UNCHECKED_CAST")
private inner class PlaylistViewHolder(view: View) : AbsHomeViewItem(view) {
fun bindView(home: Home) {
title.setText(home.titleRes)
@ -172,7 +174,6 @@ class HomeAdapter(
open class AbsHomeViewItem(itemView: View) : RecyclerView.ViewHolder(itemView) {
val recyclerView: RecyclerView = itemView.findViewById(R.id.recyclerView)
val title: AppCompatTextView = itemView.findViewById(R.id.title)
val arrow: ImageView = itemView.findViewById(R.id.arrow)
val clickableArea: ViewGroup = itemView.findViewById(R.id.clickable_area)
}
@ -209,16 +210,4 @@ class HomeAdapter(
)
)
}
override fun onClickGenre(genre: Genre, view: View) {
activity.findNavController(R.id.fragment_container).navigate(
R.id.genreDetailsFragment,
bundleOf(EXTRA_GENRE to genre),
null,
FragmentNavigatorExtras(
view to "genre"
)
)
}
}

View file

@ -89,7 +89,7 @@ class AppWidgetCircle : BaseAppWidget() {
).toBitmap()
)
val isFavorite = runBlocking(Dispatchers.IO) {
return@runBlocking MusicUtil.repository.isSongFavorite(song.id)
return@runBlocking MusicUtil.isFavorite(song)
}
val favoriteRes =
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border

View file

@ -6,12 +6,11 @@ import code.name.monkey.retromusic.cast.RetroWebServer.Companion.PART_COVER_ART
import code.name.monkey.retromusic.cast.RetroWebServer.Companion.PART_SONG
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.RetroUtil
import com.google.android.gms.cast.*
import com.google.android.gms.cast.MediaInfo
import com.google.android.gms.cast.MediaInfo.STREAM_TYPE_BUFFERED
import com.google.android.gms.cast.MediaMetadata
import com.google.android.gms.cast.MediaMetadata.*
import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.common.images.WebImage
import org.json.JSONObject
import java.net.MalformedURLException
import java.net.URL
@ -21,39 +20,7 @@ object CastHelper {
private const val CAST_MUSIC_METADATA_ALBUM_ID = "metadata_album_id"
private const val CAST_URL_PROTOCOL = "http"
fun castSong(castSession: CastSession, song: Song) {
try {
val remoteMediaClient = castSession.remoteMediaClient
val mediaLoadOptions = MediaLoadOptions.Builder().apply {
setPlayPosition(0)
setAutoplay(true)
}.build()
remoteMediaClient?.load(song.toMediaInfo()!!, mediaLoadOptions)
} catch (e: Exception) {
e.printStackTrace()
}
}
fun castQueue(castSession: CastSession, songs: List<Song>, position: Int, progress: Long) {
try {
val remoteMediaClient = castSession.remoteMediaClient
remoteMediaClient?.queueLoad(
songs.toMediaInfoList(),
if (position != -1) position else 0,
MediaStatus.REPEAT_MODE_REPEAT_OFF,
progress,
JSONObject()
)
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun List<Song>.toMediaInfoList(): Array<MediaQueueItem> {
return map { MediaQueueItem.Builder(it.toMediaInfo()!!).build() }.toTypedArray()
}
private fun Song.toMediaInfo(): MediaInfo? {
fun Song.toMediaInfo(): MediaInfo? {
val song = this
val baseUrl: URL
try {

View file

@ -3,6 +3,7 @@
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
@ -22,12 +23,12 @@ class CastOptionsProvider : OptionsProvider {
val compatButtonActionsIndices = intArrayOf(1, 3)
val notificationOptions = NotificationOptions.Builder()
.setActions(buttonActions, compatButtonActionsIndices)
.setTargetActivityClassName(ExpandedControlsActivity::class.java.name)
.setTargetActivityClassName(MainActivity::class.java.name)
.build()
val mediaOptions = CastMediaOptions.Builder()
.setNotificationOptions(notificationOptions)
.setExpandedControllerActivityClassName(ExpandedControlsActivity::class.java.name)
.setExpandedControllerActivityClassName(MainActivity::class.java.name)
.build()
return CastOptions.Builder()

View file

@ -1,19 +0,0 @@
package code.name.monkey.retromusic.cast
import android.view.Menu
import code.name.monkey.retromusic.R
import com.google.android.gms.cast.framework.CastButtonFactory
import com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity
class ExpandedControlsActivity : ExpandedControllerActivity() {
override fun onCreateOptionsMenu(menu: Menu): Boolean {
super.onCreateOptionsMenu(menu)
menuInflater.inflate(R.menu.menu_cast, menu)
CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.action_cast)
return true
}
}

View file

@ -18,14 +18,12 @@ import androidx.room.Database
import androidx.room.RoomDatabase
@Database(
entities = [PlaylistEntity::class, SongEntity::class, HistoryEntity::class, PlayCountEntity::class, BlackListStoreEntity::class, LyricsEntity::class],
version = 23,
entities = [PlaylistEntity::class, SongEntity::class, HistoryEntity::class, PlayCountEntity::class],
version = 24,
exportSchema = false
)
abstract class RetroDatabase : RoomDatabase() {
abstract fun playlistDao(): PlaylistDao
abstract fun blackListStore(): BlackListStoreDao
abstract fun playCountDao(): PlayCountDao
abstract fun historyDao(): HistoryDao
abstract fun lyricsDao(): LyricsDao
}

View file

@ -0,0 +1,11 @@
package code.name.monkey.retromusic.db
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
val MIGRATION_23_24 = object : Migration(23, 24) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL("DROP TABLE LyricsEntity")
database.execSQL("DROP TABLE BlackListStoreEntity")
}
}

View file

@ -16,7 +16,7 @@ import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.util.PreferenceUtil
fun AppCompatActivity.toggleScreenOn() {
fun AppCompatActivity.maybeSetScreenOn() {
if (PreferenceUtil.isScreenOnEnabled) {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} else {

View file

@ -163,6 +163,15 @@ fun SeekBar.applyColor(@ColorInt color: Int) {
progressBackgroundTintList = ColorStateList.valueOf(color)
}
fun Slider.applyColor(@ColorInt color: Int) {
ColorStateList.valueOf(color).run {
thumbTintList = this
trackActiveTintList = this
trackInactiveTintList = ColorStateList.valueOf(color.addAlpha(0.1f))
haloTintList = this
}
}
fun ExtendedFloatingActionButton.accentColor() {
if (materialYou) return
val color = ThemeStore.accentColor(context)
@ -301,5 +310,9 @@ inline val @receiver:ColorInt Int.lighterColor
inline val @receiver:ColorInt Int.darkerColor
get() = ColorUtil.darkenColor(this)
inline val Int.colorStateList : ColorStateList
get() = ColorStateList.valueOf(this)
inline val Int.colorStateList: ColorStateList
get() = ColorStateList.valueOf(this)
fun @receiver:ColorInt Int.addAlpha(alpha: Float): Int {
return ColorUtil.withAlpha(this, alpha)
}

View file

@ -4,7 +4,7 @@ import androidx.core.view.WindowInsetsCompat
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil
fun WindowInsetsCompat?.safeGetBottomInsets(): Int {
fun WindowInsetsCompat?.getBottomInsets(): Int {
return if (PreferenceUtil.isFullScreenMode) {
return 0
} else {

View file

@ -7,14 +7,16 @@ import code.name.monkey.retromusic.util.MusicUtil
val Song.uri get() = MusicUtil.getSongFileUri(songId = id)
val Song.albumArtUri get() = MusicUtil.getMediaStoreAlbumCoverUri(albumId)
fun ArrayList<Song>.toMediaSessionQueue(): List<QueueItem> {
return map {
return map { song ->
val mediaDescription = MediaDescriptionCompat.Builder()
.setMediaId(it.id.toString())
.setTitle(it.title)
.setSubtitle(it.artistName)
.setMediaId(song.id.toString())
.setTitle(song.title)
.setSubtitle(song.artistName)
.setIconUri(song.albumArtUri)
.build()
QueueItem(mediaDescription, it.hashCode().toLong())
QueueItem(mediaDescription, song.hashCode().toLong())
}
}

View file

@ -40,6 +40,8 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.card.MaterialCardView
import dev.chrisbanes.insetter.applyInsetter
const val ANIM_DURATION = 300L
@Suppress("UNCHECKED_CAST")
fun <T : View> ViewGroup.inflate(@LayoutRes layout: Int): T {
return LayoutInflater.from(context).inflate(layout, this, false) as T
@ -90,10 +92,10 @@ fun BottomNavigationView.show() {
drawable.setBounds(left, parent.height, right, parent.height + height)
parent.overlay.add(drawable)
ValueAnimator.ofInt(parent.height, top).apply {
duration = 300
duration = ANIM_DURATION
interpolator = AnimationUtils.loadInterpolator(
context,
android.R.interpolator.linear_out_slow_in
android.R.interpolator.accelerate_decelerate
)
addUpdateListener {
val newTop = it.animatedValue as Int
@ -130,10 +132,10 @@ fun BottomNavigationView.hide() {
parent.overlay.add(drawable)
isGone = true
ValueAnimator.ofInt(top, parent.height).apply {
duration = 300L
duration = ANIM_DURATION
interpolator = AnimationUtils.loadInterpolator(
context,
android.R.interpolator.fast_out_linear_in
android.R.interpolator.accelerate_decelerate
)
addUpdateListener {
val newTop = it.animatedValue as Int
@ -164,7 +166,7 @@ fun View.translateYAnimate(value: Float): Animator {
fun BottomSheetBehavior<*>.peekHeightAnimate(value: Int): Animator {
return ObjectAnimator.ofInt(this, "peekHeight", value)
.apply {
duration = 300
duration = ANIM_DURATION
start()
}
}
@ -260,7 +262,7 @@ fun View.updateMargin(
@Px left: Int = marginLeft,
@Px top: Int = marginTop,
@Px right: Int = marginRight,
@Px bottom: Int = marginBottom
@Px bottom: Int = marginBottom,
) {
(layoutParams as ViewGroup.MarginLayoutParams).updateMargins(left, top, right, bottom)
}
@ -301,7 +303,7 @@ fun View.requestApplyInsetsWhenAttached() {
data class InitialPadding(
val left: Int, val top: Int,
val right: Int, val bottom: Int
val right: Int, val bottom: Int,
)
fun recordInitialPaddingForView(view: View) = InitialPadding(

View file

@ -16,7 +16,6 @@ package code.name.monkey.retromusic.fragments
import android.animation.ValueAnimator
import android.content.Context
import android.widget.Toast
import androidx.core.animation.doOnEnd
import androidx.lifecycle.*
import code.name.monkey.retromusic.*
@ -30,6 +29,7 @@ import code.name.monkey.retromusic.model.*
import code.name.monkey.retromusic.repository.RealRepository
import code.name.monkey.retromusic.util.DensityUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.logD
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch
@ -141,48 +141,47 @@ class LibraryViewModel(
}
override fun onMediaStoreChanged() {
println("onMediaStoreChanged")
logD("onMediaStoreChanged")
loadLibraryContent()
}
override fun onServiceConnected() {
println("onServiceConnected")
logD("onServiceConnected")
}
override fun onServiceDisconnected() {
println("onServiceDisconnected")
logD("onServiceDisconnected")
}
override fun onQueueChanged() {
println("onQueueChanged")
logD("onQueueChanged")
}
override fun onPlayingMetaChanged() {
println("onPlayingMetaChanged")
logD("onPlayingMetaChanged")
}
override fun onPlayStateChanged() {
println("onPlayStateChanged")
logD("onPlayStateChanged")
}
override fun onRepeatModeChanged() {
println("onRepeatModeChanged")
logD("onRepeatModeChanged")
}
override fun onShuffleModeChanged() {
println("onShuffleModeChanged")
logD("onShuffleModeChanged")
}
override fun onFavoriteStateChanged() {
println("onFavoriteStateChanged")
logD("onFavoriteStateChanged")
}
fun shuffleSongs() = viewModelScope.launch(IO) {
val songs = repository.allSongs()
MusicPlayerRemote.openAndShuffleQueue(
songs,
true
)
withContext(Main) {
MusicPlayerRemote.openAndShuffleQueue(songs, true)
}
}
fun renameRoomPlaylist(playListId: Long, name: String) = viewModelScope.launch(IO) {
@ -351,8 +350,7 @@ class LibraryViewModel(
context.getString(
R.string.added_song_count_to_playlist,
songs.size,
playlistName),
Toast.LENGTH_SHORT)
playlistName))
}
}
}

View file

@ -45,9 +45,9 @@ class MusicSeekSkipTouchListener(val activity: FragmentActivity, val next: Boole
@SuppressLint("ClickableViewAccessibility")
override fun onTouch(v: View?, event: MotionEvent?): Boolean {
val action = event?.actionMasked
if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
if (action == MotionEvent.ACTION_UP) {
job?.cancel()
if (!wasSeeking) {
if (v?.isPressed == true && !wasSeeking) {
if (next) {
MusicPlayerRemote.playNextSong()
} else {
@ -55,6 +55,8 @@ class MusicSeekSkipTouchListener(val activity: FragmentActivity, val next: Boole
}
}
wasSeeking = false
} else if (action == MotionEvent.ACTION_CANCEL) {
job?.cancel()
}
return gestureDetector.onTouchEvent(event)
}

View file

@ -62,10 +62,7 @@ import code.name.monkey.retromusic.model.Artist
import code.name.monkey.retromusic.network.Result
import code.name.monkey.retromusic.network.model.LastFmAlbum
import code.name.monkey.retromusic.repository.RealRepository
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.*
import com.afollestad.materialcab.attached.AttachedCab
import com.afollestad.materialcab.attached.destroy
import com.afollestad.materialcab.attached.isActive
@ -245,10 +242,10 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
detailsViewModel.getAlbumInfo(album).observe(viewLifecycleOwner) { result ->
when (result) {
is Result.Loading -> {
println("Loading")
logD("Loading")
}
is Result.Error -> {
println("Error")
logE("Error")
}
is Result.Success -> {
aboutAlbum(result.data)

View file

@ -367,7 +367,6 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
override fun openCab(menuRes: Int, callback: ICabCallback): AttachedCab {
cab?.let {
println("Cab")
if (it.isActive()) {
it.destroy()
}

View file

@ -180,8 +180,8 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
detailsViewModel.getArtistInfo(name, lang, null)
.observe(viewLifecycleOwner) { result ->
when (result) {
is Result.Loading -> println("Loading")
is Result.Error -> println("Error")
is Result.Loading -> logD("Loading")
is Result.Error -> logE("Error")
is Result.Success -> artistInfo(result.data)
}
}

View file

@ -22,7 +22,7 @@ import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.helper.BackupHelper
import code.name.monkey.retromusic.helper.sanitize
import code.name.monkey.retromusic.util.BackupUtil
import code.name.monkey.retromusic.util.Share
import com.afollestad.materialdialogs.input.input
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -128,12 +128,7 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
return true
}
R.id.action_share -> {
activity?.startActivity(
Intent.createChooser(
BackupUtil.createShareFileIntent(file, requireContext()),
null
)
)
Share.shareFile(requireContext(), file, "*/*")
return true
}
R.id.action_rename -> {

View file

@ -23,6 +23,7 @@ import androidx.navigation.navOptions
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.interfaces.IMusicServiceEventListener
import code.name.monkey.retromusic.util.maybeShowAnnoyingToasts
/**
* Created by hemanths on 18/08/17.
@ -63,6 +64,7 @@ open class AbsMusicServiceFragment(@LayoutRes layout: Int) : Fragment(layout),
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
serviceActivity?.addMusicServiceEventListener(this)
maybeShowAnnoyingToasts()
}
override fun onDestroyView() {

View file

@ -35,11 +35,11 @@ import code.name.monkey.retromusic.fragments.MusicSeekSkipTouchListener
import code.name.monkey.retromusic.fragments.other.VolumeFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.google.android.material.slider.Slider
/**
* Created by hemanths on 24/09/17.
@ -58,10 +58,11 @@ abstract class AbsPlayerControlsFragment(@LayoutRes layout: Int) : AbsMusicServi
var lastDisabledPlaybackControlsColor: Int = 0
var isSeeking = false
private set
private var isSeeking = false
open val progressSlider: SeekBar? = null
open val progressSlider: Slider? = null
open val seekBar: SeekBar? = null
abstract val shuffleButton: ImageButton
@ -78,45 +79,76 @@ abstract class AbsPlayerControlsFragment(@LayoutRes layout: Int) : AbsMusicServi
private var progressAnimator: ObjectAnimator? = null
override fun onUpdateProgressViews(progress: Int, total: Int) {
progressSlider?.max = total
if (seekBar == null) {
progressSlider?.valueTo = total.toFloat()
if (progress > total) return
progressSlider?.value = progress.toFloat()
if (isSeeking) {
progressSlider?.progress = progress
} else {
progressAnimator = ObjectAnimator.ofInt(progressSlider, "progress", progress).apply {
duration = SLIDER_ANIMATION_TIME
interpolator = LinearInterpolator()
start()
}
seekBar?.max = total
if (isSeeking) {
seekBar?.progress = progress
} else {
progressAnimator =
ObjectAnimator.ofInt(seekBar, "progress", progress).apply {
duration = SLIDER_ANIMATION_TIME
interpolator = LinearInterpolator()
start()
}
}
}
songTotalTime?.text = MusicUtil.getReadableDurationString(total.toLong())
songCurrentProgress?.text = MusicUtil.getReadableDurationString(progress.toLong())
}
private fun setUpProgressSlider() {
progressSlider?.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
onUpdateProgressViews(
progress,
MusicPlayerRemote.songDurationMillis
)
}
progressSlider?.addOnChangeListener(Slider.OnChangeListener { _, value, fromUser ->
onProgressChange(value.toInt(), fromUser)
})
progressSlider?.addOnSliderTouchListener(object : Slider.OnSliderTouchListener {
override fun onStartTrackingTouch(slider: Slider) {
onStartTrackingTouch()
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
isSeeking = true
progressViewUpdateHelper.stop()
progressAnimator?.cancel()
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
isSeeking = false
MusicPlayerRemote.seekTo(seekBar.progress)
progressViewUpdateHelper.start()
override fun onStopTrackingTouch(slider: Slider) {
onStopTrackingTouch(slider.value.toInt())
}
})
seekBar?.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
onProgressChange(progress, fromUser)
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
onStartTrackingTouch()
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
onStopTrackingTouch(seekBar?.progress ?: 0)
}
})
}
private fun onProgressChange(value: Int, fromUser: Boolean) {
if (fromUser) {
onUpdateProgressViews(value, MusicPlayerRemote.songDurationMillis)
}
}
private fun onStartTrackingTouch() {
isSeeking = true
progressViewUpdateHelper.stop()
progressAnimator?.cancel()
}
private fun onStopTrackingTouch(value: Int) {
isSeeking = false
MusicPlayerRemote.seekTo(value)
progressViewUpdateHelper.start()
}
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper

View file

@ -163,8 +163,10 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
R.id.now_playing -> {
requireActivity().findNavController(R.id.fragment_container).navigate(
R.id.playing_queue_fragment,
null
null,
navOptions { launchSingleTop = true }
)
mainActivity.collapsePanel()
return true
}
R.id.action_show_lyrics -> {
@ -289,6 +291,15 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
}
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
if (PreferenceUtil.circlePlayButton) {
requireContext().theme.applyStyle(R.style.CircleFABOverlay, true)
} else {
requireContext().theme.applyStyle(R.style.RoundedFABOverlay, true)
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
if (PreferenceUtil.isFullScreenMode &&
@ -316,7 +327,15 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragme
showLyricsIcon(this)
}
}
requireView().setOnTouchListener(
}
override fun onStart() {
super.onStart()
addSwipeDetector()
}
fun addSwipeDetector() {
view?.setOnTouchListener(
if (PreferenceUtil.swipeAnywhereToChangeSong) {
SwipeDetector(
requireContext(),
@ -421,8 +440,7 @@ fun goToLyrics(activity: Activity) {
findNavController(R.id.fragment_container).navigate(
R.id.lyrics_fragment,
null,
navOptions { launchSingleTop = true },
null
navOptions { launchSingleTop = true }
)
}
}

View file

@ -19,6 +19,7 @@ import androidx.recyclerview.widget.RecyclerView
import androidx.transition.TransitionManager
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.logD
import com.google.android.material.transition.MaterialFade
abstract class AbsRecyclerViewCustomGridSizeFragment<A : RecyclerView.Adapter<*>, LM : RecyclerView.LayoutManager> :
@ -73,7 +74,7 @@ abstract class AbsRecyclerViewCustomGridSizeFragment<A : RecyclerView.Adapter<*>
fun setAndSaveSortOrder(sortOrder: String) {
this.sortOrder = sortOrder
println(sortOrder)
logD(sortOrder)
saveSortOrder(sortOrder)
setSortOrder(sortOrder)
}

View file

@ -216,7 +216,7 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
override fun onMenuItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_settings -> findNavController().navigate(
R.id.settingsActivity,
R.id.settings_fragment,
null,
navOptions
)

View file

@ -24,6 +24,7 @@ import android.view.View
import android.webkit.MimeTypeMap
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.widget.PopupMenu
import androidx.appcompat.widget.Toolbar
import androidx.core.text.parseAsHtml
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
@ -66,7 +67,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.material.shape.MaterialShapeDrawable
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.transition.MaterialFadeThrough
import kotlinx.coroutines.Dispatchers
@ -83,6 +83,9 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
LoaderManager.LoaderCallbacks<List<File>>, StorageClickListener {
private var _binding: FragmentFolderBinding? = null
private val binding get() = _binding!!
val toolbar: Toolbar get() = binding.appBarLayout.toolbar
private var adapter: SongFileAdapter? = null
private var storageAdapter: StorageAdapter? = null
private var cab: AttachedCab? = null
@ -100,7 +103,7 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
_binding = FragmentFolderBinding.bind(view)
mainActivity.addMusicServiceEventListener(libraryViewModel)
mainActivity.setSupportActionBar(binding.toolbar)
mainActivity.setSupportActionBar(toolbar)
mainActivity.supportActionBar?.title = null
enterTransition = MaterialFadeThrough()
reenterTransition = MaterialFadeThrough()
@ -119,16 +122,13 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
}
}
})
binding.toolbarContainer.drawNextToNavbar()
binding.appBarLayout.statusBarForeground =
MaterialShapeDrawable.createWithElevationOverlay(requireContext())
}
private fun setUpTitle() {
binding.toolbar.setNavigationOnClickListener {
toolbar.setNavigationOnClickListener {
findNavController().navigate(R.id.action_search, null, navOptions)
}
binding.appNameText.text = resources.getString(R.string.folders)
binding.appBarLayout.title = resources.getString(R.string.folders)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
@ -185,7 +185,7 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
lifecycleScope.launch(Dispatchers.IO) {
listSongs(
requireContext(),
toList(file),
listOf(file),
AUDIO_FILE_FILTER,
fileComparator
) { songs ->
@ -226,7 +226,7 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
lifecycleScope.launch(Dispatchers.IO) {
listSongs(
requireContext(),
toList(file),
listOf(file),
AUDIO_FILE_FILTER,
fileComparator
) { songs ->
@ -264,7 +264,7 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
lifecycleScope.launch(Dispatchers.IO) {
listSongs(
requireContext(),
toList(mFile.parentFile),
listOf(mFile.parentFile),
fileFilter,
fileComparator
) { songs ->
@ -332,7 +332,7 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
}
override fun onPrepareMenu(menu: Menu) {
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), binding.toolbar)
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), toolbar)
}
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
@ -346,8 +346,8 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
menu.removeItem(R.id.action_layout_type)
menu.removeItem(R.id.action_sort_order)
ToolbarContentTintHelper.handleOnCreateOptionsMenu(
requireContext(), binding.toolbar, menu, ATHToolbarActivity.getToolbarBackgroundColor(
binding.toolbar
requireContext(), toolbar, menu, ATHToolbarActivity.getToolbarBackgroundColor(
toolbar
)
)
}
@ -374,7 +374,7 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
}
R.id.action_settings -> {
findNavController().navigate(
R.id.settingsActivity,
R.id.settings_fragment,
null,
navOptions
)
@ -501,12 +501,6 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
)
}
private fun toList(file: File): ArrayList<File> {
val files = ArrayList<File>(1)
files.add(file)
return files
}
private fun updateAdapter(files: List<File>) {
adapter?.swapDataSet(files)
val crumb = activeCrumb
@ -578,7 +572,7 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
suspend fun listSongs(
context: Context,
files: List<File>,
files: List<File?>,
fileFilter: FileFilter,
fileComparator: Comparator<File>,
doOnSongsListed: (songs: List<Song>) -> Unit

View file

@ -47,6 +47,7 @@ import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.helper.MusicPlayerRemote
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
@ -221,7 +222,7 @@ class HomeFragment :
}
private fun loadSuggestions(songs: List<Song>) {
if (songs.isEmpty()) {
if (!PreferenceUtil.homeSuggestions || songs.isEmpty()) {
binding.suggestions.root.isVisible = false
return
}
@ -277,7 +278,7 @@ class HomeFragment :
override fun onMenuItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_settings -> findNavController().navigate(
R.id.settingsActivity,
R.id.settings_fragment,
null,
navOptions
)

View file

@ -105,7 +105,7 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
override fun onMenuItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_settings -> findNavController().navigate(
R.id.settingsActivity,
R.id.settings_fragment,
null,
navOptions
)

View file

@ -282,7 +282,6 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
override fun openCab(menuRes: Int, callback: ICabCallback): AttachedCab {
cab?.let {
println("Cab")
if (it.isActive()) {
it.destroy()
}

View file

@ -66,7 +66,10 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(R.layout.fragment_mini_p
_binding = FragmentMiniPlayerBinding.bind(view)
view.setOnTouchListener(FlingPlayBackController(requireContext()))
setUpMiniPlayer()
setUpButtons()
}
fun setUpButtons() {
if (RetroUtil.isTablet) {
binding.actionNext.show()
binding.actionPrevious.show()

View file

@ -21,7 +21,6 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.SeekBar
import androidx.core.content.getSystemService
import androidx.fragment.app.Fragment
import code.name.monkey.appthemehelper.ThemeStore
@ -32,8 +31,9 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.volume.AudioVolumeObserver
import code.name.monkey.retromusic.volume.OnAudioVolumeChangedListener
import com.google.android.material.slider.Slider
class VolumeFragment : Fragment(), SeekBar.OnSeekBarChangeListener, OnAudioVolumeChangedListener,
class VolumeFragment : Fragment(), Slider.OnChangeListener, OnAudioVolumeChangedListener,
View.OnClickListener {
private var _binding: FragmentVolumeBinding? = null
@ -47,7 +47,7 @@ class VolumeFragment : Fragment(), SeekBar.OnSeekBarChangeListener, OnAudioVolum
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
savedInstanceState: Bundle?,
): View {
_binding = FragmentVolumeBinding.inflate(inflater, container, false)
return binding.root
@ -68,15 +68,17 @@ class VolumeFragment : Fragment(), SeekBar.OnSeekBarChangeListener, OnAudioVolum
audioVolumeObserver?.register(AudioManager.STREAM_MUSIC, this)
val audioManager = audioManager
binding.volumeSeekBar.max = audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)
binding.volumeSeekBar.progress = audioManager.getStreamVolume(AudioManager.STREAM_MUSIC)
binding.volumeSeekBar.setOnSeekBarChangeListener(this)
binding.volumeSeekBar.valueTo =
audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC).toFloat()
binding.volumeSeekBar.value =
audioManager.getStreamVolume(AudioManager.STREAM_MUSIC).toFloat()
binding.volumeSeekBar.addOnChangeListener(this)
}
override fun onAudioVolumeChanged(currentVolume: Int, maxVolume: Int) {
if (_binding != null) {
binding.volumeSeekBar.max = maxVolume
binding.volumeSeekBar.progress = currentVolume
binding.volumeSeekBar.valueTo = maxVolume.toFloat()
binding.volumeSeekBar.value = currentVolume.toFloat()
binding.volumeDown.setImageResource(if (currentVolume == 0) R.drawable.ic_volume_off else R.drawable.ic_volume_down)
}
}
@ -87,17 +89,11 @@ class VolumeFragment : Fragment(), SeekBar.OnSeekBarChangeListener, OnAudioVolum
_binding = null
}
override fun onProgressChanged(seekBar: SeekBar, i: Int, b: Boolean) {
override fun onValueChange(slider: Slider, value: Float, fromUser: Boolean) {
val audioManager = audioManager
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, i, 0)
setPauseWhenZeroVolume(i < 1)
binding.volumeDown.setImageResource(if (i == 0) R.drawable.ic_volume_off else R.drawable.ic_volume_down)
}
override fun onStartTrackingTouch(seekBar: SeekBar) {
}
override fun onStopTrackingTouch(seekBar: SeekBar) {
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, value.toInt(), 0)
setPauseWhenZeroVolume(value < 1f)
binding.volumeDown.setImageResource(if (value == 0f) R.drawable.ic_volume_off else R.drawable.ic_volume_down)
}
override fun onClick(view: View) {

View file

@ -102,8 +102,6 @@ class CoverLyricsFragment : AbsMusicServiceFragment(R.layout.fragment_cover_lyri
null
}
}
}
override fun onUpdateProgressViews(progress: Int, total: Int) {

View file

@ -49,6 +49,7 @@ import code.name.monkey.retromusic.util.LyricUtil
import code.name.monkey.retromusic.util.LyricsType
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
@ -115,6 +116,22 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentPlayerAlbumCoverBinding.bind(view)
setupViewPager()
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this, 500, 1000)
maybeInitLyrics()
lrcView.apply {
setDraggable(true) { time ->
MusicPlayerRemote.seekTo(time.toInt())
MusicPlayerRemote.resumePlaying()
true
}
setOnClickListener {
goToLyrics(requireActivity())
}
}
}
private fun setupViewPager() {
binding.viewPager.addOnPageChangeListener(this)
val nps = PreferenceUtil.nowPlayingScreen
@ -140,18 +157,6 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
PreferenceUtil.albumCoverTransform
)
}
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this, 500, 1000)
maybeInitLyrics()
lrcView.apply {
setDraggable(true) { time ->
MusicPlayerRemote.seekTo(time.toInt())
MusicPlayerRemote.resumePlaying()
true
}
setOnClickListener {
goToLyrics(requireActivity())
}
}
}
override fun onResume() {
@ -171,29 +176,35 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
}
override fun onServiceConnected() {
logD("Service Connected")
updatePlayingQueue()
updateLyrics()
}
override fun onPlayingMetaChanged() {
binding.viewPager.currentItem = MusicPlayerRemote.position
logD("Playing Meta Changed")
viewPager.setCurrentItem(MusicPlayerRemote.position, true)
updateLyrics()
}
override fun onQueueChanged() {
logD("Queue Changed")
updatePlayingQueue()
}
override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String?) {
if (key == SHOW_LYRICS) {
if (sharedPreferences.getBoolean(key, false)) {
maybeInitLyrics()
} else {
showLyrics(false)
progressViewUpdateHelper?.stop()
when (key) {
SHOW_LYRICS -> {
if (PreferenceUtil.showLyrics) {
maybeInitLyrics()
} else {
showLyrics(false)
progressViewUpdateHelper?.stop()
}
}
LYRICS_TYPE -> {
maybeInitLyrics()
}
} else if (key == LYRICS_TYPE) {
maybeInitLyrics()
}
}
@ -244,7 +255,7 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
binding.viewPager.apply {
adapter = AlbumCoverPagerAdapter(childFragmentManager, MusicPlayerRemote.playingQueue)
adapter?.notifyDataSetChanged()
currentItem = MusicPlayerRemote.position
setCurrentItem(MusicPlayerRemote.position, true)
onPageSelected(MusicPlayerRemote.position)
}
}

View file

@ -17,9 +17,7 @@ package code.name.monkey.retromusic.fragments.player.adaptive
import android.os.Bundle
import android.view.View
import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.TextView
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.MaterialValueHelper
@ -31,6 +29,7 @@ import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.google.android.material.slider.Slider
class AdaptivePlaybackControlsFragment :
AbsPlayerControlsFragment(R.layout.fragment_adaptive_player_playback_controls) {
@ -38,7 +37,7 @@ class AdaptivePlaybackControlsFragment :
private var _binding: FragmentAdaptivePlayerPlaybackControlsBinding? = null
private val binding get() = _binding!!
override val progressSlider: SeekBar
override val progressSlider: Slider
get() = binding.progressSlider
override val shuffleButton: ImageButton
@ -124,7 +123,7 @@ class AdaptivePlaybackControlsFragment :
val colorFinal = if (PreferenceUtil.isAdaptiveColor) {
color.primaryTextColor
} else {
ThemeStore.accentColor(requireContext())
accentColor()
}.ripAlpha()
TintHelper.setTintAuto(

View file

@ -19,7 +19,6 @@ import android.os.Bundle
import android.view.View
import android.view.animation.DecelerateInterpolator
import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.TextView
import androidx.core.content.ContextCompat
import code.name.monkey.appthemehelper.util.ColorUtil
@ -37,13 +36,14 @@ import code.name.monkey.retromusic.fragments.base.goToArtist
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.google.android.material.slider.Slider
class BlurPlaybackControlsFragment :
AbsPlayerControlsFragment(R.layout.fragment_blur_player_playback_controls) {
private var _binding: FragmentBlurPlayerPlaybackControlsBinding? = null
private val binding get() = _binding!!
override val progressSlider: SeekBar
override val progressSlider: Slider
get() = binding.progressSlider
override val shuffleButton: ImageButton

View file

@ -20,17 +20,13 @@ import android.view.View
import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.TextView
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.MaterialValueHelper
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentCardPlayerPlaybackControlsBinding
import code.name.monkey.retromusic.extensions.getSongInfo
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.ripAlpha
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.fragments.base.goToAlbum
import code.name.monkey.retromusic.fragments.base.goToArtist
@ -45,7 +41,7 @@ class CardPlaybackControlsFragment :
private var _binding: FragmentCardPlayerPlaybackControlsBinding? = null
private val binding get() = _binding!!
override val progressSlider: SeekBar
override val seekBar: SeekBar
get() = binding.progressSlider
override val shuffleButton: ImageButton
@ -138,7 +134,7 @@ class CardPlaybackControlsFragment :
val colorFinal = if (PreferenceUtil.isAdaptiveColor) {
color.primaryTextColor
} else {
ThemeStore.accentColor(requireContext()).ripAlpha()
accentColor().ripAlpha()
}
binding.image.setColorFilter(colorFinal, PorterDuff.Mode.SRC_IN)
TintHelper.setTintAuto(

View file

@ -19,7 +19,6 @@ import android.os.Bundle
import android.view.View
import android.view.animation.DecelerateInterpolator
import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.TextView
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.TintHelper
@ -34,6 +33,7 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.google.android.material.slider.Slider
class CardBlurPlaybackControlsFragment :
AbsPlayerControlsFragment(R.layout.fragment_card_blur_player_playback_controls) {
@ -41,7 +41,7 @@ class CardBlurPlaybackControlsFragment :
private var _binding: FragmentCardBlurPlayerPlaybackControlsBinding? = null
private val binding get() = _binding!!
override val progressSlider: SeekBar
override val progressSlider: Slider
get() = binding.progressSlider
override val shuffleButton: ImageButton

View file

@ -25,10 +25,8 @@ import android.os.Bundle
import android.view.View
import android.view.animation.Animation
import android.view.animation.LinearInterpolator
import android.widget.SeekBar
import androidx.appcompat.widget.Toolbar
import androidx.core.content.getSystemService
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.TintHelper
@ -49,13 +47,12 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper.Callback
import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler
import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.ViewUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import code.name.monkey.retromusic.volume.AudioVolumeObserver
import code.name.monkey.retromusic.volume.OnAudioVolumeChangedListener
import com.google.android.material.slider.Slider
import me.tankery.lib.circularseekbar.CircularSeekBar
/**
@ -78,6 +75,9 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
private var rotateAnimator: ObjectAnimator? = null
private var lastRequest: GlideRequest<Drawable>? = null
private var progressAnimator: ObjectAnimator? = null
var isSeeking = false
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
@ -113,11 +113,6 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
private fun setupViews() {
setUpProgressSlider()
ViewUtil.setProgressDrawable(
binding.progressSlider,
ThemeStore.accentColor(requireContext()),
false
)
binding.volumeSeekBar.circleProgressColor = accentColor()
binding.volumeSeekBar.circleColor = ColorUtil.withAlpha(accentColor(), 0.25f)
setUpPlayPauseFab()
@ -135,11 +130,12 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
private fun setUpPrevNext() {
updatePrevNextColor()
binding.nextButton.setOnTouchListener(MusicSeekSkipTouchListener(requireActivity(), true))
binding.previousButton.setOnTouchListener(MusicSeekSkipTouchListener(requireActivity(), false))
binding.previousButton.setOnTouchListener(MusicSeekSkipTouchListener(requireActivity(),
false))
}
private fun updatePrevNextColor() {
val accentColor = ThemeStore.accentColor(requireContext())
val accentColor = accentColor()
binding.nextButton.setColorFilter(accentColor, PorterDuff.Mode.SRC_IN)
binding.previousButton.setColorFilter(accentColor, PorterDuff.Mode.SRC_IN)
}
@ -147,7 +143,7 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
private fun setUpPlayPauseFab() {
TintHelper.setTintAuto(
binding.playPauseButton,
ThemeStore.accentColor(requireContext()),
accentColor(),
false
)
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
@ -275,7 +271,11 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
}
override fun onProgressChanged(seekBar: CircularSeekBar?, progress: Float, fromUser: Boolean) {
override fun onProgressChanged(
circularSeekBar: CircularSeekBar?,
progress: Float,
fromUser: Boolean,
) {
val audioManager = audioManager
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, progress.toInt(), 0)
}
@ -286,28 +286,45 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
override fun onStopTrackingTouch(seekBar: CircularSeekBar?) {
}
fun setUpProgressSlider() {
private fun setUpProgressSlider() {
binding.progressSlider.applyColor(accentColor())
binding.progressSlider.setOnSeekBarChangeListener(object : SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
onUpdateProgressViews(
MusicPlayerRemote.songProgressMillis,
MusicPlayerRemote.songDurationMillis
)
}
val progressSlider = binding.progressSlider
progressSlider.addOnChangeListener(Slider.OnChangeListener { _, value, fromUser ->
if (fromUser) {
onUpdateProgressViews(
value.toInt(),
MusicPlayerRemote.songDurationMillis
)
}
})
progressSlider.addOnSliderTouchListener(object : Slider.OnSliderTouchListener {
override fun onStartTrackingTouch(slider: Slider) {
isSeeking = true
progressViewUpdateHelper.stop()
}
override fun onStopTrackingTouch(slider: Slider) {
isSeeking = false
MusicPlayerRemote.seekTo(slider.value.toInt())
progressViewUpdateHelper.start()
}
})
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
binding.progressSlider.max = total
val progressSlider = binding.progressSlider
progressSlider.valueTo = total.toFloat()
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
animator.duration = AbsPlayerControlsFragment.SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
if (isSeeking) {
progressSlider.value = progress.toFloat()
} else {
progressAnimator =
ObjectAnimator.ofFloat(progressSlider, "value", progress.toFloat()).apply {
duration = AbsPlayerControlsFragment.SLIDER_ANIMATION_TIME
interpolator = LinearInterpolator()
start()
}
}
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())

View file

@ -85,7 +85,7 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
mainActivity.getBottomSheetBehavior().isDraggable = false
mainActivity.getBottomSheetBehavior().isDraggable = false
binding.playerQueueSheet.setContentPadding(
binding.playerQueueSheet.contentPaddingLeft,
(slideOffset * binding.statusBar.height).toInt(),

View file

@ -22,7 +22,6 @@ import android.view.ViewAnimationUtils
import android.view.animation.AccelerateInterpolator
import android.view.animation.DecelerateInterpolator
import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.TextView
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.TintHelper
@ -38,6 +37,7 @@ import code.name.monkey.retromusic.fragments.base.goToArtist
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.google.android.material.slider.Slider
import kotlin.math.sqrt
class ColorPlaybackControlsFragment :
@ -46,7 +46,7 @@ class ColorPlaybackControlsFragment :
private var _binding: FragmentColorPlayerPlaybackControlsBinding? = null
private val binding get() = _binding!!
override val progressSlider: SeekBar
override val progressSlider: Slider
get() = binding.progressSlider
override val shuffleButton: ImageButton

View file

@ -20,7 +20,6 @@ import android.view.animation.DecelerateInterpolator
import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.TextView
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.TintHelper
@ -40,7 +39,7 @@ class FitPlaybackControlsFragment :
private var _binding: FragmentFitPlaybackControlsBinding? = null
private val binding get() = _binding!!
override val progressSlider: SeekBar
override val seekBar: SeekBar
get() = binding.progressSlider
override val shuffleButton: ImageButton
@ -128,7 +127,7 @@ class FitPlaybackControlsFragment :
val colorFinal = if (PreferenceUtil.isAdaptiveColor) {
color.primaryTextColor
} else {
ThemeStore.accentColor(requireContext()).ripAlpha()
accentColor().ripAlpha()
}
volumeFragment?.setTintable(colorFinal)

View file

@ -20,7 +20,6 @@ import android.view.animation.DecelerateInterpolator
import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.TextView
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.MaterialValueHelper
@ -43,7 +42,7 @@ class FlatPlaybackControlsFragment :
private var _binding: FragmentFlatPlayerPlaybackControlsBinding? = null
private val binding get() = _binding!!
override val progressSlider: SeekBar
override val seekBar: SeekBar
get() = binding.progressSlider
override val shuffleButton: ImageButton
@ -110,7 +109,7 @@ class FlatPlaybackControlsFragment :
val colorFinal = if (PreferenceUtil.isAdaptiveColor) {
color.primaryTextColor
} else {
ThemeStore.accentColor(requireContext()).ripAlpha()
accentColor().ripAlpha()
}
updateTextColors(colorFinal)

View file

@ -23,7 +23,6 @@ import android.view.MenuItem
import android.view.View
import android.view.animation.DecelerateInterpolator
import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.TextView
import androidx.appcompat.widget.PopupMenu
import androidx.lifecycle.lifecycleScope
@ -45,6 +44,7 @@ import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.google.android.material.slider.Slider
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -62,7 +62,7 @@ class FullPlaybackControlsFragment :
private var _binding: FragmentFullPlayerControlsBinding? = null
private val binding get() = _binding!!
override val progressSlider: SeekBar
override val progressSlider: Slider
get() = binding.progressSlider
override val shuffleButton: ImageButton
@ -177,10 +177,9 @@ class FullPlaybackControlsFragment :
private fun setUpPlayPauseFab() {
binding.playPauseButton.setOnClickListener(PlayPauseButtonOnClickHandler())
binding.playPauseButton.post {
binding.playPauseButton.pivotX = (binding.playPauseButton.width / 2).toFloat()
binding.playPauseButton.pivotY = (binding.playPauseButton.height / 2).toFloat()
}
binding.playPauseButton.pivotX = (binding.playPauseButton.width / 2).toFloat()
binding.playPauseButton.pivotY = (binding.playPauseButton.height / 2).toFloat()
}
private fun setUpMusicControllers() {

View file

@ -23,7 +23,6 @@ import android.graphics.drawable.AnimatedVectorDrawable
import android.os.Bundle
import android.view.View
import android.view.animation.LinearInterpolator
import android.widget.SeekBar
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.PopupMenu
import androidx.appcompat.widget.Toolbar
@ -50,13 +49,13 @@ import code.name.monkey.retromusic.fragments.other.VolumeFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler
import code.name.monkey.retromusic.misc.SimpleOnSeekbarChangeListener
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.*
import com.google.android.material.slider.Slider
import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator
import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager
import com.h6ah4i.android.widget.advrecyclerview.swipeable.RecyclerViewSwipeManager
@ -85,6 +84,9 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
private var _binding: FragmentGradientPlayerBinding? = null
private val binding get() = _binding!!
private var progressAnimator: ObjectAnimator? = null
var isSeeking = false
private val bottomSheetCallbackList = object : BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
mainActivity.getBottomSheetBehavior().isDraggable = false
@ -99,7 +101,8 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
override fun onStateChanged(bottomSheet: View, newState: Int) {
when (newState) {
STATE_EXPANDED,
STATE_DRAGGING -> {
STATE_DRAGGING,
-> {
mainActivity.getBottomSheetBehavior().isDraggable = false
}
STATE_COLLAPSED -> {
@ -161,7 +164,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
ViewCompat.setOnApplyWindowInsetsListener(
(binding.container)
) { v: View, insets: WindowInsetsCompat ->
navBarHeight = insets.safeGetBottomInsets()
navBarHeight = insets.getBottomInsets()
v.updatePadding(bottom = navBarHeight)
insets
}
@ -312,7 +315,6 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
super.onServiceConnected()
updateSong()
updatePlayPauseDrawableState()
updatePlayPauseDrawableState()
updateQueue()
updateIsFavoriteIcon()
}
@ -379,15 +381,17 @@ 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.previousButton.setOnTouchListener(MusicSeekSkipTouchListener(requireActivity(), false))
binding.playbackControlsFragment.nextButton.setOnTouchListener(MusicSeekSkipTouchListener(
requireActivity(),
true))
binding.playbackControlsFragment.previousButton.setOnTouchListener(
MusicSeekSkipTouchListener(requireActivity(), false))
}
private fun updatePrevNextColor() {
@ -469,7 +473,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
oldLeft: Int,
oldTop: Int,
oldRight: Int,
oldBottom: Int
oldBottom: Int,
) {
val panel = getQueuePanel()
if (panel.state == STATE_COLLAPSED) {
@ -542,30 +546,43 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
}
private fun setUpProgressSlider() {
binding.playbackControlsFragment.progressSlider.setOnSeekBarChangeListener(object :
SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {
if (fromUser) {
MusicPlayerRemote.seekTo(progress)
onUpdateProgressViews(
MusicPlayerRemote.songProgressMillis,
MusicPlayerRemote.songDurationMillis
)
}
val progressSlider = binding.playbackControlsFragment.progressSlider
progressSlider.addOnChangeListener(Slider.OnChangeListener { _, value, fromUser ->
if (fromUser) {
onUpdateProgressViews(
value.toInt(),
MusicPlayerRemote.songDurationMillis
)
}
})
progressSlider.addOnSliderTouchListener(object : Slider.OnSliderTouchListener {
override fun onStartTrackingTouch(slider: Slider) {
isSeeking = true
progressViewUpdateHelper.stop()
}
override fun onStopTrackingTouch(slider: Slider) {
isSeeking = false
MusicPlayerRemote.seekTo(slider.value.toInt())
progressViewUpdateHelper.start()
}
})
}
override fun onUpdateProgressViews(progress: Int, total: Int) {
binding.playbackControlsFragment.progressSlider.max = total
val animator = ObjectAnimator.ofInt(
binding.playbackControlsFragment.progressSlider,
"progress",
progress
)
animator.duration = AbsPlayerControlsFragment.SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
val progressSlider = binding.playbackControlsFragment.progressSlider
progressSlider.valueTo = total.toFloat()
if (isSeeking) {
progressSlider.value = progress.toFloat()
} else {
progressAnimator =
ObjectAnimator.ofFloat(progressSlider, "value", progress.toFloat()).apply {
duration = AbsPlayerControlsFragment.SLIDER_ANIMATION_TIME
interpolator = LinearInterpolator()
start()
}
}
binding.playbackControlsFragment.songTotalTime.text =
MusicUtil.getReadableDurationString(total.toLong())
binding.playbackControlsFragment.songCurrentProgress.text =

View file

@ -18,7 +18,6 @@ import android.os.Bundle
import android.view.View
import android.view.animation.DecelerateInterpolator
import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.TextView
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ColorUtil
@ -34,6 +33,7 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.google.android.material.slider.Slider
/**
* @author Hemanth S (h4h13).
@ -44,7 +44,7 @@ class LockScreenControlsFragment :
private var _binding: FragmentLockScreenPlaybackControlsBinding? = null
private val binding get() = _binding!!
override val progressSlider: SeekBar
override val progressSlider: Slider
get() = binding.progressSlider
override val shuffleButton: ImageButton

View file

@ -18,7 +18,6 @@ import android.graphics.PorterDuff
import android.os.Bundle
import android.view.View
import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.TextView
import androidx.core.content.ContextCompat
import code.name.monkey.appthemehelper.util.ATHUtil
@ -33,6 +32,7 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.google.android.material.slider.Slider
/**
* @author Hemanth S (h4h13).
@ -44,7 +44,7 @@ class MaterialControlsFragment :
private var _binding: FragmentMaterialPlaybackControlsBinding? = null
private val binding get() = _binding!!
override val progressSlider: SeekBar
override val progressSlider: Slider
get() = binding.progressSlider
override val shuffleButton: ImageButton

View file

@ -14,12 +14,9 @@
*/
package code.name.monkey.retromusic.fragments.player.md3
import android.animation.ObjectAnimator
import android.os.Bundle
import android.view.View
import android.view.animation.LinearInterpolator
import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.TextView
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ColorUtil
@ -32,20 +29,18 @@ import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.fragments.base.goToAlbum
import code.name.monkey.retromusic.fragments.base.goToArtist
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.google.android.material.slider.Slider
class MD3PlaybackControlsFragment :
AbsPlayerControlsFragment(R.layout.fragment_md3_player_playback_controls) {
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
private var _binding: FragmentMd3PlayerPlaybackControlsBinding? = null
private val binding get() = _binding!!
override val progressSlider: SeekBar
override val progressSlider: Slider
get() = binding.progressSlider
override val shuffleButton: ImageButton
@ -66,11 +61,6 @@ class MD3PlaybackControlsFragment :
override val songCurrentProgress: TextView
get() = binding.songCurrentProgress
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentMd3PlayerPlaybackControlsBinding.bind(view)
@ -139,16 +129,6 @@ class MD3PlaybackControlsFragment :
}
}
override fun onResume() {
super.onResume()
progressViewUpdateHelper.start()
}
override fun onPause() {
super.onPause()
progressViewUpdateHelper.stop()
}
override fun onServiceConnected() {
updatePlayPauseDrawableState()
updateRepeatState()
@ -157,7 +137,6 @@ class MD3PlaybackControlsFragment :
}
override fun onPlayingMetaChanged() {
super.onPlayingMetaChanged()
updateSong()
}
@ -196,18 +175,6 @@ class MD3PlaybackControlsFragment :
public override fun hide() {}
override fun onUpdateProgressViews(progress: Int, total: Int) {
binding.progressSlider.max = total
val animator = ObjectAnimator.ofInt(binding.progressSlider, "progress", progress)
animator.duration = SLIDER_ANIMATION_TIME
animator.interpolator = LinearInterpolator()
animator.start()
binding.songTotalTime.text = MusicUtil.getReadableDurationString(total.toLong())
binding.songCurrentProgress.text = MusicUtil.getReadableDurationString(progress.toLong())
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null

View file

@ -164,6 +164,7 @@ class PlayerFragment : AbsPlayerFragment(R.layout.fragment_player),
}
private fun startOrStopSnow(isSnowFalling: Boolean) {
if (_binding == null) return
if (isSnowFalling && !surfaceColor().isColorLight) {
binding.snowfallView.isVisible = true
binding.snowfallView.restartFalling()

View file

@ -18,9 +18,7 @@ import android.os.Bundle
import android.view.View
import android.view.animation.DecelerateInterpolator
import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.TextView
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.MaterialValueHelper
@ -34,6 +32,7 @@ import code.name.monkey.retromusic.fragments.base.goToArtist
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.google.android.material.slider.Slider
class PlayerPlaybackControlsFragment :
AbsPlayerControlsFragment(R.layout.fragment_player_playback_controls) {
@ -41,7 +40,7 @@ class PlayerPlaybackControlsFragment :
private var _binding: FragmentPlayerPlaybackControlsBinding? = null
private val binding get() = _binding!!
override val progressSlider: SeekBar
override val progressSlider: Slider
get() = binding.progressSlider
override val shuffleButton: ImageButton
@ -94,7 +93,7 @@ class PlayerPlaybackControlsFragment :
val colorFinal = if (PreferenceUtil.isAdaptiveColor) {
color.primaryTextColor
} else {
ThemeStore.accentColor(requireContext())
accentColor()
}.ripAlpha()
TintHelper.setTintAuto(

View file

@ -19,20 +19,20 @@ import android.graphics.PorterDuff
import android.os.Bundle
import android.view.View
import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.TextView
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentPeekControlPlayerBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.applyColor
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.google.android.material.slider.Slider
/**
* Created by hemanths on 2019-10-04.
@ -43,7 +43,7 @@ class PeekPlayerControlFragment : AbsPlayerControlsFragment(R.layout.fragment_pe
private var _binding: FragmentPeekControlPlayerBinding? = null
private val binding get() = _binding!!
override val progressSlider: SeekBar
override val progressSlider: Slider
get() = binding.progressSlider
override val shuffleButton: ImageButton
@ -82,7 +82,7 @@ class PeekPlayerControlFragment : AbsPlayerControlsFragment(R.layout.fragment_pe
if (PreferenceUtil.isAdaptiveColor) {
color.primaryTextColor
} else {
ThemeStore.accentColor(requireContext())
accentColor()
}
binding.progressSlider.applyColor(controlsColor)
volumeFragment?.setTintableColor(controlsColor)

View file

@ -18,23 +18,19 @@ import android.os.Bundle
import android.view.View
import android.view.animation.DecelerateInterpolator
import android.widget.ImageButton
import android.widget.SeekBar
import android.widget.TextView
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.MaterialValueHelper
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentPlainControlsFragmentBinding
import code.name.monkey.retromusic.extensions.applyColor
import code.name.monkey.retromusic.extensions.getSongInfo
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.google.android.material.slider.Slider
/**
* @author Hemanth S (h4h13).
@ -46,7 +42,7 @@ class PlainPlaybackControlsFragment :
private var _binding: FragmentPlainControlsFragmentBinding? = null
private val binding get() = _binding!!
override val progressSlider: SeekBar
override val progressSlider: Slider
get() = binding.progressSlider
override val shuffleButton: ImageButton
@ -134,7 +130,7 @@ class PlainPlaybackControlsFragment :
val colorFinal = if (PreferenceUtil.isAdaptiveColor) {
color.primaryTextColor
} else {
ThemeStore.accentColor(requireContext())
accentColor()
}
volumeFragment?.setTintable(colorFinal)
binding.progressSlider.applyColor(colorFinal)

View file

@ -18,13 +18,13 @@ import android.os.Bundle
import android.view.View
import android.view.animation.DecelerateInterpolator
import android.widget.ImageButton
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.MaterialValueHelper
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentSimpleControlsFragmentBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.getSongInfo
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show
@ -154,7 +154,7 @@ class SimplePlaybackControlsFragment :
val colorFinal = if (PreferenceUtil.isAdaptiveColor) {
color.primaryTextColor
} else {
ThemeStore.accentColor(requireContext())
accentColor()
}
volumeFragment?.setTintable(colorFinal)

View file

@ -177,7 +177,6 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
override fun openCab(menuRes: Int, callback: ICabCallback): AttachedCab {
cab?.let {
println("Cab")
if (it.isActive()) {
it.destroy()
}

View file

@ -50,6 +50,9 @@ class PlayingQueueFragment : AbsMusicServiceFragment(R.layout.fragment_playing_q
private var playingQueueAdapter: PlayingQueueAdapter? = null
private lateinit var linearLayoutManager: LinearLayoutManager
val mainActivity: MainActivity
get() = activity as MainActivity
private fun getUpNextAndQueueTime(): String {
val duration = MusicPlayerRemote.getQueueDurationMillis(MusicPlayerRemote.position)
return MusicUtil.buildInfoString(
@ -69,6 +72,7 @@ class PlayingQueueFragment : AbsMusicServiceFragment(R.layout.fragment_playing_q
MusicPlayerRemote.clearQueue()
}
checkForPadding()
mainActivity.collapsePanel()
}
private fun setUpRecyclerView() {
@ -175,7 +179,7 @@ class PlayingQueueFragment : AbsMusicServiceFragment(R.layout.fragment_playing_q
playingQueueAdapter = null
super.onDestroy()
if (MusicPlayerRemote.playingQueue.isNotEmpty())
(requireActivity() as MainActivity).expandPanel()
mainActivity.expandPanel()
}
private fun setupToolbar() {

View file

@ -29,17 +29,12 @@ import androidx.core.widget.doAfterTextChanged
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import androidx.transition.TransitionManager
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.SearchAdapter
import code.name.monkey.retromusic.databinding.FragmentSearchBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.dipToPix
import code.name.monkey.retromusic.extensions.focusAndShowKeyboard
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.views.addAlpha
import com.google.android.material.chip.Chip
import com.google.android.material.chip.ChipGroup
import com.google.android.material.shape.MaterialShapeDrawable
@ -133,7 +128,7 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search),
val colors = intArrayOf(
android.R.color.transparent,
ThemeStore.accentColor(requireContext()).addAlpha(0.5F)
accentColor().addAlpha(0.5F)
)
chips.forEach {

View file

@ -25,7 +25,6 @@ import androidx.preference.PreferenceManager
import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceFragmentCompat
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.OnThemeChangedListener
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.preferences.*
import code.name.monkey.retromusic.util.NavigationUtil

View file

@ -25,6 +25,7 @@ import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.BLUETOOTH_PLAYBACK
import code.name.monkey.retromusic.EQUALIZER
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity.Companion.BLUETOOTH_PERMISSION_REQUEST
import code.name.monkey.retromusic.util.NavigationUtil
/**
@ -52,7 +53,7 @@ class AudioSettings : AbsSettingsFragment() {
BLUETOOTH_CONNECT) != PERMISSION_GRANTED
) {
ActivityCompat.requestPermissions(requireActivity(), arrayOf(
BLUETOOTH_CONNECT), 100)
BLUETOOTH_CONNECT), BLUETOOTH_PERMISSION_REQUEST)
}
}
return@setOnPreferenceChangeListener true

View file

@ -38,7 +38,6 @@ class OtherSettingsFragment : AbsSettingsFragment() {
override fun invalidateSettings() {
val languagePreference: ATEListPreference? = findPreference(LANGUAGE_NAME)
languagePreference?.setOnPreferenceChangeListener { _, _ ->
println("Invalidated")
restartActivity()
return@setOnPreferenceChangeListener true
}

View file

@ -16,24 +16,20 @@ package code.name.monkey.retromusic.fragments.settings
import android.os.Bundle
import android.view.View
import androidx.preference.TwoStatePreference
import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEListPreference
import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.HOME_ALBUM_GRID_STYLE
import code.name.monkey.retromusic.HOME_ARTIST_GRID_STYLE
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.TAB_TEXT_MODE
class PersonalizeSettingsFragment : AbsSettingsFragment() {
override fun invalidateSettings() {
val toggleFullScreen: TwoStatePreference? = findPreference(TOGGLE_FULL_SCREEN)
toggleFullScreen?.setOnPreferenceChangeListener { _, _ ->
restartActivity()
true
}
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
addPreferencesFromResource(R.xml.pref_ui)
}
override fun invalidateSettings() {}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val homeArtistStyle: ATEListPreference? = findPreference(HOME_ARTIST_GRID_STYLE)

View file

@ -12,42 +12,47 @@
* See the GNU General Public License for more details.
*
*/
package code.name.monkey.retromusic.activities
package code.name.monkey.retromusic.fragments.settings
import android.Manifest.permission.BLUETOOTH_CONNECT
import android.content.Intent
import android.os.Bundle
import android.view.MenuItem
import android.view.View
import androidx.core.view.updatePadding
import androidx.navigation.NavController
import androidx.navigation.NavDestination
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager
import code.name.monkey.retromusic.databinding.ActivitySettingsBinding
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.databinding.FragmentSettingsBinding
import code.name.monkey.retromusic.extensions.applyToolbar
import code.name.monkey.retromusic.extensions.dip
import code.name.monkey.retromusic.extensions.extra
import code.name.monkey.retromusic.extensions.findNavController
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.color.ColorCallback
class SettingsActivity : AbsBaseActivity(), ColorCallback, OnThemeChangedListener {
private lateinit var binding: ActivitySettingsBinding
class SettingsFragment : AbsMusicServiceFragment(R.layout.fragment_settings), ColorCallback {
private var _binding: FragmentSettingsBinding? = null
private val binding get() = _binding!!
override fun onCreate(savedInstanceState: Bundle?) {
val mSavedInstanceState = extra<Bundle>(TAG).value ?: savedInstanceState
super.onCreate(mSavedInstanceState)
binding = ActivitySettingsBinding.inflate(layoutInflater)
setContentView(binding.root)
setupToolbar()
setPermissionDeniedMessage(getString(R.string.permission_bluetooth_denied))
}
override fun onResume() {
super.onResume()
setNavigationBarColorPreOreo(surfaceColor())
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
_binding = FragmentSettingsBinding.bind(view)
setupToolbar()
updateBottomPadding()
}
private fun setupToolbar() {
applyToolbar(binding.toolbar)
binding.toolbar.setNavigationOnClickListener {
requireActivity().onBackPressed()
}
val navController: NavController = findNavController(R.id.contentFrame)
navController.addOnDestinationChangedListener { _, _, _ ->
binding.collapsingToolbarLayout.title =
@ -72,48 +77,32 @@ class SettingsActivity : AbsBaseActivity(), ColorCallback, OnThemeChangedListene
return getString(idRes)
}
override fun onSupportNavigateUp(): Boolean {
return findNavController(R.id.contentFrame).navigateUp() || super.onSupportNavigateUp()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
onBackPressed()
}
return super.onOptionsItemSelected(item)
}
override fun getPermissionsToRequest(): Array<String> {
return if (VersionUtils.hasS()) {
arrayOf(BLUETOOTH_CONNECT)
} else {
arrayOf()
}
}
override fun invoke(dialog: MaterialDialog, color: Int) {
ThemeStore.editTheme(this).accentColor(color).commit()
ThemeStore.editTheme(requireContext()).accentColor(color).commit()
if (VersionUtils.hasNougatMR())
DynamicShortcutManager(this).updateDynamicShortcuts()
restart()
DynamicShortcutManager(requireContext()).updateDynamicShortcuts()
restartActivity()
}
override fun onThemeValuesChanged() {
restart()
}
private fun restart() {
val savedInstanceState = Bundle().apply {
onSaveInstanceState(this)
fun restartActivity() {
if (activity is OnThemeChangedListener && !VersionUtils.hasS()) {
(activity as OnThemeChangedListener).onThemeValuesChanged()
} else {
activity?.recreate()
}
finish()
val intent = Intent(this, this::class.java).putExtra(TAG, savedInstanceState)
startActivity(intent)
overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out)
}
override fun onQueueChanged() {
updateBottomPadding()
}
private fun updateBottomPadding() {
binding.root.updatePadding(
bottom = if (MusicPlayerRemote.playingQueue.isEmpty()) 0 else dip(R.dimen.mini_player_height))
}
companion object {
val TAG: String = SettingsActivity::class.java.simpleName
val TAG: String = SettingsFragment::class.java.simpleName
}
}

View file

@ -29,6 +29,7 @@ import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager
import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
import code.name.monkey.retromusic.util.PreferenceUtil
import com.afollestad.materialdialogs.color.colorChooser
import com.google.android.material.color.DynamicColors
@ -130,6 +131,10 @@ class ThemeSettingsFragment : AbsSettingsFragment() {
restartActivity()
true
}
val adaptiveColor: ATESwitchPreference? = findPreference(ADAPTIVE_COLOR_APP)
adaptiveColor?.isEnabled =
PreferenceUtil.nowPlayingScreen in listOf(Normal, Material, Flat)
}
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {

View file

@ -363,7 +363,6 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLay
override fun openCab(menuRes: Int, callback: ICabCallback): AttachedCab {
cab?.let {
println("Cab")
if (it.isActive()) {
it.destroy()
}

View file

@ -15,26 +15,18 @@ import java.security.MessageDigest
@Suppress("Deprecation")
class BlurTransformation : BitmapTransformation {
class BlurTransformation private constructor(builder: Builder) : BitmapTransformation() {
private var context: Context? = null
private var blurRadius = 0f
private var sampling = 0
private fun init(builder: Builder) {
init {
this.context = builder.context
this.blurRadius = builder.blurRadius
this.sampling = builder.sampling
}
private constructor(builder: Builder) : super() {
init(builder)
}
private constructor(builder: Builder, bitmapPool: BitmapPool) : super() {
init(builder)
}
class Builder(val context: Context) {
private var bitmapPool: BitmapPool? = null
var blurRadius = DEFAULT_BLUR_RADIUS
@ -69,7 +61,7 @@ class BlurTransformation : BitmapTransformation {
fun build(): BlurTransformation {
return if (bitmapPool != null) {
BlurTransformation(this, bitmapPool!!)
BlurTransformation(this)
} else BlurTransformation(this)
}
}
@ -78,7 +70,7 @@ class BlurTransformation : BitmapTransformation {
pool: BitmapPool,
toTransform: Bitmap,
outWidth: Int,
outHeight: Int
outHeight: Int,
): Bitmap {
val sampling = if (this.sampling == 0) {
ImageUtil.calculateInSampleSize(toTransform.width, toTransform.height, 100)

View file

@ -55,25 +55,20 @@ class Factory(
val context: Context
) : ModelLoaderFactory<ArtistImage, InputStream> {
private var deezerService: DeezerService
private var okHttp: OkHttpClient
private var deezerService = DeezerService.invoke(
DeezerService.createDefaultOkHttpClient(context)
.connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.addInterceptor(createLogInterceptor())
.build()
)
init {
okHttp =
OkHttpClient.Builder()
.connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.build()
deezerService = DeezerService.invoke(
DeezerService.createDefaultOkHttpClient(context)
.connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.addInterceptor(createLogInterceptor())
.build()
)
}
private var okHttp = OkHttpClient.Builder()
.connectTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.readTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.writeTimeout(TIMEOUT, TimeUnit.MILLISECONDS)
.build()
private fun createLogInterceptor(): Interceptor {
val interceptor = HttpLoggingInterceptor()

View file

@ -28,12 +28,14 @@ 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.MusicService
import code.name.monkey.retromusic.util.PreferenceUtil
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
import java.util.*
import kotlin.collections.set
object MusicPlayerRemote : KoinComponent {
@ -43,14 +45,6 @@ object MusicPlayerRemote : KoinComponent {
private val songRepository by inject<SongRepository>()
var isCasting: Boolean = false
set(value) {
field = value
if (value) {
musicService?.quit()
}
}
@JvmStatic
val isPlaying: Boolean
get() = musicService != null && musicService!!.isPlaying
@ -71,9 +65,6 @@ object MusicPlayerRemote : KoinComponent {
musicService?.nextSong
} else Song.emptySong
/**
* Async
*/
var position: Int
get() = if (musicService != null) {
musicService!!.position
@ -121,11 +112,7 @@ object MusicPlayerRemote : KoinComponent {
fun bindToService(context: Context, callback: ServiceConnection): ServiceToken? {
var realActivity: Activity? = (context as Activity).parent
if (realActivity == null) {
realActivity = context
}
val realActivity = (context as Activity).parent ?: context
val contextWrapper = ContextWrapper(realActivity)
val intent = Intent(contextWrapper, MusicService::class.java)
try {
@ -232,14 +219,9 @@ object MusicPlayerRemote : KoinComponent {
) && musicService != null
) {
musicService?.openQueue(queue, startPosition, startPlaying)
if (PreferenceUtil.isShuffleModeOn)
setShuffleMode(MusicService.SHUFFLE_MODE_NONE)
}
}
/**
* Async
*/
@JvmStatic
fun openAndShuffleQueue(queue: List<Song>, startPlaying: Boolean) {
var startPosition = 0
@ -440,10 +422,10 @@ object MusicPlayerRemote : KoinComponent {
if (songs == null || songs.isEmpty()) {
var songFile: File? = null
if (uri.authority != null && uri.authority == "com.android.externalstorage.documents") {
songFile = File(
getExternalStorageDirectory(),
uri.path?.split(":".toRegex(), 2)?.get(1)
)
val path = uri.path?.split(":".toRegex(), 2)?.get(1)
if (path != null) {
songFile = File(getExternalStorageDirectory(), path)
}
}
if (songFile == null) {
val path = getFilePathFromUri(context, uri)
@ -460,9 +442,11 @@ object MusicPlayerRemote : KoinComponent {
if (songs != null && songs.isNotEmpty()) {
openQueue(songs, 0, true)
} else {
// TODO the file is not listed in the media store
context.showToast(R.string.unplayable_file)
println("The file is not listed in the media store")
try {
context.showToast(R.string.unplayable_file)
} catch (e: Exception) {
logE("The file is not listed in the media store")
}
}
}
}
@ -472,6 +456,14 @@ object MusicPlayerRemote : KoinComponent {
.dropLastWhile { it.isEmpty() }.toTypedArray()[1]
}
fun switchToRemotePlayback(castSession: CastSession) {
musicService?.switchToRemotePlayback(castSession)
}
fun switchToLocalPlayback() {
musicService?.switchToLocalPlayback()
}
class ServiceBinder internal constructor(private val mCallback: ServiceConnection?) :
ServiceConnection {

View file

@ -15,6 +15,7 @@
package code.name.monkey.retromusic.helper
import android.os.Handler
import android.os.Looper
import android.os.Message
import kotlin.math.max
@ -32,13 +33,17 @@ class MusicProgressViewUpdateHelper : Handler {
removeMessages(CMD_REFRESH_PROGRESS_VIEWS)
}
constructor(callback: Callback) {
constructor(callback: Callback) : super(Looper.getMainLooper()) {
this.callback = callback
this.intervalPlaying = UPDATE_INTERVAL_PLAYING
this.intervalPaused = UPDATE_INTERVAL_PAUSED
}
constructor(callback: Callback, intervalPlaying: Int, intervalPaused: Int) {
constructor(
callback: Callback,
intervalPlaying: Int,
intervalPaused: Int,
) : super(Looper.getMainLooper()) {
this.callback = callback
this.intervalPlaying = intervalPlaying
this.intervalPaused = intervalPaused

View file

@ -42,10 +42,11 @@ import kotlin.math.abs
* 歌词 Created by wcy on 2015/11/9.
*/
@SuppressLint("StaticFieldLeak")
@Suppress("deprecation")
class CoverLrcView @JvmOverloads constructor(
context: Context?,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0
defStyleAttr: Int = 0,
) : View(context, attrs, defStyleAttr) {
private val mLrcEntryList: MutableList<LrcEntry> = ArrayList()
private val mLrcPaint = TextPaint()
@ -108,7 +109,7 @@ class CoverLrcView @JvmOverloads constructor(
e1: MotionEvent,
e2: MotionEvent,
distanceX: Float,
distanceY: Float
distanceY: Float,
): Boolean {
if (mOffset == getOffset(0) && distanceY < 0F) {
return super.onScroll(e1, e2, distanceX, distanceY)
@ -128,7 +129,7 @@ class CoverLrcView @JvmOverloads constructor(
e1: MotionEvent,
e2: MotionEvent,
velocityX: Float,
velocityY: Float
velocityY: Float,
): Boolean {
if (hasLrc()) {
mScroller!!.fling(
@ -256,16 +257,6 @@ class CoverLrcView @JvmOverloads constructor(
postInvalidate()
}
/** 普通歌词文本字体大小 */
fun setNormalTextSize(size: Float) {
mNormalTextSize = size
}
/** 当前歌词文本字体大小 */
fun setCurrentTextSize(size: Float) {
mCurrentTextSize = size
}
/** 设置当前行歌词的字体颜色 */
fun setCurrentColor(currentColor: Int) {
mCurrentTextColor = currentColor
@ -403,28 +394,6 @@ class CoverLrcView @JvmOverloads constructor(
}
}
/**
* 加载在线歌词默认使用 utf-8 编码
*
* @param lrcUrl 歌词文件的网络地址
*/
@JvmOverloads
fun loadLrcByUrl(lrcUrl: String, charset: String? = "utf-8") {
val flag = "url://$lrcUrl"
this.flag = flag
object : AsyncTask<String?, Int?, String>() {
override fun doInBackground(vararg params: String?): String? {
return LrcUtils.getContentFromNetwork(params[0], params[1])
}
override fun onPostExecute(lrcText: String) {
if (flag == flag) {
loadLrc(lrcText)
}
}
}.execute(lrcUrl, charset)
}
/**
* 歌词是否有效
*
@ -629,7 +598,6 @@ class CoverLrcView @JvmOverloads constructor(
mOffset = animation.animatedValue as Float
invalidate()
}
LrcUtils.resetDurationScale()
start()
}
}
@ -711,10 +679,6 @@ class CoverLrcView @JvmOverloads constructor(
fun onPlayClick(time: Long): Boolean
}
fun interface OnFlingXListener {
fun onFlingX(velocityX: Float): Boolean
}
companion object {
private const val ADJUST_DURATION: Long = 100
private const val TIMELINE_KEEP_TIME = 4 * DateUtils.SECOND_IN_MILLIS

View file

@ -14,7 +14,6 @@
package code.name.monkey.retromusic.lyrics;
import android.animation.ValueAnimator;
import android.text.TextUtils;
import android.text.format.DateUtils;
@ -25,7 +24,6 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
@ -208,14 +206,4 @@ class LrcUtils {
String ss = String.format(Locale.getDefault(), "%02d", s);
return mm + ":" + ss;
}
static void resetDurationScale() {
try {
Field mField = ValueAnimator.class.getDeclaredField("sDurationScale");
mField.setAccessible(true);
mField.setFloat(null, 1);
} catch (Exception e) {
e.printStackTrace();
}
}
}

View file

@ -684,7 +684,6 @@ public class LrcView extends View {
mOffset = (float) animation.getAnimatedValue();
invalidate();
});
LrcUtils.resetDurationScale();
mAnimator.start();
}

View file

@ -1,19 +0,0 @@
/*
* 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.misc;
import androidx.core.content.FileProvider;
public class GenericFileProvider extends FileProvider {}

View file

@ -49,7 +49,7 @@ fun headerInterceptor(context: Context): Interceptor {
fun provideOkHttp(context: Context, cache: Cache): OkHttpClient {
return OkHttpClient.Builder()
.addNetworkInterceptor(logInterceptor())
//.addInterceptor(headerInterceptor(context))
.addInterceptor(headerInterceptor(context))
.connectTimeout(1, TimeUnit.SECONDS)
.readTimeout(1, TimeUnit.SECONDS)
.cache(cache)

View file

@ -61,7 +61,9 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
val chooserDialog =
childFragmentManager.findFragmentByTag("FOLDER_CHOOSER") as BlacklistFolderChooserDialog?
chooserDialog?.setCallback(this)
refreshBlacklistData()
val context = requireActivity()
refreshBlacklistData(context)
return materialDialog(R.string.blacklist)
.setPositiveButton(R.string.done) { _, _ ->
dismiss()
@ -69,7 +71,9 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
.setNeutralButton(R.string.clear_action) { _, _ ->
materialDialog(R.string.clear_blacklist)
.setMessage(R.string.do_you_want_to_clear_the_blacklist)
.setPositiveButton(R.string.clear_action, null)
.setPositiveButton(R.string.clear_action) { _, _ ->
BlacklistStore.getInstance(context).clear()
}
.setNegativeButton(android.R.string.cancel, null)
.create()
.colorButtons()
@ -89,9 +93,7 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
).parseAsHtml()
)
.setPositiveButton(R.string.remove_action) { _, _ ->
BlacklistStore.getInstance(requireContext())
.removePath(File(paths[which]))
refreshBlacklistData()
BlacklistStore.getInstance(context).removePath(File(paths[which]))
}
.setNegativeButton(android.R.string.cancel, null)
.create()
@ -102,23 +104,16 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
setOnShowListener {
getButton(AlertDialog.BUTTON_POSITIVE).accentTextColor()
getButton(AlertDialog.BUTTON_NEGATIVE).accentTextColor()
getButton(AlertDialog.BUTTON_NEUTRAL).apply {
accentTextColor()
setOnClickListener {
BlacklistStore.getInstance(
requireContext()
).clear()
dismiss()
}
}
getButton(AlertDialog.BUTTON_NEUTRAL).accentTextColor()
}
}
}
private lateinit var paths: ArrayList<String>
private fun refreshBlacklistData() {
this.paths = BlacklistStore.getInstance(requireContext()).paths
private fun refreshBlacklistData(context: Context?) {
if (context == null) return
this.paths = BlacklistStore.getInstance(context).paths
val dialog = dialog as MaterialAlertDialogBuilder?
dialog?.setItems(paths.toTypedArray(), null)
}

View file

@ -72,9 +72,11 @@ class RealAlbumRepository(private val songRepository: RealSongRepository) :
// We don't need sorted list of songs (with sortAlbumSongs())
// cuz we are just displaying Albums(Cover Arts) anyway and not songs
fun splitIntoAlbums(
songs: List<Song>
songs: List<Song>,
sorted: Boolean = true
): List<Album> {
val grouped = songs.groupBy { it.albumId }.map { Album(it.key, it.value) }
if (!sorted) return grouped
val collator = Collator.getInstance()
return when (PreferenceUtil.albumSortOrder) {
SortOrder.AlbumSortOrder.ALBUM_A_Z -> {

View file

@ -42,7 +42,7 @@ class RealLastAddedRepository(
}
override fun recentAlbums(): List<Album> {
return albumRepository.splitIntoAlbums(recentSongs())
return albumRepository.splitIntoAlbums(recentSongs(), sorted = false)
}
override fun recentArtists(): List<Artist> {

View file

@ -28,6 +28,8 @@ import code.name.monkey.retromusic.network.Result.*
import code.name.monkey.retromusic.network.model.LastFmAlbum
import code.name.monkey.retromusic.network.model.LastFmArtist
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.logD
import code.name.monkey.retromusic.util.logE
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
@ -103,7 +105,6 @@ interface Repository {
suspend fun clearSongHistory()
suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity>
suspend fun playCountSongs(): List<PlayCountEntity>
suspend fun blackListPaths(): List<BlackListStoreEntity>
suspend fun deleteSongs(songs: List<Song>)
suspend fun contributor(): List<Contributor>
suspend fun searchArtists(query: String): List<Artist>
@ -195,7 +196,7 @@ class RealRepository(
return try {
Success(lastFMService.artistInfo(name, lang, cache))
} catch (e: Exception) {
println(e)
logE(e)
Error(e)
}
}
@ -208,7 +209,7 @@ class RealRepository(
val lastFmAlbum = lastFMService.albumInfo(artist, album)
Success(lastFmAlbum)
} catch (e: Exception) {
println(e)
logE(e)
Error(e)
}
}
@ -228,7 +229,7 @@ class RealRepository(
)
for (section in sections) {
if (section.arrayList.isNotEmpty()) {
println("${section.homeSection} -> ${section.arrayList.size}")
logD("${section.homeSection} -> ${section.arrayList.size}")
homeSections.add(section)
}
}
@ -345,9 +346,6 @@ class RealRepository(
override suspend fun playCountSongs(): List<PlayCountEntity> =
roomRepository.playCountSongs()
override suspend fun blackListPaths(): List<BlackListStoreEntity> =
roomRepository.blackListPaths()
override fun observableHistorySongs(): LiveData<List<Song>> =
Transformations.map(roomRepository.observableHistorySongs()) {
it.fromHistoryToSongs()
@ -381,7 +379,6 @@ class RealRepository(
}
override suspend fun suggestions(): List<Song> {
if (!PreferenceUtil.homeSuggestions) return listOf()
return NotPlayedPlaylist().songs().shuffled().takeIf {
it.size > 9
} ?: emptyList()

View file

@ -16,7 +16,6 @@ import code.name.monkey.retromusic.util.PreferenceUtil
interface RoomRepository {
fun historySongs(): List<HistoryEntity>
fun favoritePlaylistLiveData(favorite: String): LiveData<List<SongEntity>>
fun insertBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
fun observableHistorySongs(): LiveData<List<HistoryEntity>>
fun getSongs(playListId: Long): LiveData<List<SongEntity>>
suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long
@ -42,11 +41,6 @@ interface RoomRepository {
suspend fun clearSongHistory()
suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity>
suspend fun playCountSongs(): List<PlayCountEntity>
suspend fun insertBlacklistPath(blackListStoreEntities: List<BlackListStoreEntity>)
suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity)
suspend fun clearBlacklist()
suspend fun insertBlacklistPathAsync(blackListStoreEntity: BlackListStoreEntity)
suspend fun blackListPaths(): List<BlackListStoreEntity>
suspend fun deleteSongs(songs: List<Song>)
suspend fun isSongFavorite(context: Context, songId: Long): Boolean
fun checkPlaylistExists(playListId: Long): LiveData<Boolean>
@ -54,10 +48,8 @@ interface RoomRepository {
class RealRoomRepository(
private val playlistDao: PlaylistDao,
private val blackListStoreDao: BlackListStoreDao,
private val playCountDao: PlayCountDao,
private val historyDao: HistoryDao,
private val lyricsDao: LyricsDao
private val historyDao: HistoryDao
) : RoomRepository {
@WorkerThread
override suspend fun createPlaylist(playlistEntity: PlaylistEntity): Long =
@ -123,7 +115,6 @@ class RealRoomRepository(
return if (playlist != null) {
playlist
} else {
println("Playlist Created")
createPlaylist(PlaylistEntity(playlistName = favorite))
playlistDao.playlist(favorite).first()
}
@ -185,27 +176,10 @@ class RealRoomRepository(
override suspend fun playCountSongs(): List<PlayCountEntity> =
playCountDao.playCountSongs()
override fun insertBlacklistPath(blackListStoreEntity: BlackListStoreEntity) =
blackListStoreDao.insertBlacklistPath(blackListStoreEntity)
override suspend fun insertBlacklistPath(blackListStoreEntities: List<BlackListStoreEntity>) =
blackListStoreDao.insertBlacklistPath(blackListStoreEntities)
override suspend fun insertBlacklistPathAsync(blackListStoreEntity: BlackListStoreEntity) =
blackListStoreDao.insertBlacklistPath(blackListStoreEntity)
override suspend fun blackListPaths(): List<BlackListStoreEntity> =
blackListStoreDao.blackListPaths()
override suspend fun deleteSongs(songs: List<Song>) = songs.forEach {
playCountDao.deleteSong(it.id)
}
override suspend fun deleteBlacklistPath(blackListStoreEntity: BlackListStoreEntity) =
blackListStoreDao.deleteBlacklistPath(blackListStoreEntity)
override suspend fun clearBlacklist() = blackListStoreDao.clearBlacklist()
override suspend fun isSongFavorite(context: Context, songId: Long): Boolean {
return playlistDao.isSongExistsInPlaylist(
playlistDao.playlist(context.getString(R.string.favorites)).firstOrNull()?.playListId

View file

@ -81,7 +81,7 @@ class RealTopPlayedRepository(
}
override fun topAlbums(): List<Album> {
return albumRepository.splitIntoAlbums(topTracks())
return albumRepository.splitIntoAlbums(topTracks(), sorted = false)
}
override fun topArtists(): List<Artist> {

View file

@ -12,9 +12,9 @@ class AudioFader {
@JvmStatic
inline fun createFadeAnimator(
fadeIn: Boolean /* fadeIn -> true fadeOut -> false*/,
fadeIn: Boolean, /* fadeIn -> true fadeOut -> false*/
mediaPlayer: MediaPlayer,
crossinline endAction: (animator: Animator) -> Unit /* Code to run when Animator Ends*/
crossinline endAction: (animator: Animator) -> Unit, /* Code to run when Animator Ends*/
): Animator? {
val duration = PreferenceUtil.crossFadeDuration * 1000
if (duration == 0) {
@ -40,8 +40,8 @@ class AudioFader {
@JvmStatic
fun startFadeAnimator(
playback: Playback,
fadeIn: Boolean /* fadeIn -> true fadeOut -> false*/,
callback: Runnable /* Code to run when Animator Ends*/
fadeIn: Boolean, /* fadeIn -> true fadeOut -> false*/
callback: Runnable, /* Code to run when Animator Ends*/
) {
val duration = PreferenceUtil.audioFadeDuration.toLong()
if (duration == 0L) {

View file

@ -0,0 +1,115 @@
package code.name.monkey.retromusic.service
import code.name.monkey.retromusic.cast.CastHelper.toMediaInfo
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.service.playback.Playback
import code.name.monkey.retromusic.util.PreferenceUtil.playbackSpeed
import com.google.android.gms.cast.MediaLoadOptions
import com.google.android.gms.cast.MediaSeekOptions
import com.google.android.gms.cast.MediaStatus
import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.cast.framework.media.RemoteMediaClient
class CastPlayer(castSession: CastSession) : Playback,
RemoteMediaClient.Callback() {
override val isInitialized: Boolean = true
private val remoteMediaClient: RemoteMediaClient? = castSession.remoteMediaClient
init {
remoteMediaClient?.registerCallback(this)
remoteMediaClient?.setPlaybackRate(playbackSpeed.toDouble().coerceIn(0.5, 2.0))
}
private var isActuallyPlaying = false
override val isPlaying: Boolean
get() {
return remoteMediaClient?.isPlaying == true || isActuallyPlaying
}
override val audioSessionId: Int = 0
private var callbacks: Playback.PlaybackCallbacks? = null
override fun setDataSource(
song: Song,
force: Boolean,
completion: (success: Boolean) -> Unit,
) {
try {
val mediaLoadOptions =
MediaLoadOptions.Builder().setPlayPosition(0).setAutoplay(true).build()
remoteMediaClient?.load(song.toMediaInfo()!!, mediaLoadOptions)
completion(true)
} catch (e: Exception) {
e.printStackTrace()
completion(false)
}
}
override fun setNextDataSource(path: String?) {}
override fun setCallbacks(callbacks: Playback.PlaybackCallbacks) {
this.callbacks = callbacks
}
override fun start(): Boolean {
isActuallyPlaying = true
remoteMediaClient?.play()
return true
}
override fun stop() {
isActuallyPlaying = false
remoteMediaClient?.stop()
}
override fun release() {
stop()
}
override fun pause(): Boolean {
isActuallyPlaying = false
remoteMediaClient?.pause()
return true
}
override fun duration(): Int {
return remoteMediaClient?.streamDuration?.toInt() ?: 0
}
override fun position(): Int {
return remoteMediaClient?.approximateStreamPosition?.toInt() ?: 0
}
override fun seek(whereto: Int): Int {
remoteMediaClient?.seek(MediaSeekOptions.Builder().setPosition(whereto.toLong()).build())
return 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) {
remoteMediaClient?.setPlaybackRate(speed.toDouble().coerceIn(0.5, 2.0))
}
override fun onStatusUpdated() {
when (remoteMediaClient?.playerState) {
MediaStatus.PLAYER_STATE_IDLE -> {
val idleReason = remoteMediaClient.idleReason
if (idleReason == MediaStatus.IDLE_REASON_FINISHED) {
callbacks?.onTrackEnded()
}
}
MediaStatus.PLAYER_STATE_PLAYING, MediaStatus.PLAYER_STATE_PAUSED -> {
callbacks?.onPlayStateChanged()
}
}
}
}

View file

@ -2,26 +2,23 @@ package code.name.monkey.retromusic.service
import android.animation.Animator
import android.content.Context
import android.content.Intent
import android.media.AudioAttributes
import android.media.AudioManager
import android.media.MediaPlayer
import android.media.PlaybackParams
import android.media.audiofx.AudioEffect
import android.os.PowerManager
import android.util.Log
import androidx.core.net.toUri
import code.name.monkey.appthemehelper.util.VersionUtils.hasMarshmallow
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.extensions.uri
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.service.AudioFader.Companion.createFadeAnimator
import code.name.monkey.retromusic.service.playback.Playback
import code.name.monkey.retromusic.service.playback.Playback.PlaybackCallbacks
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.PreferenceUtil.playbackPitch
import code.name.monkey.retromusic.util.PreferenceUtil.playbackSpeed
import kotlinx.coroutines.*
/** @author Prathamesh M */
@ -124,18 +121,27 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion
override val isPlaying: Boolean
get() = mIsInitialized && getCurrentPlayer()?.isPlaying == true
override fun setDataSource(path: String, force: Boolean): Boolean {
override fun setDataSource(
song: Song,
force: Boolean,
completion: (success: Boolean) -> Unit,
) {
cancelFade()
if (force) hasDataSource = false
mIsInitialized = false
/* We've already set DataSource if initialized is true in setNextDataSource */
if (!hasDataSource) {
getCurrentPlayer()?.let { mIsInitialized = setDataSourceImpl(it, path) }
getCurrentPlayer()?.let {
setDataSourceImpl(it, song.uri.toString()) { success ->
mIsInitialized = success
completion(success)
}
}
hasDataSource = true
} else {
completion(true)
mIsInitialized = true
}
return mIsInitialized
}
override fun setNextDataSource(path: String?) {}
@ -148,9 +154,9 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion
private fun setDataSourceImpl(
player: MediaPlayer,
path: String,
): Boolean {
completion: (success: Boolean) -> Unit,
) {
player.reset()
player.setOnPreparedListener(null)
try {
if (path.startsWith("content://")) {
player.setDataSource(context, path.toUri())
@ -160,20 +166,17 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion
player.setAudioAttributes(
AudioAttributes.Builder().setLegacyStreamType(AudioManager.STREAM_MUSIC).build()
)
player.prepare()
player.setPlaybackSpeedPitch(playbackSpeed, playbackPitch)
player.setOnPreparedListener {
player.setOnPreparedListener(null)
completion(true)
}
player.prepareAsync()
} catch (e: Exception) {
completion(false)
e.printStackTrace()
return false
}
player.setOnCompletionListener(this)
player.setOnErrorListener(this)
val intent = Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION)
intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, audioSessionId)
intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.packageName)
intent.putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC)
context.sendBroadcast(intent)
return true
}
override fun setAudioSessionId(sessionId: Int): Boolean {
@ -315,15 +318,15 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion
}
}
fun onDurationUpdated(progress: Int, total: Int) {
if (total > 0 && (total - progress).div(1000) == crossFadeDuration) {
getNextPlayer()?.let { player ->
val nextSong = MusicPlayerRemote.nextSong
if (nextSong != null) {
setDataSourceImpl(player, MusicUtil.getSongFileUri(nextSong.id).toString())
// Switch to other player / Crossfade only if next song exists
switchPlayer()
setDataSourceImpl(player, nextSong.uri.toString()) { success ->
// Switch to other player (Crossfade) only if next song exists
if (success) switchPlayer()
}
}
}
}
@ -348,15 +351,8 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion
override fun setPlaybackSpeedPitch(speed: Float, pitch: Float) {
getCurrentPlayer()?.setPlaybackSpeedPitch(speed, pitch)
}
private fun MediaPlayer.setPlaybackSpeedPitch(speed: Float, pitch: Float) {
if (hasMarshmallow()) {
val wasPlaying: Boolean = isPlaying
playbackParams = PlaybackParams().setSpeed(speed).setPitch(pitch)
if (!wasPlaying) {
if (isPlaying) pause()
}
if (getNextPlayer()?.isPlaying == true) {
getNextPlayer()?.setPlaybackSpeedPitch(speed, pitch)
}
}
@ -365,4 +361,10 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion
}
}
internal fun crossFadeScope(): CoroutineScope = CoroutineScope(Job() + Dispatchers.Main)
internal fun crossFadeScope(): CoroutineScope = CoroutineScope(Job() + Dispatchers.Main)
fun MediaPlayer.setPlaybackSpeedPitch(speed: Float, pitch: Float) {
if (hasMarshmallow()) {
playbackParams = PlaybackParams().setSpeed(speed).setPitch(pitch)
}
}

Some files were not shown because too many files have changed in this diff Show more