Merge branch 'RetroMusicPlayer:dev' into feat/audio_focus_2

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -20,16 +20,12 @@ import android.appwidget.AppWidgetProvider
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent import android.content.Intent
import android.content.res.Resources
import android.graphics.* import android.graphics.*
import android.graphics.drawable.BitmapDrawable import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import android.widget.RemoteViews import android.widget.RemoteViews
import androidx.core.content.ContextCompat 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.appthemehelper.util.VersionUtils
import code.name.monkey.retromusic.App
import code.name.monkey.retromusic.R import code.name.monkey.retromusic.R
import code.name.monkey.retromusic.model.Song import code.name.monkey.retromusic.model.Song
import code.name.monkey.retromusic.service.MusicService import code.name.monkey.retromusic.service.MusicService
@ -116,11 +112,11 @@ abstract class BaseAppWidget : AppWidgetProvider() {
abstract fun performUpdate(service: MusicService, appWidgetIds: IntArray?) 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) { return if (bitmap == null) {
ContextCompat.getDrawable(App.getContext(), R.drawable.default_audio_art)!! ContextCompat.getDrawable(context, R.drawable.default_audio_art)!!
} else { } else {
BitmapDrawable(resources, bitmap) BitmapDrawable(context.resources, bitmap)
} }
} }
@ -171,16 +167,6 @@ abstract class BaseAppWidget : AppWidgetProvider() {
return rounded 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( protected fun composeRoundedRectPath(
rect: RectF, rect: RectF,
tl: Float, tl: Float,

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -22,11 +22,12 @@ import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable import android.graphics.drawable.Drawable
import androidx.annotation.DimenRes import androidx.annotation.DimenRes
import androidx.annotation.DrawableRes import androidx.annotation.DrawableRes
import androidx.core.graphics.drawable.toBitmap
fun Context.scaledDrawableResources( fun Context.scaledDrawableResources(
@DrawableRes id: Int, @DrawableRes id: Int,
@DimenRes width: Int, @DimenRes width: Int,
@DimenRes height: Int @DimenRes height: Int,
): Drawable { ): Drawable {
val w = resources.getDimension(width).toInt() val w = resources.getDimension(width).toInt()
val h = resources.getDimension(height).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) 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 { fun Drawable.getBitmapDrawable(): Bitmap {
val bmp = Bitmap.createBitmap(bounds.width(), bounds.height(), Bitmap.Config.ARGB_8888) val bmp = Bitmap.createBitmap(bounds.width(), bounds.height(), Bitmap.Config.ARGB_8888)
val canvas = Canvas(bmp) val canvas = Canvas(bmp)

View file

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

View file

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

View file

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

View file

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

View file

@ -16,10 +16,13 @@ package code.name.monkey.retromusic.extensions
import android.animation.Animator import android.animation.Animator
import android.animation.ObjectAnimator import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.graphics.drawable.BitmapDrawable
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import android.view.ViewTreeObserver import android.view.ViewTreeObserver
import android.view.animation.AnimationUtils
import android.view.inputmethod.InputMethodManager import android.view.inputmethod.InputMethodManager
import android.widget.EditText import android.widget.EditText
import androidx.annotation.LayoutRes 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.appthemehelper.util.TintHelper
import code.name.monkey.retromusic.util.PreferenceUtil import code.name.monkey.retromusic.util.PreferenceUtil
import code.name.monkey.retromusic.util.RetroUtil import code.name.monkey.retromusic.util.RetroUtil
import com.google.android.material.bottomnavigation.BottomNavigationView
import com.google.android.material.bottomsheet.BottomSheetBehavior import com.google.android.material.bottomsheet.BottomSheetBehavior
import dev.chrisbanes.insetter.applyInsetter import dev.chrisbanes.insetter.applyInsetter
@ -58,6 +62,84 @@ fun EditText.appHandleColor(): EditText {
return this 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 { fun View.translateYAnimate(value: Float): Animator {
return ObjectAnimator.ofFloat(this, "translationY", value) return ObjectAnimator.ofFloat(this, "translationY", value)
.apply { .apply {
@ -122,7 +204,7 @@ fun View.focusAndShowKeyboard() {
*/ */
fun View.drawAboveSystemBars(onlyPortrait: Boolean = true) { fun View.drawAboveSystemBars(onlyPortrait: Boolean = true) {
if (PreferenceUtil.isFullScreenMode) return if (PreferenceUtil.isFullScreenMode) return
if (onlyPortrait && RetroUtil.isLandscape()) return if (onlyPortrait && RetroUtil.isLandscape) return
applyInsetter { applyInsetter {
type(navigationBars = true) { type(navigationBars = true) {
margin() margin()

View file

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

View file

@ -14,13 +14,10 @@
*/ */
package code.name.monkey.retromusic.fragments.about package code.name.monkey.retromusic.fragments.about
import android.content.Intent
import android.content.pm.PackageManager import android.content.pm.PackageManager
import android.os.Bundle import android.os.Bundle
import android.view.View import android.view.View
import androidx.core.app.ShareCompat import androidx.core.app.ShareCompat
import androidx.core.net.toUri
import androidx.core.view.updatePadding
import androidx.fragment.app.Fragment import androidx.fragment.app.Fragment
import androidx.recyclerview.widget.DefaultItemAnimator import androidx.recyclerview.widget.DefaultItemAnimator
import androidx.recyclerview.widget.LinearLayoutManager 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.R
import code.name.monkey.retromusic.adapter.ContributorAdapter import code.name.monkey.retromusic.adapter.ContributorAdapter
import code.name.monkey.retromusic.databinding.FragmentAboutBinding 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.fragments.LibraryViewModel
import code.name.monkey.retromusic.util.NavigationUtil 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 import org.koin.androidx.viewmodel.ext.android.sharedViewModel
class AboutFragment : Fragment(R.layout.fragment_about), View.OnClickListener { 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()) binding.aboutContent.cardOther.version.setSummary(getAppVersion())
setUpView() setUpView()
loadContributors() 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) { binding.aboutContent.root.applyInsetter {
val i = Intent(Intent.ACTION_VIEW) type(navigationBars = true) {
i.data = url.toUri() padding()
i.flags = Intent.FLAG_ACTIVITY_NEW_TASK }
startActivity(i) }
} }
private fun setUpView() { private fun setUpView() {
binding.aboutContent.cardRetroInfo.appGithub.setOnClickListener(this) binding.aboutContent.cardRetroInfo.appGithub.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.faqLink.setOnClickListener(this) binding.aboutContent.cardRetroInfo.faqLink.setOnClickListener(this)
binding.aboutContent.cardSocial.telegramLink.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.appRate.setOnClickListener(this) binding.aboutContent.cardRetroInfo.appRate.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.appTranslation.setOnClickListener(this) binding.aboutContent.cardRetroInfo.appTranslation.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.appShare.setOnClickListener(this) binding.aboutContent.cardRetroInfo.appShare.setOnClickListener(this)
binding.aboutContent.cardRetroInfo.donateLink.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.instagramLink.setOnClickListener(this)
binding.aboutContent.cardSocial.twitterLink.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.changelog.setOnClickListener(this)
binding.aboutContent.cardOther.openSource.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) { override fun onClick(view: View) {

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

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