Merge branch 'RetroMusicPlayer:dev' into feat/audio_focus_2

This commit is contained in:
Doozy 2022-05-06 21:28:11 +03:00 committed by GitHub
commit 51f772247a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
305 changed files with 2587 additions and 5938 deletions

View file

@ -5,17 +5,17 @@ apply plugin: "androidx.navigation.safeargs.kotlin"
apply plugin: 'kotlin-parcelize'
android {
compileSdk 31
compileSdk 32
defaultConfig {
minSdk 21
targetSdk 31
targetSdk 32
vectorDrawables.useSupportLibrary = true
applicationId "code.name.monkey.retromusic"
versionCode 10573
versionName '5.8.0'
versionCode 10576
versionName '5.8.3'
buildConfigField("String", "GOOGLE_PLAY_LICENSING_KEY", "\"${getProperty(getProperties('../public.properties'), 'GOOGLE_PLAY_LICENSE_KEY')}\"")
}
@ -55,8 +55,6 @@ android {
disable 'MissingTranslation', 'InvalidPackage'
}
compileOptions {
coreLibraryDesugaringEnabled true
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
@ -99,7 +97,7 @@ dependencies {
implementation 'androidx.palette:palette-ktx:1.0.0'
//Cast Dependencies
implementation 'androidx.mediarouter:mediarouter:1.3.0-rc01'
implementation 'androidx.mediarouter:mediarouter:1.3.0'
implementation 'com.google.android.gms:play-services-cast-framework:21.0.1'
//WebServer by NanoHttpd
implementation "org.nanohttpd:nanohttpd:2.3.1"
@ -113,7 +111,7 @@ dependencies {
implementation "androidx.room:room-ktx:$room_version"
kapt "androidx.room:room-compiler:$room_version"
def lifecycle_version = "2.4.1"
def lifecycle_version = "2.5.0-beta01"
implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-livedata-ktx:$lifecycle_version"
implementation "androidx.lifecycle:lifecycle-common-java8:$lifecycle_version"
@ -126,19 +124,18 @@ dependencies {
def retrofit_version = '2.9.0'
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.6'
implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.7'
def material_dialog_version = "3.3.0"
implementation "com.afollestad.material-dialogs:core:$material_dialog_version"
implementation "com.afollestad.material-dialogs:input:$material_dialog_version"
implementation "com.afollestad.material-dialogs:color:$material_dialog_version"
implementation "com.afollestad.material-dialogs:bottomsheets:$material_dialog_version"
implementation 'com.afollestad:material-cab:2.0.1'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
def kotlin_coroutines_version = '1.6.0'
def kotlin_coroutines_version = '1.6.1'
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlin_coroutines_version"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlin_coroutines_version"
@ -151,8 +148,6 @@ dependencies {
kapt "com.github.bumptech.glide:compiler:$glide_version"
implementation "com.github.bumptech.glide:okhttp3-integration:$glide_version"
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5'
implementation 'com.h6ah4i.android.widget.advrecyclerview:advrecyclerview:1.0.0'
implementation 'com.github.bosphere.android-fadingedgelayout:fadingedgelayout:1.0.0'
@ -168,9 +163,8 @@ dependencies {
implementation 'com.r0adkll:slidableactivity:2.1.0'
implementation 'com.heinrichreimersoftware:material-intro:2.0.0'
implementation 'com.github.dhaval2404:imagepicker:2.1'
implementation 'me.zhanghai.android.fastscroll:library:1.1.7'
implementation 'me.zhanghai.android.fastscroll:library:1.1.8'
implementation 'cat.ereza:customactivityoncrash:2.3.0'
implementation 'me.tankery.lib:circularSeekBar:1.3.2'
debugImplementation 'com.github.amitshekhariitbhu:Android-Debug-Database:1.0.6'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.8.1'
debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'
}

View file

@ -19,7 +19,7 @@
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="com.android.vending.BILLING" />
<uses-permission android:name="android.permission.BLUETOOTH_CONNECT"/>
<application
android:name=".App"
@ -116,7 +116,6 @@
<activity android:name=".activities.SupportDevelopmentActivity" />
<activity android:name=".activities.LicenseActivity" />
<activity android:name=".activities.PurchaseActivity" />
<activity android:name=".activities.WhatsNewActivity" />
<activity android:name=".activities.bugreport.BugReportActivity" />
<activity android:name=".activities.ShareInstagramStory" />
<activity android:name=".activities.DriveModeActivity" />
@ -190,7 +189,6 @@
</intent-filter>
</activity>
<provider
android:name=".misc.GenericFileProvider"
android:authorities="${applicationId}.provider"

View file

@ -62,6 +62,22 @@
</head>
<body>
<div>
<h5>May 07, 2022</h5>
<h2>v5.8.3</h2>
<h3>What's New</h3>
<ul>
<li>Swipe down to dismiss Mini player</li>
<li>Add support for Just Black with Material You</li>
</ul>
<h3>Fixed</h3>
<ul>
<li>Fixed sharing of files from SD Card</li>
<li>Fix ChromeCast crash and bugs</li>
<li>Fix Audio Crossfade</li>
<li>Tried to fix incorrect song data in notification</li>
</ul>
</div>
<div>
<h5>April 8, 2022</h5>
<h2>v5.8.0</h2>

View file

@ -15,13 +15,13 @@
package code.name.monkey.retromusic
import android.app.Application
import android.widget.Toast
import cat.ereza.customactivityoncrash.config.CaocConfig
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.Constants.PRO_VERSION_PRODUCT_ID
import code.name.monkey.retromusic.activities.ErrorActivity
import code.name.monkey.retromusic.appshortcuts.DynamicShortcutManager
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.helper.WallpaperAccentManager
import com.anjlab.android.iab.v3.BillingProcessor
import com.anjlab.android.iab.v3.PurchaseInfo
@ -60,11 +60,7 @@ class App : Application() {
override fun onProductPurchased(productId: String, details: PurchaseInfo?) {}
override fun onPurchaseHistoryRestored() {
Toast.makeText(
this@App,
R.string.restored_previous_purchase_please_restart,
Toast.LENGTH_LONG
).show()
showToast(R.string.restored_previous_purchase_please_restart)
}
override fun onBillingError(errorCode: Int, error: Throwable?) {}

View file

@ -37,6 +37,8 @@ object Constants {
const val IS_MUSIC =
MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''"
const val DATA = "_data"
@Suppress("Deprecation")
val baseProjection = arrayOf(
BaseColumns._ID, // 0
@ -44,7 +46,7 @@ object Constants {
MediaStore.Audio.AudioColumns.TRACK, // 2
MediaStore.Audio.AudioColumns.YEAR, // 3
MediaStore.Audio.AudioColumns.DURATION, // 4
MediaStore.Audio.AudioColumns.DATA, // 5
DATA, // 5
MediaStore.Audio.AudioColumns.DATE_MODIFIED, // 6
MediaStore.Audio.AudioColumns.ALBUM_ID, // 7
MediaStore.Audio.AudioColumns.ALBUM, // 8

View file

@ -1,38 +0,0 @@
package code.name.monkey.retromusic;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.LocaleList;
import com.google.android.gms.common.annotation.KeepName;
import java.util.Locale;
import code.name.monkey.appthemehelper.util.VersionUtils;
public class LanguageContextWrapper extends ContextWrapper {
public LanguageContextWrapper(Context base) {
super(base);
}
@KeepName
public static LanguageContextWrapper wrap(Context context, Locale newLocale) {
Resources res = context.getResources();
Configuration configuration = res.getConfiguration();
if (VersionUtils.INSTANCE.hasNougatMR()) {
configuration.setLocale(newLocale);
LocaleList localeList = new LocaleList(newLocale);
LocaleList.setDefault(localeList);
configuration.setLocales(localeList);
} else {
configuration.setLocale(newLocale);
}
context = context.createConfigurationContext(configuration);
return new LanguageContextWrapper(context);
}
}

View file

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

View file

@ -4,6 +4,7 @@ import androidx.room.Room
import androidx.room.RoomDatabase
import androidx.sqlite.db.SupportSQLiteDatabase
import code.name.monkey.retromusic.auto.AutoMusicProvider
import code.name.monkey.retromusic.cast.RetroWebServer
import code.name.monkey.retromusic.db.BlackListStoreDao
import code.name.monkey.retromusic.db.BlackListStoreEntity
import code.name.monkey.retromusic.db.PlaylistWithSongs
@ -88,7 +89,8 @@ private val roomModule = module {
}
private val autoModule = module {
single {
AutoMusicProvider(androidContext(),
AutoMusicProvider(
androidContext(),
get(),
get(),
get(),
@ -102,6 +104,9 @@ private val mainModule = module {
single {
androidContext().contentResolver
}
single {
RetroWebServer(get())
}
}
private val dataModule = module {
single {

View file

@ -1,38 +0,0 @@
package code.name.monkey.retromusic;
import android.content.Context;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import org.jetbrains.annotations.NotNull;
public class RetroBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {
private static final String TAG = "RetroBottomSheetBehavior";
private boolean allowDragging = true;
public RetroBottomSheetBehavior() {}
public RetroBottomSheetBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setAllowDragging(boolean allowDragging) {
this.allowDragging = allowDragging;
}
@Override
public boolean onInterceptTouchEvent(
@NotNull CoordinatorLayout parent, @NotNull V child, @NotNull MotionEvent event) {
if (!allowDragging) {
return false;
}
return super.onInterceptTouchEvent(parent, child, event);
}
}

View file

@ -22,11 +22,11 @@ import android.os.Bundle
import android.view.animation.LinearInterpolator
import android.widget.SeekBar
import androidx.lifecycle.lifecycleScope
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.databinding.ActivityDriveModeBinding
import code.name.monkey.retromusic.db.toSongEntity
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.drawAboveSystemBars
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.glide.BlurTransformation
@ -66,7 +66,7 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
setUpMusicControllers()
progressViewUpdateHelper = MusicProgressViewUpdateHelper(this)
lastPlaybackControlsColor = ThemeStore.accentColor(this)
lastPlaybackControlsColor = accentColor()
binding.close.setOnClickListener {
onBackPressed()
}
@ -91,7 +91,6 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
private fun toggleFavorite(song: Song) {
lifecycleScope.launch(Dispatchers.IO) {
val playlist = repository.favoritePlaylist()
if (playlist != null) {
val songEntity = song.toSongEntity(playlist.playListId)
val isFavorite = repository.isSongFavorite(song.id)
if (isFavorite) {
@ -99,7 +98,6 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
} else {
repository.insertSongs(listOf(song.toSongEntity(playlist.playListId)))
}
}
sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED))
}
}
@ -139,7 +137,6 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
}
private fun setUpPrevNext() {
binding.nextButton.setOnClickListener { MusicPlayerRemote.playNextSong() }
binding.previousButton.setOnClickListener { MusicPlayerRemote.back() }
}
@ -246,7 +243,8 @@ class DriveModeActivity : AbsMusicServiceActivity(), Callback {
GlideApp.with(this)
.load(RetroGlideExtension.getSongModel(song))
.songCoverOptions(song).transform(BlurTransformation.Builder(this).build())
.songCoverOptions(song)
.transform(BlurTransformation.Builder(this).build())
.into(binding.image)
}

View file

@ -16,12 +16,12 @@ package code.name.monkey.retromusic.activities
import android.graphics.Color
import android.os.Bundle
import android.view.MenuItem
import code.name.monkey.appthemehelper.ThemeStore.Companion.accentColor
import code.name.monkey.appthemehelper.util.ATHUtil.isWindowBackgroundDark
import code.name.monkey.appthemehelper.util.ColorUtil.lightenColor
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.activities.base.AbsThemeActivity
import code.name.monkey.retromusic.databinding.ActivityLicenseBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.drawAboveSystemBars
import code.name.monkey.retromusic.extensions.surfaceColor
import java.io.BufferedReader
@ -59,11 +59,11 @@ class LicenseActivity : AbsThemeActivity() {
"body { background-color: %s; color: %s; }", backgroundColor, contentColor
)
)
.replace("{link-color}", colorToCSS(accentColor(this)))
.replace("{link-color}", colorToCSS(accentColor()))
.replace(
"{link-color-active}",
colorToCSS(
lightenColor(accentColor(this))
lightenColor(accentColor())
)
)
binding.license.loadData(changeLog, "text/html", "UTF-8")

View file

@ -35,7 +35,6 @@ import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.repository.PlaylistSongsLoader
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.AppRater
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.launch
@ -62,9 +61,7 @@ class MainActivity : AbsCastActivity(), OnSharedPreferenceChangeListener {
if (!hasPermissions()) {
findNavController(R.id.fragment_container).navigate(R.id.permissionFragment)
}
if (BuildConfig.VERSION_CODE > PreferenceUtil.lastVersion && !BuildConfig.DEBUG) {
NavigationUtil.gotoWhatNews(this)
}
WhatsNewFragment.showChangeLog(this)
}
private fun setupNavigationController() {
@ -179,7 +176,7 @@ class MainActivity : AbsCastActivity(), OnSharedPreferenceChangeListener {
handled = true
}
if (uri != null && uri.toString().isNotEmpty()) {
MusicPlayerRemote.playFromUri(uri)
MusicPlayerRemote.playFromUri(this@MainActivity, uri)
handled = true
} else if (MediaStore.Audio.Playlists.CONTENT_TYPE == mimeType) {
val id = parseLongFromIntent(intent, "playlistId", "playlist")

View file

@ -22,17 +22,14 @@ import android.os.Build
import android.os.Bundle
import android.provider.Settings
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import androidx.core.net.toUri
import androidx.core.text.parseAsHtml
import androidx.core.view.isVisible
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.activities.base.AbsMusicServiceActivity
import code.name.monkey.retromusic.databinding.ActivityPermissionBinding
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.*
import code.name.monkey.retromusic.util.RingtoneManager
class PermissionActivity : AbsMusicServiceActivity() {
@ -75,32 +72,32 @@ class PermissionActivity : AbsMusicServiceActivity() {
}
private fun setupTitle() {
val color = ThemeStore.accentColor(this)
val color = accentColor()
val hexColor = String.format("#%06X", 0xFFFFFF and color)
val appName = "Hello there! <br>Welcome to <b>Retro <span style='color:$hexColor';>Music</span></b>"
val appName =
"Hello there! <br>Welcome to <b>Retro <span style='color:$hexColor';>Music</span></b>"
.parseAsHtml()
binding.appNameText.text = appName
}
@RequiresApi(Build.VERSION_CODES.M)
override fun onResume() {
super.onResume()
if (hasStoragePermission()) {
binding.storagePermission.checkImage.isVisible = true
binding.storagePermission.checkImage.imageTintList =
ColorStateList.valueOf(ThemeStore.accentColor(this))
ColorStateList.valueOf(accentColor())
}
if (VersionUtils.hasMarshmallow()) {
if (hasAudioPermission()) {
binding.audioPermission.checkImage.isVisible = true
binding.audioPermission.checkImage.imageTintList =
ColorStateList.valueOf(ThemeStore.accentColor(this))
ColorStateList.valueOf(accentColor())
}
}
}
super.onResume()
}
@RequiresApi(Build.VERSION_CODES.M)
private fun hasStoragePermission(): Boolean {
return checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
return ActivityCompat.checkSelfPermission(this , Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
}
@RequiresApi(Build.VERSION_CODES.M)

View file

@ -19,8 +19,6 @@ import android.graphics.Color
import android.os.Bundle
import android.util.Log
import android.view.MenuItem
import android.widget.Toast
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.BuildConfig
@ -28,8 +26,10 @@ import code.name.monkey.retromusic.Constants.PRO_VERSION_PRODUCT_ID
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.databinding.ActivityProVersionBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.setLightStatusBar
import code.name.monkey.retromusic.extensions.setStatusBarColor
import code.name.monkey.retromusic.extensions.showToast
import com.anjlab.android.iab.v3.BillingProcessor
import com.anjlab.android.iab.v3.PurchaseInfo
@ -61,12 +61,11 @@ class PurchaseActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler {
billingProcessor.purchase(this@PurchaseActivity, PRO_VERSION_PRODUCT_ID)
}
binding.bannerContainer.backgroundTintList =
ColorStateList.valueOf(ThemeStore.accentColor(this))
ColorStateList.valueOf(accentColor())
}
private fun restorePurchase() {
Toast.makeText(this, R.string.restoring_purchase, Toast.LENGTH_SHORT)
.show()
showToast(R.string.restoring_purchase)
billingProcessor.loadOwnedPurchasesFromGoogleAsync(object :
BillingProcessor.IPurchasesResponseListener {
override fun onPurchasesSuccess() {
@ -74,30 +73,22 @@ class PurchaseActivity : AbsBaseActivity(), BillingProcessor.IBillingHandler {
}
override fun onPurchasesError() {
Toast.makeText(
this@PurchaseActivity,
R.string.could_not_restore_purchase,
Toast.LENGTH_SHORT
).show()
showToast(R.string.could_not_restore_purchase)
}
})
}
override fun onProductPurchased(productId: String, details: PurchaseInfo?) {
Toast.makeText(this, R.string.thank_you, Toast.LENGTH_SHORT).show()
showToast(R.string.thank_you)
setResult(RESULT_OK)
}
override fun onPurchaseHistoryRestored() {
if (App.isProVersion()) {
Toast.makeText(
this,
R.string.restored_previous_purchase_please_restart,
Toast.LENGTH_LONG
).show()
showToast(R.string.restored_previous_purchase_please_restart)
setResult(RESULT_OK)
} else {
Toast.makeText(this, R.string.no_purchase_found, Toast.LENGTH_SHORT).show()
showToast(R.string.no_purchase_found)
}
}

View file

@ -23,11 +23,11 @@ import android.provider.MediaStore.Images.Media
import android.view.MenuItem
import androidx.core.net.toUri
import androidx.core.view.drawToBitmap
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.databinding.ActivityShareInstagramBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.setLightStatusBar
import code.name.monkey.retromusic.extensions.setStatusBarColor
import code.name.monkey.retromusic.glide.GlideApp
@ -96,11 +96,11 @@ class ShareInstagramStory : AbsBaseActivity() {
binding.shareButton.setTextColor(
MaterialValueHelper.getPrimaryTextColor(
this,
ColorUtil.isColorLight(ThemeStore.accentColor(this))
ColorUtil.isColorLight(accentColor())
)
)
binding.shareButton.backgroundTintList =
ColorStateList.valueOf(ThemeStore.accentColor(this))
ColorStateList.valueOf(accentColor())
}
private fun setColors(colorLight: Boolean, color: Int) {

View file

@ -21,12 +21,10 @@ import android.view.LayoutInflater
import android.view.MenuItem
import android.view.ViewGroup
import android.widget.TextView
import android.widget.Toast
import androidx.core.view.isVisible
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.GridLayoutManager
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
@ -75,8 +73,8 @@ class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingH
setupToolbar()
billingProcessor = BillingProcessor(this, BuildConfig.GOOGLE_PLAY_LICENSING_KEY, this)
TintHelper.setTint(binding.progress, ThemeStore.accentColor(this))
binding.donation.setTextColor(ThemeStore.accentColor(this))
TintHelper.setTint(binding.progress, accentColor())
binding.donation.setTextColor(accentColor())
}
private fun setupToolbar() {
@ -121,7 +119,7 @@ class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingH
override fun onProductPurchased(productId: String, details: PurchaseInfo?) {
// loadSkuDetails();
Toast.makeText(this, R.string.thank_you, Toast.LENGTH_SHORT).show()
showToast(R.string.thank_you)
}
override fun onBillingError(errorCode: Int, error: Throwable?) {
@ -130,7 +128,7 @@ class SupportDevelopmentActivity : AbsBaseActivity(), BillingProcessor.IBillingH
override fun onPurchaseHistoryRestored() {
// loadSkuDetails();
Toast.makeText(this, R.string.restored_previous_purchases, Toast.LENGTH_SHORT).show()
showToast(R.string.restored_previous_purchases)
}
override fun onDestroy() {

View file

@ -4,39 +4,45 @@ import android.content.Context
import android.content.pm.PackageManager
import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.core.content.pm.PackageInfoCompat
import androidx.core.widget.NestedScrollView
import code.name.monkey.appthemehelper.ThemeStore.Companion.accentColor
import androidx.fragment.app.FragmentActivity
import code.name.monkey.appthemehelper.util.ATHUtil.isWindowBackgroundDark
import code.name.monkey.appthemehelper.util.ColorUtil.isColorLight
import code.name.monkey.appthemehelper.util.ColorUtil.lightenColor
import code.name.monkey.appthemehelper.util.MaterialValueHelper.getPrimaryTextColor
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.BuildConfig
import code.name.monkey.retromusic.Constants
import code.name.monkey.retromusic.activities.base.AbsThemeActivity
import code.name.monkey.retromusic.databinding.ActivityWhatsNewBinding
import code.name.monkey.retromusic.databinding.FragmentWhatsNewBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.drawAboveSystemBars
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.extensions.openUrl
import code.name.monkey.retromusic.util.PreferenceUtil.lastVersion
import code.name.monkey.retromusic.util.RetroUtil
import java.io.BufferedReader
import java.io.InputStreamReader
import com.google.android.material.bottomsheet.BottomSheetDialogFragment
import java.nio.charset.StandardCharsets
import java.util.*
class WhatsNewActivity : AbsThemeActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val binding = ActivityWhatsNewBinding.inflate(layoutInflater)
setContentView(binding.root)
setTaskDescriptionColorAuto()
binding.toolbar.setNavigationOnClickListener { onBackPressed() }
ToolbarContentTintHelper.colorBackButton(binding.toolbar)
class WhatsNewFragment : BottomSheetDialogFragment() {
private var _binding: FragmentWhatsNewBinding? = null
val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
_binding = FragmentWhatsNewBinding.inflate(inflater, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
try {
val buf = StringBuilder()
val json = assets.open("retro-changelog.html")
BufferedReader(InputStreamReader(json, StandardCharsets.UTF_8)).use { br ->
val stream= requireContext().assets.open("retro-changelog.html")
stream.reader(StandardCharsets.UTF_8).buffered().use { br ->
var str: String?
while (br.readLine().also { str = it } != null) {
buf.append(str)
@ -44,31 +50,29 @@ class WhatsNewActivity : AbsThemeActivity() {
}
// Inject color values for WebView body background and links
val isDark = isWindowBackgroundDark(this)
val accentColor = accentColor(this)
val backgroundColor = colorToCSS(
surfaceColor(Color.parseColor(if (isDark) "#424242" else "#ffffff"))
)
val isDark = isWindowBackgroundDark(requireContext())
val accentColor = accentColor()
binding.webView.setBackgroundColor(0)
val contentColor = colorToCSS(Color.parseColor(if (isDark) "#ffffff" else "#000000"))
val textColor = colorToCSS(Color.parseColor(if (isDark) "#60FFFFFF" else "#80000000"))
val accentColorString = colorToCSS(accentColor(this))
val accentColorString = colorToCSS(accentColor())
val cardBackgroundColor =
colorToCSS(Color.parseColor(if (isDark) "#353535" else "#ffffff"))
val accentTextColor = colorToCSS(
getPrimaryTextColor(
this, isColorLight(accentColor)
requireContext(), isColorLight(accentColor)
)
)
val changeLog = buf.toString()
.replace(
"{style-placeholder}",
"body { background-color: $backgroundColor; color: $contentColor; } li {color: $textColor;} h3 {color: $accentColorString;} .tag {background-color: $accentColorString; color: $accentTextColor; } div{background-color: $cardBackgroundColor;}"
"body { color: $contentColor; } li {color: $textColor;} h3 {color: $accentColorString;} .tag {background-color: $accentColorString; color: $accentTextColor; } div{background-color: $cardBackgroundColor;}"
)
.replace("{link-color}", colorToCSS(accentColor(this)))
.replace("{link-color}", colorToCSS(accentColor()))
.replace(
"{link-color-active}",
colorToCSS(
lightenColor(accentColor(this))
lightenColor(accentColor())
)
)
binding.webView.loadData(changeLog, "text/html", "UTF-8")
@ -77,12 +81,9 @@ class WhatsNewActivity : AbsThemeActivity() {
"<h1>Unable to load</h1><p>" + e.localizedMessage + "</p>", "text/html", "UTF-8"
)
}
setChangelogRead(this)
setChangelogRead(requireContext())
binding.tgFab.setOnClickListener {
RetroUtil.openUrl(
this,
Constants.TELEGRAM_CHANGE_LOG
)
openUrl(Constants.TELEGRAM_CHANGE_LOG)
}
binding.tgFab.accentColor()
binding.tgFab.shrink()
@ -94,10 +95,16 @@ class WhatsNewActivity : AbsThemeActivity() {
binding.tgFab.extend()
}
}
binding.webView.drawAboveSystemBars()
}
override fun onDestroy() {
super.onDestroy()
_binding = null
}
companion object {
const val TAG = "WhatsNewFragment"
private fun colorToCSS(color: Int): String {
return String.format(
Locale.getDefault(),
@ -112,11 +119,20 @@ class WhatsNewActivity : AbsThemeActivity() {
private fun setChangelogRead(context: Context) {
try {
val pInfo = context.packageManager.getPackageInfo(context.packageName, 0)
val currentVersion = pInfo.versionCode
val currentVersion = PackageInfoCompat.getLongVersionCode(pInfo)
lastVersion = currentVersion
} catch (e: PackageManager.NameNotFoundException) {
e.printStackTrace()
}
}
fun showChangeLog(activity: FragmentActivity) {
val pInfo = activity.packageManager.getPackageInfo(activity.packageName, 0)
val currentVersion = PackageInfoCompat.getLongVersionCode(pInfo)
if (currentVersion > lastVersion && !BuildConfig.DEBUG) {
val changelogBottomSheet = WhatsNewFragment()
changelogBottomSheet.show(activity.supportFragmentManager, TAG)
}
}
}
}

View file

@ -29,9 +29,9 @@ import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import androidx.core.app.ActivityCompat
import androidx.core.content.getSystemService
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.accentColor
import com.google.android.material.snackbar.Snackbar
abstract class AbsBaseActivity : AbsThemeActivity() {
@ -90,19 +90,15 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
}
protected open fun requestPermissions() {
if (VersionUtils.hasMarshmallow()) {
requestPermissions(permissions, PERMISSION_REQUEST)
}
ActivityCompat.requestPermissions(this, permissions, PERMISSION_REQUEST)
}
protected fun hasPermissions(): Boolean {
if (VersionUtils.hasMarshmallow()) {
for (permission in permissions) {
if (checkSelfPermission(permission) != PackageManager.PERMISSION_GRANTED) {
if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) {
return false
}
}
}
return true
}
@ -126,14 +122,15 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
Snackbar.LENGTH_INDEFINITE
)
.setAction(R.string.action_grant) { requestPermissions() }
.setActionTextColor(ThemeStore.accentColor(this)).show()
.setActionTextColor(accentColor()).show()
} else {
// User has deny permission and checked never show permission dialog so you can redirect to Application settings page
Snackbar.make(
snackBarContainer,
permissionDeniedMessage!!,
Snackbar.LENGTH_INDEFINITE
).setAction(R.string.action_settings) {
)
.setAction(R.string.action_settings) {
val intent = Intent()
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
val uri = Uri.fromParts(
@ -143,7 +140,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
)
intent.data = uri
startActivity(intent)
}.setActionTextColor(ThemeStore.accentColor(this)).show()
}.setActionTextColor(accentColor()).show()
}
return
}
@ -156,6 +153,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
companion object {
const val PERMISSION_REQUEST = 100
}
// this lets keyboard close when clicked in backgroud
override fun dispatchTouchEvent(event: MotionEvent): Boolean {
if (event.action == MotionEvent.ACTION_DOWN) {
@ -165,7 +163,10 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
v.getGlobalVisibleRect(outRect)
if (!outRect.contains(event.rawX.toInt(), event.rawY.toInt())) {
v.clearFocus()
getSystemService<InputMethodManager>()?.hideSoftInputFromWindow(v.windowToken, 0)
getSystemService<InputMethodManager>()?.hideSoftInputFromWindow(
v.windowToken,
0
)
}
}
}

View file

@ -1,10 +1,8 @@
package code.name.monkey.retromusic.activities.base
import android.os.Bundle
import android.view.ViewStub
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.cast.CastHelper
import code.name.monkey.retromusic.cast.RetroSessionManager
import code.name.monkey.retromusic.cast.RetroSessionManagerListener
import code.name.monkey.retromusic.cast.RetroWebServer
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import com.google.android.gms.cast.framework.CastContext
@ -12,36 +10,40 @@ import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.cast.framework.SessionManager
import com.google.android.gms.common.ConnectionResult
import com.google.android.gms.common.GoogleApiAvailability
import org.koin.android.ext.android.inject
abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() {
private var mCastSession: CastSession? = null
private lateinit var sessionManager: SessionManager
private var webServer: RetroWebServer? = null
private val webServer: RetroWebServer by inject()
private var playServicesAvailable: Boolean = false
private val sessionManagerListener by lazy {
object : RetroSessionManager {
object : RetroSessionManagerListener {
override fun onSessionStarting(castSession: CastSession) {
invalidateOptionsMenu()
webServer = RetroWebServer.getInstance(this@AbsCastActivity)
webServer?.start()
webServer.start()
}
override fun onSessionStarted(castSession: CastSession, p1: String) {
invalidateOptionsMenu()
mCastSession = castSession
loadCastQueue(MusicPlayerRemote.position)
inflateCastController()
loadCastQueue()
MusicPlayerRemote.isCasting = true
setAllowDragging(false)
collapsePanel()
}
override fun onSessionEnding(p0: CastSession) {
invalidateOptionsMenu()
webServer?.stop()
override fun onSessionEnding(castSession: CastSession) {
MusicPlayerRemote.isCasting = false
castSession.remoteMediaClient?.let {
val position = it.mediaQueue.indexOfItemWithId(it.currentItem?.itemId ?: 0)
val progress = it.approximateStreamPosition
MusicPlayerRemote.position = position
MusicPlayerRemote.seekTo(progress.toInt())
}
}
override fun onSessionEnded(castSession: CastSession, p1: Int) {
@ -49,15 +51,18 @@ abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() {
if (mCastSession == castSession) {
mCastSession = null
}
MusicPlayerRemote.isCasting = false
setAllowDragging(true)
webServer.stop()
}
override fun onSessionResumed(castSession: CastSession, p1: Boolean) {
invalidateOptionsMenu()
mCastSession = castSession
loadCastQueue(MusicPlayerRemote.position)
inflateCastController()
webServer.start()
mCastSession?.remoteMediaClient?.let {
loadCastQueue(it.mediaQueue.indexOfItemWithId(it.currentItem?.itemId ?: 0), it.approximateStreamPosition)
}
MusicPlayerRemote.isCasting = true
setAllowDragging(false)
collapsePanel()
@ -70,6 +75,7 @@ abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() {
}
MusicPlayerRemote.isCasting = false
setAllowDragging(true)
webServer.stop()
}
}
}
@ -88,10 +94,11 @@ abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() {
}
private fun setupCast() {
sessionManager = CastContext.getSharedInstance(applicationContext).sessionManager
sessionManager = CastContext.getSharedInstance(this).sessionManager
}
override fun onResume() {
super.onResume()
if (playServicesAvailable) {
sessionManager.addSessionManagerListener(
sessionManagerListener,
@ -101,41 +108,39 @@ abstract class AbsCastActivity : AbsSlidingMusicPanelActivity() {
mCastSession = sessionManager.currentCastSession
}
}
super.onResume()
}
override fun onStop() {
super.onStop()
override fun onPause() {
super.onPause()
if (playServicesAvailable) {
sessionManager.removeSessionManagerListener(
sessionManagerListener,
CastSession::class.java
)
mCastSession = null
}
private fun songChanged(position: Int) {
loadCastQueue(position)
}
fun loadCastQueue(position: Int) {
if (!MusicPlayerRemote.playingQueue.isNullOrEmpty()) {
fun loadCastQueue(
position: Int = MusicPlayerRemote.position,
progress: Long = MusicPlayerRemote.songProgressMillis.toLong(),
) {
mCastSession?.let {
if (!MusicPlayerRemote.playingQueue.isNullOrEmpty()) {
CastHelper.castQueue(
it,
MusicPlayerRemote.playingQueue,
position,
MusicPlayerRemote.songProgressMillis.toLong()
progress
)
}
} else {
mCastSession?.let { CastHelper.castSong(it, MusicPlayerRemote.currentSong) }
}
}
override fun onPlayingMetaChanged() {
super.onPlayingMetaChanged()
override fun onQueueChanged() {
super.onQueueChanged()
if (playServicesAvailable) {
songChanged(MusicPlayerRemote.position)
loadCastQueue()
}
}
fun inflateCastController() {
findViewById<ViewStub>(R.id.cast_stub)?.inflate()
}
}

View file

@ -30,7 +30,6 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.commit
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.RetroBottomSheetBehavior
import code.name.monkey.retromusic.databinding.SlidingMusicPanelLayoutBinding
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.LibraryViewModel
@ -60,6 +59,7 @@ import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.CategoryInfo
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.ViewUtil
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.*
import org.koin.androidx.viewmodel.ext.android.viewModel
@ -72,7 +72,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
var fromNotification = false
private var windowInsets: WindowInsetsCompat? = null
protected val libraryViewModel by viewModel<LibraryViewModel>()
private lateinit var bottomSheetBehavior: RetroBottomSheetBehavior<FrameLayout>
private lateinit var bottomSheetBehavior: BottomSheetBehavior<FrameLayout>
private var playerFragment: AbsPlayerFragment? = null
private var miniPlayerFragment: MiniPlayerFragment? = null
private var nowPlayingScreen: NowPlayingScreen? = null
@ -122,6 +122,9 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
fromNotification = false
}
}
STATE_HIDDEN -> {
MusicPlayerRemote.clearQueue()
}
else -> {
println("Do a flip")
}
@ -154,9 +157,9 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
}
private fun setupBottomSheet() {
bottomSheetBehavior = from(binding.slidingPanel) as RetroBottomSheetBehavior
bottomSheetBehavior = from(binding.slidingPanel)
bottomSheetBehavior.addBottomSheetCallback(bottomSheetCallbackList)
bottomSheetBehavior.isHideable = false
bottomSheetBehavior.isHideable = true
setMiniPlayerAlphaProgress(0F)
}
@ -294,7 +297,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
navigationBarColor = surfaceColor()
setTaskDescColor(paletteColor)
val isColorLight = paletteColor.isColorLight
if (PreferenceUtil.isAdaptiveColor && (nowPlayingScreen == Normal || nowPlayingScreen == Flat)) {
if (PreferenceUtil.isAdaptiveColor && (nowPlayingScreen == Normal || nowPlayingScreen == Flat || nowPlayingScreen == Material)) {
setLightNavigationBar(true)
setLightStatusBar(isColorLight)
} else if (nowPlayingScreen == Card || nowPlayingScreen == Blur || nowPlayingScreen == BlurCard) {
@ -363,18 +366,15 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
)
return
}
val translationY =
if (visible) 0F else dip(R.dimen.bottom_nav_height).toFloat() + windowInsets.safeGetBottomInsets()
val mAnimate = animate && bottomSheetBehavior.state == STATE_COLLAPSED
if (mAnimate) {
binding.bottomNavigationView.translateYAnimate(translationY).doOnEnd {
if (visible && bottomSheetBehavior.state != STATE_EXPANDED) {
if (visible) {
binding.bottomNavigationView.bringToFront()
}
binding.bottomNavigationView.show()
} else {
binding.bottomNavigationView.hide()
}
} else {
binding.bottomNavigationView.translationY =
translationY
binding.bottomNavigationView.isVisible = false
if (visible && bottomSheetBehavior.state != STATE_EXPANDED) {
binding.bottomNavigationView.bringToFront()
@ -399,7 +399,10 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
if (hide) {
bottomSheetBehavior.peekHeight = -windowInsets.safeGetBottomInsets()
bottomSheetBehavior.state = STATE_COLLAPSED
libraryViewModel.setFabMargin(if (isBottomNavVisible) dip(R.dimen.bottom_nav_height) else 0)
libraryViewModel.setFabMargin(
this,
if (isBottomNavVisible) dip(R.dimen.bottom_nav_height) else 0
)
} else {
if (MusicPlayerRemote.playingQueue.isNotEmpty()) {
binding.slidingPanel.elevation = 0F
@ -411,7 +414,7 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
} else {
bottomSheetBehavior.peekHeight = heightOfBarWithTabs
}
libraryViewModel.setFabMargin(dip(R.dimen.mini_player_height_expanded))
libraryViewModel.setFabMargin(this, dip(R.dimen.mini_player_height_expanded))
} else {
println("Details")
if (animate) {
@ -422,14 +425,14 @@ abstract class AbsSlidingMusicPanelActivity : AbsMusicServiceActivity() {
bottomSheetBehavior.peekHeight = heightOfBar
binding.slidingPanel.bringToFront()
}
libraryViewModel.setFabMargin(dip(R.dimen.mini_player_height))
libraryViewModel.setFabMargin(this, dip(R.dimen.mini_player_height))
}
}
}
}
fun setAllowDragging(allowDragging: Boolean) {
bottomSheetBehavior.setAllowDragging(allowDragging)
bottomSheetBehavior.isDraggable = allowDragging
hideBottomSheet(false)
}

View file

@ -18,6 +18,7 @@ import android.content.Context
import android.content.res.Resources
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.KeyEvent
import android.view.View
import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode
@ -28,12 +29,13 @@ import code.name.monkey.retromusic.LanguageContextWrapper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.theme.ThemeManager
import code.name.monkey.retromusic.util.theme.getNightMode
import code.name.monkey.retromusic.util.theme.getThemeResValue
import java.util.*
abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
private val handler = Handler()
private val handler = Handler(Looper.getMainLooper())
override fun onCreate(savedInstanceState: Bundle?) {
updateTheme()
@ -50,9 +52,9 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
}
private fun updateTheme() {
setTheme(ThemeManager.getThemeResValue())
setTheme(getThemeResValue())
if (PreferenceUtil.materialYou) {
setDefaultNightMode(ThemeManager.getNightMode())
setDefaultNightMode(getNightMode())
}
if (PreferenceUtil.isCustomFont) {

View file

@ -20,13 +20,11 @@ import android.content.Intent
import android.os.Bundle
import android.view.MenuItem
import android.view.inputmethod.EditorInfo
import android.widget.Toast
import androidx.annotation.StringDef
import androidx.annotation.StringRes
import androidx.core.content.getSystemService
import androidx.core.net.toUri
import androidx.lifecycle.lifecycleScope
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.MaterialUtil
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
@ -38,7 +36,9 @@ 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.GithubTarget
import code.name.monkey.retromusic.databinding.ActivityBugReportBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
import code.name.monkey.retromusic.extensions.showToast
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.textfield.TextInputLayout
@ -87,7 +87,7 @@ open class BugReportActivity : AbsThemeActivity() {
}
private fun initViews() {
val accentColor = ThemeStore.accentColor(this)
val accentColor = accentColor()
setSupportActionBar(binding.toolbar)
ToolbarContentTintHelper.colorBackButton(binding.toolbar)
supportActionBar?.setDisplayHomeAsUpEnabled(true)
@ -163,11 +163,7 @@ open class BugReportActivity : AbsThemeActivity() {
val clipboard = getSystemService<ClipboardManager>()
val clip = ClipData.newPlainText(getString(R.string.device_info), deviceInfo?.toMarkdown())
clipboard?.setPrimaryClip(clip)
Toast.makeText(
this@BugReportActivity,
R.string.copied_device_info_to_clipboard,
Toast.LENGTH_LONG
).show()
showToast(R.string.copied_device_info_to_clipboard)
}
private fun validateInput(): Boolean {
@ -314,6 +310,7 @@ open class BugReportActivity : AbsThemeActivity() {
private const val STATUS_BAD_CREDENTIALS = 401
private const val STATUS_ISSUES_NOT_ENABLED = 410
private const val ISSUE_TRACKER_LINK = "https://github.com/RetroMusicPlayer/RetroMusicPlayer"
private const val ISSUE_TRACKER_LINK =
"https://github.com/RetroMusicPlayer/RetroMusicPlayer"
}
}

View file

@ -5,6 +5,7 @@ import android.content.Context
import android.content.pm.PackageManager
import android.os.Build
import androidx.annotation.IntRange
import androidx.core.content.pm.PackageInfoCompat
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.PreferenceUtil.isAdaptiveColor
import code.name.monkey.retromusic.util.PreferenceUtil.languageCode
@ -35,7 +36,7 @@ class DeviceInfo(context: Context) {
@IntRange(from = 0)
private val sdkVersion = Build.VERSION.SDK_INT
private var versionCode = 0
private var versionCode = 0L
private var versionName: String? = null
private val selectedLang: String
fun toMarkdown(): String {
@ -96,7 +97,7 @@ class DeviceInfo(context: Context) {
null
}
if (packageInfo != null) {
versionCode = packageInfo.versionCode
versionCode = PackageInfoCompat.getLongVersionCode(packageInfo)
versionName = packageInfo.versionName
} else {
versionCode = -1

View file

@ -41,11 +41,12 @@ import code.name.monkey.retromusic.R.drawable
import code.name.monkey.retromusic.activities.base.AbsBaseActivity
import code.name.monkey.retromusic.activities.saf.SAFGuideActivity
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.colorButtons
import code.name.monkey.retromusic.extensions.hideSoftKeyboard
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
import code.name.monkey.retromusic.model.ArtworkInfo
import code.name.monkey.retromusic.model.AudioTagInfo
import code.name.monkey.retromusic.repository.Repository
import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.SAFUtil
import com.google.android.material.button.MaterialButton
import com.google.android.material.dialog.MaterialAlertDialogBuilder
@ -92,7 +93,9 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
2 -> deleteImage()
}
}
.setNegativeButton(R.string.action_cancel, null)
.show()
.colorButtons()
internal val albumArtist: String?
get() {
@ -346,7 +349,7 @@ abstract class AbsTagEditorActivity<VB : ViewBinding> : AbsBaseActivity() {
fieldKeyValueMap: Map<FieldKey, String>,
artworkInfo: ArtworkInfo?
) {
RetroUtil.hideSoftKeyboard(this)
hideSoftKeyboard()
hideFab()
println(fieldKeyValueMap)

View file

@ -30,10 +30,7 @@ import androidx.core.widget.doAfterTextChanged
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.ActivityAlbumTagEditorBinding
import code.name.monkey.retromusic.extensions.appHandleColor
import code.name.monkey.retromusic.extensions.defaultFooterColor
import code.name.monkey.retromusic.extensions.isColorLight
import code.name.monkey.retromusic.extensions.setTint
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.model.ArtworkInfo
@ -117,11 +114,7 @@ class AlbumTagEditorActivity : AbsTagEditorActivity<ActivityAlbumTagEditorBindin
}
private fun toastLoadingFailed() {
Toast.makeText(
this@AlbumTagEditorActivity,
R.string.could_not_download_album_cover,
Toast.LENGTH_SHORT
).show()
showToast(R.string.could_not_download_album_cover)
}
override fun searchImageOnWeb() {
@ -161,8 +154,7 @@ class AlbumTagEditorActivity : AbsTagEditorActivity<ActivityAlbumTagEditorBindin
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
Toast.makeText(this@AlbumTagEditorActivity, "Load Failed", Toast.LENGTH_LONG)
.show()
showToast("Load Failed", Toast.LENGTH_LONG)
}
override fun setResource(resource: BitmapPaletteWrapper?) {}

View file

@ -30,10 +30,7 @@ import androidx.core.widget.doAfterTextChanged
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.ActivitySongTagEditorBinding
import code.name.monkey.retromusic.extensions.appHandleColor
import code.name.monkey.retromusic.extensions.defaultFooterColor
import code.name.monkey.retromusic.extensions.isColorLight
import code.name.monkey.retromusic.extensions.setTint
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
import code.name.monkey.retromusic.model.ArtworkInfo
@ -196,8 +193,7 @@ class SongTagEditorActivity : AbsTagEditorActivity<ActivitySongTagEditorBinding>
override fun onLoadFailed(errorDrawable: Drawable?) {
super.onLoadFailed(errorDrawable)
Toast.makeText(this@SongTagEditorActivity, "Load Failed", Toast.LENGTH_LONG)
.show()
showToast("Load Failed", Toast.LENGTH_LONG)
}
override fun setResource(resource: BitmapPaletteWrapper?) {}

View file

@ -6,8 +6,8 @@ import android.graphics.Bitmap
import android.media.MediaScannerConnection
import android.os.Build
import android.util.Log
import android.widget.Toast
import androidx.annotation.RequiresApi
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.misc.UpdateToastMediaScannerCompletionListener
import code.name.monkey.retromusic.model.AudioTagInfo
import code.name.monkey.retromusic.util.MusicUtil.createAlbumArtFile
@ -24,7 +24,6 @@ import org.jaudiotagger.tag.TagException
import org.jaudiotagger.tag.images.AndroidArtwork
import org.jaudiotagger.tag.images.Artwork
import java.io.File
import java.io.FileOutputStream
import java.io.IOException
class TagWriter {
@ -34,7 +33,7 @@ class TagWriter {
suspend fun scan(context: Context, toBeScanned: List<String?>?) {
if (toBeScanned == null || toBeScanned.isEmpty()) {
Log.i("scan", "scan: Empty")
Toast.makeText(context, "Scan file from folder", Toast.LENGTH_SHORT).show()
context.showToast( "Scan file from folder")
return
}
MediaScannerConnection.scanFile(
@ -60,7 +59,7 @@ class TagWriter {
info.artworkInfo.artwork.compress(
Bitmap.CompressFormat.JPEG,
100,
FileOutputStream(albumArtFile)
albumArtFile.outputStream()
)
artwork = AndroidArtwork.createArtworkFromFile(albumArtFile)
} catch (e: IOException) {
@ -133,7 +132,7 @@ class TagWriter {
info.artworkInfo.artwork.compress(
Bitmap.CompressFormat.JPEG,
100,
FileOutputStream(albumArtFile)
albumArtFile.outputStream()
)
artwork = AndroidArtwork.createArtworkFromFile(albumArtFile)
} catch (e: IOException) {

View file

@ -19,12 +19,12 @@ import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore.Companion.accentColor
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.PreferenceDialogLibraryCategoriesListitemBinding
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.model.CategoryInfo
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.SwipeAndDragHelper
@ -59,12 +59,7 @@ class CategoryInfoAdapter : RecyclerView.Adapter<CategoryInfoAdapter.ViewHolder>
categoryInfo.visible = !categoryInfo.visible
holder.binding.checkbox.isChecked = categoryInfo.visible
} else {
Toast.makeText(
holder.itemView.context,
R.string.you_have_to_select_at_least_one_category,
Toast.LENGTH_SHORT
)
.show()
holder.itemView.context.showToast(R.string.you_have_to_select_at_least_one_category)
}
}
holder.binding.dragView.setOnTouchListener { _: View?, event: MotionEvent ->

View file

@ -14,15 +14,14 @@
*/
package code.name.monkey.retromusic.adapter
import android.app.Activity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.openUrl
import code.name.monkey.retromusic.model.Contributor
import code.name.monkey.retromusic.util.RetroUtil.openUrl
import code.name.monkey.retromusic.views.RetroShapeableImageView
import com.bumptech.glide.Glide
@ -65,7 +64,7 @@ class ContributorAdapter(
val contributor = contributors[position]
holder.bindData(contributor)
holder.itemView.setOnClickListener {
openUrl(it?.context as Activity, contributors[position].link)
it?.context?.openUrl(contributors[position].link)
}
}

View file

@ -25,13 +25,13 @@ import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.base.AbsMultiSelectAdapter
import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
import code.name.monkey.retromusic.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.audiocover.AudioFileCover
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.interfaces.ICallbacks
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.RetroUtil
import com.bumptech.glide.load.engine.DiskCacheStrategy
import com.bumptech.glide.signature.MediaStoreSignature
import me.zhanghai.android.fastscroll.PopupTextProvider
@ -45,7 +45,7 @@ class SongFileAdapter(
private var dataSet: List<File>,
private val itemLayoutRes: Int,
private val iCallbacks: ICallbacks?,
iCabHolder: ICabHolder?
iCabHolder: ICabHolder?,
) : AbsMultiSelectAdapter<SongFileAdapter.ViewHolder, File>(
activity, iCabHolder, R.menu.menu_media_selection
), PopupTextProvider {
@ -110,9 +110,7 @@ class SongFileAdapter(
)
)
} else {
val error = RetroUtil.getTintedVectorDrawable(
activity, R.drawable.ic_file_music, iconColor
)
val error = activity.getTintedDrawable(R.drawable.ic_file_music, iconColor)
GlideApp.with(activity)
.load(AudioFileCover(file.path))
.diskCacheStrategy(DiskCacheStrategy.NONE)
@ -132,8 +130,8 @@ class SongFileAdapter(
return dataSet[position]
}
override fun getName(`object`: File): String {
return getFileTitle(`object`)
override fun getName(model: File): String {
return getFileTitle(model)
}
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<File>) {

View file

@ -91,9 +91,9 @@ open class AlbumAdapter(
// Check if imageContainer exists so we can have a smooth transition without
// CardView clipping, if it doesn't exist in current layout set transition name to image instead.
if (holder.imageContainer != null) {
holder.imageContainer!!.setTransitionName(album.id.toString())
holder.imageContainer?.transitionName = album.id.toString()
} else {
holder.image!!.setTransitionName(album.id.toString())
holder.image?.transitionName = album.id.toString()
}
loadAlbumCover(album, holder)
}
@ -135,8 +135,8 @@ open class AlbumAdapter(
return dataSet[position]
}
override fun getName(album: Album): String {
return album.title
override fun getName(model: Album): String {
return model.title
}
override fun onMultipleItemAction(

View file

@ -85,7 +85,6 @@ class AlbumCoverPagerAdapter(
class AlbumCoverFragment : Fragment() {
private lateinit var albumCover: ImageView
private var isColorReady: Boolean = false
private lateinit var color: MediaNotificationProcessor
private lateinit var song: Song
@ -106,8 +105,6 @@ class AlbumCoverPagerAdapter(
savedInstanceState: Bundle?
): View? {
val view = inflater.inflate(getLayoutWithPlayerTheme(), container, false)
view.setTransitionName("lyrics")
albumCover = view.findViewById(R.id.player_image)
view.setOnClickListener {
if (mainActivity.getBottomSheetBehavior().state == STATE_EXPANDED) {
showLyricsDialog()
@ -158,7 +155,7 @@ class AlbumCoverPagerAdapter(
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
loadAlbumCover()
loadAlbumCover(albumCover = view.findViewById(R.id.player_image))
}
override fun onDestroyView() {
@ -166,7 +163,7 @@ class AlbumCoverPagerAdapter(
colorReceiver = null
}
private fun loadAlbumCover() {
private fun loadAlbumCover(albumCover: ImageView) {
GlideApp.with(this).asBitmapPalette().songCoverOptions(song)
//.checkIgnoreMediaStore()
.load(RetroGlideExtension.getSongModel(song))

View file

@ -92,9 +92,9 @@ class ArtistAdapter(
val transitionName =
if (albumArtistsOnly) artist.name else artist.id.toString()
if (holder.imageContainer != null) {
holder.imageContainer!!.setTransitionName(transitionName)
holder.imageContainer?.transitionName = transitionName
} else {
holder.image!!.setTransitionName(transitionName)
holder.image?.transitionName = transitionName
}
loadArtistImage(artist, holder)
}
@ -132,8 +132,8 @@ class ArtistAdapter(
return dataSet[position]
}
override fun getName(artist: Artist): String {
return artist.name
override fun getName(model: Artist): String {
return model.name
}
override fun onMultipleItemAction(

View file

@ -64,9 +64,8 @@ abstract class AbsMultiSelectAdapter<V : RecyclerView.ViewHolder?, I>(
}
protected abstract fun getIdentifier(position: Int): I?
protected open fun getName(i: I): String? {
return i.toString()
}
protected abstract fun getName(model: I): String?
protected fun isChecked(identifier: I): Boolean {
return checked.contains(identifier)

View file

@ -120,8 +120,8 @@ class PlaylistAdapter(
return dataSet[position]
}
override fun getName(playlist: PlaylistWithSongs): String {
return playlist.playlistEntity.playlistName
override fun getName(model: PlaylistWithSongs): String {
return model.playlistEntity.playlistName
}
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<PlaylistWithSongs>) {
@ -163,7 +163,7 @@ class PlaylistAdapter(
if (isInQuickSelectMode) {
toggleChecked(layoutPosition)
} else {
itemView.setTransitionName("playlist")
itemView.transitionName = "playlist"
listener.onPlaylistClick(dataSet[layoutPosition], itemView)
}
}

View file

@ -60,7 +60,7 @@ class ShuffleButtonSongAdapter(
}
} else {
super.onBindViewHolder(holder, position - 1)
val landscape = RetroUtil.isLandscape()
val landscape = RetroUtil.isLandscape
if ((PreferenceUtil.songGridSize > 2 && !landscape) || (PreferenceUtil.songGridSizeLand > 5 && landscape)) {
holder.menu?.isVisible = false
}

View file

@ -100,7 +100,7 @@ open class SongAdapter(
holder.text?.text = getSongText(song)
holder.text2?.text = getSongText(song)
loadAlbumCover(song, holder)
val landscape = RetroUtil.isLandscape()
val landscape = RetroUtil.isLandscape
if ((PreferenceUtil.songGridSize > 2 && !landscape) || (PreferenceUtil.songGridSizeLand > 5 && landscape)) {
holder.menu?.isVisible = false
}
@ -149,8 +149,8 @@ open class SongAdapter(
return dataSet[position]
}
override fun getName(song: Song): String {
return song.title
override fun getName(model: Song): String {
return model.title
}
override fun onMultipleItemAction(menuItem: MenuItem, selection: List<Song>) {

View file

@ -15,19 +15,16 @@
package code.name.monkey.retromusic.appshortcuts
import android.content.Context
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.graphics.drawable.Icon
import android.graphics.drawable.LayerDrawable
import android.os.Build
import android.util.TypedValue
import androidx.annotation.RequiresApi
import androidx.core.graphics.applyCanvas
import androidx.core.graphics.createBitmap
import androidx.core.graphics.drawable.toBitmap
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.getTintedDrawable
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil
@RequiresApi(Build.VERSION_CODES.N_MR1)
object AppShortcutIconGenerator {
@ -64,25 +61,17 @@ object AppShortcutIconGenerator {
context: Context,
iconId: Int,
foregroundColor: Int,
backgroundColor: Int
backgroundColor: Int,
): Icon {
// Get and tint foreground and background drawables
val vectorDrawable = RetroUtil.getTintedVectorDrawable(context, iconId, foregroundColor)
val backgroundDrawable = RetroUtil.getTintedVectorDrawable(
context, R.drawable.ic_app_shortcut_background, backgroundColor
)
val vectorDrawable = context.getTintedDrawable(iconId, foregroundColor)
val backgroundDrawable =
context.getTintedDrawable(R.drawable.ic_app_shortcut_background, backgroundColor)
// Squash the two drawables together
val layerDrawable = LayerDrawable(arrayOf(backgroundDrawable, vectorDrawable))
// Return as an Icon
return Icon.createWithBitmap(drawableToBitmap(layerDrawable))
}
private fun drawableToBitmap(drawable: Drawable): Bitmap {
return createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight).applyCanvas {
drawable.setBounds(0, 0, width, height)
drawable.draw(this)
}
return Icon.createWithBitmap(layerDrawable.toBitmap())
}
}

View file

@ -22,11 +22,13 @@ import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.view.View
import android.widget.RemoteViews
import androidx.core.graphics.drawable.toBitmap
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.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.service.MusicService
@ -36,7 +38,7 @@ import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_TOGGLE_
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.CustomTarget
import com.bumptech.glide.request.target.Target
import com.bumptech.glide.request.transition.Transition
@ -58,31 +60,24 @@ class AppWidgetBig : BaseAppWidget() {
)
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_audio_art)
appWidgetView.setImageViewBitmap(
R.id.button_next, createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
R.id.button_next, context.getTintedDrawable(
R.drawable.ic_skip_next,
MaterialValueHelper.getPrimaryTextColor(context, false)
), 1f
)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_prev, createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
R.id.button_prev,
context.getTintedDrawable(
R.drawable.ic_skip_previous,
MaterialValueHelper.getPrimaryTextColor(context, false)
), 1f
)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_toggle_play_pause, createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
R.id.button_toggle_play_pause,
context.getTintedDrawable(
R.drawable.ic_play_arrow_white_32dp,
MaterialValueHelper.getPrimaryTextColor(context, false)
), 1f
)
).toBitmap()
)
linkButtons(context, appWidgetView)
@ -123,33 +118,27 @@ class AppWidgetBig : BaseAppWidget() {
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,
R.id.button_toggle_play_pause,
service.getTintedDrawable(
playPauseRes,
primaryColor
), 1f
)
).toBitmap()
)
// Set prev/next button drawables
appWidgetView.setImageViewBitmap(
R.id.button_next, createBitmap(
RetroUtil.getTintedVectorDrawable(
service,
R.id.button_next,
service.getTintedDrawable(
R.drawable.ic_skip_next,
primaryColor
), 1f
)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_prev, createBitmap(
RetroUtil.getTintedVectorDrawable(
service,
R.id.button_prev,
service.getTintedDrawable(
R.drawable.ic_skip_previous,
primaryColor
), 1f
)
).toBitmap()
)
// Link actions buttons to intents
@ -167,10 +156,10 @@ class AppWidgetBig : BaseAppWidget() {
.asBitmap()
//.checkIgnoreMediaStore()
.load(RetroGlideExtension.getSongModel(song))
.into(object : SimpleTarget<Bitmap>(widgetImageSize, widgetImageSize) {
.into(object : CustomTarget<Bitmap>(widgetImageSize, widgetImageSize) {
override fun onResourceReady(
resource: Bitmap,
transition: Transition<in Bitmap>?
transition: Transition<in Bitmap>?,
) {
update(resource)
}
@ -180,6 +169,8 @@ class AppWidgetBig : BaseAppWidget() {
update(null)
}
override fun onLoadCleared(placeholder: Drawable?) {}
private fun update(bitmap: Bitmap?) {
if (bitmap == null) {
appWidgetView.setImageViewResource(

View file

@ -22,11 +22,13 @@ import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.view.View
import android.widget.RemoteViews
import androidx.core.graphics.drawable.toBitmap
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.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
@ -34,11 +36,9 @@ import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_SKIP
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_TOGGLE_PAUSE
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.CustomTarget
import com.bumptech.glide.request.target.Target
import com.bumptech.glide.request.transition.Transition
@ -56,31 +56,25 @@ class AppWidgetCard : BaseAppWidget() {
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.id.button_next,
context.getTintedDrawable(
R.drawable.ic_skip_next,
secondaryColor
), 1f
)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_prev, createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
R.id.button_prev,
context.getTintedDrawable(
R.drawable.ic_skip_previous,
secondaryColor
), 1f
)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_toggle_play_pause, createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
R.id.button_toggle_play_pause,
context.getTintedDrawable(
R.drawable.ic_play_arrow_white_32dp,
secondaryColor
), 1f
)
).toBitmap()
)
linkButtons(context, appWidgetView)
@ -109,33 +103,27 @@ class AppWidgetCard : BaseAppWidget() {
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,
R.id.button_toggle_play_pause,
service.getTintedDrawable(
playPauseRes,
MaterialValueHelper.getSecondaryTextColor(service, true)
), 1f
)
).toBitmap()
)
// Set prev/next button drawables
appWidgetView.setImageViewBitmap(
R.id.button_next, createBitmap(
RetroUtil.getTintedVectorDrawable(
service,
R.id.button_next,
service.getTintedDrawable(
R.drawable.ic_skip_next,
MaterialValueHelper.getSecondaryTextColor(service, true)
), 1f
)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_prev, createBitmap(
RetroUtil.getTintedVectorDrawable(
service,
R.id.button_prev,
service.getTintedDrawable(
R.drawable.ic_skip_previous,
MaterialValueHelper.getSecondaryTextColor(service, true)
), 1f
)
).toBitmap()
)
// Link actions buttons to intents
@ -158,10 +146,10 @@ class AppWidgetCard : BaseAppWidget() {
target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song))
.centerCrop()
.into(object : SimpleTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
.into(object : CustomTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
override fun onResourceReady(
resource: BitmapPaletteWrapper,
transition: Transition<in BitmapPaletteWrapper>?
transition: Transition<in BitmapPaletteWrapper>?,
) {
val palette = resource.palette
update(
@ -180,33 +168,26 @@ class AppWidgetCard : BaseAppWidget() {
update(null, MaterialValueHelper.getSecondaryTextColor(service, true))
}
override fun onLoadCleared(placeholder: Drawable?) {}
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
)
)
R.id.button_toggle_play_pause,
service.getTintedDrawable(playPauseRes, color).toBitmap()
)
// Set prev/next button drawables
appWidgetView.setImageViewBitmap(
R.id.button_next, ImageUtil.createBitmap(
ImageUtil.getTintedVectorDrawable(
service, R.drawable.ic_skip_next, color
)
)
R.id.button_next,
service.getTintedDrawable(R.drawable.ic_skip_next, color).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_prev, ImageUtil.createBitmap(
ImageUtil.getTintedVectorDrawable(
service, R.drawable.ic_skip_previous, color
)
)
R.id.button_prev,
service.getTintedDrawable(R.drawable.ic_skip_previous, color).toBitmap()
)
val image = getAlbumArtDrawable(service.resources, bitmap)
val image = getAlbumArtDrawable(service, bitmap)
val roundedBitmap = createRoundedBitmap(
image, imageSize, imageSize, cardRadius, 0F, cardRadius, 0F
)

View file

@ -21,25 +21,25 @@ import android.content.Intent
import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.widget.RemoteViews
import androidx.core.graphics.drawable.toBitmap
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.extensions.getTintedDrawable
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.Companion.ACTION_TOGGLE_PAUSE
import code.name.monkey.retromusic.service.MusicService.Companion.TOGGLE_FAVORITE
import code.name.monkey.retromusic.util.ImageUtil
import code.name.monkey.retromusic.util.MusicUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil
import com.bumptech.glide.Glide
import com.bumptech.glide.load.resource.bitmap.RoundedCorners
import com.bumptech.glide.request.RequestOptions
import com.bumptech.glide.request.target.SimpleTarget
import com.bumptech.glide.request.target.CustomTarget
import com.bumptech.glide.request.target.Target
import com.bumptech.glide.request.transition.Transition
import kotlinx.coroutines.Dispatchers
@ -58,13 +58,11 @@ class AppWidgetCircle : BaseAppWidget() {
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_audio_art)
val secondaryColor = MaterialValueHelper.getSecondaryTextColor(context, true)
appWidgetView.setImageViewBitmap(
R.id.button_toggle_play_pause, createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
R.id.button_toggle_play_pause,
context.getTintedDrawable(
R.drawable.ic_play_arrow,
secondaryColor
), 1f
)
).toBitmap()
)
linkButtons(context, appWidgetView)
@ -84,13 +82,11 @@ class AppWidgetCircle : BaseAppWidget() {
val playPauseRes =
if (isPlaying) R.drawable.ic_pause else R.drawable.ic_play_arrow
appWidgetView.setImageViewBitmap(
R.id.button_toggle_play_pause, createBitmap(
RetroUtil.getTintedVectorDrawable(
service,
R.id.button_toggle_play_pause,
service.getTintedDrawable(
playPauseRes,
MaterialValueHelper.getSecondaryTextColor(service, true)
), 1f
)
).toBitmap()
)
val isFavorite = runBlocking(Dispatchers.IO) {
return@runBlocking MusicUtil.repository.isSongFavorite(song.id)
@ -98,13 +94,11 @@ class AppWidgetCircle : BaseAppWidget() {
val favoriteRes =
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
appWidgetView.setImageViewBitmap(
R.id.button_toggle_favorite, createBitmap(
RetroUtil.getTintedVectorDrawable(
service,
R.id.button_toggle_favorite,
service.getTintedDrawable(
favoriteRes,
MaterialValueHelper.getSecondaryTextColor(service, true)
), 1f
)
).toBitmap()
)
// Link actions buttons to intents
@ -122,13 +116,11 @@ class AppWidgetCircle : BaseAppWidget() {
}
target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song))
.apply(
RequestOptions().transform(RoundedCorners(imageSize / 2))
)
.into(object : SimpleTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
.apply(RequestOptions.circleCropTransform())
.into(object : CustomTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
override fun onResourceReady(
resource: BitmapPaletteWrapper,
transition: Transition<in BitmapPaletteWrapper>?
transition: Transition<in BitmapPaletteWrapper>?,
) {
val palette = resource.palette
update(
@ -150,25 +142,27 @@ class AppWidgetCircle : BaseAppWidget() {
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
)
)
R.id.button_toggle_play_pause,
service.getTintedDrawable(
playPauseRes, color
).toBitmap()
)
// Set favorite button drawables
appWidgetView.setImageViewBitmap(
R.id.button_toggle_favorite, ImageUtil.createBitmap(
ImageUtil.getTintedVectorDrawable(
service, favoriteRes, color
)
)
R.id.button_toggle_favorite,
service.getTintedDrawable(
favoriteRes, color
).toBitmap()
)
if (bitmap != null) {
appWidgetView.setImageViewBitmap(R.id.image, bitmap)
}
pushUpdate(service, appWidgetIds, appWidgetView)
}
override fun onLoadCleared(placeholder: Drawable?) {}
})
}
}

View file

@ -23,11 +23,13 @@ import android.graphics.Color
import android.graphics.drawable.Drawable
import android.view.View
import android.widget.RemoteViews
import androidx.core.graphics.drawable.toBitmap
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.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
@ -35,11 +37,9 @@ import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_SKIP
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_TOGGLE_PAUSE
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.CustomTarget
import com.bumptech.glide.request.target.Target
import com.bumptech.glide.request.transition.Transition
@ -57,33 +57,27 @@ class AppWidgetClassic : BaseAppWidget() {
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_audio_art)
appWidgetView.setImageViewBitmap(
R.id.button_next,
createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
context.getTintedDrawable(
R.drawable.ic_skip_next,
MaterialValueHelper.getSecondaryTextColor(context, true)
), 1f
)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_prev,
createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
context.getTintedDrawable(
R.drawable.ic_skip_previous,
MaterialValueHelper.getSecondaryTextColor(context, true)
), 1f
)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_toggle_play_pause,
createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
context.getTintedDrawable(
R.drawable.ic_play_arrow_white_32dp,
MaterialValueHelper.getSecondaryTextColor(context, true)
), 1f
)
).toBitmap()
)
linkButtons(context, appWidgetView)
@ -129,10 +123,10 @@ class AppWidgetClassic : BaseAppWidget() {
.load(RetroGlideExtension.getSongModel(song))
//.checkIgnoreMediaStore()
.centerCrop()
.into(object : SimpleTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
.into(object : CustomTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
override fun onResourceReady(
resource: BitmapPaletteWrapper,
transition: Transition<in BitmapPaletteWrapper>?
transition: Transition<in BitmapPaletteWrapper>?,
) {
val palette = resource.palette
update(
@ -153,44 +147,37 @@ class AppWidgetClassic : BaseAppWidget() {
update(null, Color.WHITE)
}
override fun onLoadCleared(placeholder: Drawable?) {}
private fun update(bitmap: Bitmap?, color: Int) {
// Set correct drawable for pause state
val playPauseRes =
if (isPlaying) R.drawable.ic_pause else R.drawable.ic_play_arrow
appWidgetView.setImageViewBitmap(
R.id.button_toggle_play_pause,
ImageUtil.createBitmap(
ImageUtil.getTintedVectorDrawable(
service,
service.getTintedDrawable(
playPauseRes,
color
)
)
).toBitmap()
)
// Set prev/next button drawables
appWidgetView.setImageViewBitmap(
R.id.button_next,
ImageUtil.createBitmap(
ImageUtil.getTintedVectorDrawable(
service,
service.getTintedDrawable(
R.drawable.ic_skip_next,
color
)
)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_prev,
ImageUtil.createBitmap(
ImageUtil.getTintedVectorDrawable(
service,
service.getTintedDrawable(
R.drawable.ic_skip_previous,
color
)
)
).toBitmap()
)
val image = getAlbumArtDrawable(service.resources, bitmap)
val image = getAlbumArtDrawable(service, bitmap)
val roundedBitmap =
createRoundedBitmap(
image,

View file

@ -22,11 +22,13 @@ import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.view.View
import android.widget.RemoteViews
import androidx.core.graphics.drawable.toBitmap
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.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
@ -35,11 +37,9 @@ import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_SKIP
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_TOGGLE_PAUSE
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.CustomTarget
import com.bumptech.glide.request.target.Target
import com.bumptech.glide.request.transition.Transition
@ -57,31 +57,25 @@ class AppWidgetMD3 : BaseAppWidget() {
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.id.button_next,
context.getTintedDrawable(
R.drawable.ic_skip_next,
secondaryColor
), 1f
)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_prev, createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
R.id.button_prev,
context.getTintedDrawable(
R.drawable.ic_skip_previous,
secondaryColor
), 1f
)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_toggle_play_pause, createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
R.id.button_toggle_play_pause,
context.getTintedDrawable(
R.drawable.ic_play_arrow_white_32dp,
secondaryColor
), 1f
)
).toBitmap()
)
linkButtons(context, appWidgetView)
@ -110,33 +104,27 @@ class AppWidgetMD3 : BaseAppWidget() {
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,
R.id.button_toggle_play_pause,
service.getTintedDrawable(
playPauseRes,
MaterialValueHelper.getSecondaryTextColor(service, true)
), 1f
)
).toBitmap()
)
// Set prev/next button drawables
appWidgetView.setImageViewBitmap(
R.id.button_next, createBitmap(
RetroUtil.getTintedVectorDrawable(
service,
R.id.button_next,
service.getTintedDrawable(
R.drawable.ic_skip_next,
MaterialValueHelper.getSecondaryTextColor(service, true)
), 1f
)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_prev, createBitmap(
RetroUtil.getTintedVectorDrawable(
service,
R.id.button_prev,
service.getTintedDrawable(
R.drawable.ic_skip_previous,
MaterialValueHelper.getSecondaryTextColor(service, true)
), 1f
)
).toBitmap()
)
// Link actions buttons to intents
@ -159,10 +147,10 @@ class AppWidgetMD3 : BaseAppWidget() {
target = GlideApp.with(service).asBitmapPalette().songCoverOptions(song)
.load(RetroGlideExtension.getSongModel(song))
.centerCrop()
.into(object : SimpleTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
.into(object : CustomTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
override fun onResourceReady(
resource: BitmapPaletteWrapper,
transition: Transition<in BitmapPaletteWrapper>?
transition: Transition<in BitmapPaletteWrapper>?,
) {
val palette = resource.palette
update(
@ -181,33 +169,26 @@ class AppWidgetMD3 : BaseAppWidget() {
update(null, MaterialValueHelper.getSecondaryTextColor(service, true))
}
override fun onLoadCleared(placeholder: Drawable?) {}
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
)
)
R.id.button_toggle_play_pause,
service.getTintedDrawable(playPauseRes, color).toBitmap()
)
// Set prev/next button drawables
appWidgetView.setImageViewBitmap(
R.id.button_next, ImageUtil.createBitmap(
ImageUtil.getTintedVectorDrawable(
service, R.drawable.ic_skip_next, color
)
)
R.id.button_next,
service.getTintedDrawable(R.drawable.ic_skip_next, color).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_prev, ImageUtil.createBitmap(
ImageUtil.getTintedVectorDrawable(
service, R.drawable.ic_skip_previous, color
)
)
R.id.button_prev,
service.getTintedDrawable(R.drawable.ic_skip_previous, color).toBitmap()
)
val image = getAlbumArtDrawable(service.resources, bitmap)
val image = getAlbumArtDrawable(service, bitmap)
val roundedBitmap = createRoundedBitmap(
image,
imageSize,

View file

@ -22,11 +22,13 @@ import android.graphics.Bitmap
import android.graphics.drawable.Drawable
import android.view.View
import android.widget.RemoteViews
import androidx.core.graphics.drawable.toBitmap
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.extensions.getTintedDrawable
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper
@ -35,9 +37,8 @@ import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_SKIP
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_TOGGLE_PAUSE
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.CustomTarget
import com.bumptech.glide.request.target.Target
import com.bumptech.glide.request.transition.Transition
@ -55,33 +56,26 @@ class AppWidgetSmall : BaseAppWidget() {
appWidgetView.setImageViewResource(R.id.image, R.drawable.default_audio_art)
appWidgetView.setImageViewBitmap(
R.id.button_next,
createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
context.getTintedDrawable(
R.drawable.ic_skip_next,
MaterialValueHelper.getSecondaryTextColor(context, true)
), 1f
)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_prev,
createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
context.getTintedDrawable(
R.drawable.ic_skip_previous,
MaterialValueHelper.getSecondaryTextColor(context, true)
), 1f
)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_toggle_play_pause,
createBitmap(
RetroUtil.getTintedVectorDrawable(
context,
context.getTintedDrawable(
R.drawable.ic_play_arrow_white_32dp,
MaterialValueHelper.getSecondaryTextColor(context, true)
), 1f
)
).toBitmap()
)
linkButtons(context, appWidgetView)
@ -132,10 +126,10 @@ class AppWidgetSmall : BaseAppWidget() {
//.checkIgnoreMediaStore()
.load(RetroGlideExtension.getSongModel(song))
.centerCrop()
.into(object : SimpleTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
.into(object : CustomTarget<BitmapPaletteWrapper>(imageSize, imageSize) {
override fun onResourceReady(
resource: BitmapPaletteWrapper,
transition: Transition<in BitmapPaletteWrapper>?
transition: Transition<in BitmapPaletteWrapper>?,
) {
val palette = resource.palette
update(
@ -154,35 +148,30 @@ class AppWidgetSmall : BaseAppWidget() {
update(null, MaterialValueHelper.getSecondaryTextColor(service, true))
}
override fun onLoadCleared(placeholder: Drawable?) {
update(null, MaterialValueHelper.getSecondaryTextColor(service, true))
}
private fun update(bitmap: Bitmap?, color: Int) {
// 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, color
), 1f
)
R.id.button_toggle_play_pause,
service.getTintedDrawable(playPauseRes, color).toBitmap()
)
// Set prev/next button drawables
appWidgetView.setImageViewBitmap(
R.id.button_next, createBitmap(
RetroUtil.getTintedVectorDrawable(
service, R.drawable.ic_skip_next, color
), 1f
)
R.id.button_next,
service.getTintedDrawable(R.drawable.ic_skip_next, color).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_prev, createBitmap(
RetroUtil.getTintedVectorDrawable(
service, R.drawable.ic_skip_previous, color
), 1f
)
R.id.button_prev,
service.getTintedDrawable(R.drawable.ic_skip_previous, color).toBitmap()
)
val image = getAlbumArtDrawable(service.resources, bitmap)
val image = getAlbumArtDrawable(service, bitmap)
val roundedBitmap = createRoundedBitmap(
image, imageSize, imageSize, cardRadius, 0f, 0f, 0f
)

View file

@ -21,48 +21,41 @@ import android.content.Intent
import android.view.View
import android.widget.RemoteViews
import androidx.core.content.ContextCompat
import androidx.core.graphics.drawable.toBitmap
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.App
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.extensions.getTintedDrawable
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_REWIND
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_SKIP
import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_TOGGLE_PAUSE
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil
class AppWidgetText : BaseAppWidget() {
override fun defaultAppWidget(context: Context, appWidgetIds: IntArray) {
val appWidgetView = RemoteViews(context.packageName, R.layout.app_widget_text)
appWidgetView.setImageViewBitmap(
R.id.button_next, createBitmap(
RetroUtil.getTintedVectorDrawable(
context, R.drawable.ic_skip_next, ContextCompat.getColor(
R.id.button_next,
context.getTintedDrawable(R.drawable.ic_skip_next, ContextCompat.getColor(
context, R.color.md_white_1000
)
), 1f
)
)).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_prev, createBitmap(
RetroUtil.getTintedVectorDrawable(
context, R.drawable.ic_skip_previous, ContextCompat.getColor(
R.id.button_prev,
context.getTintedDrawable(R.drawable.ic_skip_previous, ContextCompat.getColor(
context, R.color.md_white_1000
)
), 1f
)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_toggle_play_pause, createBitmap(
RetroUtil.getTintedVectorDrawable(
context, R.drawable.ic_play_arrow_white_32dp, ContextCompat.getColor(
R.id.button_toggle_play_pause,
context.getTintedDrawable(R.drawable.ic_play_arrow_white_32dp, ContextCompat.getColor(
context, R.color.md_white_1000
)
), 1f
)
).toBitmap()
)
appWidgetView.setTextColor(
@ -132,35 +125,29 @@ class AppWidgetText : BaseAppWidget() {
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(
App.getContext(), playPauseRes, ContextCompat.getColor(
App.getContext(), R.color.md_white_1000
)
), 1f
)
R.id.button_toggle_play_pause,
service.getTintedDrawable(playPauseRes, ContextCompat.getColor(
service, R.color.md_white_1000)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_next, createBitmap(
RetroUtil.getTintedVectorDrawable(
App.getContext(),
R.id.button_next,
service.getTintedDrawable(
R.drawable.ic_skip_next,
ContextCompat.getColor(
App.getContext(), R.color.md_white_1000
)
), 1f
service,
R.color.md_white_1000
)
).toBitmap()
)
appWidgetView.setImageViewBitmap(
R.id.button_prev, createBitmap(
RetroUtil.getTintedVectorDrawable(
App.getContext(),
R.id.button_prev,
service.getTintedDrawable(
R.drawable.ic_skip_previous,
ContextCompat.getColor(
App.getContext(), R.color.md_white_1000
)
), 1f
service, R.color.md_white_1000
)
).toBitmap()
)
pushUpdate(service.applicationContext, appWidgetIds, appWidgetView)

View file

@ -20,16 +20,12 @@ import android.appwidget.AppWidgetProvider
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.res.Resources
import android.graphics.*
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import android.widget.RemoteViews
import androidx.core.content.ContextCompat
import androidx.core.graphics.applyCanvas
import androidx.core.graphics.createBitmap
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.service.MusicService
@ -116,11 +112,11 @@ abstract class BaseAppWidget : AppWidgetProvider() {
abstract fun performUpdate(service: MusicService, appWidgetIds: IntArray?)
protected fun getAlbumArtDrawable(resources: Resources, bitmap: Bitmap?): Drawable {
protected fun getAlbumArtDrawable(context: Context, bitmap: Bitmap?): Drawable {
return if (bitmap == null) {
ContextCompat.getDrawable(App.getContext(), R.drawable.default_audio_art)!!
ContextCompat.getDrawable(context, R.drawable.default_audio_art)!!
} else {
BitmapDrawable(resources, bitmap)
BitmapDrawable(context.resources, bitmap)
}
}
@ -171,16 +167,6 @@ abstract class BaseAppWidget : AppWidgetProvider() {
return rounded
}
fun createBitmap(drawable: Drawable, sizeMultiplier: Float): Bitmap {
return createBitmap(
(drawable.intrinsicWidth * sizeMultiplier).toInt(),
(drawable.intrinsicHeight * sizeMultiplier).toInt(),
).applyCanvas {
drawable.setBounds(0, 0, this.width, this.height)
drawable.draw(this)
}
}
protected fun composeRoundedRectPath(
rect: RectF,
tl: Float,

View file

@ -4,8 +4,9 @@ import android.content.Context
import android.net.Uri
import android.support.v4.media.MediaBrowserCompat
import android.support.v4.media.MediaDescriptionCompat
import androidx.core.content.res.ResourcesCompat
import androidx.core.graphics.drawable.toBitmap
import androidx.core.os.bundleOf
import code.name.monkey.retromusic.util.ImageUtil
internal object AutoMediaItem {
@ -13,7 +14,7 @@ internal object AutoMediaItem {
return Builder(context)
}
internal class Builder(val mContext: Context) {
internal class Builder(private val mContext: Context) {
private var mBuilder: MediaDescriptionCompat.Builder?
private var mFlags = 0
fun path(fullPath: String): Builder {
@ -42,13 +43,11 @@ internal object AutoMediaItem {
fun icon(iconDrawableId: Int): Builder {
mBuilder?.setIconBitmap(
ImageUtil.createBitmap(
ImageUtil.getVectorDrawable(
ResourcesCompat.getDrawable(
mContext.resources,
iconDrawableId,
mContext.theme
)
)
)?.toBitmap()
)
return this
}

View file

@ -79,6 +79,5 @@ object CastHelper {
setMetadata(musicMetadata)
setStreamDuration(song.duration)
}.build()
}
}

View file

@ -1,3 +1,5 @@
@file:Suppress("unused")
package code.name.monkey.retromusic.cast
import android.content.Context

View file

@ -3,20 +3,12 @@ package code.name.monkey.retromusic.cast
import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.cast.framework.SessionManagerListener
interface RetroSessionManager : SessionManagerListener<CastSession> {
override fun onSessionResuming(p0: CastSession, p1: String) {
interface RetroSessionManagerListener : SessionManagerListener<CastSession> {
override fun onSessionResuming(p0: CastSession, p1: String) {}
}
override fun onSessionStartFailed(p0: CastSession, p1: Int) {
}
override fun onSessionResumeFailed(p0: CastSession, p1: Int) {
}
override fun onSessionEnding(p0: CastSession) {
}
override fun onSessionStartFailed(p0: CastSession, p1: Int) {}
override fun onSessionResumeFailed(p0: CastSession, p1: Int) {}
override fun onSessionEnding(castSession: CastSession) {}
}

View file

@ -17,24 +17,11 @@ class RetroWebServer(val context: Context) : NanoHTTPD(SERVER_PORT) {
const val PART_COVER_ART = "coverart"
const val PART_SONG = "song"
const val PARAM_ID = "id"
private var mRetroWebServer: RetroWebServer? = null
fun getInstance(context: Context): RetroWebServer {
if (mRetroWebServer == null) {
mRetroWebServer = RetroWebServer(context)
}
return mRetroWebServer!!
}
}
override fun serve(
uri: String?,
method: Method?,
headers: MutableMap<String, String>?,
parms: MutableMap<String, String>?,
files: MutableMap<String, String>?
): Response {
if (uri?.contains(PART_COVER_ART) == true) {
val albumId = parms?.get(PARAM_ID) ?: return errorResponse()
override fun serve(session: IHTTPSession?): Response {
if (session?.uri?.contains(PART_COVER_ART) == true) {
val albumId = session.parameters?.get(PARAM_ID)?.get(0) ?: return errorResponse()
val albumArtUri = MusicUtil.getMediaStoreAlbumCoverUri(albumId.toLong())
val fis: InputStream?
try {
@ -43,12 +30,12 @@ class RetroWebServer(val context: Context) : NanoHTTPD(SERVER_PORT) {
return errorResponse()
}
return newChunkedResponse(Status.OK, MIME_TYPE_IMAGE, fis)
} else if (uri?.contains(PART_SONG) == true) {
val songId = parms?.get(PARAM_ID) ?: return errorResponse()
} else if (session?.uri?.contains(PART_SONG) == true) {
val songId = session.parameters?.get(PARAM_ID)?.get(0) ?: return errorResponse()
val songUri = MusicUtil.getSongFileUri(songId.toLong())
val songPath = MusicUtil.getSongFilePath(context, songUri)
val song = File(songPath)
return serveFile(headers!!, song, MIME_TYPE_AUDIO)
return serveFile(session.headers!!, song, MIME_TYPE_AUDIO)
}
return newFixedLengthResponse(Status.NOT_FOUND, MIME_PLAINTEXT, "Not Found")
}
@ -120,7 +107,7 @@ class RetroWebServer(val context: Context) : NanoHTTPD(SERVER_PORT) {
} else {
res = newFixedLengthResponse(
Status.OK, mime,
FileInputStream(file), file.length()
file.inputStream(), file.length()
)
res.addHeader("Accept-Ranges", "bytes")
res.addHeader("Content-Length", "" + fileLen)

View file

@ -16,7 +16,6 @@ package code.name.monkey.retromusic.dialogs
import android.app.Dialog
import android.os.Bundle
import android.widget.ArrayAdapter
import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment
import code.name.monkey.retromusic.EXTRA_PLAYLISTS
@ -50,12 +49,6 @@ class AddToPlaylistDialog : DialogFragment() {
}
}
private fun playlistAdapter(playlists: List<String>): ArrayAdapter<String> {
val adapter = ArrayAdapter<String>(requireContext(), R.layout.item_simple_text, R.id.title)
adapter.addAll(playlists)
return adapter
}
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val playlistEntities = extraNotNull<List<PlaylistEntity>>(EXTRA_PLAYLISTS).value
val songs = extraNotNull<List<Song>>(EXTRA_SONG).value
@ -65,18 +58,17 @@ class AddToPlaylistDialog : DialogFragment() {
playlistNames.add(entity.playlistName)
}
return materialDialog(R.string.add_playlist_title)
.setAdapter(
playlistAdapter(playlistNames)
) { dialog, which ->
.setItems(playlistNames.toTypedArray()) { dialog, which->
if (which == 0) {
showCreateDialog(songs)
} else {
libraryViewModel.addToPlaylist(playlistNames[which], songs)
libraryViewModel.addToPlaylist(requireContext(), playlistNames[which], songs)
}
dialog.dismiss()
}
.setNegativeButton(R.string.action_cancel, null)
.create().colorButtons()
.create()
.colorButtons()
}
private fun showCreateDialog(songs: List<Song>) {

View file

@ -4,19 +4,19 @@ import android.Manifest
import android.app.Dialog
import android.content.pm.PackageManager
import android.os.Bundle
import android.os.Environment
import androidx.core.app.ActivityCompat
import androidx.fragment.app.DialogFragment
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.util.getExternalStorageDirectory
import com.afollestad.materialdialogs.MaterialDialog
import com.afollestad.materialdialogs.list.listItems
import com.afollestad.materialdialogs.list.updateListItems
import java.io.File
class BlacklistFolderChooserDialog : DialogFragment() {
private var initialPath: String = Environment.getExternalStorageDirectory().absolutePath
private var initialPath: String = getExternalStorageDirectory().absolutePath
private var parentFolder: File? = null
private var parentContents: Array<File>? = null
private var canGoUp = false
@ -97,7 +97,7 @@ class BlacklistFolderChooserDialog : DialogFragment() {
parentFolder = parentContents?.getOrNull(if (canGoUp) i - 1 else i)
canGoUp = true
if (parentFolder?.absolutePath == "/storage/emulated") {
parentFolder = Environment.getExternalStorageDirectory()
parentFolder = getExternalStorageDirectory()
}
}
reload()

View file

@ -64,11 +64,12 @@ class CreatePlaylistDialog : DialogFragment() {
) { _, _ ->
val playlistName = playlistView.text.toString()
if (!TextUtils.isEmpty(playlistName)) {
libraryViewModel.addToPlaylist(playlistName, songs)
libraryViewModel.addToPlaylist(requireContext(), playlistName, songs)
} else {
playlistContainer.error = "Playlist name can't be empty"
}
}
.setNegativeButton(R.string.action_cancel, null)
.create()
.colorButtons()
}

View file

@ -16,7 +16,6 @@ package code.name.monkey.retromusic.dialogs
import android.app.Dialog
import android.os.Bundle
import android.view.LayoutInflater
import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment
import code.name.monkey.retromusic.EXTRA_PLAYLIST_ID
@ -48,7 +47,7 @@ class RenamePlaylistDialog : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val playlistEntity = extraNotNull<PlaylistEntity>(EXTRA_PLAYLIST_ID).value
val layout = LayoutInflater.from(requireContext()).inflate(R.layout.dialog_playlist, null)
val layout = layoutInflater.inflate(R.layout.dialog_playlist, null)
val inputEditText: TextInputEditText = layout.findViewById(R.id.actionNewPlaylist)
val nameContainer: TextInputLayout = layout.findViewById(R.id.actionNewPlaylistContainer)
nameContainer.accentColor()

View file

@ -22,14 +22,10 @@ import androidx.core.os.bundleOf
import androidx.fragment.app.DialogFragment
import androidx.lifecycle.lifecycleScope
import code.name.monkey.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.EXTRA_PLAYLIST
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.db.PlaylistWithSongs
import code.name.monkey.retromusic.extensions.colorButtons
import code.name.monkey.retromusic.extensions.createNewFile
import code.name.monkey.retromusic.extensions.extraNotNull
import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.helper.M3UWriter
import code.name.monkey.retromusic.util.PlaylistsUtil
import kotlinx.coroutines.Dispatchers
@ -64,25 +60,19 @@ class SavePlaylistDialog : DialogFragment() {
playlistWithSongs
)
withContext(Dispatchers.Main) {
Toast.makeText(
requireContext(),
String.format(
requireContext().getString(R.string.saved_playlist_to),
data?.lastPathSegment
),
showToast(
requireContext().getString(R.string.saved_playlist_to,
data?.lastPathSegment),
Toast.LENGTH_LONG
).show()
)
dismiss()
}
}
}
} catch (e: Exception) {
Toast.makeText(
context,
"Something went wrong : " + e.message,
Toast.LENGTH_SHORT
showToast(
"Something went wrong : " + e.message
)
.show()
}
}
} else {
@ -95,11 +85,10 @@ class SavePlaylistDialog : DialogFragment() {
) { _, _ ->
}
withContext(Dispatchers.Main) {
Toast.makeText(
requireContext(),
String.format(App.getContext().getString(R.string.saved_playlist_to), file),
showToast(
getString(R.string.saved_playlist_to, file),
Toast.LENGTH_LONG
).show()
)
dismiss()
}
}

View file

@ -19,60 +19,50 @@ import android.content.Context
import android.os.Bundle
import android.text.Spanned
import android.util.Log
import android.view.LayoutInflater
import android.widget.TextView
import androidx.annotation.NonNull
import androidx.core.os.bundleOf
import androidx.core.text.parseAsHtml
import androidx.fragment.app.DialogFragment
import code.name.monkey.retromusic.EXTRA_SONG
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.DialogFileDetailsBinding
import code.name.monkey.retromusic.extensions.colorButtons
import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.MusicUtil
import org.jaudiotagger.audio.AudioFileIO
import org.jaudiotagger.audio.exceptions.CannotReadException
import org.jaudiotagger.audio.exceptions.InvalidAudioFrameException
import org.jaudiotagger.audio.exceptions.ReadOnlyFileException
import org.jaudiotagger.tag.TagException
import java.io.File
import java.io.IOException
class SongDetailDialog : DialogFragment() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val context: Context = requireContext()
val dialogView = LayoutInflater.from(context).inflate(R.layout.dialog_file_details, null)
val binding = DialogFileDetailsBinding.inflate(layoutInflater)
val song = requireArguments().getParcelable<Song>(EXTRA_SONG)
val fileName: TextView = dialogView.findViewById(R.id.fileName)
val filePath: TextView = dialogView.findViewById(R.id.filePath)
val fileSize: TextView = dialogView.findViewById(R.id.fileSize)
val dateModified: TextView = dialogView.findViewById(R.id.dateModified)
val fileFormat: TextView = dialogView.findViewById(R.id.fileFormat)
val trackLength: TextView = dialogView.findViewById(R.id.trackLength)
val bitRate: TextView = dialogView.findViewById(R.id.bitrate)
val samplingRate: TextView = dialogView.findViewById(R.id.samplingRate)
with(binding) {
fileName.text = makeTextWithTitle(context, R.string.label_file_name, "-")
filePath.text = makeTextWithTitle(context, R.string.label_file_path, "-")
fileSize.text = makeTextWithTitle(context, R.string.label_file_size, "-")
fileFormat.text = makeTextWithTitle(context, R.string.label_file_format, "-")
trackLength.text = makeTextWithTitle(context, R.string.label_track_length, "-")
bitRate.text = makeTextWithTitle(context, R.string.label_bit_rate, "-")
bitrate.text = makeTextWithTitle(context, R.string.label_bit_rate, "-")
samplingRate.text = makeTextWithTitle(context, R.string.label_sampling_rate, "-")
}
if (song != null) {
val songFile = File(song.data)
if (songFile.exists()) {
fileName.text = makeTextWithTitle(context, R.string.label_file_name, songFile.name)
filePath.text =
binding.fileName.text =
makeTextWithTitle(context, R.string.label_file_name, songFile.name)
binding.filePath.text =
makeTextWithTitle(context, R.string.label_file_path, songFile.absolutePath)
dateModified.text = makeTextWithTitle(context, R.string.label_last_modified,
MusicUtil.getDateModifiedString(songFile.lastModified()))
binding.dateModified.text = makeTextWithTitle(
context, R.string.label_last_modified,
MusicUtil.getDateModifiedString(songFile.lastModified())
)
fileSize.text =
binding.fileSize.text =
makeTextWithTitle(
context,
R.string.label_file_size,
@ -82,56 +72,28 @@ class SongDetailDialog : DialogFragment() {
val audioFile = AudioFileIO.read(songFile)
val audioHeader = audioFile.audioHeader
fileFormat.text =
binding.fileFormat.text =
makeTextWithTitle(context, R.string.label_file_format, audioHeader.format)
trackLength.text = makeTextWithTitle(
binding.trackLength.text = makeTextWithTitle(
context,
R.string.label_track_length,
MusicUtil.getReadableDurationString((audioHeader.trackLength * 1000).toLong())
)
bitRate.text = makeTextWithTitle(
binding.bitrate.text = makeTextWithTitle(
context,
R.string.label_bit_rate,
audioHeader.bitRate + " kb/s"
)
samplingRate.text =
binding.samplingRate.text =
makeTextWithTitle(
context,
R.string.label_sampling_rate,
audioHeader.sampleRate + " Hz"
)
} catch (@NonNull e: CannotReadException) {
} catch (e: Exception) {
Log.e(TAG, "error while reading the song file", e)
// fallback
trackLength.text = makeTextWithTitle(
context,
R.string.label_track_length,
MusicUtil.getReadableDurationString(song.duration)
)
} catch (@NonNull e: IOException) {
Log.e(TAG, "error while reading the song file", e)
trackLength.text = makeTextWithTitle(
context,
R.string.label_track_length,
MusicUtil.getReadableDurationString(song.duration)
)
} catch (@NonNull e: TagException) {
Log.e(TAG, "error while reading the song file", e)
trackLength.text = makeTextWithTitle(
context,
R.string.label_track_length,
MusicUtil.getReadableDurationString(song.duration)
)
} catch (@NonNull e: ReadOnlyFileException) {
Log.e(TAG, "error while reading the song file", e)
trackLength.text = makeTextWithTitle(
context,
R.string.label_track_length,
MusicUtil.getReadableDurationString(song.duration)
)
} catch (@NonNull e: InvalidAudioFrameException) {
Log.e(TAG, "error while reading the song file", e)
trackLength.text = makeTextWithTitle(
binding.trackLength.text = makeTextWithTitle(
context,
R.string.label_track_length,
MusicUtil.getReadableDurationString(song.duration)
@ -139,8 +101,9 @@ class SongDetailDialog : DialogFragment() {
}
} else {
// fallback
fileName.text = makeTextWithTitle(context, R.string.label_file_name, song.title)
trackLength.text = makeTextWithTitle(
binding.fileName.text =
makeTextWithTitle(context, R.string.label_file_name, song.title)
binding.trackLength.text = makeTextWithTitle(
context,
R.string.label_track_length,
MusicUtil.getReadableDurationString(song.duration)
@ -149,7 +112,7 @@ class SongDetailDialog : DialogFragment() {
}
return materialDialog(R.string.action_details)
.setPositiveButton(android.R.string.ok, null)
.setView(dialogView)
.setView(binding.root)
.create()
.colorButtons()
}

View file

@ -46,6 +46,7 @@ class SongShareDialog : DialogFragment() {
) { _, which ->
withAction(which, song, listening)
}
.setNegativeButton(R.string.action_cancel, null)
.create()
.colorButtons()
}

View file

@ -6,7 +6,9 @@ import android.os.Build
import android.view.View
import android.view.View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR
import android.view.WindowManager
import android.view.inputmethod.InputMethodManager
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.getSystemService
import androidx.core.view.*
import androidx.fragment.app.FragmentActivity
import code.name.monkey.appthemehelper.util.ColorUtil
@ -222,3 +224,12 @@ fun AppCompatActivity.setStatusBarColorPreMarshmallow(color: Int) {
window.statusBarColor = ColorUtil.darkenColor(color)
}
}
fun AppCompatActivity.hideSoftKeyboard() {
val currentFocus: View? = currentFocus
if (currentFocus != null) {
val inputMethodManager =
getSystemService<InputMethodManager>()
inputMethodManager?.hideSoftInputFromWindow(currentFocus.windowToken, 0)
}
}

View file

@ -36,7 +36,6 @@ import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.ATHUtil
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.MaterialValueHelper
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.util.PreferenceUtil.materialYou
import com.google.android.material.button.MaterialButton
@ -131,12 +130,12 @@ fun Slider.accent() {
fun Button.accentTextColor() {
if (materialYou) return
setTextColor(ThemeStore.accentColor(App.getContext()))
setTextColor(context.accentColor())
}
fun MaterialButton.accentBackgroundColor() {
if (materialYou) return
backgroundTintList = ColorStateList.valueOf(ThemeStore.accentColor(App.getContext()))
backgroundTintList = ColorStateList.valueOf(context.accentColor())
}
fun MaterialButton.accentOutlineColor() {

View file

@ -0,0 +1,26 @@
package code.name.monkey.retromusic.extensions
import android.content.Context
import android.content.res.Configuration
import android.graphics.drawable.Drawable
import android.widget.Toast
import androidx.annotation.ColorInt
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
fun Context.showToast(@StringRes stringRes: Int, duration: Int = Toast.LENGTH_SHORT) {
showToast(getString(stringRes), duration)
}
fun Context.showToast(message: String, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(this, message, duration).show()
}
val Context.isLandscape: Boolean get() = resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
val Context.isTablet: Boolean get() = resources.configuration.smallestScreenWidthDp >= 600
fun Context.getTintedDrawable(@DrawableRes id: Int, @ColorInt color: Int): Drawable {
return ContextCompat.getDrawable(this, id)?.tint(color)!!
}

View file

@ -15,17 +15,23 @@
package code.name.monkey.retromusic.extensions
import androidx.appcompat.app.AlertDialog
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.Fragment
import code.name.monkey.retromusic.BuildConfig
import code.name.monkey.retromusic.R
import com.afollestad.materialdialogs.MaterialDialog
import com.google.android.material.dialog.MaterialAlertDialogBuilder
fun DialogFragment.materialDialog(title: Int): MaterialAlertDialogBuilder {
return MaterialAlertDialogBuilder(
fun Fragment.materialDialog(title: Int): MaterialAlertDialogBuilder {
return if (BuildConfig.DEBUG) {
MaterialAlertDialogBuilder(
requireContext(),
R.style.MaterialAlertDialogTheme
).setTitle(title)
)
} else {
MaterialAlertDialogBuilder(
requireContext()
)
}.setTitle(title)
}
fun AlertDialog.colorButtons(): AlertDialog {

View file

@ -22,11 +22,12 @@ import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable
import androidx.annotation.DimenRes
import androidx.annotation.DrawableRes
import androidx.core.graphics.drawable.toBitmap
fun Context.scaledDrawableResources(
@DrawableRes id: Int,
@DimenRes width: Int,
@DimenRes height: Int
@DimenRes height: Int,
): Drawable {
val w = resources.getDimension(width).toInt()
val h = resources.getDimension(height).toInt()
@ -39,6 +40,10 @@ fun Context.scaledDrawable(@DrawableRes id: Int, width: Int, height: Int): Drawa
return BitmapDrawable(resources, bmpScaled)
}
fun Drawable.toBitmap(scaleFactor: Float, config: Bitmap.Config? = null): Bitmap {
return toBitmap((intrinsicHeight*scaleFactor).toInt(), (intrinsicWidth*scaleFactor).toInt(), config)
}
fun Drawable.getBitmapDrawable(): Bitmap {
val bmp = Bitmap.createBitmap(bounds.width(), bounds.height(), Bitmap.Config.ARGB_8888)
val canvas = Canvas(bmp)

View file

@ -0,0 +1,6 @@
package code.name.monkey.retromusic.extensions
import java.io.BufferedOutputStream
import java.util.zip.ZipOutputStream
fun BufferedOutputStream.zipOutputStream(): ZipOutputStream = ZipOutputStream(this)

View file

@ -24,7 +24,6 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.content.getSystemService
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentManager
import androidx.navigation.fragment.NavHostFragment
import code.name.monkey.retromusic.util.PreferenceUtil
import com.google.android.material.appbar.MaterialToolbar
@ -58,12 +57,6 @@ inline fun <reified T : Any> Fragment.extraNotNull(key: String, default: T? = nu
requireNotNull(if (value is T) value else default) { key }
}
val NavHostFragment.currentFragment: Fragment?
get() = targetFragment
val FragmentManager.currentNavigationFragment: Fragment?
get() = primaryNavigationFragment?.childFragmentManager?.fragments?.first()
fun AppCompatActivity.currentFragment(navHostId: Int): Fragment? {
val navHostFragment: NavHostFragment =
supportFragmentManager.findFragmentById(navHostId) as NavHostFragment
@ -80,12 +73,12 @@ fun <T> Fragment.whichFragment(@IdRes id: Int): T {
return childFragmentManager.findFragmentById(id) as T
}
fun Fragment.showToast(@StringRes stringRes: Int) {
showToast(getString(stringRes))
fun Fragment.showToast(@StringRes stringRes: Int, duration: Int = Toast.LENGTH_SHORT) {
showToast(getString(stringRes), duration)
}
fun Fragment.showToast(message: String) {
Toast.makeText(requireContext(), message, Toast.LENGTH_SHORT).show()
fun Fragment.showToast(message: String, duration: Int = Toast.LENGTH_SHORT) {
Toast.makeText(requireContext(), message, duration).show()
}
fun Context.getDrawableCompat(@DrawableRes drawableRes: Int): Drawable {

View file

@ -8,6 +8,6 @@ fun WindowInsetsCompat?.safeGetBottomInsets(): Int {
return if (PreferenceUtil.isFullScreenMode) {
return 0
} else {
this?.getInsets(WindowInsetsCompat.Type.systemBars())?.bottom ?: RetroUtil.getNavigationBarHeight()
this?.getInsets(WindowInsetsCompat.Type.systemBars())?.bottom ?: RetroUtil.navigationBarHeight
}
}

View file

@ -1,10 +1,12 @@
package code.name.monkey.retromusic.extensions
import android.app.Activity
import android.content.Context
import android.content.Intent
import android.net.Uri
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.net.toUri
import androidx.fragment.app.Fragment
import java.io.OutputStream
@ -30,3 +32,15 @@ fun Fragment.createNewFile(
}
startForResult.launch(intent)
}
fun Context.openUrl(url: String) {
val i = Intent(Intent.ACTION_VIEW)
i.data = url.toUri()
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(i)
}
fun Fragment.openUrl(url: String) {
requireContext().openUrl(url)
}

View file

@ -16,10 +16,13 @@ package code.name.monkey.retromusic.extensions
import android.animation.Animator
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.graphics.drawable.BitmapDrawable
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver
import android.view.animation.AnimationUtils
import android.view.inputmethod.InputMethodManager
import android.widget.EditText
import androidx.annotation.LayoutRes
@ -32,6 +35,7 @@ import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.bottomsheet.BottomSheetBehavior
import dev.chrisbanes.insetter.applyInsetter
@ -58,6 +62,84 @@ fun EditText.appHandleColor(): EditText {
return this
}
/**
* Potentially animate showing a [BottomNavigationView].
*
* Abruptly changing the visibility leads to a re-layout of main content, animating
* `translationY` leaves a gap where the view was that content does not fill.
*
* Instead, take a snapshot of the view, and animate this in, only changing the visibility (and
* thus layout) when the animation completes.
*/
fun BottomNavigationView.show() {
if (isVisible) return
val parent = parent as ViewGroup
// View needs to be laid out to create a snapshot & know position to animate. If view isn't
// laid out yet, need to do this manually.
if (!isLaidOut) {
measure(
View.MeasureSpec.makeMeasureSpec(parent.width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(parent.height, View.MeasureSpec.AT_MOST)
)
layout(parent.left, parent.height - measuredHeight, parent.right, parent.height)
}
val drawable = BitmapDrawable(context.resources, drawToBitmap())
drawable.setBounds(left, parent.height, right, parent.height + height)
parent.overlay.add(drawable)
ValueAnimator.ofInt(parent.height, top).apply {
duration = 300
interpolator = AnimationUtils.loadInterpolator(
context,
android.R.interpolator.linear_out_slow_in
)
addUpdateListener {
val newTop = it.animatedValue as Int
drawable.setBounds(left, newTop, right, newTop + height)
}
doOnEnd {
parent.overlay.remove(drawable)
isVisible = true
}
start()
}
}
/**
* Potentially animate hiding a [BottomNavigationView].
*
* Abruptly changing the visibility leads to a re-layout of main content, animating
* `translationY` leaves a gap where the view was that content does not fill.
*
* Instead, take a snapshot, instantly hide the view (so content lays out to fill), then animate
* out the snapshot.
*/
fun BottomNavigationView.hide() {
if (isGone) return
val drawable = BitmapDrawable(context.resources, drawToBitmap())
val parent = parent as ViewGroup
drawable.setBounds(left, top, right, bottom)
parent.overlay.add(drawable)
isGone = true
ValueAnimator.ofInt(top, parent.height).apply {
duration = 300L
interpolator = AnimationUtils.loadInterpolator(
context,
android.R.interpolator.fast_out_linear_in
)
addUpdateListener {
val newTop = it.animatedValue as Int
drawable.setBounds(left, newTop, right, newTop + height)
}
doOnEnd {
parent.overlay.remove(drawable)
}
start()
}
}
fun View.translateYAnimate(value: Float): Animator {
return ObjectAnimator.ofFloat(this, "translationY", value)
.apply {
@ -122,7 +204,7 @@ fun View.focusAndShowKeyboard() {
*/
fun View.drawAboveSystemBars(onlyPortrait: Boolean = true) {
if (PreferenceUtil.isFullScreenMode) return
if (onlyPortrait && RetroUtil.isLandscape()) return
if (onlyPortrait && RetroUtil.isLandscape) return
applyInsetter {
type(navigationBars = true) {
margin()

View file

@ -15,11 +15,13 @@
package code.name.monkey.retromusic.fragments
import android.animation.ValueAnimator
import android.content.Context
import android.widget.Toast
import androidx.core.animation.doOnEnd
import androidx.lifecycle.*
import code.name.monkey.retromusic.*
import code.name.monkey.retromusic.db.*
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.fragments.ReloadType.*
import code.name.monkey.retromusic.fragments.search.Filter
import code.name.monkey.retromusic.helper.MusicPlayerRemote
@ -45,7 +47,6 @@ class LibraryViewModel(
private val songs = MutableLiveData<List<Song>>()
private val artists = MutableLiveData<List<Artist>>()
private val playlists = MutableLiveData<List<PlaylistWithSongs>>()
private val legacyPlaylists = MutableLiveData<List<Playlist>>()
private val genres = MutableLiveData<List<Genre>>()
private val searchResults = MutableLiveData<List<Any>>()
private val fabMargin = MutableLiveData(0)
@ -69,41 +70,21 @@ class LibraryViewModel(
fun getSearchResult(): LiveData<List<Any>> = searchResults
fun getSongs(): LiveData<List<Song>> {
return songs
}
fun getSongs(): LiveData<List<Song>> = songs
fun getAlbums(): LiveData<List<Album>> {
return albums
}
fun getAlbums(): LiveData<List<Album>> = albums
fun getArtists(): LiveData<List<Artist>> {
return artists
}
fun getArtists(): LiveData<List<Artist>> = artists
fun getPlaylists(): LiveData<List<PlaylistWithSongs>> {
return playlists
}
fun getPlaylists(): LiveData<List<PlaylistWithSongs>> = playlists
fun getLegacyPlaylist(): LiveData<List<Playlist>> {
return legacyPlaylists
}
fun getGenre(): LiveData<List<Genre>> = genres
fun getGenre(): LiveData<List<Genre>> {
return genres
}
fun getHome(): LiveData<List<Home>> = home
fun getHome(): LiveData<List<Home>> {
return home
}
fun getSuggestions(): LiveData<List<Song>> = suggestions
fun getSuggestions(): LiveData<List<Song>> {
return suggestions
}
fun getFabMargin(): LiveData<Int> {
return fabMargin
}
fun getFabMargin(): LiveData<Int> = fabMargin
private suspend fun fetchSongs() {
songs.postValue(repository.allSongs())
@ -111,7 +92,6 @@ class LibraryViewModel(
private suspend fun fetchAlbums() {
albums.postValue(repository.fetchAlbums())
}
private suspend fun fetchArtists() {
@ -126,12 +106,6 @@ class LibraryViewModel(
playlists.postValue(repository.fetchPlaylistWithSongs())
}
private fun fetchLegacyPlaylist() {
viewModelScope.launch(IO) {
legacyPlaylists.postValue(repository.fetchLegacyPlaylist())
}
}
private suspend fun fetchGenres() {
genres.postValue(repository.fetchGenres())
}
@ -267,35 +241,22 @@ class LibraryViewModel(
}
}
fun deleteTracks(songs: List<Song>) = viewModelScope.launch(IO) {
repository.deleteSongs(songs)
fetchPlaylists()
loadLibraryContent()
}
fun recentSongs(): LiveData<List<Song>> = liveData {
fun recentSongs(): LiveData<List<Song>> = liveData(IO) {
emit(repository.recentSongs())
}
fun playCountSongs(): LiveData<List<Song>> = liveData {
val songs = repository.playCountSongs().map {
it.toSong()
}
emit(songs)
// Cleaning up deleted or moved songs
withContext(IO) {
songs.forEach { song ->
fun playCountSongs(): LiveData<List<Song>> = liveData(IO) {
repository.playCountSongs().forEach { song ->
if (!File(song.data).exists() || song.id == -1L) {
repository.deleteSongInPlayCount(song.toPlayCount())
repository.deleteSongInPlayCount(song)
}
}
emit(repository.playCountSongs().map {
it.toSong()
})
}
}
fun artists(type: Int): LiveData<List<Artist>> = liveData {
fun artists(type: Int): LiveData<List<Artist>> = liveData(IO) {
when (type) {
TOP_ARTISTS -> emit(repository.topArtists())
RECENT_ARTISTS -> {
@ -304,7 +265,7 @@ class LibraryViewModel(
}
}
fun albums(type: Int): LiveData<List<Album>> = liveData {
fun albums(type: Int): LiveData<List<Album>> = liveData(IO) {
when (type) {
TOP_ALBUMS -> emit(repository.topAlbums())
RECENT_ALBUMS -> {
@ -313,29 +274,25 @@ class LibraryViewModel(
}
}
fun artist(artistId: Long): LiveData<Artist> = liveData {
fun artist(artistId: Long): LiveData<Artist> = liveData(IO) {
emit(repository.artistById(artistId))
}
fun fetchContributors(): LiveData<List<Contributor>> = liveData {
fun fetchContributors(): LiveData<List<Contributor>> = liveData(IO) {
emit(repository.contributor())
}
fun observableHistorySongs(): LiveData<List<Song>> {
val songs = repository.historySong().map {
it.toSong()
}
songHistory.value = songs
// Cleaning up deleted or moved songs
viewModelScope.launch {
songs.forEach { song ->
viewModelScope.launch(IO) {
repository.historySong().forEach { song ->
if (!File(song.data).exists() || song.id == -1L) {
repository.deleteSongInHistory(song.id)
}
}
}
songHistory.value = repository.historySong().map {
songHistory.postValue(repository.historySong().map {
it.toSong()
})
}
return songHistory
}
@ -366,12 +323,10 @@ class LibraryViewModel(
fun favorites() = repository.favorites()
fun clearSearchResult() {
viewModelScope.launch {
searchResults.postValue(emptyList())
}
searchResults.value = emptyList()
}
fun addToPlaylist(playlistName: String, songs: List<Song>) {
fun addToPlaylist(context: Context, playlistName: String, songs: List<Song>) {
viewModelScope.launch(IO) {
val playlists = checkPlaylistExists(playlistName)
if (playlists.isEmpty()) {
@ -379,12 +334,8 @@ class LibraryViewModel(
createPlaylist(PlaylistEntity(playlistName = playlistName))
insertSongs(songs.map { it.toSongEntity(playlistId) })
withContext(Main) {
Toast.makeText(
App.getContext(),
App.getContext()
.getString(R.string.playlist_created_sucessfully, playlistName),
Toast.LENGTH_SHORT
).show()
context.showToast(context.getString(R.string.playlist_created_sucessfully,
playlistName))
}
} else {
val playlist = playlists.firstOrNull()
@ -396,17 +347,18 @@ class LibraryViewModel(
}
forceReload(Playlists)
withContext(Main) {
Toast.makeText(App.getContext(), App.getContext().getString(
context.showToast(
context.getString(
R.string.added_song_count_to_playlist,
songs.size,
playlistName
), Toast.LENGTH_SHORT).show()
playlistName),
Toast.LENGTH_SHORT)
}
}
}
fun setFabMargin(bottomMargin: Int) {
val currentValue = DensityUtil.dip2px(App.getContext(), 16F) +
fun setFabMargin(context: Context, bottomMargin: Int) {
val currentValue = DensityUtil.dip2px(context, 16F) +
bottomMargin
ValueAnimator.ofInt(fabMargin.value!!, currentValue).apply {
addUpdateListener {

View file

@ -14,13 +14,10 @@
*/
package code.name.monkey.retromusic.fragments.about
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Bundle
import android.view.View
import androidx.core.app.ShareCompat
import androidx.core.net.toUri
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager
@ -29,9 +26,10 @@ import code.name.monkey.retromusic.Constants
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.ContributorAdapter
import code.name.monkey.retromusic.databinding.FragmentAboutBinding
import code.name.monkey.retromusic.extensions.openUrl
import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.RetroUtil
import dev.chrisbanes.insetter.applyInsetter
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
class AboutFragment : Fragment(R.layout.fragment_about), View.OnClickListener {
@ -45,36 +43,31 @@ class AboutFragment : Fragment(R.layout.fragment_about), View.OnClickListener {
binding.aboutContent.cardOther.version.setSummary(getAppVersion())
setUpView()
loadContributors()
// This is a workaround as CollapsingToolbarLayout consumes insets and
// insets are not passed to child views
// https://github.com/material-components/material-components-android/issues/1310
if (!RetroUtil.isLandscape()) {
binding.aboutContent.root.updatePadding(bottom = RetroUtil.getNavigationBarHeight())
}
}
private fun openUrl(url: String) {
val i = Intent(Intent.ACTION_VIEW)
i.data = url.toUri()
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK
startActivity(i)
binding.aboutContent.root.applyInsetter {
type(navigationBars = true) {
padding()
}
}
}
private fun setUpView() {
binding.aboutContent.cardRetroInfo.appGithub.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.faqLink.setOnClickListener(this)
binding.aboutContent.cardSocial.telegramLink.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.appRate.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.appTranslation.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.appShare.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.donateLink.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.bugReportLink.setOnClickListener(this)
binding.aboutContent.cardSocial.telegramLink.setOnClickListener(this)
binding.aboutContent.cardSocial.instagramLink.setOnClickListener(this)
binding.aboutContent.cardSocial.twitterLink.setOnClickListener(this)
binding.aboutContent.cardSocial.pinterestLink.setOnClickListener(this)
binding.aboutContent.cardSocial.websiteLink.setOnClickListener(this)
binding.aboutContent.cardOther.changelog.setOnClickListener(this)
binding.aboutContent.cardOther.openSource.setOnClickListener(this)
binding.aboutContent.cardSocial.pinterestLink.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.bugReportLink.setOnClickListener(this)
binding.aboutContent.cardSocial.websiteLink.setOnClickListener(this)
}
override fun onClick(view: View) {

View file

@ -112,23 +112,22 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentAlbumDetailsBinding.bind(view)
setHasOptionsMenu(true)
mainActivity.addMusicServiceEventListener(detailsViewModel)
mainActivity.setSupportActionBar(binding.toolbar)
binding.toolbar.title = " "
binding.albumCoverContainer.setTransitionName(arguments.extraAlbumId.toString())
binding.albumCoverContainer.transitionName = arguments.extraAlbumId.toString()
postponeEnterTransition()
detailsViewModel.getAlbum().observe(viewLifecycleOwner) {
requireView().doOnPreDraw {
view.doOnPreDraw {
startPostponedEnterTransition()
}
albumArtistExists = !it.albumArtist.isNullOrEmpty()
showAlbum(it)
if (albumArtistExists) {
binding.artistImage.setTransitionName(album.albumArtist)
binding.artistImage.transitionName = if (albumArtistExists) {
album.albumArtist
} else {
binding.artistImage.setTransitionName(album.artistId.toString())
album.artistId.toString()
}
}
@ -308,7 +307,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
.load(
RetroGlideExtension.getArtistModel(
artist,
PreferenceUtil.isAllowedToDownloadMetadata()
PreferenceUtil.isAllowedToDownloadMetadata(requireContext())
)
)
.artistImageOptions(artist)
@ -347,8 +346,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_album_detail, menu)
val sortOrder = menu.findItem(R.id.action_sort_order)
setUpSortOrderMenu(sortOrder.subMenu)
@ -360,7 +358,7 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
override fun onMenuItemSelected(item: MenuItem): Boolean {
return handleSortOrderMenuItem(item)
}

View file

@ -52,7 +52,7 @@ class AlbumDetailsViewModel(
emit(artist)
}
fun getAlbumInfo(album: Album): LiveData<Result<LastFmAlbum>> = liveData {
fun getAlbumInfo(album: Album): LiveData<Result<LastFmAlbum>> = liveData(IO) {
emit(Result.Loading)
emit(repository.albumInfo(album.artistName, album.title))
}

View file

@ -158,10 +158,10 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
reenterTransition = null
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateMenu(menu, inflater)
val gridSizeItem: MenuItem = menu.findItem(R.id.action_grid_size)
if (RetroUtil.isLandscape()) {
if (RetroUtil.isLandscape) {
gridSizeItem.setTitle(R.string.action_grid_size_land)
}
setUpGridSizeMenu(gridSizeItem.subMenu)
@ -267,7 +267,7 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
override fun onMenuItemSelected(item: MenuItem): Boolean {
if (handleGridSizeMenuItem(item)) {
return true
}
@ -277,7 +277,7 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
if (handleSortOrderMenuItem(item)) {
return true
}
return super.onOptionsItemSelected(item)
return super.onMenuItemSelected(item)
}
private fun handleSortOrderMenuItem(

View file

@ -10,6 +10,7 @@ import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.activity.addCallback
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.widget.PopupMenu
import androidx.core.os.bundleOf
import androidx.core.text.parseAsHtml
@ -84,14 +85,13 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentArtistDetailsBinding.bind(view)
setHasOptionsMenu(true)
mainActivity.addMusicServiceEventListener(detailsViewModel)
mainActivity.setSupportActionBar(binding.toolbar)
binding.toolbar.title = null
binding.artistCoverContainer.setTransitionName((artistId ?: artistName).toString())
binding.artistCoverContainer.transitionName = (artistId ?: artistName).toString()
postponeEnterTransition()
detailsViewModel.getArtist().observe(viewLifecycleOwner) {
requireView().doOnPreDraw {
view.doOnPreDraw {
startPostponedEnterTransition()
}
showArtist(it)
@ -146,7 +146,7 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
}
this.artist = artist
loadArtistImage(artist)
if (RetroUtil.isAllowedToDownloadMetadata(requireContext())) {
if (PreferenceUtil.isAllowedToDownloadMetadata(requireContext())) {
loadBiography(artist.name)
}
binding.artistTitle.text = artist.name
@ -173,7 +173,7 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
private fun loadBiography(
name: String,
lang: String? = Locale.getDefault().language
lang: String? = Locale.getDefault().language,
) {
biography = null
this.lang = lang
@ -245,7 +245,7 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
override fun onMenuItemSelected(item: MenuItem): Boolean {
return handleSortOrderMenuItem(item)
}
@ -274,15 +274,16 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
R.id.action_set_artist_image -> {
val intent = Intent(Intent.ACTION_GET_CONTENT)
intent.type = "image/*"
startActivityForResult(
Intent.createChooser(intent, getString(R.string.pick_from_local_storage)),
REQUEST_CODE_SELECT_IMAGE
)
selectImageLauncher.launch(Intent.createChooser(intent,
getString(R.string.pick_from_local_storage)))
return true
}
R.id.action_reset_artist_image -> {
showToast(resources.getString(R.string.updating))
CustomArtistImageUtil.getInstance(requireContext()).resetCustomArtistImage(artist)
lifecycleScope.launch {
CustomArtistImageUtil.getInstance(requireContext())
.resetCustomArtistImage(artist)
}
forceDownload = true
return true
}
@ -295,18 +296,18 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
PopupMenu(requireContext(), binding.fragmentArtistContent.songSortOrder).apply {
inflate(R.menu.menu_artist_song_sort_order)
setUpSortOrderMenu(menu)
setOnMenuItemClickListener { menuItem ->
val sortOrder = when (menuItem.itemId) {
setOnMenuItemClickListener { item ->
val sortOrder = when (item.itemId) {
R.id.action_sort_order_title -> SortOrder.ArtistSongSortOrder.SONG_A_Z
R.id.action_sort_order_title_desc -> SortOrder.ArtistSongSortOrder.SONG_Z_A
R.id.action_sort_order_album -> SortOrder.ArtistSongSortOrder.SONG_ALBUM
R.id.action_sort_order_year -> SortOrder.ArtistSongSortOrder.SONG_YEAR
R.id.action_sort_order_song_duration -> SortOrder.ArtistSongSortOrder.SONG_DURATION
else -> {
throw IllegalArgumentException("invalid ${menuItem.title}")
throw IllegalArgumentException("invalid ${item.title}")
}
}
menuItem.isChecked = true
item.isChecked = true
setSaveSortOrder(sortOrder)
return@setOnMenuItemClickListener true
}
@ -322,8 +323,10 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
private fun setUpSortOrderMenu(sortOrder: Menu) {
when (savedSongSortOrder) {
SortOrder.ArtistSongSortOrder.SONG_A_Z -> sortOrder.findItem(R.id.action_sort_order_title).isChecked = true
SortOrder.ArtistSongSortOrder.SONG_Z_A -> sortOrder.findItem(R.id.action_sort_order_title_desc).isChecked = true
SortOrder.ArtistSongSortOrder.SONG_A_Z -> sortOrder.findItem(R.id.action_sort_order_title).isChecked =
true
SortOrder.ArtistSongSortOrder.SONG_Z_A -> sortOrder.findItem(R.id.action_sort_order_title_desc).isChecked =
true
SortOrder.ArtistSongSortOrder.SONG_ALBUM ->
sortOrder.findItem(R.id.action_sort_order_album).isChecked = true
SortOrder.ArtistSongSortOrder.SONG_YEAR ->
@ -336,24 +339,20 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
REQUEST_CODE_SELECT_IMAGE -> if (resultCode == Activity.RESULT_OK) {
data?.data?.let {
private val selectImageLauncher =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
result.data?.data?.let {
lifecycleScope.launch {
CustomArtistImageUtil.getInstance(requireContext())
.setCustomArtistImage(artist, it)
}
}
else -> if (resultCode == Activity.RESULT_OK) {
println("OK")
}
}
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_artist_detail, menu)
}
@ -395,8 +394,4 @@ abstract class AbsArtistDetailsFragment : AbsMainActivityFragment(R.layout.fragm
super.onDestroyView()
_binding = null
}
companion object {
const val REQUEST_CODE_SELECT_IMAGE = 9002
}
}

View file

@ -168,10 +168,10 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
reenterTransition = null
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateMenu(menu, inflater)
val gridSizeItem: MenuItem = menu.findItem(R.id.action_grid_size)
if (RetroUtil.isLandscape()) {
if (RetroUtil.isLandscape) {
gridSizeItem.setTitle(R.string.action_grid_size_land)
}
setUpGridSizeMenu(gridSizeItem.subMenu)
@ -261,7 +261,7 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
override fun onMenuItemSelected(item: MenuItem): Boolean {
if (handleGridSizeMenuItem(item)) {
return true
}
@ -274,7 +274,7 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
if (handleAlbumArtistMenu(item)) {
return true
}
return super.onOptionsItemSelected(item)
return super.onMenuItemSelected(item)
}
private fun handleAlbumArtistMenu(item: MenuItem): Boolean {

View file

@ -5,7 +5,6 @@ import android.content.Intent
import android.os.Bundle
import android.view.MenuItem
import android.view.View
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.net.toUri
import androidx.core.view.isVisible
@ -20,6 +19,7 @@ import code.name.monkey.retromusic.databinding.FragmentBackupBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.accentOutlineColor
import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.helper.BackupHelper
import code.name.monkey.retromusic.helper.sanitize
import code.name.monkey.retromusic.util.BackupUtil
@ -47,7 +47,7 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
else
backupAdapter?.swapDataset(listOf())
}
backupViewModel.loadBackups(requireContext())
backupViewModel.loadBackups()
val openFilePicker = registerForActivityResult(ActivityResultContracts.OpenDocument()) {
lifecycleScope.launch(Dispatchers.IO) {
it?.let {
@ -98,7 +98,7 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
// Text submitted with the action button
lifecycleScope.launch {
BackupHelper.createBackup(requireContext(), text.sanitize())
backupViewModel.loadBackups(requireContext())
backupViewModel.loadBackups()
}
}
positiveButton(android.R.string.ok)
@ -122,13 +122,9 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
try {
file.delete()
} catch (exception: SecurityException) {
Toast.makeText(
activity,
"Could not delete backup",
Toast.LENGTH_SHORT
).show()
showToast("Could not delete backup")
}
backupViewModel.loadBackups(requireContext())
backupViewModel.loadBackups()
return true
}
R.id.action_share -> {
@ -149,13 +145,9 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
File(file.parent, "$text${BackupHelper.APPEND_EXTENSION}")
if (!renamedFile.exists()) {
file.renameTo(renamedFile)
backupViewModel.loadBackups(requireContext())
backupViewModel.loadBackups()
} else {
Toast.makeText(
requireContext(),
"File already exists",
Toast.LENGTH_SHORT
).show()
showToast("File already exists")
}
}
positiveButton(android.R.string.ok)

View file

@ -1,7 +1,6 @@
package code.name.monkey.retromusic.fragments.backup
import android.app.Activity
import android.content.Context
import android.content.Intent
import androidx.lifecycle.LiveData
import androidx.lifecycle.MutableLiveData
@ -20,7 +19,7 @@ class BackupViewModel : ViewModel() {
private val backupsMutableLiveData = MutableLiveData<List<File>>()
val backupsLiveData: LiveData<List<File>> = backupsMutableLiveData
fun loadBackups(context: Context) {
fun loadBackups() {
BackupHelper.getBackupRoot().listFiles { _, name ->
return@listFiles name.endsWith(BackupHelper.BACKUP_EXTENSION)
}?.toList()?.let {

View file

@ -10,12 +10,17 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.ActivityRestoreBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.accentOutlineColor
import code.name.monkey.retromusic.extensions.addAccentColor
import code.name.monkey.retromusic.helper.BackupContent
import code.name.monkey.retromusic.helper.BackupContent.*
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.theme.ThemeManager
import code.name.monkey.retromusic.util.theme.getNightMode
import com.google.android.material.color.DynamicColors
import com.google.android.material.color.DynamicColorsOptions
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
@ -33,14 +38,20 @@ class RestoreActivity : AppCompatActivity() {
setWidth()
val backupUri = intent?.data
binding.backupName.setText(getFileName(backupUri))
binding.cancelButton.accentOutlineColor()
binding.cancelButton.setOnClickListener {
finish()
}
binding.restoreButton.accentColor()
binding.checkArtistImages.addAccentColor()
binding.checkPlaylists.addAccentColor()
binding.checkSettings.addAccentColor()
binding.checkUserImages.addAccentColor()
binding.restoreButton.setOnClickListener {
val backupContents = mutableListOf<BackupContent>()
if (binding.checkSettings.isChecked) backupContents.add(SETTINGS)
if (binding.checkDatabases.isChecked) backupContents.add(PLAYLISTS)
if (binding.checkPlaylists.isChecked) backupContents.add(PLAYLISTS)
if (binding.checkArtistImages.isChecked) backupContents.add(CUSTOM_ARTIST_IMAGES)
if (binding.checkSettings.isChecked) backupContents.add(SETTINGS)
if (binding.checkUserImages.isChecked) backupContents.add(USER_IMAGES)
lifecycleScope.launch(Dispatchers.IO) {
if (backupUri != null) {
@ -53,13 +64,15 @@ class RestoreActivity : AppCompatActivity() {
}
private fun updateTheme() {
AppCompatDelegate.setDefaultNightMode(ThemeManager.getNightMode())
AppCompatDelegate.setDefaultNightMode(getNightMode())
// Apply dynamic colors to activity if enabled
if (PreferenceUtil.materialYou) {
DynamicColors.applyIfAvailable(
DynamicColors.applyToActivityIfAvailable(
this,
com.google.android.material.R.style.ThemeOverlay_Material3_DynamicColors_DayNight
DynamicColorsOptions.Builder()
.setThemeOverlay(R.style.ThemeOverlay_Material3_DynamicColors_DayNight)
.build()
)
}
}

View file

@ -15,21 +15,25 @@
package code.name.monkey.retromusic.fragments.base
import android.os.Bundle
import android.view.View
import androidx.annotation.LayoutRes
import androidx.core.view.MenuHost
import androidx.core.view.MenuProvider
import androidx.lifecycle.Lifecycle
import code.name.monkey.retromusic.activities.MainActivity
import code.name.monkey.retromusic.extensions.setTaskDescriptionColorAuto
import code.name.monkey.retromusic.fragments.LibraryViewModel
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
abstract class AbsMainActivityFragment(@LayoutRes layout: Int) : AbsMusicServiceFragment(layout) {
abstract class AbsMainActivityFragment(@LayoutRes layout: Int) : AbsMusicServiceFragment(layout),
MenuProvider {
val libraryViewModel: LibraryViewModel by sharedViewModel()
val mainActivity: MainActivity
get() = activity as MainActivity
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setHasOptionsMenu(true)
mainActivity.setTaskDescriptionColorAuto()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val menuHost: MenuHost = requireActivity()
menuHost.addMenuProvider(this, viewLifecycleOwner, Lifecycle.State.STARTED)
}
}

View file

@ -30,6 +30,7 @@ import androidx.core.view.isVisible
import androidx.fragment.app.commit
import androidx.fragment.app.replace
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.extensions.whichFragment
import code.name.monkey.retromusic.fragments.MusicSeekSkipTouchListener
import code.name.monkey.retromusic.fragments.other.VolumeFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
@ -224,8 +225,7 @@ abstract class AbsPlayerControlsFragment(@LayoutRes layout: Int) : AbsMusicServi
}
childFragmentManager.executePendingTransactions()
}
volumeFragment =
childFragmentManager.findFragmentById(R.id.volumeFragmentContainer) as? VolumeFragment
volumeFragment = whichFragment(R.id.volumeFragmentContainer)
}
override fun onResume() {

View file

@ -20,7 +20,6 @@ import android.content.ContentUris
import android.content.Context
import android.content.Intent
import android.graphics.drawable.AnimatedVectorDrawable
import android.graphics.drawable.Drawable
import android.media.MediaMetadataRetriever
import android.os.Bundle
import android.provider.MediaStore
@ -29,7 +28,6 @@ import android.view.MenuItem
import android.view.MotionEvent
import android.view.View
import android.widget.RelativeLayout
import android.widget.Toast
import androidx.annotation.LayoutRes
import androidx.appcompat.widget.Toolbar
import androidx.core.os.bundleOf
@ -48,10 +46,8 @@ import code.name.monkey.retromusic.activities.tageditor.SongTagEditorActivity
import code.name.monkey.retromusic.db.PlaylistEntity
import code.name.monkey.retromusic.db.toSongEntity
import code.name.monkey.retromusic.dialogs.*
import code.name.monkey.retromusic.extensions.currentFragment
import code.name.monkey.retromusic.extensions.hide
import code.name.monkey.retromusic.extensions.keepScreenOn
import code.name.monkey.retromusic.extensions.whichFragment
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.fragments.NowPlayingScreen
import code.name.monkey.retromusic.fragments.ReloadType
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
@ -60,22 +56,30 @@ import code.name.monkey.retromusic.interfaces.IPaletteColorHolder
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.repository.RealRepository
import code.name.monkey.retromusic.service.MusicService
import code.name.monkey.retromusic.util.*
import code.name.monkey.retromusic.util.NavigationUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RingtoneManager
import com.google.android.material.bottomsheet.BottomSheetBehavior
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.android.ext.android.get
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
import kotlin.math.abs
abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragment(layout),
abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMusicServiceFragment(layout),
Toolbar.OnMenuItemClickListener, IPaletteColorHolder, PlayerAlbumCoverFragment.Callbacks {
val libraryViewModel: LibraryViewModel by sharedViewModel()
val mainActivity: MainActivity
get() = activity as MainActivity
private var playerAlbumCoverFragment: PlayerAlbumCoverFragment? = null
override fun onMenuItemClick(
item: MenuItem
item: MenuItem,
): Boolean {
val song = MusicPlayerRemote.currentSong
when (item.itemId) {
@ -196,7 +200,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
if (genre == null) {
genre = "Not Specified"
}
Toast.makeText(context, genre, Toast.LENGTH_SHORT).show()
showToast(genre)
return true
}
}
@ -206,8 +210,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
private fun showLyricsIcon(item: MenuItem) {
val icon =
if (PreferenceUtil.showLyrics) R.drawable.ic_lyrics else R.drawable.ic_lyrics_outline
val drawable: Drawable = RetroUtil.getTintedVectorDrawable(
requireContext(),
val drawable = requireContext().getTintedDrawable(
icon,
toolbarIconColor()
)
@ -240,7 +243,6 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
protected open fun toggleFavorite(song: Song) {
lifecycleScope.launch(IO) {
val playlist: PlaylistEntity = libraryViewModel.favoritePlaylist()
if (playlist != null) {
val songEntity = song.toSongEntity(playlist.playListId)
val isFavorite = libraryViewModel.isSongFavorite(song.id)
if (isFavorite) {
@ -248,7 +250,6 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
} else {
libraryViewModel.insertSongs(listOf(song.toSongEntity(playlist.playListId)))
}
}
libraryViewModel.forceReload(ReloadType.Playlists)
requireContext().sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED))
}
@ -264,8 +265,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
} else {
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
}
val drawable: Drawable = RetroUtil.getTintedVectorDrawable(
requireContext(),
val drawable = requireContext().getTintedDrawable(
icon,
toolbarIconColor()
)
@ -333,7 +333,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
e1: MotionEvent?,
e2: MotionEvent?,
distanceX: Float,
distanceY: Float
distanceY: Float,
): Boolean {
return when {
abs(distanceX) > abs(distanceY) -> {
@ -359,15 +359,6 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
val TAG: String = AbsPlayerFragment::class.java.simpleName
const val VISIBILITY_ANIM_DURATION: Long = 300
}
protected fun getUpNextAndQueueTime(): String {
val duration = MusicPlayerRemote.getQueueDurationMillis(MusicPlayerRemote.position)
return MusicUtil.buildInfoString(
resources.getString(R.string.up_next),
MusicUtil.getReadableDurationString(duration)
)
}
}
fun goToArtist(activity: Activity) {

View file

@ -28,7 +28,7 @@ abstract class AbsRecyclerViewCustomGridSizeFragment<A : RecyclerView.Adapter<*>
private var sortOrder: String? = null
private var currentLayoutRes: Int = 0
private val isLandscape: Boolean
get() = RetroUtil.isLandscape()
get() = RetroUtil.isLandscape
val maxGridSize: Int
get() = if (isLandscape) {

View file

@ -199,13 +199,11 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
binding.appBarLayout.setExpanded(true, true)
}
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
override fun onPrepareMenu(menu: Menu) {
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), toolbar)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_main, menu)
ToolbarContentTintHelper.handleOnCreateOptionsMenu(
requireContext(),
@ -215,7 +213,7 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
override fun onMenuItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_settings -> findNavController().navigate(
R.id.settingsActivity,
@ -231,7 +229,7 @@ abstract class AbsRecyclerViewFragment<A : RecyclerView.Adapter<*>, LM : Recycle
"ShowCreatePlaylistDialog"
)
}
return super.onOptionsItemSelected(item)
return false
}
override fun onDestroyView() {

View file

@ -13,21 +13,20 @@
*/
package code.name.monkey.retromusic.fragments.folder
import android.app.Dialog
import android.content.Context
import android.media.MediaScannerConnection
import android.os.Bundle
import android.os.Environment
import android.text.Html
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.webkit.MimeTypeMap
import android.widget.Toast
import androidx.activity.OnBackPressedCallback
import androidx.appcompat.widget.PopupMenu
import androidx.core.text.parseAsHtml
import androidx.core.view.isVisible
import androidx.lifecycle.lifecycleScope
import androidx.loader.app.LoaderManager
import androidx.loader.content.Loader
import androidx.navigation.fragment.findNavController
@ -36,7 +35,6 @@ import androidx.recyclerview.widget.RecyclerView
import code.name.monkey.appthemehelper.ThemeStore.Companion.accentColor
import code.name.monkey.appthemehelper.common.ATHToolbarActivity
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.adapter.SongFileAdapter
import code.name.monkey.retromusic.adapter.Storage
@ -45,17 +43,13 @@ import code.name.monkey.retromusic.adapter.StorageClickListener
import code.name.monkey.retromusic.databinding.FragmentFolderBinding
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.fragments.folder.FoldersFragment.ListPathsAsyncTask.OnPathsListedCallback
import code.name.monkey.retromusic.fragments.folder.FoldersFragment.ListSongsAsyncTask.OnSongsListedCallback
import code.name.monkey.retromusic.helper.MusicPlayerRemote.openQueue
import code.name.monkey.retromusic.helper.MusicPlayerRemote.playingQueue
import code.name.monkey.retromusic.helper.menu.SongMenuHelper.handleMenuClick
import code.name.monkey.retromusic.helper.menu.SongsMenuHelper
import code.name.monkey.retromusic.interfaces.ICabCallback
import code.name.monkey.retromusic.interfaces.ICabHolder
import code.name.monkey.retromusic.interfaces.ICallbacks
import code.name.monkey.retromusic.interfaces.IMainActivityFragmentCallbacks
import code.name.monkey.retromusic.misc.DialogAsyncTask
import code.name.monkey.retromusic.misc.UpdateToastMediaScannerCompletionListener
import code.name.monkey.retromusic.misc.WrappedAsyncTaskLoader
import code.name.monkey.retromusic.model.Song
@ -64,16 +58,20 @@ import code.name.monkey.retromusic.util.FileUtil
import code.name.monkey.retromusic.util.PreferenceUtil.startDirectory
import code.name.monkey.retromusic.util.RetroColorUtil
import code.name.monkey.retromusic.util.ThemedFastScroller.create
import code.name.monkey.retromusic.util.getExternalStorageDirectory
import code.name.monkey.retromusic.util.getExternalStoragePublicDirectory
import code.name.monkey.retromusic.views.BreadCrumbLayout.Crumb
import code.name.monkey.retromusic.views.BreadCrumbLayout.SelectionCallback
import com.afollestad.materialcab.attached.AttachedCab
import com.afollestad.materialcab.attached.destroy
import com.afollestad.materialcab.attached.isActive
import com.afollestad.materialcab.createCab
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.snackbar.Snackbar
import com.google.android.material.transition.MaterialFadeThrough
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.io.File
import java.io.FileFilter
import java.io.IOException
@ -101,7 +99,6 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
_binding = FragmentFolderBinding.bind(view)
mainActivity.addMusicServiceEventListener(libraryViewModel)
mainActivity.setSupportActionBar(binding.toolbar)
mainActivity.supportActionBar?.title = null
@ -136,7 +133,6 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setHasOptionsMenu(true)
if (savedInstanceState == null) {
switchToFileAdapter()
setCrumb(
@ -186,48 +182,37 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
popupMenu.setOnMenuItemClickListener { item: MenuItem ->
when (val itemId = item.itemId) {
R.id.action_play_next, R.id.action_add_to_current_playing, R.id.action_add_to_playlist, R.id.action_delete_from_device -> {
ListSongsAsyncTask(
activity,
null,
object : OnSongsListedCallback {
override fun onSongsListed(songs: List<Song>, extra: Any?) {
lifecycleScope.launch(Dispatchers.IO) {
listSongs(
requireContext(),
toList(file),
AUDIO_FILE_FILTER,
fileComparator
) { songs ->
if (songs.isNotEmpty()) {
SongsMenuHelper.handleMenuClick(
requireActivity(), songs, itemId
)
}
}
})
.execute(
ListSongsAsyncTask.LoadingInfo(
toList(file), AUDIO_FILE_FILTER, fileComparator
)
)
}
return@setOnMenuItemClickListener true
}
R.id.action_add_to_blacklist -> {
BlacklistStore.getInstance(App.getContext()).addPath(file)
BlacklistStore.getInstance(requireContext()).addPath(file)
return@setOnMenuItemClickListener true
}
R.id.action_set_as_start_directory -> {
startDirectory = file
Toast.makeText(
activity,
String.format(getString(R.string.new_start_directory), file.path),
Toast.LENGTH_SHORT
showToast(
String.format(getString(R.string.new_start_directory), file.path)
)
.show()
return@setOnMenuItemClickListener true
}
R.id.action_scan -> {
ListPathsAsyncTask(
activity,
object : OnPathsListedCallback {
override fun onPathsListed(paths: Array<String?>) {
scanPaths(paths)
lifecycleScope.launch {
listPaths(file, AUDIO_FILE_FILTER) { paths -> scanPaths(paths) }
}
})
.execute(ListPathsAsyncTask.LoadingInfo(file, AUDIO_FILE_FILTER))
return@setOnMenuItemClickListener true
}
}
@ -238,32 +223,26 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
popupMenu.setOnMenuItemClickListener { item: MenuItem ->
when (val itemId = item.itemId) {
R.id.action_play_next, R.id.action_add_to_current_playing, R.id.action_add_to_playlist, R.id.action_go_to_album, R.id.action_go_to_artist, R.id.action_share, R.id.action_tag_editor, R.id.action_details, R.id.action_set_as_ringtone, R.id.action_delete_from_device -> {
ListSongsAsyncTask(
activity,
null,
object : OnSongsListedCallback {
override fun onSongsListed(songs: List<Song>, extra: Any?) {
handleMenuClick(
requireActivity(), songs[0], itemId
lifecycleScope.launch(Dispatchers.IO) {
listSongs(
requireContext(),
toList(file),
AUDIO_FILE_FILTER,
fileComparator
) { songs ->
if (songs.isNotEmpty()) {
SongsMenuHelper.handleMenuClick(
requireActivity(), songs, itemId
)
}
})
.execute(
ListSongsAsyncTask.LoadingInfo(
toList(file), AUDIO_FILE_FILTER, fileComparator
)
)
}
}
return@setOnMenuItemClickListener true
}
R.id.action_scan -> {
ListPathsAsyncTask(
activity,
object : OnPathsListedCallback {
override fun onPathsListed(paths: Array<String?>) {
scanPaths(paths)
lifecycleScope.launch {
listPaths(file, AUDIO_FILE_FILTER) { paths -> scanPaths(paths) }
}
})
.execute(ListPathsAsyncTask.LoadingInfo(file, AUDIO_FILE_FILTER))
return@setOnMenuItemClickListener true
}
}
@ -282,16 +261,17 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
val fileFilter = FileFilter { pathname: File ->
!pathname.isDirectory && AUDIO_FILE_FILTER.accept(pathname)
}
ListSongsAsyncTask(
activity,
mFile,
object : OnSongsListedCallback {
override fun onSongsListed(songs: List<Song>, extra: Any?) {
val file1 = extra as File
lifecycleScope.launch(Dispatchers.IO) {
listSongs(
requireContext(),
toList(mFile.parentFile),
fileFilter,
fileComparator
) { songs ->
if (songs.isNotEmpty()) {
var startIndex = -1
for (i in songs.indices) {
if (file1
.path
if (mFile.path
== songs[i].data
) { // path is already canonical here
startIndex = i
@ -303,39 +283,29 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
} else {
Snackbar.make(
mainActivity.slidingPanel,
Html.fromHtml(
String.format(
getString(R.string.not_listed_in_media_store), file1.name
)
),
getString(R.string.not_listed_in_media_store), mFile.name
).parseAsHtml(),
Snackbar.LENGTH_LONG
)
.setAction(
R.string.action_scan
) {
ListPathsAsyncTask(
requireActivity(),
object : OnPathsListedCallback {
override fun onPathsListed(paths: Array<String?>) {
scanPaths(paths)
lifecycleScope.launch {
listPaths(mFile, AUDIO_FILE_FILTER) { paths ->
scanPaths(
paths
)
}
}
})
.execute(
ListPathsAsyncTask.LoadingInfo(
file1, AUDIO_FILE_FILTER
)
)
}
.setActionTextColor(accentColor(requireActivity()))
.show()
}
}
})
.execute(
ListSongsAsyncTask.LoadingInfo(
toList(mFile.parentFile), fileFilter, fileComparator
)
)
}
}
}
}
@ -349,28 +319,23 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
override fun onMultipleItemAction(item: MenuItem, files: ArrayList<File>) {
val itemId = item.itemId
ListSongsAsyncTask(
activity,
null,
object : OnSongsListedCallback {
override fun onSongsListed(songs: List<Song>, extra: Any?) {
lifecycleScope.launch(Dispatchers.IO) {
listSongs(requireContext(), files, AUDIO_FILE_FILTER, fileComparator) { songs ->
if (songs.isNotEmpty()) {
SongsMenuHelper.handleMenuClick(
requireActivity(),
songs,
itemId
requireActivity(), songs, itemId
)
}
})
.execute(ListSongsAsyncTask.LoadingInfo(files, AUDIO_FILE_FILTER, fileComparator))
}
}
}
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
override fun onPrepareMenu(menu: Menu) {
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), binding.toolbar)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
menu.add(0, R.id.action_scan, 0, R.string.scan_media)
.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
menu.add(0, R.id.action_go_to_start_directory, 1, R.string.action_go_to_start_directory)
@ -387,7 +352,7 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
override fun onMenuItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_go_to_start_directory -> {
setCrumb(
@ -401,14 +366,9 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
R.id.action_scan -> {
val crumb = activeCrumb
if (crumb != null) {
ListPathsAsyncTask(
activity,
object : OnPathsListedCallback {
override fun onPathsListed(paths: Array<String?>) {
scanPaths(paths)
lifecycleScope.launch {
listPaths(crumb.file, AUDIO_FILE_FILTER) { paths -> scanPaths(paths) }
}
})
.execute(ListPathsAsyncTask.LoadingInfo(crumb.file, AUDIO_FILE_FILTER))
}
return true
}
@ -421,7 +381,7 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
return true
}
}
return super.onOptionsItemSelected(item)
return false
}
override fun onQueueChanged() {
@ -457,7 +417,7 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
if (_binding != null) {
binding.recyclerView.updatePadding(
bottom = if (count > 0 && playingQueue.isNotEmpty()) dip(R.dimen.mini_player_height_expanded)
else dip(R.dimen.mini_player_height_expanded)
else dip(R.dimen.mini_player_height)
)
}
}
@ -491,7 +451,7 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
return
}
if (toBeScanned.isEmpty()) {
Toast.makeText(activity, R.string.nothing_to_scan, Toast.LENGTH_SHORT).show()
showToast(R.string.nothing_to_scan)
} else {
MediaScannerConnection.scanFile(
requireContext(),
@ -561,69 +521,32 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
_binding = null
}
class ListPathsAsyncTask(context: Context?, callback: OnPathsListedCallback) :
ListingFilesDialogAsyncTask<ListPathsAsyncTask.LoadingInfo, String?, Array<String?>>(
context
private suspend fun listPaths(
file: File,
fileFilter: FileFilter,
doOnPathListed: (paths: Array<String?>) -> Unit
) {
private val onPathsListedCallbackWeakReference: WeakReference<OnPathsListedCallback> =
WeakReference(callback)
override fun doInBackground(vararg params: LoadingInfo): Array<String?> {
return try {
if (isCancelled || checkCallbackReference() == null) {
return arrayOf()
}
val info = params[0]
val paths = try {
val paths: Array<String?>
if (info.file.isDirectory) {
val files = FileUtil.listFilesDeep(info.file, info.fileFilter)
if (isCancelled || checkCallbackReference() == null) {
return arrayOf()
}
if (file.isDirectory) {
val files = FileUtil.listFilesDeep(file, fileFilter)
paths = arrayOfNulls(files.size)
for (i in files.indices) {
val f = files[i]
paths[i] = FileUtil.safeGetCanonicalPath(f)
if (isCancelled || checkCallbackReference() == null) {
return arrayOf()
}
}
} else {
paths = arrayOfNulls(1)
paths[0] = info.file.path
paths[0] = file.path
}
paths
} catch (e: Exception) {
e.printStackTrace()
cancel(false)
arrayOf()
}
withContext(Dispatchers.Main) {
doOnPathListed(paths)
}
override fun onPostExecute(paths: Array<String?>) {
super.onPostExecute(paths)
checkCallbackReference()?.onPathsListed(paths)
}
override fun onPreExecute() {
super.onPreExecute()
checkCallbackReference()
}
private fun checkCallbackReference(): OnPathsListedCallback? {
val callback = onPathsListedCallbackWeakReference.get()
if (callback == null) {
cancel(false)
}
return callback
}
interface OnPathsListedCallback {
fun onPathsListed(paths: Array<String?>)
}
class LoadingInfo(val file: File, val fileFilter: FileFilter)
}
private class AsyncFileLoader(foldersFragment: FoldersFragment) :
@ -651,87 +574,25 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
LinkedList()
}
}
}
private open class ListSongsAsyncTask(
context: Context?,
private val extra: Any?,
callback: OnSongsListedCallback
) : ListingFilesDialogAsyncTask<ListSongsAsyncTask.LoadingInfo, Void, List<Song>>(context) {
private val callbackWeakReference = WeakReference(callback)
private val contextWeakReference = WeakReference(context)
override fun doInBackground(vararg params: LoadingInfo): List<Song> {
return try {
val info = params[0]
val files = FileUtil.listFilesDeep(info.files, info.fileFilter)
if (isCancelled || checkContextReference() == null || checkCallbackReference() == null) {
return emptyList()
}
Collections.sort(files, info.fileComparator)
val context = checkContextReference()
if (isCancelled || context == null || checkCallbackReference() == null) {
emptyList()
} else FileUtil.matchFilesWithMediaStore(context, files)
suspend fun listSongs(
context: Context,
files: List<File>,
fileFilter: FileFilter,
fileComparator: Comparator<File>,
doOnSongsListed: (songs: List<Song>) -> Unit
) {
val songs = try {
val fileList = FileUtil.listFilesDeep(files, fileFilter)
Collections.sort(fileList, fileComparator)
FileUtil.matchFilesWithMediaStore(context, fileList)
} catch (e: Exception) {
e.printStackTrace()
cancel(false)
emptyList()
}
}
override fun onPostExecute(songs: List<Song>) {
super.onPostExecute(songs)
checkCallbackReference()?.onSongsListed(songs, extra)
}
override fun onPreExecute() {
super.onPreExecute()
checkCallbackReference()
checkContextReference()
}
private fun checkCallbackReference(): OnSongsListedCallback? {
val callback = callbackWeakReference.get()
if (callback == null) {
cancel(false)
}
return callback
}
private fun checkContextReference(): Context? {
val context = contextWeakReference.get()
if (context == null) {
cancel(false)
}
return context
}
interface OnSongsListedCallback {
fun onSongsListed(songs: List<Song>, extra: Any?)
}
class LoadingInfo(
val files: List<File>,
val fileFilter: FileFilter,
val fileComparator: Comparator<File>
)
}
abstract class ListingFilesDialogAsyncTask<Params, Progress, Result> internal constructor(
context: Context?
) :
DialogAsyncTask<Params, Progress, Result>(context) {
override fun createDialog(context: Context): Dialog {
return MaterialAlertDialogBuilder(context)
.setTitle(R.string.listing_files)
.setCancelable(false)
.setView(R.layout.loading)
.setOnCancelListener { cancel(false) }
.setOnDismissListener { cancel(false) }
.create()
withContext(Dispatchers.Main) {
doOnSongsListed(songs)
}
}
@ -772,7 +633,11 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
(!file.isHidden
&& (file.isDirectory
|| FileUtil.fileIsMimeType(file, "audio/*", MimeTypeMap.getSingleton())
|| FileUtil.fileIsMimeType(file, "application/opus", MimeTypeMap.getSingleton())
|| FileUtil.fileIsMimeType(
file,
"application/opus",
MimeTypeMap.getSingleton()
)
|| FileUtil.fileIsMimeType(
file,
"application/ogg",
@ -786,11 +651,11 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
val defaultStartDirectory: File
get() {
val musicDir =
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC)
getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC)
val startFolder = if (musicDir.exists() && musicDir.isDirectory) {
musicDir
} else {
val externalStorage = Environment.getExternalStorageDirectory()
val externalStorage = getExternalStorageDirectory()
if (externalStorage.exists() && externalStorage.isDirectory) {
externalStorage
} else {

View file

@ -53,10 +53,9 @@ class GenreDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_
enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).addTarget(view)
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false)
_binding = FragmentPlaylistDetailBinding.bind(view)
setHasOptionsMenu(true)
mainActivity.addMusicServiceEventListener(detailsViewModel)
mainActivity.setSupportActionBar(binding.toolbar)
binding.container.setTransitionName("genre")
binding.container.transitionName = "genre"
genre = arguments.extraGenre
binding.toolbar.title = arguments.extraGenre.name
setupRecyclerView()
@ -107,12 +106,11 @@ class GenreDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playlist_
binding.recyclerView.setPadding(0, 0, 0, height)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_genre_detail, menu)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
override fun onMenuItemSelected(item: MenuItem): Boolean {
return GenreMenuHelper.handleMenuClick(requireActivity(), genre, item)
}

View file

@ -22,6 +22,7 @@ import code.name.monkey.retromusic.interfaces.IMusicServiceEventListener
import code.name.monkey.retromusic.model.Genre
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.repository.RealRepository
import kotlinx.coroutines.Dispatchers.IO
import kotlinx.coroutines.Dispatchers.Main
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
@ -44,7 +45,7 @@ class GenreDetailsViewModel(
loadGenreSongs(genre)
}
private fun loadGenreSongs(genre: Genre) = viewModelScope.launch {
private fun loadGenreSongs(genre: Genre) = viewModelScope.launch(IO) {
val songs = realRepository.getGenre(genre.id)
withContext(Main) { _playListSongs.postValue(songs) }
}

View file

@ -19,7 +19,6 @@ import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import androidx.activity.addCallback
import androidx.core.os.bundleOf
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.GridLayoutManager
@ -46,14 +45,10 @@ GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager>(),
else
adapter?.swapDataSet(listOf())
}
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
remove()
requireActivity().onBackPressed()
}
}
override fun createLayoutManager(): LinearLayoutManager {
return if (RetroUtil.isLandscape()) {
return if (RetroUtil.isLandscape) {
GridLayoutManager(activity, 4)
} else {
GridLayoutManager(activity, 2)
@ -65,8 +60,8 @@ GenresFragment : AbsRecyclerViewFragment<GenreAdapter, LinearLayoutManager>(),
return GenreAdapter(requireActivity(), dataSet, this)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateMenu(menu, inflater)
menu.removeItem(R.id.action_grid_size)
menu.removeItem(R.id.action_layout_type)
menu.removeItem(R.id.action_sort_order)

View file

@ -20,7 +20,7 @@ import android.view.MenuInflater
import android.view.MenuItem
import android.view.MenuItem.SHOW_AS_ACTION_IF_ROOM
import android.view.View
import androidx.activity.addCallback
import androidx.coordinatorlayout.widget.CoordinatorLayout
import androidx.core.os.bundleOf
import androidx.core.text.parseAsHtml
import androidx.core.view.doOnLayout
@ -29,7 +29,6 @@ import androidx.core.view.isVisible
import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import code.name.monkey.appthemehelper.ThemeStore
import code.name.monkey.appthemehelper.common.ATHToolbarActivity
import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
@ -48,7 +47,7 @@ import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.interfaces.IScrollHelper
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.PreferenceUtil.userName
import com.google.android.gms.cast.framework.CastButtonFactory
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.transition.MaterialFadeThrough
@ -67,7 +66,7 @@ class HomeFragment :
mainActivity.setSupportActionBar(binding.toolbar)
mainActivity.supportActionBar?.title = null
setupListeners()
binding.titleWelcome.text = String.format("%s", PreferenceUtil.userName)
binding.titleWelcome.text = String.format("%s", userName)
enterTransition = MaterialFadeThrough().addTarget(binding.contentContainer)
reenterTransition = MaterialFadeThrough().addTarget(binding.contentContainer)
@ -77,12 +76,12 @@ class HomeFragment :
layoutManager = LinearLayoutManager(mainActivity)
adapter = homeAdapter
}
libraryViewModel.getHome().observe(viewLifecycleOwner) {
homeAdapter.swapData(it)
}
libraryViewModel.getSuggestions().observe(viewLifecycleOwner) {
loadSuggestions(it)
}
libraryViewModel.getHome().observe(viewLifecycleOwner) {
homeAdapter.swapData(it)
}
loadProfile()
setupTitle()
@ -92,10 +91,6 @@ class HomeFragment :
binding.appBarLayout.statusBarForeground =
MaterialShapeDrawable.createWithElevationOverlay(requireContext())
binding.toolbar.drawNextToNavbar()
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
remove()
requireActivity().onBackPressed()
}
view.doOnLayout {
adjustPlaylistButtons()
}
@ -110,7 +105,6 @@ class HomeFragment :
button.setLines(maxLineCount)
}
}
}
private fun setupListeners() {
@ -195,8 +189,7 @@ class HomeFragment :
binding.actionShuffle.elevatedAccentColor()
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_main, menu)
menu.removeItem(R.id.action_grid_size)
menu.removeItem(R.id.action_layout_type)
@ -218,16 +211,12 @@ class HomeFragment :
}
fun setSharedAxisXTransitions() {
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true).apply {
addTarget(binding.root)
}
exitTransition = MaterialSharedAxis(MaterialSharedAxis.X, true).addTarget(CoordinatorLayout::class.java)
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.X, false)
}
private fun setSharedAxisYTransitions() {
exitTransition = MaterialSharedAxis(MaterialSharedAxis.Y, true).apply {
addTarget(binding.root)
}
exitTransition = MaterialSharedAxis(MaterialSharedAxis.Y, true).addTarget(CoordinatorLayout::class.java)
reenterTransition = MaterialSharedAxis(MaterialSharedAxis.Y, false)
}
@ -246,7 +235,7 @@ class HomeFragment :
binding.suggestions.image7,
binding.suggestions.image8
)
val color = ThemeStore.accentColor(requireContext())
val color = accentColor()
binding.suggestions.message.apply {
setTextColor(color)
setOnClickListener {
@ -285,7 +274,7 @@ class HomeFragment :
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
override fun onMenuItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_settings -> findNavController().navigate(
R.id.settingsActivity,
@ -301,11 +290,11 @@ class HomeFragment :
"ShowCreatePlaylistDialog"
)
}
return super.onOptionsItemSelected(item)
return false
}
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
override fun onPrepareMenu(menu: Menu) {
super.onPrepareMenu(menu)
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), binding.toolbar)
}

View file

@ -48,7 +48,6 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
setHasOptionsMenu(true)
mainActivity.setBottomNavVisibility(true)
mainActivity.setSupportActionBar(binding.toolbar)
mainActivity.supportActionBar?.title = null
@ -87,13 +86,11 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
}
}
override fun onPrepareOptionsMenu(menu: Menu) {
super.onPrepareOptionsMenu(menu)
override fun onPrepareMenu(menu: Menu) {
ToolbarContentTintHelper.handleOnPrepareOptionsMenu(requireActivity(), binding.toolbar)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_main, menu)
ToolbarContentTintHelper.handleOnCreateOptionsMenu(
requireContext(),
@ -105,7 +102,7 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
override fun onMenuItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_settings -> findNavController().navigate(
R.id.settingsActivity,
@ -121,7 +118,7 @@ class LibraryFragment : AbsMainActivityFragment(R.layout.fragment_library) {
"ShowCreatePlaylistDialog"
)
}
return super.onOptionsItemSelected(item)
return false
}
override fun onDestroyView() {

View file

@ -66,12 +66,6 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setHasOptionsMenu(true)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentPlaylistDetailBinding.bind(view)
when (args.type) {
TOP_ARTISTS,
RECENT_ARTISTS,
@ -86,6 +80,13 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
returnTransition = MaterialSharedAxis(MaterialSharedAxis.Y, false)
}
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
_binding = FragmentPlaylistDetailBinding.bind(view)
postponeEnterTransition()
view.doOnPreDraw { startPostponedEnterTransition() }
mainActivity.setSupportActionBar(binding.toolbar)
binding.progressIndicator.hide()
when (args.type) {
@ -111,8 +112,6 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
})
binding.appBarLayout.statusBarForeground =
MaterialShapeDrawable.createWithElevationOverlay(requireContext())
postponeEnterTransition()
view.doOnPreDraw { startPostponedEnterTransition() }
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) {
if (!handleBackPress()) {
remove()
@ -237,10 +236,10 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
GridLayoutManager(requireContext(), gridCount(), GridLayoutManager.VERTICAL, false)
private fun gridCount(): Int {
if (RetroUtil.isTablet()) {
return if (RetroUtil.isLandscape()) 6 else 4
if (RetroUtil.isTablet) {
return if (RetroUtil.isLandscape) 6 else 4
}
return if (RetroUtil.isLandscape()) 4 else 2
return if (RetroUtil.isLandscape) 4 else 2
}
@ -302,25 +301,25 @@ class DetailListFragment : AbsMainActivityFragment(R.layout.fragment_playlist_de
return cab as AttachedCab
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
super.onCreateOptionsMenu(menu, inflater)
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_clear_history, menu)
if (showClearHistoryOption) {
menu.findItem(R.id.action_clear_history).isVisible = true // Show Clear History option
}
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
override fun onMenuItemSelected(item: MenuItem): Boolean {
when (item.itemId) {
R.id.action_clear_history -> {
if (binding.recyclerView.adapter?.itemCount!! > 0) {
libraryViewModel.clearHistory()
val snackBar =
Snackbar.make(binding.container,
Snackbar.make(
binding.container,
getString(R.string.history_cleared),
Snackbar.LENGTH_LONG)
Snackbar.LENGTH_LONG
)
.setAction(getString(R.string.history_undo_button)) {
libraryViewModel.restoreHistory()
}

View file

@ -40,10 +40,8 @@ import code.name.monkey.retromusic.activities.tageditor.TagWriter
import code.name.monkey.retromusic.databinding.FragmentLyricsBinding
import code.name.monkey.retromusic.databinding.FragmentNormalLyricsBinding
import code.name.monkey.retromusic.databinding.FragmentSyncedLyricsBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.materialDialog
import code.name.monkey.retromusic.extensions.textColorSecondary
import code.name.monkey.retromusic.extensions.uri
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.helper.MusicProgressViewUpdateHelper
@ -52,12 +50,9 @@ import code.name.monkey.retromusic.model.AudioTagInfo
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.FileUtils
import code.name.monkey.retromusic.util.LyricUtil
import code.name.monkey.retromusic.util.RetroUtil
import code.name.monkey.retromusic.util.UriUtil
import com.afollestad.materialdialogs.input.input
import com.google.android.material.color.MaterialColors
import com.google.android.material.tabs.TabLayoutMediator
import com.google.android.material.transition.platform.MaterialContainerTransform
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import org.jaudiotagger.audio.AudioFileIO
@ -66,15 +61,12 @@ import java.io.File
import java.io.FileOutputStream
import java.util.*
class LyricsFragment : AbsMusicServiceFragment(R.layout.fragment_lyrics) {
class LyricsFragment : AbsMainActivityFragment(R.layout.fragment_lyrics) {
private var _binding: FragmentLyricsBinding? = null
private val binding get() = _binding!!
private lateinit var song: Song
val mainActivity: MainActivity
get() = activity as MainActivity
private lateinit var lyricsSectionsAdapter: LyricsSectionsAdapter
private val googleSearchLrcUrl: String
@ -94,16 +86,6 @@ class LyricsFragment : AbsMusicServiceFragment(R.layout.fragment_lyrics) {
return baseUrl
}
private fun buildContainerTransform(): MaterialContainerTransform {
val transform = MaterialContainerTransform()
transform.setAllContainerColors(
MaterialColors.getColor(requireView().findViewById(R.id.container), R.attr.colorSurface)
)
transform.addTarget(R.id.container)
transform.duration = 300
return transform
}
private lateinit var normalLyricsLauncher: ActivityResultLauncher<IntentSenderRequest>
private lateinit var newSyncedLyricsLauncher: ActivityResultLauncher<Intent>
private lateinit var editSyncedLyricsLauncher: ActivityResultLauncher<IntentSenderRequest>
@ -143,13 +125,12 @@ class LyricsFragment : AbsMusicServiceFragment(R.layout.fragment_lyrics) {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setHasOptionsMenu(true)
updateTitleSong()
enterTransition = Fade()
exitTransition = Fade()
lyricsSectionsAdapter = LyricsSectionsAdapter(requireActivity())
_binding = FragmentLyricsBinding.bind(view)
binding.container.setTransitionName("lyrics")
binding.container.transitionName = "lyrics"
setupWakelock()
setupViews()
@ -208,7 +189,7 @@ class LyricsFragment : AbsMusicServiceFragment(R.layout.fragment_lyrics) {
requireActivity().window.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON)
}
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
inflater.inflate(R.menu.menu_search, menu)
ToolbarContentTintHelper.handleOnCreateOptionsMenu(
requireContext(),
@ -216,24 +197,18 @@ class LyricsFragment : AbsMusicServiceFragment(R.layout.fragment_lyrics) {
menu,
ATHToolbarActivity.getToolbarBackgroundColor(binding.toolbar)
)
return super.onCreateOptionsMenu(menu, inflater)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
findNavController().navigateUp()
return true
}
override fun onMenuItemSelected(item: MenuItem): Boolean {
if (item.itemId == R.id.action_search) {
RetroUtil.openUrl(
requireActivity(), when (binding.lyricsPager.currentItem) {
openUrl(when (binding.lyricsPager.currentItem) {
0 -> syairSearchLrcUrl
1 -> googleSearchLrcUrl
else -> googleSearchLrcUrl
}
)
}
return super.onOptionsItemSelected(item)
return false
}

View file

@ -67,7 +67,7 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(R.layout.fragment_mini_p
view.setOnTouchListener(FlingPlayBackController(requireContext()))
setUpMiniPlayer()
if (RetroUtil.isTablet()) {
if (RetroUtil.isTablet) {
binding.actionNext.show()
binding.actionPrevious.show()
} else {

View file

@ -15,16 +15,15 @@
package code.name.monkey.retromusic.fragments.other
import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import android.graphics.Color
import android.net.Uri
import android.os.Bundle
import android.view.LayoutInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.activity.result.ActivityResult
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.view.doOnPreDraw
import androidx.core.view.updateLayoutParams
import androidx.fragment.app.Fragment
@ -36,11 +35,12 @@ import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentUserInfoBinding
import code.name.monkey.retromusic.extensions.accentColor
import code.name.monkey.retromusic.extensions.applyToolbar
import code.name.monkey.retromusic.extensions.showToast
import code.name.monkey.retromusic.fragments.LibraryViewModel
import code.name.monkey.retromusic.glide.GlideApp
import code.name.monkey.retromusic.glide.RetroGlideExtension
import code.name.monkey.retromusic.util.ImageUtil
import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.PreferenceUtil.userName
import com.bumptech.glide.Glide
import com.bumptech.glide.load.DataSource
import com.bumptech.glide.load.engine.DiskCacheStrategy
@ -55,9 +55,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import org.koin.androidx.viewmodel.ext.android.sharedViewModel
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
class UserInfoFragment : Fragment() {
@ -85,7 +83,7 @@ class UserInfoFragment : Fragment() {
binding.nameContainer.accentColor()
binding.next.accentColor()
binding.name.setText(PreferenceUtil.userName)
binding.name.setText(userName)
binding.userImage.setOnClickListener {
showUserImageOptions()
@ -98,14 +96,10 @@ class UserInfoFragment : Fragment() {
binding.next.setOnClickListener {
val nameString = binding.name.text.toString().trim { it <= ' ' }
if (nameString.isEmpty()) {
Toast.makeText(
requireContext(),
"Your name can't be empty!",
Toast.LENGTH_SHORT
).show()
showToast("Your name can't be empty!")
return@setOnClickListener
}
PreferenceUtil.userName = nameString
userName = nameString
findNavController().navigateUp()
}
@ -172,19 +166,14 @@ class UserInfoFragment : Fragment() {
.into(binding.userImage)
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (item.itemId == android.R.id.home) {
findNavController().navigateUp()
}
return super.onOptionsItemSelected(item)
}
private fun selectBannerImage() {
ImagePicker.with(this)
.compress(1440)
.provider(ImageProvider.GALLERY)
.crop(16f, 9f)
.start(PICK_BANNER_REQUEST)
.createIntent {
startForBannerImageResult.launch(it)
}
}
private fun pickNewPhoto() {
@ -192,21 +181,40 @@ class UserInfoFragment : Fragment() {
.provider(ImageProvider.GALLERY)
.cropSquare()
.compress(1440)
.start(PICK_IMAGE_REQUEST)
.createIntent {
startForProfileImageResult.launch(it)
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (resultCode == Activity.RESULT_OK && requestCode == PICK_IMAGE_REQUEST) {
val fileUri = data?.data
fileUri?.let { setAndSaveUserImage(it) }
} else if (resultCode == Activity.RESULT_OK && requestCode == PICK_BANNER_REQUEST) {
val fileUri = data?.data
fileUri?.let { setAndSaveBannerImage(it) }
} else if (resultCode == ImagePicker.RESULT_ERROR) {
Toast.makeText(requireContext(), ImagePicker.getError(data), Toast.LENGTH_SHORT).show()
} else {
Toast.makeText(requireContext(), "Task Cancelled", Toast.LENGTH_SHORT).show()
private val startForProfileImageResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult ->
saveImage(result) { fileUri ->
setAndSaveUserImage(fileUri)
}
}
private val startForBannerImageResult =
registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result: ActivityResult ->
saveImage(result) { fileUri ->
setAndSaveBannerImage(fileUri)
}
}
private fun saveImage(result: ActivityResult, doIfResultOk: (uri: Uri) -> Unit) {
val resultCode = result.resultCode
val data = result.data
when (resultCode) {
Activity.RESULT_OK -> {
data?.data?.let { uri ->
doIfResultOk(uri)
}
}
ImagePicker.RESULT_ERROR -> {
showToast(ImagePicker.getError(data))
}
else -> {
showToast("Task Cancelled")
}
}
}
@ -245,7 +253,7 @@ class UserInfoFragment : Fragment() {
val file = File(appDir, fileName)
var successful = false
runCatching {
BufferedOutputStream(FileOutputStream(file)).use {
file.outputStream().buffered().use {
successful = ImageUtil.resizeBitmap(bitmap, 2048)
.compress(Bitmap.CompressFormat.WEBP, 100, it)
}
@ -254,7 +262,7 @@ class UserInfoFragment : Fragment() {
}
if (successful) {
withContext(Dispatchers.Main) {
Toast.makeText(requireContext(), "Updated", Toast.LENGTH_SHORT).show()
showToast("Updated")
}
}
}
@ -293,9 +301,4 @@ class UserInfoFragment : Fragment() {
super.onDestroyView()
_binding = null
}
companion object {
private const val PICK_IMAGE_REQUEST = 9002
private const val PICK_BANNER_REQUEST = 9004
}
}

View file

@ -116,12 +116,11 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
binding.viewPager.addOnPageChangeListener(this)
val nps = PreferenceUtil.nowPlayingScreen
val metrics = resources.displayMetrics
val ratio = metrics.heightPixels.toFloat() / metrics.widthPixels.toFloat()
if (nps == Full || nps == Classic || nps == Fit || nps == Gradient) {
binding.viewPager.offscreenPageLimit = 2
} else if (PreferenceUtil.isCarouselEffect) {
val metrics = resources.displayMetrics
val ratio = metrics.heightPixels.toFloat() / metrics.widthPixels.toFloat()
binding.viewPager.clipToPadding = false
val padding =
if (ratio >= 1.777f) {
@ -281,7 +280,7 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
setLRCViewColors(
when (PreferenceUtil.nowPlayingScreen) {
Adaptive, Fit, Plain, Simple -> surfaceColor()
Flat, Normal -> if (PreferenceUtil.isAdaptiveColor) {
Flat, Normal, Material -> if (PreferenceUtil.isAdaptiveColor) {
color.backgroundColor
} else {
surfaceColor()

View file

@ -48,9 +48,9 @@ class AdaptiveFragment : AbsPlayerFragment(R.layout.fragment_adaptive_player) {
private fun setUpSubFragments() {
playbackControlsFragment =
childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as AdaptivePlaybackControlsFragment
whichFragment(R.id.playbackControlsFragment) as AdaptivePlaybackControlsFragment
val playerAlbumCoverFragment =
childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment
whichFragment(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment
playerAlbumCoverFragment.apply {
removeSlideEffect()
setCallbacks(this@AdaptiveFragment)

View file

@ -27,6 +27,7 @@ import code.name.monkey.retromusic.NEW_BLUR_AMOUNT
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentBlurBinding
import code.name.monkey.retromusic.extensions.drawAboveSystemBars
import code.name.monkey.retromusic.extensions.whichFragment
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
import code.name.monkey.retromusic.glide.*
@ -62,10 +63,9 @@ class BlurPlayerFragment : AbsPlayerFragment(R.layout.fragment_blur),
}
private fun setUpSubFragments() {
playbackControlsFragment =
childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as BlurPlaybackControlsFragment
val playerAlbumCoverFragment =
childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment
playbackControlsFragment = whichFragment(R.id.playbackControlsFragment)
val playerAlbumCoverFragment: PlayerAlbumCoverFragment =
whichFragment(R.id.playerAlbumCoverFragment)
playerAlbumCoverFragment.setCallbacks(this)
}
@ -141,6 +141,7 @@ class BlurPlayerFragment : AbsPlayerFragment(R.layout.fragment_blur),
override fun onResume() {
super.onResume()
lastRequest = null
PreferenceManager.getDefaultSharedPreferences(requireContext())
.registerOnSharedPreferenceChangeListener(this)
}

View file

@ -22,9 +22,9 @@ import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentCardPlayerBinding
import code.name.monkey.retromusic.extensions.drawAboveSystemBars
import code.name.monkey.retromusic.extensions.whichFragment
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
import code.name.monkey.retromusic.fragments.player.normal.PlayerFragment
import code.name.monkey.retromusic.helper.MusicPlayerRemote
import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
@ -87,10 +87,9 @@ class CardFragment : AbsPlayerFragment(R.layout.fragment_card_player) {
}
private fun setUpSubFragments() {
playbackControlsFragment =
childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as CardPlaybackControlsFragment
val playerAlbumCoverFragment =
childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment
playbackControlsFragment = whichFragment(R.id.playbackControlsFragment)
val playerAlbumCoverFragment: PlayerAlbumCoverFragment =
whichFragment(R.id.playerAlbumCoverFragment)
playerAlbumCoverFragment.setCallbacks(this)
playerAlbumCoverFragment.removeSlideEffect()
}
@ -117,14 +116,4 @@ class CardFragment : AbsPlayerFragment(R.layout.fragment_card_player) {
super.onDestroyView()
_binding = null
}
companion object {
fun newInstance(): PlayerFragment {
val args = Bundle()
val fragment = PlayerFragment()
fragment.arguments = args
return fragment
}
}
}

View file

@ -26,6 +26,7 @@ import code.name.monkey.retromusic.NEW_BLUR_AMOUNT
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.databinding.FragmentCardBlurPlayerBinding
import code.name.monkey.retromusic.extensions.drawAboveSystemBars
import code.name.monkey.retromusic.extensions.whichFragment
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment
import code.name.monkey.retromusic.fragments.player.normal.PlayerFragment
@ -98,8 +99,8 @@ class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player),
private fun setUpSubFragments() {
playbackControlsFragment =
childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as CardBlurPlaybackControlsFragment
(childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment?)?.setCallbacks(
whichFragment(R.id.playbackControlsFragment) as CardBlurPlaybackControlsFragment
(whichFragment(R.id.playerAlbumCoverFragment) as? PlayerAlbumCoverFragment)?.setCallbacks(
this
)
}
@ -153,6 +154,7 @@ class CardBlurFragment : AbsPlayerFragment(R.layout.fragment_card_blur_player),
override fun onResume() {
super.onResume()
lastRequest = null
PreferenceManager.getDefaultSharedPreferences(requireContext())
.registerOnSharedPreferenceChangeListener(this)
}

View file

@ -166,6 +166,7 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
override fun onResume() {
super.onResume()
lastRequest = null
progressViewUpdateHelper.start()
if (audioVolumeObserver == null) {
audioVolumeObserver = AudioVolumeObserver(requireActivity())

View file

@ -32,13 +32,9 @@ import code.name.monkey.appthemehelper.util.ColorUtil
import code.name.monkey.appthemehelper.util.TintHelper
import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper
import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.RetroBottomSheetBehavior
import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter
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.show
import code.name.monkey.retromusic.extensions.surfaceColor
import code.name.monkey.retromusic.extensions.*
import code.name.monkey.retromusic.fragments.MusicSeekSkipTouchListener
import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
@ -57,6 +53,7 @@ import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.ViewUtil
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
import com.google.android.material.bottomsheet.BottomSheetBehavior
import com.google.android.material.bottomsheet.BottomSheetBehavior.from
import com.google.android.material.card.MaterialCardView
import com.google.android.material.shape.MaterialShapeDrawable
import com.google.android.material.shape.ShapeAppearanceModel
@ -88,7 +85,7 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
private val bottomSheetCallbackList = object : BottomSheetBehavior.BottomSheetCallback() {
override fun onSlide(bottomSheet: View, slideOffset: Float) {
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
mainActivity.getBottomSheetBehavior().isDraggable = false
binding.playerQueueSheet.setContentPadding(
binding.playerQueueSheet.contentPaddingLeft,
(slideOffset * binding.statusBar.height).toInt(),
@ -103,14 +100,14 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
when (newState) {
BottomSheetBehavior.STATE_EXPANDED,
BottomSheetBehavior.STATE_DRAGGING -> {
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
mainActivity.getBottomSheetBehavior().isDraggable = false
}
BottomSheetBehavior.STATE_COLLAPSED -> {
resetToCurrentPosition()
mainActivity.getBottomSheetBehavior().setAllowDragging(true)
mainActivity.getBottomSheetBehavior().isDraggable = true
}
else -> {
mainActivity.getBottomSheetBehavior().setAllowDragging(true)
mainActivity.getBottomSheetBehavior().isDraggable = true
}
}
}
@ -131,8 +128,7 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
hideVolumeIfAvailable()
setupRecyclerView()
val coverFragment =
childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment
val coverFragment: PlayerAlbumCoverFragment = whichFragment(R.id.playerAlbumCoverFragment)
coverFragment.setCallbacks(this)
getQueuePanel().addBottomSheetCallback(bottomSheetCallbackList)
@ -149,8 +145,8 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
binding.playerQueueSheet.background = shapeDrawable
binding.playerQueueSheet.setOnTouchListener { _, _ ->
mainActivity.getBottomSheetBehavior().setAllowDragging(false)
getQueuePanel().setAllowDragging(true)
mainActivity.getBottomSheetBehavior().isDraggable = false
getQueuePanel().isDraggable = true
return@setOnTouchListener false
}
@ -174,7 +170,7 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
}
childFragmentManager.executePendingTransactions()
volumeFragment =
childFragmentManager.findFragmentById(R.id.volumeFragmentContainer) as VolumeFragment?
whichFragment(R.id.volumeFragmentContainer) as VolumeFragment?
}
}
@ -363,12 +359,12 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0)
}
private fun getQueuePanel(): RetroBottomSheetBehavior<MaterialCardView> {
return RetroBottomSheetBehavior.from(binding.playerQueueSheet) as RetroBottomSheetBehavior<MaterialCardView>
private fun getQueuePanel(): BottomSheetBehavior<MaterialCardView> {
return from(binding.playerQueueSheet)
}
private fun setupPanel() {
if (!binding.playerContainer.isLaidOut() || binding.playerContainer.isLayoutRequested) {
if (!binding.playerContainer.isLaidOut || binding.playerContainer.isLayoutRequested) {
binding.playerContainer.addOnLayoutChangeListener(this)
return
}
@ -419,7 +415,7 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
linearLayoutManager.scrollToPositionWithOffset(MusicPlayerRemote.position + 1, 0)
}
fun setUpProgressSlider() {
private fun setUpProgressSlider() {
binding.playerControlsContainer.progressSlider.setOnSeekBarChangeListener(object :
SimpleOnSeekbarChangeListener() {
override fun onProgressChanged(seekBar: SeekBar, progress: Int, fromUser: Boolean) {

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