diff --git a/app/build.gradle b/app/build.gradle index d5bca44df..deab9fdbc 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -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' } \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6351206bf..909d433e1 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -19,7 +19,7 @@ tools:ignore="ProtectedPermissions" /> - + - @@ -190,7 +189,6 @@ - +
+
May 07, 2022
+

v5.8.3

+

What's New

+
    +
  • Swipe down to dismiss Mini player
  • +
  • Add support for Just Black with Material You
  • +
+

Fixed

+
    +
  • Fixed sharing of files from SD Card
  • +
  • Fix ChromeCast crash and bugs
  • +
  • Fix Audio Crossfade
  • +
  • Tried to fix incorrect song data in notification
  • +
+
April 8, 2022

v5.8.0

diff --git a/app/src/main/java/code/name/monkey/retromusic/App.kt b/app/src/main/java/code/name/monkey/retromusic/App.kt index 7269a5a69..4d4bf4d00 100644 --- a/app/src/main/java/code/name/monkey/retromusic/App.kt +++ b/app/src/main/java/code/name/monkey/retromusic/App.kt @@ -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?) {} diff --git a/app/src/main/java/code/name/monkey/retromusic/Constants.kt b/app/src/main/java/code/name/monkey/retromusic/Constants.kt index 3d224be7b..04f7a0e2f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/Constants.kt +++ b/app/src/main/java/code/name/monkey/retromusic/Constants.kt @@ -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 diff --git a/app/src/main/java/code/name/monkey/retromusic/LanguageContextWrapper.java b/app/src/main/java/code/name/monkey/retromusic/LanguageContextWrapper.java deleted file mode 100644 index 2e8852664..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/LanguageContextWrapper.java +++ /dev/null @@ -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); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/LanguageContextWrapper.kt b/app/src/main/java/code/name/monkey/retromusic/LanguageContextWrapper.kt new file mode 100644 index 000000000..a14c8fdd5 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/LanguageContextWrapper.kt @@ -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)) + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt index bce82a70d..c1c58f3de 100644 --- a/app/src/main/java/code/name/monkey/retromusic/MainModule.kt +++ b/app/src/main/java/code/name/monkey/retromusic/MainModule.kt @@ -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,13 +89,14 @@ private val roomModule = module { } private val autoModule = module { single { - AutoMusicProvider(androidContext(), - get(), - get(), - get(), - get(), - get(), - get() + AutoMusicProvider( + androidContext(), + get(), + get(), + get(), + get(), + get(), + get() ) } } @@ -102,6 +104,9 @@ private val mainModule = module { single { androidContext().contentResolver } + single { + RetroWebServer(get()) + } } private val dataModule = module { single { diff --git a/app/src/main/java/code/name/monkey/retromusic/RetroBottomSheetBehavior.java b/app/src/main/java/code/name/monkey/retromusic/RetroBottomSheetBehavior.java deleted file mode 100644 index 1ad8c572d..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/RetroBottomSheetBehavior.java +++ /dev/null @@ -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 extends BottomSheetBehavior { - - 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); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/DriveModeActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/DriveModeActivity.kt index 39c46e712..81f880ace 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/DriveModeActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/DriveModeActivity.kt @@ -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,14 +91,12 @@ 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) { - repository.removeSongFromPlaylist(songEntity) - } else { - repository.insertSongs(listOf(song.toSongEntity(playlist.playListId))) - } + val songEntity = song.toSongEntity(playlist.playListId) + val isFavorite = repository.isSongFavorite(song.id) + if (isFavorite) { + repository.removeSongFromPlaylist(songEntity) + } 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) } diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/LicenseActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/LicenseActivity.kt index e4d6a8f40..755793938 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/LicenseActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/LicenseActivity.kt @@ -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") diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt index 6757172d2..74d173fc5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/MainActivity.kt @@ -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") diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/PermissionActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/PermissionActivity.kt index 57a0d2657..3344f8e05 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/PermissionActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/PermissionActivity.kt @@ -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!
Welcome to Retro Music" - .parseAsHtml() + val appName = + "Hello there!
Welcome to Retro Music" + .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 (hasAudioPermission()) { - binding.audioPermission.checkImage.isVisible = true - binding.audioPermission.checkImage.imageTintList = - ColorStateList.valueOf(ThemeStore.accentColor(this)) + if (VersionUtils.hasMarshmallow()) { + if (hasAudioPermission()) { + binding.audioPermission.checkImage.isVisible = true + binding.audioPermission.checkImage.imageTintList = + 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) diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/PurchaseActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/PurchaseActivity.kt index 656423df5..85072735e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/PurchaseActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/PurchaseActivity.kt @@ -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) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/ShareInstagramStory.kt b/app/src/main/java/code/name/monkey/retromusic/activities/ShareInstagramStory.kt index 23b9bfb77..9ca6c4caf 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/ShareInstagramStory.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/ShareInstagramStory.kt @@ -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) { diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/SupportDevelopmentActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/SupportDevelopmentActivity.kt index fda12d6bf..511433043 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/SupportDevelopmentActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/SupportDevelopmentActivity.kt @@ -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() { diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewFragment.kt similarity index 57% rename from app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewActivity.kt rename to app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewFragment.kt index e3d6644f1..dd0f50821 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/WhatsNewFragment.kt @@ -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() { "

Unable to load

" + e.localizedMessage + "

", "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) + } + } } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsBaseActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsBaseActivity.kt index fa29c98fb..386bd560d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsBaseActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsBaseActivity.kt @@ -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,17 +90,13 @@ 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) { - return false - } + for (permission in permissions) { + if (ActivityCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { + return false } } return true @@ -126,24 +122,25 @@ 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) { - val intent = Intent() - intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS - val uri = Uri.fromParts( - "package", - this@AbsBaseActivity.packageName, - null - ) - intent.data = uri - startActivity(intent) - }.setActionTextColor(ThemeStore.accentColor(this)).show() + ) + .setAction(R.string.action_settings) { + val intent = Intent() + intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS + val uri = Uri.fromParts( + "package", + this@AbsBaseActivity.packageName, + null + ) + intent.data = uri + startActivity(intent) + }.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()?.hideSoftInputFromWindow(v.windowToken, 0) + getSystemService()?.hideSoftInputFromWindow( + v.windowToken, + 0 + ) } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsCastActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsCastActivity.kt index d5157bc2b..ffd0eaadc 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsCastActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsCastActivity.kt @@ -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() - mCastSession = null + 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()) { - mCastSession?.let { + 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(R.id.cast_stub)?.inflate() - } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt index fe169e332..62101f2d4 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsSlidingMusicPanelActivity.kt @@ -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() - private lateinit var bottomSheetBehavior: RetroBottomSheetBehavior + private lateinit var bottomSheetBehavior: BottomSheetBehavior 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) { - binding.bottomNavigationView.bringToFront() - } + 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) } diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsThemeActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsThemeActivity.kt index 25e6d2d65..b2aba2318 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsThemeActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/base/AbsThemeActivity.kt @@ -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) { diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt index 4bf23f402..68494eeea 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/BugReportActivity.kt @@ -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() 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" } } diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/DeviceInfo.kt b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/DeviceInfo.kt index 98d0a6d55..142d3fed5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/DeviceInfo.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/bugreport/model/DeviceInfo.kt @@ -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 diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt index 8cf8cbd40..4185287f3 100755 --- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AbsTagEditorActivity.kt @@ -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 : AbsBaseActivity() { 2 -> deleteImage() } } + .setNegativeButton(R.string.action_cancel, null) .show() + .colorButtons() internal val albumArtist: String? get() { @@ -346,7 +349,7 @@ abstract class AbsTagEditorActivity : AbsBaseActivity() { fieldKeyValueMap: Map, artworkInfo: ArtworkInfo? ) { - RetroUtil.hideSoftKeyboard(this) + hideSoftKeyboard() hideFab() println(fieldKeyValueMap) diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt index 40e03b8a3..8f30f8de3 100755 --- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/AlbumTagEditorActivity.kt @@ -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 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?) {} diff --git a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/TagWriter.kt b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/TagWriter.kt index a78624583..e4cf7fe89 100644 --- a/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/TagWriter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/activities/tageditor/TagWriter.kt @@ -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?) { 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) { diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.kt index 0347d42b7..496f60a13 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/CategoryInfoAdapter.kt @@ -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 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 -> diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/ContributorAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/ContributorAdapter.kt index 28719c962..de7226b5c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/ContributorAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/ContributorAdapter.kt @@ -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) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/SongFileAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/SongFileAdapter.kt index c6c0a2b5a..f6ed05809 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/SongFileAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/SongFileAdapter.kt @@ -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, private val itemLayoutRes: Int, private val iCallbacks: ICallbacks?, - iCabHolder: ICabHolder? + iCabHolder: ICabHolder?, ) : AbsMultiSelectAdapter( 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) { diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumAdapter.kt index ade999edc..49b00d412 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumAdapter.kt @@ -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( diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt index a568ad12d..7d0f1bd4d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/album/AlbumCoverPagerAdapter.kt @@ -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)) diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/artist/ArtistAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/artist/ArtistAdapter.kt index d896b1c73..4976fcb44 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/artist/ArtistAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/artist/ArtistAdapter.kt @@ -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( diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/base/AbsMultiSelectAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/base/AbsMultiSelectAdapter.kt index 093233c36..675c3cbda 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/base/AbsMultiSelectAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/base/AbsMultiSelectAdapter.kt @@ -64,9 +64,8 @@ abstract class AbsMultiSelectAdapter( } 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) diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt index d039691ee..70afd22b1 100755 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/playlist/PlaylistAdapter.kt @@ -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) { @@ -163,7 +163,7 @@ class PlaylistAdapter( if (isInQuickSelectMode) { toggleChecked(layoutPosition) } else { - itemView.setTransitionName("playlist") + itemView.transitionName = "playlist" listener.onPlaylistClick(dataSet[layoutPosition], itemView) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/ShuffleButtonSongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/ShuffleButtonSongAdapter.kt index 29ccf448b..b8f053ec7 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/ShuffleButtonSongAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/ShuffleButtonSongAdapter.kt @@ -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 } diff --git a/app/src/main/java/code/name/monkey/retromusic/adapter/song/SongAdapter.kt b/app/src/main/java/code/name/monkey/retromusic/adapter/song/SongAdapter.kt index b76ce5d25..a7c6b634d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/adapter/song/SongAdapter.kt +++ b/app/src/main/java/code/name/monkey/retromusic/adapter/song/SongAdapter.kt @@ -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) { diff --git a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutIconGenerator.kt b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutIconGenerator.kt index 78d8d90a2..ad8f964e7 100644 --- a/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutIconGenerator.kt +++ b/app/src/main/java/code/name/monkey/retromusic/appshortcuts/AppShortcutIconGenerator.kt @@ -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()) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetBig.kt b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetBig.kt index ac2f6359f..0aea9d366 100644 --- a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetBig.kt +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetBig.kt @@ -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.drawable.ic_skip_next, - MaterialValueHelper.getPrimaryTextColor(context, false) - ), 1f - ) + R.id.button_next, context.getTintedDrawable( + R.drawable.ic_skip_next, + MaterialValueHelper.getPrimaryTextColor(context, false) + ).toBitmap() ) appWidgetView.setImageViewBitmap( - R.id.button_prev, createBitmap( - RetroUtil.getTintedVectorDrawable( - context, - R.drawable.ic_skip_previous, - MaterialValueHelper.getPrimaryTextColor(context, false) - ), 1f - ) + R.id.button_prev, + context.getTintedDrawable( + R.drawable.ic_skip_previous, + MaterialValueHelper.getPrimaryTextColor(context, false) + ).toBitmap() ) appWidgetView.setImageViewBitmap( - R.id.button_toggle_play_pause, createBitmap( - RetroUtil.getTintedVectorDrawable( - context, - R.drawable.ic_play_arrow_white_32dp, - MaterialValueHelper.getPrimaryTextColor(context, false) - ), 1f - ) + R.id.button_toggle_play_pause, + context.getTintedDrawable( + R.drawable.ic_play_arrow_white_32dp, + MaterialValueHelper.getPrimaryTextColor(context, false) + ).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, - playPauseRes, - primaryColor - ), 1f - ) + R.id.button_toggle_play_pause, + service.getTintedDrawable( + playPauseRes, + primaryColor + ).toBitmap() ) // Set prev/next button drawables appWidgetView.setImageViewBitmap( - R.id.button_next, createBitmap( - RetroUtil.getTintedVectorDrawable( - service, - R.drawable.ic_skip_next, - primaryColor - ), 1f - ) + R.id.button_next, + service.getTintedDrawable( + R.drawable.ic_skip_next, + primaryColor + ).toBitmap() ) appWidgetView.setImageViewBitmap( - R.id.button_prev, createBitmap( - RetroUtil.getTintedVectorDrawable( - service, - R.drawable.ic_skip_previous, - primaryColor - ), 1f - ) + R.id.button_prev, + service.getTintedDrawable( + R.drawable.ic_skip_previous, + primaryColor + ).toBitmap() ) // Link actions buttons to intents @@ -167,10 +156,10 @@ class AppWidgetBig : BaseAppWidget() { .asBitmap() //.checkIgnoreMediaStore() .load(RetroGlideExtension.getSongModel(song)) - .into(object : SimpleTarget(widgetImageSize, widgetImageSize) { + .into(object : CustomTarget(widgetImageSize, widgetImageSize) { override fun onResourceReady( resource: Bitmap, - transition: Transition? + transition: Transition?, ) { 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( diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetCard.kt b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetCard.kt index ee3e1c990..80e0b09ea 100644 --- a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetCard.kt +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetCard.kt @@ -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.drawable.ic_skip_next, - secondaryColor - ), 1f - ) + R.id.button_next, + context.getTintedDrawable( + R.drawable.ic_skip_next, + secondaryColor + ).toBitmap() ) appWidgetView.setImageViewBitmap( - R.id.button_prev, createBitmap( - RetroUtil.getTintedVectorDrawable( - context, - R.drawable.ic_skip_previous, - secondaryColor - ), 1f - ) + R.id.button_prev, + context.getTintedDrawable( + R.drawable.ic_skip_previous, + secondaryColor + ).toBitmap() ) appWidgetView.setImageViewBitmap( - R.id.button_toggle_play_pause, createBitmap( - RetroUtil.getTintedVectorDrawable( - context, - R.drawable.ic_play_arrow_white_32dp, - secondaryColor - ), 1f - ) + R.id.button_toggle_play_pause, + context.getTintedDrawable( + R.drawable.ic_play_arrow_white_32dp, + secondaryColor + ).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, - playPauseRes, - MaterialValueHelper.getSecondaryTextColor(service, true) - ), 1f - ) + R.id.button_toggle_play_pause, + service.getTintedDrawable( + playPauseRes, + MaterialValueHelper.getSecondaryTextColor(service, true) + ).toBitmap() ) // Set prev/next button drawables appWidgetView.setImageViewBitmap( - R.id.button_next, createBitmap( - RetroUtil.getTintedVectorDrawable( - service, - R.drawable.ic_skip_next, - MaterialValueHelper.getSecondaryTextColor(service, true) - ), 1f - ) + R.id.button_next, + service.getTintedDrawable( + R.drawable.ic_skip_next, + MaterialValueHelper.getSecondaryTextColor(service, true) + ).toBitmap() ) appWidgetView.setImageViewBitmap( - R.id.button_prev, createBitmap( - RetroUtil.getTintedVectorDrawable( - service, - R.drawable.ic_skip_previous, - MaterialValueHelper.getSecondaryTextColor(service, true) - ), 1f - ) + R.id.button_prev, + service.getTintedDrawable( + R.drawable.ic_skip_previous, + MaterialValueHelper.getSecondaryTextColor(service, true) + ).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(imageSize, imageSize) { + .into(object : CustomTarget(imageSize, imageSize) { override fun onResourceReady( resource: BitmapPaletteWrapper, - transition: Transition? + transition: Transition?, ) { 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 ) diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetCircle.kt b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetCircle.kt index f89319eea..cdb48a063 100644 --- a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetCircle.kt +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetCircle.kt @@ -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.drawable.ic_play_arrow, - secondaryColor - ), 1f - ) + R.id.button_toggle_play_pause, + context.getTintedDrawable( + R.drawable.ic_play_arrow, + secondaryColor + ).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, - playPauseRes, - MaterialValueHelper.getSecondaryTextColor(service, true) - ), 1f - ) + R.id.button_toggle_play_pause, + service.getTintedDrawable( + playPauseRes, + MaterialValueHelper.getSecondaryTextColor(service, true) + ).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, - favoriteRes, - MaterialValueHelper.getSecondaryTextColor(service, true) - ), 1f - ) + R.id.button_toggle_favorite, + service.getTintedDrawable( + favoriteRes, + MaterialValueHelper.getSecondaryTextColor(service, true) + ).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(imageSize, imageSize) { + .apply(RequestOptions.circleCropTransform()) + .into(object : CustomTarget(imageSize, imageSize) { override fun onResourceReady( resource: BitmapPaletteWrapper, - transition: Transition? + transition: Transition?, ) { 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() ) - appWidgetView.setImageViewBitmap(R.id.image, bitmap) + if (bitmap != null) { + appWidgetView.setImageViewBitmap(R.id.image, bitmap) + } pushUpdate(service, appWidgetIds, appWidgetView) } + + override fun onLoadCleared(placeholder: Drawable?) {} }) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetClassic.kt b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetClassic.kt index 87cacc283..2f1d7b173 100644 --- a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetClassic.kt +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetClassic.kt @@ -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, - R.drawable.ic_skip_next, - MaterialValueHelper.getSecondaryTextColor(context, true) - ), 1f - ) + + context.getTintedDrawable( + R.drawable.ic_skip_next, + MaterialValueHelper.getSecondaryTextColor(context, true) + ).toBitmap() ) appWidgetView.setImageViewBitmap( R.id.button_prev, - createBitmap( - RetroUtil.getTintedVectorDrawable( - context, - R.drawable.ic_skip_previous, - MaterialValueHelper.getSecondaryTextColor(context, true) - ), 1f - ) + + context.getTintedDrawable( + R.drawable.ic_skip_previous, + MaterialValueHelper.getSecondaryTextColor(context, true) + ).toBitmap() ) appWidgetView.setImageViewBitmap( R.id.button_toggle_play_pause, - createBitmap( - RetroUtil.getTintedVectorDrawable( - context, - R.drawable.ic_play_arrow_white_32dp, - MaterialValueHelper.getSecondaryTextColor(context, true) - ), 1f - ) + + context.getTintedDrawable( + R.drawable.ic_play_arrow_white_32dp, + MaterialValueHelper.getSecondaryTextColor(context, true) + ).toBitmap() ) linkButtons(context, appWidgetView) @@ -129,10 +123,10 @@ class AppWidgetClassic : BaseAppWidget() { .load(RetroGlideExtension.getSongModel(song)) //.checkIgnoreMediaStore() .centerCrop() - .into(object : SimpleTarget(imageSize, imageSize) { + .into(object : CustomTarget(imageSize, imageSize) { override fun onResourceReady( resource: BitmapPaletteWrapper, - transition: Transition? + transition: Transition?, ) { 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, - playPauseRes, - color - ) - ) + 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 - ) - ) + 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 - ) - ) + service.getTintedDrawable( + R.drawable.ic_skip_previous, + color + ).toBitmap() ) - val image = getAlbumArtDrawable(service.resources, bitmap) + val image = getAlbumArtDrawable(service, bitmap) val roundedBitmap = createRoundedBitmap( image, diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetMD3.kt b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetMD3.kt index 0ce4ebf28..cc07fa1d2 100644 --- a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetMD3.kt +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetMD3.kt @@ -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.drawable.ic_skip_next, - secondaryColor - ), 1f - ) + R.id.button_next, + context.getTintedDrawable( + R.drawable.ic_skip_next, + secondaryColor + ).toBitmap() ) appWidgetView.setImageViewBitmap( - R.id.button_prev, createBitmap( - RetroUtil.getTintedVectorDrawable( - context, - R.drawable.ic_skip_previous, - secondaryColor - ), 1f - ) + R.id.button_prev, + context.getTintedDrawable( + R.drawable.ic_skip_previous, + secondaryColor + ).toBitmap() ) appWidgetView.setImageViewBitmap( - R.id.button_toggle_play_pause, createBitmap( - RetroUtil.getTintedVectorDrawable( - context, - R.drawable.ic_play_arrow_white_32dp, - secondaryColor - ), 1f - ) + R.id.button_toggle_play_pause, + context.getTintedDrawable( + R.drawable.ic_play_arrow_white_32dp, + secondaryColor + ).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, - playPauseRes, - MaterialValueHelper.getSecondaryTextColor(service, true) - ), 1f - ) + R.id.button_toggle_play_pause, + service.getTintedDrawable( + playPauseRes, + MaterialValueHelper.getSecondaryTextColor(service, true) + ).toBitmap() ) // Set prev/next button drawables appWidgetView.setImageViewBitmap( - R.id.button_next, createBitmap( - RetroUtil.getTintedVectorDrawable( - service, - R.drawable.ic_skip_next, - MaterialValueHelper.getSecondaryTextColor(service, true) - ), 1f - ) + R.id.button_next, + service.getTintedDrawable( + R.drawable.ic_skip_next, + MaterialValueHelper.getSecondaryTextColor(service, true) + ).toBitmap() ) appWidgetView.setImageViewBitmap( - R.id.button_prev, createBitmap( - RetroUtil.getTintedVectorDrawable( - service, - R.drawable.ic_skip_previous, - MaterialValueHelper.getSecondaryTextColor(service, true) - ), 1f - ) + R.id.button_prev, + service.getTintedDrawable( + R.drawable.ic_skip_previous, + MaterialValueHelper.getSecondaryTextColor(service, true) + ).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(imageSize, imageSize) { + .into(object : CustomTarget(imageSize, imageSize) { override fun onResourceReady( resource: BitmapPaletteWrapper, - transition: Transition? + transition: Transition?, ) { 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, diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetSmall.kt b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetSmall.kt index 3a92daa1e..12246e860 100644 --- a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetSmall.kt +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetSmall.kt @@ -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, - R.drawable.ic_skip_next, - MaterialValueHelper.getSecondaryTextColor(context, true) - ), 1f - ) + context.getTintedDrawable( + R.drawable.ic_skip_next, + MaterialValueHelper.getSecondaryTextColor(context, true) + ).toBitmap() ) appWidgetView.setImageViewBitmap( R.id.button_prev, - createBitmap( - RetroUtil.getTintedVectorDrawable( - context, - R.drawable.ic_skip_previous, - MaterialValueHelper.getSecondaryTextColor(context, true) - ), 1f - ) + + context.getTintedDrawable( + R.drawable.ic_skip_previous, + MaterialValueHelper.getSecondaryTextColor(context, true) + ).toBitmap() ) appWidgetView.setImageViewBitmap( R.id.button_toggle_play_pause, - createBitmap( - RetroUtil.getTintedVectorDrawable( - context, - R.drawable.ic_play_arrow_white_32dp, - MaterialValueHelper.getSecondaryTextColor(context, true) - ), 1f - ) + + context.getTintedDrawable( + R.drawable.ic_play_arrow_white_32dp, + MaterialValueHelper.getSecondaryTextColor(context, true) + ).toBitmap() ) linkButtons(context, appWidgetView) @@ -132,10 +126,10 @@ class AppWidgetSmall : BaseAppWidget() { //.checkIgnoreMediaStore() .load(RetroGlideExtension.getSongModel(song)) .centerCrop() - .into(object : SimpleTarget(imageSize, imageSize) { + .into(object : CustomTarget(imageSize, imageSize) { override fun onResourceReady( resource: BitmapPaletteWrapper, - transition: Transition? + transition: Transition?, ) { 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 ) diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetText.kt b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetText.kt index 76bbc77c5..5e9004e98 100644 --- a/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetText.kt +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/AppWidgetText.kt @@ -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( - context, R.color.md_white_1000 - ) - ), 1f - ) + R.id.button_next, + context.getTintedDrawable(R.drawable.ic_skip_next, ContextCompat.getColor( + context, R.color.md_white_1000 + )).toBitmap() ) appWidgetView.setImageViewBitmap( - R.id.button_prev, createBitmap( - RetroUtil.getTintedVectorDrawable( - context, R.drawable.ic_skip_previous, ContextCompat.getColor( - context, R.color.md_white_1000 - ) - ), 1f + R.id.button_prev, + context.getTintedDrawable(R.drawable.ic_skip_previous, ContextCompat.getColor( + context, R.color.md_white_1000 ) + ).toBitmap() ) appWidgetView.setImageViewBitmap( - R.id.button_toggle_play_pause, createBitmap( - RetroUtil.getTintedVectorDrawable( - context, R.drawable.ic_play_arrow_white_32dp, ContextCompat.getColor( - context, R.color.md_white_1000 - ) - ), 1f + R.id.button_toggle_play_pause, + context.getTintedDrawable(R.drawable.ic_play_arrow_white_32dp, ContextCompat.getColor( + context, R.color.md_white_1000 ) + ).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.drawable.ic_skip_next, - ContextCompat.getColor( - App.getContext(), R.color.md_white_1000 - ) - ), 1f - ) + R.id.button_next, + service.getTintedDrawable( + R.drawable.ic_skip_next, + ContextCompat.getColor( + service, + R.color.md_white_1000 + ) + ).toBitmap() ) appWidgetView.setImageViewBitmap( - R.id.button_prev, createBitmap( - RetroUtil.getTintedVectorDrawable( - App.getContext(), - R.drawable.ic_skip_previous, - ContextCompat.getColor( - App.getContext(), R.color.md_white_1000 - ) - ), 1f - ) + R.id.button_prev, + service.getTintedDrawable( + R.drawable.ic_skip_previous, + ContextCompat.getColor( + service, R.color.md_white_1000 + ) + ).toBitmap() ) pushUpdate(service.applicationContext, appWidgetIds, appWidgetView) diff --git a/app/src/main/java/code/name/monkey/retromusic/appwidgets/base/BaseAppWidget.kt b/app/src/main/java/code/name/monkey/retromusic/appwidgets/base/BaseAppWidget.kt index a95c35a7e..e460b7956 100644 --- a/app/src/main/java/code/name/monkey/retromusic/appwidgets/base/BaseAppWidget.kt +++ b/app/src/main/java/code/name/monkey/retromusic/appwidgets/base/BaseAppWidget.kt @@ -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, diff --git a/app/src/main/java/code/name/monkey/retromusic/auto/MediaItemBuilder.kt b/app/src/main/java/code/name/monkey/retromusic/auto/MediaItemBuilder.kt index b94a60274..534b0ec52 100644 --- a/app/src/main/java/code/name/monkey/retromusic/auto/MediaItemBuilder.kt +++ b/app/src/main/java/code/name/monkey/retromusic/auto/MediaItemBuilder.kt @@ -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 } diff --git a/app/src/main/java/code/name/monkey/retromusic/cast/CastHelper.kt b/app/src/main/java/code/name/monkey/retromusic/cast/CastHelper.kt index 426fdcb9a..05839216f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/cast/CastHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/cast/CastHelper.kt @@ -79,6 +79,5 @@ object CastHelper { setMetadata(musicMetadata) setStreamDuration(song.duration) }.build() - } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/cast/CastOptionsProvider.kt b/app/src/main/java/code/name/monkey/retromusic/cast/CastOptionsProvider.kt index cf365c84a..7bbc955be 100644 --- a/app/src/main/java/code/name/monkey/retromusic/cast/CastOptionsProvider.kt +++ b/app/src/main/java/code/name/monkey/retromusic/cast/CastOptionsProvider.kt @@ -1,3 +1,5 @@ +@file:Suppress("unused") + package code.name.monkey.retromusic.cast import android.content.Context diff --git a/app/src/main/java/code/name/monkey/retromusic/cast/RetroSessionManager.kt b/app/src/main/java/code/name/monkey/retromusic/cast/RetroSessionManagerListener.kt similarity index 69% rename from app/src/main/java/code/name/monkey/retromusic/cast/RetroSessionManager.kt rename to app/src/main/java/code/name/monkey/retromusic/cast/RetroSessionManagerListener.kt index 69bc45348..020dd21b2 100644 --- a/app/src/main/java/code/name/monkey/retromusic/cast/RetroSessionManager.kt +++ b/app/src/main/java/code/name/monkey/retromusic/cast/RetroSessionManagerListener.kt @@ -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 { - override fun onSessionResuming(p0: CastSession, p1: String) { +interface RetroSessionManagerListener : SessionManagerListener { + override fun onSessionResuming(p0: CastSession, p1: String) {} - } + override fun onSessionStartFailed(p0: CastSession, p1: Int) {} - override fun onSessionStartFailed(p0: CastSession, p1: Int) { + override fun onSessionResumeFailed(p0: CastSession, p1: Int) {} - } - - override fun onSessionResumeFailed(p0: CastSession, p1: Int) { - - } - - override fun onSessionEnding(p0: CastSession) { - - } + override fun onSessionEnding(castSession: CastSession) {} } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/cast/RetroWebServer.kt b/app/src/main/java/code/name/monkey/retromusic/cast/RetroWebServer.kt index faee38b2e..658e1bf88 100644 --- a/app/src/main/java/code/name/monkey/retromusic/cast/RetroWebServer.kt +++ b/app/src/main/java/code/name/monkey/retromusic/cast/RetroWebServer.kt @@ -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?, - parms: MutableMap?, - files: MutableMap? - ): 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) diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.kt index 1440270c0..c4bdd047d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/AddToPlaylistDialog.kt @@ -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): ArrayAdapter { - val adapter = ArrayAdapter(requireContext(), R.layout.item_simple_text, R.id.title) - adapter.addAll(playlists) - return adapter - } - override fun onCreateDialog(savedInstanceState: Bundle?): Dialog { val playlistEntities = extraNotNull>(EXTRA_PLAYLISTS).value val songs = extraNotNull>(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 -> - if (which == 0) { + .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) { diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.kt index 738269cb3..0b787608f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/BlacklistFolderChooserDialog.kt @@ -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? = 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() diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt index 8a3324c8d..bd9b3e258 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/CreatePlaylistDialog.kt @@ -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() } diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/RenamePlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/RenamePlaylistDialog.kt index 79b7d2501..18a3ab714 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/RenamePlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/RenamePlaylistDialog.kt @@ -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(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() diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/SavePlaylistDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/SavePlaylistDialog.kt index ef4dd7cce..157a1b221 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/SavePlaylistDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/SavePlaylistDialog.kt @@ -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() } } diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/SongDetailDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/SongDetailDialog.kt index 339996d5b..5a5c90855 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/SongDetailDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/SongDetailDialog.kt @@ -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(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, "-") + samplingRate.text = makeTextWithTitle(context, R.string.label_sampling_rate, "-") + } - 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, "-") - 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() } diff --git a/app/src/main/java/code/name/monkey/retromusic/dialogs/SongShareDialog.kt b/app/src/main/java/code/name/monkey/retromusic/dialogs/SongShareDialog.kt index 5c7af6733..ab50e3dc4 100644 --- a/app/src/main/java/code/name/monkey/retromusic/dialogs/SongShareDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/dialogs/SongShareDialog.kt @@ -46,6 +46,7 @@ class SongShareDialog : DialogFragment() { ) { _, which -> withAction(which, song, listening) } + .setNegativeButton(R.string.action_cancel, null) .create() .colorButtons() } diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/ActivityThemeExtensions.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/ActivityThemeExtensions.kt index 60b90f6a4..c4a5c7ee8 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/ActivityThemeExtensions.kt +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/ActivityThemeExtensions.kt @@ -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 @@ -221,4 +223,13 @@ fun AppCompatActivity.setStatusBarColorPreMarshmallow(color: Int) { } else { window.statusBarColor = ColorUtil.darkenColor(color) } +} + +fun AppCompatActivity.hideSoftKeyboard() { + val currentFocus: View? = currentFocus + if (currentFocus != null) { + val inputMethodManager = + getSystemService() + inputMethodManager?.hideSoftInputFromWindow(currentFocus.windowToken, 0) + } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExtensions.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExtensions.kt index c31a3e675..20d6d14d8 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExtensions.kt +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/ColorExtensions.kt @@ -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() { diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/ContextExtensions.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/ContextExtensions.kt new file mode 100644 index 000000000..a479903d7 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/ContextExtensions.kt @@ -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)!! +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/DialogExtension.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/DialogExtension.kt index 63f77e134..ffd894af4 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/DialogExtension.kt +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/DialogExtension.kt @@ -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( - requireContext(), - R.style.MaterialAlertDialogTheme - ).setTitle(title) +fun Fragment.materialDialog(title: Int): MaterialAlertDialogBuilder { + return if (BuildConfig.DEBUG) { + MaterialAlertDialogBuilder( + requireContext(), + R.style.MaterialAlertDialogTheme + ) + } else { + MaterialAlertDialogBuilder( + requireContext() + ) + }.setTitle(title) } fun AlertDialog.colorButtons(): AlertDialog { diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/DrawableExtensions.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/DrawableExtensions.kt index 9a7c76f96..c23f0e979 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/DrawableExtensions.kt +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/DrawableExtensions.kt @@ -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) diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/FileExtensions.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/FileExtensions.kt new file mode 100644 index 000000000..5c4df1a37 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/FileExtensions.kt @@ -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) \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/FragmentExtensions.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/FragmentExtensions.kt index a4082a824..b1e8f5930 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/FragmentExtensions.kt +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/FragmentExtensions.kt @@ -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 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 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 { diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/InsetsExtensions.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/InsetsExtensions.kt index 01bdaaafa..bc2f1bde9 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/InsetsExtensions.kt +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/InsetsExtensions.kt @@ -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 } } diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/IntentExtensions.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/IntentExtensions.kt index 1d7f25cab..e91e81347 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/IntentExtensions.kt +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/IntentExtensions.kt @@ -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 @@ -29,4 +31,16 @@ 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) } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/extensions/ViewExtensions.kt b/app/src/main/java/code/name/monkey/retromusic/extensions/ViewExtensions.kt index f4d94ea06..2ca9bbd37 100644 --- a/app/src/main/java/code/name/monkey/retromusic/extensions/ViewExtensions.kt +++ b/app/src/main/java/code/name/monkey/retromusic/extensions/ViewExtensions.kt @@ -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() diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt index 2ca92ef72..944b1db67 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/LibraryViewModel.kt @@ -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>() private val artists = MutableLiveData>() private val playlists = MutableLiveData>() - private val legacyPlaylists = MutableLiveData>() private val genres = MutableLiveData>() private val searchResults = MutableLiveData>() private val fabMargin = MutableLiveData(0) @@ -69,41 +70,21 @@ class LibraryViewModel( fun getSearchResult(): LiveData> = searchResults - fun getSongs(): LiveData> { - return songs - } + fun getSongs(): LiveData> = songs - fun getAlbums(): LiveData> { - return albums - } + fun getAlbums(): LiveData> = albums - fun getArtists(): LiveData> { - return artists - } + fun getArtists(): LiveData> = artists - fun getPlaylists(): LiveData> { - return playlists - } + fun getPlaylists(): LiveData> = playlists - fun getLegacyPlaylist(): LiveData> { - return legacyPlaylists - } + fun getGenre(): LiveData> = genres - fun getGenre(): LiveData> { - return genres - } + fun getHome(): LiveData> = home - fun getHome(): LiveData> { - return home - } + fun getSuggestions(): LiveData> = suggestions - fun getSuggestions(): LiveData> { - return suggestions - } - - fun getFabMargin(): LiveData { - return fabMargin - } + fun getFabMargin(): LiveData = 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()) } @@ -146,7 +120,7 @@ class LibraryViewModel( fun search(query: String?, filter: Filter) = viewModelScope.launch(IO) { - val result =repository.search(query, filter) + val result = repository.search(query, filter) searchResults.postValue(result) } @@ -267,35 +241,22 @@ class LibraryViewModel( } } - fun deleteTracks(songs: List) = viewModelScope.launch(IO) { - repository.deleteSongs(songs) - fetchPlaylists() - loadLibraryContent() - } - - fun recentSongs(): LiveData> = liveData { + fun recentSongs(): LiveData> = liveData(IO) { emit(repository.recentSongs()) } - fun playCountSongs(): LiveData> = liveData { - val songs = repository.playCountSongs().map { - it.toSong() - } - emit(songs) - // Cleaning up deleted or moved songs - withContext(IO) { - songs.forEach { song -> - if (!File(song.data).exists() || song.id == -1L) { - repository.deleteSongInPlayCount(song.toPlayCount()) - } + fun playCountSongs(): LiveData> = liveData(IO) { + repository.playCountSongs().forEach { song -> + if (!File(song.data).exists() || song.id == -1L) { + repository.deleteSongInPlayCount(song) } - emit(repository.playCountSongs().map { - it.toSong() - }) } + emit(repository.playCountSongs().map { + it.toSong() + }) } - fun artists(type: Int): LiveData> = liveData { + fun artists(type: Int): LiveData> = liveData(IO) { when (type) { TOP_ARTISTS -> emit(repository.topArtists()) RECENT_ARTISTS -> { @@ -304,7 +265,7 @@ class LibraryViewModel( } } - fun albums(type: Int): LiveData> = liveData { + fun albums(type: Int): LiveData> = liveData(IO) { when (type) { TOP_ALBUMS -> emit(repository.topAlbums()) RECENT_ALBUMS -> { @@ -313,29 +274,25 @@ class LibraryViewModel( } } - fun artist(artistId: Long): LiveData = liveData { + fun artist(artistId: Long): LiveData = liveData(IO) { emit(repository.artistById(artistId)) } - fun fetchContributors(): LiveData> = liveData { + fun fetchContributors(): LiveData> = liveData(IO) { emit(repository.contributor()) } fun observableHistorySongs(): LiveData> { - 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 { - it.toSong() + + 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) { + fun addToPlaylist(context: Context, playlistName: String, songs: List) { 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( - R.string.added_song_count_to_playlist, - songs.size, - playlistName - ), Toast.LENGTH_SHORT).show() + context.showToast( + context.getString( + R.string.added_song_count_to_playlist, + songs.size, + 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 { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/about/AboutFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/about/AboutFragment.kt index 116dba855..847f7b928 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/about/AboutFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/about/AboutFragment.kt @@ -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) { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt index 72b54775c..34476eabb 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsFragment.kt @@ -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) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt index 4ac3fb663..22d084c4a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumDetailsViewModel.kt @@ -52,7 +52,7 @@ class AlbumDetailsViewModel( emit(artist) } - fun getAlbumInfo(album: Album): LiveData> = liveData { + fun getAlbumInfo(album: Album): LiveData> = liveData(IO) { emit(Result.Loading) emit(repository.albumInfo(album.artistName, album.title)) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt index 55ff96cd2..5bb4af92b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/albums/AlbumsFragment.kt @@ -158,10 +158,10 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment { 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,38 +323,36 @@ 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 -> sortOrder.findItem(R.id.action_sort_order_year).isChecked = true SortOrder.ArtistSongSortOrder.SONG_DURATION -> sortOrder.findItem(R.id.action_sort_order_song_duration).isChecked = true - else-> { + else -> { throw IllegalArgumentException("invalid $savedSongSortOrder") } } } + 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) + } - 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 { - 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 - } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt index ff85467e3..f7347e425 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/artists/ArtistsFragment.kt @@ -168,10 +168,10 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment { @@ -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) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/backup/BackupViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/backup/BackupViewModel.kt index e506a3b4d..f3b67abec 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/backup/BackupViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/backup/BackupViewModel.kt @@ -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>() val backupsLiveData: LiveData> = backupsMutableLiveData - fun loadBackups(context: Context) { + fun loadBackups() { BackupHelper.getBackupRoot().listFiles { _, name -> return@listFiles name.endsWith(BackupHelper.BACKUP_EXTENSION) }?.toList()?.let { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/backup/RestoreActivity.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/backup/RestoreActivity.kt index 73983765b..6ef85b503 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/backup/RestoreActivity.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/backup/RestoreActivity.kt @@ -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() - 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() ) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsMainActivityFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsMainActivityFragment.kt index 2118a1092..17c1a82db 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsMainActivityFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsMainActivityFragment.kt @@ -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) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerControlsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerControlsFragment.kt index 5bb7bdbbe..4d3a63875 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerControlsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerControlsFragment.kt @@ -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() { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt index 3dd8fd76a..082f1ce4b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsPlayerFragment.kt @@ -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,14 +243,12 @@ 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) { - libraryViewModel.removeSongFromPlaylist(songEntity) - } else { - libraryViewModel.insertSongs(listOf(song.toSongEntity(playlist.playListId))) - } + val songEntity = song.toSongEntity(playlist.playListId) + val isFavorite = libraryViewModel.isSongFavorite(song.id) + if (isFavorite) { + libraryViewModel.removeSongFromPlaylist(songEntity) + } 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) { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsRecyclerViewCustomGridSizeFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsRecyclerViewCustomGridSizeFragment.kt index 43dd94606..aa6d39d08 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsRecyclerViewCustomGridSizeFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsRecyclerViewCustomGridSizeFragment.kt @@ -28,7 +28,7 @@ abstract class AbsRecyclerViewCustomGridSizeFragment 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) { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsRecyclerViewFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsRecyclerViewFragment.kt index c36ddc65c..a3004be8b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsRecyclerViewFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/base/AbsRecyclerViewFragment.kt @@ -199,13 +199,11 @@ abstract class AbsRecyclerViewFragment, 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, 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, LM : Recycle "ShowCreatePlaylistDialog" ) } - return super.onOptionsItemSelected(item) + return false } override fun onDestroyView() { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/folder/FoldersFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/folder/FoldersFragment.kt index ceb39d34e..d1a70aeb3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/folder/FoldersFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/folder/FoldersFragment.kt @@ -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, extra: Any?) { - if (songs.isNotEmpty()) { - SongsMenuHelper.handleMenuClick( - requireActivity(), songs, 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_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) { - scanPaths(paths) - } - }) - .execute(ListPathsAsyncTask.LoadingInfo(file, AUDIO_FILE_FILTER)) + lifecycleScope.launch { + listPaths(file, AUDIO_FILE_FILTER) { paths -> scanPaths(paths) } + } 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, 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) { - scanPaths(paths) - } - }) - .execute(ListPathsAsyncTask.LoadingInfo(file, AUDIO_FILE_FILTER)) + lifecycleScope.launch { + listPaths(file, AUDIO_FILE_FILTER) { paths -> scanPaths(paths) } + } 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, 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 - ) - ), + String.format( + 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) { - scanPaths(paths) - } - }) - .execute( - ListPathsAsyncTask.LoadingInfo( - file1, AUDIO_FILE_FILTER + lifecycleScope.launch { + listPaths(mFile, AUDIO_FILE_FILTER) { paths -> + scanPaths( + paths ) - ) + } + } } .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) { val itemId = item.itemId - ListSongsAsyncTask( - activity, - null, - object : OnSongsListedCallback { - override fun onSongsListed(songs: List, 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) { - scanPaths(paths) - } - }) - .execute(ListPathsAsyncTask.LoadingInfo(crumb.file, AUDIO_FILE_FILTER)) + lifecycleScope.launch { + listPaths(crumb.file, AUDIO_FILE_FILTER) { paths -> scanPaths(paths) } + } } 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>( - context - ) { - private val onPathsListedCallbackWeakReference: WeakReference = - WeakReference(callback) - - override fun doInBackground(vararg params: LoadingInfo): Array { - return try { - if (isCancelled || checkCallbackReference() == null) { - return arrayOf() + private suspend fun listPaths( + file: File, + fileFilter: FileFilter, + doOnPathListed: (paths: Array) -> Unit + ) { + val paths = try { + val paths: Array + 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) } - val info = params[0] - val paths: Array - if (info.file.isDirectory) { - val files = FileUtil.listFilesDeep(info.file, info.fileFilter) - if (isCancelled || checkCallbackReference() == null) { - return arrayOf() - } - 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 - } catch (e: Exception) { - e.printStackTrace() - cancel(false) - arrayOf() + } else { + paths = arrayOfNulls(1) + paths[0] = file.path } + paths + } catch (e: Exception) { + e.printStackTrace() + arrayOf() } - - override fun onPostExecute(paths: Array) { - super.onPostExecute(paths) - checkCallbackReference()?.onPathsListed(paths) + withContext(Dispatchers.Main) { + doOnPathListed(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) - } - - 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>(context) { - private val callbackWeakReference = WeakReference(callback) - private val contextWeakReference = WeakReference(context) - override fun doInBackground(vararg params: LoadingInfo): List { - 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) - } catch (e: Exception) { - e.printStackTrace() - cancel(false) - emptyList() - } + suspend fun listSongs( + context: Context, + files: List, + fileFilter: FileFilter, + fileComparator: Comparator, + doOnSongsListed: (songs: List) -> Unit + ) { + val songs = try { + val fileList = FileUtil.listFilesDeep(files, fileFilter) + Collections.sort(fileList, fileComparator) + FileUtil.matchFilesWithMediaStore(context, fileList) + } catch (e: Exception) { + e.printStackTrace() + emptyList() } - - override fun onPostExecute(songs: List) { - 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, extra: Any?) - } - - class LoadingInfo( - val files: List, - val fileFilter: FileFilter, - val fileComparator: Comparator - ) - - } - - abstract class ListingFilesDialogAsyncTask internal constructor( - context: Context? - ) : - DialogAsyncTask(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 { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenreDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenreDetailsFragment.kt index dd108ee6a..64b4aefa2 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenreDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenreDetailsFragment.kt @@ -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) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenreDetailsViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenreDetailsViewModel.kt index 113ec34cf..cc6918b2c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenreDetailsViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenreDetailsViewModel.kt @@ -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) } } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenresFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenresFragment.kt index 571e998cd..8ba01f9e5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenresFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/genres/GenresFragment.kt @@ -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(), 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(), 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) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt index 292784dff..0992eb06a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/home/HomeFragment.kt @@ -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) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt index 5dbd00759..41f465fd1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/library/LibraryFragment.kt @@ -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() { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/other/DetailListFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/other/DetailListFragment.kt index 61600960c..dda396c94 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/other/DetailListFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/other/DetailListFragment.kt @@ -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() } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt index e64fbfab6..d1ce9c693 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/other/LyricsFragment.kt @@ -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 private lateinit var newSyncedLyricsLauncher: ActivityResultLauncher private lateinit var editSyncedLyricsLauncher: ActivityResultLauncher @@ -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 } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/other/MiniPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/other/MiniPlayerFragment.kt index 8787f1cc8..d4eebd6d2 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/other/MiniPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/other/MiniPlayerFragment.kt @@ -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 { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/other/UserInfoFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/other/UserInfoFragment.kt index d517e1dd1..915e34116 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/other/UserInfoFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/other/UserInfoFragment.kt @@ -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 - } } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/PlayerAlbumCoverFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/PlayerAlbumCoverFragment.kt index d14b0cc03..9e7f7673a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/PlayerAlbumCoverFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/PlayerAlbumCoverFragment.kt @@ -80,7 +80,7 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe lifecycleScope.launchWhenStarted { viewPager.setPageTransformer(false, transformer) } -} + } private fun updateLyrics() { binding.lyricsView.setLabel(context?.getString(R.string.no_lyrics_found)) @@ -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,12 +280,12 @@ 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() } - Color ,Classic -> color.backgroundColor + Color, Classic -> color.backgroundColor Blur -> Color.BLACK else -> surfaceColor() } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/adaptive/AdaptiveFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/adaptive/AdaptiveFragment.kt index c12ec2183..a67eadd9c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/adaptive/AdaptiveFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/adaptive/AdaptiveFragment.kt @@ -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) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/blur/BlurPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/blur/BlurPlayerFragment.kt index 675e85e4d..459dc8c43 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/blur/BlurPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/blur/BlurPlayerFragment.kt @@ -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) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/card/CardFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/card/CardFragment.kt index 1a6c7acb7..c75448b27 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/card/CardFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/card/CardFragment.kt @@ -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 - } - } } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/cardblur/CardBlurFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/cardblur/CardBlurFragment.kt index ef45e01ca..bd6f7b64e 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/cardblur/CardBlurFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/cardblur/CardBlurFragment.kt @@ -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) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/circle/CirclePlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/circle/CirclePlayerFragment.kt index 1763c7351..e9489f20f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/circle/CirclePlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/circle/CirclePlayerFragment.kt @@ -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()) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/classic/ClassicPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/classic/ClassicPlayerFragment.kt index 6db36c55c..99d7aad61 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/classic/ClassicPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/classic/ClassicPlayerFragment.kt @@ -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 { - return RetroBottomSheetBehavior.from(binding.playerQueueSheet) as RetroBottomSheetBehavior + private fun getQueuePanel(): BottomSheetBehavior { + 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) { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/color/ColorFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/color/ColorFragment.kt index 4197affde..bd5a29e46 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/color/ColorFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/color/ColorFragment.kt @@ -24,6 +24,7 @@ import code.name.monkey.retromusic.R import code.name.monkey.retromusic.databinding.FragmentColorPlayerBinding import code.name.monkey.retromusic.extensions.colorControlNormal 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.helper.MusicPlayerRemote @@ -110,15 +111,14 @@ class ColorFragment : AbsPlayerFragment(R.layout.fragment_color_player) { _binding = FragmentColorPlayerBinding.bind(view) setUpSubFragments() setUpPlayerToolbar() - val playerAlbumCoverFragment = - childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment + val playerAlbumCoverFragment: PlayerAlbumCoverFragment = + whichFragment(R.id.playerAlbumCoverFragment) playerAlbumCoverFragment.setCallbacks(this) playerToolbar().drawAboveSystemBars() } private fun setUpSubFragments() { - playbackControlsFragment = - childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as ColorPlaybackControlsFragment + playbackControlsFragment = whichFragment(R.id.playbackControlsFragment) } private fun setUpPlayerToolbar() { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/fit/FitFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/fit/FitFragment.kt index 1bddc630a..468ce3c1b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/fit/FitFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/fit/FitFragment.kt @@ -22,6 +22,7 @@ import code.name.monkey.retromusic.R import code.name.monkey.retromusic.databinding.FragmentFitBinding import code.name.monkey.retromusic.extensions.colorControlNormal 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.helper.MusicPlayerRemote @@ -90,10 +91,9 @@ class FitFragment : AbsPlayerFragment(R.layout.fragment_fit) { } private fun setUpSubFragments() { - playbackControlsFragment = - childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as FitPlaybackControlsFragment - val playerAlbumCoverFragment = - childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment + playbackControlsFragment = whichFragment(R.id.playbackControlsFragment) + val playerAlbumCoverFragment: PlayerAlbumCoverFragment = + whichFragment(R.id.playerAlbumCoverFragment) playerAlbumCoverFragment.setCallbacks(this) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/flat/FlatPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/flat/FlatPlayerFragment.kt index 971ff2459..bd84e4eca 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/flat/FlatPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/flat/FlatPlayerFragment.kt @@ -27,6 +27,7 @@ import code.name.monkey.retromusic.R import code.name.monkey.retromusic.databinding.FragmentFlatPlayerBinding import code.name.monkey.retromusic.extensions.colorControlNormal 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.helper.MusicPlayerRemote @@ -52,10 +53,9 @@ class FlatPlayerFragment : AbsPlayerFragment(R.layout.fragment_flat_player) { private fun setUpSubFragments() { - controlsFragment = - childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as FlatPlaybackControlsFragment - val playerAlbumCoverFragment = - childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment + controlsFragment = whichFragment(R.id.playbackControlsFragment) + val playerAlbumCoverFragment: PlayerAlbumCoverFragment = + whichFragment(R.id.playerAlbumCoverFragment) playerAlbumCoverFragment.setCallbacks(this) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/full/FullPlaybackControlsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/full/FullPlaybackControlsFragment.kt index e49e5ad7d..08831b0c6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/full/FullPlaybackControlsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/full/FullPlaybackControlsFragment.kt @@ -18,7 +18,6 @@ import android.content.Intent import android.content.res.ColorStateList import android.graphics.Color import android.graphics.drawable.AnimatedVectorDrawable -import android.graphics.drawable.Drawable import android.os.Bundle import android.view.MenuItem import android.view.View @@ -34,10 +33,7 @@ import code.name.monkey.retromusic.R import code.name.monkey.retromusic.databinding.FragmentFullPlayerControlsBinding import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.db.toSongEntity -import code.name.monkey.retromusic.extensions.applyColor -import code.name.monkey.retromusic.extensions.getSongInfo -import code.name.monkey.retromusic.extensions.hide -import code.name.monkey.retromusic.extensions.show +import code.name.monkey.retromusic.extensions.* import code.name.monkey.retromusic.fragments.LibraryViewModel import code.name.monkey.retromusic.fragments.ReloadType import code.name.monkey.retromusic.fragments.base.AbsPlayerControlsFragment @@ -48,7 +44,6 @@ import code.name.monkey.retromusic.helper.PlayPauseButtonOnClickHandler import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.util.PreferenceUtil -import code.name.monkey.retromusic.util.RetroUtil import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch @@ -237,17 +232,14 @@ class FullPlaybackControlsFragment : } else { if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border } - val drawable: Drawable = RetroUtil.getTintedVectorDrawable( - requireContext(), + val drawable = requireContext().getTintedDrawable( icon, Color.WHITE ) binding.songFavourite.apply { setImageDrawable(drawable) - getDrawable().also { - if (it is AnimatedVectorDrawable) { - it.start() - } + if (drawable is AnimatedVectorDrawable) { + drawable.start() } } } @@ -257,14 +249,12 @@ class FullPlaybackControlsFragment : private fun toggleFavorite(song: Song) { lifecycleScope.launch(Dispatchers.IO) { val playlist: PlaylistEntity = libraryViewModel.favoritePlaylist() - if (playlist != null) { - val songEntity = song.toSongEntity(playlist.playListId) - val isFavorite = libraryViewModel.isFavoriteSong(songEntity).isNotEmpty() - if (isFavorite) { - libraryViewModel.removeSongFromPlaylist(songEntity) - } else { - libraryViewModel.insertSongs(listOf(song.toSongEntity(playlist.playListId))) - } + val songEntity = song.toSongEntity(playlist.playListId) + val isFavorite = libraryViewModel.isFavoriteSong(songEntity).isNotEmpty() + if (isFavorite) { + libraryViewModel.removeSongFromPlaylist(songEntity) + } else { + libraryViewModel.insertSongs(listOf(song.toSongEntity(playlist.playListId))) } libraryViewModel.forceReload(ReloadType.Playlists) requireContext().sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED)) diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt index 8be7e32de..44db2f4d4 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/gradient/GradientPlayerFragment.kt @@ -38,7 +38,6 @@ import androidx.recyclerview.widget.RecyclerView import code.name.monkey.appthemehelper.util.ColorUtil import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.retromusic.R -import code.name.monkey.retromusic.RetroBottomSheetBehavior import code.name.monkey.retromusic.adapter.song.PlayingQueueAdapter import code.name.monkey.retromusic.databinding.FragmentGradientPlayerBinding import code.name.monkey.retromusic.extensions.* @@ -57,6 +56,7 @@ import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.ViewUtil import code.name.monkey.retromusic.util.color.MediaNotificationProcessor +import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior.* import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator import com.h6ah4i.android.widget.advrecyclerview.draggable.RecyclerViewDragDropManager @@ -88,7 +88,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play private val bottomSheetCallbackList = object : BottomSheetCallback() { override fun onSlide(bottomSheet: View, slideOffset: Float) { - mainActivity.getBottomSheetBehavior().setAllowDragging(false) + mainActivity.getBottomSheetBehavior().isDraggable = false binding.playerQueueSheet.updatePadding( top = (slideOffset * binding.statusBarLayout.statusBar.height).toInt() ) @@ -101,14 +101,14 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play when (newState) { STATE_EXPANDED, STATE_DRAGGING -> { - mainActivity.getBottomSheetBehavior().setAllowDragging(false) + mainActivity.getBottomSheetBehavior().isDraggable = false } STATE_COLLAPSED -> { resetToCurrentPosition() - mainActivity.getBottomSheetBehavior().setAllowDragging(true) + mainActivity.getBottomSheetBehavior().isDraggable = true } else -> { - mainActivity.getBottomSheetBehavior().setAllowDragging(true) + mainActivity.getBottomSheetBehavior().isDraggable = true } } } @@ -132,7 +132,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play } private fun setupPanel() { - if (!binding.colorBackground.isLaidOut() || binding.colorBackground.isLayoutRequested) { + if (!binding.colorBackground.isLaidOut || binding.colorBackground.isLayoutRequested) { binding.colorBackground.addOnLayoutChangeListener(this) return } @@ -173,14 +173,14 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play private fun setupSheet() { getQueuePanel().addBottomSheetCallback(bottomSheetCallbackList) binding.playerQueueSheet.setOnTouchListener { _, _ -> - mainActivity.getBottomSheetBehavior().setAllowDragging(false) - getQueuePanel().setAllowDragging(true) + mainActivity.getBottomSheetBehavior().isDraggable = false + getQueuePanel().isDraggable = true return@setOnTouchListener false } } - private fun getQueuePanel(): RetroBottomSheetBehavior { - return RetroBottomSheetBehavior.from(binding.playerQueueSheet) as RetroBottomSheetBehavior + private fun getQueuePanel(): BottomSheetBehavior { + return from(binding.playerQueueSheet) } override fun onResume() { @@ -205,7 +205,6 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play } override fun onBackPressed(): Boolean { - println("OK") var wasExpanded = false if (getQueuePanel().state == STATE_EXPANDED) { wasExpanded = getQueuePanel().state == STATE_EXPANDED @@ -309,7 +308,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play } childFragmentManager.executePendingTransactions() volumeFragment = - childFragmentManager.findFragmentById(R.id.volumeFragmentContainer) as VolumeFragment? + whichFragment(R.id.volumeFragmentContainer) as VolumeFragment? } } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/material/MaterialFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/material/MaterialFragment.kt index b57654fad..1af54215d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/material/MaterialFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/material/MaterialFragment.kt @@ -26,6 +26,7 @@ import code.name.monkey.retromusic.databinding.FragmentMaterialBinding import code.name.monkey.retromusic.extensions.colorControlNormal import code.name.monkey.retromusic.extensions.drawAboveSystemBars import code.name.monkey.retromusic.extensions.surfaceColor +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 @@ -134,10 +135,9 @@ class MaterialFragment : AbsPlayerFragment(R.layout.fragment_material) { } private fun setUpSubFragments() { - playbackControlsFragment = - childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as MaterialControlsFragment - val playerAlbumCoverFragment = - childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment + playbackControlsFragment = whichFragment(R.id.playbackControlsFragment) + val playerAlbumCoverFragment: PlayerAlbumCoverFragment = + whichFragment(R.id.playerAlbumCoverFragment) playerAlbumCoverFragment.setCallbacks(this) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerFragment.kt index fd3327ca9..0144ae835 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/normal/PlayerFragment.kt @@ -27,10 +27,7 @@ import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.retromusic.R import code.name.monkey.retromusic.SNOWFALL import code.name.monkey.retromusic.databinding.FragmentPlayerBinding -import code.name.monkey.retromusic.extensions.colorControlNormal -import code.name.monkey.retromusic.extensions.drawAboveSystemBars -import code.name.monkey.retromusic.extensions.isColorLight -import code.name.monkey.retromusic.extensions.surfaceColor +import code.name.monkey.retromusic.extensions.* import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment import code.name.monkey.retromusic.fragments.player.PlayerAlbumCoverFragment import code.name.monkey.retromusic.helper.MusicPlayerRemote @@ -141,10 +138,9 @@ class PlayerFragment : AbsPlayerFragment(R.layout.fragment_player), } private fun setUpSubFragments() { - controlsFragment = - childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as PlayerPlaybackControlsFragment - val playerAlbumCoverFragment = - childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment + controlsFragment = whichFragment(R.id.playbackControlsFragment) + val playerAlbumCoverFragment: PlayerAlbumCoverFragment = + whichFragment(R.id.playerAlbumCoverFragment) playerAlbumCoverFragment.setCallbacks(this) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/peek/PeekPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/peek/PeekPlayerFragment.kt index dc5116399..2d17d5a99 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/peek/PeekPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/peek/PeekPlayerFragment.kt @@ -58,10 +58,10 @@ class PeekPlayerFragment : AbsPlayerFragment(R.layout.fragment_peek_player) { private fun setUpSubFragments() { controlsFragment = - childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as PeekPlayerControlFragment + whichFragment(R.id.playbackControlsFragment) as PeekPlayerControlFragment val coverFragment = - childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment + whichFragment(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment coverFragment.setCallbacks(this) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/plain/PlainPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/plain/PlainPlayerFragment.kt index 894fc03c0..fbbb7cd26 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/plain/PlainPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/plain/PlainPlayerFragment.kt @@ -22,6 +22,7 @@ import code.name.monkey.retromusic.R import code.name.monkey.retromusic.databinding.FragmentPlainPlayerBinding import code.name.monkey.retromusic.extensions.colorControlNormal 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.base.goToAlbum import code.name.monkey.retromusic.fragments.base.goToArtist @@ -89,10 +90,9 @@ class PlainPlayerFragment : AbsPlayerFragment(R.layout.fragment_plain_player) { } private fun setUpSubFragments() { - plainPlaybackControlsFragment = - childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as PlainPlaybackControlsFragment - val playerAlbumCoverFragment = - childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment + plainPlaybackControlsFragment = whichFragment(R.id.playbackControlsFragment) + val playerAlbumCoverFragment: PlayerAlbumCoverFragment = + whichFragment(R.id.playerAlbumCoverFragment) playerAlbumCoverFragment.setCallbacks(this) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/simple/SimplePlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/simple/SimplePlayerFragment.kt index b2bdd469a..722ab28ba 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/simple/SimplePlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/simple/SimplePlayerFragment.kt @@ -22,6 +22,7 @@ import code.name.monkey.retromusic.R import code.name.monkey.retromusic.databinding.FragmentSimplePlayerBinding import code.name.monkey.retromusic.extensions.colorControlNormal 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.helper.MusicPlayerRemote @@ -56,11 +57,10 @@ class SimplePlayerFragment : AbsPlayerFragment(R.layout.fragment_simple_player) } private fun setUpSubFragments() { - val playerAlbumCoverFragment = - childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment + val playerAlbumCoverFragment: PlayerAlbumCoverFragment = + whichFragment(R.id.playerAlbumCoverFragment) playerAlbumCoverFragment.setCallbacks(this) - controlsFragment = - childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as SimplePlaybackControlsFragment + controlsFragment = whichFragment(R.id.playbackControlsFragment) } override fun onShow() { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/player/tiny/TinyPlayerFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/player/tiny/TinyPlayerFragment.kt index 9ac50de1b..021f5ef82 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/player/tiny/TinyPlayerFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/player/tiny/TinyPlayerFragment.kt @@ -29,10 +29,7 @@ import code.name.monkey.appthemehelper.util.ToolbarContentTintHelper import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.retromusic.R import code.name.monkey.retromusic.databinding.FragmentTinyPlayerBinding -import code.name.monkey.retromusic.extensions.drawAboveSystemBars -import code.name.monkey.retromusic.extensions.getSongInfo -import code.name.monkey.retromusic.extensions.hide -import code.name.monkey.retromusic.extensions.show +import code.name.monkey.retromusic.extensions.* import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment import code.name.monkey.retromusic.fragments.base.goToAlbum import code.name.monkey.retromusic.fragments.base.goToArtist @@ -153,10 +150,9 @@ class TinyPlayerFragment : AbsPlayerFragment(R.layout.fragment_tiny_player), } private fun setUpSubFragments() { - controlsFragment = - childFragmentManager.findFragmentById(R.id.playbackControlsFragment) as TinyPlaybackControlsFragment - val playerAlbumCoverFragment = - childFragmentManager.findFragmentById(R.id.playerAlbumCoverFragment) as PlayerAlbumCoverFragment + controlsFragment = whichFragment(R.id.playbackControlsFragment) + val playerAlbumCoverFragment: PlayerAlbumCoverFragment = + whichFragment(R.id.playerAlbumCoverFragment) playerAlbumCoverFragment.setCallbacks(this) } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt index d48a5025f..aa7f71bc1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsFragment.kt @@ -1,11 +1,11 @@ package code.name.monkey.retromusic.fragments.playlists +import android.graphics.Color import android.os.Bundle import android.view.Menu import android.view.MenuInflater import android.view.MenuItem import android.view.View -import androidx.activity.addCallback import androidx.core.view.doOnPreDraw import androidx.core.view.isVisible import androidx.navigation.fragment.findNavController @@ -31,6 +31,8 @@ import com.afollestad.materialcab.attached.destroy import com.afollestad.materialcab.attached.isActive import com.afollestad.materialcab.createCab import com.google.android.material.shape.MaterialShapeDrawable +import com.google.android.material.transition.MaterialArcMotion +import com.google.android.material.transition.MaterialContainerTransform import com.google.android.material.transition.MaterialSharedAxis import com.h6ah4i.android.widget.advrecyclerview.animator.DraggableItemAnimator import com.h6ah4i.android.widget.advrecyclerview.animator.GeneralItemAnimator @@ -52,14 +54,23 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli private lateinit var playlist: PlaylistWithSongs private lateinit var playlistSongAdapter: OrderablePlaylistSongAdapter + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + sharedElementEnterTransition = MaterialContainerTransform(requireContext(), true).apply { + drawingViewId = R.id.fragment_container + scrimColor = Color.TRANSPARENT + setAllContainerColors(surfaceColor()) + setPathMotion(MaterialArcMotion()) + } + } + override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) _binding = FragmentPlaylistDetailBinding.bind(view) enterTransition = MaterialSharedAxis(MaterialSharedAxis.Z, true).addTarget(view) returnTransition = MaterialSharedAxis(MaterialSharedAxis.Z, false) - setHasOptionsMenu(true) mainActivity.setSupportActionBar(binding.toolbar) - binding.container.setTransitionName("playlist") + binding.container.transitionName = "playlist" playlist = arguments.extraPlaylist binding.toolbar.title = playlist.playlistEntity.playlistName setUpRecyclerView() @@ -72,13 +83,7 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli } } postponeEnterTransition() - requireView().doOnPreDraw { startPostponedEnterTransition() } - requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) { - if (!handleBackPress()) { - remove() - requireActivity().onBackPressed() - } - } + view.doOnPreDraw { startPostponedEnterTransition() } binding.appBarLayout.statusBarForeground = MaterialShapeDrawable.createWithElevationOverlay(requireContext()) } @@ -116,12 +121,11 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli }) } - override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) { - super.onCreateOptionsMenu(menu, inflater) + override fun onCreateMenu(menu: Menu, inflater: MenuInflater) { inflater.inflate(R.menu.menu_playlist_detail, menu) } - override fun onOptionsItemSelected(item: MenuItem): Boolean { + override fun onMenuItemSelected(item: MenuItem): Boolean { return PlaylistMenuHelper.handleMenuClick(requireActivity(), playlist, item) } @@ -169,16 +173,6 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli _binding = null } - private fun handleBackPress(): Boolean { - cab?.let { - if (it.isActive()) { - it.destroy() - return true - } - } - return false - } - private var cab: AttachedCab? = null override fun openCab(menuRes: Int, callback: ICabCallback): AttachedCab { @@ -201,5 +195,4 @@ class PlaylistDetailsFragment : AbsMainActivityFragment(R.layout.fragment_playli } return cab as AttachedCab } - } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsViewModel.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsViewModel.kt index fad139742..0d15a279d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsViewModel.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistDetailsViewModel.kt @@ -15,14 +15,10 @@ package code.name.monkey.retromusic.fragments.playlists import androidx.lifecycle.LiveData -import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import code.name.monkey.retromusic.db.PlaylistWithSongs import code.name.monkey.retromusic.db.SongEntity -import code.name.monkey.retromusic.interfaces.IMusicServiceEventListener -import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.repository.RealRepository -import code.name.monkey.retromusic.repository.RealRoomRepository class PlaylistDetailsViewModel( private val realRepository: RealRepository, diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt index 1a928ab27..d6b9bb126 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/playlists/PlaylistsFragment.kt @@ -16,7 +16,6 @@ package code.name.monkey.retromusic.fragments.playlists import android.os.Bundle import android.view.* -import androidx.activity.addCallback import androidx.core.os.bundleOf import androidx.core.view.MenuCompat import androidx.navigation.fragment.findNavController @@ -46,10 +45,6 @@ class PlaylistsFragment : else adapter?.swapDataSet(listOf()) } - requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) { - remove() - requireActivity().onBackPressed() - } } override val titleRes: Int @@ -76,10 +71,10 @@ class PlaylistsFragment : ) } - 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) @@ -93,14 +88,14 @@ class PlaylistsFragment : CastButtonFactory.setUpMediaRouteButton(requireContext(), menu, R.id.action_cast) } - override fun onOptionsItemSelected(item: MenuItem): Boolean { + override fun onMenuItemSelected(item: MenuItem): Boolean { if (handleGridSizeMenuItem(item)) { return true } if (handleSortOrderMenuItem(item)) { return true } - return super.onOptionsItemSelected(item) + return super.onMenuItemSelected(item) } private fun setupGridSizeMenu(gridSizeMenu: SubMenu) { @@ -114,7 +109,7 @@ class PlaylistsFragment : 7 -> gridSizeMenu.findItem(R.id.action_grid_size_7).isChecked = true 8 -> gridSizeMenu.findItem(R.id.action_grid_size_8).isChecked = true } - val gridSize = if (RetroUtil.isLandscape()) 4 else 2 + val gridSize = if (RetroUtil.isLandscape) 4 else 2 if (gridSize < 8) { gridSizeMenu.findItem(R.id.action_grid_size_8).isVisible = false } diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchFragment.kt index 5b7c25d76..eced42489 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/search/SearchFragment.kt @@ -20,9 +20,9 @@ import android.content.Intent import android.content.res.ColorStateList import android.os.Bundle import android.speech.RecognizerIntent -import android.view.View -import android.view.ViewGroup +import android.view.* import android.view.inputmethod.InputMethodManager +import androidx.activity.result.contract.ActivityResultContracts import androidx.core.content.getSystemService import androidx.core.view.* import androidx.core.widget.doAfterTextChanged @@ -54,7 +54,6 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), ChipGroup.OnCheckedStateChangeListener { companion object { const val QUERY = "query" - const val REQ_CODE_SPEECH_INPUT = 9001 } private var _binding: FragmentSearchBinding? = null @@ -83,6 +82,11 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), doAfterTextChanged { if (!it.isNullOrEmpty()) search(it.toString()) + else { + TransitionManager.beginDelayedTransition(binding.appBarLayout) + binding.voiceSearch.isVisible = true + binding.clearText.isGone = true + } } focusAndShowKeyboard() } @@ -204,25 +208,21 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault()) intent.putExtra(RecognizerIntent.EXTRA_PROMPT, getString(R.string.speech_prompt)) try { - startActivityForResult( - intent, - REQ_CODE_SPEECH_INPUT - ) + speechInputLauncher.launch(intent) } catch (e: ActivityNotFoundException) { e.printStackTrace() showToast(getString(R.string.speech_not_supported)) } } - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - if (resultCode == RESULT_OK) { - val spokenText: String? = - data?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS) - .let { text -> text?.get(0) } - binding.searchView.setText(spokenText) + private val speechInputLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.resultCode == RESULT_OK) { + val spokenText: String? = + result?.data?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)?.get(0) + binding.searchView.setText(spokenText) + } } - } override fun onDestroyView() { hideKeyboard(view) @@ -246,6 +246,10 @@ class SearchFragment : AbsMainActivityFragment(R.layout.fragment_search), override fun onCheckedChanged(group: ChipGroup, checkedIds: MutableList) { search(binding.searchView.text.toString()) } + + override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {} + + override fun onMenuItemSelected(menuItem: MenuItem) = false } enum class Filter { diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/AbsSettingsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/AbsSettingsFragment.kt index 8a1502ab0..8e09950f3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/AbsSettingsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/AbsSettingsFragment.kt @@ -19,12 +19,13 @@ import android.graphics.drawable.ColorDrawable import android.os.Build import android.os.Bundle import android.view.View -import android.widget.Toast import androidx.preference.ListPreference import androidx.preference.Preference import androidx.preference.PreferenceManager import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEPreferenceFragmentCompat +import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.retromusic.activities.OnThemeChangedListener +import code.name.monkey.retromusic.extensions.showToast import code.name.monkey.retromusic.preferences.* import code.name.monkey.retromusic.util.NavigationUtil import dev.chrisbanes.insetter.applyInsetter @@ -36,8 +37,7 @@ import dev.chrisbanes.insetter.applyInsetter abstract class AbsSettingsFragment : ATEPreferenceFragmentCompat() { internal fun showProToastAndNavigate(message: String) { - Toast.makeText(requireContext(), "$message is Pro version feature.", Toast.LENGTH_SHORT) - .show() + showToast("$message is Pro version feature.") NavigationUtil.goToProVersion(requireActivity()) } @@ -105,7 +105,7 @@ abstract class AbsSettingsFragment : ATEPreferenceFragmentCompat() { } fun restartActivity() { - if (activity is OnThemeChangedListener) { + if (activity is OnThemeChangedListener && !VersionUtils.hasS()) { (activity as OnThemeChangedListener).onThemeValuesChanged() } else { activity?.recreate() diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/ThemeSettingsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/ThemeSettingsFragment.kt index c0c19fa78..6d339be7c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/settings/ThemeSettingsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/settings/ThemeSettingsFragment.kt @@ -44,12 +44,10 @@ class ThemeSettingsFragment : AbsSettingsFragment() { generalTheme?.let { setSummary(it) it.setOnPreferenceChangeListener { _, newValue -> - val theme = newValue as String setSummary(it, newValue) ThemeStore.markChanged(requireContext()) if (VersionUtils.hasNougatMR()) { - requireActivity().setTheme(PreferenceUtil.themeResFromPrefValue(theme)) DynamicShortcutManager(requireContext()).updateDynamicShortcuts() } restartActivity() diff --git a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt index acbd45923..b0ada25df 100644 --- a/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt +++ b/app/src/main/java/code/name/monkey/retromusic/fragments/songs/SongsFragment.kt @@ -125,10 +125,10 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment { return baseRequestOptions.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY) - .error(DEFAULT_SONG_IMAGE) - .placeholder(DEFAULT_SONG_IMAGE) + .error(getDrawable(DEFAULT_SONG_IMAGE)) + .placeholder(getDrawable(DEFAULT_SONG_IMAGE)) .signature(createSignature(song)) } @@ -142,8 +144,8 @@ object RetroGlideExtension { song: Song ): BaseRequestOptions<*> { return baseRequestOptions.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY) - .error(DEFAULT_ALBUM_IMAGE) - .placeholder(DEFAULT_ALBUM_IMAGE) + .error(ContextCompat.getDrawable(getContext(), DEFAULT_ALBUM_IMAGE)) + .placeholder(ContextCompat.getDrawable(getContext(), DEFAULT_ALBUM_IMAGE)) .signature(createSignature(song)) } @@ -177,7 +179,7 @@ object RetroGlideExtension { baseRequestOptions: BaseRequestOptions<*> ): BaseRequestOptions<*> { return baseRequestOptions.diskCacheStrategy(DEFAULT_DISK_CACHE_STRATEGY) - .error(DEFAULT_ALBUM_IMAGE) + .error(getDrawable(DEFAULT_ALBUM_IMAGE)) } private fun createSignature(song: Song): Key { @@ -205,15 +207,19 @@ object RetroGlideExtension { private fun getErrorUserProfile(context: Context): Drawable { return TintHelper.createTintedDrawable( - getContext(), + context, R.drawable.ic_account, - accentColor(context) + context.accentColor() ) } fun getDefaultTransition(): GenericTransitionOptions { return GenericTransitionOptions().transition(DEFAULT_ANIMATION) } + + fun getDrawable(@DrawableRes id: Int): Drawable? { + return ContextCompat.getDrawable(getContext(), id) + } } // https://github.com/bumptech/glide/issues/527#issuecomment-148840717 diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageFetcher.kt b/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageFetcher.kt index 356a829f6..1260892a6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageFetcher.kt +++ b/app/src/main/java/code/name/monkey/retromusic/glide/artistimage/ArtistImageFetcher.kt @@ -42,7 +42,7 @@ class ArtistImageFetcher( override fun loadData(priority: Priority, callback: DataFetcher.DataCallback) { try { if (!MusicUtil.isArtistNameUnknown(model.artist.name) && - PreferenceUtil.isAllowedToDownloadMetadata() + PreferenceUtil.isAllowedToDownloadMetadata(context) ) { val artists = model.artist.name.split(",", "&") response = deezerService.getArtistImage(artists[0]) diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCover.kt b/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCover.kt new file mode 100644 index 000000000..0045669c1 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCover.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2019 Hemanth Savarala. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + */ +package code.name.monkey.retromusic.glide.audiocover + +/** @author Karim Abou Zeid (kabouzeid) + */ +class AudioFileCover(val filePath: String) { + override fun hashCode(): Int { + return filePath.hashCode() + } + + override fun equals(other: Any?): Boolean { + return if (other is AudioFileCover) { + other.filePath == filePath + } else false + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverFetcher.java b/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverFetcher.java deleted file mode 100644 index a95bb46a7..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverFetcher.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.glide.audiocover; - -import android.media.MediaMetadataRetriever; - -import com.bumptech.glide.Priority; -import com.bumptech.glide.load.DataSource; -import com.bumptech.glide.load.data.DataFetcher; - -import org.jetbrains.annotations.NotNull; - -import java.io.ByteArrayInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; - -public class AudioFileCoverFetcher implements DataFetcher { - private final AudioFileCover model; - - private InputStream stream; - - public AudioFileCoverFetcher(AudioFileCover model) { - this.model = model; - } - - @Override - public void loadData(@NotNull Priority priority, @NotNull DataCallback callback) { - final MediaMetadataRetriever retriever = new MediaMetadataRetriever(); - try { - retriever.setDataSource(model.filePath); - byte[] picture = retriever.getEmbeddedPicture(); - if (picture != null) { - stream = new ByteArrayInputStream(picture); - } else { - stream = AudioFileCoverUtils.fallback(model.filePath); - } - callback.onDataReady(stream); - } catch (FileNotFoundException e) { - callback.onLoadFailed(e); - } finally { - retriever.release(); - } - } - - @Override - public void cleanup() { - // already cleaned up in loadData and ByteArrayInputStream will be GC'd - if (stream != null) { - try { - stream.close(); - } catch (IOException ignore) { - // can't do much about it - } - } - } - - @Override - public void cancel() { - // cannot cancel - } - - @NotNull - @Override - public Class getDataClass() { - return InputStream.class; - } - - @NotNull - @Override - public DataSource getDataSource() { - return DataSource.LOCAL; - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverFetcher.kt b/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverFetcher.kt new file mode 100644 index 000000000..897d46730 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverFetcher.kt @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2019 Hemanth Savarala. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + */ +package code.name.monkey.retromusic.glide.audiocover + +import android.media.MediaMetadataRetriever +import com.bumptech.glide.Priority +import com.bumptech.glide.load.DataSource +import com.bumptech.glide.load.data.DataFetcher +import java.io.ByteArrayInputStream +import java.io.FileNotFoundException +import java.io.IOException +import java.io.InputStream + +class AudioFileCoverFetcher(private val model: AudioFileCover) : DataFetcher { + private var stream: InputStream? = null + override fun loadData(priority: Priority, callback: DataFetcher.DataCallback) { + val retriever = MediaMetadataRetriever() + try { + retriever.setDataSource(model.filePath) + val picture = retriever.embeddedPicture + stream = if (picture != null) { + ByteArrayInputStream(picture) + } else { + AudioFileCoverUtils.fallback(model.filePath) + } + callback.onDataReady(stream) + } catch (e: FileNotFoundException) { + callback.onLoadFailed(e) + } finally { + retriever.release() + } + } + + override fun cleanup() { + // already cleaned up in loadData and ByteArrayInputStream will be GC'd + if (stream != null) { + try { + stream?.close() + } catch (ignore: IOException) { + // can't do much about it + } + } + } + + override fun cancel() { + // cannot cancel + } + + override fun getDataClass(): Class { + return InputStream::class.java + } + + override fun getDataSource(): DataSource { + return DataSource.LOCAL + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverLoader.java b/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverLoader.java deleted file mode 100644 index 69c0f907e..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverLoader.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.glide.audiocover; - -import androidx.annotation.NonNull; - -import com.bumptech.glide.load.Options; -import com.bumptech.glide.load.model.ModelLoader; -import com.bumptech.glide.load.model.ModelLoaderFactory; -import com.bumptech.glide.load.model.MultiModelLoaderFactory; -import com.bumptech.glide.signature.ObjectKey; - -import org.jetbrains.annotations.NotNull; - -import java.io.InputStream; - -public class AudioFileCoverLoader implements ModelLoader { - - @Override - public LoadData buildLoadData(@NonNull @NotNull AudioFileCover audioFileCover, int width, int height, @NonNull @NotNull Options options) { - return new LoadData<>(new ObjectKey(audioFileCover.filePath), new AudioFileCoverFetcher(audioFileCover)); - } - - @Override - public boolean handles(@NonNull @NotNull AudioFileCover audioFileCover) { - return audioFileCover.filePath != null; - } - - public static class Factory implements ModelLoaderFactory { - - @NotNull - @Override - public ModelLoader build(@NonNull @NotNull MultiModelLoaderFactory multiFactory) { - return new AudioFileCoverLoader(); - } - - @Override - public void teardown() { - } - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverLoader.kt b/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverLoader.kt new file mode 100644 index 000000000..0008f09c1 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCoverLoader.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019 Hemanth Savarala. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + */ +package code.name.monkey.retromusic.glide.audiocover + +import com.bumptech.glide.load.Options +import com.bumptech.glide.load.model.ModelLoader +import com.bumptech.glide.load.model.ModelLoader.LoadData +import com.bumptech.glide.load.model.ModelLoaderFactory +import com.bumptech.glide.load.model.MultiModelLoaderFactory +import com.bumptech.glide.signature.ObjectKey +import java.io.InputStream + +class AudioFileCoverLoader : ModelLoader { + override fun buildLoadData( + audioFileCover: AudioFileCover, + width: Int, + height: Int, + options: Options + ): LoadData { + return LoadData(ObjectKey(audioFileCover.filePath), AudioFileCoverFetcher(audioFileCover)) + } + + override fun handles(audioFileCover: AudioFileCover): Boolean { + return true + } + + class Factory : ModelLoaderFactory { + override fun build(multiFactory: MultiModelLoaderFactory): ModelLoader { + return AudioFileCoverLoader() + } + + override fun teardown() {} + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/BackupHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/BackupHelper.kt index fef31b6d4..ac970fe4c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/BackupHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/BackupHelper.kt @@ -2,25 +2,26 @@ package code.name.monkey.retromusic.helper import android.content.Context import android.os.Environment -import android.widget.Toast -import code.name.monkey.retromusic.App import code.name.monkey.retromusic.BuildConfig import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.db.toSongEntity +import code.name.monkey.retromusic.extensions.showToast +import code.name.monkey.retromusic.extensions.zipOutputStream import code.name.monkey.retromusic.helper.BackupContent.* import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.repository.Repository import code.name.monkey.retromusic.repository.SongRepository +import code.name.monkey.retromusic.util.getExternalStoragePublicDirectory import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import org.koin.core.component.KoinComponent import org.koin.core.component.inject -import java.io.* +import java.io.File +import java.io.InputStream import java.text.SimpleDateFormat import java.util.* import java.util.zip.ZipEntry import java.util.zip.ZipInputStream -import java.util.zip.ZipOutputStream object BackupHelper : KoinComponent { private val repository by inject() @@ -37,38 +38,30 @@ object BackupHelper : KoinComponent { zipItems.addAll(getSettingsZipItems(context)) getUserImageZipItems(context)?.let { zipItems.addAll(it) } zipItems.addAll(getCustomArtistZipItems(context)) - zipAll(zipItems, backupFile) + zipAll(context, zipItems, backupFile) // Clean Cache Playlist Directory File(context.filesDir, PLAYLISTS_PATH).deleteRecursively() } - private suspend fun zipAll(zipItems: List, backupFile: File) = + private suspend fun zipAll(context: Context, zipItems: List, backupFile: File) = withContext(Dispatchers.IO) { runCatching { - ZipOutputStream(BufferedOutputStream(FileOutputStream(backupFile))).use { out -> + backupFile.outputStream().buffered().zipOutputStream().use { out -> for (zipItem in zipItems) { - FileInputStream(zipItem.filePath).use { fi -> - BufferedInputStream(fi).use { origin -> - val entry = ZipEntry(zipItem.zipPath) - out.putNextEntry(entry) - origin.copyTo(out) - } + File(zipItem.filePath).inputStream().buffered().use { origin -> + val entry = ZipEntry(zipItem.zipPath) + out.putNextEntry(entry) + origin.copyTo(out) } } } }.onFailure { withContext(Dispatchers.Main) { - Toast.makeText(App.getContext(), "Couldn't create backup", Toast.LENGTH_SHORT) - .show() + context.showToast("Couldn't create backup") } }.onSuccess { withContext(Dispatchers.Main) { - Toast.makeText( - App.getContext(), - "Backup created successfully", - Toast.LENGTH_SHORT - ) - .show() + context.showToast("Backup created successfully") } } } @@ -167,7 +160,7 @@ object BackupHelper : KoinComponent { } } withContext(Dispatchers.Main) { - Toast.makeText(context, "Restore Completed Successfully", Toast.LENGTH_SHORT).show() + context.showToast("Restore Completed Successfully") } } } @@ -176,7 +169,7 @@ object BackupHelper : KoinComponent { val file = File( context.filesDir.path, zipEntry.getFileName() ) - BufferedOutputStream(FileOutputStream(file)).use { bos -> + file.outputStream().buffered().use { bos -> zipIn.copyTo(bos) } } @@ -188,7 +181,7 @@ object BackupHelper : KoinComponent { if (file.exists()) { file.delete() } - BufferedOutputStream(FileOutputStream(file)).use { bos -> + file.outputStream().buffered().use { bos -> zipIn.copyTo(bos) } } @@ -233,16 +226,14 @@ object BackupHelper : KoinComponent { if (!parentFolder.exists()) { parentFolder.mkdirs() } - BufferedOutputStream( - FileOutputStream( - File( - parentFolder, - zipEntry.getFileName() - ) - ) - ).use { bos -> - zipIn.copyTo(bos) - } + val file = File( + parentFolder, + zipEntry.getFileName() + ) + file.outputStream().buffered() + .use { bos -> + zipIn.copyTo(bos) + } } private fun restoreCustomArtistPrefs( @@ -252,14 +243,14 @@ object BackupHelper : KoinComponent { ) { val file = File(context.filesDir.parentFile, "shared_prefs".child(zipEntry.getFileName())) - BufferedOutputStream(FileOutputStream(file)).use { bos -> + file.outputStream().buffered().use { bos -> zipIn.copyTo(bos) } } fun getBackupRoot(): File { return File( - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), + getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS), "RetroMusic/Backups" ) } diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt b/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt index a8235ad80..fb03f95a6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/MusicPlayerRemote.kt @@ -19,16 +19,17 @@ import android.app.Activity import android.content.* import android.database.Cursor import android.net.Uri -import android.os.Environment import android.os.IBinder import android.provider.DocumentsContract import android.widget.Toast import androidx.core.content.ContextCompat import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.extensions.showToast import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.repository.SongRepository import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.util.PreferenceUtil +import code.name.monkey.retromusic.util.getExternalStorageDirectory import org.koin.core.component.KoinComponent import org.koin.core.component.inject import java.io.File @@ -48,7 +49,6 @@ object MusicPlayerRemote : KoinComponent { if (value) { musicService?.quit() } - println(value.toString() + "" + isCasting.toString()) } @JvmStatic @@ -131,7 +131,9 @@ object MusicPlayerRemote : KoinComponent { try { contextWrapper.startService(intent) } catch (ignored: IllegalStateException) { - ContextCompat.startForegroundService(context, intent) + runCatching { + ContextCompat.startForegroundService(context, intent) + } } val binder = ServiceBinder(callback) @@ -171,7 +173,7 @@ object MusicPlayerRemote : KoinComponent { return cursor.getString(columnIndex) } } catch (e: Exception) { - println(e.message) + e.printStackTrace() } finally { cursor?.close() } @@ -259,7 +261,7 @@ object MusicPlayerRemote : KoinComponent { private fun tryToHandleOpenPlayingQueue( queue: List, startPosition: Int, - startPlaying: Boolean + startPlaying: Boolean, ): Boolean { if (playingQueue === queue) { if (startPlaying) { @@ -317,11 +319,7 @@ object MusicPlayerRemote : KoinComponent { queue.add(song) openQueue(queue, 0, false) } - Toast.makeText( - musicService, - musicService!!.resources.getString(R.string.added_title_to_playing_queue), - Toast.LENGTH_SHORT - ).show() + musicService?.showToast(R.string.added_title_to_playing_queue) return true } return false @@ -340,7 +338,7 @@ object MusicPlayerRemote : KoinComponent { R.string.added_x_titles_to_playing_queue, songs.size ) - Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show() + musicService?.showToast(toast, Toast.LENGTH_SHORT) return true } return false @@ -355,11 +353,7 @@ object MusicPlayerRemote : KoinComponent { queue.add(song) openQueue(queue, 0, false) } - Toast.makeText( - musicService, - musicService!!.resources.getString(R.string.added_title_to_playing_queue), - Toast.LENGTH_SHORT - ).show() + musicService?.showToast(R.string.added_title_to_playing_queue) return true } return false @@ -377,7 +371,7 @@ object MusicPlayerRemote : KoinComponent { R.string.added_x_titles_to_playing_queue, songs.size ) - Toast.makeText(musicService, toast, Toast.LENGTH_SHORT).show() + musicService?.showToast(toast) return true } return false @@ -426,7 +420,7 @@ object MusicPlayerRemote : KoinComponent { } @JvmStatic - fun playFromUri(uri: Uri) { + fun playFromUri(context: Context, uri: Uri) { if (musicService != null) { var songs: List? = null @@ -438,10 +432,8 @@ object MusicPlayerRemote : KoinComponent { } else if (uri.authority == "media") { songId = uri.lastPathSegment } - songs = if (songId != null) { - songRepository.songs(songId) - } else { - songRepository.songsIgnoreBlacklist(uri) + if (songId != null) { + songs = songRepository.songs(songId) } } } @@ -449,12 +441,12 @@ object MusicPlayerRemote : KoinComponent { var songFile: File? = null if (uri.authority != null && uri.authority == "com.android.externalstorage.documents") { songFile = File( - Environment.getExternalStorageDirectory(), + getExternalStorageDirectory(), uri.path?.split(":".toRegex(), 2)?.get(1) ) } if (songFile == null) { - val path = getFilePathFromUri(musicService!!, uri) + val path = getFilePathFromUri(context, uri) if (path != null) songFile = File(path) } @@ -469,6 +461,7 @@ object MusicPlayerRemote : KoinComponent { openQueue(songs, 0, true) } else { // TODO the file is not listed in the media store + context.showToast(R.string.unplayable_file) println("The file is not listed in the media store") } } diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/SearchQueryHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/SearchQueryHelper.kt index 9bd72fa58..06c76294d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/SearchQueryHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/SearchQueryHelper.kt @@ -139,8 +139,6 @@ object SearchQueryHelper : KoinComponent { arrayOf(query.lowercase()) ) ) - return if (songs.isNotEmpty()) { - songs - } else ArrayList() + return songs.ifEmpty { ArrayList() } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt index 26dfe7a8c..4c63a6f39 100644 --- a/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt +++ b/app/src/main/java/code/name/monkey/retromusic/helper/menu/SongMenuHelper.kt @@ -21,7 +21,6 @@ import androidx.appcompat.widget.PopupMenu import androidx.core.os.bundleOf import androidx.fragment.app.FragmentActivity import androidx.navigation.findNavController -import code.name.monkey.retromusic.App import code.name.monkey.retromusic.EXTRA_ALBUM_ID import code.name.monkey.retromusic.EXTRA_ARTIST_ID import code.name.monkey.retromusic.R @@ -124,7 +123,7 @@ object SongMenuHelper : KoinComponent { return true } R.id.action_add_to_blacklist -> { - BlacklistStore.getInstance(App.getContext()).addPath(File(song.data)) + BlacklistStore.getInstance(activity).addPath(File(song.data)) libraryViewModel.forceReload(ReloadType.Songs) return true } diff --git a/app/src/main/java/code/name/monkey/retromusic/misc/DialogAsyncTask.java b/app/src/main/java/code/name/monkey/retromusic/misc/DialogAsyncTask.java deleted file mode 100644 index 38e41539b..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/misc/DialogAsyncTask.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.misc; - -import android.app.Dialog; -import android.content.Context; -import android.os.Handler; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.lang.ref.WeakReference; - -public abstract class DialogAsyncTask - extends WeakContextAsyncTask { - private final int delay; - - private WeakReference dialogWeakReference; - - private boolean supposedToBeDismissed; - - public DialogAsyncTask(Context context) { - this(context, 0); - } - - public DialogAsyncTask(Context context, int showDelay) { - super(context); - this.delay = showDelay; - dialogWeakReference = new WeakReference<>(null); - } - - @Override - protected void onPreExecute() { - super.onPreExecute(); - if (delay > 0) { - new Handler().postDelayed(this::initAndShowDialog, delay); - } else { - initAndShowDialog(); - } - } - - private void initAndShowDialog() { - Context context = getContext(); - if (!supposedToBeDismissed && context != null) { - Dialog dialog = createDialog(context); - dialogWeakReference = new WeakReference<>(dialog); - dialog.show(); - } - } - - @SuppressWarnings("unchecked") - @Override - protected void onProgressUpdate(Progress... values) { - super.onProgressUpdate(values); - Dialog dialog = getDialog(); - if (dialog != null) { - onProgressUpdate(dialog, values); - } - } - - @SuppressWarnings("unchecked") - protected void onProgressUpdate(@NonNull Dialog dialog, Progress... values) {} - - @Nullable - protected Dialog getDialog() { - return dialogWeakReference.get(); - } - - @Override - protected void onCancelled(Result result) { - super.onCancelled(result); - tryToDismiss(); - } - - @Override - protected void onPostExecute(Result result) { - super.onPostExecute(result); - tryToDismiss(); - } - - private void tryToDismiss() { - supposedToBeDismissed = true; - try { - Dialog dialog = getDialog(); - if (dialog != null) dialog.dismiss(); - } catch (Exception e) { - e.printStackTrace(); - } - } - - protected abstract Dialog createDialog(@NonNull Context context); -} diff --git a/app/src/main/java/code/name/monkey/retromusic/misc/LagTracker.java b/app/src/main/java/code/name/monkey/retromusic/misc/LagTracker.java deleted file mode 100755 index 983081184..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/misc/LagTracker.java +++ /dev/null @@ -1,86 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.misc; - -import android.util.Log; - -import java.util.HashMap; -import java.util.Map; -import java.util.concurrent.TimeUnit; - -public class LagTracker { - private static Map mMap; - private static LagTracker mSingleton; - private boolean mEnabled = true; - - private LagTracker() { - mMap = new HashMap<>(); - } - - public static LagTracker get() { - if (mSingleton == null) { - mSingleton = new LagTracker(); - } - return mSingleton; - } - - private void print(String str, long j) { - long toMillis = TimeUnit.NANOSECONDS.toMillis(j); - Log.d( - "LagTracker", - "[" - + str - + " completed in]: " - + j - + " ns (" - + toMillis - + "ms, " - + TimeUnit.NANOSECONDS.toSeconds(j) - + "s)"); - } - - public LagTracker disable() { - this.mEnabled = false; - return this; - } - - public LagTracker enable() { - this.mEnabled = true; - return this; - } - - public void end(String str) { - long nanoTime = System.nanoTime(); - if (this.mEnabled) { - if (mMap.containsKey(str)) { - print(str, nanoTime - mMap.get(str)); - mMap.remove(str); - return; - } - throw new IllegalStateException("No start time found for " + str); - } else if (!mMap.isEmpty()) { - mMap.clear(); - } - } - - public void start(String str) { - long nanoTime = System.nanoTime(); - if (this.mEnabled) { - mMap.put(str, nanoTime); - } else if (!mMap.isEmpty()) { - mMap.clear(); - } - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/misc/WeakContextAsyncTask.kt b/app/src/main/java/code/name/monkey/retromusic/misc/WeakContextAsyncTask.kt deleted file mode 100644 index 9b9b4896b..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/misc/WeakContextAsyncTask.kt +++ /dev/null @@ -1 +0,0 @@ -/* * Copyright (c) 2019 Hemanth Savarala. * * Licensed under the GNU General Public License v3 * * This is free software: you can redistribute it and/or modify it under * the terms of the GNU General Public License as published by * the Free Software Foundation either version 3 of the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. */ package code.name.monkey.retromusic.misc import android.content.Context import android.os.AsyncTask import java.lang.ref.WeakReference abstract class WeakContextAsyncTask(context: Context) : AsyncTask() { private val contextWeakReference: WeakReference = WeakReference(context) protected val context: Context? get() = contextWeakReference.get() } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/network/conversion/LyricsConverterFactory.kt b/app/src/main/java/code/name/monkey/retromusic/network/conversion/LyricsConverterFactory.kt index 1103653c4..03a8f4c77 100644 --- a/app/src/main/java/code/name/monkey/retromusic/network/conversion/LyricsConverterFactory.kt +++ b/app/src/main/java/code/name/monkey/retromusic/network/conversion/LyricsConverterFactory.kt @@ -25,9 +25,9 @@ import java.lang.reflect.Type class LyricsConverterFactory : Converter.Factory() { override fun responseBodyConverter( - type: Type?, - annotations: Array?, - retrofit: Retrofit? + type: Type, + annotations: Array, + retrofit: Retrofit ): Converter? { return if (String::class.java == type) { Converter { value -> value.string() } @@ -35,10 +35,10 @@ class LyricsConverterFactory : Converter.Factory() { } override fun requestBodyConverter( - type: Type?, - parameterAnnotations: Array?, - methodAnnotations: Array?, - retrofit: Retrofit? + type: Type, + parameterAnnotations: Array, + methodAnnotations: Array, + retrofit: Retrofit ): Converter<*, RequestBody>? { return if (String::class.java == type) { diff --git a/app/src/main/java/code/name/monkey/retromusic/preferences/AlbumCoverStylePreferenceDialog.kt b/app/src/main/java/code/name/monkey/retromusic/preferences/AlbumCoverStylePreferenceDialog.kt index 85dc63596..0a58e6573 100644 --- a/app/src/main/java/code/name/monkey/retromusic/preferences/AlbumCoverStylePreferenceDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/preferences/AlbumCoverStylePreferenceDialog.kt @@ -21,7 +21,6 @@ import android.util.AttributeSet import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.Toast import androidx.core.graphics.BlendModeColorFilterCompat import androidx.core.graphics.BlendModeCompat.SRC_IN import androidx.fragment.app.DialogFragment @@ -81,7 +80,7 @@ class AlbumCoverStylePreferenceDialog : DialogFragment(), val coverStyle = values()[viewPagerPosition] if (isAlbumCoverStyle(coverStyle)) { val result = getString(coverStyle.titleRes) + " theme is Pro version feature." - Toast.makeText(context, result, Toast.LENGTH_SHORT).show() + showToast(result) NavigationUtil.goToProVersion(requireActivity()) } else { PreferenceUtil.albumCoverStyle = coverStyle diff --git a/app/src/main/java/code/name/monkey/retromusic/preferences/BlacklistPreferenceDialog.kt b/app/src/main/java/code/name/monkey/retromusic/preferences/BlacklistPreferenceDialog.kt index 6c47487e5..c3283be21 100644 --- a/app/src/main/java/code/name/monkey/retromusic/preferences/BlacklistPreferenceDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/preferences/BlacklistPreferenceDialog.kt @@ -24,7 +24,6 @@ import androidx.core.graphics.BlendModeCompat.SRC_IN import androidx.core.text.parseAsHtml import androidx.fragment.app.DialogFragment import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEDialogPreference -import code.name.monkey.retromusic.App import code.name.monkey.retromusic.R import code.name.monkey.retromusic.dialogs.BlacklistFolderChooserDialog import code.name.monkey.retromusic.extensions.accentTextColor @@ -90,7 +89,7 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog ).parseAsHtml() ) .setPositiveButton(R.string.remove_action) { _, _ -> - BlacklistStore.getInstance(App.getContext()) + BlacklistStore.getInstance(requireContext()) .removePath(File(paths[which])) refreshBlacklistData() } @@ -119,13 +118,13 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog private lateinit var paths: ArrayList private fun refreshBlacklistData() { - this.paths = BlacklistStore.getInstance(App.getContext()).paths + this.paths = BlacklistStore.getInstance(requireContext()).paths val dialog = dialog as MaterialAlertDialogBuilder? dialog?.setItems(paths.toTypedArray(), null) } override fun onFolderSelection(dialog: BlacklistFolderChooserDialog, folder: File) { - BlacklistStore.getInstance(App.getContext()).addPath(folder) + BlacklistStore.getInstance(requireContext()).addPath(folder) refreshBlacklistData() } } diff --git a/app/src/main/java/code/name/monkey/retromusic/preferences/LibraryPreference.kt b/app/src/main/java/code/name/monkey/retromusic/preferences/LibraryPreference.kt index e88120a9c..3fa4aad50 100644 --- a/app/src/main/java/code/name/monkey/retromusic/preferences/LibraryPreference.kt +++ b/app/src/main/java/code/name/monkey/retromusic/preferences/LibraryPreference.kt @@ -18,7 +18,6 @@ import android.app.Dialog import android.content.Context import android.os.Bundle import android.util.AttributeSet -import android.widget.Toast import androidx.core.graphics.BlendModeColorFilterCompat import androidx.core.graphics.BlendModeCompat.SRC_IN import androidx.fragment.app.DialogFragment @@ -30,6 +29,7 @@ import code.name.monkey.retromusic.databinding.PreferenceDialogLibraryCategories import code.name.monkey.retromusic.extensions.colorButtons import code.name.monkey.retromusic.extensions.colorControlNormal import code.name.monkey.retromusic.extensions.materialDialog +import code.name.monkey.retromusic.extensions.showToast import code.name.monkey.retromusic.model.CategoryInfo import code.name.monkey.retromusic.util.PreferenceUtil @@ -76,7 +76,7 @@ class LibraryPreferenceDialog : DialogFragment() { private fun updateCategories(categories: List) { if (getSelected(categories) == 0) return if (getSelected(categories) > 5) { - Toast.makeText(context, "Not more than 5 items", Toast.LENGTH_SHORT).show() + showToast("Not more than 5 items") return } PreferenceUtil.libraryCategory = categories diff --git a/app/src/main/java/code/name/monkey/retromusic/preferences/NowPlayingScreenPreferenceDialog.kt b/app/src/main/java/code/name/monkey/retromusic/preferences/NowPlayingScreenPreferenceDialog.kt index 64b95d87e..3b038f120 100644 --- a/app/src/main/java/code/name/monkey/retromusic/preferences/NowPlayingScreenPreferenceDialog.kt +++ b/app/src/main/java/code/name/monkey/retromusic/preferences/NowPlayingScreenPreferenceDialog.kt @@ -21,7 +21,6 @@ import android.util.AttributeSet import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.widget.Toast import androidx.core.graphics.BlendModeColorFilterCompat import androidx.core.graphics.BlendModeCompat.SRC_IN import androidx.fragment.app.DialogFragment @@ -91,7 +90,7 @@ class NowPlayingScreenPreferenceDialog : DialogFragment(), ViewPager.OnPageChang if (isNowPlayingThemes(nowPlayingScreen)) { val result = "${getString(nowPlayingScreen.titleRes)} theme is Pro version feature." - Toast.makeText(context, result, Toast.LENGTH_SHORT).show() + showToast(result) NavigationUtil.goToProVersion(requireContext()) } else { PreferenceUtil.nowPlayingScreen = nowPlayingScreen diff --git a/app/src/main/java/code/name/monkey/retromusic/providers/BlacklistStore.java b/app/src/main/java/code/name/monkey/retromusic/providers/BlacklistStore.java index 90a89770e..b125385a6 100644 --- a/app/src/main/java/code/name/monkey/retromusic/providers/BlacklistStore.java +++ b/app/src/main/java/code/name/monkey/retromusic/providers/BlacklistStore.java @@ -15,6 +15,7 @@ package code.name.monkey.retromusic.providers; import static code.name.monkey.retromusic.service.MusicService.MEDIA_STORE_CHANGED; +import static code.name.monkey.retromusic.util.FileUtilsKt.getExternalStoragePublicDirectory; import android.content.ContentValues; import android.content.Context; @@ -50,11 +51,11 @@ public class BlacklistStore extends SQLiteOpenHelper { if (!PreferenceUtil.INSTANCE.isInitializedBlacklist()) { // blacklisted by default sInstance.addPathImpl( - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS)); + getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS)); sInstance.addPathImpl( - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_NOTIFICATIONS)); + getExternalStoragePublicDirectory(Environment.DIRECTORY_NOTIFICATIONS)); sInstance.addPathImpl( - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_RINGTONES)); + getExternalStoragePublicDirectory(Environment.DIRECTORY_RINGTONES)); PreferenceUtil.INSTANCE.setInitializedBlacklist(true); } diff --git a/app/src/main/java/code/name/monkey/retromusic/providers/MusicPlaybackQueueStore.java b/app/src/main/java/code/name/monkey/retromusic/providers/MusicPlaybackQueueStore.java index 6875083b9..f1349ad7a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/providers/MusicPlaybackQueueStore.java +++ b/app/src/main/java/code/name/monkey/retromusic/providers/MusicPlaybackQueueStore.java @@ -27,6 +27,7 @@ import androidx.annotation.Nullable; import java.util.List; import code.name.monkey.retromusic.App; +import code.name.monkey.retromusic.Constants; import code.name.monkey.retromusic.model.Song; import code.name.monkey.retromusic.repository.RealSongRepository; @@ -128,7 +129,7 @@ public class MusicPlaybackQueueStore extends SQLiteOpenHelper { builder.append(AudioColumns.DURATION); builder.append(" LONG NOT NULL,"); - builder.append(AudioColumns.DATA); + builder.append(Constants.DATA); builder.append(" STRING NOT NULL,"); builder.append(AudioColumns.DATE_MODIFIED); @@ -192,7 +193,7 @@ public class MusicPlaybackQueueStore extends SQLiteOpenHelper { values.put(AudioColumns.TRACK, song.getTrackNumber()); values.put(AudioColumns.YEAR, song.getYear()); values.put(AudioColumns.DURATION, song.getDuration()); - values.put(AudioColumns.DATA, song.getData()); + values.put(Constants.DATA, song.getData()); values.put(AudioColumns.DATE_MODIFIED, song.getDateModified()); values.put(AudioColumns.ALBUM_ID, song.getAlbumId()); values.put(AudioColumns.ALBUM, song.getAlbumName()); diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/GenreRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/GenreRepository.kt index d773beef9..668bdc64f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/GenreRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/GenreRepository.kt @@ -102,7 +102,7 @@ class RealGenreRepository( private fun getGenresFromCursor(cursor: Cursor?): ArrayList { val genres = arrayListOf() - if (cursor != null) { + cursor?.use { if (cursor.moveToFirst()) { do { val genre = getGenreFromCursor(cursor) diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistRepository.kt index 004dfa370..75fbeaca1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistRepository.kt @@ -51,7 +51,7 @@ interface PlaylistRepository { fun playlistSongs(playlistId: Long): List } - +@Suppress("Deprecation") class RealPlaylistRepository( private val contentResolver: ContentResolver ) : PlaylistRepository { @@ -148,7 +148,7 @@ class RealPlaylistRepository( val trackNumber = cursor.getInt(AudioColumns.TRACK) val year = cursor.getInt(AudioColumns.YEAR) val duration = cursor.getLong(AudioColumns.DURATION) - val data = cursor.getString(AudioColumns.DATA) + val data = cursor.getString(Constants.DATA) val dateModified = cursor.getLong(AudioColumns.DATE_MODIFIED) val albumId = cursor.getLong(AudioColumns.ALBUM_ID) val albumName = cursor.getString(AudioColumns.ALBUM) @@ -202,7 +202,7 @@ class RealPlaylistRepository( AudioColumns.TRACK, // 2 AudioColumns.YEAR, // 3 AudioColumns.DURATION, // 4 - AudioColumns.DATA, // 5 + Constants.DATA, // 5 AudioColumns.DATE_MODIFIED, // 6 AudioColumns.ALBUM_ID, // 7 AudioColumns.ALBUM, // 8 diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistSongsLoader.kt b/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistSongsLoader.kt index 80f0829a8..abdec08fb 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistSongsLoader.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/PlaylistSongsLoader.kt @@ -18,33 +18,21 @@ import android.content.Context import android.database.Cursor import android.provider.MediaStore.Audio.AudioColumns import android.provider.MediaStore.Audio.Playlists.Members +import code.name.monkey.retromusic.Constants import code.name.monkey.retromusic.Constants.IS_MUSIC import code.name.monkey.retromusic.extensions.getInt import code.name.monkey.retromusic.extensions.getLong import code.name.monkey.retromusic.extensions.getString import code.name.monkey.retromusic.extensions.getStringOrNull -import code.name.monkey.retromusic.model.AbsCustomPlaylist -import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.PlaylistSong import code.name.monkey.retromusic.model.Song /** * Created by hemanths on 16/08/17. */ - +@Suppress("Deprecation") object PlaylistSongsLoader { - fun getPlaylistSongList( - context: Context, - playlist: Playlist - ): List { - return if (playlist is AbsCustomPlaylist) { - return playlist.songs() - } else { - getPlaylistSongList(context, playlist.id) - } - } - @JvmStatic fun getPlaylistSongList(context: Context, playlistId: Long): List { val songs = mutableListOf() @@ -75,7 +63,7 @@ object PlaylistSongsLoader { val trackNumber = cursor.getInt(AudioColumns.TRACK) val year = cursor.getInt(AudioColumns.YEAR) val duration = cursor.getLong(AudioColumns.DURATION) - val data = cursor.getString(AudioColumns.DATA) + val data = cursor.getString(Constants.DATA) val dateModified = cursor.getLong(AudioColumns.DATE_MODIFIED) val albumId = cursor.getLong(AudioColumns.ALBUM_ID) val albumName = cursor.getString(AudioColumns.ALBUM) @@ -113,7 +101,7 @@ object PlaylistSongsLoader { AudioColumns.TRACK, // 2 AudioColumns.YEAR, // 3 AudioColumns.DURATION, // 4 - AudioColumns.DATA, // 5 + Constants.DATA, // 5 AudioColumns.DATE_MODIFIED, // 6 AudioColumns.ALBUM_ID, // 7 AudioColumns.ALBUM, // 8 diff --git a/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt b/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt index 0b5f237e7..b6ddb4a69 100644 --- a/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt +++ b/app/src/main/java/code/name/monkey/retromusic/repository/SongRepository.kt @@ -16,12 +16,12 @@ package code.name.monkey.retromusic.repository import android.content.Context import android.database.Cursor -import android.net.Uri import android.os.Environment import android.provider.MediaStore import android.provider.MediaStore.Audio.AudioColumns import android.provider.MediaStore.Audio.Media import code.name.monkey.appthemehelper.util.VersionUtils +import code.name.monkey.retromusic.Constants import code.name.monkey.retromusic.Constants.IS_MUSIC import code.name.monkey.retromusic.Constants.baseProjection import code.name.monkey.retromusic.extensions.getInt @@ -32,6 +32,7 @@ import code.name.monkey.retromusic.helper.SortOrder import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.providers.BlacklistStore import code.name.monkey.retromusic.util.PreferenceUtil +import code.name.monkey.retromusic.util.getExternalStoragePublicDirectory import java.text.Collator /** @@ -52,8 +53,6 @@ interface SongRepository { fun song(cursor: Cursor?): Song fun song(songId: Long): Song - - fun songsIgnoreBlacklist(uri: Uri): List } class RealSongRepository(private val context: Context) : SongRepository { @@ -120,35 +119,13 @@ class RealSongRepository(private val context: Context) : SongRepository { override fun songsByFilePath(filePath: String, ignoreBlacklist: Boolean): List { return songs( makeSongCursor( - AudioColumns.DATA + "=?", + Constants.DATA + "=?", arrayOf(filePath), ignoreBlacklist = ignoreBlacklist ) ) } - override fun songsIgnoreBlacklist(uri: Uri): List { - var filePath = "" - context.contentResolver.query( - uri, - arrayOf(AudioColumns.DATA), - null, - null, - null - ).use { cursor -> - if (cursor != null) { - if (cursor.count != 0) { - cursor.moveToFirst() - filePath = cursor.getString(AudioColumns.DATA) - println("File Path: $filePath") - } - } - } - return songsByFilePath( - filePath, true - ) - } - private fun getSongFromCursorImpl( cursor: Cursor ): Song { @@ -157,7 +134,7 @@ class RealSongRepository(private val context: Context) : SongRepository { val trackNumber = cursor.getInt(AudioColumns.TRACK) val year = cursor.getInt(AudioColumns.YEAR) val duration = cursor.getLong(AudioColumns.DURATION) - val data = cursor.getString(AudioColumns.DATA) + val data = cursor.getString(Constants.DATA) val dateModified = cursor.getLong(AudioColumns.DATE_MODIFIED) val albumId = cursor.getLong(AudioColumns.ALBUM_ID) val albumName = cursor.getStringOrNull(AudioColumns.ALBUM) @@ -201,10 +178,10 @@ class RealSongRepository(private val context: Context) : SongRepository { // Whitelist if (PreferenceUtil.isWhiteList) { selectionFinal = - selectionFinal + " AND " + AudioColumns.DATA + " LIKE ?" + selectionFinal + " AND " + Constants.DATA + " LIKE ?" selectionValuesFinal = addSelectionValues( selectionValuesFinal, arrayListOf( - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).canonicalPath + getExternalStoragePublicDirectory(Environment.DIRECTORY_MUSIC).canonicalPath ) ) } else { @@ -243,9 +220,9 @@ class RealSongRepository(private val context: Context) : SongRepository { ): String { val newSelection = StringBuilder( if (selection != null && selection.trim { it <= ' ' } != "") "$selection AND " else "") - newSelection.append(AudioColumns.DATA + " NOT LIKE ?") + newSelection.append(Constants.DATA + " NOT LIKE ?") for (i in 0 until pathCount - 1) { - newSelection.append(" AND " + AudioColumns.DATA + " NOT LIKE ?") + newSelection.append(" AND " + Constants.DATA + " NOT LIKE ?") } return newSelection.toString() } diff --git a/app/src/main/java/code/name/monkey/retromusic/service/CrossFadePlayer.kt b/app/src/main/java/code/name/monkey/retromusic/service/CrossFadePlayer.kt index e9a7ffd00..4f5e791ad 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/CrossFadePlayer.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/CrossFadePlayer.kt @@ -9,9 +9,9 @@ import android.media.MediaPlayer import android.media.audiofx.AudioEffect import android.os.PowerManager import android.util.Log -import android.widget.Toast import androidx.core.net.toUri import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.extensions.showToast import code.name.monkey.retromusic.helper.MusicPlayerRemote import code.name.monkey.retromusic.service.AudioFader.Companion.createFadeAnimator import code.name.monkey.retromusic.service.playback.Playback @@ -120,20 +120,9 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion override val isPlaying: Boolean get() = mIsInitialized && getCurrentPlayer()?.isPlaying == true - // This has to run when queue is changed or song is changed manually by user - fun sourceChangedByUser() { - hasDataSource = false - cancelFade() - getCurrentPlayer()?.apply { - if (isPlaying) stop() - } - getNextPlayer()?.apply { - if (isPlaying) stop() - } - } - - override fun setDataSource(path: String): Boolean { + override fun setDataSource(path: String, force: Boolean): Boolean { cancelFade() + if (force) hasDataSource = false mIsInitialized = false /* We've already set DataSource if initialized is true in setNextDataSource */ if (!hasDataSource) { @@ -154,7 +143,7 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion */ private fun setDataSourceImpl( player: MediaPlayer, - path: String + path: String, ): Boolean { player.reset() player.setOnPreparedListener(null) @@ -291,12 +280,7 @@ class CrossFadePlayer(val context: Context) : Playback, MediaPlayer.OnCompletion player2 = MediaPlayer() mIsInitialized = true mp?.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK) - Toast.makeText( - context, - context.resources.getString(R.string.unplayable_file), - Toast.LENGTH_SHORT - ) - .show() + context.showToast(R.string.unplayable_file) Log.e(TAG, what.toString() + extra) return false } diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.java b/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.java index 275300f2b..f5c8756bb 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.java +++ b/app/src/main/java/code/name/monkey/retromusic/service/MultiPlayer.java @@ -30,6 +30,8 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.preference.PreferenceManager; +import org.jetbrains.annotations.NotNull; + import code.name.monkey.appthemehelper.util.VersionUtils; import code.name.monkey.retromusic.ConstantsKt; import code.name.monkey.retromusic.R; @@ -66,7 +68,7 @@ public class MultiPlayer * @return True if the player has been prepared and is ready to play, false otherwise */ @Override - public boolean setDataSource(@NonNull final String path) { + public boolean setDataSource(@NotNull final String path, boolean force) { mIsInitialized = false; mIsInitialized = setDataSourceImpl(mCurrentMediaPlayer, path); if (mIsInitialized) { diff --git a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt index e39ddf6bf..72005339d 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/MusicService.kt @@ -13,6 +13,7 @@ */ package code.name.monkey.retromusic.service +import android.annotation.SuppressLint import android.app.NotificationManager import android.appwidget.AppWidgetManager import android.bluetooth.BluetoothDevice @@ -54,8 +55,10 @@ import code.name.monkey.retromusic.activities.LockScreenActivity import code.name.monkey.retromusic.appwidgets.* import code.name.monkey.retromusic.auto.AutoMediaIDHelper import code.name.monkey.retromusic.auto.AutoMusicProvider +import code.name.monkey.retromusic.extensions.showToast import code.name.monkey.retromusic.glide.BlurTransformation import code.name.monkey.retromusic.glide.GlideApp +import code.name.monkey.retromusic.glide.RetroGlideExtension.getDefaultTransition import code.name.monkey.retromusic.glide.RetroGlideExtension.getSongModel import code.name.monkey.retromusic.helper.MusicPlayerRemote.isCasting import code.name.monkey.retromusic.helper.ShuffleHelper.makeShuffleList @@ -73,7 +76,6 @@ import code.name.monkey.retromusic.service.playback.Playback import code.name.monkey.retromusic.service.playback.Playback.PlaybackCallbacks import code.name.monkey.retromusic.util.MusicUtil.getMediaStoreAlbumCoverUri import code.name.monkey.retromusic.util.MusicUtil.getSongFileUri -import code.name.monkey.retromusic.util.MusicUtil.isFavorite import code.name.monkey.retromusic.util.MusicUtil.toggleFavorite import code.name.monkey.retromusic.util.PackageValidator import code.name.monkey.retromusic.util.PreferenceUtil.crossFadeDuration @@ -87,11 +89,10 @@ import code.name.monkey.retromusic.util.PreferenceUtil.isPauseOnZeroVolume import code.name.monkey.retromusic.util.PreferenceUtil.playbackSpeed import code.name.monkey.retromusic.util.PreferenceUtil.registerOnSharedPreferenceChangedListener import code.name.monkey.retromusic.util.PreferenceUtil.unregisterOnSharedPreferenceChangedListener -import code.name.monkey.retromusic.util.RetroUtil import code.name.monkey.retromusic.volume.AudioVolumeObserver import code.name.monkey.retromusic.volume.OnAudioVolumeChangedListener -import com.bumptech.glide.RequestBuilder -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 org.koin.java.KoinJavaComponent.get import java.util.* @@ -251,7 +252,6 @@ class MusicService : MediaBrowserServiceCompat(), play() TelephonyManager.CALL_STATE_RINGING, TelephonyManager.CALL_STATE_OFFHOOK -> // A call is dialing, active or on hold pause() - else -> {} } super.onCallStateChanged(state, incomingNumber) } @@ -303,7 +303,7 @@ class MusicService : MediaBrowserServiceCompat(), HandlerThread("QueueSaveHandler", Process.THREAD_PRIORITY_BACKGROUND) queueSaveHandlerThread?.start() queueSaveHandler = QueueSaveHandler(this, queueSaveHandlerThread!!.looper) - uiThreadHandler = Handler() + uiThreadHandler = Handler(Looper.getMainLooper()) registerReceiver(widgetIntentReceiver, IntentFilter(APP_WIDGET_UPDATE)) registerReceiver(updateFavoriteReceiver, IntentFilter(FAVORITE_STATE_CHANGED)) registerReceiver(lockScreenReceiver, IntentFilter(Intent.ACTION_SCREEN_OFF)) @@ -392,7 +392,7 @@ class MusicService : MediaBrowserServiceCompat(), wakeLock?.acquire(milli) } - var pausedByZeroVolume = false + private var pausedByZeroVolume = false override fun onAudioVolumeChanged(currentVolume: Int, maxVolume: Int) { if (isPauseOnZeroVolume) { if (isPlaying && currentVolume < 1) { @@ -643,7 +643,7 @@ class MusicService : MediaBrowserServiceCompat(), override fun onGetRoot( clientPackageName: String, clientUid: Int, - rootHints: Bundle? + rootHints: Bundle?, ): BrowserRoot { @@ -672,7 +672,7 @@ class MusicService : MediaBrowserServiceCompat(), override fun onLoadChildren( parentId: String, - result: Result> + result: Result>, ) { if (parentId == AutoMediaIDHelper.RECENT_ROOT) { val song = currentSong @@ -691,16 +691,14 @@ class MusicService : MediaBrowserServiceCompat(), } override fun onSharedPreferenceChanged( - sharedPreferences: SharedPreferences, key: String + sharedPreferences: SharedPreferences, key: String, ) { when (key) { CROSS_FADE_DURATION -> { val progress = songProgressMillis val wasPlaying = isPlaying /* Switch to MultiPlayer if Crossfade duration is 0 and - Playback is not an instance of MultiPlayer */if (playback != null) playback?.setCrossFadeDuration( - crossFadeDuration - ) + Playback is not an instance of MultiPlayer */ if (playback !is MultiPlayer && crossFadeDuration == 0) { if (playback != null) { playback?.release() @@ -728,6 +726,9 @@ class MusicService : MediaBrowserServiceCompat(), } } } + if (playback != null) playback?.setCrossFadeDuration( + crossFadeDuration + ) } ALBUM_ART_ON_LOCK_SCREEN, BLURRED_ALBUM_ART -> updateMediaSessionMetaData() COLORED_NOTIFICATION -> { @@ -799,7 +800,7 @@ class MusicService : MediaBrowserServiceCompat(), fun openQueue( playingQueue: List?, startPosition: Int, - startPlaying: Boolean + startPlaying: Boolean, ) { if (playingQueue != null && playingQueue.isNotEmpty() && startPosition >= 0 && startPosition < playingQueue.size @@ -891,10 +892,7 @@ class MusicService : MediaBrowserServiceCompat(), } } } else { - Toast.makeText( - this, resources.getString(R.string.audio_focus_denied), Toast.LENGTH_SHORT - ) - .show() + showToast(R.string.audio_focus_denied) } } @@ -913,19 +911,10 @@ class MusicService : MediaBrowserServiceCompat(), } fun playSongAtImpl(position: Int) { - if (!trackEndedByCrossfade) { - // This is only imp if we are using crossfade - if (playback is CrossFadePlayer) { - (playback as CrossFadePlayer).sourceChangedByUser() - } - } else { - trackEndedByCrossfade = false - } if (openTrackAndPrepareNextAt(position)) { play() } else { - Toast.makeText(this, resources.getString(R.string.unplayable_file), Toast.LENGTH_SHORT) - .show() + showToast(resources.getString(R.string.unplayable_file)) } } @@ -940,7 +929,7 @@ class MusicService : MediaBrowserServiceCompat(), } play() } else { - Toast.makeText(applicationContext, R.string.playlist_is_empty, Toast.LENGTH_LONG).show() + showToast(R.string.playlist_is_empty) } } @@ -1125,6 +1114,7 @@ class MusicService : MediaBrowserServiceCompat(), } } + @SuppressLint("CheckResult") fun updateMediaSessionMetaData() { Log.i(TAG, "onResourceReady: ") val song = currentSong @@ -1134,29 +1124,29 @@ class MusicService : MediaBrowserServiceCompat(), } val metaData = MediaMetadataCompat.Builder() .putString(MediaMetadataCompat.METADATA_KEY_ARTIST, song.artistName) - .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST, song.artistName) + .putString(MediaMetadataCompat.METADATA_KEY_ALBUM_ARTIST, song.albumArtist) .putString(MediaMetadataCompat.METADATA_KEY_ALBUM, song.albumName) .putString(MediaMetadataCompat.METADATA_KEY_TITLE, song.title) .putLong(MediaMetadataCompat.METADATA_KEY_DURATION, song.duration) .putLong(MediaMetadataCompat.METADATA_KEY_TRACK_NUMBER, (getPosition() + 1).toLong()) .putLong(MediaMetadataCompat.METADATA_KEY_YEAR, song.year.toLong()) .putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, null) - metaData.putLong( - MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, - playingQueue.size.toLong() - ) + .putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, playingQueue.size.toLong()) + if (isAlbumArtOnLockScreen) { - val screenSize = RetroUtil.getScreenSize(this@MusicService) - val request: RequestBuilder = - GlideApp.with(this@MusicService) - .asBitmap() - .songCoverOptions(song) - .load(getSongModel(song)) + // val screenSize: Point = RetroUtil.getScreenSize(this) + val request = GlideApp.with(this) + .asBitmap() + .songCoverOptions(song) + .load(getSongModel(song)) + .transition(getDefaultTransition()) + if (isBlurredAlbumArt) { request.transform(BlurTransformation.Builder(this@MusicService).build()) } runOnUiThread { - request.into(object : SimpleTarget(screenSize.x, screenSize.y) { + request.into(object : + CustomTarget(Target.SIZE_ORIGINAL, Target.SIZE_ORIGINAL) { override fun onLoadFailed(errorDrawable: Drawable?) { super.onLoadFailed(errorDrawable) mediaSession?.setMetadata(metaData.build()) @@ -1164,7 +1154,7 @@ class MusicService : MediaBrowserServiceCompat(), override fun onResourceReady( resource: Bitmap, - transition: Transition? + transition: Transition?, ) { metaData.putBitmap( MediaMetadataCompat.METADATA_KEY_ALBUM_ART, @@ -1172,6 +1162,10 @@ class MusicService : MediaBrowserServiceCompat(), ) mediaSession?.setMetadata(metaData.build()) } + + override fun onLoadCleared(placeholder: Drawable?) { + mediaSession?.setMetadata(metaData.build()) + } }) } } else { @@ -1244,17 +1238,16 @@ class MusicService : MediaBrowserServiceCompat(), private fun startForegroundOrNotify() { if (playingNotification != null && currentSong.id != -1L) { - if (!VersionUtils.hasS()) { - if (isForeground && !isPlaying) { - // This makes the notification dismissible - // We can't call stopForeground(false) on A12 though, which may result in crashes - // when we call startForeground after that e.g. when Alarm goes off - + if (isForeground && !isPlaying) { + // This makes the notification dismissible + // We can't call stopForeground(false) on A12 though, which may result in crashes + // when we call startForeground after that e.g. when Alarm goes off, + if (!VersionUtils.hasS()) { stopForeground(false) isForeground = false } } - if (!isForeground) { + if (!isForeground && isPlaying) { // Specify that this is a media service, if supported. if (VersionUtils.hasQ()) { startForeground( @@ -1285,15 +1278,15 @@ class MusicService : MediaBrowserServiceCompat(), @Synchronized private fun openCurrent(): Boolean { + val force = if (!trackEndedByCrossfade) { + true + } else { + trackEndedByCrossfade = false + false + } return try { if (playback != null) { - return playback!!.setDataSource( - getTrackUri( - Objects.requireNonNull( - currentSong - ) - ) - ) + return playback!!.setDataSource(getTrackUri(currentSong), force) } else false } catch (e: Exception) { e.printStackTrace() @@ -1315,11 +1308,10 @@ class MusicService : MediaBrowserServiceCompat(), openQueue(playlistSongs, 0, true) } } else { - Toast.makeText(applicationContext, R.string.playlist_is_empty, Toast.LENGTH_LONG) - .show() + showToast(R.string.playlist_is_empty, Toast.LENGTH_LONG) } } else { - Toast.makeText(applicationContext, R.string.playlist_is_empty, Toast.LENGTH_LONG).show() + showToast(R.string.playlist_is_empty, Toast.LENGTH_LONG) } } @@ -1422,17 +1414,6 @@ class MusicService : MediaBrowserServiceCompat(), ) .build() ) - val favoriteIcon = if (isFavorite( - applicationContext, - currentSong - ) - ) R.drawable.ic_favorite else R.drawable.ic_favorite_border - stateBuilder.addCustomAction( - PlaybackStateCompat.CustomAction.Builder( - TOGGLE_FAVORITE, getString(R.string.action_toggle_favorite), favoriteIcon - ) - .build() - ) } private fun setupMediaSession() { diff --git a/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationClassic.kt b/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationClassic.kt index 8bd1bceff..7acb1d21c 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationClassic.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationClassic.kt @@ -25,6 +25,7 @@ import android.graphics.Color import android.graphics.drawable.Drawable import android.widget.RemoteViews import androidx.core.app.NotificationCompat +import androidx.core.graphics.drawable.toBitmap import androidx.media.app.NotificationCompat.DecoratedMediaCustomViewStyle import code.name.monkey.appthemehelper.util.ATHUtil.resolveColor import code.name.monkey.appthemehelper.util.ColorUtil @@ -32,8 +33,10 @@ 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.extensions.getTintedDrawable import code.name.monkey.retromusic.extensions.isColorLight import code.name.monkey.retromusic.extensions.isSystemDarkModeEnabled +import code.name.monkey.retromusic.extensions.toBitmap import code.name.monkey.retromusic.glide.GlideApp import code.name.monkey.retromusic.glide.RetroGlideExtension import code.name.monkey.retromusic.glide.palette.BitmapPaletteWrapper @@ -45,7 +48,6 @@ 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 code.name.monkey.retromusic.util.RetroUtil.createBitmap import code.name.monkey.retromusic.util.color.MediaNotificationProcessor import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.transition.Transition @@ -55,7 +57,7 @@ import com.bumptech.glide.request.transition.Transition */ @SuppressLint("RestrictedApi") class PlayingNotificationClassic( - val context: Context + val context: Context, ) : PlayingNotification(context) { private var primaryColor: Int = 0 @@ -114,7 +116,7 @@ class PlayingNotificationClassic( ) { override fun onResourceReady( resource: BitmapPaletteWrapper, - transition: Transition? + transition: Transition?, ) { val colors = MediaNotificationProcessor(context, resource.bitmap) update(resource.bitmap, colors.backgroundColor) @@ -183,27 +185,20 @@ class PlayingNotificationClassic( val secondary = MaterialValueHelper.getSecondaryTextColor(context, dark) primaryColor = primary - val close = createBitmap( - RetroUtil.getTintedVectorDrawable( - context, - R.drawable.ic_close, - primary - ), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER - ) - val prev = createBitmap( - RetroUtil.getTintedVectorDrawable( - context, + val close = context.getTintedDrawable( + R.drawable.ic_close, + primary + ).toBitmap() + val prev = + context.getTintedDrawable( R.drawable.ic_skip_previous_round_white_32dp, primary - ), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER - ) - val next = createBitmap( - RetroUtil.getTintedVectorDrawable( - context, + ).toBitmap() + val next = + context.getTintedDrawable( R.drawable.ic_skip_next_round_white_32dp, primary - ), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER - ) + ).toBitmap() val playPause = getPlayPauseBitmap(true) contentView.setTextColor(R.id.title, primary) @@ -225,44 +220,35 @@ class PlayingNotificationClassic( contentView.setImageViewBitmap( R.id.smallIcon, - createBitmap( - RetroUtil.getTintedVectorDrawable( - context, - R.drawable.ic_notification, - secondary - ), 0.6f - ) + context.getTintedDrawable( + R.drawable.ic_notification, + secondary + ).toBitmap(0.6f) ) bigContentView.setImageViewBitmap( R.id.smallIcon, - createBitmap( - RetroUtil.getTintedVectorDrawable( - context, - R.drawable.ic_notification, - secondary - ), 0.6f - ) + context.getTintedDrawable( + R.drawable.ic_notification, + secondary + ).toBitmap(0.6f) ) } }) } private fun getPlayPauseBitmap(isPlaying: Boolean): Bitmap { - return createBitmap( - RetroUtil.getTintedVectorDrawable( - context, - if (isPlaying) - R.drawable.ic_pause_white_48dp - else - R.drawable.ic_play_arrow_white_48dp, primaryColor - ), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER - ) + return context.getTintedDrawable( + if (isPlaying) + R.drawable.ic_pause_white_48dp + else + R.drawable.ic_play_arrow_white_48dp, primaryColor + ).toBitmap() } override fun setPlaying(isPlaying: Boolean) { getPlayPauseBitmap(isPlaying).also { - contentView.setImageViewBitmap(R.id.action_play_pause, it) - bigContentView.setImageViewBitmap(R.id.action_play_pause, it) + contentView?.setImageViewBitmap(R.id.action_play_pause, it) + bigContentView?.setImageViewBitmap(R.id.action_play_pause, it) } } @@ -271,7 +257,7 @@ class PlayingNotificationClassic( private fun buildPendingIntent( context: Context, action: String, - serviceName: ComponentName? + serviceName: ComponentName?, ): PendingIntent { val intent = Intent(action) intent.component = serviceName @@ -308,7 +294,7 @@ class PlayingNotificationClassic( companion object { fun from( context: Context, - notificationManager: NotificationManager + notificationManager: NotificationManager, ): PlayingNotification { if (VersionUtils.hasOreo()) { createNotificationChannel(context, notificationManager) diff --git a/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationImpl24.kt b/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationImpl24.kt index e65443ca6..887209ab3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationImpl24.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/notification/PlayingNotificationImpl24.kt @@ -20,10 +20,9 @@ import android.app.PendingIntent import android.content.ComponentName import android.content.Context import android.content.Intent +import android.graphics.Bitmap import android.graphics.BitmapFactory -import android.graphics.Color import android.graphics.drawable.Drawable -import android.os.Build import android.support.v4.media.session.MediaSessionCompat import androidx.core.app.NotificationCompat import androidx.core.text.parseAsHtml @@ -33,7 +32,6 @@ import code.name.monkey.retromusic.R import code.name.monkey.retromusic.activities.MainActivity 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.model.Song import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_QUIT @@ -43,7 +41,6 @@ import code.name.monkey.retromusic.service.MusicService.Companion.ACTION_TOGGLE_ import code.name.monkey.retromusic.service.MusicService.Companion.TOGGLE_FAVORITE import code.name.monkey.retromusic.util.MusicUtil import code.name.monkey.retromusic.util.PreferenceUtil -import code.name.monkey.retromusic.util.RetroColorUtil import com.bumptech.glide.request.target.CustomTarget import com.bumptech.glide.request.transition.Transition import kotlinx.coroutines.Dispatchers @@ -125,26 +122,18 @@ class PlayingNotificationImpl24( setSubText(("" + song.albumName + "").parseAsHtml()) val bigNotificationImageSize = context.resources .getDimensionPixelSize(R.dimen.notification_big_image_size) - GlideApp.with(context).asBitmapPalette().songCoverOptions(song) + GlideApp.with(context) + .asBitmap() + .songCoverOptions(song) .load(RetroGlideExtension.getSongModel(song)) //.checkIgnoreMediaStore() .centerCrop() - .into(object : CustomTarget( + .into(object : CustomTarget( bigNotificationImageSize, bigNotificationImageSize ) { - override fun onResourceReady( - resource: BitmapPaletteWrapper, - transition: Transition? - ) { - setLargeIcon( - resource.bitmap - ) - if (Build.VERSION.SDK_INT <= - Build.VERSION_CODES.O && PreferenceUtil.isColoredNotification - ) { - color = RetroColorUtil.getColor(resource.palette, Color.TRANSPARENT) - } + override fun onResourceReady(resource: Bitmap, transition: Transition?) { + setLargeIcon(resource) onUpdate() } diff --git a/app/src/main/java/code/name/monkey/retromusic/service/playback/Playback.kt b/app/src/main/java/code/name/monkey/retromusic/service/playback/Playback.kt index 08c81bb05..9a0ef73a7 100644 --- a/app/src/main/java/code/name/monkey/retromusic/service/playback/Playback.kt +++ b/app/src/main/java/code/name/monkey/retromusic/service/playback/Playback.kt @@ -23,7 +23,7 @@ interface Playback { val audioSessionId: Int - fun setDataSource(path: String): Boolean + fun setDataSource(path: String, force: Boolean): Boolean fun setNextDataSource(path: String?) diff --git a/app/src/main/java/code/name/monkey/retromusic/util/ArtistSignatureUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/ArtistSignatureUtil.java deleted file mode 100644 index 5a069f5a1..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/util/ArtistSignatureUtil.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.util; - -import android.content.Context; -import android.content.SharedPreferences; - -import androidx.annotation.NonNull; - -import com.bumptech.glide.signature.ObjectKey; - -/** @author Karim Abou Zeid (kabouzeid) */ -public class ArtistSignatureUtil { - private static final String ARTIST_SIGNATURE_PREFS = "artist_signatures"; - - private static ArtistSignatureUtil sInstance; - - private final SharedPreferences mPreferences; - - private ArtistSignatureUtil(@NonNull final Context context) { - mPreferences = context.getSharedPreferences(ARTIST_SIGNATURE_PREFS, Context.MODE_PRIVATE); - } - - public static ArtistSignatureUtil getInstance(@NonNull final Context context) { - if (sInstance == null) { - sInstance = new ArtistSignatureUtil(context.getApplicationContext()); - } - return sInstance; - } - - public void updateArtistSignature(String artistName) { - mPreferences.edit().putLong(artistName, System.currentTimeMillis()).apply(); - } - - public long getArtistSignatureRaw(String artistName) { - return mPreferences.getLong(artistName, 0); - } - - public ObjectKey getArtistSignature(String artistName) { - return new ObjectKey(String.valueOf(getArtistSignatureRaw(artistName))); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/ArtistSignatureUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/ArtistSignatureUtil.kt new file mode 100644 index 000000000..94a5b0b58 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/ArtistSignatureUtil.kt @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2019 Hemanth Savarala. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + */ +package code.name.monkey.retromusic.util + +import android.content.Context +import android.content.SharedPreferences +import androidx.core.content.edit +import com.bumptech.glide.signature.ObjectKey + +/** @author Karim Abou Zeid (kabouzeid) + */ +class ArtistSignatureUtil private constructor(context: Context) { + private val mPreferences: SharedPreferences = + context.getSharedPreferences(ARTIST_SIGNATURE_PREFS, Context.MODE_PRIVATE) + + fun updateArtistSignature(artistName: String?) { + mPreferences.edit { putLong(artistName, System.currentTimeMillis()) } + } + + private fun getArtistSignatureRaw(artistName: String?): Long { + return mPreferences.getLong(artistName, 0) + } + + fun getArtistSignature(artistName: String?): ObjectKey { + return ObjectKey(getArtistSignatureRaw(artistName).toString()) + } + + companion object { + private const val ARTIST_SIGNATURE_PREFS = "artist_signatures" + private var INSTANCE: ArtistSignatureUtil? = null + fun getInstance(context: Context): ArtistSignatureUtil { + if (INSTANCE == null) { + INSTANCE = ArtistSignatureUtil(context.applicationContext) + } + return INSTANCE!! + } + } + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/AutoGeneratedPlaylistBitmap.java b/app/src/main/java/code/name/monkey/retromusic/util/AutoGeneratedPlaylistBitmap.java deleted file mode 100644 index b0efcd62f..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/util/AutoGeneratedPlaylistBitmap.java +++ /dev/null @@ -1,52 +0,0 @@ -package code.name.monkey.retromusic.util; - -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; - -import androidx.annotation.NonNull; - -import com.bumptech.glide.Glide; - -import java.util.ArrayList; -import java.util.List; - -import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.model.Song; - -public class AutoGeneratedPlaylistBitmap { - - public static Bitmap getBitmap( - Context context, List songPlaylist) { - if (songPlaylist == null || songPlaylist.isEmpty()) return getDefaultBitmap(context); - if (songPlaylist.size() == 1) - return getBitmapWithAlbumId(context, songPlaylist.get(0).getAlbumId()); - List albumID = new ArrayList<>(); - for (Song song : songPlaylist) { - if (!albumID.contains(song.getAlbumId())) albumID.add(song.getAlbumId()); - } - List art = new ArrayList<>(); - for (Long id : albumID) { - Bitmap bitmap = getBitmapWithAlbumId(context, id); - if (bitmap != null) art.add(BitmapEditor.getRoundedCornerBitmap(bitmap, 20)); - if (art.size() == 9) break; - } - return MergedImageUtils.INSTANCE.joinImages(art); - } - - private static Bitmap getBitmapWithAlbumId(@NonNull Context context, Long id) { - try { - return Glide.with(context) - .asBitmap() - .load(MusicUtil.getMediaStoreAlbumCoverUri(id)) - .submit(200, 200) - .get(); - } catch (Exception e) { - return null; - } - } - - public static Bitmap getDefaultBitmap(@NonNull Context context) { - return BitmapFactory.decodeResource(context.getResources(), R.drawable.default_album_art); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/AutoGeneratedPlaylistBitmap.kt b/app/src/main/java/code/name/monkey/retromusic/util/AutoGeneratedPlaylistBitmap.kt new file mode 100644 index 000000000..1024e03fc --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/AutoGeneratedPlaylistBitmap.kt @@ -0,0 +1,48 @@ +package code.name.monkey.retromusic.util + +import android.content.Context +import android.graphics.Bitmap +import android.graphics.BitmapFactory +import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.glide.GlideApp +import code.name.monkey.retromusic.model.Song +import code.name.monkey.retromusic.util.MergedImageUtils.joinImages +import code.name.monkey.retromusic.util.MusicUtil.getMediaStoreAlbumCoverUri +import com.bumptech.glide.load.resource.bitmap.RoundedCorners + +object AutoGeneratedPlaylistBitmap { + fun getBitmap( + context: Context, songPlaylist: List? + ): Bitmap? { + if (songPlaylist == null || songPlaylist.isEmpty()) return getDefaultBitmap(context) + if (songPlaylist.size == 1) return getBitmapWithAlbumId(context, songPlaylist[0].albumId) + val albumID: MutableList = ArrayList() + for (song in songPlaylist) { + if (!albumID.contains(song.albumId)) albumID.add(song.albumId) + } + val art: MutableList = ArrayList() + for (id in albumID) { + val bitmap = getBitmapWithAlbumId(context, id) + if (bitmap != null) art.add(bitmap) + if (art.size == 9) break + } + return joinImages(art) + } + + private fun getBitmapWithAlbumId(context: Context, id: Long): Bitmap? { + return try { + GlideApp.with(context) + .asBitmap() + .transform(RoundedCorners(20)) + .load(getMediaStoreAlbumCoverUri(id)) + .submit(200, 200) + .get() + } catch (e: Exception) { + null + } + } + + private fun getDefaultBitmap(context: Context): Bitmap { + return BitmapFactory.decodeResource(context.resources, R.drawable.default_album_art) + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/BackupUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/BackupUtil.kt index c3f00af0f..e7a6f430a 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/BackupUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/BackupUtil.kt @@ -2,8 +2,8 @@ package code.name.monkey.retromusic.util import android.content.Context import android.content.Intent -import android.widget.Toast import androidx.core.content.FileProvider +import code.name.monkey.retromusic.extensions.showToast import java.io.File object BackupUtil { @@ -19,11 +19,9 @@ object BackupUtil { ).addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION).setType("*/*") } catch (e: IllegalArgumentException) { e.printStackTrace() - Toast.makeText( - context, - "Could not share this file.", - Toast.LENGTH_SHORT - ).show() + context.showToast( + "Could not share this file." + ) Intent() } } diff --git a/app/src/main/java/code/name/monkey/retromusic/util/BitmapEditor.java b/app/src/main/java/code/name/monkey/retromusic/util/BitmapEditor.java deleted file mode 100644 index 8cde4762f..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/util/BitmapEditor.java +++ /dev/null @@ -1,998 +0,0 @@ -package code.name.monkey.retromusic.util; - -import android.app.Activity; -import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.ColorFilter; -import android.graphics.ColorMatrix; -import android.graphics.ColorMatrixColorFilter; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.Path; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; -import android.graphics.PorterDuffXfermode; -import android.graphics.Rect; -import android.graphics.drawable.BitmapDrawable; -import android.graphics.drawable.Drawable; -import android.renderscript.Allocation; -import android.renderscript.Element; -import android.renderscript.RenderScript; -import android.renderscript.ScriptIntrinsicBlur; -import android.view.View; -import android.widget.ImageView; - -/** Created by trung on 7/11/2017. */ -public final class BitmapEditor { - /** - * Stack Blur v1.0 from http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html Java - * Author: Mario Klingemann http://incubator.quasimondo.com - * - *

created Feburary 29, 2004 Android port : Yahel Bouaziz - * http://www.kayenko.com ported april 5th, 2012 - * - *

This is A compromise between Gaussian Blur and Box blur It creates much better looking blurs - * than Box Blur, but is 7x faster than my Gaussian Blur implementation. - * - *

I called it Stack Blur because this describes best how this filter works internally: it - * creates A kind of moving stack of colors whilst scanning through the image. Thereby it just has - * to add one new block of color to the right side of the stack and removeFromParent the leftmost - * color. The remaining colors on the topmost layer of the stack are either added on or reduced by - * one, depending on if they are on the right or on the x side of the stack. - * - *

If you are using this algorithm in your code please add the following line: Stack Blur - * Algorithm by Mario Klingemann - */ - public static Bitmap FastBlurSupportAlpha(Bitmap sentBitmap, float scale, int radius) { - - int width = Math.round(sentBitmap.getWidth() * scale); - int height = Math.round(sentBitmap.getHeight() * scale); - sentBitmap = Bitmap.createScaledBitmap(sentBitmap, width, height, false); - - Bitmap bitmap = sentBitmap.copy(sentBitmap.getConfig(), true); - - if (radius < 1) { - return (null); - } - - int w = bitmap.getWidth(); - int h = bitmap.getHeight(); - - int[] pix = new int[w * h]; - // Log.e("pix", w + " " + h + " " + pix.length); - bitmap.getPixels(pix, 0, w, 0, 0, w, h); - - int wm = w - 1; - int hm = h - 1; - int wh = w * h; - int div = radius + radius + 1; - - int[] r = new int[wh]; - int[] g = new int[wh]; - int[] b = new int[wh]; - int[] a = new int[wh]; - int rsum, gsum, bsum, asum, x, y, i, p, yp, yi, yw; - int[] vmin = new int[Math.max(w, h)]; - - int divsum = (div + 1) >> 1; - divsum *= divsum; - int[] dv = new int[256 * divsum]; - for (i = 0; i < 256 * divsum; i++) { - dv[i] = (i / divsum); - } - - yw = yi = 0; - - int[][] stack = new int[div][4]; - int stackpointer; - int stackstart; - int[] sir; - int rbs; - int r1 = radius + 1; - int routsum, goutsum, boutsum, aoutsum; - int rinsum, ginsum, binsum, ainsum; - - for (y = 0; y < h; y++) { - rinsum = - ginsum = - binsum = - ainsum = routsum = goutsum = boutsum = aoutsum = rsum = gsum = bsum = asum = 0; - for (i = -radius; i <= radius; i++) { - p = pix[yi + Math.min(wm, Math.max(i, 0))]; - sir = stack[i + radius]; - sir[0] = (p & 0xff0000) >> 16; - sir[1] = (p & 0x00ff00) >> 8; - sir[2] = (p & 0x0000ff); - sir[3] = 0xff & (p >> 24); - - rbs = r1 - Math.abs(i); - rsum += sir[0] * rbs; - gsum += sir[1] * rbs; - bsum += sir[2] * rbs; - asum += sir[3] * rbs; - if (i > 0) { - rinsum += sir[0]; - ginsum += sir[1]; - binsum += sir[2]; - ainsum += sir[3]; - } else { - routsum += sir[0]; - goutsum += sir[1]; - boutsum += sir[2]; - aoutsum += sir[3]; - } - } - stackpointer = radius; - - for (x = 0; x < w; x++) { - - r[yi] = dv[rsum]; - g[yi] = dv[gsum]; - b[yi] = dv[bsum]; - a[yi] = dv[asum]; - - rsum -= routsum; - gsum -= goutsum; - bsum -= boutsum; - asum -= aoutsum; - - stackstart = stackpointer - radius + div; - sir = stack[stackstart % div]; - - routsum -= sir[0]; - goutsum -= sir[1]; - boutsum -= sir[2]; - aoutsum -= sir[3]; - - if (y == 0) { - vmin[x] = Math.min(x + radius + 1, wm); - } - p = pix[yw + vmin[x]]; - - sir[0] = (p & 0xff0000) >> 16; - sir[1] = (p & 0x00ff00) >> 8; - sir[2] = (p & 0x0000ff); - sir[3] = 0xff & (p >> 24); - - rinsum += sir[0]; - ginsum += sir[1]; - binsum += sir[2]; - ainsum += sir[3]; - - rsum += rinsum; - gsum += ginsum; - bsum += binsum; - asum += ainsum; - - stackpointer = (stackpointer + 1) % div; - sir = stack[(stackpointer) % div]; - - routsum += sir[0]; - goutsum += sir[1]; - boutsum += sir[2]; - aoutsum += sir[3]; - - rinsum -= sir[0]; - ginsum -= sir[1]; - binsum -= sir[2]; - ainsum -= sir[3]; - - yi++; - } - yw += w; - } - for (x = 0; x < w; x++) { - rinsum = - ginsum = - binsum = - ainsum = routsum = goutsum = boutsum = aoutsum = rsum = gsum = bsum = asum = 0; - yp = -radius * w; - for (i = -radius; i <= radius; i++) { - yi = Math.max(0, yp) + x; - - sir = stack[i + radius]; - - sir[0] = r[yi]; - sir[1] = g[yi]; - sir[2] = b[yi]; - sir[3] = a[yi]; - - rbs = r1 - Math.abs(i); - - rsum += r[yi] * rbs; - gsum += g[yi] * rbs; - bsum += b[yi] * rbs; - asum += a[yi] * rbs; - - if (i > 0) { - rinsum += sir[0]; - ginsum += sir[1]; - binsum += sir[2]; - ainsum += sir[3]; - } else { - routsum += sir[0]; - goutsum += sir[1]; - boutsum += sir[2]; - aoutsum += sir[3]; - } - - if (i < hm) { - yp += w; - } - } - yi = x; - stackpointer = radius; - for (y = 0; y < h; y++) { - pix[yi] = (dv[asum] << 24) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum]; - - rsum -= routsum; - gsum -= goutsum; - bsum -= boutsum; - asum -= aoutsum; - - stackstart = stackpointer - radius + div; - sir = stack[stackstart % div]; - - routsum -= sir[0]; - goutsum -= sir[1]; - boutsum -= sir[2]; - aoutsum -= sir[3]; - - if (x == 0) { - vmin[y] = Math.min(y + r1, hm) * w; - } - p = x + vmin[y]; - - sir[0] = r[p]; - sir[1] = g[p]; - sir[2] = b[p]; - sir[3] = a[p]; - - rinsum += sir[0]; - ginsum += sir[1]; - binsum += sir[2]; - ainsum += sir[3]; - - rsum += rinsum; - gsum += ginsum; - bsum += binsum; - asum += ainsum; - - stackpointer = (stackpointer + 1) % div; - sir = stack[stackpointer]; - - routsum += sir[0]; - goutsum += sir[1]; - boutsum += sir[2]; - aoutsum += sir[3]; - - rinsum -= sir[0]; - ginsum -= sir[1]; - binsum -= sir[2]; - ainsum -= sir[3]; - - yi += w; - } - } - - // Log.e("pix", w + " " + h + " " + pix.length); - bitmap.setPixels(pix, 0, w, 0, 0, w, h); - - return (bitmap); - } - - public static boolean PerceivedBrightness(int will_White, int[] c) { - double TBT = Math.sqrt(c[0] * c[0] * .241 + c[1] * c[1] * .691 + c[2] * c[2] * .068); - // Log.d("themee",TBT+""); - return !(TBT > will_White); - } - - public static int[] getAverageColorRGB(Bitmap bitmap) { - final int width = bitmap.getWidth(); - final int height = bitmap.getHeight(); - int size = width * height; - int pixelColor; - int r, g, b; - r = g = b = 0; - for (int x = 0; x < width; ++x) { - for (int y = 0; y < height; ++y) { - pixelColor = bitmap.getPixel(x, y); - if (pixelColor == 0) { - size--; - continue; - } - r += Color.red(pixelColor); - g += Color.green(pixelColor); - b += Color.blue(pixelColor); - } - } - r /= size; - g /= size; - b /= size; - return new int[] {r, g, b}; - } - - public static Bitmap updateSat(Bitmap src, float settingSat) { - - int w = src.getWidth(); - int h = src.getHeight(); - - Bitmap bitmapResult = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); - Canvas canvasResult = new Canvas(bitmapResult); - Paint paint = new Paint(); - ColorMatrix colorMatrix = new ColorMatrix(); - colorMatrix.setSaturation(settingSat); - ColorMatrixColorFilter filter = new ColorMatrixColorFilter(colorMatrix); - paint.setColorFilter(filter); - canvasResult.drawBitmap(src, 0, 0, paint); - canvasResult.setBitmap(null); - canvasResult = null; - return bitmapResult; - } - - /** - * Stack Blur v1.0 from http://www.quasimondo.com/StackBlurForCanvas/StackBlurDemo.html Java - * Author: Mario Klingemann http://incubator.quasimondo.com - * - *

created Feburary 29, 2004 Android port : Yahel Bouaziz - * http://www.kayenko.com ported april 5th, 2012 - * - *

This is A compromise between Gaussian Blur and Box blur It creates much better looking blurs - * than Box Blur, but is 7x faster than my Gaussian Blur implementation. - * - *

I called it Stack Blur because this describes best how this filter works internally: it - * creates A kind of moving stack of colors whilst scanning through the image. Thereby it just has - * to add one new block of color to the right side of the stack and removeFromParent the leftmost - * color. The remaining colors on the topmost layer of the stack are either added on or reduced by - * one, depending on if they are on the right or on the x side of the stack. - * - *

If you are using this algorithm in your code please add the following line: Stack Blur - * Algorithm by Mario Klingemann - */ - public static Bitmap fastblur(Bitmap sentBitmap, float scale, int radius) { - - Bitmap afterscaleSentBitmap; - Bitmap bitmap; - if (scale != 1) { - int width = Math.round(sentBitmap.getWidth() * scale); // lấy chiều rộng làm tròn - int height = Math.round(sentBitmap.getHeight() * scale); // lấy chiều cao làm tròn - afterscaleSentBitmap = - Bitmap.createScaledBitmap(sentBitmap, width, height, false); // tạo bitmap scaled - bitmap = afterscaleSentBitmap.copy(afterscaleSentBitmap.getConfig(), true); - afterscaleSentBitmap.recycle(); - } else { - bitmap = sentBitmap.copy(sentBitmap.getConfig(), true); // đơn giản chỉ copy - } - - if (radius < 1) { - return (sentBitmap.copy(sentBitmap.getConfig(), true)); - } - - int w = bitmap.getWidth(); // w is the width of sample bitmap - int h = bitmap.getHeight(); // h is the height of sample bitmap - - int[] pix = new int[w * h]; // pix is the arrary of all bitmap pixel - - bitmap.getPixels(pix, 0, w, 0, 0, w, h); - - int wm = w - 1; - int hm = h - 1; - int wh = w * h; - int div = radius + radius + 1; - - int[] r = new int[wh]; - int[] g = new int[wh]; - int[] b = new int[wh]; - int rsum, gsum, bsum, x, y, i, p, yp, yi, yw; - int[] vmin = new int[Math.max(w, h)]; - - int divsum = (div + 1) >> 1; - divsum *= divsum; - int[] dv = new int[256 * divsum]; - for (i = 0; i < 256 * divsum; i++) { - dv[i] = (i / divsum); - } - - yw = yi = 0; - - int[][] stack = new int[div][3]; - int stackpointer; - int stackstart; - int[] sir; - int rbs; - int r1 = radius + 1; - int routsum, goutsum, boutsum; - int rinsum, ginsum, binsum; - - for (y = 0; y < h; y++) { - rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; - for (i = -radius; i <= radius; i++) { - p = pix[yi + Math.min(wm, Math.max(i, 0))]; - sir = stack[i + radius]; - sir[0] = (p & 0xff0000) >> 16; - sir[1] = (p & 0x00ff00) >> 8; - sir[2] = (p & 0x0000ff); - rbs = r1 - Math.abs(i); - rsum += sir[0] * rbs; - gsum += sir[1] * rbs; - bsum += sir[2] * rbs; - if (i > 0) { - rinsum += sir[0]; - ginsum += sir[1]; - binsum += sir[2]; - } else { - routsum += sir[0]; - goutsum += sir[1]; - boutsum += sir[2]; - } - } - stackpointer = radius; - - for (x = 0; x < w; x++) { - - r[yi] = dv[rsum]; - g[yi] = dv[gsum]; - b[yi] = dv[bsum]; - - rsum -= routsum; - gsum -= goutsum; - bsum -= boutsum; - - stackstart = stackpointer - radius + div; - sir = stack[stackstart % div]; - - routsum -= sir[0]; - goutsum -= sir[1]; - boutsum -= sir[2]; - - if (y == 0) { - vmin[x] = Math.min(x + radius + 1, wm); - } - p = pix[yw + vmin[x]]; - - sir[0] = (p & 0xff0000) >> 16; - sir[1] = (p & 0x00ff00) >> 8; - sir[2] = (p & 0x0000ff); - - rinsum += sir[0]; - ginsum += sir[1]; - binsum += sir[2]; - - rsum += rinsum; - gsum += ginsum; - bsum += binsum; - - stackpointer = (stackpointer + 1) % div; - sir = stack[(stackpointer) % div]; - - routsum += sir[0]; - goutsum += sir[1]; - boutsum += sir[2]; - - rinsum -= sir[0]; - ginsum -= sir[1]; - binsum -= sir[2]; - - yi++; - } - yw += w; - } - for (x = 0; x < w; x++) { - rinsum = ginsum = binsum = routsum = goutsum = boutsum = rsum = gsum = bsum = 0; - yp = -radius * w; - for (i = -radius; i <= radius; i++) { - yi = Math.max(0, yp) + x; - - sir = stack[i + radius]; - - sir[0] = r[yi]; - sir[1] = g[yi]; - sir[2] = b[yi]; - - rbs = r1 - Math.abs(i); - - rsum += r[yi] * rbs; - gsum += g[yi] * rbs; - bsum += b[yi] * rbs; - - if (i > 0) { - rinsum += sir[0]; - ginsum += sir[1]; - binsum += sir[2]; - } else { - routsum += sir[0]; - goutsum += sir[1]; - boutsum += sir[2]; - } - - if (i < hm) { - yp += w; - } - } - yi = x; - stackpointer = radius; - for (y = 0; y < h; y++) { - // Preserve alpha channel: ( 0xff000000 & pix[yi] ) - pix[yi] = (0xff000000 & pix[yi]) | (dv[rsum] << 16) | (dv[gsum] << 8) | dv[bsum]; - - rsum -= routsum; - gsum -= goutsum; - bsum -= boutsum; - - stackstart = stackpointer - radius + div; - sir = stack[stackstart % div]; - - routsum -= sir[0]; - goutsum -= sir[1]; - boutsum -= sir[2]; - - if (x == 0) { - vmin[y] = Math.min(y + r1, hm) * w; - } - p = x + vmin[y]; - - sir[0] = r[p]; - sir[1] = g[p]; - sir[2] = b[p]; - - rinsum += sir[0]; - ginsum += sir[1]; - binsum += sir[2]; - - rsum += rinsum; - gsum += ginsum; - bsum += binsum; - - stackpointer = (stackpointer + 1) % div; - sir = stack[stackpointer]; - - routsum += sir[0]; - goutsum += sir[1]; - boutsum += sir[2]; - - rinsum -= sir[0]; - ginsum -= sir[1]; - binsum -= sir[2]; - - yi += w; - } - } - - bitmap.setPixels(pix, 0, w, 0, 0, w, h); - - return (bitmap); - } - - public static Bitmap getRoundedCornerBitmap(Bitmap bitmap, int pixels) { - Bitmap output = - Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(output); - - final int color = 0xff424242; - final Paint paint = new Paint(); - final Rect rect = new Rect(0, 0, bitmap.getWidth(), bitmap.getHeight()); - // final ScreenSize rectF = new ScreenSize(rect); - final float roundPx = pixels; - - paint.setAntiAlias(true); - canvas.drawARGB(0, 0, 0, 0); - paint.setColor(color); - // canvas.drawRoundRect(rectF, roundPx, roundPx, paint); - canvas.drawPath( - BitmapEditor.RoundedRect( - 0, 0, bitmap.getWidth(), bitmap.getHeight(), roundPx, roundPx, false), - paint); - paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_IN)); - canvas.drawBitmap(bitmap, rect, rect, paint); - - return output; - } - - /** - * getResizedBitmap method is used to Resized the Image according to custom width and height - * - * @param image image to be resized - * @param newHeight (new desired height) - * @param newWidth (new desired Width) - * @return image (new resized image) - */ - public static Bitmap getResizedBitmap(Bitmap image, int newHeight, int newWidth) { - int width = image.getWidth(); - int height = image.getHeight(); - float scaleWidth = ((float) newWidth) / width; - float scaleHeight = ((float) newHeight) / height; - // create A matrix for the manipulation - Matrix matrix = new Matrix(); - // onTap the bit map - matrix.postScale(scaleWidth, scaleHeight); - // recreate the new Bitmap - return Bitmap.createBitmap(image, 0, 0, width, height, matrix, false); - } - - public static boolean TrueIfBitmapBigger(Bitmap bitmap, int size) { - int sizeBitmap = - Math.max(bitmap.getHeight(), bitmap.getWidth()); - return sizeBitmap > size; - } - - public static Bitmap getRoundedBitmapWithBlurShadow( - Bitmap original, int paddingTop, int paddingBottom, int paddingLeft, int paddingRight) { - int original_width = original.getWidth(); - int original_height = original.getHeight(); - int bitmap_width = original_width + paddingLeft + paddingRight; - int bitmap_height = original_height + paddingTop + paddingBottom; - Bitmap bitmap = Bitmap.createBitmap(bitmap_width, bitmap_height, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - Paint paint = new Paint(); - paint.setStyle(Paint.Style.FILL); - // paint.setAlpha(60); - // canvas.drawRect(0,0,bitmap_width,bitmap_height,paint); - paint.setAntiAlias(true); - canvas.drawBitmap(original, paddingLeft, paddingTop, paint); - Bitmap blurred_bitmap = getBlurredWithGoodPerformance(bitmap, 1, 6, 4); - canvas.setBitmap(null); - bitmap.recycle(); - return blurred_bitmap; - } - - // Activity. - // | - // Original bitmap. - // | - // | To make the blur background, the original must to padding. - // | - // | | | | - // | - // V - // V V V V - // V - public static Bitmap GetRoundedBitmapWithBlurShadow( - Context context, - Bitmap original, - int paddingTop, - int paddingBottom, - int paddingLeft, - int paddingRight, - int TopBack // this value makes the overview bitmap is higher or belower the background. - , - int alphaBlurBackground // this is the alpha of the background Bitmap, you need A number - // between 0 -> 255, the value recommend is 180. - , - int valueBlurBackground // this is the value used to blur the background Bitmap, the - // recommended one is 12. - , - int valueSaturationBlurBackground // this is the value used to background Bitmap more - // colorful, if valueBlur is 12, the valudeSaturation should - // be 2. - ) { - int original_width = original.getWidth(); - int orginal_height = original.getHeight(); - int bitmap_width = original_width + paddingLeft + paddingRight; - int bitmap_height = orginal_height + paddingTop + paddingBottom; - Bitmap bitmap = Bitmap.createBitmap(bitmap_width, bitmap_height, Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - Paint paint = new Paint(); - paint.setStyle(Paint.Style.FILL); - paint.setAntiAlias(true); - canvas.drawBitmap(original, paddingLeft, paddingTop, paint); - Bitmap blurred_bitmap = - getBlurredWithGoodPerformance( - context, bitmap, 1, valueBlurBackground, valueSaturationBlurBackground); - // Bitmap blurred_bitmap= getBlurredWithGoodPerformance(context, bitmap,1,15,3); - Bitmap end_bitmap = Bitmap.createBitmap(bitmap_width, bitmap_height, Bitmap.Config.ARGB_8888); - canvas.setBitmap(end_bitmap); - paint.setAlpha(alphaBlurBackground); - - canvas.drawBitmap( - blurred_bitmap, - new Rect(0, 0, blurred_bitmap.getWidth(), blurred_bitmap.getHeight()), - new Rect(0, 0, bitmap_width, bitmap_height), - paint); - paint.setAlpha(255); - - canvas.drawBitmap(bitmap, 0, TopBack, paint); // drawVisualWave cái lớn - canvas.setBitmap(null); - blurred_bitmap.recycle(); - bitmap.recycle(); - return end_bitmap; - } - - public static void setBitmapforImageView(ImageView imv, Bitmap apply) { - Bitmap old = ((BitmapDrawable) imv.getDrawable()).getBitmap(); - imv.setImageBitmap(apply); - if (old != null) old.recycle(); - } - - public static Bitmap getBlurredWithGoodPerformance( - Bitmap bitmap, int scale, int radius, int saturation) { - BitmapFactory.Options options = new BitmapFactory.Options(); - Bitmap bitmap1 = getResizedBitmap(bitmap, 50, 50); - Bitmap updateSatBitmap = updateSat(bitmap1, saturation); - Bitmap blurredBitmap = FastBlurSupportAlpha(updateSatBitmap, scale, radius); - - updateSatBitmap.recycle(); - bitmap1.recycle(); - return blurredBitmap; - } - - public static Path RoundedRect( - float left, - float top, - float right, - float bottom, - float rx, - float ry, - boolean conformToOriginalPost) { - Path path = new Path(); - if (rx < 0) rx = 0; - if (ry < 0) ry = 0; - float width = right - left; - float height = bottom - top; - if (rx > width / 2) rx = width / 2; - if (ry > height / 2) ry = height / 2; - float widthMinusCorners = (width - (2 * rx)); // do dai phan "thang" cua chieu rong - float heightMinusCorners = (height - (2 * ry)); // do dai phan "thang" cua chieu dai - - path.moveTo(right, top + ry); // bat dau tu day - path.rQuadTo(0, -ry, -rx, -ry); // y-right corner - path.rLineTo(-widthMinusCorners, 0); - path.rQuadTo(-rx, 0, -rx, ry); // y-x corner - path.rLineTo(0, heightMinusCorners); - - if (conformToOriginalPost) { - path.rLineTo(0, ry); - path.rLineTo(width, 0); - path.rLineTo(0, -ry); - } else { - - path.rQuadTo(0, ry, rx, ry); // bottom-x corner - path.rLineTo(widthMinusCorners, 0); - path.rQuadTo(rx, 0, rx, -ry); // bottom-right corner - } - - path.rLineTo(0, -heightMinusCorners); - - path.close(); // Given close, last lineto can be removed. - - return path; - } - - public static int mixTwoColors(int color1, int color2, float amount) { - final byte ALPHA_CHANNEL = 24; - final byte RED_CHANNEL = 16; - final byte GREEN_CHANNEL = 8; - final byte BLUE_CHANNEL = 0; - - final float inverseAmount = 1.0f - amount; - - int a = - ((int) - (((float) (color1 >> ALPHA_CHANNEL & 0xff) * amount) - + ((float) (color2 >> ALPHA_CHANNEL & 0xff) * inverseAmount))) - & 0xff; - int r = - ((int) - (((float) (color1 >> RED_CHANNEL & 0xff) * amount) - + ((float) (color2 >> RED_CHANNEL & 0xff) * inverseAmount))) - & 0xff; - int g = - ((int) - (((float) (color1 >> GREEN_CHANNEL & 0xff) * amount) - + ((float) (color2 >> GREEN_CHANNEL & 0xff) * inverseAmount))) - & 0xff; - int b = - ((int) (((float) (color1 & 0xff) * amount) + ((float) (color2 & 0xff) * inverseAmount))) - & 0xff; - - return a << ALPHA_CHANNEL | r << RED_CHANNEL | g << GREEN_CHANNEL | b << BLUE_CHANNEL; - } - - public static Bitmap getBlurredWithGoodPerformance( - Context context, Bitmap bitmap, int scale, int radius, float saturation) { - Bitmap bitmap1 = getResizedBitmap(bitmap, 150, 150); - Bitmap updateSatBimap = updateSat(bitmap1, saturation); - Bitmap blurredBitmap = BlurBitmapWithRenderScript(context, updateSatBimap, radius); - updateSatBimap.recycle(); - bitmap1.recycle(); - return blurredBitmap; - } - - public static Bitmap getBlurredBimapWithRenderScript( - Context context, Bitmap bitmapOriginal, float radius) { - // define this only once if blurring multiple times - RenderScript rs = RenderScript.create(context); - - // this will blur the bitmapOriginal with A radius of 8 and save it in bitmapOriginal - final Allocation input = - Allocation.createFromBitmap( - rs, bitmapOriginal); // use this constructor for best performance, because it uses - // USAGE_SHARED mode which reuses memory - final Allocation output = Allocation.createTyped(rs, input.getType()); - final ScriptIntrinsicBlur script = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); - script.setRadius(radius); - script.setInput(input); - script.forEach(output); - output.copyTo(bitmapOriginal); - return bitmapOriginal; - } - - public static Bitmap BlurBitmapWithRenderScript(Context context, Bitmap bitmap, float radius) { - // Let's create an empty bitmap with the same size of the bitmap we want to blur - Bitmap outBitmap = - Bitmap.createBitmap(bitmap.getWidth(), bitmap.getHeight(), Bitmap.Config.ARGB_8888); - - // Instantiate A new Renderscript - RenderScript rs = RenderScript.create(context); - - // Create an Intrinsic Blur Script using the Renderscript - ScriptIntrinsicBlur blurScript = ScriptIntrinsicBlur.create(rs, Element.U8_4(rs)); - - // Create the Allocations (in/out) with the Renderscript and the in/out bitmaps - Allocation allIn = Allocation.createFromBitmap(rs, bitmap); - Allocation allOut = Allocation.createFromBitmap(rs, outBitmap); - // Set the radius of the blur - blurScript.setRadius(radius); - - // Perform the Renderscript - blurScript.setInput(allIn); - blurScript.forEach(allOut); - - // Copy the final bitmap created by the out Allocation to the outBitmap - allOut.copyTo(outBitmap); - - // recycle the original bitmap - - // After finishing everything, we destroy the Renderscript. - rs.destroy(); - - return outBitmap; - } - - public static Drawable covertBitmapToDrawable(Context context, Bitmap bitmap) { - Drawable d = new BitmapDrawable(context.getResources(), bitmap); - return d; - } - - public static Bitmap convertDrawableToBitmap(Drawable drawable) { - if (drawable instanceof BitmapDrawable) { - return ((BitmapDrawable) drawable).getBitmap(); - } - Bitmap bitmap = - Bitmap.createBitmap( - drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888); - Canvas canvas = new Canvas(bitmap); - drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight()); - drawable.draw(canvas); - return bitmap; - } - - public static Bitmap changeBitmapColor(Bitmap sourceBitmap, int color) { - Bitmap resultBitmap = sourceBitmap.copy(sourceBitmap.getConfig(), true); - Paint paint = new Paint(); - ColorFilter filter = new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_IN); - paint.setColorFilter(filter); - Canvas canvas = new Canvas(resultBitmap); - canvas.drawBitmap(resultBitmap, 0, 0, paint); - return resultBitmap; - } - - /** - * @param mode - * @return 0 : CLEAR
- * 1 : SRC
- * 2 : DST
- * 3 : SRC_OVER
- * 4 : DST_OVER
- * 5 : SRC_IN
- * 6 : DST_IN
- * 7 : SRC_OUT
- * 8 : DST_OUT
- * 9 : SRC_ATOP
- * 10 : DST_ATOP
- * 11 : XOR
- * 12 : ADD
- * 13 : MULTIPLY
- * 14 : SCREEN
- * 15 : OVERLAY
- * 16 : DARKEN
- * 17 : LIGHTEN - */ - public static PorterDuff.Mode getPorterMode(int mode) { - switch (mode) { - default: - case 0: - return PorterDuff.Mode.CLEAR; - case 1: - return PorterDuff.Mode.SRC; - case 2: - return PorterDuff.Mode.DST; - case 3: - return PorterDuff.Mode.SRC_OVER; - case 4: - return PorterDuff.Mode.DST_OVER; - case 5: - return PorterDuff.Mode.SRC_IN; - case 6: - return PorterDuff.Mode.DST_IN; - case 7: - return PorterDuff.Mode.SRC_OUT; - case 8: - return PorterDuff.Mode.DST_OUT; - case 9: - return PorterDuff.Mode.SRC_ATOP; - case 10: - return PorterDuff.Mode.DST_ATOP; - case 11: - return PorterDuff.Mode.XOR; - case 16: - return PorterDuff.Mode.DARKEN; - case 17: - return PorterDuff.Mode.LIGHTEN; - case 13: - return PorterDuff.Mode.MULTIPLY; - case 14: - return PorterDuff.Mode.SCREEN; - case 12: - return PorterDuff.Mode.ADD; - case 15: - return PorterDuff.Mode.OVERLAY; - } - } - - public static void applyNewColor4Bitmap( - Context context, int[] idBitmaps, ImageView[] imageViews, int color, float alpha) { - android.content.res.Resources resource = context.getResources(); - int size = idBitmaps.length; - Bitmap usingBitmap, resultBitmap; - for (int i = 0; i < size; i++) { - usingBitmap = BitmapFactory.decodeResource(resource, idBitmaps[i]); - resultBitmap = changeBitmapColor(usingBitmap, color); - imageViews[i].setImageBitmap(resultBitmap); - imageViews[i].setAlpha(alpha); - } - } - - public static void applyNewColor4Bitmap( - Context context, int idBitmap, ImageView applyView, int color, float alpha) { - - android.content.res.Resources resource = context.getResources(); - Bitmap usingBitmap = BitmapFactory.decodeResource(resource, idBitmap); - Bitmap resultBitmap = changeBitmapColor(usingBitmap, color); - applyView.setImageBitmap(resultBitmap); - applyView.setAlpha(alpha); - } - - public static Bitmap getBitmapFromView(View view) { - Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(bitmap); - view.layout(view.getLeft(), view.getTop(), view.getRight(), view.getBottom()); - view.draw(c); - return bitmap; - } - - public static Bitmap getBitmapFromView(View view, int left, int top, int right, int bottom) { - Bitmap bitmap = Bitmap.createBitmap(view.getWidth(), view.getHeight(), Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(bitmap); - view.layout(left, top, right, bottom); - view.draw(c); - return bitmap; - } - - public static Bitmap getBackgroundBitmapAViewWithParent(View childView, View parentView) { - int[] pos_child = new int[2]; - childView.getLocationOnScreen(pos_child); - return getBitmapFromView( - parentView, pos_child[0], pos_child[1], parentView.getRight(), parentView.getBottom()); - } - - public static Bitmap getBackgroundBlurAViewWithParent( - Activity activity, View childView, View parentView) { - Bitmap b1 = getBackgroundBitmapAViewWithParent(childView, parentView); - Bitmap b2 = getBlurredWithGoodPerformance(activity, b1, 1, 8, 2); - b1.recycle(); - return b2; - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/CalendarUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/CalendarUtil.java deleted file mode 100644 index 28a75cc14..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/util/CalendarUtil.java +++ /dev/null @@ -1,140 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.util; - -import java.util.Calendar; -import java.util.GregorianCalendar; - -/** @author Eugene Cheung (arkon) */ -public class CalendarUtil { - private static final long MS_PER_MINUTE = 60 * 1000; - private static final long MS_PER_DAY = 24 * 60 * MS_PER_MINUTE; - - private final Calendar calendar; - - public CalendarUtil() { - this.calendar = Calendar.getInstance(); - } - - /** - * Returns the time elapsed so far today in milliseconds. - * - * @return Time elapsed today in milliseconds. - */ - public long getElapsedToday() { - // Time elapsed so far today - return (calendar.get(Calendar.HOUR_OF_DAY) * 60 + calendar.get(Calendar.MINUTE)) * MS_PER_MINUTE - + calendar.get(Calendar.SECOND) * 1000 - + calendar.get(Calendar.MILLISECOND); - } - - /** - * Returns the time elapsed so far this week in milliseconds. - * - * @return Time elapsed this week in milliseconds. - */ - public long getElapsedWeek() { - // Today + days passed this week - long elapsed = getElapsedToday(); - - final int passedWeekdays = - calendar.get(Calendar.DAY_OF_WEEK) - 1 - calendar.getFirstDayOfWeek(); - if (passedWeekdays > 0) { - elapsed += passedWeekdays * MS_PER_DAY; - } - - return elapsed; - } - - /** - * Returns the time elapsed so far this month in milliseconds. - * - * @return Time elapsed this month in milliseconds. - */ - public long getElapsedMonth() { - // Today + rest of this month - return getElapsedToday() + ((calendar.get(Calendar.DAY_OF_MONTH) - 1) * MS_PER_DAY); - } - - /** - * Returns the time elapsed so far this month and the last numMonths months in milliseconds. - * - * @param numMonths Additional number of months prior to the current month to calculate. - * @return Time elapsed this month and the last numMonths months in milliseconds. - */ - public long getElapsedMonths(int numMonths) { - // Today + rest of this month - long elapsed = getElapsedMonth(); - - // Previous numMonths months - int month = calendar.get(Calendar.MONTH); - int year = calendar.get(Calendar.YEAR); - for (int i = 0; i < numMonths; i++) { - month--; - - if (month < Calendar.JANUARY) { - month = Calendar.DECEMBER; - year--; - } - - elapsed += getDaysInMonth(month) * MS_PER_DAY; - } - - return elapsed; - } - - /** - * Returns the time elapsed so far this year in milliseconds. - * - * @return Time elapsed this year in milliseconds. - */ - public long getElapsedYear() { - // Today + rest of this month + previous months until January - long elapsed = getElapsedMonth(); - - int month = calendar.get(Calendar.MONTH) - 1; - int year = calendar.get(Calendar.YEAR); - while (month > Calendar.JANUARY) { - elapsed += getDaysInMonth(month) * MS_PER_DAY; - - month--; - } - - return elapsed; - } - - /** - * Gets the number of days for the given month in the given year. - * - * @param month The month (1 - 12). - * @return The days in that month/year. - */ - private int getDaysInMonth(int month) { - final Calendar monthCal = new GregorianCalendar(calendar.get(Calendar.YEAR), month, 1); - return monthCal.getActualMaximum(Calendar.DAY_OF_MONTH); - } - - /** - * Returns the time elapsed so far last N days in milliseconds. - * - * @return Time elapsed since N days in milliseconds. - */ - public long getElapsedDays(int numDays) { - long elapsed = getElapsedToday(); - elapsed += numDays * MS_PER_DAY; - - return elapsed; - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/CalendarUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/CalendarUtil.kt new file mode 100644 index 000000000..777b63842 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/CalendarUtil.kt @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2019 Hemanth Savarala. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + */ +package code.name.monkey.retromusic.util + +import java.util.* + +/** @author Eugene Cheung (arkon) + */ +class CalendarUtil { + private val calendar = Calendar.getInstance()// Time elapsed so far today + + /** + * Returns the time elapsed so far today in milliseconds. + * + * @return Time elapsed today in milliseconds. + */ + val elapsedToday: Long + get() =// Time elapsed so far today + (calendar[Calendar.HOUR_OF_DAY] * 60 + calendar[Calendar.MINUTE]) * MS_PER_MINUTE + calendar[Calendar.SECOND] * 1000 + calendar[Calendar.MILLISECOND]// Today + days passed this week + + /** + * Returns the time elapsed so far this week in milliseconds. + * + * @return Time elapsed this week in milliseconds. + */ + val elapsedWeek: Long + get() { + // Today + days passed this week + var elapsed = elapsedToday + val passedWeekdays = calendar[Calendar.DAY_OF_WEEK] - 1 - calendar.firstDayOfWeek + if (passedWeekdays > 0) { + elapsed += passedWeekdays * MS_PER_DAY + } + return elapsed + }// Today + rest of this month + + /** + * Returns the time elapsed so far this month in milliseconds. + * + * @return Time elapsed this month in milliseconds. + */ + val elapsedMonth: Long + get() =// Today + rest of this month + elapsedToday + (calendar[Calendar.DAY_OF_MONTH] - 1) * MS_PER_DAY + + /** + * Returns the time elapsed so far this month and the last numMonths months in milliseconds. + * + * @param numMonths Additional number of months prior to the current month to calculate. + * @return Time elapsed this month and the last numMonths months in milliseconds. + */ + fun getElapsedMonths(numMonths: Int): Long { + // Today + rest of this month + var elapsed = elapsedMonth + + // Previous numMonths months + var month = calendar[Calendar.MONTH] + var year = calendar[Calendar.YEAR] + for (i in 0 until numMonths) { + month-- + if (month < Calendar.JANUARY) { + month = Calendar.DECEMBER + year-- + } + elapsed += getDaysInMonth(month) * MS_PER_DAY + } + return elapsed + }// Today + rest of this month + previous months until January + + /** + * Returns the time elapsed so far this year in milliseconds. + * + * @return Time elapsed this year in milliseconds. + */ + val elapsedYear: Long + get() { + // Today + rest of this month + previous months until January + var elapsed = elapsedMonth + var month = calendar[Calendar.MONTH] - 1 + while (month > Calendar.JANUARY) { + elapsed += getDaysInMonth(month) * MS_PER_DAY + month-- + } + return elapsed + } + + /** + * Gets the number of days for the given month in the given year. + * + * @param month The month (1 - 12). + * @return The days in that month/year. + */ + private fun getDaysInMonth(month: Int): Int { + val monthCal: Calendar = GregorianCalendar(calendar[Calendar.YEAR], month, 1) + return monthCal.getActualMaximum(Calendar.DAY_OF_MONTH) + } + + /** + * Returns the time elapsed so far last N days in milliseconds. + * + * @return Time elapsed since N days in milliseconds. + */ + fun getElapsedDays(numDays: Int): Long { + var elapsed = elapsedToday + elapsed += numDays * MS_PER_DAY + return elapsed + } + + companion object { + private const val MS_PER_MINUTE = (60 * 1000).toLong() + private const val MS_PER_DAY = 24 * 60 * MS_PER_MINUTE + } + +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/ColorAnimUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/ColorAnimUtil.kt deleted file mode 100644 index 81cb66de6..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/util/ColorAnimUtil.kt +++ /dev/null @@ -1,19 +0,0 @@ -package code.name.monkey.retromusic.util - -import android.animation.ArgbEvaluator -import android.animation.ValueAnimator - -class ColorAnimUtil { - companion object { - fun createColorAnimator( - fromColor: Int, - toColor: Int, - mDuration: Long = 300 - ): ValueAnimator { - return ValueAnimator.ofInt(fromColor, toColor).apply { - setEvaluator(ArgbEvaluator()) - duration = mDuration - } - } - } -} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/Compressor.java b/app/src/main/java/code/name/monkey/retromusic/util/Compressor.java deleted file mode 100644 index 6259a52bf..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/util/Compressor.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.util; - -import android.content.Context; -import android.graphics.Bitmap; - -import java.io.File; -import java.io.IOException; - -/** - * Created on : June 18, 2016 Author : zetbaitsu Name : Zetra GitHub : https://github.com/zetbaitsu - */ -public class Compressor { - // max width and height values of the compressed image is taken as 612x816 - private int maxWidth = 612; - private int maxHeight = 816; - private Bitmap.CompressFormat compressFormat = Bitmap.CompressFormat.JPEG; - private int quality = 80; - private String destinationDirectoryPath; - - public Compressor(Context context) { - destinationDirectoryPath = context.getCacheDir().getPath() + File.separator + "images"; - } - - public Compressor setMaxWidth(int maxWidth) { - this.maxWidth = maxWidth; - return this; - } - - public Compressor setMaxHeight(int maxHeight) { - this.maxHeight = maxHeight; - return this; - } - - public Compressor setCompressFormat(Bitmap.CompressFormat compressFormat) { - this.compressFormat = compressFormat; - return this; - } - - public Compressor setQuality(int quality) { - this.quality = quality; - return this; - } - - public Compressor setDestinationDirectoryPath(String destinationDirectoryPath) { - this.destinationDirectoryPath = destinationDirectoryPath; - return this; - } - - public File compressToFile(File imageFile) throws IOException { - return compressToFile(imageFile, imageFile.getName()); - } - - public File compressToFile(File imageFile, String compressedFileName) throws IOException { - return ImageUtil.compressImage( - imageFile, - maxWidth, - maxHeight, - compressFormat, - quality, - destinationDirectoryPath + File.separator + compressedFileName); - } - - public Bitmap compressToBitmap(File imageFile) throws IOException { - return ImageUtil.decodeSampledBitmapFromFile(imageFile, maxWidth, maxHeight); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/CustomArtistImageUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/CustomArtistImageUtil.kt index 4836032a1..39994818f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/CustomArtistImageUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/CustomArtistImageUtil.kt @@ -14,25 +14,21 @@ package code.name.monkey.retromusic.util -import android.annotation.SuppressLint import android.content.Context import android.content.SharedPreferences import android.graphics.Bitmap -import android.graphics.drawable.Drawable import android.net.Uri -import android.os.AsyncTask import android.provider.MediaStore import android.widget.Toast import androidx.core.content.edit import code.name.monkey.retromusic.App +import code.name.monkey.retromusic.extensions.showToast +import code.name.monkey.retromusic.glide.GlideApp import code.name.monkey.retromusic.model.Artist -import com.bumptech.glide.Glide import com.bumptech.glide.load.engine.DiskCacheStrategy -import com.bumptech.glide.request.target.SimpleTarget -import com.bumptech.glide.request.transition.Transition -import java.io.BufferedOutputStream +import kotlinx.coroutines.Dispatchers.IO +import kotlinx.coroutines.withContext import java.io.File -import java.io.FileOutputStream import java.io.IOException import java.util.* @@ -44,78 +40,71 @@ class CustomArtistImageUtil private constructor(context: Context) { Context.MODE_PRIVATE ) - fun setCustomArtistImage(artist: Artist, uri: Uri) { - Glide.with(App.getContext()) - .asBitmap() - .load(uri) - .diskCacheStrategy(DiskCacheStrategy.NONE) - .skipMemoryCache(true) - .into(object : SimpleTarget() { - override fun onLoadFailed(errorDrawable: Drawable?) { - super.onLoadFailed(errorDrawable) - Toast.makeText(App.getContext(), "Load Failed", Toast.LENGTH_LONG).show() + suspend fun setCustomArtistImage(artist: Artist, uri: Uri) { + val context = App.getContext() + withContext(IO) { + runCatching { + GlideApp.with(context) + .asBitmap() + .load(uri) + .diskCacheStrategy(DiskCacheStrategy.NONE) + .skipMemoryCache(true) + .submit() + .get() + } + .onSuccess { + saveImage(context, artist, it) } - - @SuppressLint("StaticFieldLeak") - override fun onResourceReady(resource: Bitmap, transition: Transition?) { - object : AsyncTask() { - override fun doInBackground(vararg params: Void): Void? { - val dir = File(App.getContext().filesDir, FOLDER_NAME) - if (!dir.exists()) { - if (!dir.mkdirs()) { // create the folder - return null - } - } - val file = File(dir, getFileName(artist)) - - var succesful = false - try { - val os = BufferedOutputStream(FileOutputStream(file)) - succesful = ImageUtil.resizeBitmap(resource, 2048) - .compress(Bitmap.CompressFormat.JPEG, 100, os) - os.close() - } catch (e: IOException) { - Toast.makeText(App.getContext(), e.toString(), Toast.LENGTH_LONG) - .show() - } - - if (succesful) { - mPreferences.edit { putBoolean(getFileName(artist), true) } - ArtistSignatureUtil.getInstance(App.getContext()) - .updateArtistSignature(artist.name) - App.getContext().contentResolver.notifyChange( - MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, - null - ) // trigger media store changed to force artist image reload - } - return null - } - }.execute() + .onFailure { + context.showToast("Load Failed") } - }) + } } - @SuppressLint("StaticFieldLeak") - fun resetCustomArtistImage(artist: Artist) { - object : AsyncTask() { - @SuppressLint("ApplySharedPref") - override fun doInBackground(vararg params: Void): Void? { - mPreferences.edit(commit = true) { putBoolean(getFileName(artist), false) } - ArtistSignatureUtil.getInstance(App.getContext()).updateArtistSignature(artist.name) - App.getContext().contentResolver.notifyChange( - MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, - null - ) // trigger media store changed to force artist image reload - - val file = getFile(artist) - if (!file.exists()) { - return null - } else { - file.delete() - } - return null + private fun saveImage(context: Context, artist: Artist, bitmap: Bitmap) { + val dir = File(context.filesDir, FOLDER_NAME) + if (!dir.exists()) { + if (!dir.mkdirs()) { // create the folder + return } - }.execute() + } + val file = File(dir, getFileName(artist)) + + var successful = false + try { + file.outputStream().buffered().use { bos -> + successful = ImageUtil.resizeBitmap(bitmap, 2048) + .compress(Bitmap.CompressFormat.JPEG, 100, bos) + } + } catch (e: IOException) { + context.showToast(e.toString(), Toast.LENGTH_LONG) + } + + if (successful) { + mPreferences.edit { putBoolean(getFileName(artist), true) } + ArtistSignatureUtil.getInstance(context) + .updateArtistSignature(artist.name) + context.contentResolver.notifyChange( + MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, + null + ) // trigger media store changed to force artist image reload + } + } + + suspend fun resetCustomArtistImage(artist: Artist) { + withContext(IO) { + mPreferences.edit { putBoolean(getFileName(artist), false) } + ArtistSignatureUtil.getInstance(App.getContext()).updateArtistSignature(artist.name) + App.getContext().contentResolver.notifyChange( + MediaStore.Audio.Artists.EXTERNAL_CONTENT_URI, + null + ) // trigger media store changed to force artist image reload + + val file = getFile(artist) + if (file.exists()) { + file.delete() + } + } } // shared prefs saves us many IO operations diff --git a/app/src/main/java/code/name/monkey/retromusic/util/FilePathUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/FilePathUtil.kt index da30e71c9..b0abc8af5 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/FilePathUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/FilePathUtil.kt @@ -1,14 +1,13 @@ package code.name.monkey.retromusic.util import android.os.Environment -import java.io.File object FilePathUtil { fun blacklistFilePaths(): List { - return listOf( - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS), - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_RINGTONES), - Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_NOTIFICATIONS) + return listOf( + getExternalStoragePublicDirectory(Environment.DIRECTORY_ALARMS), + getExternalStoragePublicDirectory(Environment.DIRECTORY_RINGTONES), + getExternalStoragePublicDirectory(Environment.DIRECTORY_NOTIFICATIONS) ).map { FileUtil.safeGetCanonicalPath(it) } diff --git a/app/src/main/java/code/name/monkey/retromusic/util/FileUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/FileUtil.java index 09957a93c..903df0aab 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/FileUtil.java +++ b/app/src/main/java/code/name/monkey/retromusic/util/FileUtil.java @@ -14,10 +14,11 @@ package code.name.monkey.retromusic.util; +import static code.name.monkey.retromusic.util.FileUtilsKt.getExternalStorageDirectory; + import android.content.Context; import android.database.Cursor; import android.os.Environment; -import android.provider.MediaStore; import android.webkit.MimeTypeMap; import androidx.annotation.NonNull; @@ -40,6 +41,7 @@ import java.util.LinkedList; import java.util.List; import java.util.StringTokenizer; +import code.name.monkey.retromusic.Constants; import code.name.monkey.retromusic.adapter.Storage; import code.name.monkey.retromusic.model.Song; import code.name.monkey.retromusic.repository.RealSongRepository; @@ -87,7 +89,7 @@ public final class FileUtil { if (files.size() > 0 && files.size() < 999) { // 999 is the max amount Androids SQL implementation can handle. selection = - MediaStore.Audio.AudioColumns.DATA + " IN (" + makePlaceholders(files.size()) + ")"; + Constants.DATA + " IN (" + makePlaceholders(files.size()) + ")"; } } @@ -96,7 +98,7 @@ public final class FileUtil { return songCursor == null ? null - : new SortedCursor(songCursor, paths, MediaStore.Audio.AudioColumns.DATA); + : new SortedCursor(songCursor, paths, Constants.DATA); } private static String makePlaceholders(int len) { @@ -113,12 +115,6 @@ public final class FileUtil { if (files != null) { String[] paths = new String[files.size()]; for (int i = 0; i < files.size(); i++) { - /*try { - paths[i] = files.get(i).getCanonicalPath(); // canonical path is important here because we want to compare the path with the media store entry later - } catch (IOException e) { - e.printStackTrace(); - paths[i] = files.get(i).getPath(); - }*/ paths[i] = safeGetCanonicalPath(files.get(i)); } return paths; @@ -268,7 +264,7 @@ public final class FileUtil { public static ArrayList listRoots() { ArrayList storageItems = new ArrayList<>(); HashSet paths = new HashSet<>(); - String defaultPath = Environment.getExternalStorageDirectory().getPath(); + String defaultPath = getExternalStorageDirectory().getPath(); String defaultPathState = Environment.getExternalStorageState(); if (defaultPathState.equals(Environment.MEDIA_MOUNTED) || defaultPathState.equals(Environment.MEDIA_MOUNTED_READ_ONLY)) { Storage ext = new Storage(); @@ -277,7 +273,7 @@ public final class FileUtil { } else { ext.title = "Internal Storage"; } - ext.file = Environment.getExternalStorageDirectory(); + ext.file = getExternalStorageDirectory(); storageItems.add(ext); paths.add(defaultPath); } diff --git a/app/src/main/java/code/name/monkey/retromusic/util/FileUtils.kt b/app/src/main/java/code/name/monkey/retromusic/util/FileUtils.kt index e38e006ee..8a06bf62b 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/FileUtils.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/FileUtils.kt @@ -2,6 +2,7 @@ package code.name.monkey.retromusic.util import android.content.Context import android.net.Uri +import android.os.Environment import android.util.Log import java.io.File import java.io.IOException @@ -23,7 +24,13 @@ object FileUtils { * @return the file * @throws IOException */ - fun createFile(context: Context, directoryName: String, fileName: String, body: String, fileType: String): File { + fun createFile( + context: Context, + directoryName: String, + fileName: String, + body: String, + fileType: String + ): File { val root = createDirectory(context, directoryName) val filePath = "$root/$fileName$fileType" val file = File(filePath) @@ -57,4 +64,13 @@ object FileUtils { } return file } +} +@Suppress("Deprecation") +fun getExternalStorageDirectory(): File { + return Environment.getExternalStorageDirectory() +} + +@Suppress("Deprecation") +fun getExternalStoragePublicDirectory(type: String): File { + return Environment.getExternalStoragePublicDirectory(type) } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/ImageUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/ImageUtil.java index d10a4232f..b87eceab9 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/ImageUtil.java +++ b/app/src/main/java/code/name/monkey/retromusic/util/ImageUtil.java @@ -14,128 +14,17 @@ package code.name.monkey.retromusic.util; -import android.content.Context; -import android.content.res.Resources; import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Canvas; -import android.graphics.Matrix; -import android.graphics.Paint; -import android.graphics.PorterDuff; -import android.graphics.PorterDuffColorFilter; -import android.graphics.drawable.Drawable; -import android.media.ExifInterface; -import androidx.annotation.ColorInt; -import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.content.res.ResourcesCompat; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.InputStream; - -import code.name.monkey.appthemehelper.util.TintHelper; /** * Created on : June 18, 2016 Author : zetbaitsu Name : Zetra GitHub : https://github.com/zetbaitsu */ public class ImageUtil { - private static final int TOLERANCE = 20; - // Alpha amount for which values below are considered transparent. - private static final int ALPHA_TOLERANCE = 50; - private static int[] mTempBuffer; - private ImageUtil() {} - public static boolean isGrayscale(Bitmap bitmap) { - final int height = bitmap.getHeight(); - final int width = bitmap.getWidth(); - int size = height * width; - ensureBufferSize(size); - bitmap.getPixels(mTempBuffer, 0, width, 0, 0, width, height); - for (int i = 0; i < size; i++) { - if (!isGrayscale(mTempBuffer[i])) { - return false; - } - } - return true; - } - - public static Bitmap createBitmap(Drawable drawable) { - return createBitmap(drawable, 1f); - } - - public static Bitmap createBitmap(Drawable drawable, float sizeMultiplier) { - Bitmap bitmap = - Bitmap.createBitmap( - (int) (drawable.getIntrinsicWidth() * sizeMultiplier), - (int) (drawable.getIntrinsicHeight() * sizeMultiplier), - Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(bitmap); - drawable.setBounds(0, 0, c.getWidth(), c.getHeight()); - drawable.draw(c); - return bitmap; - } - - public static Drawable getTintedVectorDrawable( - @NonNull Resources res, - @DrawableRes int resId, - @Nullable Resources.Theme theme, - @ColorInt int color) { - return TintHelper.createTintedDrawable(getVectorDrawable(res, resId, theme), color); - } - - public static Drawable getTintedVectorDrawable( - @NonNull Context context, @DrawableRes int id, @ColorInt int color) { - return TintHelper.createTintedDrawable( - getVectorDrawable(context.getResources(), id, context.getTheme()), color); - } - - public static Drawable getVectorDrawable(@NonNull Context context, @DrawableRes int id) { - return getVectorDrawable(context.getResources(), id, context.getTheme()); - } - - public static Drawable getVectorDrawable( - @NonNull Resources res, @DrawableRes int resId, @Nullable Resources.Theme theme) { - return ResourcesCompat.getDrawable(res,resId, theme); - } - - /** Makes sure that {@code mTempBuffer} has at least length {@code size}. */ - private static void ensureBufferSize(int size) { - if (mTempBuffer == null || mTempBuffer.length < size) { - mTempBuffer = new int[size]; - } - } - - public static Bitmap setBitmapColor(Bitmap bitmap, int color) { - Bitmap result = - Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth() - 1, bitmap.getHeight() - 1); - Paint paint = new Paint(); - paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP)); - - Canvas canvas = new Canvas(result); - canvas.drawBitmap(result, 0, 0, paint); - - return result; - } - - public static boolean isGrayscale(int color) { - int alpha = 0xFF & (color >> 24); - if (alpha < ALPHA_TOLERANCE) { - return true; - } - int r = 0xFF & (color >> 16); - int g = 0xFF & (color >> 8); - int b = 0xFF & color; - return Math.abs(r - g) < TOLERANCE - && Math.abs(r - b) < TOLERANCE - && Math.abs(g - b) < TOLERANCE; - } // Amount (max is 255) that two channels can differ before the color is no longer "gray". - public static Bitmap resizeBitmap(@NonNull Bitmap src, int maxForSmallerSize) { int width = src.getWidth(); int height = src.getHeight(); @@ -185,108 +74,4 @@ public class ImageUtil { return inSampleSize; } - - static File compressImage( - File imageFile, - int reqWidth, - int reqHeight, - Bitmap.CompressFormat compressFormat, - int quality, - String destinationPath) - throws IOException { - FileOutputStream fileOutputStream = null; - File file = new File(destinationPath).getParentFile(); - if (!file.exists()) { - file.mkdirs(); - } - try { - fileOutputStream = new FileOutputStream(destinationPath); - // write the compressed bitmap at the destination specified by destinationPath. - decodeSampledBitmapFromFile(imageFile, reqWidth, reqHeight) - .compress(compressFormat, quality, fileOutputStream); - } finally { - if (fileOutputStream != null) { - fileOutputStream.flush(); - fileOutputStream.close(); - } - } - - return new File(destinationPath); - } - - static Bitmap decodeSampledBitmapFromFile(File imageFile, int reqWidth, int reqHeight) - throws IOException { - // First decode with inJustDecodeBounds=true to check dimensions - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options); - - // Calculate inSampleSize - options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight); - - // Decode bitmap with inSampleSize set - options.inJustDecodeBounds = false; - - Bitmap scaledBitmap = BitmapFactory.decodeFile(imageFile.getAbsolutePath(), options); - - // check the rotation of the image and display it properly - ExifInterface exif; - exif = new ExifInterface(imageFile.getAbsolutePath()); - int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0); - Matrix matrix = new Matrix(); - if (orientation == 6) { - matrix.postRotate(90); - } else if (orientation == 3) { - matrix.postRotate(180); - } else if (orientation == 8) { - matrix.postRotate(270); - } - scaledBitmap = - Bitmap.createBitmap( - scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true); - return scaledBitmap; - } - - private static int calculateInSampleSize( - BitmapFactory.Options options, int reqWidth, int reqHeight) { - // Raw height and width of image - final int height = options.outHeight; - final int width = options.outWidth; - int inSampleSize = 1; - - if (height > reqHeight || width > reqWidth) { - - final int halfHeight = height / 2; - final int halfWidth = width / 2; - - // Calculate the largest inSampleSize value that is a power of 2 and keeps both - // height and width larger than the requested height and width. - while ((halfHeight / inSampleSize) >= reqHeight && (halfWidth / inSampleSize) >= reqWidth) { - inSampleSize *= 2; - } - } - - return inSampleSize; - } - - @NonNull - public static Bitmap getResizedBitmap(@NonNull Bitmap image, int maxSize) { - int width = image.getWidth(); - int height = image.getHeight(); - - float bitmapRatio = (float) width / (float) height; - if (bitmapRatio > 1) { - width = maxSize; - height = (int) (width / bitmapRatio); - } else { - height = maxSize; - width = (int) (height * bitmapRatio); - } - return Bitmap.createScaledBitmap(image, width, height, true); - } - - public static Bitmap resize(InputStream stream, int scaledWidth, int scaledHeight) { - final Bitmap bitmap = BitmapFactory.decodeStream(stream); - return Bitmap.createScaledBitmap(bitmap, scaledWidth, scaledHeight, true); - } } diff --git a/app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.kt index 66e46929a..6db2a55c1 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/LyricUtil.kt @@ -13,7 +13,6 @@ */ package code.name.monkey.retromusic.util -import android.os.Environment import android.util.Log import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics @@ -26,7 +25,7 @@ import java.io.* */ object LyricUtil { private val lrcRootPath = - Environment.getExternalStorageDirectory().toString() + "/RetroMusic/lyrics/" + getExternalStorageDirectory().toString() + "/RetroMusic/lyrics/" private const val TAG = "LyricUtil" fun writeLrcToLoc( title: String, artist: String, lrcContext: String diff --git a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt index 62b364e8d..3262157ff 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/MusicUtil.kt @@ -5,27 +5,25 @@ import android.content.Context import android.content.Intent import android.database.Cursor import android.net.Uri -import android.os.Environment import android.provider.BaseColumns import android.provider.MediaStore import android.util.Log -import android.widget.Toast import androidx.core.content.FileProvider import androidx.core.content.contentValuesOf import androidx.core.net.toUri import androidx.fragment.app.FragmentActivity import code.name.monkey.appthemehelper.util.VersionUtils +import code.name.monkey.retromusic.Constants import code.name.monkey.retromusic.R import code.name.monkey.retromusic.db.PlaylistEntity import code.name.monkey.retromusic.db.SongEntity import code.name.monkey.retromusic.db.toSongEntity import code.name.monkey.retromusic.extensions.getLong +import code.name.monkey.retromusic.extensions.showToast import code.name.monkey.retromusic.helper.MusicPlayerRemote.removeFromQueue import code.name.monkey.retromusic.model.Artist -import code.name.monkey.retromusic.model.Playlist import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics -import code.name.monkey.retromusic.repository.RealPlaylistRepository import code.name.monkey.retromusic.repository.Repository import code.name.monkey.retromusic.repository.SongRepository import code.name.monkey.retromusic.service.MusicService @@ -56,14 +54,10 @@ object MusicUtil : KoinComponent { ) ).addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION).setType("audio/*") } catch (e: IllegalArgumentException) { - // TODO the path is most likely not like /storage/emulated/0/... but something like /storage/28C7-75B0/... - e.printStackTrace() - Toast.makeText( - context, - "Could not share this file, I'm aware of the issue.", - Toast.LENGTH_SHORT - ).show() - Intent() + Intent().setAction(Intent.ACTION_SEND).putExtra( + Intent.EXTRA_STREAM, + getSongFileUri(song.id) + ).addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION).setType("audio/*") } } @@ -83,7 +77,7 @@ object MusicUtil : KoinComponent { private fun createAlbumArtDir(context: Context): File { val albumArtDir = File( - if (VersionUtils.hasR()) context.cacheDir else Environment.getExternalStorageDirectory(), + if (VersionUtils.hasR()) context.cacheDir else getExternalStorageDirectory(), "/albumthumbs/" ) if (!albumArtDir.exists()) { @@ -268,15 +262,14 @@ object MusicUtil : KoinComponent { ) } - fun getSongFilePath(context: Context, uri: Uri): String? { - val projection = arrayOf(MediaStore.MediaColumns.DATA) - return context.contentResolver.query(uri, projection, null, null, null)?.use { + fun getSongFilePath(context: Context, uri: Uri): String { + val projection = arrayOf(Constants.DATA) + context.contentResolver.query(uri, projection, null, null, null)?.use { if (it.moveToFirst()) { - it.getString(0) - } else { - "" + return it.getString(0) } } + return "" } fun getTotalDuration(songs: List): Long { @@ -340,48 +333,21 @@ object MusicUtil : KoinComponent { return false } - fun isFavorite(context: Context, song: Song): Boolean { - return PlaylistsUtil - .doPlaylistContains(context, getFavoritesPlaylist(context).id, song.id) - } - - fun isFavoritePlaylist( - context: Context, - playlist: Playlist - ): Boolean { - return playlist.name == context.getString(R.string.favorites) - } - val repository = get() fun toggleFavorite(context: Context, song: Song) { GlobalScope.launch { val playlist: PlaylistEntity = repository.favoritePlaylist() - if (playlist != null) { - val songEntity = song.toSongEntity(playlist.playListId) - val isFavorite = repository.isFavoriteSong(songEntity).isNotEmpty() - if (isFavorite) { - repository.removeSongFromPlaylist(songEntity) - } else { - repository.insertSongs(listOf(song.toSongEntity(playlist.playListId))) - } + val songEntity = song.toSongEntity(playlist.playListId) + val isFavorite = repository.isFavoriteSong(songEntity).isNotEmpty() + if (isFavorite) { + repository.removeSongFromPlaylist(songEntity) + } else { + repository.insertSongs(listOf(song.toSongEntity(playlist.playListId))) } context.sendBroadcast(Intent(MusicService.FAVORITE_STATE_CHANGED)) } } - private fun getFavoritesPlaylist(context: Context): Playlist { - return RealPlaylistRepository(context.contentResolver).playlist(context.getString(R.string.favorites)) - } - - private fun getOrCreateFavoritesPlaylist(context: Context): Playlist { - return RealPlaylistRepository(context.contentResolver).playlist( - PlaylistsUtil.createPlaylist( - context, - context.getString(R.string.favorites) - ) - ) - } - fun deleteTracks( activity: FragmentActivity, songs: List, @@ -390,7 +356,7 @@ object MusicUtil : KoinComponent { ) { val songRepository: SongRepository = get() val projection = arrayOf( - BaseColumns._ID, MediaStore.MediaColumns.DATA + BaseColumns._ID, Constants.DATA ) // Split the query into multiple batches, and merge the resulting cursors var batchStart: Int @@ -457,20 +423,14 @@ object MusicUtil : KoinComponent { } activity.contentResolver.notifyChange("content://media".toUri(), null) activity.runOnUiThread { - Toast.makeText( - activity, - activity.getString(R.string.deleted_x_songs, songCount), - Toast.LENGTH_SHORT - ) - .show() + activity.showToast(activity.getString(R.string.deleted_x_songs, songCount)) callback?.run() } - } } suspend fun deleteTracks(context: Context, songs: List) { - val projection = arrayOf(BaseColumns._ID, MediaStore.MediaColumns.DATA) + val projection = arrayOf(BaseColumns._ID, Constants.DATA) val selection = StringBuilder() selection.append(BaseColumns._ID + " IN (") for (i in songs.indices) { @@ -520,11 +480,7 @@ object MusicUtil : KoinComponent { cursor.close() } withContext(Dispatchers.Main) { - Toast.makeText( - context, - context.getString(R.string.deleted_x_songs, deletedCount), - Toast.LENGTH_SHORT - ).show() + context.showToast(context.getString(R.string.deleted_x_songs, deletedCount)) } } catch (ignored: SecurityException) { diff --git a/app/src/main/java/code/name/monkey/retromusic/util/NavigationUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/NavigationUtil.kt index 37e26254f..2d960af00 100755 --- a/app/src/main/java/code/name/monkey/retromusic/util/NavigationUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/NavigationUtil.kt @@ -19,9 +19,11 @@ import android.content.Context import android.content.Intent import android.media.audiofx.AudioEffect import android.widget.Toast +import androidx.fragment.app.FragmentActivity import code.name.monkey.retromusic.R import code.name.monkey.retromusic.activities.* import code.name.monkey.retromusic.activities.bugreport.BugReportActivity +import code.name.monkey.retromusic.extensions.showToast import code.name.monkey.retromusic.helper.MusicPlayerRemote.audioSessionId object NavigationUtil { @@ -55,10 +57,9 @@ object NavigationUtil { ) } - fun gotoWhatNews(activity: Activity) { - activity.startActivity( - Intent(activity, WhatsNewActivity::class.java), null - ) + fun gotoWhatNews(activity: FragmentActivity) { + val changelogBottomSheet = WhatsNewFragment() + changelogBottomSheet.show(activity.supportFragmentManager, WhatsNewFragment.TAG) } fun openEqualizer(activity: Activity) { @@ -68,10 +69,7 @@ object NavigationUtil { private fun stockEqualizer(activity: Activity) { val sessionId = audioSessionId if (sessionId == AudioEffect.ERROR_BAD_VALUE) { - Toast.makeText( - activity, activity.resources.getString(R.string.no_audio_ID), Toast.LENGTH_LONG - ) - .show() + activity.showToast(R.string.no_audio_ID, Toast.LENGTH_LONG) } else { try { val effects = Intent(AudioEffect.ACTION_DISPLAY_AUDIO_EFFECT_CONTROL_PANEL) @@ -79,12 +77,7 @@ object NavigationUtil { effects.putExtra(AudioEffect.EXTRA_CONTENT_TYPE, AudioEffect.CONTENT_TYPE_MUSIC) activity.startActivityForResult(effects, 0) } catch (notFound: ActivityNotFoundException) { - Toast.makeText( - activity, - activity.resources.getString(R.string.no_equalizer), - Toast.LENGTH_SHORT - ) - .show() + activity.showToast(R.string.no_equalizer) } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PackageValidator.kt b/app/src/main/java/code/name/monkey/retromusic/util/PackageValidator.kt index 15b9722ee..cc4124a90 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/PackageValidator.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/PackageValidator.kt @@ -71,7 +71,7 @@ class PackageValidator( /** * Checks whether the caller attempting to connect to a [MediaBrowserServiceCompat] is known. - * See [MusicService.onGetRoot] for where this is utilized. + * See [MediaBrowserServiceCompat.onGetRoot] for where this is utilized. * * @param callingPackage The package name of the caller. * @param callingUid The user id of the caller. diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.java deleted file mode 100644 index 028625509..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.java +++ /dev/null @@ -1,333 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.util; - -import static android.provider.MediaStore.Audio.Playlists.EXTERNAL_CONTENT_URI; - -import android.content.ContentResolver; -import android.content.ContentValues; -import android.content.Context; -import android.database.Cursor; -import android.net.Uri; -import android.os.Environment; -import android.provider.BaseColumns; -import android.provider.MediaStore; -import android.widget.Toast; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import java.io.File; -import java.io.IOException; -import java.util.ArrayList; -import java.util.List; - -import code.name.monkey.retromusic.R; -import code.name.monkey.retromusic.db.PlaylistWithSongs; -import code.name.monkey.retromusic.helper.M3UWriter; -import code.name.monkey.retromusic.model.Playlist; -import code.name.monkey.retromusic.model.PlaylistSong; -import code.name.monkey.retromusic.model.Song; - -public class PlaylistsUtil { - - public static long createPlaylist(@NonNull final Context context, @Nullable final String name) { - int id = -1; - if (name != null && name.length() > 0) { - try { - Cursor cursor = - context - .getContentResolver() - .query( - EXTERNAL_CONTENT_URI, - new String[] {MediaStore.Audio.Playlists._ID}, - MediaStore.Audio.PlaylistsColumns.NAME + "=?", - new String[] {name}, - null); - if (cursor == null || cursor.getCount() < 1) { - final ContentValues values = new ContentValues(1); - values.put(MediaStore.Audio.PlaylistsColumns.NAME, name); - final Uri uri = context.getContentResolver().insert(EXTERNAL_CONTENT_URI, values); - if (uri != null) { - // Necessary because somehow the MediaStoreObserver is not notified when adding a - // playlist - context.getContentResolver().notifyChange(Uri.parse("content://media"), null); - Toast.makeText( - context, - context.getResources().getString(R.string.created_playlist_x, name), - Toast.LENGTH_SHORT) - .show(); - id = Integer.parseInt(uri.getLastPathSegment()); - } - } else { - // Playlist exists - if (cursor.moveToFirst()) { - id = cursor.getInt(cursor.getColumnIndex(MediaStore.Audio.Playlists._ID)); - } - } - if (cursor != null) { - cursor.close(); - } - } catch (SecurityException e) { - e.printStackTrace(); - } - } - if (id == -1) { - Toast.makeText( - context, - context.getResources().getString(R.string.could_not_create_playlist), - Toast.LENGTH_SHORT) - .show(); - } - return id; - } - - public static void deletePlaylists( - @NonNull final Context context, @NonNull final List playlists) { - final StringBuilder selection = new StringBuilder(); - selection.append(MediaStore.Audio.Playlists._ID + " IN ("); - for (int i = 0; i < playlists.size(); i++) { - selection.append(playlists.get(i).getId()); - if (i < playlists.size() - 1) { - selection.append(","); - } - } - selection.append(")"); - try { - context.getContentResolver().delete(EXTERNAL_CONTENT_URI, selection.toString(), null); - context.getContentResolver().notifyChange(Uri.parse("content://media"), null); - } catch (SecurityException ignored) { - } - } - - public static void addToPlaylist( - @NonNull final Context context, - final Song song, - final long playlistId, - final boolean showToastOnFinish) { - List helperList = new ArrayList<>(); - helperList.add(song); - addToPlaylist(context, helperList, playlistId, showToastOnFinish); - } - - public static void addToPlaylist( - @NonNull final Context context, - @NonNull final List songs, - final long playlistId, - final boolean showToastOnFinish) { - final int size = songs.size(); - final ContentResolver resolver = context.getContentResolver(); - final String[] projection = - new String[] { - "max(" + MediaStore.Audio.Playlists.Members.PLAY_ORDER + ")", - }; - final Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId); - Cursor cursor = null; - int base = 0; - - try { - try { - cursor = resolver.query(uri, projection, null, null, null); - - if (cursor != null && cursor.moveToFirst()) { - base = cursor.getInt(0) + 1; - } - } finally { - if (cursor != null) { - cursor.close(); - } - } - - int numInserted = 0; - for (int offSet = 0; offSet < size; offSet += 1000) - numInserted += resolver.bulkInsert(uri, makeInsertItems(songs, offSet, 1000, base)); - - if (showToastOnFinish) { - Toast.makeText( - context, - context - .getResources() - .getString( - R.string.inserted_x_songs_into_playlist_x, - numInserted, - getNameForPlaylist(context, playlistId)), - Toast.LENGTH_SHORT) - .show(); - } - } catch (SecurityException exception) { - exception.printStackTrace(); - } - } - - @NonNull - public static ContentValues[] makeInsertItems( - @NonNull final List songs, final int offset, int len, final int base) { - if (offset + len > songs.size()) { - len = songs.size() - offset; - } - - ContentValues[] contentValues = new ContentValues[len]; - - for (int i = 0; i < len; i++) { - contentValues[i] = new ContentValues(); - contentValues[i].put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, base + offset + i); - contentValues[i].put( - MediaStore.Audio.Playlists.Members.AUDIO_ID, songs.get(offset + i).getId()); - } - return contentValues; - } - - public static String getNameForPlaylist(@NonNull final Context context, final long id) { - try { - Cursor cursor = - context - .getContentResolver() - .query( - EXTERNAL_CONTENT_URI, - new String[] {MediaStore.Audio.PlaylistsColumns.NAME}, - BaseColumns._ID + "=?", - new String[] {String.valueOf(id)}, - null); - if (cursor != null) { - try { - if (cursor.moveToFirst()) { - return cursor.getString(0); - } - } finally { - cursor.close(); - } - } - } catch (SecurityException ignored) { - } - return ""; - } - - public static void removeFromPlaylist( - @NonNull final Context context, @NonNull final Song song, long playlistId) { - Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId); - String selection = MediaStore.Audio.Playlists.Members.AUDIO_ID + " =?"; - String[] selectionArgs = new String[] {String.valueOf(song.getId())}; - - try { - context.getContentResolver().delete(uri, selection, selectionArgs); - } catch (SecurityException ignored) { - } - } - - public static void removeFromPlaylist( - @NonNull final Context context, @NonNull final List songs) { - final long playlistId = songs.get(0).getPlaylistId(); - Uri uri = MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId); - String[] selectionArgs = new String[songs.size()]; - for (int i = 0; i < selectionArgs.length; i++) { - selectionArgs[i] = String.valueOf(songs.get(i).getIdInPlayList()); - } - StringBuilder selection = new StringBuilder(MediaStore.Audio.Playlists.Members._ID + " in ("); - - for (String selectionArg : selectionArgs) selection.append("?, "); - selection = new StringBuilder(selection.substring(0, selection.length() - 2) + ")"); - - try { - context.getContentResolver().delete(uri, selection.toString(), selectionArgs); - } catch (SecurityException ignored) { - } - } - - public static boolean doPlaylistContains( - @NonNull final Context context, final long playlistId, final long songId) { - if (playlistId != -1) { - try { - Cursor c = - context - .getContentResolver() - .query( - MediaStore.Audio.Playlists.Members.getContentUri("external", playlistId), - new String[] {MediaStore.Audio.Playlists.Members.AUDIO_ID}, - MediaStore.Audio.Playlists.Members.AUDIO_ID + "=?", - new String[] {String.valueOf(songId)}, - null); - int count = 0; - if (c != null) { - count = c.getCount(); - c.close(); - } - return count > 0; - } catch (SecurityException ignored) { - } - } - return false; - } - - public static boolean moveItem( - @NonNull final Context context, long playlistId, int from, int to) { - return MediaStore.Audio.Playlists.Members.moveItem( - context.getContentResolver(), playlistId, from, to); - } - - public static void renamePlaylist( - @NonNull final Context context, final long id, final String newName) { - ContentValues contentValues = new ContentValues(); - contentValues.put(MediaStore.Audio.PlaylistsColumns.NAME, newName); - try { - context - .getContentResolver() - .update( - EXTERNAL_CONTENT_URI, - contentValues, - MediaStore.Audio.Playlists._ID + "=?", - new String[] {String.valueOf(id)}); - context.getContentResolver().notifyChange(Uri.parse("content://media"), null); - } catch (SecurityException ignored) { - } - } - - public static File savePlaylist(Context context, Playlist playlist) throws IOException { - return M3UWriter.write( - new File(Environment.getExternalStorageDirectory(), "Playlists"), playlist); - } - - public static File savePlaylistWithSongs(PlaylistWithSongs playlist) throws IOException { - return M3UWriter.writeIO( - new File(Environment.getExternalStorageDirectory(), "Playlists"), playlist); - } - - public static boolean doesPlaylistExist(@NonNull final Context context, final int playlistId) { - return playlistId != -1 - && doesPlaylistExist( - context, - MediaStore.Audio.Playlists._ID + "=?", - new String[] {String.valueOf(playlistId)}); - } - - public static boolean doesPlaylistExist(@NonNull final Context context, final String name) { - return doesPlaylistExist( - context, MediaStore.Audio.PlaylistsColumns.NAME + "=?", new String[] {name}); - } - - private static boolean doesPlaylistExist( - @NonNull Context context, @NonNull final String selection, @NonNull final String[] values) { - Cursor cursor = - context - .getContentResolver() - .query(EXTERNAL_CONTENT_URI, new String[]{}, selection, values, null); - - boolean exists = false; - if (cursor != null) { - exists = cursor.getCount() != 0; - cursor.close(); - } - return exists; - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.kt new file mode 100644 index 000000000..d8e3003ab --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/PlaylistsUtil.kt @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2019 Hemanth Savarala. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + */ +package code.name.monkey.retromusic.util + +import code.name.monkey.retromusic.db.PlaylistWithSongs +import code.name.monkey.retromusic.helper.M3UWriter.writeIO +import java.io.File +import java.io.IOException + +object PlaylistsUtil { + @Throws(IOException::class) + fun savePlaylistWithSongs(playlist: PlaylistWithSongs?): File { + return writeIO( + File(getExternalStorageDirectory(), "Playlists"), playlist!! + ) + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt index 3f819e68d..c46a169fb 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/PreferenceUtil.kt @@ -1,10 +1,12 @@ package code.name.monkey.retromusic.util +import android.content.Context import android.content.SharedPreferences.OnSharedPreferenceChangeListener import android.net.ConnectivityManager -import android.net.NetworkInfo import androidx.core.content.edit import androidx.core.content.getSystemService +import androidx.core.content.res.use +import androidx.fragment.app.Fragment import androidx.preference.PreferenceManager import androidx.viewpager.widget.ViewPager import code.name.monkey.appthemehelper.util.VersionUtils @@ -97,10 +99,10 @@ object PreferenceUtil { val languageCode: String get() = sharedPreferences.getString(LANGUAGE_NAME, "auto") ?: "auto" - var userName + var Fragment.userName get() = sharedPreferences.getString( USER_NAME, - App.getContext().getString(R.string.user_name) + getString(R.string.user_name) ) set(value) = sharedPreferences.edit { putString(USER_NAME, value) @@ -333,15 +335,12 @@ object PreferenceUtil { val isLockScreen get() = sharedPreferences.getBoolean(LOCK_SCREEN, false) - fun isAllowedToDownloadMetadata(): Boolean { + fun isAllowedToDownloadMetadata(context: Context): Boolean { return when (autoDownloadImagesPolicy) { "always" -> true "only_wifi" -> { - val connectivityManager = App.getContext().getSystemService() - var netInfo: NetworkInfo? = null - if (connectivityManager != null) { - netInfo = connectivityManager.activeNetworkInfo - } + val connectivityManager = context.getSystemService() + val netInfo = connectivityManager?.activeNetworkInfo netInfo != null && netInfo.type == ConnectivityManager.TYPE_WIFI && netInfo.isConnectedOrConnecting } "never" -> false @@ -395,9 +394,15 @@ object PreferenceUtil { val filterLength get() = sharedPreferences.getInt(FILTER_SONG, 20) var lastVersion - get() = sharedPreferences.getInt(LAST_CHANGELOG_VERSION, 0) + // This was stored as an integer before now it's a long, so avoid a ClassCastException + get() = try { + sharedPreferences.getLong(LAST_CHANGELOG_VERSION, 0) + } catch (e: ClassCastException) { + sharedPreferences.edit { remove(LAST_CHANGELOG_VERSION) } + 0 + } set(value) = sharedPreferences.edit { - putInt(LAST_CHANGELOG_VERSION, value) + putLong(LAST_CHANGELOG_VERSION, value) } var lastSleepTimerValue @@ -432,10 +437,11 @@ object PreferenceUtil { val position = sharedPreferences.getStringOrDefault( HOME_ARTIST_GRID_STYLE, "0" ).toInt() - val typedArray = App.getContext() - .resources.obtainTypedArray(R.array.pref_home_grid_style_layout) - val layoutRes = typedArray.getResourceId(position, 0) - typedArray.recycle() + val layoutRes = + App.getContext().resources.obtainTypedArray(R.array.pref_home_grid_style_layout) + .use { + it.getResourceId(position, 0) + } return if (layoutRes == 0) { R.layout.item_artist } else layoutRes @@ -446,10 +452,10 @@ object PreferenceUtil { val position = sharedPreferences.getStringOrDefault( HOME_ALBUM_GRID_STYLE, "4" ).toInt() - val typedArray = App.getContext() - .resources.obtainTypedArray(R.array.pref_home_grid_style_layout) - val layoutRes = typedArray.getResourceId(position, 0) - typedArray.recycle() + val layoutRes = App.getContext() + .resources.obtainTypedArray(R.array.pref_home_grid_style_layout).use { + it.getResourceId(position, 0) + } return if (layoutRes == 0) { R.layout.item_image } else layoutRes @@ -590,7 +596,7 @@ object PreferenceUtil { 4 -> VerticalFlipTransformation() 5 -> HingeTransformation() 6 -> VerticalStackTransformer() - else -> NormalPageTransformer() + else -> ViewPager.PageTransformer { _, _ -> } } } diff --git a/app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.java b/app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.java deleted file mode 100644 index 8005ab2b4..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.java +++ /dev/null @@ -1,262 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.util; - -import android.annotation.TargetApi; -import android.app.Activity; -import android.content.Context; -import android.content.Intent; -import android.content.res.Configuration; -import android.content.res.Resources; -import android.graphics.Bitmap; -import android.graphics.Canvas; -import android.graphics.Color; -import android.graphics.Point; -import android.graphics.drawable.Drawable; -import android.net.ConnectivityManager; -import android.net.NetworkInfo; -import android.net.Uri; -import android.os.Build; -import android.util.DisplayMetrics; -import android.view.Display; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; -import android.view.inputmethod.InputMethodManager; - -import androidx.annotation.ColorInt; -import androidx.annotation.DrawableRes; -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import androidx.core.content.res.ResourcesCompat; - -import java.net.InetAddress; -import java.net.NetworkInterface; -import java.text.DecimalFormat; -import java.util.Collections; -import java.util.List; - -import code.name.monkey.appthemehelper.util.TintHelper; -import code.name.monkey.retromusic.App; - -public class RetroUtil { - - private static final int[] TEMP_ARRAY = new int[1]; - - private static final String SHOW_NAV_BAR_RES_NAME = "config_showNavigationBar"; - - public static int calculateNoOfColumns(@NonNull Context context) { - DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics(); - float dpWidth = displayMetrics.widthPixels / displayMetrics.density; - return (int) (dpWidth / 180); - } - - @NonNull - public static Bitmap createBitmap(@NonNull Drawable drawable, float sizeMultiplier) { - Bitmap bitmap = - Bitmap.createBitmap( - (int) (drawable.getIntrinsicWidth() * sizeMultiplier), - (int) (drawable.getIntrinsicHeight() * sizeMultiplier), - Bitmap.Config.ARGB_8888); - Canvas c = new Canvas(bitmap); - drawable.setBounds(0, 0, c.getWidth(), c.getHeight()); - drawable.draw(c); - return bitmap; - } - - public static String formatValue(float value) { - String[] arr = {"", "K", "M", "B", "T", "P", "E"}; - int index = 0; - while ((value / 1000) >= 1) { - value = value / 1000; - index++; - } - DecimalFormat decimalFormat = new DecimalFormat("#.##"); - return String.format("%s %s", decimalFormat.format(value), arr[index]); - } - - public static float frequencyCount(int frequency) { - return (float) (frequency / 1000.0); - } - - public static Point getScreenSize(@NonNull Context c) { - Display display = null; - if (c.getSystemService(Context.WINDOW_SERVICE) != null) { - display = ((WindowManager) c.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay(); - } - Point size = new Point(); - if (display != null) { - display.getSize(size); - } - return size; - } - - public static int getStatusBarHeight() { - int result = 0; - int resourceId = - App.Companion.getContext() - .getResources() - .getIdentifier("status_bar_height", "dimen", "android"); - if (resourceId > 0) { - result = App.Companion.getContext().getResources().getDimensionPixelSize(resourceId); - } - return result; - } - - public static int getNavigationBarHeight() { - int result = 0; - int resourceId = - App.Companion.getContext() - .getResources() - .getIdentifier("navigation_bar_height", "dimen", "android"); - if (resourceId > 0) { - result = App.Companion.getContext().getResources().getDimensionPixelSize(resourceId); - } - return result; - } - - @NonNull - public static Drawable getTintedVectorDrawable( - @NonNull Context context, @DrawableRes int id, @ColorInt int color) { - return TintHelper.createTintedDrawable( - getVectorDrawable(context.getResources(), id, context.getTheme()), color); - } - - @NonNull - public static Drawable getTintedVectorDrawable( - @NonNull Resources res, - @DrawableRes int resId, - @Nullable Resources.Theme theme, - @ColorInt int color) { - return TintHelper.createTintedDrawable(getVectorDrawable(res, resId, theme), color); - } - - @Nullable - public static Drawable getVectorDrawable( - @NonNull Resources res, @DrawableRes int resId, @Nullable Resources.Theme theme) { - return ResourcesCompat.getDrawable(res, resId, theme); - } - - public static void hideSoftKeyboard(@Nullable Activity activity) { - if (activity != null) { - View currentFocus = activity.getCurrentFocus(); - if (currentFocus != null) { - InputMethodManager inputMethodManager = - (InputMethodManager) activity.getSystemService(Activity.INPUT_METHOD_SERVICE); - if (inputMethodManager != null) { - inputMethodManager.hideSoftInputFromWindow(currentFocus.getWindowToken(), 0); - } - } - } - } - - public static boolean isAllowedToDownloadMetadata(final @NonNull Context context) { - switch (PreferenceUtil.INSTANCE.getAutoDownloadImagesPolicy()) { - case "always": - return true; - case "only_wifi": - final ConnectivityManager connectivityManager = - (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); - NetworkInfo netInfo = connectivityManager.getActiveNetworkInfo(); - return netInfo != null - && netInfo.getType() == ConnectivityManager.TYPE_WIFI - && netInfo.isConnectedOrConnecting(); - case "never": - default: - return false; - } - } - - public static boolean isLandscape() { - return App.Companion.getContext().getResources().getConfiguration().orientation - == Configuration.ORIENTATION_LANDSCAPE; - } - - @TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) - public static boolean isRTL(@NonNull Context context) { - Configuration config = context.getResources().getConfiguration(); - return config.getLayoutDirection() == View.LAYOUT_DIRECTION_RTL; - } - - public static boolean isTablet() { - return App.Companion.getContext().getResources().getConfiguration().smallestScreenWidthDp - >= 600; - } - - public static void openUrl(@NonNull Activity context, @NonNull String str) { - Intent intent = new Intent("android.intent.action.VIEW"); - intent.setData(Uri.parse(str)); - intent.setFlags(268435456); - context.startActivity(intent); - } - - public static void setAllowDrawUnderNavigationBar(Window window) { - window.setNavigationBarColor(Color.TRANSPARENT); - window - .getDecorView() - .setSystemUiVisibility( - Build.VERSION.SDK_INT >= Build.VERSION_CODES.O - ? View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION - : View.SYSTEM_UI_FLAG_LAYOUT_STABLE - | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); - } - - public static void setAllowDrawUnderStatusBar(@NonNull Window window) { - window - .getDecorView() - .setSystemUiVisibility( - View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN); - window.setStatusBarColor(Color.TRANSPARENT); - } - - public static String getIpAddress(boolean useIPv4) { - try { - List interfaces = - Collections.list(NetworkInterface.getNetworkInterfaces()); - for (NetworkInterface intf : interfaces) { - List addrs = Collections.list(intf.getInetAddresses()); - for (InetAddress addr : addrs) { - if (!addr.isLoopbackAddress()) { - String sAddr = addr.getHostAddress(); - //boolean isIPv4 = InetAddressUtils.isIPv4Address(sAddr); - boolean isIPv4 = sAddr.indexOf(':') < 0; - if (useIPv4) { - if (isIPv4) return sAddr; - } else { - if (!isIPv4) { - int delim = sAddr.indexOf('%'); // drop ip6 zone suffix - if (delim < 0) { - return sAddr.toUpperCase(); - } else { - return sAddr.substring( - 0, - delim - ).toUpperCase(); - } - } - } - } - } - - } - } catch (Exception ignored) { - } - return ""; - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.kt new file mode 100644 index 000000000..60f4f5823 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/util/RetroUtil.kt @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2019 Hemanth Savarala. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + */ +package code.name.monkey.retromusic.util + +import android.content.Context +import android.content.res.Configuration +import android.graphics.Point +import code.name.monkey.retromusic.App.Companion.getContext +import java.net.InetAddress +import java.net.NetworkInterface +import java.text.DecimalFormat +import java.util.* + +object RetroUtil { + fun formatValue(numValue: Float): String { + var value = numValue + val arr = arrayOf("", "K", "M", "B", "T", "P", "E") + var index = 0 + while (value / 1000 >= 1) { + value /= 1000 + index++ + } + val decimalFormat = DecimalFormat("#.##") + return String.format("%s %s", decimalFormat.format(value.toDouble()), arr[index]) + } + + fun frequencyCount(frequency: Int): Float { + return (frequency / 1000.0).toFloat() + } + + fun getScreenSize(context: Context): Point { + val x: Int = context.resources.displayMetrics.widthPixels + val y: Int = context.resources.displayMetrics.heightPixels + return Point(x, y) + } + + val statusBarHeight: Int + get() { + var result = 0 + val resourceId = getContext() + .resources + .getIdentifier("status_bar_height", "dimen", "android") + if (resourceId > 0) { + result = getContext().resources.getDimensionPixelSize(resourceId) + } + return result + } + + val navigationBarHeight: Int + get() { + var result = 0 + val resourceId = getContext() + .resources + .getIdentifier("navigation_bar_height", "dimen", "android") + if (resourceId > 0) { + result = getContext().resources.getDimensionPixelSize(resourceId) + } + return result + } + + val isLandscape: Boolean + get() = (getContext().resources.configuration.orientation + == Configuration.ORIENTATION_LANDSCAPE) + val isTablet: Boolean + get() = (getContext().resources.configuration.smallestScreenWidthDp + >= 600) + + fun getIpAddress(useIPv4: Boolean): String? { + try { + val interfaces: List = + Collections.list(NetworkInterface.getNetworkInterfaces()) + for (intf in interfaces) { + val addrs: List = Collections.list(intf.inetAddresses) + for (addr in addrs) { + if (!addr.isLoopbackAddress) { + val sAddr = addr.hostAddress + + if (sAddr != null) { + val isIPv4 = sAddr.indexOf(':') < 0 + if (useIPv4) { + if (isIPv4) return sAddr + } else { + if (!isIPv4) { + val delim = sAddr.indexOf('%') // drop ip6 zone suffix + return if (delim < 0) { + sAddr.uppercase() + } else { + sAddr.substring( + 0, + delim + ).uppercase() + } + } + } + } else { + return null + } + + } + } + } + } catch (ignored: Exception) { + } + return "" + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/util/RingtoneManager.kt b/app/src/main/java/code/name/monkey/retromusic/util/RingtoneManager.kt index a023e7475..8071ce4fa 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/RingtoneManager.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/RingtoneManager.kt @@ -19,10 +19,10 @@ import android.content.Intent import android.provider.BaseColumns import android.provider.MediaStore import android.provider.Settings -import android.widget.Toast import androidx.core.net.toUri import code.name.monkey.appthemehelper.util.VersionUtils import code.name.monkey.retromusic.R +import code.name.monkey.retromusic.extensions.showToast import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.util.MusicUtil.getSongFileUri import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -45,7 +45,7 @@ class RingtoneManager(val context: Context) { Settings.System.putString(resolver, Settings.System.RINGTONE, uri.toString()) val message = context .getString(R.string.x_has_been_set_as_ringtone, cursorSong.getString(0)) - Toast.makeText(context, message, Toast.LENGTH_SHORT).show() + context.showToast(message) } } } catch (ignored: SecurityException) { diff --git a/app/src/main/java/code/name/monkey/retromusic/util/UriUtil.kt b/app/src/main/java/code/name/monkey/retromusic/util/UriUtil.kt index 4b1ef3d16..923e5dac4 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/UriUtil.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/UriUtil.kt @@ -6,6 +6,7 @@ import android.net.Uri import android.os.Build import android.provider.MediaStore import androidx.annotation.RequiresApi +import code.name.monkey.retromusic.Constants object UriUtil { @RequiresApi(Build.VERSION_CODES.Q) @@ -13,7 +14,7 @@ object UriUtil { val uri = MediaStore.Files.getContentUri(MediaStore.VOLUME_EXTERNAL) val proj = arrayOf(MediaStore.Files.FileColumns._ID) context.contentResolver.query( - uri, proj, MediaStore.Files.FileColumns.DATA + "=?", arrayOf(path), null + uri, proj, Constants.DATA + "=?", arrayOf(path), null )?.use { cursor -> if (cursor.count != 0) { cursor.moveToFirst() diff --git a/app/src/main/java/code/name/monkey/retromusic/util/theme/ThemeManager.kt b/app/src/main/java/code/name/monkey/retromusic/util/theme/ThemeManager.kt index 1f69fbc4f..c1a8283df 100644 --- a/app/src/main/java/code/name/monkey/retromusic/util/theme/ThemeManager.kt +++ b/app/src/main/java/code/name/monkey/retromusic/util/theme/ThemeManager.kt @@ -1,31 +1,29 @@ package code.name.monkey.retromusic.util.theme +import android.content.Context import androidx.annotation.StyleRes import androidx.appcompat.app.AppCompatDelegate -import code.name.monkey.retromusic.App import code.name.monkey.retromusic.R import code.name.monkey.retromusic.extensions.generalThemeValue import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.theme.ThemeMode.* -object ThemeManager { - - @StyleRes - fun getThemeResValue(): Int = - if (PreferenceUtil.materialYou) { - R.style.Theme_RetroMusic_MD3 - } else { - when (App.getContext().generalThemeValue) { - LIGHT -> R.style.Theme_RetroMusic_Light - DARK -> R.style.Theme_RetroMusic_Base - BLACK -> R.style.Theme_RetroMusic_Black - AUTO -> R.style.Theme_RetroMusic_FollowSystem - } +@StyleRes +fun Context.getThemeResValue(): Int = + if (PreferenceUtil.materialYou) { + if (generalThemeValue == BLACK) R.style.Theme_RetroMusic_MD3_Black + else R.style.Theme_RetroMusic_MD3 + } else { + when (generalThemeValue) { + LIGHT -> R.style.Theme_RetroMusic_Light + DARK -> R.style.Theme_RetroMusic_Base + BLACK -> R.style.Theme_RetroMusic_Black + AUTO -> R.style.Theme_RetroMusic_FollowSystem } - - fun getNightMode(): Int = when (App.getContext().generalThemeValue) { - LIGHT -> AppCompatDelegate.MODE_NIGHT_NO - DARK -> AppCompatDelegate.MODE_NIGHT_YES - else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM } + +fun Context.getNightMode(): Int = when (generalThemeValue) { + LIGHT -> AppCompatDelegate.MODE_NIGHT_NO + DARK -> AppCompatDelegate.MODE_NIGHT_YES + else -> AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/views/ContributorsView.java b/app/src/main/java/code/name/monkey/retromusic/views/ContributorsView.java deleted file mode 100644 index 4e4c1a743..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/views/ContributorsView.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.views; - -import static code.name.monkey.retromusic.util.RetroUtil.openUrl; - -import android.app.Activity; -import android.content.Context; -import android.content.res.TypedArray; -import android.util.AttributeSet; -import android.view.LayoutInflater; -import android.view.View; -import android.widget.FrameLayout; -import android.widget.TextView; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import code.name.monkey.retromusic.R; - -public class ContributorsView extends FrameLayout { - public ContributorsView(@NonNull Context context) { - super(context); - init(context, null); - } - - public ContributorsView(@NonNull Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - init(context, attrs); - } - - public ContributorsView( - @NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context, attrs); - } - - private void init(Context context, AttributeSet attributeSet) { - final TypedArray attributes = - context.obtainStyledAttributes(attributeSet, R.styleable.ContributorsView, 0, 0); - if (attributes != null) { - final View layout = LayoutInflater.from(context).inflate(R.layout.item_contributor, this); - - NetworkImageView networkImageView = layout.findViewById(R.id.image); - String url = attributes.getString(R.styleable.ContributorsView_profile_url); - networkImageView.setImageUrl(url); - - String name = attributes.getString(R.styleable.ContributorsView_profile_name); - TextView title = layout.findViewById(R.id.title); - title.setText(name); - - String summary = attributes.getString(R.styleable.ContributorsView_profile_summary); - TextView text = layout.findViewById(R.id.text); - text.setText(summary); - - String link = attributes.getString(R.styleable.ContributorsView_profile_link); - layout.setOnClickListener( - v -> { - if (link == null) { - return; - } - openUrl((Activity) getContext(), link); - }); - attributes.recycle(); - } - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/views/HeightFitSquareLayout.java b/app/src/main/java/code/name/monkey/retromusic/views/HeightFitSquareLayout.java deleted file mode 100755 index 8ed2a9e66..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/views/HeightFitSquareLayout.java +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.views; - -import android.annotation.TargetApi; -import android.content.Context; -import android.util.AttributeSet; -import android.widget.FrameLayout; - -public class HeightFitSquareLayout extends FrameLayout { - private boolean forceSquare = true; - - public HeightFitSquareLayout(Context context) { - super(context); - } - - public HeightFitSquareLayout(Context context, AttributeSet attributeSet) { - super(context, attributeSet); - } - - public HeightFitSquareLayout(Context context, AttributeSet attributeSet, int i) { - super(context, attributeSet, i); - } - - @TargetApi(21) - public HeightFitSquareLayout(Context context, AttributeSet attributeSet, int i, int i2) { - super(context, attributeSet, i, i2); - } - - public void forceSquare(boolean z) { - this.forceSquare = z; - requestLayout(); - } - - protected void onMeasure(int i, int i2) { - if (this.forceSquare) { - i = i2; - } - super.onMeasure(i, i2); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/views/HeightFitSquareLayout.kt b/app/src/main/java/code/name/monkey/retromusic/views/HeightFitSquareLayout.kt new file mode 100644 index 000000000..3653fddd6 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/HeightFitSquareLayout.kt @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2019 Hemanth Savarala. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + */ +package code.name.monkey.retromusic.views + +import android.content.Context +import android.util.AttributeSet +import android.widget.FrameLayout + +class HeightFitSquareLayout @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = -1 +) : FrameLayout(context, attrs, defStyleAttr){ + private var forceSquare = true + + fun setForceSquare(forceSquare: Boolean) { + this.forceSquare = forceSquare + requestLayout() + } + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + var i = widthMeasureSpec + if (forceSquare) { + i = heightMeasureSpec + } + super.onMeasure(i, heightMeasureSpec) + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/views/ListItemView.kt b/app/src/main/java/code/name/monkey/retromusic/views/ListItemView.kt index a1b199682..37924d275 100644 --- a/app/src/main/java/code/name/monkey/retromusic/views/ListItemView.kt +++ b/app/src/main/java/code/name/monkey/retromusic/views/ListItemView.kt @@ -27,29 +27,16 @@ import code.name.monkey.retromusic.extensions.show /** * Created by hemanths on 2019-10-02. */ -class ListItemView : FrameLayout { +class ListItemView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = -1 +) : FrameLayout(context, attrs, defStyleAttr) { - private lateinit var binding: ListItemViewNoCardBinding - - constructor(context: Context) : super(context) { - init(context, null) - } - - constructor(context: Context, attrs: AttributeSet) : super(context, attrs) { - init(context, attrs) - } - - constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super( - context, - attrs, - defStyleAttr - ) { - init(context, attrs) - } - - private fun init(context: Context, attrs: AttributeSet?) { - binding = ListItemViewNoCardBinding.inflate(LayoutInflater.from(context), this, true) + private var binding = + ListItemViewNoCardBinding.inflate(LayoutInflater.from(context), this, true) + init { context.withStyledAttributes(attrs, R.styleable.ListItemView) { if (hasValue(R.styleable.ListItemView_listItemIcon)) { binding.icon.setImageDrawable(getDrawable(R.styleable.ListItemView_listItemIcon)) diff --git a/app/src/main/java/code/name/monkey/retromusic/views/LollipopFixedWebView.java b/app/src/main/java/code/name/monkey/retromusic/views/LollipopFixedWebView.java deleted file mode 100644 index 662843408..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/views/LollipopFixedWebView.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.views; - -import android.annotation.TargetApi; -import android.content.Context; -import android.content.res.Configuration; -import android.os.Build; -import android.util.AttributeSet; -import android.webkit.WebView; - -public class LollipopFixedWebView extends WebView { - public LollipopFixedWebView(Context context) { - super(getFixedContext(context)); - } - - public LollipopFixedWebView(Context context, AttributeSet attrs) { - super(getFixedContext(context), attrs); - } - - public LollipopFixedWebView(Context context, AttributeSet attrs, int defStyleAttr) { - super(getFixedContext(context), attrs, defStyleAttr); - } - - @TargetApi(Build.VERSION_CODES.LOLLIPOP) - public LollipopFixedWebView( - Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { - super(getFixedContext(context), attrs, defStyleAttr, defStyleRes); - } - - public LollipopFixedWebView( - Context context, AttributeSet attrs, int defStyleAttr, boolean privateBrowsing) { - super(getFixedContext(context), attrs, defStyleAttr, privateBrowsing); - } - - public static Context getFixedContext(Context context) { - return context.createConfigurationContext(new Configuration()); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCover.java b/app/src/main/java/code/name/monkey/retromusic/views/LollipopFixedWebView.kt similarity index 52% rename from app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCover.java rename to app/src/main/java/code/name/monkey/retromusic/views/LollipopFixedWebView.kt index 346e0591a..d49092ee0 100644 --- a/app/src/main/java/code/name/monkey/retromusic/glide/audiocover/AudioFileCover.java +++ b/app/src/main/java/code/name/monkey/retromusic/views/LollipopFixedWebView.kt @@ -11,29 +11,22 @@ * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. */ +package code.name.monkey.retromusic.views -package code.name.monkey.retromusic.glide.audiocover; +import android.content.Context +import android.content.res.Configuration +import android.util.AttributeSet +import android.webkit.WebView -import androidx.annotation.Nullable; +class LollipopFixedWebView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = -1 +) : WebView(getFixedContext(context), attrs, defStyleAttr){ -/** @author Karim Abou Zeid (kabouzeid) */ -public class AudioFileCover { - public final String filePath; - - public AudioFileCover(String filePath) { - this.filePath = filePath; - } - - @Override - public int hashCode() { - return filePath.hashCode(); - } - - @Override - public boolean equals(@Nullable Object object) { - if (object instanceof AudioFileCover){ - return ((AudioFileCover) object).filePath.equals(filePath); + companion object { + fun getFixedContext(context: Context): Context { + return context.createConfigurationContext(Configuration()) + } } - return false; - } -} +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/views/NetworkImageView.java b/app/src/main/java/code/name/monkey/retromusic/views/NetworkImageView.java deleted file mode 100644 index 8f0916ecd..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/views/NetworkImageView.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.views; - -import android.content.Context; -import android.content.res.TypedArray; -import android.util.AttributeSet; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.bumptech.glide.Glide; - -import code.name.monkey.retromusic.R; - -/** @author Hemanth S (h4h13). */ -public class NetworkImageView extends CircularImageView { - - public NetworkImageView(@NonNull Context context) { - super(context); - init(context, null); - } - - public NetworkImageView(@NonNull Context context, @Nullable AttributeSet attrs) { - super(context, attrs); - init(context, attrs); - } - - public NetworkImageView( - @NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context, attrs); - } - - public void setImageUrl(@NonNull String imageUrl) { - setImageUrl(getContext(), imageUrl); - } - - public void setImageUrl(@NonNull Context context, @NonNull String imageUrl) { - Glide.with(context) - .load(imageUrl) - .error(R.drawable.ic_account) - .placeholder(R.drawable.ic_account) - .into(this); - } - - private void init(Context context, AttributeSet attributeSet) { - TypedArray attributes = - context.obtainStyledAttributes(attributeSet, R.styleable.NetworkImageView, 0, 0); - String url = attributes.getString(R.styleable.NetworkImageView_url_link); - setImageUrl(context, url); - attributes.recycle(); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/views/NetworkImageView.kt b/app/src/main/java/code/name/monkey/retromusic/views/NetworkImageView.kt new file mode 100644 index 000000000..8dd3887a5 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/NetworkImageView.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019 Hemanth Savarala. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + */ +package code.name.monkey.retromusic.views + +import android.content.Context +import android.util.AttributeSet +import androidx.core.content.withStyledAttributes +import code.name.monkey.retromusic.R +import com.bumptech.glide.Glide + +/** @author Hemanth S (h4h13). + */ +class NetworkImageView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = 0 +) : + CircularImageView(context, attrs, defStyleAttr) { + + init { + context.withStyledAttributes(attrs, R.styleable.NetworkImageView, 0, 0) { + val url = getString(R.styleable.NetworkImageView_url_link) + setImageUrl(context, url!!) + } + } + + fun setImageUrl(imageUrl: String) { + setImageUrl(context, imageUrl) + } + + private fun setImageUrl(context: Context, imageUrl: String) { + Glide.with(context) + .load(imageUrl) + .error(R.drawable.ic_account) + .placeholder(R.drawable.ic_account) + .into(this) + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/views/PermissionItem.kt b/app/src/main/java/code/name/monkey/retromusic/views/PermissionItem.kt index e80bf48aa..21df2fa0f 100644 --- a/app/src/main/java/code/name/monkey/retromusic/views/PermissionItem.kt +++ b/app/src/main/java/code/name/monkey/retromusic/views/PermissionItem.kt @@ -44,6 +44,6 @@ class PermissionItem @JvmOverloads constructor( } fun setButtonClick(callBack: () -> Unit) { - binding.button.setOnClickListener { callBack.invoke() } + binding.button.setOnClickListener { callBack() } } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/views/RetroShapeableImageView.kt b/app/src/main/java/code/name/monkey/retromusic/views/RetroShapeableImageView.kt index 18939a3ec..de9d391b3 100644 --- a/app/src/main/java/code/name/monkey/retromusic/views/RetroShapeableImageView.kt +++ b/app/src/main/java/code/name/monkey/retromusic/views/RetroShapeableImageView.kt @@ -15,6 +15,7 @@ package code.name.monkey.retromusic.views import android.content.Context import android.util.AttributeSet +import androidx.core.content.withStyledAttributes import code.name.monkey.retromusic.R import com.google.android.material.imageview.ShapeableImageView import com.google.android.material.shape.CornerFamily @@ -29,13 +30,12 @@ class RetroShapeableImageView @JvmOverloads constructor( init { - val typedArray = - context.obtainStyledAttributes(attrs, R.styleable.RetroShapeableImageView, defStyle, -1) - addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> - val radius = width / 2f - shapeAppearanceModel = ShapeAppearanceModel().withCornerSize(radius) + context.withStyledAttributes(attrs, R.styleable.RetroShapeableImageView, defStyle, -1) { + addOnLayoutChangeListener { _, _, _, _, _, _, _, _, _ -> + val radius = width / 2f + shapeAppearanceModel = ShapeAppearanceModel().withCornerSize(radius) + } } - typedArray.recycle() } private fun updateCornerSize(cornerSize: Float) { diff --git a/app/src/main/java/code/name/monkey/retromusic/views/SeekArc.java b/app/src/main/java/code/name/monkey/retromusic/views/SeekArc.java deleted file mode 100644 index 64abadf92..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/views/SeekArc.java +++ /dev/null @@ -1,509 +0,0 @@ -/* - * Copyright (c) 2020 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ -package code.name.monkey.retromusic.views; - -import android.content.Context; -import android.content.res.Resources; -import android.content.res.TypedArray; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.RectF; -import android.graphics.drawable.Drawable; -import android.util.AttributeSet; -import android.util.Log; -import android.view.MotionEvent; -import android.view.View; - -import code.name.monkey.retromusic.R; - -/** - * SeekArc.java - * - *

This is a class that functions much like a SeekBar but follows a circle path instead of a - * straight line. - * - * @author Neil Davies - */ -public class SeekArc extends View { - - private static final String TAG = SeekArc.class.getSimpleName(); - private static final int INVALID_PROGRESS_VALUE = -1; - private Paint mArcPaint; - // Internal variables - private int mArcRadius = 0; - private final RectF mArcRect = new RectF(); - /** - * The Width of the background arc for the SeekArc - */ - private int mArcWidth = 2; - /** Will the progress increase clockwise or anti-clockwise */ - private boolean mClockwise = true; - /** is the control enabled/touchable */ - private boolean mEnabled = true; - /** The Maximum value that this SeekArc can be set to */ - private int mMax = 100; - - private OnSeekArcChangeListener mOnSeekArcChangeListener; - /** The Current value that the SeekArc is set to */ - private int mProgress = 0; - - private Paint mProgressPaint; - private float mProgressSweep = 0; - /** The width of the progress line for this SeekArc */ - private int mProgressWidth = 4; - /** The rotation of the SeekArc- 0 is twelve o'clock */ - private int mRotation = 0; - /** Give the SeekArc rounded edges */ - private boolean mRoundedEdges = false; - /** The Angle to start drawing this Arc from */ - private int mStartAngle = 0; - /** The Angle through which to draw the arc (Max is 360) */ - private int mSweepAngle = 360; - /** The Drawable for the seek arc thumbnail */ - private Drawable mThumb; - - private int mThumbXPos; - private int mThumbYPos; - private float mTouchIgnoreRadius; - /** Enable touch inside the SeekArc */ - private boolean mTouchInside = true; - - private int mTranslateX; - private int mTranslateY; - - public SeekArc(Context context) { - super(context); - init(context, null, 0); - } - - public SeekArc(Context context, AttributeSet attrs) { - super(context, attrs); - init(context, attrs, R.attr.seekArcStyle); - } - - public SeekArc(Context context, AttributeSet attrs, int defStyle) { - super(context, attrs, defStyle); - init(context, attrs, defStyle); - } - - public int getArcColor() { - return mArcPaint.getColor(); - } - - public void setArcColor(int color) { - mArcPaint.setColor(color); - invalidate(); - } - - public int getArcRotation() { - return mRotation; - } - - public void setArcRotation(int mRotation) { - this.mRotation = mRotation; - updateThumbPosition(); - } - - public int getArcWidth() { - return mArcWidth; - } - - public void setArcWidth(int mArcWidth) { - this.mArcWidth = mArcWidth; - mArcPaint.setStrokeWidth(mArcWidth); - } - - public int getMax() { - return mMax; - } - - public void setMax(int mMax) { - this.mMax = mMax; - } - - public int getProgress() { - return mProgress; - } - - public void setProgress(int progress) { - updateProgress(progress, false); - } - - public int getProgressColor() { - return mProgressPaint.getColor(); - } - - public void setProgressColor(int color) { - mProgressPaint.setColor(color); - invalidate(); - } - - public int getProgressWidth() { - return mProgressWidth; - } - - public void setProgressWidth(int mProgressWidth) { - this.mProgressWidth = mProgressWidth; - mProgressPaint.setStrokeWidth(mProgressWidth); - } - - public int getStartAngle() { - return mStartAngle; - } - - public void setStartAngle(int mStartAngle) { - this.mStartAngle = mStartAngle; - updateThumbPosition(); - } - - public int getSweepAngle() { - return mSweepAngle; - } - - public void setSweepAngle(int mSweepAngle) { - this.mSweepAngle = mSweepAngle; - updateThumbPosition(); - } - - public boolean isClockwise() { - return mClockwise; - } - - public void setClockwise(boolean isClockwise) { - mClockwise = isClockwise; - } - - public boolean isEnabled() { - return mEnabled; - } - - public void setEnabled(boolean enabled) { - this.mEnabled = enabled; - } - - @Override - public boolean onTouchEvent(MotionEvent event) { - if (mEnabled) { - this.getParent().requestDisallowInterceptTouchEvent(true); - - switch (event.getAction()) { - case MotionEvent.ACTION_DOWN: - onStartTrackingTouch(); - updateOnTouch(event); - break; - case MotionEvent.ACTION_MOVE: - updateOnTouch(event); - break; - case MotionEvent.ACTION_UP: - case MotionEvent.ACTION_CANCEL: - onStopTrackingTouch(); - setPressed(false); - this.getParent().requestDisallowInterceptTouchEvent(false); - break; - } - return true; - } - return false; - } - - /** - * Sets a listener to receive notifications of changes to the SeekArc's progress level. Also - * provides notifications of when the user starts and stops a touch gesture within the SeekArc. - * - * @param l The seek bar notification listener - * @see SeekArc.OnSeekArcChangeListener - */ - public void setOnSeekArcChangeListener(OnSeekArcChangeListener l) { - mOnSeekArcChangeListener = l; - } - - public void setRoundedEdges(boolean isEnabled) { - mRoundedEdges = isEnabled; - if (mRoundedEdges) { - mArcPaint.setStrokeCap(Paint.Cap.ROUND); - mProgressPaint.setStrokeCap(Paint.Cap.ROUND); - } else { - mArcPaint.setStrokeCap(Paint.Cap.SQUARE); - mProgressPaint.setStrokeCap(Paint.Cap.SQUARE); - } - } - - public void setTouchInSide(boolean isEnabled) { - int thumbHalfheight = mThumb.getIntrinsicHeight() / 2; - int thumbHalfWidth = mThumb.getIntrinsicWidth() / 2; - mTouchInside = isEnabled; - if (mTouchInside) { - mTouchIgnoreRadius = (float) mArcRadius / 4; - } else { - // Don't use the exact radius makes interaction too tricky - mTouchIgnoreRadius = mArcRadius - Math.min(thumbHalfWidth, thumbHalfheight); - } - } - - @Override - protected void drawableStateChanged() { - super.drawableStateChanged(); - if (mThumb != null && mThumb.isStateful()) { - int[] state = getDrawableState(); - mThumb.setState(state); - } - invalidate(); - } - - @Override - protected void onDraw(Canvas canvas) { - if (!mClockwise) { - canvas.scale(-1, 1, mArcRect.centerX(), mArcRect.centerY()); - } - - // Draw the arcs - // The initial rotational offset -90 means we start at 12 o'clock - int mAngleOffset = -90; - final int arcStart = mStartAngle + mAngleOffset + mRotation; - final int arcSweep = mSweepAngle; - canvas.drawArc(mArcRect, arcStart, arcSweep, false, mArcPaint); - canvas.drawArc(mArcRect, arcStart, mProgressSweep, false, mProgressPaint); - - if (mEnabled) { - // Draw the thumb nail - canvas.translate(mTranslateX - mThumbXPos, mTranslateY - mThumbYPos); - mThumb.draw(canvas); - } - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - - final int height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec); - final int width = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec); - final int min = Math.min(width, height); - float top = 0; - float left = 0; - int arcDiameter = 0; - - mTranslateX = (int) (width * 0.5f); - mTranslateY = (int) (height * 0.5f); - - arcDiameter = min - getPaddingLeft(); - mArcRadius = arcDiameter / 2; - top = height / 2 - (arcDiameter / 2); - left = width / 2 - (arcDiameter / 2); - mArcRect.set(left, top, left + arcDiameter, top + arcDiameter); - - int arcStart = (int) mProgressSweep + mStartAngle + mRotation + 90; - mThumbXPos = (int) (mArcRadius * Math.cos(Math.toRadians(arcStart))); - mThumbYPos = (int) (mArcRadius * Math.sin(Math.toRadians(arcStart))); - - setTouchInSide(mTouchInside); - super.onMeasure(widthMeasureSpec, heightMeasureSpec); - } - - private int getProgressForAngle(double angle) { - int touchProgress = (int) Math.round(valuePerDegree() * angle); - - touchProgress = (touchProgress < 0) ? INVALID_PROGRESS_VALUE : touchProgress; - touchProgress = (touchProgress > mMax) ? INVALID_PROGRESS_VALUE : touchProgress; - return touchProgress; - } - - private double getTouchDegrees(float xPos, float yPos) { - float x = xPos - mTranslateX; - float y = yPos - mTranslateY; - // invert the x-coord if we are rotating anti-clockwise - x = (mClockwise) ? x : -x; - // convert to arc Angle - double angle = Math.toDegrees(Math.atan2(y, x) + (Math.PI / 2) - Math.toRadians(mRotation)); - if (angle < 0) { - angle = 360 + angle; - } - angle -= mStartAngle; - return angle; - } - - private boolean ignoreTouch(float xPos, float yPos) { - boolean ignore = false; - float x = xPos - mTranslateX; - float y = yPos - mTranslateY; - - float touchRadius = (float) Math.sqrt(((x * x) + (y * y))); - if (touchRadius < mTouchIgnoreRadius) { - ignore = true; - } - return ignore; - } - - private void init(Context context, AttributeSet attrs, int defStyle) { - - Log.d(TAG, "Initialising SeekArc"); - final Resources res = getResources(); - float density = context.getResources().getDisplayMetrics().density; - - // Defaults, may need to link this into theme settings - int arcColor = res.getColor(R.color.progress_gray); - int progressColor = res.getColor(R.color.default_blue_light); - int thumbHalfheight = 0; - int thumbHalfWidth = 0; - mThumb = res.getDrawable(R.drawable.switch_thumb_material); - // Convert progress width to pixels for current density - mProgressWidth = (int) (mProgressWidth * density); - - if (attrs != null) { - // Attribute initialization - final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SeekArc, defStyle, 0); - - Drawable thumb = a.getDrawable(R.styleable.SeekArc_thumb); - if (thumb != null) { - mThumb = thumb; - } - - thumbHalfheight = mThumb.getIntrinsicHeight() / 2; - thumbHalfWidth = mThumb.getIntrinsicWidth() / 2; - mThumb.setBounds(-thumbHalfWidth, -thumbHalfheight, thumbHalfWidth, thumbHalfheight); - - mMax = a.getInteger(R.styleable.SeekArc_max, mMax); - mProgress = a.getInteger(R.styleable.SeekArc_seekProgress, mProgress); - mProgressWidth = (int) a.getDimension(R.styleable.SeekArc_progressWidth, mProgressWidth); - mArcWidth = (int) a.getDimension(R.styleable.SeekArc_arcWidth, mArcWidth); - mStartAngle = a.getInt(R.styleable.SeekArc_startAngle, mStartAngle); - mSweepAngle = a.getInt(R.styleable.SeekArc_sweepAngle, mSweepAngle); - mRotation = a.getInt(R.styleable.SeekArc_rotation, mRotation); - mRoundedEdges = a.getBoolean(R.styleable.SeekArc_roundEdges, mRoundedEdges); - mTouchInside = a.getBoolean(R.styleable.SeekArc_touchInside, mTouchInside); - mClockwise = a.getBoolean(R.styleable.SeekArc_clockwise, mClockwise); - mEnabled = a.getBoolean(R.styleable.SeekArc_enabled, mEnabled); - - arcColor = a.getColor(R.styleable.SeekArc_arcColor, arcColor); - progressColor = a.getColor(R.styleable.SeekArc_progressColor, progressColor); - - a.recycle(); - } - - mProgress = Math.min(mProgress, mMax); - mProgress = Math.max(mProgress, 0); - - mSweepAngle = Math.min(mSweepAngle, 360); - mSweepAngle = Math.max(mSweepAngle, 0); - - mProgressSweep = (float) mProgress / mMax * mSweepAngle; - - mStartAngle = (mStartAngle > 360) ? 0 : mStartAngle; - mStartAngle = Math.max(mStartAngle, 0); - - mArcPaint = new Paint(); - mArcPaint.setColor(arcColor); - mArcPaint.setAntiAlias(true); - mArcPaint.setStyle(Paint.Style.STROKE); - mArcPaint.setStrokeWidth(mArcWidth); - // mArcPaint.setAlpha(45); - - mProgressPaint = new Paint(); - mProgressPaint.setColor(progressColor); - mProgressPaint.setAntiAlias(true); - mProgressPaint.setStyle(Paint.Style.STROKE); - mProgressPaint.setStrokeWidth(mProgressWidth); - - if (mRoundedEdges) { - mArcPaint.setStrokeCap(Paint.Cap.ROUND); - mProgressPaint.setStrokeCap(Paint.Cap.ROUND); - } - } - - private void onProgressRefresh(int progress, boolean fromUser) { - updateProgress(progress, fromUser); - } - - private void onStartTrackingTouch() { - if (mOnSeekArcChangeListener != null) { - mOnSeekArcChangeListener.onStartTrackingTouch(this); - } - } - - private void onStopTrackingTouch() { - if (mOnSeekArcChangeListener != null) { - mOnSeekArcChangeListener.onStopTrackingTouch(this); - } - } - - private void updateOnTouch(MotionEvent event) { - boolean ignoreTouch = ignoreTouch(event.getX(), event.getY()); - if (ignoreTouch) { - return; - } - setPressed(true); - double mTouchAngle = getTouchDegrees(event.getX(), event.getY()); - int progress = getProgressForAngle(mTouchAngle); - onProgressRefresh(progress, true); - } - - private void updateProgress(int progress, boolean fromUser) { - - if (progress == INVALID_PROGRESS_VALUE) { - return; - } - - progress = Math.min(progress, mMax); - progress = Math.max(progress, 0); - mProgress = progress; - - if (mOnSeekArcChangeListener != null) { - mOnSeekArcChangeListener.onProgressChanged(this, progress, fromUser); - } - - mProgressSweep = (float) progress / mMax * mSweepAngle; - - updateThumbPosition(); - - invalidate(); - } - - private void updateThumbPosition() { - int thumbAngle = (int) (mStartAngle + mProgressSweep + mRotation + 90); - mThumbXPos = (int) (mArcRadius * Math.cos(Math.toRadians(thumbAngle))); - mThumbYPos = (int) (mArcRadius * Math.sin(Math.toRadians(thumbAngle))); - } - - private float valuePerDegree() { - return (float) mMax / mSweepAngle; - } - - public interface OnSeekArcChangeListener { - - /** - * Notification that the progress level has changed. Clients can use the fromUser parameter to - * distinguish user-initiated changes from those that occurred programmatically. - * - * @param seekArc The SeekArc whose progress has changed - * @param progress The current progress level. This will be in the range 0..max where max was - * set by {@link ProgressArc#setMax(int)}. (The default value for max is 100.) - * @param fromUser True if the progress change was initiated by the user. - */ - void onProgressChanged(SeekArc seekArc, int progress, boolean fromUser); - - /** - * Notification that the user has started a touch gesture. Clients may want to use this to - * disable advancing the seekbar. - * - * @param seekArc The SeekArc in which the touch gesture began - */ - void onStartTrackingTouch(SeekArc seekArc); - - /** - * Notification that the user has finished a touch gesture. Clients may want to use this to - * re-enable advancing the seekarc. - * - * @param seekArc The SeekArc in which the touch gesture began - */ - void onStopTrackingTouch(SeekArc seekArc); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/views/StatusBarMarginFrameLayout.java b/app/src/main/java/code/name/monkey/retromusic/views/StatusBarMarginFrameLayout.java deleted file mode 100644 index 452807b8d..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/views/StatusBarMarginFrameLayout.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.views; - -import android.content.Context; -import android.util.AttributeSet; -import android.view.WindowInsets; -import android.widget.FrameLayout; - -import androidx.annotation.NonNull; - -public class StatusBarMarginFrameLayout extends FrameLayout { - - public StatusBarMarginFrameLayout(@NonNull Context context) { - super(context); - } - - public StatusBarMarginFrameLayout(@NonNull Context context, @NonNull AttributeSet attrs) { - super(context, attrs); - } - - public StatusBarMarginFrameLayout( - @NonNull Context context, @NonNull AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - } - - @NonNull - @Override - public WindowInsets onApplyWindowInsets(@NonNull WindowInsets insets) { - MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams(); - lp.topMargin = insets.getSystemWindowInsetTop(); - lp.bottomMargin = insets.getSystemWindowInsetBottom(); - setLayoutParams(lp); - return super.onApplyWindowInsets(insets); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/views/StatusBarView.java b/app/src/main/java/code/name/monkey/retromusic/views/StatusBarView.java deleted file mode 100644 index 21c0dc91b..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/views/StatusBarView.java +++ /dev/null @@ -1,56 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.views; - -import android.content.Context; -import android.content.res.Resources; -import android.util.AttributeSet; -import android.view.View; - -import androidx.annotation.NonNull; - -public class StatusBarView extends View { - - public StatusBarView(@NonNull Context context) { - super(context); - init(context); - } - - public StatusBarView(@NonNull Context context, @NonNull AttributeSet attrs) { - super(context, attrs); - init(context); - } - - public StatusBarView(@NonNull Context context, @NonNull AttributeSet attrs, int defStyleAttr) { - super(context, attrs, defStyleAttr); - init(context); - } - - public static int getStatusBarHeight(@NonNull Resources r) { - int result = 0; - int resourceId = r.getIdentifier("status_bar_height", "dimen", "android"); - if (resourceId > 0) { - result = r.getDimensionPixelSize(resourceId); - } - return result; - } - - private void init(Context context) {} - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec), getStatusBarHeight(getResources())); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/views/StatusBarView.kt b/app/src/main/java/code/name/monkey/retromusic/views/StatusBarView.kt new file mode 100644 index 000000000..d1979f12f --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/StatusBarView.kt @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2019 Hemanth Savarala. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + */ +package code.name.monkey.retromusic.views + +import android.content.Context +import android.content.res.Resources +import android.util.AttributeSet +import android.view.View + +class StatusBarView @JvmOverloads constructor( + context: Context, + attrs: AttributeSet? = null, + defStyleAttr: Int = -1 +) : View(context, attrs, defStyleAttr) { + + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + setMeasuredDimension( + MeasureSpec.getSize(widthMeasureSpec), getStatusBarHeight( + resources + ) + ) + } + + companion object { + fun getStatusBarHeight(r: Resources): Int { + var result = 0 + val resourceId = r.getIdentifier("status_bar_height", "dimen", "android") + if (resourceId > 0) { + result = r.getDimensionPixelSize(resourceId) + } + return result + } + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/views/VerticalTextView.java b/app/src/main/java/code/name/monkey/retromusic/views/VerticalTextView.java deleted file mode 100644 index 5c086aada..000000000 --- a/app/src/main/java/code/name/monkey/retromusic/views/VerticalTextView.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright (c) 2019 Hemanth Savarala. - * - * Licensed under the GNU General Public License v3 - * - * This is free software: you can redistribute it and/or modify it under - * the terms of the GNU General Public License as published by - * the Free Software Foundation either version 3 of the License, or (at your option) any later version. - * - * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; - * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - * See the GNU General Public License for more details. - */ - -package code.name.monkey.retromusic.views; - -import android.content.Context; -import android.graphics.Canvas; -import android.text.TextPaint; -import android.util.AttributeSet; -import android.view.Gravity; - -import androidx.appcompat.widget.AppCompatTextView; - -public class VerticalTextView extends AppCompatTextView { - final boolean topDown; - - public VerticalTextView(Context context, AttributeSet attrs) { - super(context, attrs); - final int gravity = getGravity(); - if (Gravity.isVertical(gravity) - && (gravity & Gravity.VERTICAL_GRAVITY_MASK) == Gravity.BOTTOM) { - setGravity((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) | Gravity.TOP); - topDown = false; - } else topDown = true; - } - - @Override - protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { - super.onMeasure(heightMeasureSpec, widthMeasureSpec); - setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth()); - } - - @Override - protected void onDraw(Canvas canvas) { - TextPaint textPaint = getPaint(); - textPaint.setColor(getCurrentTextColor()); - textPaint.drawableState = getDrawableState(); - - canvas.save(); - - if (topDown) { - canvas.translate(getWidth(), 0); - canvas.rotate(90); - } else { - canvas.translate(0, getHeight()); - canvas.rotate(-90); - } - - canvas.translate(getCompoundPaddingLeft(), getExtendedPaddingTop()); - - getLayout().draw(canvas); - canvas.restore(); - } -} diff --git a/app/src/main/java/code/name/monkey/retromusic/views/VerticalTextView.kt b/app/src/main/java/code/name/monkey/retromusic/views/VerticalTextView.kt new file mode 100644 index 000000000..f3538e918 --- /dev/null +++ b/app/src/main/java/code/name/monkey/retromusic/views/VerticalTextView.kt @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2019 Hemanth Savarala. + * + * Licensed under the GNU General Public License v3 + * + * This is free software: you can redistribute it and/or modify it under + * the terms of the GNU General Public License as published by + * the Free Software Foundation either version 3 of the License, or (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. + */ +package code.name.monkey.retromusic.views + +import android.content.Context +import android.graphics.Canvas +import android.util.AttributeSet +import android.view.Gravity +import androidx.appcompat.widget.AppCompatTextView + +class VerticalTextView(context: Context, attrs: AttributeSet?) : AppCompatTextView( + context, attrs +) { + private var topDown = false + override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { + super.onMeasure(heightMeasureSpec, widthMeasureSpec) + setMeasuredDimension(measuredHeight, measuredWidth) + } + + override fun onDraw(canvas: Canvas) { + val textPaint = paint + textPaint.color = currentTextColor + textPaint.drawableState = drawableState + canvas.save() + if (topDown) { + canvas.translate(width.toFloat(), 0f) + canvas.rotate(90f) + } else { + canvas.translate(0f, height.toFloat()) + canvas.rotate(-90f) + } + canvas.translate(compoundPaddingLeft.toFloat(), extendedPaddingTop.toFloat()) + layout.draw(canvas) + canvas.restore() + } + + init { + val gravity = gravity + topDown = if (Gravity.isVertical(gravity) + && gravity and Gravity.VERTICAL_GRAVITY_MASK == Gravity.BOTTOM + ) { + setGravity(gravity and Gravity.HORIZONTAL_GRAVITY_MASK or Gravity.TOP) + false + } else true + } +} \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/views/insets/InsetsConstraintLayout.kt b/app/src/main/java/code/name/monkey/retromusic/views/insets/InsetsConstraintLayout.kt index 4d2cb5569..a00be5a93 100644 --- a/app/src/main/java/code/name/monkey/retromusic/views/insets/InsetsConstraintLayout.kt +++ b/app/src/main/java/code/name/monkey/retromusic/views/insets/InsetsConstraintLayout.kt @@ -12,7 +12,7 @@ class InsetsConstraintLayout @JvmOverloads constructor( defStyleAttr: Int = 0 ) : ConstraintLayout(context, attrs, defStyleAttr) { init { - if (!RetroUtil.isLandscape()) + if (!RetroUtil.isLandscape) drawAboveSystemBarsWithPadding() } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/views/insets/InsetsLinearLayout.kt b/app/src/main/java/code/name/monkey/retromusic/views/insets/InsetsLinearLayout.kt index 8f1f67534..dda7c6d06 100644 --- a/app/src/main/java/code/name/monkey/retromusic/views/insets/InsetsLinearLayout.kt +++ b/app/src/main/java/code/name/monkey/retromusic/views/insets/InsetsLinearLayout.kt @@ -12,7 +12,7 @@ class InsetsLinearLayout @JvmOverloads constructor( defStyleAttr: Int = 0 ) : LinearLayout(context, attrs, defStyleAttr) { init { - if (!RetroUtil.isLandscape()) + if (!RetroUtil.isLandscape) drawAboveSystemBarsWithPadding() } } \ No newline at end of file diff --git a/app/src/main/java/code/name/monkey/retromusic/volume/AudioVolumeObserver.kt b/app/src/main/java/code/name/monkey/retromusic/volume/AudioVolumeObserver.kt index ad8247866..5b69f31b8 100644 --- a/app/src/main/java/code/name/monkey/retromusic/volume/AudioVolumeObserver.kt +++ b/app/src/main/java/code/name/monkey/retromusic/volume/AudioVolumeObserver.kt @@ -16,6 +16,7 @@ package code.name.monkey.retromusic.volume import android.content.Context import android.media.AudioManager import android.os.Handler +import android.os.Looper import android.provider.Settings import androidx.core.content.getSystemService @@ -25,7 +26,7 @@ class AudioVolumeObserver(private val context: Context) { private var contentObserver: AudioVolumeContentObserver? = null fun register(audioStreamType: Int, listener: OnAudioVolumeChangedListener) { - val handler = Handler() + val handler = Handler(Looper.getMainLooper()) // with this handler AudioVolumeContentObserver#onChange() // will be executed in the main thread // To execute in another thread you can use a Looper diff --git a/app/src/main/res/drawable-hdpi/default_album_art.webp b/app/src/main/res/drawable-hdpi/default_album_art.webp index 744489568..ef3872a29 100644 Binary files a/app/src/main/res/drawable-hdpi/default_album_art.webp and b/app/src/main/res/drawable-hdpi/default_album_art.webp differ diff --git a/app/src/main/res/drawable-hdpi/default_artist_art.webp b/app/src/main/res/drawable-hdpi/default_artist_art.webp index bb551b29e..176d3cf5c 100644 Binary files a/app/src/main/res/drawable-hdpi/default_artist_art.webp and b/app/src/main/res/drawable-hdpi/default_artist_art.webp differ diff --git a/app/src/main/res/drawable-hdpi/default_audio_art.webp b/app/src/main/res/drawable-hdpi/default_audio_art.webp index b5dc131ab..0f6e0a213 100644 Binary files a/app/src/main/res/drawable-hdpi/default_audio_art.webp and b/app/src/main/res/drawable-hdpi/default_audio_art.webp differ diff --git a/app/src/main/res/drawable-mdpi/default_album_art.webp b/app/src/main/res/drawable-mdpi/default_album_art.webp index 6ffd34f02..a6ce05dc2 100644 Binary files a/app/src/main/res/drawable-mdpi/default_album_art.webp and b/app/src/main/res/drawable-mdpi/default_album_art.webp differ diff --git a/app/src/main/res/drawable-mdpi/default_artist_art.webp b/app/src/main/res/drawable-mdpi/default_artist_art.webp index c5e115d22..6428e9b37 100644 Binary files a/app/src/main/res/drawable-mdpi/default_artist_art.webp and b/app/src/main/res/drawable-mdpi/default_artist_art.webp differ diff --git a/app/src/main/res/drawable-mdpi/default_audio_art.webp b/app/src/main/res/drawable-mdpi/default_audio_art.webp index ad86e0e0c..7f22b4309 100644 Binary files a/app/src/main/res/drawable-mdpi/default_audio_art.webp and b/app/src/main/res/drawable-mdpi/default_audio_art.webp differ diff --git a/app/src/main/res/drawable-night-hdpi/default_album_art.webp b/app/src/main/res/drawable-night-hdpi/default_album_art.webp new file mode 100644 index 000000000..744489568 Binary files /dev/null and b/app/src/main/res/drawable-night-hdpi/default_album_art.webp differ diff --git a/app/src/main/res/drawable-night-hdpi/default_artist_art.webp b/app/src/main/res/drawable-night-hdpi/default_artist_art.webp new file mode 100644 index 000000000..bb551b29e Binary files /dev/null and b/app/src/main/res/drawable-night-hdpi/default_artist_art.webp differ diff --git a/app/src/main/res/drawable-night-hdpi/default_audio_art.webp b/app/src/main/res/drawable-night-hdpi/default_audio_art.webp new file mode 100644 index 000000000..b5dc131ab Binary files /dev/null and b/app/src/main/res/drawable-night-hdpi/default_audio_art.webp differ diff --git a/app/src/main/res/drawable-night-mdpi/default_album_art.webp b/app/src/main/res/drawable-night-mdpi/default_album_art.webp new file mode 100644 index 000000000..6ffd34f02 Binary files /dev/null and b/app/src/main/res/drawable-night-mdpi/default_album_art.webp differ diff --git a/app/src/main/res/drawable-night-mdpi/default_artist_art.webp b/app/src/main/res/drawable-night-mdpi/default_artist_art.webp new file mode 100644 index 000000000..c5e115d22 Binary files /dev/null and b/app/src/main/res/drawable-night-mdpi/default_artist_art.webp differ diff --git a/app/src/main/res/drawable-night-mdpi/default_audio_art.webp b/app/src/main/res/drawable-night-mdpi/default_audio_art.webp new file mode 100644 index 000000000..ad86e0e0c Binary files /dev/null and b/app/src/main/res/drawable-night-mdpi/default_audio_art.webp differ diff --git a/app/src/main/res/drawable-night-xhdpi/default_album_art.webp b/app/src/main/res/drawable-night-xhdpi/default_album_art.webp new file mode 100644 index 000000000..0c50842cb Binary files /dev/null and b/app/src/main/res/drawable-night-xhdpi/default_album_art.webp differ diff --git a/app/src/main/res/drawable-night-xhdpi/default_artist_art.webp b/app/src/main/res/drawable-night-xhdpi/default_artist_art.webp new file mode 100644 index 000000000..d519bac07 Binary files /dev/null and b/app/src/main/res/drawable-night-xhdpi/default_artist_art.webp differ diff --git a/app/src/main/res/drawable-night-xhdpi/default_audio_art.webp b/app/src/main/res/drawable-night-xhdpi/default_audio_art.webp new file mode 100644 index 000000000..7ee8cdc52 Binary files /dev/null and b/app/src/main/res/drawable-night-xhdpi/default_audio_art.webp differ diff --git a/app/src/main/res/drawable-night-xxhdpi/default_album_art.webp b/app/src/main/res/drawable-night-xxhdpi/default_album_art.webp new file mode 100644 index 000000000..0b8fe94ac Binary files /dev/null and b/app/src/main/res/drawable-night-xxhdpi/default_album_art.webp differ diff --git a/app/src/main/res/drawable-night-xxhdpi/default_artist_art.webp b/app/src/main/res/drawable-night-xxhdpi/default_artist_art.webp new file mode 100644 index 000000000..ad8396ae7 Binary files /dev/null and b/app/src/main/res/drawable-night-xxhdpi/default_artist_art.webp differ diff --git a/app/src/main/res/drawable-night-xxhdpi/default_audio_art.webp b/app/src/main/res/drawable-night-xxhdpi/default_audio_art.webp new file mode 100644 index 000000000..4688f9dc3 Binary files /dev/null and b/app/src/main/res/drawable-night-xxhdpi/default_audio_art.webp differ diff --git a/app/src/main/res/drawable-night-xxxhdpi/default_album_art.webp b/app/src/main/res/drawable-night-xxxhdpi/default_album_art.webp new file mode 100644 index 000000000..c6e9b5a85 Binary files /dev/null and b/app/src/main/res/drawable-night-xxxhdpi/default_album_art.webp differ diff --git a/app/src/main/res/drawable-night-xxxhdpi/default_artist_art.webp b/app/src/main/res/drawable-night-xxxhdpi/default_artist_art.webp new file mode 100644 index 000000000..1acef0849 Binary files /dev/null and b/app/src/main/res/drawable-night-xxxhdpi/default_artist_art.webp differ diff --git a/app/src/main/res/drawable-night-xxxhdpi/default_audio_art.webp b/app/src/main/res/drawable-night-xxxhdpi/default_audio_art.webp new file mode 100644 index 000000000..357baba58 Binary files /dev/null and b/app/src/main/res/drawable-night-xxxhdpi/default_audio_art.webp differ diff --git a/app/src/main/res/drawable-xhdpi/default_album_art.webp b/app/src/main/res/drawable-xhdpi/default_album_art.webp index 0c50842cb..fc8e05c61 100644 Binary files a/app/src/main/res/drawable-xhdpi/default_album_art.webp and b/app/src/main/res/drawable-xhdpi/default_album_art.webp differ diff --git a/app/src/main/res/drawable-xhdpi/default_artist_art.webp b/app/src/main/res/drawable-xhdpi/default_artist_art.webp index d519bac07..3522db793 100644 Binary files a/app/src/main/res/drawable-xhdpi/default_artist_art.webp and b/app/src/main/res/drawable-xhdpi/default_artist_art.webp differ diff --git a/app/src/main/res/drawable-xhdpi/default_audio_art.webp b/app/src/main/res/drawable-xhdpi/default_audio_art.webp index 7ee8cdc52..458590631 100644 Binary files a/app/src/main/res/drawable-xhdpi/default_audio_art.webp and b/app/src/main/res/drawable-xhdpi/default_audio_art.webp differ diff --git a/app/src/main/res/drawable-xxhdpi/default_album_art.webp b/app/src/main/res/drawable-xxhdpi/default_album_art.webp index 0b8fe94ac..d8e3a1333 100644 Binary files a/app/src/main/res/drawable-xxhdpi/default_album_art.webp and b/app/src/main/res/drawable-xxhdpi/default_album_art.webp differ diff --git a/app/src/main/res/drawable-xxhdpi/default_artist_art.webp b/app/src/main/res/drawable-xxhdpi/default_artist_art.webp index ad8396ae7..946b95e2b 100644 Binary files a/app/src/main/res/drawable-xxhdpi/default_artist_art.webp and b/app/src/main/res/drawable-xxhdpi/default_artist_art.webp differ diff --git a/app/src/main/res/drawable-xxhdpi/default_audio_art.webp b/app/src/main/res/drawable-xxhdpi/default_audio_art.webp index 4688f9dc3..c025db78f 100644 Binary files a/app/src/main/res/drawable-xxhdpi/default_audio_art.webp and b/app/src/main/res/drawable-xxhdpi/default_audio_art.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/default_album_art.webp b/app/src/main/res/drawable-xxxhdpi/default_album_art.webp index c6e9b5a85..9c2f5c51b 100644 Binary files a/app/src/main/res/drawable-xxxhdpi/default_album_art.webp and b/app/src/main/res/drawable-xxxhdpi/default_album_art.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/default_artist_art.webp b/app/src/main/res/drawable-xxxhdpi/default_artist_art.webp index 1acef0849..c3a67b99f 100644 Binary files a/app/src/main/res/drawable-xxxhdpi/default_artist_art.webp and b/app/src/main/res/drawable-xxxhdpi/default_artist_art.webp differ diff --git a/app/src/main/res/drawable-xxxhdpi/default_audio_art.webp b/app/src/main/res/drawable-xxxhdpi/default_audio_art.webp index 357baba58..4398ea0f2 100644 Binary files a/app/src/main/res/drawable-xxxhdpi/default_audio_art.webp and b/app/src/main/res/drawable-xxxhdpi/default_audio_art.webp differ diff --git a/app/src/main/res/layout-land/activity_album_tag_editor.xml b/app/src/main/res/layout-land/activity_album_tag_editor.xml index 18b98d1dc..8db003e24 100644 --- a/app/src/main/res/layout-land/activity_album_tag_editor.xml +++ b/app/src/main/res/layout-land/activity_album_tag_editor.xml @@ -3,8 +3,8 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface" - android:fitsSystemWindows="true"> + android:fitsSystemWindows="true" + android:transitionGroup="true"> + app:layout_constraintTop_toTopOf="parent" /> diff --git a/app/src/main/res/layout-land/fragment_blur.xml b/app/src/main/res/layout-land/fragment_blur.xml index 6568c6ae8..4014ba939 100644 --- a/app/src/main/res/layout-land/fragment_blur.xml +++ b/app/src/main/res/layout-land/fragment_blur.xml @@ -4,7 +4,6 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface" android:clickable="true" android:focusable="true"> @@ -12,7 +11,6 @@ android:id="@+id/colorBackground" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface" android:scaleType="centerCrop" app:srcCompat="@color/black_color" /> diff --git a/app/src/main/res/layout-land/fragment_card_blur_player.xml b/app/src/main/res/layout-land/fragment_card_blur_player.xml index 51d6b643e..dddb02628 100644 --- a/app/src/main/res/layout-land/fragment_card_blur_player.xml +++ b/app/src/main/res/layout-land/fragment_card_blur_player.xml @@ -4,7 +4,6 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface" android:clickable="true" android:focusable="true"> @@ -12,7 +11,6 @@ android:id="@+id/colorBackground" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface" android:scaleType="centerCrop" app:srcCompat="@color/black_color" /> diff --git a/app/src/main/res/layout-sw600dp/fragment_playing_queue.xml b/app/src/main/res/layout-sw600dp/fragment_playing_queue.xml index 4192be524..b7e28dae5 100644 --- a/app/src/main/res/layout-sw600dp/fragment_playing_queue.xml +++ b/app/src/main/res/layout-sw600dp/fragment_playing_queue.xml @@ -4,7 +4,6 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface" android:orientation="vertical" tools:ignore="UnusedAttribute"> diff --git a/app/src/main/res/layout-xlarge-land/fragment_blur.xml b/app/src/main/res/layout-xlarge-land/fragment_blur.xml index c0899dca7..2dd353075 100644 --- a/app/src/main/res/layout-xlarge-land/fragment_blur.xml +++ b/app/src/main/res/layout-xlarge-land/fragment_blur.xml @@ -4,7 +4,6 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface" android:clickable="true" android:focusable="true"> @@ -12,7 +11,6 @@ android:id="@+id/colorBackground" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface" android:scaleType="centerCrop" app:srcCompat="@color/black_color" /> diff --git a/app/src/main/res/layout/activity_album_tag_editor.xml b/app/src/main/res/layout/activity_album_tag_editor.xml index e3c4e3745..ee7a664c8 100755 --- a/app/src/main/res/layout/activity_album_tag_editor.xml +++ b/app/src/main/res/layout/activity_album_tag_editor.xml @@ -3,9 +3,9 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface" android:fitsSystemWindows="true" - android:orientation="vertical"> + android:orientation="vertical" + android:transitionGroup="true"> @@ -89,7 +88,6 @@ android:id="@+id/albumArtistText" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@null" android:hint="@string/album_artist" android:inputType="text|textCapWords" android:maxLines="1" /> @@ -109,7 +107,6 @@ android:id="@+id/genreTitle" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@null" android:hint="@string/genre" android:inputType="text|textCapWords" android:maxLines="1" /> @@ -129,7 +126,6 @@ android:id="@+id/yearTitle" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="@null" android:hint="@string/year" android:inputType="text|number" android:maxLines="1" /> diff --git a/app/src/main/res/layout/activity_donation.xml b/app/src/main/res/layout/activity_donation.xml index 1eace20f0..8fafdadc7 100644 --- a/app/src/main/res/layout/activity_donation.xml +++ b/app/src/main/res/layout/activity_donation.xml @@ -4,7 +4,6 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface" android:fitsSystemWindows="true"> + app:titleTextAppearance="@style/ToolbarTextAppearanceNormal" /> diff --git a/app/src/main/res/layout/activity_drive_mode.xml b/app/src/main/res/layout/activity_drive_mode.xml index efdb49f7a..23849de05 100644 --- a/app/src/main/res/layout/activity_drive_mode.xml +++ b/app/src/main/res/layout/activity_drive_mode.xml @@ -11,7 +11,6 @@ ~ without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ~ See the GNU General Public License for more details. --> - - + app:layout_constraintTop_toTopOf="parent" /> - - + android:fitsSystemWindows="true"> - + + + + + + + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior"> - - - - - - - - - - - - + android:scrollbars="none" + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" /> + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_lock_screen.xml b/app/src/main/res/layout/activity_lock_screen.xml index 2f49f9b3a..1b6165daa 100644 --- a/app/src/main/res/layout/activity_lock_screen.xml +++ b/app/src/main/res/layout/activity_lock_screen.xml @@ -4,7 +4,6 @@ xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface" android:orientation="vertical"> + app:layout_constraintTop_toTopOf="parent" /> + app:titleTextColor="@color/md_white_1000" /> diff --git a/app/src/main/res/layout/activity_restore.xml b/app/src/main/res/layout/activity_restore.xml index e9e922f8d..8e3d5f561 100644 --- a/app/src/main/res/layout/activity_restore.xml +++ b/app/src/main/res/layout/activity_restore.xml @@ -34,7 +34,7 @@ android:text="@string/action_settings" /> + @@ -27,11 +28,11 @@ style="?attr/collapsingToolbarLayoutLargeStyle" android:layout_width="match_parent" android:layout_height="?attr/collapsingToolbarLayoutLargeSize" + app:collapsedTitleTextAppearance="@style/TextViewHeadline6" app:expandedTitleMarginBottom="24dp" app:expandedTitleMarginEnd="24dp" app:expandedTitleMarginStart="24dp" app:expandedTitleTextAppearance="@style/TextViewHeadline4" - app:collapsedTitleTextAppearance="@style/TextViewHeadline6" app:layout_scrollFlags="scroll|exitUntilCollapsed|snap|enterAlwaysCollapsed"> diff --git a/app/src/main/res/layout/cast_controller_layout.xml b/app/src/main/res/layout/cast_controller_layout.xml deleted file mode 100644 index 1047760d2..000000000 --- a/app/src/main/res/layout/cast_controller_layout.xml +++ /dev/null @@ -1,6 +0,0 @@ - - \ No newline at end of file diff --git a/app/src/main/res/layout/dialog_playlist.xml b/app/src/main/res/layout/dialog_playlist.xml index 5810be9c4..b1deabcdf 100644 --- a/app/src/main/res/layout/dialog_playlist.xml +++ b/app/src/main/res/layout/dialog_playlist.xml @@ -6,7 +6,6 @@ android:orientation="vertical" android:padding="16dp"> - + tools:srcCompat="@tools:sample/backgrounds/scenic[0]" /> @@ -77,7 +77,6 @@ app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/artistCoverContainer" - tools:ignore="MissingPrefix" tools:text="@tools:sample/full_names" /> @@ -12,7 +11,6 @@ android:id="@+id/colorBackground" android:layout_width="0dp" android:layout_height="0dp" - android:background="?attr/colorSurface" android:scaleType="centerCrop" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" diff --git a/app/src/main/res/layout/fragment_classic_player.xml b/app/src/main/res/layout/fragment_classic_player.xml index cfddbd87e..049309aab 100644 --- a/app/src/main/res/layout/fragment_classic_player.xml +++ b/app/src/main/res/layout/fragment_classic_player.xml @@ -82,7 +82,7 @@ android:theme="@style/TopCornerCardView" app:behavior_hideable="false" app:cardElevation="24dp" - app:layout_behavior="code.name.monkey.retromusic.RetroBottomSheetBehavior" + app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior" tools:peekHeight="0dp"> + app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"> @@ -43,7 +42,6 @@ android:id="@+id/tabLyrics" android:layout_width="match_parent" android:layout_height="wrap_content" - android:background="?attr/colorSurface" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" diff --git a/app/src/main/res/layout/fragment_main_recycler.xml b/app/src/main/res/layout/fragment_main_recycler.xml index 1e74d3aa1..65201612e 100644 --- a/app/src/main/res/layout/fragment_main_recycler.xml +++ b/app/src/main/res/layout/fragment_main_recycler.xml @@ -6,14 +6,6 @@ android:layout_height="match_parent" android:fitsSystemWindows="true"> - - + + diff --git a/app/src/main/res/layout/activity_whats_new.xml b/app/src/main/res/layout/fragment_whats_new.xml similarity index 61% rename from app/src/main/res/layout/activity_whats_new.xml rename to app/src/main/res/layout/fragment_whats_new.xml index 47948b164..afb6fca00 100644 --- a/app/src/main/res/layout/activity_whats_new.xml +++ b/app/src/main/res/layout/fragment_whats_new.xml @@ -3,26 +3,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" - android:background="?attr/colorSurface" - android:fitsSystemWindows="true"> - - - - - - + android:fitsSystemWindows="true" + android:paddingTop="8dp"> + android:background="?attr/colorSurface" + app:layout_behavior="com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior" + tools:layout="@layout/fragment_home" /> + app:gestureInsetBottomIgnored="true" + app:layout_behavior="com.google.android.material.bottomsheet.BottomSheetBehavior"> - + android:layout_height="wrap_content" /> diff --git a/app/src/main/res/navigation/library_graph.xml b/app/src/main/res/navigation/library_graph.xml index 52fa309ab..b592676a5 100644 --- a/app/src/main/res/navigation/library_graph.xml +++ b/app/src/main/res/navigation/library_graph.xml @@ -38,7 +38,7 @@ android:id="@+id/action_home" android:name="code.name.monkey.retromusic.fragments.home.HomeFragment" android:label="" - tools:layout="@layout/fragment_banner_home" /> + tools:layout="@layout/fragment_home" /> \ No newline at end of file diff --git a/app/src/main/res/navigation/main_graph.xml b/app/src/main/res/navigation/main_graph.xml index fd3d34b22..63ecf9dc7 100644 --- a/app/src/main/res/navigation/main_graph.xml +++ b/app/src/main/res/navigation/main_graph.xml @@ -120,7 +120,7 @@ android:id="@+id/action_home" android:name="code.name.monkey.retromusic.fragments.home.HomeFragment" android:label="" - tools:layout="@layout/fragment_banner_home" /> + tools:layout="@layout/fragment_home" /> إضافة "إضافة الى قائمة التشغيل" أضف وقت كلمات الأغاني - Added %d song(s) to %s + Added %1$d song(s) to %2$s "إضافة ١ من العناوين الى قائمة التشغيل الحالية" إضافة %1$d من العناوين الى قائمة التشغيل الحالية البوم diff --git a/app/src/main/res/values-b+es+419/strings.xml b/app/src/main/res/values-b+es+419/strings.xml index 126b50fd4..8ca945cd7 100644 --- a/app/src/main/res/values-b+es+419/strings.xml +++ b/app/src/main/res/values-b+es+419/strings.xml @@ -54,7 +54,7 @@ Agregar "Agregar a playlist" Agregar letras de marcos de tiempo - %d Cancion(es) añadidas a %s + %1$d Canción(es) añadidas a %2$s "Se agregó 1 canción a la cola de reproducción." Se agregó %1$d canción a la cola de reproducción. Álbum diff --git a/app/src/main/res/values-cs-rCZ/strings.xml b/app/src/main/res/values-cs-rCZ/strings.xml index 6ea65a6e0..9133fab37 100644 --- a/app/src/main/res/values-cs-rCZ/strings.xml +++ b/app/src/main/res/values-cs-rCZ/strings.xml @@ -54,7 +54,7 @@ Přidat "Přidat do seznamu skladeb" Add Time Framed Lyrics - Added %d song(s) to %s + Added %1$d song(s) to %2$s "Přidán 1 titul do fronty přehrávání." Přidány %1$d tituly do fronty přehrávání. Album diff --git a/app/src/main/res/values-de-rDE/strings.xml b/app/src/main/res/values-de-rDE/strings.xml index 739e2bd00..ed9211526 100644 --- a/app/src/main/res/values-de-rDE/strings.xml +++ b/app/src/main/res/values-de-rDE/strings.xml @@ -54,7 +54,7 @@ Hinzufügen "Zur Playlist hinzufügen" Synchronisierten Songtext hinzufügen - %d Titel(e) zu %s hinzugefügt + %1$d Titel(e) zu %2$s hinzugefügt "1 Titel wurde zur Wiedergabeliste hinzugefügt." %1$d Titel wurden zur Wiedergabeliste hinzugefügt. Album diff --git a/app/src/main/res/values-el-rGR/strings.xml b/app/src/main/res/values-el-rGR/strings.xml index 3ca4e1276..43323f4d5 100644 --- a/app/src/main/res/values-el-rGR/strings.xml +++ b/app/src/main/res/values-el-rGR/strings.xml @@ -54,7 +54,7 @@ Προσθήκη "Προσθήκη στη λίστα αναπαραγωγής" Προσθήκη Στίχων Με Χρονικό Πλαίσιο - Added %d song(s) to %s + Added %1$d song(s) to %2$s "Προστέθηκε 1 κομμάτι στην ουρά αναπαραγωγής." Προστέθηκαν %1$d κομμάτια στην ουρά αναπαραγωγής. Άλμπουμ diff --git a/app/src/main/res/values-es-rES/strings.xml b/app/src/main/res/values-es-rES/strings.xml index 6d5f5eed8..98992346a 100644 --- a/app/src/main/res/values-es-rES/strings.xml +++ b/app/src/main/res/values-es-rES/strings.xml @@ -54,7 +54,7 @@ Agregar "Agregar a lista de reproducción" Añadir letras sincronizadas - %d Canción(es) añadidas a %s + %1$d Canción(es) añadidas a %2$s "Se ha agregado 1 canción a la cola de reproducción." %1$d canciones agregadas a la cola de reproducción. Álbum diff --git a/app/src/main/res/values-fa-rIR/strings.xml b/app/src/main/res/values-fa-rIR/strings.xml index beb40c49c..e614462f3 100644 --- a/app/src/main/res/values-fa-rIR/strings.xml +++ b/app/src/main/res/values-fa-rIR/strings.xml @@ -54,7 +54,7 @@ ﺍﻓﺰﻭﺩﻥ "افزودن به لیست پخش" اضافه کردن متون دارای زمان - Added %d song(s) to %s + Added %1$d song(s) to %2$s "یک‌ مورد به لیست پخش اهنگ ها اضافه شد." مورد خاص به لیست پخش اهنگ اضافه شد. آلبوم diff --git a/app/src/main/res/values-fil-rPH/strings.xml b/app/src/main/res/values-fil-rPH/strings.xml index eacd1e105..1ac0f2af1 100644 --- a/app/src/main/res/values-fil-rPH/strings.xml +++ b/app/src/main/res/values-fil-rPH/strings.xml @@ -54,7 +54,7 @@ Magdagdag "Idagdag sa playlist" Mag-dagdag ng Time Framed Lyrics - Added %d song(s) to %s + Added %1$d song(s) to %2$s "Nadagdag ang 1 title sa playing queue." Nadagdag ang %1$d titles sa playing queue. Album diff --git a/app/src/main/res/values-fr-rFR/strings.xml b/app/src/main/res/values-fr-rFR/strings.xml index 605b95810..f6815b369 100644 --- a/app/src/main/res/values-fr-rFR/strings.xml +++ b/app/src/main/res/values-fr-rFR/strings.xml @@ -54,7 +54,7 @@ Ajouter "Ajouter à la liste de lecture" Ajouter des paroles synchronisées - Added %d song(s) to %s + Added %1$d song(s) to %2$d "1 titre a été ajouté à la file d'attente." %1$d titres ont été ajoutés à la file d\'attente. Album diff --git a/app/src/main/res/values-hi-rIN/strings.xml b/app/src/main/res/values-hi-rIN/strings.xml index 3e8e4f293..f8c207635 100644 --- a/app/src/main/res/values-hi-rIN/strings.xml +++ b/app/src/main/res/values-hi-rIN/strings.xml @@ -54,7 +54,7 @@ जोड़ें "प्लेलिस्ट में जोड़ें" Add Time Framed Lyrics - Added %d song(s) to %s + Added %1$d song(s) to %2$s "कतार मे 1 शीर्षक जोड़ा गया है।" कतार मे %1$d शीर्षक जोड़ा गया है। एल्बम diff --git a/app/src/main/res/values-hr-rHR/strings.xml b/app/src/main/res/values-hr-rHR/strings.xml index 2f8431408..43d1cf84c 100644 --- a/app/src/main/res/values-hr-rHR/strings.xml +++ b/app/src/main/res/values-hr-rHR/strings.xml @@ -54,7 +54,7 @@ Dodaj "Dodaj na popis" Add Time Framed Lyrics - Added %d song(s) to %s + Added %1$d song(s) to %2$s "Added 1 title to the playing queue." Added %1$d titles to the playing queue. Album diff --git a/app/src/main/res/values-hu-rHU/strings.xml b/app/src/main/res/values-hu-rHU/strings.xml index 1216fddc1..18469ebe8 100644 --- a/app/src/main/res/values-hu-rHU/strings.xml +++ b/app/src/main/res/values-hu-rHU/strings.xml @@ -54,7 +54,7 @@ Hozzáad "Hozzáadás lejátszási listához" Időzített dalszöveg hozzáadása - Added %d song(s) to %s + Added %1$d song(s) to %2$s "1 cím lett hozzáadva a lejátszási sorhoz." %1$d cím hozzáadva a lejátszási sorhoz. Album diff --git a/app/src/main/res/values-in-rID/strings.xml b/app/src/main/res/values-in-rID/strings.xml index 77aadeffd..d29ccad8f 100644 --- a/app/src/main/res/values-in-rID/strings.xml +++ b/app/src/main/res/values-in-rID/strings.xml @@ -54,7 +54,7 @@ Tambah "Tambah ke daftar putar" Tambah kerangka waktu pada lirik - Menambah %d lagu ke %s + Menambah %1$d lagu ke %2$s "1 lagu ditambah ke antrean." %1$d lagu telah ditambah ke antrean. Album diff --git a/app/src/main/res/values-it-rIT/strings.xml b/app/src/main/res/values-it-rIT/strings.xml index 6ac3cd16f..7f848d1cd 100644 --- a/app/src/main/res/values-it-rIT/strings.xml +++ b/app/src/main/res/values-it-rIT/strings.xml @@ -54,7 +54,7 @@ Aggiungi "Aggiungi alla playlist" Aggiungi testi sincronizzati - Aggiunta/e %d canzone/i a %s + Aggiunta/e %1$d canzone/i a %2$s "Aggiunto un brano alla coda." Aggiunti %1$d brani alla coda. Album diff --git a/app/src/main/res/values-ja-rJP/strings.xml b/app/src/main/res/values-ja-rJP/strings.xml index 6ddc898e8..30cbda947 100644 --- a/app/src/main/res/values-ja-rJP/strings.xml +++ b/app/src/main/res/values-ja-rJP/strings.xml @@ -54,7 +54,7 @@ 追加 "プレイリストに追加" 時間指定の歌詞を追加 - Added %d song(s) to %s + Added %1$d song(s) to %2$s "1曲が再生キューに追加されました" %1$d 曲が再生キューに追加されました アルバム diff --git a/app/src/main/res/values-kmr-rTR/strings.xml b/app/src/main/res/values-kmr-rTR/strings.xml index 4f1b2eb4c..af134c1c6 100644 --- a/app/src/main/res/values-kmr-rTR/strings.xml +++ b/app/src/main/res/values-kmr-rTR/strings.xml @@ -54,7 +54,7 @@ Tevlî bike "Tevlî rêzoka lêdanê bike" Dema peyvên stranê têxe - %d stran tevlî %s bû + %1$d stran tevlî %2$s bû "1 sernav li rêzeya lêdanê hate tevlîkirin." %1$d sernav li rêzeya lêdanê hate tevlîkirin. Album diff --git a/app/src/main/res/values-ko-rKR/strings.xml b/app/src/main/res/values-ko-rKR/strings.xml index 340d57398..2b95bdf11 100644 --- a/app/src/main/res/values-ko-rKR/strings.xml +++ b/app/src/main/res/values-ko-rKR/strings.xml @@ -54,7 +54,7 @@ 추가 "재생목록에 추가" Add Time Framed Lyrics - Added %d song(s) to %s + Added %1$d song(s) to %2$s "재생 대기열에 1곡이 추가되었습니다." 재생 대기열에 %1$d곡이 추가되었습니다. 앨범 diff --git a/app/src/main/res/values-ml-rIN/strings.xml b/app/src/main/res/values-ml-rIN/strings.xml index 2ce920be3..a167f6da1 100644 --- a/app/src/main/res/values-ml-rIN/strings.xml +++ b/app/src/main/res/values-ml-rIN/strings.xml @@ -54,9 +54,9 @@ Add "പ്ലേലിസ്റ്റിലേക്ക് ആഡ് ചെയ്യുക" Add Time Framed Lyrics - Added %d song(s) to %s + Added %1$d song(s) to %2$s "Added 1 title to the playing queue." - Added %1$d titles to the playing queue. + Added %d titles to the playing queue. Album Song diff --git a/app/src/main/res/values-my-rMM/strings.xml b/app/src/main/res/values-my-rMM/strings.xml index 3e498f57a..d66ea1ada 100644 --- a/app/src/main/res/values-my-rMM/strings.xml +++ b/app/src/main/res/values-my-rMM/strings.xml @@ -54,7 +54,7 @@ ထည့်မည် "အောက်ပါ Playlist သို့ထည့်မည်" Add Time Framed Lyrics - Added %d song(s) to %s + Added %1$d song(s) to %2$s "နားထောင်နေသည့်စာရင်းထဲသို့ ၁ ပုဒ်ပေါင်းထည့်ခဲ့သည်" နားထောင်နေသည့်စာရင်းထဲသို့ %1$d ပုဒ်ပေါင်းထည့်ခဲ့သည် Album diff --git a/app/src/main/res/values-night-v31/styles.xml b/app/src/main/res/values-night-v31/styles.xml index 3f0129227..ed9ee3788 100644 --- a/app/src/main/res/values-night-v31/styles.xml +++ b/app/src/main/res/values-night-v31/styles.xml @@ -1,4 +1,8 @@ + + diff --git a/app/src/main/res/values-nl-rNL/strings.xml b/app/src/main/res/values-nl-rNL/strings.xml index c0bda382e..492fb1ffc 100644 --- a/app/src/main/res/values-nl-rNL/strings.xml +++ b/app/src/main/res/values-nl-rNL/strings.xml @@ -54,7 +54,7 @@ Toevoegen "Toevogen aan afspeellijst" Add Time Framed Lyrics - Added %d song(s) to %s + Added %1$d song(s) to %2$s "1 titel aan afspeel wachtrij toegevoegd." %1$d titels toegevoegd aan afspeel wachtrij Album diff --git a/app/src/main/res/values-pl-rPL/strings.xml b/app/src/main/res/values-pl-rPL/strings.xml index 148e3446a..f18f06ef4 100644 --- a/app/src/main/res/values-pl-rPL/strings.xml +++ b/app/src/main/res/values-pl-rPL/strings.xml @@ -54,7 +54,7 @@ Dodaj "Dodaj do playlisty" Dodaj tekst z ramką czasową - Dodano %d utwór(y/ów) do %s + Dodano %1$d utwór(y/ów) do %2$s "Dodano tytuł do kolejki odtwarzania" Dodano %1$d tytułów do kolejki Album diff --git a/app/src/main/res/values-pt-rBR/strings.xml b/app/src/main/res/values-pt-rBR/strings.xml index 2e66098aa..005cdfee7 100644 --- a/app/src/main/res/values-pt-rBR/strings.xml +++ b/app/src/main/res/values-pt-rBR/strings.xml @@ -54,7 +54,7 @@ Adicionar "Adicionar à playlist" Adicionar Letras Sincronizadas - %d música(s) adicionada(s) para %s + %1$d música(s) adicionada(s) para %2$s "1 música foi adicionada à fila." %1$d músicas foram adicionadas à fila. Álbum diff --git a/app/src/main/res/values-pt-rPT/strings.xml b/app/src/main/res/values-pt-rPT/strings.xml index b5c02e563..3d704b3ae 100644 --- a/app/src/main/res/values-pt-rPT/strings.xml +++ b/app/src/main/res/values-pt-rPT/strings.xml @@ -54,7 +54,7 @@ Adicionar "Adicionar à lista" Adicionar letras do cronograma - Added %d song(s) to %s + Added %1$d song(s) to %2$s "Adicionada 1 música à fila." Adicionadas %1$d músicas à fila. Álbum diff --git a/app/src/main/res/values-ro-rRO/strings.xml b/app/src/main/res/values-ro-rRO/strings.xml index 4529e9124..bfeb3bebb 100644 --- a/app/src/main/res/values-ro-rRO/strings.xml +++ b/app/src/main/res/values-ro-rRO/strings.xml @@ -54,7 +54,7 @@ Adaugă "Adaugă la playlist" Add Time Framed Lyrics - Added %d song(s) to %s + Added %1$d song(s) to %2$s "Adăugat 1 titlu la coada de redare." Adăugate %1$d titluri la coada de redare Album diff --git a/app/src/main/res/values-ru-rRU/strings.xml b/app/src/main/res/values-ru-rRU/strings.xml index 2fe0a7d79..adfded31c 100644 --- a/app/src/main/res/values-ru-rRU/strings.xml +++ b/app/src/main/res/values-ru-rRU/strings.xml @@ -54,7 +54,7 @@ Добавить "Добавить в плейлист" Добавить синхронизированный текст - Добавлено %d песни в %s + Добавлено %1$d песни в %2$s "В очередь добавлен 1 трек" В очередь добавлено %1$d треков. Альбом diff --git a/app/src/main/res/values-sr-rSP/strings.xml b/app/src/main/res/values-sr-rSP/strings.xml index 6ed84bac9..29eb44cc6 100644 --- a/app/src/main/res/values-sr-rSP/strings.xml +++ b/app/src/main/res/values-sr-rSP/strings.xml @@ -54,7 +54,7 @@ Dodaj "Dodaj na plejlistu" Add Time Framed Lyrics - Added %d song(s) to %s + Added %1$d song(s) to %2$s "Dodata je 1 pesma na plejlistu" Dodato %1$d pesama na plejlistu Album diff --git a/app/src/main/res/values-sv-rSE/strings.xml b/app/src/main/res/values-sv-rSE/strings.xml index e247ed7ba..97ef11496 100644 --- a/app/src/main/res/values-sv-rSE/strings.xml +++ b/app/src/main/res/values-sv-rSE/strings.xml @@ -54,7 +54,7 @@ Lägg till "Lägg till i spellista" Add Time Framed Lyrics - Added %d song(s) to %s + Added %1$d song(s) to %2$s "Lade till en titel i spelkön." Lade till %1$d titlar i spelkön. Album diff --git a/app/src/main/res/values-ta-rIN/strings.xml b/app/src/main/res/values-ta-rIN/strings.xml index 0d722bbd7..eed361c0c 100644 --- a/app/src/main/res/values-ta-rIN/strings.xml +++ b/app/src/main/res/values-ta-rIN/strings.xml @@ -54,7 +54,7 @@ சேர் "பாடல் வரிசையில் சேர்" Add Time Framed Lyrics - Added %d song(s) to %s + Added %1$d song(s) to %2$s "Added 1 title to the playing queue." Added %1$d titles to the playing queue. Album diff --git a/app/src/main/res/values-te-rIN/strings.xml b/app/src/main/res/values-te-rIN/strings.xml index 71a1f4f90..267e00c22 100644 --- a/app/src/main/res/values-te-rIN/strings.xml +++ b/app/src/main/res/values-te-rIN/strings.xml @@ -114,7 +114,7 @@ సృష్టించు ప్లేజాబితా%1$sసృష్టించబడింది. సభ్యులు మరియు సహాయకులు - ప్రస్తుతం% 2 by s ద్వారా%1$sవింటున్నారు. + ప్రస్తుతం %2$s ద్వారా %1$d వింటున్నారు. కైండా డార్క్ ప్లేజాబితాను తొలగించండి %1$s ప్లేజాబితాను తొలగించాలా?]]> diff --git a/app/src/main/res/values-th-rTH/strings.xml b/app/src/main/res/values-th-rTH/strings.xml index 5eefea6e1..ee386ec56 100644 --- a/app/src/main/res/values-th-rTH/strings.xml +++ b/app/src/main/res/values-th-rTH/strings.xml @@ -54,7 +54,7 @@ เพิ่ม "เพิ่มชื่อเพลย์ลิสต์" เพิ่มเนื้อเพลงในกรอบเวลา - Added %d song(s) to %s + Added %1$d song(s) to %2$s "เพิ่ม 1 ชื่อเข้าคิวเพลง" เพิ่ม %1$d ชื่อเข้าคิวเพลง อัลบัม diff --git a/app/src/main/res/values-tr-rTR/strings.xml b/app/src/main/res/values-tr-rTR/strings.xml index 581f4e20d..88705c83a 100644 --- a/app/src/main/res/values-tr-rTR/strings.xml +++ b/app/src/main/res/values-tr-rTR/strings.xml @@ -54,7 +54,7 @@ Ekle "Oynatma listesine ekle" Zaman Dilimli Sözleri Ekle - Added %d song(s) to %s + Added %1$d song(s) to %2$s "Kuyruğa 1 parça eklendi." %1$d şarkı kuyruğuna eklendi. Albüm diff --git a/app/src/main/res/values-uk-rUA/strings.xml b/app/src/main/res/values-uk-rUA/strings.xml index b64d3c982..21e15a645 100644 --- a/app/src/main/res/values-uk-rUA/strings.xml +++ b/app/src/main/res/values-uk-rUA/strings.xml @@ -54,7 +54,7 @@ Додати "Додати до списку відтворення" Додати часові розмежування тексту - Added %d song(s) to %s + Added %1$d song(s) to %2$s "Додано 1 композицію до черги відтворення." Додано %1$d композицій до черги відтворення. Альбом diff --git a/app/src/main/res/values-v27/styles_parents.xml b/app/src/main/res/values-v27/styles_parents.xml index 3197150b8..e50cf022c 100644 --- a/app/src/main/res/values-v27/styles_parents.xml +++ b/app/src/main/res/values-v27/styles_parents.xml @@ -35,7 +35,7 @@ @style/MaterialButtonTheme @color/darkColorSurface - @color/window_color_dark + ?colorSurface @style/Widget.Material3.CardView.Elevated @color/elevationOverlay @drawable/popup_background @@ -45,7 +45,7 @@ @drawable/round_selector @drawable/rect_selector @style/ThemeOverlay.AppCompat.Light - @color/md_white_1000 + ?colorSurface @style/Widget.ActionButton.Overflow @style/MaterialAlertDialogTheme @style/MaterialButtonTheme diff --git a/app/src/main/res/values-v31/styles.xml b/app/src/main/res/values-v31/styles.xml index 050f979f4..7437a1528 100644 --- a/app/src/main/res/values-v31/styles.xml +++ b/app/src/main/res/values-v31/styles.xml @@ -8,8 +8,11 @@ @style/Widget.Material3.CardView.Elevated @style/MaterialButtonTheme @drawable/popup_background + ?attr/colorSurface + diff --git a/app/src/main/res/values-vi-rVN/strings.xml b/app/src/main/res/values-vi-rVN/strings.xml index add26ce29..e1e7d9a60 100644 --- a/app/src/main/res/values-vi-rVN/strings.xml +++ b/app/src/main/res/values-vi-rVN/strings.xml @@ -54,7 +54,7 @@ Thêm "Thêm vào danh sách phát" Thêm lời theo thời gian - Added %d song(s) to %s + Added %1$d song(s) to %2$s "Đã thêm 1 bài vào danh sách chờ phát." Đã thêm %1$d bài vào danh sách chờ phát. Album diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml index 668aa912a..d35752872 100644 --- a/app/src/main/res/values-zh-rCN/strings.xml +++ b/app/src/main/res/values-zh-rCN/strings.xml @@ -54,7 +54,7 @@ 添加 "加入播放列表" 添加同步歌词 - 已将 %d 首歌添加到 %s + 已将 %1$d 首歌添加到 %2$s "已添加 1 首歌到播放队列。" 已添加 %1$d 首歌到播放队列。 专辑 diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index eebbfc8c4..d735a6243 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -54,7 +54,7 @@ 新增 "新增到播放清單" 新增同步歌詞 - 新增 %d 首歌到 %s + 新增 %1$d 首歌到 %2$s "已新增 1 首歌到播放佇列。" 已新增 %1$d 首歌到播放佇列。 專輯 diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index a1122eb94..9de012247 100755 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -8,7 +8,7 @@ @string/horizontal_flip @string/hinge @string/stack - @string/classic + @string/simple @@ -53,8 +53,8 @@ - @string/collapsing - @string/simple + @string/expanded + @string/compact @@ -229,5 +229,4 @@ @string/choose_image @string/remove_image - Collapsing \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4ea24f5a0..c22f24b3a 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -9,6 +9,7 @@ Add to favorites Add to playing queue Add to playlist + Cancel Cast Clear playing queue Cycle repeat mode @@ -54,7 +55,7 @@ Add "Add to playlist" Add Time Framed Lyrics - Added %d song(s) to %s + Added %1$d song(s) to %2$s "Added 1 title to the playing queue." Added %1$d titles to the playing queue. Album @@ -103,6 +104,7 @@ Please enter your valid GitHub password Please enter an issue title Please enter your valid GitHub username + Bug report successful An unexpected error occurred. Sorry you found this bug, if it keeps crashing \"Clear app data\" or send an Email Send using GitHub account Buy now @@ -126,6 +128,7 @@ Clear queue Color Colors + Compact Composer Copied device info to clipboard. Couldn\u2019t create playlist. @@ -168,6 +171,7 @@ Edit Synced Lyrics Empty Equalizer + Expanded FAQ Favorites Finish last song @@ -355,7 +359,7 @@ Album cover theme Album cover skip Colored app shortcuts - App bar mode + Header style Reduce volume on focus loss Fade audio Auto-download artist images @@ -535,5 +539,4 @@ You have to select at least one category. You will be forwarded to the issue tracker website. Your account data is only used for authentication. - Bug report successful diff --git a/app/src/main/res/values/styles.xml b/app/src/main/res/values/styles.xml index cf42f1d20..9452f0649 100644 --- a/app/src/main/res/values/styles.xml +++ b/app/src/main/res/values/styles.xml @@ -7,7 +7,7 @@ - + @@ -142,23 +142,7 @@ center_vertical|end - +