Merge pull request #1178 from prathameshmm02/dev

Bug Fixes & Improvements
main
Daksh P. Jain 2021-12-05 15:11:41 +05:30 committed by GitHub
commit 350cba2042
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
64 changed files with 1275 additions and 749 deletions

View File

@ -15,8 +15,8 @@ android {
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
applicationId "code.name.monkey.retromusic" applicationId "code.name.monkey.retromusic"
versionCode 10544 versionCode 10545
versionName '5.4.1 ' + "_" + getDate() versionName '5.4.2 ' + "_" + getDate()
buildConfigField("String", "GOOGLE_PLAY_LICENSING_KEY", "\"${getProperty(getProperties('../public.properties'), 'GOOGLE_PLAY_LICENSE_KEY')}\"") buildConfigField("String", "GOOGLE_PLAY_LICENSING_KEY", "\"${getProperty(getProperties('../public.properties'), 'GOOGLE_PLAY_LICENSE_KEY')}\"")
} }
@ -94,8 +94,8 @@ dependencies {
implementation 'androidx.appcompat:appcompat:1.4.0' implementation 'androidx.appcompat:appcompat:1.4.0'
implementation 'androidx.annotation:annotation:1.3.0' implementation 'androidx.annotation:annotation:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.2' implementation 'androidx.constraintlayout:constraintlayout:2.1.2'
implementation 'androidx.recyclerview:recyclerview:1.2.1' implementation 'androidx.recyclerview:recyclerview:1.3.0-alpha01'
implementation 'androidx.preference:preference-ktx:1.1.1' implementation 'androidx.preference:preference-ktx:1.2.0-beta01'
implementation 'androidx.core:core-ktx:1.7.0' implementation 'androidx.core:core-ktx:1.7.0'
implementation 'androidx.palette:palette-ktx:1.0.0' implementation 'androidx.palette:palette-ktx:1.0.0'
@ -110,7 +110,7 @@ dependencies {
implementation "androidx.navigation:navigation-fragment-ktx:$nav_version" implementation "androidx.navigation:navigation-fragment-ktx:$nav_version"
implementation "androidx.navigation:navigation-ui-ktx:$nav_version" implementation "androidx.navigation:navigation-ui-ktx:$nav_version"
def room_version = '2.4.0-beta02' def room_version = '2.4.0-rc01'
implementation "androidx.room:room-runtime:$room_version" implementation "androidx.room:room-runtime:$room_version"
implementation "androidx.room:room-ktx:$room_version" implementation "androidx.room:room-ktx:$room_version"
kapt "androidx.room:room-compiler:$room_version" kapt "androidx.room:room-compiler:$room_version"
@ -138,7 +138,7 @@ dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
def kotlin_coroutines_version = '1.5.2' def kotlin_coroutines_version = '1.6.0-RC'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version" implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"

View File

@ -121,7 +121,7 @@
<activity android:name=".activities.PermissionActivity" /> <activity android:name=".activities.PermissionActivity" />
<activity android:name=".activities.LockScreenActivity" /> <activity android:name=".activities.LockScreenActivity" />
<activity <activity
android:name="code.name.monkey.retromusic.fragments.backup.RestoreActivity" android:name=".fragments.backup.RestoreActivity"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.VIEW" /> <action android:name="android.intent.action.VIEW" />
@ -256,13 +256,25 @@
android:name="android.appwidget.provider" android:name="android.appwidget.provider"
android:resource="@xml/app_widget_card_info" /> android:resource="@xml/app_widget_card_info" />
</receiver> </receiver>
<receiver
android:name=".appwidgets.AppWidgetMD3"
android:exported="true"
android:label="@string/app_widget_md3_name">
<intent-filter>
<action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
</intent-filter>
<meta-data
android:name="android.appwidget.provider"
android:resource="@xml/app_widget_md3_info" />
</receiver>
<service <service
android:name=".service.MusicService" android:name=".service.MusicService"
android:enabled="true" android:enabled="true"
android:exported="true" android:exported="true"
android:label="@string/app_name"
android:foregroundServiceType="mediaPlayback" android:foregroundServiceType="mediaPlayback"
android:label="@string/app_name"
tools:ignore="ExportedService"> tools:ignore="ExportedService">
<intent-filter> <intent-filter>
<action android:name="android.media.browse.MediaBrowserService" /> <action android:name="android.media.browse.MediaBrowserService" />

View File

@ -24,6 +24,7 @@ import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.databinding.ActivityDriveModeBinding import code.name.monkey.retromusic.databinding.ActivityDriveModeBinding
import code.name.monkey.retromusic.extensions.setDrawUnderStatusBar
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.glide.BlurTransformation import code.name.monkey.retromusic.glide.BlurTransformation
import code.name.monkey.retromusic.glide.GlideApp import code.name.monkey.retromusic.glide.GlideApp

View File

@ -24,7 +24,7 @@ import androidx.core.view.ViewCompat
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.databinding.ActivityLockScreenBinding import code.name.monkey.retromusic.databinding.ActivityLockScreenBinding
import code.name.monkey.retromusic.extensions.whichFragment import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.player.lockscreen.LockScreenControlsFragment import code.name.monkey.retromusic.fragments.player.lockscreen.LockScreenControlsFragment
import code.name.monkey.retromusic.glide.GlideApp import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension import code.name.monkey.retromusic.glide.RetroGlideExtension
@ -47,7 +47,7 @@ class LockScreenActivity : AbsMusicServiceActivity() {
binding = ActivityLockScreenBinding.inflate(layoutInflater) binding = ActivityLockScreenBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
hideStatusBar() hideStatusBar()
setStatusbarColorAuto() setStatusBarColorAuto()
setTaskDescriptionColorAuto() setTaskDescriptionColorAuto()
val config = SlidrConfig.Builder().listener(object : SlidrListener { val config = SlidrConfig.Builder().listener(object : SlidrListener {

View File

@ -26,9 +26,7 @@ import androidx.navigation.ui.setupWithNavController
import code.name.monkey.retromusic.* import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.activities.base.AbsCastActivity import code.name.monkey.retromusic.activities.base.AbsCastActivity
import code.name.monkey.retromusic.databinding.SlidingMusicPanelLayoutBinding import code.name.monkey.retromusic.databinding.SlidingMusicPanelLayoutBinding
import code.name.monkey.retromusic.extensions.currentFragment import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.extensions.extra
import code.name.monkey.retromusic.extensions.findNavController
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewFragment
import code.name.monkey.retromusic.fragments.home.HomeFragment import code.name.monkey.retromusic.fragments.home.HomeFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
@ -136,8 +134,8 @@ class MainActivity : AbsCastActivity(), OnSharedPreferenceChangeListener {
PreferenceUtil.registerOnSharedPreferenceChangedListener(this) PreferenceUtil.registerOnSharedPreferenceChangedListener(this)
val expand = extra<Boolean>(EXPAND_PANEL).value ?: false val expand = extra<Boolean>(EXPAND_PANEL).value ?: false
if (expand && PreferenceUtil.isExpandPanel) { if (expand && PreferenceUtil.isExpandPanel) {
setBottomNavVisibility(false)
fromNotification = true fromNotification = true
slidingPanel.bringToFront()
expandPanel() expandPanel()
intent.removeExtra(EXPAND_PANEL) intent.removeExtra(EXPAND_PANEL)
} }

View File

@ -30,6 +30,8 @@ import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.databinding.ActivityPermissionBinding import code.name.monkey.retromusic.databinding.ActivityPermissionBinding
import code.name.monkey.retromusic.extensions.accentBackgroundColor import code.name.monkey.retromusic.extensions.accentBackgroundColor
import code.name.monkey.retromusic.extensions.setStatusBarColorAuto
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.util.RingtoneManager import code.name.monkey.retromusic.util.RingtoneManager
@ -40,7 +42,7 @@ class PermissionActivity : AbsMusicServiceActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityPermissionBinding.inflate(layoutInflater) binding = ActivityPermissionBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
setStatusbarColorAuto() setStatusBarColorAuto()
setTaskDescriptionColorAuto() setTaskDescriptionColorAuto()
setupTitle() setupTitle()

View File

@ -28,6 +28,9 @@ import code.name.monkey.retromusic.Constants.PRO_VERSION_PRODUCT_ID
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.databinding.ActivityProVersionBinding import code.name.monkey.retromusic.databinding.ActivityProVersionBinding
import code.name.monkey.retromusic.extensions.setDrawUnderStatusBar
import code.name.monkey.retromusic.extensions.setLightStatusBar
import code.name.monkey.retromusic.extensions.setStatusBarColor
import com.anjlab.android.iab.v3.BillingProcessor import com.anjlab.android.iab.v3.BillingProcessor
import com.anjlab.android.iab.v3.PurchaseInfo import com.anjlab.android.iab.v3.PurchaseInfo
@ -41,8 +44,8 @@ class PurchaseActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityProVersionBinding.inflate(layoutInflater) binding = ActivityProVersionBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
setStatusbarColor(Color.TRANSPARENT) setStatusBarColor(Color.TRANSPARENT)
setLightStatusbar(false) setLightStatusBar(false)
binding.toolbar.navigationIcon?.setTint(Color.WHITE) binding.toolbar.navigationIcon?.setTint(Color.WHITE)
binding.toolbar.setNavigationOnClickListener { onBackPressed() } binding.toolbar.setNavigationOnClickListener { onBackPressed() }

View File

@ -25,10 +25,7 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsThemeActivity import code.name.monkey.retromusic.activities.base.AbsThemeActivity
import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager
import code.name.monkey.retromusic.databinding.ActivitySettingsBinding import code.name.monkey.retromusic.databinding.ActivitySettingsBinding
import code.name.monkey.retromusic.extensions.applyToolbar import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.extensions.extra
import code.name.monkey.retromusic.extensions.findNavController
import code.name.monkey.retromusic.extensions.surfaceColor
import com.afollestad.materialdialogs.MaterialDialog import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.color.ColorCallback import com.afollestad.materialdialogs.color.ColorCallback
@ -38,7 +35,7 @@ class SettingsActivity : AbsThemeActivity(), ColorCallback, OnThemeChangedListen
setDrawUnderStatusBar() setDrawUnderStatusBar()
val mSavedInstanceState = extra<Bundle>(TAG).value ?: savedInstanceState val mSavedInstanceState = extra<Bundle>(TAG).value ?: savedInstanceState
super.onCreate(mSavedInstanceState) super.onCreate(mSavedInstanceState)
setLightStatusbarAuto(surfaceColor()) setLightStatusBarAuto(surfaceColor())
binding = ActivitySettingsBinding.inflate(layoutInflater) binding = ActivitySettingsBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
setupToolbar() setupToolbar()

View File

@ -28,6 +28,10 @@ import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.activities.base.AbsBaseActivity import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.databinding.ActivityShareInstagramBinding import code.name.monkey.retromusic.databinding.ActivityShareInstagramBinding
import code.name.monkey.retromusic.extensions.applyToolbar
import code.name.monkey.retromusic.extensions.setDrawUnderStatusBar
import code.name.monkey.retromusic.extensions.setLightStatusBar
import code.name.monkey.retromusic.extensions.setStatusBarColor
import code.name.monkey.retromusic.glide.GlideApp import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
@ -60,7 +64,7 @@ class ShareInstagramStory : AbsBaseActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
binding = ActivityShareInstagramBinding.inflate(layoutInflater) binding = ActivityShareInstagramBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
setStatusbarColor(Color.TRANSPARENT) setStatusBarColor(Color.TRANSPARENT)
binding.toolbar.setBackgroundColor(Color.TRANSPARENT) binding.toolbar.setBackgroundColor(Color.TRANSPARENT)
setSupportActionBar(binding.toolbar) setSupportActionBar(binding.toolbar)
@ -104,7 +108,7 @@ class ShareInstagramStory : AbsBaseActivity() {
} }
private fun setColors(colorLight: Boolean, color: Int) { private fun setColors(colorLight: Boolean, color: Int) {
setLightStatusbar(colorLight) setLightStatusBar(colorLight)
binding.toolbar.setTitleTextColor( binding.toolbar.setTitleTextColor(
MaterialValueHelper.getPrimaryTextColor( MaterialValueHelper.getPrimaryTextColor(
this@ShareInstagramStory, this@ShareInstagramStory,

View File

@ -37,6 +37,8 @@ import code.name.monkey.retromusic.BuildConfig
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.databinding.ActivityDonationBinding import code.name.monkey.retromusic.databinding.ActivityDonationBinding
import code.name.monkey.retromusic.extensions.setStatusBarColorAuto
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
import code.name.monkey.retromusic.extensions.textColorPrimary import code.name.monkey.retromusic.extensions.textColorPrimary
import code.name.monkey.retromusic.extensions.textColorSecondary import code.name.monkey.retromusic.extensions.textColorSecondary
import com.anjlab.android.iab.v3.BillingProcessor import com.anjlab.android.iab.v3.BillingProcessor
@ -73,7 +75,7 @@ class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingH
binding = ActivityDonationBinding.inflate(layoutInflater) binding = ActivityDonationBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
setStatusbarColorAuto() setStatusBarColorAuto()
setTaskDescriptionColorAuto() setTaskDescriptionColorAuto()
setupToolbar() setupToolbar()

View File

@ -17,6 +17,8 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsThemeActivity import code.name.monkey.retromusic.activities.base.AbsThemeActivity
import code.name.monkey.retromusic.databinding.ActivityWhatsNewBinding import code.name.monkey.retromusic.databinding.ActivityWhatsNewBinding
import code.name.monkey.retromusic.extensions.accentColor import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.setLightStatusBarAuto
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
import code.name.monkey.retromusic.util.PreferenceUtil.lastVersion import code.name.monkey.retromusic.util.PreferenceUtil.lastVersion
import code.name.monkey.retromusic.util.RetroUtil import code.name.monkey.retromusic.util.RetroUtil
import java.io.BufferedReader import java.io.BufferedReader
@ -29,7 +31,7 @@ class WhatsNewActivity : AbsThemeActivity() {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
val binding = ActivityWhatsNewBinding.inflate(layoutInflater) val binding = ActivityWhatsNewBinding.inflate(layoutInflater)
setContentView(binding.root) setContentView(binding.root)
setLightStatusbarAuto(resolveColor(this, R.attr.colorSurface)) setLightStatusBarAuto(resolveColor(this, R.attr.colorSurface))
setTaskDescriptionColorAuto() setTaskDescriptionColorAuto()
binding.toolbar.setNavigationOnClickListener { onBackPressed() } binding.toolbar.setNavigationOnClickListener { onBackPressed() }
ToolbarContentTintHelper.colorBackButton(binding.toolbar) ToolbarContentTintHelper.colorBackButton(binding.toolbar)

View File

@ -14,7 +14,6 @@
*/ */
package code.name.monkey.retromusic.activities.base package code.name.monkey.retromusic.activities.base
import android.animation.Animator
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.graphics.Color import android.graphics.Color
import android.os.Bundle import android.os.Bundle
@ -25,6 +24,7 @@ import android.widget.FrameLayout
import androidx.core.animation.doOnEnd import androidx.core.animation.doOnEnd
import androidx.core.view.ViewCompat import androidx.core.view.ViewCompat
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import androidx.core.view.isGone
import androidx.core.view.isVisible import androidx.core.view.isVisible
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.fragment.app.commit import androidx.fragment.app.commit
@ -67,11 +67,10 @@ import org.koin.androidx.viewmodel.ext.android.viewModel
abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() { abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
companion object { companion object {
val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName val TAG: String = AbsSlidingMusicPanelActivity::class.java.simpleName
var fromNotification: Boolean = false
} }
var fromNotification = false
private var windowInsets: WindowInsetsCompat? = null private var windowInsets: WindowInsetsCompat? = null
private var bottomNavAnimator: Animator? = null
protected val libraryViewModel by viewModel<LibraryViewModel>() protected val libraryViewModel by viewModel<LibraryViewModel>()
private lateinit var bottomSheetBehavior: RetroBottomSheetBehavior<FrameLayout> private lateinit var bottomSheetBehavior: RetroBottomSheetBehavior<FrameLayout>
private var playerFragment: AbsPlayerFragment? = null private var playerFragment: AbsPlayerFragment? = null
@ -93,21 +92,19 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
when (newState) { when (newState) {
STATE_EXPANDED -> { STATE_EXPANDED -> {
onPanelExpanded() onPanelExpanded()
} }
STATE_COLLAPSED -> { STATE_COLLAPSED -> {
onPanelCollapsed() onPanelCollapsed()
if (fromNotification) {
hideBottomSheet(MusicPlayerRemote.playingQueue.isEmpty())
fromNotification = false
}
} }
STATE_SETTLING, STATE_DRAGGING -> { STATE_SETTLING, STATE_DRAGGING -> {
if (fromNotification) { if (fromNotification) {
bottomNavigationView.isVisible = true binding.bottomNavigationView.bringToFront()
fromNotification = false
} }
} }
else -> { else -> {
println("Do something") println("Do a flip")
} }
} }
} }
@ -175,7 +172,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
if (progress < 0) return if (progress < 0) return
val alpha = 1 - progress val alpha = 1 - progress
miniPlayerFragment?.view?.alpha = 1 - (progress / 0.2F) miniPlayerFragment?.view?.alpha = 1 - (progress / 0.2F)
miniPlayerFragment?.view?.visibility = if (alpha == 0f) View.GONE else View.VISIBLE miniPlayerFragment?.view?.isGone = alpha == 0f
binding.bottomNavigationView.translationY = progress * 500 binding.bottomNavigationView.translationY = progress * 500
binding.bottomNavigationView.alpha = alpha binding.bottomNavigationView.alpha = alpha
binding.playerFragmentContainer.alpha = (progress - 0.2F) / 0.2F binding.playerFragmentContainer.alpha = (progress - 0.2F) / 0.2F
@ -184,9 +181,9 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
open fun onPanelCollapsed() { open fun onPanelCollapsed() {
setMiniPlayerAlphaProgress(0F) setMiniPlayerAlphaProgress(0F)
// restore values // restore values
super.setLightStatusbarAuto(surfaceColor()) setLightStatusBarAuto(surfaceColor())
super.setLightNavigationAuto() setLightNavigationAuto()
super.setTaskDescriptionColor(taskColor) setTaskDescriptionColor(taskColor)
} }
open fun onPanelExpanded() { open fun onPanelExpanded() {
@ -217,6 +214,8 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
val bottomNavigationView get() = binding.bottomNavigationView val bottomNavigationView get() = binding.bottomNavigationView
val slidingPanel get() = binding.slidingPanel
override fun onServiceConnected() { override fun onServiceConnected() {
super.onServiceConnected() super.onServiceConnected()
if (MusicPlayerRemote.playingQueue.isNotEmpty()) { if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
@ -251,32 +250,31 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
collapsePanel() collapsePanel()
return true return true
} }
return false return false
} }
private fun onPaletteColorChanged() { private fun onPaletteColorChanged() {
if (panelState == STATE_EXPANDED) { if (panelState == STATE_EXPANDED) {
super.setTaskDescriptionColor(paletteColor) setTaskDescColor(paletteColor)
val isColorLight = ColorUtil.isColorLight(paletteColor) val isColorLight = ColorUtil.isColorLight(paletteColor)
if (PreferenceUtil.isAdaptiveColor && (nowPlayingScreen == Normal || nowPlayingScreen == Flat)) { if (PreferenceUtil.isAdaptiveColor && (nowPlayingScreen == Normal || nowPlayingScreen == Flat)) {
super.setLightNavigationBar(true) setLightNavigationBar(true)
super.setLightStatusbar(isColorLight) setLightStatusBar(isColorLight)
} else if (nowPlayingScreen == Card || nowPlayingScreen == Blur || nowPlayingScreen == BlurCard) { } else if (nowPlayingScreen == Card || nowPlayingScreen == Blur || nowPlayingScreen == BlurCard) {
super.setLightStatusbar(false) setLightStatusBar(false)
super.setLightNavigationBar(true) setLightNavigationBar(true)
} else if (nowPlayingScreen == Color || nowPlayingScreen == Tiny || nowPlayingScreen == Gradient) { } else if (nowPlayingScreen == Color || nowPlayingScreen == Tiny || nowPlayingScreen == Gradient) {
super.setLightNavigationBar(isColorLight) setLightNavigationBar(isColorLight)
super.setLightStatusbar(isColorLight) setLightStatusBar(isColorLight)
} else if (nowPlayingScreen == Full) { } else if (nowPlayingScreen == Full) {
super.setLightNavigationBar(isColorLight) setLightNavigationBar(isColorLight)
super.setLightStatusbar(false) setLightStatusBar(false)
} else if (nowPlayingScreen == Classic) { } else if (nowPlayingScreen == Classic) {
super.setLightStatusbar(false) setLightStatusBar(false)
} else if (nowPlayingScreen == Fit) { } else if (nowPlayingScreen == Fit) {
super.setLightStatusbar(false) setLightStatusBar(false)
} else { } else {
super.setLightStatusbar( setLightStatusBar(
ColorUtil.isColorLight( ColorUtil.isColorLight(
ATHUtil.resolveColor( ATHUtil.resolveColor(
this, this,
@ -284,15 +282,15 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
) )
) )
) )
super.setLightNavigationBar(true) setLightNavigationBar(true)
} }
} }
} }
override fun setTaskDescriptionColor(color: Int) { private fun setTaskDescColor(color: Int) {
taskColor = color taskColor = color
if (panelState == STATE_COLLAPSED) { if (panelState == STATE_COLLAPSED) {
super.setTaskDescriptionColor(color) setTaskDescriptionColor(color)
} }
} }
@ -319,53 +317,63 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
} }
fun setBottomNavVisibility(visible: Boolean, animate: Boolean = false) { fun setBottomNavVisibility(visible: Boolean, animate: Boolean = false) {
binding.bottomNavigationView.isVisible = visible val translationY =
hideBottomSheet(MusicPlayerRemote.playingQueue.isEmpty(), animate) if (visible) 0F else dip(R.dimen.bottom_nav_height).toFloat() + windowInsets.safeGetBottomInsets()
if (animate) {
binding.bottomNavigationView.translateYAnimate(translationY).doOnEnd {
if (visible && bottomSheetBehavior.state != STATE_EXPANDED) {
binding.bottomNavigationView.bringToFront()
}
}
} else {
binding.bottomNavigationView.translationY =
translationY
if (visible && bottomSheetBehavior.state != STATE_EXPANDED) {
binding.bottomNavigationView.bringToFront()
}
}
hideBottomSheet(
hide = MusicPlayerRemote.playingQueue.isEmpty(),
animate = animate,
isBottomNavVisible = visible
)
} }
fun hideBottomSheet(hide: Boolean, animate: Boolean = false) { fun hideBottomSheet(
hide: Boolean,
animate: Boolean = false,
isBottomNavVisible: Boolean = bottomNavigationView.isVisible
) {
val heightOfBar = val heightOfBar =
windowInsets.safeGetBottomInsets() + windowInsets.safeGetBottomInsets() +
if (MusicPlayerRemote.isCasting) dip(R.dimen.cast_mini_player_height) else dip(R.dimen.mini_player_height) if (MusicPlayerRemote.isCasting) dip(R.dimen.cast_mini_player_height) else dip(R.dimen.mini_player_height)
val heightOfBarWithTabs = heightOfBar + dip(R.dimen.bottom_nav_height) val heightOfBarWithTabs = heightOfBar + dip(R.dimen.bottom_nav_height)
val isVisible = binding.bottomNavigationView.isVisible
if (hide) { if (hide) {
bottomSheetBehavior.peekHeight = -windowInsets.safeGetBottomInsets() bottomSheetBehavior.peekHeight = -windowInsets.safeGetBottomInsets()
bottomSheetBehavior.state = STATE_COLLAPSED bottomSheetBehavior.state = STATE_COLLAPSED
libraryViewModel.setFabMargin(if (isVisible) dip(R.dimen.bottom_nav_height) else 0) libraryViewModel.setFabMargin(if (isBottomNavVisible) dip(R.dimen.bottom_nav_height) else 0)
ViewCompat.setElevation(binding.slidingPanel, 0f) ViewCompat.setElevation(binding.slidingPanel, 0f)
ViewCompat.setElevation(binding.bottomNavigationView, 10f) ViewCompat.setElevation(binding.bottomNavigationView, 10f)
} else { } else {
if (MusicPlayerRemote.playingQueue.isNotEmpty()) { if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
ViewCompat.setElevation(binding.slidingPanel, 10f) ViewCompat.setElevation(binding.slidingPanel, 10f)
ViewCompat.setElevation(binding.bottomNavigationView, 10f) ViewCompat.setElevation(binding.bottomNavigationView, 10f)
if (isVisible) { if (isBottomNavVisible) {
println("List") println("List")
if (animate) { if (animate) {
bottomNavAnimator?.end()
bottomSheetBehavior.peekHeightAnimate(heightOfBarWithTabs) bottomSheetBehavior.peekHeightAnimate(heightOfBarWithTabs)
bottomNavAnimator = binding.bottomNavigationView.translateYAnimate(0F)
} else { } else {
bottomSheetBehavior.peekHeight = heightOfBarWithTabs bottomSheetBehavior.peekHeight = heightOfBarWithTabs
binding.bottomNavigationView.translationY = 0F
} }
binding.bottomNavigationView.bringToFront()
libraryViewModel.setFabMargin(dip(R.dimen.mini_player_height_expanded)) libraryViewModel.setFabMargin(dip(R.dimen.mini_player_height_expanded))
} else { } else {
println("Details") println("Details")
if (animate) { if (animate) {
bottomSheetBehavior.peekHeightAnimate(heightOfBar) bottomSheetBehavior.peekHeightAnimate(heightOfBar).doOnEnd {
bottomNavAnimator?.end()
bottomNavAnimator =
bottomNavigationView.translateYAnimate(dip(R.dimen.bottom_nav_height).toFloat())
bottomNavAnimator?.doOnEnd {
binding.slidingPanel.bringToFront() binding.slidingPanel.bringToFront()
} }
} else { } else {
bottomSheetBehavior.peekHeight = heightOfBar bottomSheetBehavior.peekHeight = heightOfBar
binding.bottomNavigationView.translationY =
dip(R.dimen.bottom_nav_height).toFloat()
binding.slidingPanel.bringToFront() binding.slidingPanel.bringToFront()
} }
libraryViewModel.setFabMargin(dip(R.dimen.mini_player_height)) libraryViewModel.setFabMargin(dip(R.dimen.mini_player_height))

View File

@ -16,28 +16,16 @@ package code.name.monkey.retromusic.activities.base
import android.content.Context import android.content.Context
import android.content.res.Resources import android.content.res.Resources
import android.graphics.Color
import android.os.Bundle import android.os.Bundle
import android.os.Handler import android.os.Handler
import android.view.KeyEvent import android.view.KeyEvent
import android.view.View import android.view.View
import android.view.WindowManager
import androidx.annotation.ColorInt
import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode
import androidx.core.os.ConfigurationCompat import androidx.core.os.ConfigurationCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import code.name.monkey.appthemehelper.ATH
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.common.ATHToolbarActivity import code.name.monkey.appthemehelper.common.ATHToolbarActivity
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.LanguageContextWrapper import code.name.monkey.retromusic.LanguageContextWrapper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.theme.ThemeManager import code.name.monkey.retromusic.util.theme.ThemeManager
import com.google.android.material.color.DynamicColors import com.google.android.material.color.DynamicColors
import java.util.* import java.util.*
@ -53,9 +41,8 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
setImmersiveFullscreen() setImmersiveFullscreen()
registerSystemUiVisibility() registerSystemUiVisibility()
toggleScreenOn() toggleScreenOn()
setDrawUnderNavigationBar()
setLightNavigationAuto() setLightNavigationAuto()
setLightStatusbarAuto(surfaceColor()) setLightStatusBarAuto(surfaceColor())
} }
private fun updateTheme() { private fun updateTheme() {
@ -71,14 +58,6 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
} }
} }
private fun toggleScreenOn() {
if (PreferenceUtil.isScreenOnEnabled) {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
override fun onWindowFocusChanged(hasFocus: Boolean) { override fun onWindowFocusChanged(hasFocus: Boolean) {
super.onWindowFocusChanged(hasFocus) super.onWindowFocusChanged(hasFocus)
if (hasFocus) { if (hasFocus) {
@ -90,95 +69,6 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
} }
} }
fun hideStatusBar() {
hideStatusBar(PreferenceUtil.isFullScreenMode)
}
private fun hideStatusBar(fullscreen: Boolean) {
val statusBar = window.decorView.rootView.findViewById<View>(R.id.status_bar)
if (statusBar != null) {
statusBar.visibility = if (fullscreen) View.GONE else View.VISIBLE
}
}
fun setDrawUnderStatusBar() {
RetroUtil.setAllowDrawUnderStatusBar(window)
}
private fun setDrawUnderNavigationBar() {
RetroUtil.setAllowDrawUnderNavigationBar(window)
}
/**
* This will set the color of the view with the id "status_bar" on KitKat and Lollipop. On
* Lollipop if no such view is found it will set the statusbar color using the native method.
*
* @param color the new statusbar color (will be shifted down on Lollipop and above)
*/
fun setStatusbarColor(color: Int) {
val statusBar = window.decorView.rootView.findViewById<View>(R.id.status_bar)
if (statusBar != null) {
when {
VersionUtils.hasMarshmallow() -> statusBar.setBackgroundColor(color)
else -> statusBar.setBackgroundColor(
ColorUtil.darkenColor(
color
)
)
}
} else {
when {
VersionUtils.hasMarshmallow() -> window.statusBarColor = color
else -> window.statusBarColor = ColorUtil.darkenColor(color)
}
}
setLightStatusbarAuto(ATHUtil.resolveColor(this, R.attr.colorSurface))
}
fun setStatusbarColorAuto() {
// we don't want to use statusbar color because we are doing the color darkening on our own to support KitKat
setStatusbarColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
setLightStatusbarAuto(ATHUtil.resolveColor(this, R.attr.colorSurface))
}
open fun setTaskDescriptionColor(@ColorInt color: Int) {
ATH.setTaskDescriptionColor(this, color)
}
fun setTaskDescriptionColorAuto() {
setTaskDescriptionColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
}
open fun setNavigationbarColor(color: Int) {
if (ThemeStore.coloredNavigationBar(this)) {
ATH.setNavigationbarColor(this, color)
} else {
ATH.setNavigationbarColor(this, Color.BLACK)
}
}
fun setNavigationbarColorAuto() {
setNavigationbarColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
}
fun setLightNavigationAuto() {
ATH.setLightNavigationbarAuto(this, surfaceColor())
}
open fun setLightStatusbar(enabled: Boolean) {
ATH.setLightStatusbar(this, enabled)
}
fun setLightStatusbarAuto(bgColor: Int) {
setLightStatusbar(ColorUtil.isColorLight(bgColor))
}
open fun setLightNavigationBar(enabled: Boolean) {
if (!ATHUtil.isWindowBackgroundDark(this) and ThemeStore.coloredNavigationBar(this)) {
ATH.setLightNavigationbar(this, enabled)
}
}
private fun registerSystemUiVisibility() { private fun registerSystemUiVisibility() {
val decorView = window.decorView val decorView = window.decorView
decorView.setOnSystemUiVisibilityChangeListener { visibility -> decorView.setOnSystemUiVisibilityChangeListener { visibility ->
@ -193,23 +83,6 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
decorView.setOnSystemUiVisibilityChangeListener(null) decorView.setOnSystemUiVisibilityChangeListener(null)
} }
private fun setImmersiveFullscreen() {
if (PreferenceUtil.isFullScreenMode) {
WindowInsetsControllerCompat(window, window.decorView).apply {
systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
hide(WindowInsetsCompat.Type.systemBars())
}
}
}
private fun exitFullscreen() {
WindowInsetsControllerCompat(window, window.decorView).apply {
systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
show(WindowInsetsCompat.Type.systemBars())
}
}
override fun run() { override fun run() {
setImmersiveFullscreen() setImmersiveFullscreen()
} }

View File

@ -41,6 +41,7 @@ import code.name.monkey.retromusic.activities.bugreport.model.github.ExtraInfo
import code.name.monkey.retromusic.activities.bugreport.model.github.GithubLogin import code.name.monkey.retromusic.activities.bugreport.model.github.GithubLogin
import code.name.monkey.retromusic.activities.bugreport.model.github.GithubTarget import code.name.monkey.retromusic.activities.bugreport.model.github.GithubTarget
import code.name.monkey.retromusic.databinding.ActivityBugReportBinding import code.name.monkey.retromusic.databinding.ActivityBugReportBinding
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
import code.name.monkey.retromusic.misc.DialogAsyncTask import code.name.monkey.retromusic.misc.DialogAsyncTask
import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.floatingactionbutton.FloatingActionButton import com.google.android.material.floatingactionbutton.FloatingActionButton

View File

@ -42,6 +42,7 @@ import code.name.monkey.retromusic.R.drawable
import code.name.monkey.retromusic.activities.base.AbsBaseActivity import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.activities.saf.SAFGuideActivity import code.name.monkey.retromusic.activities.saf.SAFGuideActivity
import code.name.monkey.retromusic.extensions.accentColor import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
import code.name.monkey.retromusic.model.ArtworkInfo import code.name.monkey.retromusic.model.ArtworkInfo
import code.name.monkey.retromusic.model.AudioTagInfo import code.name.monkey.retromusic.model.AudioTagInfo
import code.name.monkey.retromusic.repository.Repository import code.name.monkey.retromusic.repository.Repository

View File

@ -32,6 +32,7 @@ import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.ActivityAlbumTagEditorBinding import code.name.monkey.retromusic.databinding.ActivityAlbumTagEditorBinding
import code.name.monkey.retromusic.extensions.appHandleColor import code.name.monkey.retromusic.extensions.appHandleColor
import code.name.monkey.retromusic.extensions.setDrawUnderStatusBar
import code.name.monkey.retromusic.extensions.setTint import code.name.monkey.retromusic.extensions.setTint
import code.name.monkey.retromusic.glide.GlideApp import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper

View File

@ -163,7 +163,7 @@ open class AlbumAdapter(
when (PreferenceUtil.albumSortOrder) { when (PreferenceUtil.albumSortOrder) {
SortOrder.AlbumSortOrder.ALBUM_A_Z, SortOrder.AlbumSortOrder.ALBUM_Z_A -> sectionName = SortOrder.AlbumSortOrder.ALBUM_A_Z, SortOrder.AlbumSortOrder.ALBUM_Z_A -> sectionName =
dataSet[position].title dataSet[position].title
SortOrder.AlbumSortOrder.ALBUM_ARTIST -> sectionName = dataSet[position].artistName SortOrder.AlbumSortOrder.ALBUM_ARTIST -> sectionName = dataSet[position].albumArtist
SortOrder.AlbumSortOrder.ALBUM_YEAR -> return MusicUtil.getYearString( SortOrder.AlbumSortOrder.ALBUM_YEAR -> return MusicUtil.getYearString(
dataSet[position].year dataSet[position].year
) )

View File

@ -0,0 +1,273 @@
/*
* Copyright (c) 2020 Hemanth Savarla.
*
* Licensed under the GNU General Public License v3
*
* This is free software: you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public License for more details.
*
*/
package code.name.monkey.retromusic.appwidgets
import android.app.PendingIntent
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.text.TextUtils
import android.view.View
import android.widget.RemoteViews
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.*
import code.name.monkey.retromusic.util.DensityUtil
import code.name.monkey.retromusic.util.ImageUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil
import com.bumptech.glide.Glide
import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.target.Target
import com.bumptech.glide.request.transition.Transition
class AppWidgetMD3 : BaseAppWidget() {
private var target: Target<BitmapPaletteWrapper>? = null // for cancellation
/**
* Initialize given widgets to default state, where we launch Music on default click and hide
* actions if service not running.
*/
override fun defaultAppWidget(context: Context, appWidgetIds: IntArray) {
val appWidgetView = RemoteViews(context.packageName, R.layout.app_widget_md3)
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE)
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_audio_art)
val secondaryColor = MaterialValueHelper.getSecondaryTextColor(context, true)
appWidgetView.setImageViewBitmap(
R.id.button_next, createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
R.drawable.ic_skip_next,
secondaryColor
), 1f
)
)
appWidgetView.setImageViewBitmap(
R.id.button_prev, createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
R.drawable.ic_skip_previous,
secondaryColor
), 1f
)
)
appWidgetView.setImageViewBitmap(
R.id.button_toggle_play_pause, createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
R.drawable.ic_play_arrow_white_32dp,
secondaryColor
), 1f
)
)
linkButtons(context, appWidgetView)
pushUpdate(context, appWidgetIds, appWidgetView)
}
/**
* Update all active widget instances by pushing changes
*/
override fun performUpdate(service: MusicService, appWidgetIds: IntArray?) {
val appWidgetView = RemoteViews(service.packageName, R.layout.app_widget_md3)
val isPlaying = service.isPlaying
val song = service.currentSong
// Set the titles and artwork
if (TextUtils.isEmpty(song.title) && TextUtils.isEmpty(song.artistName)) {
appWidgetView.setViewVisibility(R.id.media_titles, View.INVISIBLE)
} else {
appWidgetView.setViewVisibility(R.id.media_titles, View.VISIBLE)
appWidgetView.setTextViewText(R.id.title, song.title)
appWidgetView.setTextViewText(R.id.text, getSongArtistAndAlbum(song))
}
// Set correct drawable for pause state
val playPauseRes =
if (isPlaying) R.drawable.ic_pause else R.drawable.ic_play_arrow_white_32dp
appWidgetView.setImageViewBitmap(
R.id.button_toggle_play_pause, createBitmap(
RetroUtil.getTintedVectorDrawable(
service,
playPauseRes,
MaterialValueHelper.getSecondaryTextColor(service, true)
), 1f
)
)
// Set prev/next button drawables
appWidgetView.setImageViewBitmap(
R.id.button_next, createBitmap(
RetroUtil.getTintedVectorDrawable(
service,
R.drawable.ic_skip_next,
MaterialValueHelper.getSecondaryTextColor(service, true)
), 1f
)
)
appWidgetView.setImageViewBitmap(
R.id.button_prev, createBitmap(
RetroUtil.getTintedVectorDrawable(
service,
R.drawable.ic_skip_previous,
MaterialValueHelper.getSecondaryTextColor(service, true)
), 1f
)
)
// Link actions buttons to intents
linkButtons(service, appWidgetView)
if (imageSize == 0) {
imageSize =
service.resources.getDimensionPixelSize(R.dimen.app_widget_card_image_size)
}
if (cardRadius == 0f) {
cardRadius =
DensityUtil.dip2px(service, 8F).toFloat()
}
// Load the album cover async and push the update on completion
service.runOnUiThread {
if (target != null) {
Glide.with(service).clear(target)
}
target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song))
.centerCrop()
.into(object : SimpleTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
override fun onResourceReady(
resource: BitmapPaletteWrapper,
transition: Transition<in BitmapPaletteWrapper>?
) {
val palette = resource.palette
update(
resource.bitmap, palette.getVibrantColor(
palette.getMutedColor(
MaterialValueHelper.getSecondaryTextColor(
service, true
)
)
)
)
}
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
update(null, MaterialValueHelper.getSecondaryTextColor(service, true))
}
private fun update(bitmap: Bitmap?, color: Int) {
// Set correct drawable for pause state
appWidgetView.setImageViewBitmap(
R.id.button_toggle_play_pause, ImageUtil.createBitmap(
ImageUtil.getTintedVectorDrawable(
service, playPauseRes, color
)
)
)
// Set prev/next button drawables
appWidgetView.setImageViewBitmap(
R.id.button_next, ImageUtil.createBitmap(
ImageUtil.getTintedVectorDrawable(
service, R.drawable.ic_skip_next, color
)
)
)
appWidgetView.setImageViewBitmap(
R.id.button_prev, ImageUtil.createBitmap(
ImageUtil.getTintedVectorDrawable(
service, R.drawable.ic_skip_previous, color
)
)
)
val image = getAlbumArtDrawable(service.resources, bitmap)
val roundedBitmap = createRoundedBitmap(
image, imageSize, imageSize, cardRadius, cardRadius, cardRadius, cardRadius
)
appWidgetView.setImageViewBitmap(R.id.image, roundedBitmap)
pushUpdate(service, appWidgetIds, appWidgetView)
}
})
}
}
/**
* Link up various button actions using [PendingIntent].
*/
private fun linkButtons(context: Context, views: RemoteViews) {
val action = Intent(context, MainActivity::class.java)
.putExtra(
MainActivity.EXPAND_PANEL,
PreferenceUtil.isExpandPanel
)
val serviceName = ComponentName(context, MusicService::class.java)
// Home
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
var pendingIntent =
PendingIntent.getActivity(
context, 0, action, if (VersionUtils.hasMarshmallow())
PendingIntent.FLAG_IMMUTABLE
else 0
)
views.setOnClickPendingIntent(R.id.image, pendingIntent)
views.setOnClickPendingIntent(R.id.media_titles, pendingIntent)
// Previous track
pendingIntent = buildPendingIntent(context, ACTION_REWIND, serviceName)
views.setOnClickPendingIntent(R.id.button_prev, pendingIntent)
// Play and pause
pendingIntent = buildPendingIntent(context, ACTION_TOGGLE_PAUSE, serviceName)
views.setOnClickPendingIntent(R.id.button_toggle_play_pause, pendingIntent)
// Next track
pendingIntent = buildPendingIntent(context, ACTION_SKIP, serviceName)
views.setOnClickPendingIntent(R.id.button_next, pendingIntent)
}
companion object {
const val NAME = "app_widget_md3"
private var mInstance: AppWidgetMD3? = null
private var imageSize = 0
private var cardRadius = 0F
val instance: AppWidgetMD3
@Synchronized get() {
if (mInstance == null) {
mInstance = AppWidgetMD3()
}
return mInstance!!
}
}
}

View File

@ -0,0 +1,139 @@
package code.name.monkey.retromusic.extensions
import android.app.ActivityManager
import android.graphics.Color
import android.os.Build
import android.view.View
import android.view.WindowManager
import androidx.appcompat.app.AppCompatActivity
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
import androidx.fragment.app.FragmentActivity
import code.name.monkey.appthemehelper.ATH
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.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil
fun AppCompatActivity.toggleScreenOn() {
if (PreferenceUtil.isScreenOnEnabled) {
window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
} else {
window.clearFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
}
fun AppCompatActivity.setImmersiveFullscreen() {
if (PreferenceUtil.isFullScreenMode) {
WindowInsetsControllerCompat(window, window.decorView).apply {
systemBarsBehavior =
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
hide(WindowInsetsCompat.Type.systemBars())
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
window.attributes.layoutInDisplayCutoutMode =
WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES
}
}
}
fun AppCompatActivity.exitFullscreen() {
WindowInsetsControllerCompat(window, window.decorView).apply {
systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
show(WindowInsetsCompat.Type.systemBars())
}
}
fun AppCompatActivity.hideStatusBar() {
hideStatusBar(PreferenceUtil.isFullScreenMode)
}
private fun AppCompatActivity.hideStatusBar(fullscreen: Boolean) {
val statusBar = window.decorView.rootView.findViewById<View>(R.id.status_bar)
if (statusBar != null) {
statusBar.visibility = if (fullscreen) View.GONE else View.VISIBLE
}
}
fun AppCompatActivity.setDrawUnderStatusBar() {
WindowCompat.setDecorFitsSystemWindows(window, false)
window.statusBarColor = Color.TRANSPARENT
}
fun FragmentActivity.setTaskDescriptionColor(color: Int) {
var colorFinal = color
// Task description requires fully opaque color
colorFinal = ColorUtil.stripAlpha(colorFinal)
// Sets color of entry in the system recents page
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
setTaskDescription(
ActivityManager.TaskDescription(
title as String?,
-1,
colorFinal
)
)
} else {
setTaskDescription(ActivityManager.TaskDescription(title as String?))
}
}
fun AppCompatActivity.setTaskDescriptionColorAuto() {
setTaskDescriptionColor(surfaceColor())
}
fun AppCompatActivity.setLightNavigationAuto() {
ATH.setLightNavigationBarAuto(this, surfaceColor())
}
fun AppCompatActivity.setLightStatusBar(enabled: Boolean) {
ATH.setLightStatusBar(this, enabled)
}
fun AppCompatActivity.setLightStatusBarAuto(bgColor: Int) {
setLightStatusBar(ColorUtil.isColorLight(bgColor))
}
fun AppCompatActivity.setLightNavigationBar(enabled: Boolean) {
if (!ATHUtil.isWindowBackgroundDark(this) and ThemeStore.coloredNavigationBar(this)) {
ATH.setLightNavigationbar(this, enabled)
}
}
/**
* This will set the color of the view with the id "status_bar" on KitKat and Lollipop. On
* Lollipop if no such view is found it will set the statusbar color using the native method.
*
* @param color the new statusbar color (will be shifted down on Lollipop and above)
*/
fun AppCompatActivity.setStatusBarColor(color: Int) {
val statusBar = window.decorView.rootView.findViewById<View>(R.id.status_bar)
if (statusBar != null) {
when {
VersionUtils.hasMarshmallow() -> statusBar.setBackgroundColor(color)
else -> statusBar.setBackgroundColor(
ColorUtil.darkenColor(
color
)
)
}
} else {
when {
VersionUtils.hasMarshmallow() -> window.statusBarColor = color
else -> window.statusBarColor = ColorUtil.darkenColor(color)
}
}
setLightStatusBarAuto(ATHUtil.resolveColor(this, R.attr.colorSurface))
}
fun AppCompatActivity.setStatusBarColorAuto() {
// we don't want to use statusbar color because we are doing the color darkening on our own to support KitKat
setStatusBarColor(ATHUtil.resolveColor(this, R.attr.colorSurface))
setLightStatusBarAuto(ATHUtil.resolveColor(this, R.attr.colorSurface))
}

View File

@ -0,0 +1,39 @@
package code.name.monkey.retromusic.extensions
import android.net.Uri
import android.webkit.MimeTypeMap
import androidx.fragment.app.Fragment
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.RetroUtil
import org.jaudiotagger.audio.AudioFileIO
import java.io.File
import java.net.URLEncoder
fun getSongInfo(song: Song): String {
val file = File(song.data)
if (file.exists()) {
return try {
val audioHeader = AudioFileIO.read(File(song.data)).audioHeader
val string: StringBuilder = StringBuilder()
val uriFile = Uri.fromFile(file)
string.append(getMimeType(uriFile.toString())).append("")
string.append(audioHeader.bitRate).append(" kb/s").append("")
string.append(RetroUtil.frequencyCount(audioHeader.sampleRate.toInt()))
.append(" kHz")
string.toString()
} catch (er: Exception) {
" - "
}
}
return "-"
}
private fun getMimeType(url: String): String {
var type: String? = MimeTypeMap.getFileExtensionFromUrl(
URLEncoder.encode(url, "utf-8")
).uppercase()
if (type == null) {
type = url.substring(url.lastIndexOf(".") + 1)
}
return type
}

View File

@ -1,7 +1,9 @@
package code.name.monkey.retromusic.extensions package code.name.monkey.retromusic.extensions
import androidx.core.view.WindowInsetsCompat import androidx.core.view.WindowInsetsCompat
import code.name.monkey.retromusic.util.RetroUtil
fun WindowInsetsCompat?.safeGetBottomInsets(): Int { fun WindowInsetsCompat?.safeGetBottomInsets(): Int {
return this?.getInsets(WindowInsetsCompat.Type.systemBars())?.bottom ?: 0 // Get Navbar heights if insets are null
return (this?.getInsets(WindowInsetsCompat.Type.systemBars())?.bottom ?: RetroUtil.getNavigationBarHeight())
} }

View File

@ -37,6 +37,7 @@ import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.imageview.ShapeableImageView import com.google.android.material.imageview.ShapeableImageView
import com.google.android.material.shape.ShapeAppearanceModel import com.google.android.material.shape.ShapeAppearanceModel
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
fun <T : View> ViewGroup.inflate(@LayoutRes layout: Int): T { fun <T : View> ViewGroup.inflate(@LayoutRes layout: Int): T {
return LayoutInflater.from(context).inflate(layout, this, false) as T return LayoutInflater.from(context).inflate(layout, this, false) as T
@ -67,21 +68,22 @@ fun View.translateYAnimate(value: Float): Animator {
.apply { .apply {
duration = 300 duration = 300
doOnStart { doOnStart {
if (value == 0f) { show()
show() bringToFront()
}
} }
doOnEnd { doOnEnd {
if (value != 0f) { if (value != 0f) {
hide() hide()
} else {
show()
} }
} }
start() start()
} }
} }
fun BottomSheetBehavior<*>.peekHeightAnimate(value: Int) { fun BottomSheetBehavior<*>.peekHeightAnimate(value: Int): Animator {
ObjectAnimator.ofInt(this, "peekHeight", value) return ObjectAnimator.ofInt(this, "peekHeight", value)
.apply { .apply {
duration = 300 duration = 300
start() start()
@ -136,6 +138,7 @@ fun ShapeableImageView.setCircleShape(boolean: Boolean) {
* This will draw our view above the navigation bar instead of behind it by adding margins. * This will draw our view above the navigation bar instead of behind it by adding margins.
*/ */
fun View.drawAboveSystemBars(onlyPortrait: Boolean = true) { fun View.drawAboveSystemBars(onlyPortrait: Boolean = true) {
if (PreferenceUtil.isFullScreenMode) return
if (onlyPortrait && RetroUtil.isLandscape()) return if (onlyPortrait && RetroUtil.isLandscape()) return
// Create a snapshot of the view's margin state // Create a snapshot of the view's margin state
val initialMargin = recordInitialMarginForView(this) val initialMargin = recordInitialMarginForView(this)
@ -157,6 +160,7 @@ fun View.drawAboveSystemBars(onlyPortrait: Boolean = true) {
* This will draw our view above the navigation bar instead of behind it by adding padding. * This will draw our view above the navigation bar instead of behind it by adding padding.
*/ */
fun View.drawAboveSystemBarsWithPadding(consume: Boolean = false) { fun View.drawAboveSystemBarsWithPadding(consume: Boolean = false) {
if (PreferenceUtil.isFullScreenMode) return
val initialPadding = recordInitialPaddingForView(this) val initialPadding = recordInitialPaddingForView(this)
ViewCompat.setOnApplyWindowInsetsListener( ViewCompat.setOnApplyWindowInsetsListener(

View File

@ -29,6 +29,7 @@ import code.name.monkey.retromusic.util.DensityUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import kotlinx.coroutines.Dispatchers.IO import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File import java.io.File
class LibraryViewModel( class LibraryViewModel(
@ -278,14 +279,16 @@ class LibraryViewModel(
} }
emit(songs) emit(songs)
// Cleaning up deleted or moved songs // Cleaning up deleted or moved songs
songs.forEach { song -> withContext(IO) {
if (!File(song.data).exists() || song.id == -1L) { songs.forEach { song ->
repository.deleteSongInPlayCount(song.toPlayCount()) if (!File(song.data).exists() || song.id == -1L) {
repository.deleteSongInPlayCount(song.toPlayCount())
}
} }
emit(repository.playCountSongs().map {
it.toSong()
})
} }
emit(repository.playCountSongs().map {
it.toSong()
})
} }
fun artists(type: Int): LiveData<List<Artist>> = liveData { fun artists(type: Int): LiveData<List<Artist>> = liveData {

View File

@ -196,7 +196,7 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
0, 0,
R.id.action_album_sort_order_artist, R.id.action_album_sort_order_artist,
2, 2,
R.string.sort_order_artist R.string.sort_order_album_artist
).isChecked = ).isChecked =
currentSortOrder.equals(AlbumSortOrder.ALBUM_ARTIST) currentSortOrder.equals(AlbumSortOrder.ALBUM_ARTIST)
sortOrderMenu.add( sortOrderMenu.add(

View File

@ -22,6 +22,8 @@ import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.MainActivity import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.extensions.setLightStatusBarAuto
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.LibraryViewModel
import org.koin.androidx.viewmodel.ext.android.sharedViewModel import org.koin.androidx.viewmodel.ext.android.sharedViewModel
@ -42,7 +44,7 @@ abstract class AbsMainActivityFragment(@LayoutRes layout: Int) : AbsMusicService
if (statusBar != null) { if (statusBar != null) {
if (VersionUtils.hasMarshmallow()) { if (VersionUtils.hasMarshmallow()) {
statusBar.setBackgroundColor(color) statusBar.setBackgroundColor(color)
mainActivity.setLightStatusbarAuto(color) mainActivity.setLightStatusBarAuto(color)
} else { } else {
statusBar.setBackgroundColor(color) statusBar.setBackgroundColor(color)
} }

View File

@ -15,21 +15,14 @@
package code.name.monkey.retromusic.fragments.base package code.name.monkey.retromusic.fragments.base
import android.content.Context import android.content.Context
import android.net.Uri
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.webkit.MimeTypeMap
import androidx.annotation.LayoutRes import androidx.annotation.LayoutRes
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.navigation.navOptions import androidx.navigation.navOptions
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.interfaces.IMusicServiceEventListener import code.name.monkey.retromusic.interfaces.IMusicServiceEventListener
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.RetroUtil
import org.jaudiotagger.audio.AudioFileIO
import java.io.File
import java.net.URLEncoder
/** /**
* Created by hemanths on 18/08/17. * Created by hemanths on 18/08/17.
@ -103,33 +96,4 @@ open class AbsMusicServiceFragment(@LayoutRes layout: Int) : Fragment(layout),
override fun onMediaStoreChanged() { override fun onMediaStoreChanged() {
} }
fun getSongInfo(song: Song): String {
val file = File(song.data)
if (file.exists()) {
return try {
val audioHeader = AudioFileIO.read(File(song.data)).audioHeader
val string: StringBuilder = StringBuilder()
val uriFile = Uri.fromFile(file)
string.append(getMimeType(uriFile.toString())).append("")
string.append(audioHeader.bitRate).append(" kb/s").append("")
string.append(RetroUtil.frequencyCount(audioHeader.sampleRate.toInt()))
.append(" kHz")
string.toString()
} catch (er: Exception) {
" - "
}
}
return "-"
}
private fun getMimeType(url: String): String {
var type: String? = MimeTypeMap.getFileExtensionFromUrl(
URLEncoder.encode(url, "utf-8")
).uppercase()
if (type == null) {
type = url.substring(url.lastIndexOf(".") + 1)
}
return type
}
} }

View File

@ -97,6 +97,7 @@ class LyricsFragment : AbsMusicServiceFragment(R.layout.fragment_lyrics) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
setHasOptionsMenu(true)
enterTransition = Fade() enterTransition = Fade()
exitTransition = Fade() exitTransition = Fade()
lyricsSectionsAdapter = LyricsSectionsAdapter(requireActivity()) lyricsSectionsAdapter = LyricsSectionsAdapter(requireActivity())

View File

@ -29,10 +29,7 @@ import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentAdaptivePlayerPlaybackControlsBinding import code.name.monkey.retromusic.databinding.FragmentAdaptivePlayerPlaybackControlsBinding
import code.name.monkey.retromusic.extensions.applyColor import code.name.monkey.retromusic.extensions.*
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.fragments.base.AbsPlayerControlsFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper

View File

@ -29,6 +29,7 @@ import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentBlurPlayerPlaybackControlsBinding import code.name.monkey.retromusic.databinding.FragmentBlurPlayerPlaybackControlsBinding
import code.name.monkey.retromusic.extensions.getSongInfo
import code.name.monkey.retromusic.extensions.hide import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment

View File

@ -27,6 +27,7 @@ import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentCardPlayerPlaybackControlsBinding 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.hide
import code.name.monkey.retromusic.extensions.ripAlpha import code.name.monkey.retromusic.extensions.ripAlpha
import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.extensions.show

View File

@ -27,6 +27,7 @@ import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentCardBlurPlayerPlaybackControlsBinding import code.name.monkey.retromusic.databinding.FragmentCardBlurPlayerPlaybackControlsBinding
import code.name.monkey.retromusic.extensions.applyColor 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.hide
import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment

View File

@ -36,6 +36,7 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.RetroBottomSheetBehavior import code.name.monkey.retromusic.RetroBottomSheetBehavior
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
import code.name.monkey.retromusic.databinding.FragmentClassicPlayerBinding import code.name.monkey.retromusic.databinding.FragmentClassicPlayerBinding
import code.name.monkey.retromusic.extensions.getSongInfo
import code.name.monkey.retromusic.extensions.hide import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment

View File

@ -32,6 +32,7 @@ import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentColorPlayerPlaybackControlsBinding import code.name.monkey.retromusic.databinding.FragmentColorPlayerPlaybackControlsBinding
import code.name.monkey.retromusic.extensions.applyColor 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.hide
import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment

View File

@ -29,6 +29,7 @@ import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentFitPlaybackControlsBinding import code.name.monkey.retromusic.databinding.FragmentFitPlaybackControlsBinding
import code.name.monkey.retromusic.extensions.getSongInfo
import code.name.monkey.retromusic.extensions.hide import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.ripAlpha import code.name.monkey.retromusic.extensions.ripAlpha
import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.extensions.show

View File

@ -28,10 +28,7 @@ import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentFlatPlayerPlaybackControlsBinding import code.name.monkey.retromusic.databinding.FragmentFlatPlayerPlaybackControlsBinding
import code.name.monkey.retromusic.extensions.applyColor import code.name.monkey.retromusic.extensions.*
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.fragments.base.AbsPlayerControlsFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.fragments.base.goToAlbum import code.name.monkey.retromusic.fragments.base.goToAlbum
import code.name.monkey.retromusic.fragments.base.goToArtist import code.name.monkey.retromusic.fragments.base.goToArtist

View File

@ -36,6 +36,7 @@ import code.name.monkey.retromusic.db.PlaylistEntity
import code.name.monkey.retromusic.db.SongEntity import code.name.monkey.retromusic.db.SongEntity
import code.name.monkey.retromusic.db.toSongEntity import code.name.monkey.retromusic.db.toSongEntity
import code.name.monkey.retromusic.extensions.applyColor 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.hide
import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.LibraryViewModel

View File

@ -28,10 +28,7 @@ import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentPlayerPlaybackControlsBinding import code.name.monkey.retromusic.databinding.FragmentPlayerPlaybackControlsBinding
import code.name.monkey.retromusic.extensions.applyColor import code.name.monkey.retromusic.extensions.*
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.fragments.base.AbsPlayerControlsFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.fragments.base.goToAlbum import code.name.monkey.retromusic.fragments.base.goToAlbum
import code.name.monkey.retromusic.fragments.base.goToArtist import code.name.monkey.retromusic.fragments.base.goToArtist

View File

@ -22,6 +22,7 @@ import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentPeakPlayerBinding import code.name.monkey.retromusic.databinding.FragmentPeakPlayerBinding
import code.name.monkey.retromusic.extensions.drawAboveSystemBars import code.name.monkey.retromusic.extensions.drawAboveSystemBars
import code.name.monkey.retromusic.extensions.getSongInfo
import code.name.monkey.retromusic.extensions.hide import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment

View File

@ -30,6 +30,7 @@ import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentPlainControlsFragmentBinding import code.name.monkey.retromusic.databinding.FragmentPlainControlsFragmentBinding
import code.name.monkey.retromusic.extensions.applyColor 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.hide
import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment

View File

@ -25,6 +25,7 @@ import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.TintHelper import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentSimpleControlsFragmentBinding import code.name.monkey.retromusic.databinding.FragmentSimpleControlsFragmentBinding
import code.name.monkey.retromusic.extensions.getSongInfo
import code.name.monkey.retromusic.extensions.hide import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment

View File

@ -28,6 +28,7 @@ import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentTinyPlayerBinding import code.name.monkey.retromusic.databinding.FragmentTinyPlayerBinding
import code.name.monkey.retromusic.extensions.drawAboveSystemBars import code.name.monkey.retromusic.extensions.drawAboveSystemBars
import code.name.monkey.retromusic.extensions.getSongInfo
import code.name.monkey.retromusic.extensions.hide import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.show import code.name.monkey.retromusic.extensions.show
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment

View File

@ -18,9 +18,10 @@ import code.name.monkey.retromusic.adapter.song.OrderablePlaylistSongAdapter
import code.name.monkey.retromusic.databinding.FragmentPlaylistDetailBinding import code.name.monkey.retromusic.databinding.FragmentPlaylistDetailBinding
import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.db.toSongs import code.name.monkey.retromusic.db.toSongs
import code.name.monkey.retromusic.extensions.dipToPix import code.name.monkey.retromusic.extensions.dip
import code.name.monkey.retromusic.extensions.surfaceColor import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper import code.name.monkey.retromusic.helper.menu.PlaylistMenuHelper
import code.name.monkey.retromusic.interfaces.ICabCallback import code.name.monkey.retromusic.interfaces.ICabCallback
import code.name.monkey.retromusic.interfaces.ICabHolder import code.name.monkey.retromusic.interfaces.ICabHolder
@ -123,8 +124,12 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli
} }
private fun checkForPadding() { private fun checkForPadding() {
val height = dipToPix(52f) val itemCount: Int = playlistSongAdapter.itemCount
binding.recyclerView.setPadding(0, 0, 0, height.toInt()) if (itemCount > 0 && MusicPlayerRemote.playingQueue.isNotEmpty()) {
binding.recyclerView.updatePadding(bottom = dip(R.dimen.mini_player_height))
} else {
binding.recyclerView.updatePadding(bottom = 0)
}
} }
private fun checkIsEmpty() { private fun checkIsEmpty() {

View File

@ -19,15 +19,16 @@ import android.graphics.drawable.ColorDrawable
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import android.widget.Toast import android.widget.Toast
import androidx.core.view.ViewCompat
import androidx.core.view.updatePadding import androidx.core.view.updatePadding
import androidx.preference.ListPreference import androidx.preference.ListPreference
import androidx.preference.Preference import androidx.preference.Preference
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceFragmentCompat import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceFragmentCompat
import code.name.monkey.retromusic.activities.OnThemeChangedListener import code.name.monkey.retromusic.activities.OnThemeChangedListener
import code.name.monkey.retromusic.extensions.safeGetBottomInsets
import code.name.monkey.retromusic.preferences.* import code.name.monkey.retromusic.preferences.*
import code.name.monkey.retromusic.util.NavigationUtil import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.RetroUtil
/** /**
* @author Hemanth S (h4h13). * @author Hemanth S (h4h13).
@ -66,16 +67,19 @@ abstract class AbsSettingsFragment : ATEPreferenceFragmentCompat() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState) super.onViewCreated(view, savedInstanceState)
setDivider(ColorDrawable(Color.TRANSPARENT)) setDivider(ColorDrawable(Color.TRANSPARENT))
// This is a workaround as CollapsingToolbarLayout consumes insets and // CollapsingToolbarLayout consumes insets and insets are not passed to child views
// insets are not passed to child views // So we get insets from root view
// https://github.com/material-components/material-components-android/issues/1310 // https://github.com/material-components/material-components-android/issues/1310
if (!RetroUtil.isLandscape()) { ViewCompat.setOnApplyWindowInsetsListener(
listView.updatePadding(bottom = RetroUtil.getNavigationBarHeight()) view
) { _, insets ->
listView.updatePadding(bottom = insets.safeGetBottomInsets())
insets
} }
invalidateSettings() invalidateSettings()
} }
override fun onDisplayPreferenceDialog(preference: Preference?) { override fun onDisplayPreferenceDialog(preference: Preference) {
when (preference) { when (preference) {
is LibraryPreference -> { is LibraryPreference -> {
val fragment = LibraryPreferenceDialog.newInstance() val fragment = LibraryPreferenceDialog.newInstance()

View File

@ -33,10 +33,10 @@ import java.io.File
@GlideExtension @GlideExtension
object RetroGlideExtension { object RetroGlideExtension {
private const val DEFAULT_ERROR_ARTIST_IMAGE = private const val DEFAULT_ARTIST_IMAGE =
R.drawable.default_artist_art R.drawable.default_artist_art
private const val DEFAULT_ERROR_SONG_IMAGE: Int = R.drawable.default_audio_art private const val DEFAULT_SONG_IMAGE: Int = R.drawable.default_audio_art
private const val DEFAULT_ERROR_ALBUM_IMAGE = R.drawable.default_album_art private const val DEFAULT_ALBUM_IMAGE = R.drawable.default_album_art
private const val DEFAULT_ERROR_IMAGE_BANNER = R.drawable.material_design_default private const val DEFAULT_ERROR_IMAGE_BANNER = R.drawable.material_design_default
private val DEFAULT_DISK_CACHE_STRATEGY_ARTIST = DiskCacheStrategy.RESOURCE private val DEFAULT_DISK_CACHE_STRATEGY_ARTIST = DiskCacheStrategy.RESOURCE
@ -99,7 +99,8 @@ object RetroGlideExtension {
return baseRequestOptions return baseRequestOptions
.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY_ARTIST) .diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY_ARTIST)
.priority(Priority.LOW) .priority(Priority.LOW)
.error(DEFAULT_ERROR_ARTIST_IMAGE) .error(DEFAULT_ARTIST_IMAGE)
.placeholder(DEFAULT_ARTIST_IMAGE)
.signature(createSignature(artist)) .signature(createSignature(artist))
} }
@ -110,7 +111,8 @@ object RetroGlideExtension {
song: Song song: Song
): BaseRequestOptions<*> { ): BaseRequestOptions<*> {
return baseRequestOptions.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY) return baseRequestOptions.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
.error(DEFAULT_ERROR_SONG_IMAGE) .error(DEFAULT_SONG_IMAGE)
.placeholder(DEFAULT_SONG_IMAGE)
.signature(createSignature(song)) .signature(createSignature(song))
} }
@ -121,7 +123,8 @@ object RetroGlideExtension {
song: Song song: Song
): BaseRequestOptions<*> { ): BaseRequestOptions<*> {
return baseRequestOptions.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY) return baseRequestOptions.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
.error(DEFAULT_ERROR_ALBUM_IMAGE) .error(DEFAULT_ALBUM_IMAGE)
.placeholder(DEFAULT_ALBUM_IMAGE)
.signature(createSignature(song)) .signature(createSignature(song))
} }
@ -154,7 +157,7 @@ object RetroGlideExtension {
baseRequestOptions: BaseRequestOptions<*> baseRequestOptions: BaseRequestOptions<*>
): BaseRequestOptions<*> { ): BaseRequestOptions<*> {
return baseRequestOptions.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY) return baseRequestOptions.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY)
.error(DEFAULT_ERROR_ALBUM_IMAGE) .error(DEFAULT_ALBUM_IMAGE)
} }
private fun createSignature(song: Song): Key { private fun createSignature(song: Song): Key {

View File

@ -33,8 +33,7 @@ abstract class RetroMusicColoredTarget(view: ImageView) : BitmapPaletteTarget(vi
override fun onLoadFailed(errorDrawable: Drawable?) { override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable) super.onLoadFailed(errorDrawable)
val colors = MediaNotificationProcessor(App.getContext(), errorDrawable) onColorReady(MediaNotificationProcessor.errorColor(App.getContext()))
onColorReady(colors)
} }
override fun onResourceReady( override fun onResourceReady(

View File

@ -54,11 +54,11 @@ class SortOrder {
const val ALBUM_Z_A = "$ALBUM_A_Z DESC" const val ALBUM_Z_A = "$ALBUM_A_Z DESC"
/* Album sort order songs */ /* Album sort order songs */
const val ALBUM_NUMBER_OF_SONGS = MediaStore.Audio.AlbumColumns.NUMBER_OF_SONGS + " DESC" const val ALBUM_NUMBER_OF_SONGS =
MediaStore.Audio.AlbumColumns.NUMBER_OF_SONGS + " DESC"
/* Album sort order artist */ /* Album Artist sort order artist */
const val ALBUM_ARTIST = (MediaStore.Audio.Artists.DEFAULT_SORT_ORDER + const val ALBUM_ARTIST = "case when lower(album_artist) is null then 1 else 0 end, lower(album_artist)"
", " + MediaStore.Audio.Albums.DEFAULT_SORT_ORDER)
/* Album sort order year */ /* Album sort order year */
const val ALBUM_YEAR = MediaStore.Audio.Media.YEAR + " DESC" const val ALBUM_YEAR = MediaStore.Audio.Media.YEAR + " DESC"

View File

@ -25,6 +25,7 @@ import static code.name.monkey.retromusic.ConstantsKt.CROSS_FADE_DURATION;
import static code.name.monkey.retromusic.ConstantsKt.TOGGLE_HEADSET; import static code.name.monkey.retromusic.ConstantsKt.TOGGLE_HEADSET;
import static code.name.monkey.retromusic.service.AudioFader.startFadeAnimator; import static code.name.monkey.retromusic.service.AudioFader.startFadeAnimator;
import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
import android.appwidget.AppWidgetManager; import android.appwidget.AppWidgetManager;
import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothDevice;
@ -34,6 +35,7 @@ import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.pm.ServiceInfo;
import android.database.ContentObserver; import android.database.ContentObserver;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.Point; import android.graphics.Point;
@ -81,6 +83,7 @@ import code.name.monkey.retromusic.activities.LockScreenActivity;
import code.name.monkey.retromusic.appwidgets.AppWidgetBig; import code.name.monkey.retromusic.appwidgets.AppWidgetBig;
import code.name.monkey.retromusic.appwidgets.AppWidgetCard; import code.name.monkey.retromusic.appwidgets.AppWidgetCard;
import code.name.monkey.retromusic.appwidgets.AppWidgetClassic; import code.name.monkey.retromusic.appwidgets.AppWidgetClassic;
import code.name.monkey.retromusic.appwidgets.AppWidgetMD3;
import code.name.monkey.retromusic.appwidgets.AppWidgetSmall; import code.name.monkey.retromusic.appwidgets.AppWidgetSmall;
import code.name.monkey.retromusic.appwidgets.AppWidgetText; import code.name.monkey.retromusic.appwidgets.AppWidgetText;
import code.name.monkey.retromusic.auto.AutoMediaIDHelper; import code.name.monkey.retromusic.auto.AutoMediaIDHelper;
@ -105,6 +108,7 @@ import code.name.monkey.retromusic.util.PreferenceUtil;
import code.name.monkey.retromusic.util.RetroUtil; import code.name.monkey.retromusic.util.RetroUtil;
import code.name.monkey.retromusic.volume.AudioVolumeObserver; import code.name.monkey.retromusic.volume.AudioVolumeObserver;
import code.name.monkey.retromusic.volume.OnAudioVolumeChangedListener; import code.name.monkey.retromusic.volume.OnAudioVolumeChangedListener;
import kotlin.Unit;
/** /**
* @author Karim Abou Zeid (kabouzeid), Andrew Neal * @author Karim Abou Zeid (kabouzeid), Andrew Neal
@ -198,6 +202,8 @@ public class MusicService extends MediaBrowserServiceCompat
private final AppWidgetText appWidgetText = AppWidgetText.Companion.getInstance(); private final AppWidgetText appWidgetText = AppWidgetText.Companion.getInstance();
private final AppWidgetMD3 appWidgetMd3 = AppWidgetMD3.Companion.getInstance();
private final BroadcastReceiver widgetIntentReceiver = private final BroadcastReceiver widgetIntentReceiver =
new BroadcastReceiver() { new BroadcastReceiver() {
@Override @Override
@ -226,6 +232,10 @@ public class MusicService extends MediaBrowserServiceCompat
appWidgetText.performUpdate(MusicService.this, ids); appWidgetText.performUpdate(MusicService.this, ids);
break; break;
} }
case AppWidgetMD3.NAME: {
appWidgetMd3.performUpdate(MusicService.this, ids);
break;
}
} }
} }
} }
@ -273,7 +283,8 @@ public class MusicService extends MediaBrowserServiceCompat
new BroadcastReceiver() { new BroadcastReceiver() {
@Override @Override
public void onReceive(final Context context, final Intent intent) { public void onReceive(final Context context, final Intent intent) {
updateNotification(); playingNotification.updateFavorite(getCurrentSong(), MusicService.this::startForegroundOrNotify);
startForegroundOrNotify();
} }
}; };
private final BroadcastReceiver lockScreenReceiver = private final BroadcastReceiver lockScreenReceiver =
@ -356,6 +367,8 @@ public class MusicService extends MediaBrowserServiceCompat
private ThrottledSeekHandler throttledSeekHandler; private ThrottledSeekHandler throttledSeekHandler;
private Handler uiThreadHandler; private Handler uiThreadHandler;
private PowerManager.WakeLock wakeLock; private PowerManager.WakeLock wakeLock;
private NotificationManager notificationManager;
private boolean isForeground = false;
private static Bitmap copy(Bitmap bitmap) { private static Bitmap copy(Bitmap bitmap) {
Bitmap.Config config = bitmap.getConfig(); Bitmap.Config config = bitmap.getConfig();
@ -417,6 +430,10 @@ public class MusicService extends MediaBrowserServiceCompat
registerReceiver(updateFavoriteReceiver, new IntentFilter(FAVORITE_STATE_CHANGED)); registerReceiver(updateFavoriteReceiver, new IntentFilter(FAVORITE_STATE_CHANGED));
registerReceiver(lockScreenReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF)); registerReceiver(lockScreenReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
setSessionToken(mediaSession.getSessionToken());
if (VersionUtils.INSTANCE.hasMarshmallow()) {
notificationManager = getSystemService(NotificationManager.class);
}
initNotification(); initNotification();
mediaStoreObserver = new MediaStoreObserver(this, playerHandler); mediaStoreObserver = new MediaStoreObserver(this, playerHandler);
@ -467,7 +484,6 @@ public class MusicService extends MediaBrowserServiceCompat
mPackageValidator = new PackageValidator(this, R.xml.allowed_media_browser_callers); mPackageValidator = new PackageValidator(this, R.xml.allowed_media_browser_callers);
mMusicProvider.setMusicService(this); mMusicProvider.setMusicService(this);
setSessionToken(mediaSession.getSessionToken());
} }
@Override @Override
@ -765,11 +781,10 @@ public class MusicService extends MediaBrowserServiceCompat
public void initNotification() { public void initNotification() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N
&& !PreferenceUtil.INSTANCE.isClassicNotification()) { && !PreferenceUtil.INSTANCE.isClassicNotification()) {
playingNotification = new PlayingNotificationImpl(); playingNotification = PlayingNotificationImpl.Companion.from(this, notificationManager, mediaSession);
} else { } else {
playingNotification = new PlayingNotificationOreo(); playingNotification = PlayingNotificationOreo.Companion.from(this, notificationManager);
} }
playingNotification.init(this);
} }
public boolean isLastTrack() { public boolean isLastTrack() {
@ -837,7 +852,8 @@ public class MusicService extends MediaBrowserServiceCompat
// Request from an untrusted package: return an empty browser root // Request from an untrusted package: return an empty browser root
return new BrowserRoot(AutoMediaIDHelper.MEDIA_ID_EMPTY_ROOT, null); return new BrowserRoot(AutoMediaIDHelper.MEDIA_ID_EMPTY_ROOT, null);
} else { } else {
/** By default return the browsable root. Treat the EXTRA_RECENT flag as a special case /**
* By default return the browsable root. Treat the EXTRA_RECENT flag as a special case
* and return the recent root instead. * and return the recent root instead.
*/ */
boolean isRecentRequest = false; boolean isRecentRequest = false;
@ -882,7 +898,7 @@ public class MusicService extends MediaBrowserServiceCompat
/* Switch to MultiPlayer if Crossfade duration is 0 and /* Switch to MultiPlayer if Crossfade duration is 0 and
Playback is not an instance of MultiPlayer */ Playback is not an instance of MultiPlayer */
if (playback != null) if (playback != null)
playback.setCrossFadeDuration(PreferenceUtil.INSTANCE.getCrossFadeDuration()); playback.setCrossFadeDuration(PreferenceUtil.INSTANCE.getCrossFadeDuration());
if (!(playback instanceof MultiPlayer) && PreferenceUtil.INSTANCE.getCrossFadeDuration() == 0) { if (!(playback instanceof MultiPlayer) && PreferenceUtil.INSTANCE.getCrossFadeDuration() == 0) {
if (playback != null) { if (playback != null) {
playback.release(); playback.release();
@ -1042,6 +1058,7 @@ public class MusicService extends MediaBrowserServiceCompat
} }
public void pause() { public void pause() {
Log.i(TAG, "Paused");
pausedByTransientLossOfFocus = false; pausedByTransientLossOfFocus = false;
if (playback != null && playback.isPlaying()) { if (playback != null && playback.isPlaying()) {
startFadeAnimator(playback, false, () -> { startFadeAnimator(playback, false, () -> {
@ -1163,7 +1180,8 @@ public class MusicService extends MediaBrowserServiceCompat
public void quit() { public void quit() {
pause(); pause();
playingNotification.stop(); stopForeground(true);
notificationManager.cancel(PlayingNotification.NOTIFICATION_ID);
closeAudioEffectSession(); closeAudioEffectSession();
getAudioManager().abandonAudioFocus(audioFocusListener); getAudioManager().abandonAudioFocus(audioFocusListener);
@ -1326,7 +1344,8 @@ public class MusicService extends MediaBrowserServiceCompat
public void updateNotification() { public void updateNotification() {
if (playingNotification != null && getCurrentSong().getId() != -1) { if (playingNotification != null && getCurrentSong().getId() != -1) {
playingNotification.update(); stopForegroundAndNotification();
initNotification();
} }
} }
@ -1400,17 +1419,19 @@ public class MusicService extends MediaBrowserServiceCompat
private void handleChangeInternal(@NonNull final String what) { private void handleChangeInternal(@NonNull final String what) {
switch (what) { switch (what) {
case PLAY_STATE_CHANGED: case PLAY_STATE_CHANGED:
updateNotification();
updateMediaSessionPlaybackState(); updateMediaSessionPlaybackState();
final boolean isPlaying = isPlaying(); final boolean isPlaying = isPlaying();
if (!isPlaying && getSongProgressMillis() > 0) { if (!isPlaying && getSongProgressMillis() > 0) {
savePositionInTrack(); savePositionInTrack();
} }
songPlayCountHelper.notifyPlayStateChanged(isPlaying); songPlayCountHelper.notifyPlayStateChanged(isPlaying);
playingNotification.setPlaying(isPlaying);
startForegroundOrNotify();
break; break;
case FAVORITE_STATE_CHANGED: case FAVORITE_STATE_CHANGED:
playingNotification.updateFavorite(getCurrentSong(), this::startForegroundOrNotify);
case META_CHANGED: case META_CHANGED:
updateNotification(); playingNotification.updateMetadata(getCurrentSong(), this::startForegroundOrNotify);
updateMediaSessionMetaData(); updateMediaSessionMetaData();
updateMediaSessionPlaybackState(); updateMediaSessionPlaybackState();
savePosition(); savePosition();
@ -1428,12 +1449,41 @@ public class MusicService extends MediaBrowserServiceCompat
if (playingQueue.size() > 0) { if (playingQueue.size() > 0) {
prepareNext(); prepareNext();
} else { } else {
playingNotification.stop(); stopForegroundAndNotification();
} }
break; break;
} }
} }
private Unit startForegroundOrNotify() {
if (!isForeground) {
// Specify that this is a media service, if supported.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
startForeground(
PlayingNotification.NOTIFICATION_ID, playingNotification.build(),
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
);
} else {
startForeground(PlayingNotification.NOTIFICATION_ID, playingNotification.build());
}
isForeground = true;
} else {
// If we are already in foreground just update the notification
notificationManager.notify(
PlayingNotification.NOTIFICATION_ID, playingNotification.build()
);
}
return Unit.INSTANCE;
}
private void stopForegroundAndNotification() {
stopForeground(true);
notificationManager.cancel(PlayingNotification.NOTIFICATION_ID);
isForeground = false;
}
private boolean openCurrent() { private boolean openCurrent() {
synchronized (this) { synchronized (this) {
try { try {
@ -1551,6 +1601,7 @@ public class MusicService extends MediaBrowserServiceCompat
appWidgetSmall.notifyChange(this, what); appWidgetSmall.notifyChange(this, what);
appWidgetCard.notifyChange(this, what); appWidgetCard.notifyChange(this, what);
appWidgetText.notifyChange(this, what); appWidgetText.notifyChange(this, what);
appWidgetMd3.notifyChange(this, what);
} }
private void setCustomAction(PlaybackStateCompat.Builder stateBuilder) { private void setCustomAction(PlaybackStateCompat.Builder stateBuilder) {
@ -1592,8 +1643,8 @@ public class MusicService extends MediaBrowserServiceCompat
mediaButtonIntent.setComponent(mediaButtonReceiverComponentName); mediaButtonIntent.setComponent(mediaButtonReceiverComponentName);
PendingIntent mediaButtonReceiverPendingIntent; PendingIntent mediaButtonReceiverPendingIntent;
mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent,
VersionUtils.INSTANCE.hasMarshmallow() ? PendingIntent.FLAG_IMMUTABLE : 0); VersionUtils.INSTANCE.hasMarshmallow() ? PendingIntent.FLAG_IMMUTABLE : 0);
mediaSession = new MediaSessionCompat( mediaSession = new MediaSessionCompat(
this, this,

View File

@ -15,95 +15,51 @@
package code.name.monkey.retromusic.service.notification package code.name.monkey.retromusic.service.notification
import android.app.Notification
import android.app.NotificationChannel import android.app.NotificationChannel
import android.app.NotificationManager import android.app.NotificationManager
import android.content.Context.NOTIFICATION_SERVICE import android.content.Context
import android.content.pm.ServiceInfo
import android.os.Build
import androidx.annotation.RequiresApi import androidx.annotation.RequiresApi
import androidx.core.app.NotificationCompat
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.model.Song
abstract class PlayingNotification { abstract class PlayingNotification(context: Context) :
protected lateinit var service: MusicService NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID) {
protected var stopped: Boolean = false
private var notifyMode = NOTIFY_MODE_BACKGROUND
private var notificationManager: NotificationManager? = null
abstract fun updateMetadata(song: Song, onUpdate: () -> Unit)
@Synchronized abstract fun setPlaying(isPlaying: Boolean)
fun init(service: MusicService) {
this.service = service
notificationManager = service.getSystemService(NOTIFICATION_SERVICE) as NotificationManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel()
}
}
abstract fun update() abstract fun updateFavorite(song: Song, onUpdate: () -> Unit)
@Synchronized
fun stop() {
stopped = true
service.stopForeground(true)
notificationManager!!.cancel(NOTIFICATION_ID)
}
internal fun updateNotifyModeAndPostNotification(notification: Notification) {
val newNotifyMode: Int = if (service.isPlaying) {
NOTIFY_MODE_FOREGROUND
} else {
NOTIFY_MODE_BACKGROUND
}
if (notifyMode != newNotifyMode && newNotifyMode == NOTIFY_MODE_BACKGROUND) {
service.stopForeground(false)
}
if (newNotifyMode == NOTIFY_MODE_FOREGROUND) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
service.startForeground(
NOTIFICATION_ID,
notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
)
} else {
service.startForeground(NOTIFICATION_ID,notification)
}
} else if (newNotifyMode == NOTIFY_MODE_BACKGROUND) {
notificationManager!!.notify(NOTIFICATION_ID, notification)
}
notifyMode = newNotifyMode
}
@RequiresApi(26)
private fun createNotificationChannel() {
var notificationChannel: NotificationChannel? = notificationManager!!
.getNotificationChannel(NOTIFICATION_CHANNEL_ID)
if (notificationChannel == null) {
notificationChannel = NotificationChannel(
NOTIFICATION_CHANNEL_ID,
service.getString(R.string.playing_notification_name),
NotificationManager.IMPORTANCE_LOW
)
notificationChannel.description =
service.getString(R.string.playing_notification_description)
notificationChannel.enableLights(false)
notificationChannel.enableVibration(false)
notificationChannel.setShowBadge(false)
notificationManager!!.createNotificationChannel(notificationChannel)
}
}
companion object { companion object {
const val NOTIFICATION_CONTROLS_SIZE_MULTIPLIER = 1.0f const val NOTIFICATION_CONTROLS_SIZE_MULTIPLIER = 1.0f
internal const val NOTIFICATION_CHANNEL_ID = "playing_notification" internal const val NOTIFICATION_CHANNEL_ID = "playing_notification"
private const val NOTIFICATION_ID = 1 const val NOTIFICATION_ID = 1
private const val NOTIFY_MODE_FOREGROUND = 1
private const val NOTIFY_MODE_BACKGROUND = 0
@RequiresApi(26)
fun createNotificationChannel(
context: Context,
notificationManager: NotificationManager
) {
var notificationChannel: NotificationChannel? = notificationManager
.getNotificationChannel(NOTIFICATION_CHANNEL_ID)
if (notificationChannel == null) {
notificationChannel = NotificationChannel(
NOTIFICATION_CHANNEL_ID,
context.getString(R.string.playing_notification_name),
NotificationManager.IMPORTANCE_LOW
)
notificationChannel.description =
context.getString(R.string.playing_notification_description)
notificationChannel.enableLights(false)
notificationChannel.enableVibration(false)
notificationChannel.setShowBadge(false)
notificationManager.createNotificationChannel(notificationChannel)
}
}
} }
} }

View File

@ -14,14 +14,16 @@
package code.name.monkey.retromusic.service.notification package code.name.monkey.retromusic.service.notification
import android.annotation.SuppressLint
import android.app.NotificationManager
import android.app.PendingIntent import android.app.PendingIntent
import android.content.ComponentName import android.content.ComponentName
import android.content.Context
import android.content.Intent import android.content.Intent
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.Build import android.os.Build
import android.support.v4.media.session.MediaSessionCompat
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import androidx.core.text.HtmlCompat import androidx.core.text.HtmlCompat
import androidx.media.app.NotificationCompat.MediaStyle import androidx.media.app.NotificationCompat.MediaStyle
@ -33,177 +35,196 @@ import code.name.monkey.retromusic.db.toSongEntity
import code.name.monkey.retromusic.glide.GlideApp import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.* import code.name.monkey.retromusic.service.MusicService.*
import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroColorUtil import code.name.monkey.retromusic.util.RetroColorUtil
import com.bumptech.glide.Glide import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.target.Target
import com.bumptech.glide.request.transition.Transition import com.bumptech.glide.request.transition.Transition
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import org.koin.core.component.KoinComponent import kotlinx.coroutines.withContext
class PlayingNotificationImpl : PlayingNotification(), KoinComponent { @SuppressLint("RestrictedApi")
private var target: Target<BitmapPaletteWrapper>? = null class PlayingNotificationImpl(
val context: Context,
mediaSessionToken: MediaSessionCompat.Token
) : PlayingNotification(context) {
@Synchronized init {
override fun update() { val action = Intent(context, MainActivity::class.java)
stopped = false action.putExtra(MainActivity.EXPAND_PANEL, PreferenceUtil.isExpandPanel)
GlobalScope.launch { action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
val song = service.currentSong val clickIntent =
PendingIntent.getActivity(
context,
0,
action,
PendingIntent.FLAG_UPDATE_CURRENT or if (VersionUtils.hasMarshmallow())
PendingIntent.FLAG_IMMUTABLE
else 0
)
val serviceName = ComponentName(context, MusicService::class.java)
val intent = Intent(ACTION_QUIT)
intent.component = serviceName
val deleteIntent = PendingIntent.getService(
context,
0,
intent,
PendingIntent.FLAG_UPDATE_CURRENT or (if (VersionUtils.hasMarshmallow())
PendingIntent.FLAG_IMMUTABLE
else 0)
)
val toggleFavorite = buildFavoriteAction(false)
val playPauseAction = buildPlayAction(true)
val previousAction = NotificationCompat.Action(
R.drawable.ic_skip_previous_round_white_32dp,
context.getString(R.string.action_previous),
retrievePlaybackAction(ACTION_REWIND)
)
val nextAction = NotificationCompat.Action(
R.drawable.ic_skip_next_round_white_32dp,
context.getString(R.string.action_next),
retrievePlaybackAction(ACTION_SKIP)
)
val dismissAction = NotificationCompat.Action(
R.drawable.ic_close,
context.getString(R.string.customactivityoncrash_error_activity_error_details_close),
retrievePlaybackAction(ACTION_QUIT)
)
setSmallIcon(R.drawable.ic_notification)
setContentIntent(clickIntent)
setDeleteIntent(deleteIntent)
setShowWhen(false)
addAction(toggleFavorite)
addAction(previousAction)
addAction(playPauseAction)
addAction(nextAction)
addAction(dismissAction)
setStyle(
MediaStyle()
.setMediaSession(mediaSessionToken)
.setShowActionsInCompactView(1, 2, 3)
)
setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
if (Build.VERSION.SDK_INT <=
Build.VERSION_CODES.O && PreferenceUtil.isColoredNotification
) {
this.color = color
}
}
override fun updateMetadata(song: Song, onUpdate: () -> Unit) {
setContentTitle(song.title)
setContentText(
HtmlCompat.fromHtml(
"<b>" + song.albumName + "</b>",
HtmlCompat.FROM_HTML_MODE_LEGACY
)
)
val bigNotificationImageSize = context.resources
.getDimensionPixelSize(R.dimen.notification_big_image_size)
GlideApp.with(context).asBitmapPalette().songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song))
//.checkIgnoreMediaStore()
.centerCrop()
.into(object : CustomTarget<BitmapPaletteWrapper>(
bigNotificationImageSize,
bigNotificationImageSize
) {
override fun onResourceReady(
resource: BitmapPaletteWrapper,
transition: Transition<in BitmapPaletteWrapper>?
) {
setLargeIcon(
resource.bitmap
)
if (Build.VERSION.SDK_INT <=
Build.VERSION_CODES.O && PreferenceUtil.isColoredNotification
) {
color = RetroColorUtil.getColor(resource.palette, Color.TRANSPARENT)
}
onUpdate()
}
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
setLargeIcon(null)
onUpdate()
}
override fun onLoadCleared(placeholder: Drawable?) {
setLargeIcon(null)
onUpdate()
}
})
}
private fun buildPlayAction(isPlaying: Boolean): NotificationCompat.Action {
val playButtonResId =
if (isPlaying) R.drawable.ic_pause_white_48dp else R.drawable.ic_play_arrow_white_48dp
return NotificationCompat.Action.Builder(
playButtonResId,
context.getString(R.string.action_play_pause),
retrievePlaybackAction(ACTION_TOGGLE_PAUSE)
).build()
}
private fun buildFavoriteAction(isFavorite: Boolean): NotificationCompat.Action {
val favoriteResId =
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
return NotificationCompat.Action.Builder(
favoriteResId,
context.getString(R.string.action_toggle_favorite),
retrievePlaybackAction(TOGGLE_FAVORITE)
).build()
}
override fun setPlaying(isPlaying: Boolean) {
mActions[2] = buildPlayAction(isPlaying)
}
override fun updateFavorite(song: Song, onUpdate: () -> Unit) {
GlobalScope.launch(Dispatchers.IO) {
val playlist: PlaylistEntity = MusicUtil.repository.favoritePlaylist() val playlist: PlaylistEntity = MusicUtil.repository.favoritePlaylist()
val isPlaying = service.isPlaying
val isFavorite = if (playlist != null) { val isFavorite = if (playlist != null) {
val songEntity = song.toSongEntity(playlist.playListId) val songEntity = song.toSongEntity(playlist.playListId)
MusicUtil.repository.isFavoriteSong(songEntity).isNotEmpty() MusicUtil.repository.isFavoriteSong(songEntity).isNotEmpty()
} else false } else false
withContext(Dispatchers.Main) {
val playButtonResId = mActions[0] = buildFavoriteAction(isFavorite)
if (isPlaying) R.drawable.ic_pause_white_48dp else R.drawable.ic_play_arrow_white_48dp onUpdate()
val favoriteResId =
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
val action = Intent(service, MainActivity::class.java)
action.putExtra(MainActivity.EXPAND_PANEL, PreferenceUtil.isExpandPanel)
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
val clickIntent =
PendingIntent.getActivity(
service, 0, action, if (VersionUtils.hasMarshmallow())
PendingIntent.FLAG_IMMUTABLE
else 0 or PendingIntent.FLAG_UPDATE_CURRENT
)
val serviceName = ComponentName(service, MusicService::class.java)
val intent = Intent(ACTION_QUIT)
intent.component = serviceName
val deleteIntent = PendingIntent.getService(
service,
0,
intent,
if (VersionUtils.hasMarshmallow())
PendingIntent.FLAG_IMMUTABLE
else 0 or PendingIntent.FLAG_UPDATE_CURRENT
)
val bigNotificationImageSize = service.resources
.getDimensionPixelSize(R.dimen.notification_big_image_size)
service.runOnUiThread {
if (target != null) {
Glide.with(service).clear(target)
}
target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song))
//.checkIgnoreMediaStore()
.centerCrop()
.into(object : SimpleTarget<BitmapPaletteWrapper>(
bigNotificationImageSize,
bigNotificationImageSize
) {
override fun onResourceReady(
resource: BitmapPaletteWrapper,
transition: Transition<in BitmapPaletteWrapper>?
) {
update(
resource.bitmap,
RetroColorUtil.getColor(resource.palette, Color.TRANSPARENT)
)
}
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
update(null, Color.TRANSPARENT)
}
fun update(bitmap: Bitmap?, color: Int) {
var bitmapFinal = bitmap
if (bitmapFinal == null) {
bitmapFinal = BitmapFactory.decodeResource(
service.resources,
R.drawable.default_audio_art
)
}
val toggleFavorite = NotificationCompat.Action(
favoriteResId,
service.getString(R.string.action_toggle_favorite),
retrievePlaybackAction(TOGGLE_FAVORITE)
)
val playPauseAction = NotificationCompat.Action(
playButtonResId,
service.getString(R.string.action_play_pause),
retrievePlaybackAction(ACTION_TOGGLE_PAUSE)
)
val previousAction = NotificationCompat.Action(
R.drawable.ic_skip_previous_round_white_32dp,
service.getString(R.string.action_previous),
retrievePlaybackAction(ACTION_REWIND)
)
val nextAction = NotificationCompat.Action(
R.drawable.ic_skip_next_round_white_32dp,
service.getString(R.string.action_next),
retrievePlaybackAction(ACTION_SKIP)
)
val builder = NotificationCompat.Builder(
service,
NOTIFICATION_CHANNEL_ID
)
.setSmallIcon(R.drawable.ic_notification)
.setLargeIcon(bitmapFinal)
.setContentIntent(clickIntent)
.setDeleteIntent(deleteIntent)
.setContentTitle(
HtmlCompat.fromHtml(
"<b>" + song.title + "</b>",
HtmlCompat.FROM_HTML_MODE_LEGACY
)
)
.setContentText(song.artistName)
.setSubText(
HtmlCompat.fromHtml(
"<b>" + song.albumName + "</b>",
HtmlCompat.FROM_HTML_MODE_LEGACY
)
)
.setOngoing(isPlaying)
.setShowWhen(false)
.addAction(toggleFavorite)
.addAction(previousAction)
.addAction(playPauseAction)
.addAction(nextAction)
builder.setStyle(
MediaStyle()
.setMediaSession(service.mediaSession.sessionToken)
.setShowActionsInCompactView(1, 2, 3)
)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
if (Build.VERSION.SDK_INT <=
Build.VERSION_CODES.O && PreferenceUtil.isColoredNotification
) {
builder.color = color
}
if (stopped) {
return // notification has been stopped before loading was finished
}
updateNotifyModeAndPostNotification(builder.build())
}
})
} }
} }
} }
private fun retrievePlaybackAction(action: String): PendingIntent { private fun retrievePlaybackAction(action: String): PendingIntent {
val serviceName = ComponentName(service, MusicService::class.java) val serviceName = ComponentName(context, MusicService::class.java)
val intent = Intent(action) val intent = Intent(action)
intent.component = serviceName intent.component = serviceName
return PendingIntent.getService( return PendingIntent.getService(
service, 0, intent, context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT or
if (VersionUtils.hasMarshmallow()) PendingIntent.FLAG_IMMUTABLE if (VersionUtils.hasMarshmallow()) PendingIntent.FLAG_IMMUTABLE
else 0 or PendingIntent.FLAG_UPDATE_CURRENT else 0
) )
} }
companion object {
fun from(
context: Context,
notificationManager: NotificationManager,
mediaSession: MediaSessionCompat
): PlayingNotification {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel(context, notificationManager)
}
return PlayingNotificationImpl(context, mediaSession.sessionToken)
}
}
} }

View File

@ -14,6 +14,8 @@
package code.name.monkey.retromusic.service.notification package code.name.monkey.retromusic.service.notification
import android.annotation.SuppressLint
import android.app.NotificationManager
import android.app.PendingIntent import android.app.PendingIntent
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
@ -21,6 +23,7 @@ import android.content.Intent
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Color import android.graphics.Color
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.os.Build
import android.widget.RemoteViews import android.widget.RemoteViews
import androidx.core.app.NotificationCompat import androidx.core.app.NotificationCompat
import code.name.monkey.appthemehelper.util.ATHUtil.resolveColor import code.name.monkey.appthemehelper.util.ATHUtil.resolveColor
@ -29,6 +32,7 @@ import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.MainActivity import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.glide.GlideApp import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
@ -39,224 +43,231 @@ import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.RetroUtil.createBitmap import code.name.monkey.retromusic.util.RetroUtil.createBitmap
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.bumptech.glide.Glide import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.target.Target
import com.bumptech.glide.request.transition.Transition import com.bumptech.glide.request.transition.Transition
/** /**
* @author Hemanth S (h4h13). * @author Hemanth S (h4h13).
*/ */
class PlayingNotificationOreo : PlayingNotification() { @SuppressLint("RestrictedApi")
class PlayingNotificationOreo(
val context: Context
) : PlayingNotification(context) {
private var target: Target<BitmapPaletteWrapper>? = null private var primaryColor: Int = 0
private fun getCombinedRemoteViews(collapsed: Boolean, song: Song): RemoteViews { init {
val remoteViews = RemoteViews( val notificationLayout = getCombinedRemoteViews(true)
service.packageName, val notificationLayoutBig = getCombinedRemoteViews(false)
if (collapsed) R.layout.layout_notification_collapsed else R.layout.layout_notification_expanded
)
remoteViews.setTextViewText(
R.id.appName,
service.getString(R.string.app_name) + "" + song.albumName
)
remoteViews.setTextViewText(R.id.title, song.title)
remoteViews.setTextViewText(R.id.subtitle, song.artistName)
linkButtons(remoteViews)
return remoteViews
}
override fun update() { val action = Intent(context, MainActivity::class.java)
stopped = false
val song = service.currentSong
val isPlaying = service.isPlaying
val notificationLayout = getCombinedRemoteViews(true, song)
val notificationLayoutBig = getCombinedRemoteViews(false, song)
val action = Intent(service, MainActivity::class.java)
action.putExtra(MainActivity.EXPAND_PANEL, PreferenceUtil.isExpandPanel) action.putExtra(MainActivity.EXPAND_PANEL, PreferenceUtil.isExpandPanel)
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
val clickIntent = PendingIntent val clickIntent = PendingIntent
.getActivity( .getActivity(
service, context,
0, 0,
action, action,
PendingIntent.FLAG_UPDATE_CURRENT or if (VersionUtils.hasMarshmallow()) PendingIntent.FLAG_UPDATE_CURRENT or if (VersionUtils.hasMarshmallow())
PendingIntent.FLAG_IMMUTABLE PendingIntent.FLAG_IMMUTABLE
else 0 else 0
) )
val deleteIntent = buildPendingIntent(service, ACTION_QUIT, null) val deleteIntent = buildPendingIntent(context, ACTION_QUIT, null)
val builder = NotificationCompat.Builder(service, NOTIFICATION_CHANNEL_ID) setSmallIcon(R.drawable.ic_notification)
.setSmallIcon(R.drawable.ic_notification) setContentIntent(clickIntent)
.setContentIntent(clickIntent) setDeleteIntent(deleteIntent)
.setDeleteIntent(deleteIntent) setCategory(NotificationCompat.CATEGORY_SERVICE)
.setCategory(NotificationCompat.CATEGORY_SERVICE) priority = NotificationCompat.PRIORITY_MAX
.setPriority(NotificationCompat.PRIORITY_MAX) setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC) setCustomContentView(notificationLayout)
.setCustomContentView(notificationLayout) setCustomBigContentView(notificationLayoutBig)
.setCustomBigContentView(notificationLayoutBig) setOngoing(true)
.setOngoing(isPlaying)
val bigNotificationImageSize = service.resources
.getDimensionPixelSize(R.dimen.notification_big_image_size)
service.runOnUiThread {
if (target != null) {
Glide.with(service).clear(target)
}
target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song))
.centerCrop()
.into(object : SimpleTarget<BitmapPaletteWrapper>(
bigNotificationImageSize,
bigNotificationImageSize
) {
override fun onResourceReady(
resource: BitmapPaletteWrapper,
transition: Transition<in BitmapPaletteWrapper>?
) {
/* val mediaNotificationProcessor = MediaNotificationProcessor(
service,
service
) { i, _ -> update(resource.bitmap, i) }
mediaNotificationProcessor.processNotification(resource.bitmap)*/
val colors = MediaNotificationProcessor(service, resource.bitmap)
update(resource.bitmap, colors.backgroundColor)
}
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
update(
null,
resolveColor(service, R.attr.colorSurface, Color.WHITE)
)
}
private fun update(bitmap: Bitmap?, bgColor: Int) {
var bgColorFinal = bgColor
if (bitmap != null) {
notificationLayout.setImageViewBitmap(R.id.largeIcon, bitmap)
notificationLayoutBig.setImageViewBitmap(R.id.largeIcon, bitmap)
} else {
notificationLayout.setImageViewResource(
R.id.largeIcon,
R.drawable.default_audio_art
)
notificationLayoutBig.setImageViewResource(
R.id.largeIcon,
R.drawable.default_audio_art
)
}
// Android 12 applies a standard Notification template to every notification
// which will in turn have a default background so setting a different background
// than that, looks weird
if (!VersionUtils.hasS()) {
if (!PreferenceUtil.isColoredNotification) {
bgColorFinal =
resolveColor(service, R.attr.colorPrimary, Color.WHITE)
}
setBackgroundColor(bgColorFinal)
}
setNotificationContent(ColorUtil.isColorLight(bgColorFinal))
if (stopped) {
return // notification has been stopped before loading was finished
}
updateNotifyModeAndPostNotification(builder.build())
}
private fun setBackgroundColor(color: Int) {
notificationLayout.setInt(R.id.image, "setBackgroundColor", color)
notificationLayoutBig.setInt(R.id.image, "setBackgroundColor", color)
}
private fun setNotificationContent(dark: Boolean) {
val primary = MaterialValueHelper.getPrimaryTextColor(service, dark)
val secondary = MaterialValueHelper.getSecondaryTextColor(service, dark)
val close = createBitmap(
RetroUtil.getTintedVectorDrawable(
service,
R.drawable.ic_close,
primary
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
)
val prev = createBitmap(
RetroUtil.getTintedVectorDrawable(
service,
R.drawable.ic_skip_previous_round_white_32dp,
primary
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
)
val next = createBitmap(
RetroUtil.getTintedVectorDrawable(
service,
R.drawable.ic_skip_next_round_white_32dp,
primary
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
)
val playPause = createBitmap(
RetroUtil.getTintedVectorDrawable(
service,
if (isPlaying)
R.drawable.ic_pause_white_48dp
else
R.drawable.ic_play_arrow_white_48dp, primary
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
)
notificationLayout.setTextColor(R.id.title, primary)
notificationLayout.setTextColor(R.id.subtitle, secondary)
notificationLayout.setTextColor(R.id.appName, secondary)
notificationLayout.setImageViewBitmap(R.id.action_prev, prev)
notificationLayout.setImageViewBitmap(R.id.action_next, next)
notificationLayout.setImageViewBitmap(R.id.action_play_pause, playPause)
notificationLayoutBig.setTextColor(R.id.title, primary)
notificationLayoutBig.setTextColor(R.id.subtitle, secondary)
notificationLayoutBig.setTextColor(R.id.appName, secondary)
notificationLayoutBig.setImageViewBitmap(R.id.action_quit, close)
notificationLayoutBig.setImageViewBitmap(R.id.action_prev, prev)
notificationLayoutBig.setImageViewBitmap(R.id.action_next, next)
notificationLayoutBig.setImageViewBitmap(R.id.action_play_pause, playPause)
notificationLayout.setImageViewBitmap(
R.id.smallIcon,
createBitmap(
RetroUtil.getTintedVectorDrawable(
service,
R.drawable.ic_notification,
secondary
), 0.6f
)
)
notificationLayoutBig.setImageViewBitmap(
R.id.smallIcon,
createBitmap(
RetroUtil.getTintedVectorDrawable(
service,
R.drawable.ic_notification,
secondary
), 0.6f
)
)
}
})
}
if (stopped) {
return // notification has been stopped before loading was finished
}
updateNotifyModeAndPostNotification(builder.build())
} }
private fun getCombinedRemoteViews(collapsed: Boolean): RemoteViews {
val remoteViews = RemoteViews(
context.packageName,
if (collapsed) R.layout.layout_notification_collapsed else R.layout.layout_notification_expanded
)
linkButtons(remoteViews)
return remoteViews
}
@SuppressLint("RestrictedApi")
override fun updateMetadata(song: Song, onUpdate: () -> Unit) {
val bigNotificationImageSize = context.resources
.getDimensionPixelSize(R.dimen.notification_big_image_size)
GlideApp.with(context).asBitmapPalette().songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song))
.centerCrop()
.into(object : CustomTarget<BitmapPaletteWrapper>(
bigNotificationImageSize,
bigNotificationImageSize
) {
override fun onResourceReady(
resource: BitmapPaletteWrapper,
transition: Transition<in BitmapPaletteWrapper>?
) {
val colors = MediaNotificationProcessor(context, resource.bitmap)
update(resource.bitmap, colors.backgroundColor)
}
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
update(
null,
resolveColor(context, R.attr.colorSurface, Color.WHITE)
)
}
override fun onLoadCleared(placeholder: Drawable?) {
}
private fun update(bitmap: Bitmap?, bgColor: Int) {
var bgColorFinal = bgColor
if (bitmap != null) {
contentView.setImageViewBitmap(R.id.largeIcon, bitmap)
bigContentView.setImageViewBitmap(R.id.largeIcon, bitmap)
} else {
contentView.setImageViewResource(
R.id.largeIcon,
R.drawable.default_audio_art
)
bigContentView.setImageViewResource(
R.id.largeIcon,
R.drawable.default_audio_art
)
}
// Android 12 applies a standard Notification template to every notification
// which will in turn have a default background so setting a different background
// than that, looks weird
if (!VersionUtils.hasS()) {
if (!PreferenceUtil.isColoredNotification) {
bgColorFinal =
resolveColor(context, R.attr.colorSurface, Color.WHITE)
}
setBackgroundColor(bgColorFinal)
setNotificationContent(ColorUtil.isColorLight(bgColorFinal))
}else {
setNotificationContent(!ColorUtil.isColorLight(context.surfaceColor()))
}
onUpdate()
}
private fun setBackgroundColor(color: Int) {
contentView.setInt(R.id.image, "setBackgroundColor", color)
bigContentView.setInt(R.id.image, "setBackgroundColor", color)
}
private fun setNotificationContent(dark: Boolean) {
val primary = MaterialValueHelper.getPrimaryTextColor(context, dark)
val secondary = MaterialValueHelper.getSecondaryTextColor(context, dark)
primaryColor = primary
val close = createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
R.drawable.ic_close,
primary
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
)
val prev = createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
R.drawable.ic_skip_previous_round_white_32dp,
primary
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
)
val next = createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
R.drawable.ic_skip_next_round_white_32dp,
primary
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
)
val playPause = getPlayPauseBitmap(true)
contentView.setTextColor(R.id.title, primary)
contentView.setTextColor(R.id.subtitle, secondary)
contentView.setTextColor(R.id.appName, secondary)
contentView.setImageViewBitmap(R.id.action_prev, prev)
contentView.setImageViewBitmap(R.id.action_next, next)
contentView.setImageViewBitmap(R.id.action_play_pause, playPause)
contentView.setTextViewText(
R.id.appName,
context.getString(R.string.app_name) + "" + song.albumName
)
contentView.setTextViewText(R.id.title, song.title)
contentView.setTextViewText(R.id.subtitle, song.artistName)
bigContentView.setTextColor(R.id.title, primary)
bigContentView.setTextColor(R.id.subtitle, secondary)
bigContentView.setTextColor(R.id.appName, secondary)
bigContentView.setImageViewBitmap(R.id.action_quit, close)
bigContentView.setImageViewBitmap(R.id.action_prev, prev)
bigContentView.setImageViewBitmap(R.id.action_next, next)
bigContentView.setImageViewBitmap(R.id.action_play_pause, playPause)
bigContentView.setTextViewText(
R.id.appName,
context.getString(R.string.app_name) + "" + song.albumName
)
bigContentView.setTextViewText(R.id.title, song.title)
bigContentView.setTextViewText(R.id.subtitle, song.artistName)
contentView.setImageViewBitmap(
R.id.smallIcon,
createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
R.drawable.ic_notification,
secondary
), 0.6f
)
)
bigContentView.setImageViewBitmap(
R.id.smallIcon,
createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
R.drawable.ic_notification,
secondary
), 0.6f
)
)
}
})
}
private fun getPlayPauseBitmap(isPlaying: Boolean): Bitmap {
return createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
if (isPlaying)
R.drawable.ic_pause_white_48dp
else
R.drawable.ic_play_arrow_white_48dp, primaryColor
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER)
}
override fun setPlaying(isPlaying: Boolean) {
getPlayPauseBitmap(isPlaying).also {
contentView.setImageViewBitmap(R.id.action_play_pause, it)
bigContentView.setImageViewBitmap(R.id.action_play_pause, it)
}
}
override fun updateFavorite(song: Song, onUpdate: () -> Unit) {
}
private fun buildPendingIntent( private fun buildPendingIntent(
context: Context, action: String, context: Context, action: String,
@ -275,23 +286,34 @@ class PlayingNotificationOreo : PlayingNotification() {
private fun linkButtons(notificationLayout: RemoteViews) { private fun linkButtons(notificationLayout: RemoteViews) {
var pendingIntent: PendingIntent var pendingIntent: PendingIntent
val serviceName = ComponentName(service, MusicService::class.java) val serviceName = ComponentName(context, MusicService::class.java)
// Previous track // Previous track
pendingIntent = buildPendingIntent(service, ACTION_REWIND, serviceName) pendingIntent = buildPendingIntent(context, ACTION_REWIND, serviceName)
notificationLayout.setOnClickPendingIntent(R.id.action_prev, pendingIntent) notificationLayout.setOnClickPendingIntent(R.id.action_prev, pendingIntent)
// Play and pause // Play and pause
pendingIntent = buildPendingIntent(service, ACTION_TOGGLE_PAUSE, serviceName) pendingIntent = buildPendingIntent(context, ACTION_TOGGLE_PAUSE, serviceName)
notificationLayout.setOnClickPendingIntent(R.id.action_play_pause, pendingIntent) notificationLayout.setOnClickPendingIntent(R.id.action_play_pause, pendingIntent)
// Next track // Next track
pendingIntent = buildPendingIntent(service, ACTION_SKIP, serviceName) pendingIntent = buildPendingIntent(context, ACTION_SKIP, serviceName)
notificationLayout.setOnClickPendingIntent(R.id.action_next, pendingIntent) notificationLayout.setOnClickPendingIntent(R.id.action_next, pendingIntent)
// Close // Close
pendingIntent = buildPendingIntent(service, ACTION_QUIT, serviceName) pendingIntent = buildPendingIntent(context, ACTION_QUIT, serviceName)
notificationLayout.setOnClickPendingIntent(R.id.action_quit, pendingIntent) notificationLayout.setOnClickPendingIntent(R.id.action_quit, pendingIntent)
} }
companion object {
fun from(
context: Context,
notificationManager: NotificationManager
): PlayingNotification {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel(context, notificationManager)
}
return PlayingNotificationOreo(context)
}
}
} }

View File

@ -241,7 +241,7 @@ object MusicUtil : KoinComponent {
var musicMediaTitle = mediaTitle var musicMediaTitle = mediaTitle
return try { return try {
if (TextUtils.isEmpty(musicMediaTitle)) { if (TextUtils.isEmpty(musicMediaTitle)) {
return "" return "-"
} }
musicMediaTitle = musicMediaTitle!!.trim { it <= ' ' }.lowercase() musicMediaTitle = musicMediaTitle!!.trim { it <= ' ' }.lowercase()
if (musicMediaTitle.startsWith("the ")) { if (musicMediaTitle.startsWith("the ")) {
@ -526,6 +526,7 @@ object MusicUtil : KoinComponent {
@RequiresApi(Build.VERSION_CODES.R) @RequiresApi(Build.VERSION_CODES.R)
fun deleteTracksR(activity: Activity, songs: List<Song>) { fun deleteTracksR(activity: Activity, songs: List<Song>) {
removeFromQueue(songs)
val pendingIntent = MediaStore.createDeleteRequest(activity.contentResolver, songs.map { val pendingIntent = MediaStore.createDeleteRequest(activity.contentResolver, songs.map {
getSongFileUri(it.id) getSongFileUri(it.id)
}) })

View File

@ -372,7 +372,7 @@ object PreferenceUtil {
var artistGridStyle: GridStyle var artistGridStyle: GridStyle
get() { get() {
val id: Int = sharedPreferences.getInt(ARTIST_GRID_STYLE, 4) val id: Int = sharedPreferences.getInt(ARTIST_GRID_STYLE, 3)
return GridStyle.values().firstOrNull { gridStyle -> return GridStyle.values().firstOrNull { gridStyle ->
gridStyle.id == id gridStyle.id == id
} ?: GridStyle.Circular } ?: GridStyle.Circular

View File

@ -473,4 +473,12 @@ public class MediaNotificationProcessor {
public interface OnPaletteLoadedListener { public interface OnPaletteLoadedListener {
void onPaletteLoaded(MediaNotificationProcessor mediaNotificationProcessor); void onPaletteLoaded(MediaNotificationProcessor mediaNotificationProcessor);
} }
public static MediaNotificationProcessor errorColor(Context context) {
MediaNotificationProcessor errorColors = new MediaNotificationProcessor(context);
errorColors.backgroundColor = 0x15724528;
errorColors.primaryTextColor = 0x6974059;
errorColors.secondaryTextColor = 0x8684677;
return errorColors;
}
} }

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?><!--
Background for widgets to make the rounded corners based on the
appWidgetRadius attribute value
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<corners android:radius="16dp" />
<solid android:color="?android:attr/colorBackground" />
</shape>

View File

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="@dimen/app_widget_md3_height"
android:background="@drawable/app_widget_background"
android:backgroundTint="?android:attr/colorBackground"
android:orientation="horizontal"
tools:ignore="ContentDescription">
<ImageView
android:id="@+id/image"
android:layout_width="@dimen/app_widget_md3_image_size"
android:layout_height="@dimen/app_widget_md3_image_size"
android:background="@drawable/app_widget_background"
android:layout_margin="8dp"
android:layout_gravity="center_vertical"
android:scaleType="centerCrop" />
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="@+id/media_actions"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_gravity="bottom"
android:layoutDirection="ltr"
android:orientation="horizontal"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:paddingBottom="8dp">
<ImageButton
android:id="@+id/button_prev"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/widget_selector"
tools:src="@drawable/ic_skip_previous"
tools:tint="@color/ate_secondary_text_dark" />
<ImageButton
android:id="@+id/button_toggle_play_pause"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/widget_selector"
tools:src="@drawable/ic_play_arrow_white_32dp"
tools:tint="@color/ate_secondary_text_dark" />
<ImageButton
android:id="@+id/button_next"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="@drawable/widget_selector"
tools:src="@drawable/ic_skip_next"
tools:tint="@color/ate_secondary_text_dark" />
</LinearLayout>
<LinearLayout
android:id="@+id/media_titles"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/media_actions"
android:layout_alignParentTop="true"
android:orientation="vertical"
android:paddingStart="8dp"
android:paddingTop="4dp"
android:paddingEnd="8dp">
<TextView
android:id="@+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:singleLine="true"
android:textAppearance="@style/TextViewSubtitle1"
android:textColor="?android:attr/textColorPrimary"
tools:text="Title" />
<TextView
android:id="@+id/text"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingTop="4dp"
android:singleLine="true"
android:textAppearance="@style/TextViewNormal"
android:textColor="?android:attr/textColorSecondary"
tools:text="Text" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>

View File

@ -5,5 +5,5 @@
android:id="@+id/action_search" android:id="@+id/action_search"
android:icon="@drawable/ic_search" android:icon="@drawable/ic_search"
android:title="@string/action_search" android:title="@string/action_search"
app:showAsAction="ifRoom" /> app:showAsAction="always" />
</menu> </menu>

View File

@ -39,6 +39,9 @@
<dimen name="app_widget_card_radius">2dp</dimen> <dimen name="app_widget_card_radius">2dp</dimen>
<dimen name="now_playing_top_margin">12dp</dimen> <dimen name="now_playing_top_margin">12dp</dimen>
<dimen name="app_widget_md3_height">96dp</dimen>
<dimen name="app_widget_md3_image_size">80dp</dimen>
<dimen name="icon_notification_dimen">32dp</dimen> <dimen name="icon_notification_dimen">32dp</dimen>
<dimen name="toolbar_margin_horizontal">8dp</dimen> <dimen name="toolbar_margin_horizontal">8dp</dimen>
<dimen name="toolbar_height">48dp</dimen> <dimen name="toolbar_height">48dp</dimen>

View File

@ -454,6 +454,7 @@
<string name="sort_order_a_z">Ascending</string> <string name="sort_order_a_z">Ascending</string>
<string name="sort_order_album">Album</string> <string name="sort_order_album">Album</string>
<string name="sort_order_artist">Artist</string> <string name="sort_order_artist">Artist</string>
<string name="sort_order_album_artist">@string/album_artist</string>
<string name="sort_order_composer">Composer</string> <string name="sort_order_composer">Composer</string>
<string name="sort_order_date">Date added</string> <string name="sort_order_date">Date added</string>
<string name="sort_order_date_modified">Date modified</string> <string name="sort_order_date_modified">Date modified</string>
@ -517,4 +518,5 @@
<string name="restore_message">Do you want to restore backup?</string> <string name="restore_message">Do you want to restore backup?</string>
<string name="title_new_backup">New Backup</string> <string name="title_new_backup">New Backup</string>
<string name="backup_restore_settings_summary">Backup and restore your settings, playlists</string> <string name="backup_restore_settings_summary">Backup and restore your settings, playlists</string>
<string name="app_widget_md3_name">MD3</string>
</resources> </resources>

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<appwidget-provider xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:initialLayout="@layout/app_widget_classic"
android:minWidth="@dimen/app_widget_classic_min_width"
android:minHeight="@dimen/app_widget_classic_min_height"
android:previewImage="@drawable/widget_classic"
android:resizeMode="horizontal|vertical"
android:updatePeriodMillis="0"
android:widgetCategory="keyguard|home_screen"
tools:ignore="UnusedAttribute" />

View File

@ -25,7 +25,7 @@ dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs') implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'androidx.appcompat:appcompat:1.4.0' implementation 'androidx.appcompat:appcompat:1.4.0'
implementation 'com.google.android.material:material:1.5.0-beta01' implementation 'com.google.android.material:material:1.5.0-beta01'
implementation 'androidx.preference:preference-ktx:1.1.1' implementation 'androidx.preference:preference-ktx:1.2.0-beta01'
implementation 'androidx.cardview:cardview:1.0.0' implementation 'androidx.cardview:cardview:1.0.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version" implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"

View File

@ -1,9 +1,9 @@
package code.name.monkey.appthemehelper package code.name.monkey.appthemehelper
import android.annotation.SuppressLint
import android.app.Activity import android.app.Activity
import android.app.ActivityManager import android.app.ActivityManager
import android.content.Context import android.content.Context
import android.graphics.Color
import android.os.Build import android.os.Build
import android.view.View import android.view.View
import androidx.annotation.ColorInt import androidx.annotation.ColorInt
@ -18,7 +18,6 @@ import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
*/ */
object ATH { object ATH {
@SuppressLint("CommitPrefEdits")
fun didThemeValuesChange(context: Context, since: Long): Boolean { fun didThemeValuesChange(context: Context, since: Long): Boolean {
return ThemeStore.isConfigured(context) && ThemeStore.prefs(context).getLong( return ThemeStore.isConfigured(context) && ThemeStore.prefs(context).getLong(
ThemeStorePrefKeys.VALUES_CHANGED, ThemeStorePrefKeys.VALUES_CHANGED,
@ -26,7 +25,7 @@ object ATH {
) > since ) > since
} }
fun setLightStatusbar(activity: Activity, enabled: Boolean) { fun setLightStatusBar(activity: Activity, enabled: Boolean) {
activity.window.apply { activity.window.apply {
WindowInsetsControllerCompat( WindowInsetsControllerCompat(
this, this,
@ -36,29 +35,26 @@ object ATH {
} }
fun setLightNavigationbar(activity: Activity, enabled: Boolean) { fun setLightNavigationbar(activity: Activity, enabled: Boolean) {
activity.window?.apply { activity.window.apply {
WindowInsetsControllerCompat( WindowInsetsControllerCompat(
this, this,
decorView decorView
).isAppearanceLightNavigationBars = enabled ).isAppearanceLightNavigationBars = enabled
navigationBarColor = Color.TRANSPARENT
} }
} }
fun setLightNavigationbarAuto(activity: Activity, bgColor: Int) { fun setLightNavigationBarAuto(activity: Activity, bgColor: Int) {
setLightNavigationbar(activity, ColorUtil.isColorLight(bgColor)) setLightNavigationbar(activity, ColorUtil.isColorLight(bgColor))
} }
fun setNavigationbarColorAuto(activity: Activity) { fun setNavigationBarColor(activity: Activity, color: Int) {
setNavigationbarColor(activity, ThemeStore.navigationBarColor(activity))
}
fun setNavigationbarColor(activity: Activity, color: Int) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
activity.window.navigationBarColor = color activity.window.navigationBarColor = color
} else { } else {
activity.window.navigationBarColor = ColorUtil.darkenColor(color) activity.window.navigationBarColor = ColorUtil.darkenColor(color)
} }
setLightNavigationbarAuto(activity, color) setLightNavigationBarAuto(activity, color)
} }
fun setActivityToolbarColorAuto(activity: Activity, toolbar: Toolbar?) { fun setActivityToolbarColorAuto(activity: Activity, toolbar: Toolbar?) {

View File

@ -43,9 +43,9 @@ class ATEColorPreference @JvmOverloads constructor(
invalidateColor() invalidateColor()
}*/ }*/
override fun onBindViewHolder(holder: PreferenceViewHolder?) { override fun onBindViewHolder(holder: PreferenceViewHolder) {
super.onBindViewHolder(holder) super.onBindViewHolder(holder)
mView = holder?.itemView mView = holder.itemView
invalidateColor() invalidateColor()
} }

View File

@ -22,7 +22,7 @@ import androidx.preference.PreferenceViewHolder
import code.name.monkey.appthemehelper.ThemeStore import code.name.monkey.appthemehelper.ThemeStore
class ATEPreferenceCategory @JvmOverloads constructor( class ATEPreferenceCategory @JvmOverloads constructor(
context: Context?, context: Context,
attrs: AttributeSet?, attrs: AttributeSet?,
defStyleAttr: Int = -1, defStyleAttr: Int = -1,
defStyleRes: Int = -1 defStyleRes: Int = -1

View File

@ -9,9 +9,9 @@ buildscript {
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:7.0.3' classpath 'com.android.tools.build:gradle:7.0.3'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
def nav_version = "2.3.5" def nav_version = "2.4.0-beta02"
classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version" classpath "androidx.navigation:navigation-safe-args-gradle-plugin:$nav_version"
classpath "com.diffplug.spotless:spotless-plugin-gradle:5.16.0" classpath "com.diffplug.spotless:spotless-plugin-gradle:6.0.1"
} }
} }