Merge pull request #1176 from prathameshmm02/dev
Bug Fixes & Improvements
This commit is contained in:
commit
6924e5de01
137 changed files with 1043 additions and 1837 deletions
|
@ -9,7 +9,7 @@ android {
|
||||||
|
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
minSdkVersion 21
|
minSdkVersion 21
|
||||||
targetSdkVersion 30
|
targetSdkVersion 31
|
||||||
|
|
||||||
renderscriptTargetApi 29//must match target sdk and build tools
|
renderscriptTargetApi 29//must match target sdk and build tools
|
||||||
vectorDrawables.useSupportLibrary = true
|
vectorDrawables.useSupportLibrary = true
|
||||||
|
@ -126,7 +126,7 @@ 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.2'
|
implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.3'
|
||||||
|
|
||||||
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"
|
||||||
|
@ -142,7 +142,7 @@ dependencies {
|
||||||
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"
|
||||||
|
|
||||||
def koin_version = '3.1.3'
|
def koin_version = '3.1.4'
|
||||||
implementation "io.insert-koin:koin-core:$koin_version"
|
implementation "io.insert-koin:koin-core:$koin_version"
|
||||||
implementation "io.insert-koin:koin-android:$koin_version"
|
implementation "io.insert-koin:koin-android:$koin_version"
|
||||||
|
|
||||||
|
@ -157,7 +157,7 @@ dependencies {
|
||||||
implementation 'com.anjlab.android.iab.v3:library:2.0.3'
|
implementation 'com.anjlab.android.iab.v3:library:2.0.3'
|
||||||
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:1.7.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.7'
|
||||||
implementation 'cat.ereza:customactivityoncrash:2.3.0'
|
implementation 'cat.ereza:customactivityoncrash:2.3.0'
|
||||||
debugImplementation 'com.github.amitshekhariitbhu:Android-Debug-Database:1.0.6'
|
debugImplementation 'com.github.amitshekhariitbhu:Android-Debug-Database:1.0.6'
|
||||||
|
|
|
@ -262,6 +262,7 @@
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="true"
|
android:exported="true"
|
||||||
android:label="@string/app_name"
|
android:label="@string/app_name"
|
||||||
|
android:foregroundServiceType="mediaPlayback"
|
||||||
tools:ignore="ExportedService">
|
tools:ignore="ExportedService">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.media.browse.MediaBrowserService" />
|
<action android:name="android.media.browse.MediaBrowserService" />
|
||||||
|
|
|
@ -37,6 +37,7 @@ 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 + " != ''"
|
||||||
|
|
||||||
|
@Suppress("Deprecation")
|
||||||
val baseProjection = arrayOf(
|
val baseProjection = arrayOf(
|
||||||
BaseColumns._ID, // 0
|
BaseColumns._ID, // 0
|
||||||
MediaStore.Audio.AudioColumns.TITLE, // 1
|
MediaStore.Audio.AudioColumns.TITLE, // 1
|
||||||
|
@ -118,6 +119,8 @@ const val ALBUM_GRID_SIZE_LAND = "album_grid_size_land"
|
||||||
const val SONG_GRID_SIZE_LAND = "song_grid_size_land"
|
const val SONG_GRID_SIZE_LAND = "song_grid_size_land"
|
||||||
const val ARTIST_GRID_SIZE = "artist_grid_size"
|
const val ARTIST_GRID_SIZE = "artist_grid_size"
|
||||||
const val ARTIST_GRID_SIZE_LAND = "artist_grid_size_land"
|
const val ARTIST_GRID_SIZE_LAND = "artist_grid_size_land"
|
||||||
|
const val PLAYLIST_GRID_SIZE = "playlist_grid_size"
|
||||||
|
const val PLAYLIST_GRID_SIZE_LAND = "playlist_grid_size_land"
|
||||||
const val COLORED_APP_SHORTCUTS = "colored_app_shortcuts"
|
const val COLORED_APP_SHORTCUTS = "colored_app_shortcuts"
|
||||||
const val AUDIO_DUCKING = "audio_ducking"
|
const val AUDIO_DUCKING = "audio_ducking"
|
||||||
const val LAST_ADDED_CUTOFF = "last_added_interval"
|
const val LAST_ADDED_CUTOFF = "last_added_interval"
|
||||||
|
|
|
@ -29,18 +29,10 @@ public class LanguageContextWrapper extends ContextWrapper {
|
||||||
LocaleList localeList = new LocaleList(newLocale);
|
LocaleList localeList = new LocaleList(newLocale);
|
||||||
LocaleList.setDefault(localeList);
|
LocaleList.setDefault(localeList);
|
||||||
configuration.setLocales(localeList);
|
configuration.setLocales(localeList);
|
||||||
|
|
||||||
context = context.createConfigurationContext(configuration);
|
|
||||||
|
|
||||||
} else if (VersionUtils.INSTANCE.hasLollipop()) {
|
|
||||||
configuration.setLocale(newLocale);
|
|
||||||
context = context.createConfigurationContext(configuration);
|
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
configuration.locale = newLocale;
|
configuration.setLocale(newLocale);
|
||||||
res.updateConfiguration(configuration, res.getDisplayMetrics());
|
|
||||||
}
|
}
|
||||||
|
context = context.createConfigurationContext(configuration);
|
||||||
return new LanguageContextWrapper(context);
|
return new LanguageContextWrapper(context);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,46 +0,0 @@
|
||||||
package code.name.monkey.retromusic
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import android.util.AttributeSet
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import androidx.recyclerview.widget.LinearLayoutManager
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
|
|
||||||
class PeekingLinearLayoutManager : LinearLayoutManager {
|
|
||||||
@JvmOverloads
|
|
||||||
constructor(
|
|
||||||
context: Context?,
|
|
||||||
@RecyclerView.Orientation orientation: Int = RecyclerView.VERTICAL,
|
|
||||||
reverseLayout: Boolean = false
|
|
||||||
) : super(context, orientation, reverseLayout)
|
|
||||||
|
|
||||||
constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int, defStyleRes: Int) : super(
|
|
||||||
context,
|
|
||||||
attrs,
|
|
||||||
defStyleAttr,
|
|
||||||
defStyleRes
|
|
||||||
)
|
|
||||||
|
|
||||||
override fun generateDefaultLayoutParams() =
|
|
||||||
scaledLayoutParams(super.generateDefaultLayoutParams())
|
|
||||||
|
|
||||||
override fun generateLayoutParams(lp: ViewGroup.LayoutParams?) =
|
|
||||||
scaledLayoutParams(super.generateLayoutParams(lp))
|
|
||||||
|
|
||||||
override fun generateLayoutParams(c: Context?, attrs: AttributeSet?) =
|
|
||||||
scaledLayoutParams(super.generateLayoutParams(c, attrs))
|
|
||||||
|
|
||||||
private fun scaledLayoutParams(layoutParams: RecyclerView.LayoutParams) =
|
|
||||||
layoutParams.apply {
|
|
||||||
when (orientation) {
|
|
||||||
HORIZONTAL -> width = (horizontalSpace * ratio).toInt()
|
|
||||||
VERTICAL -> height = (verticalSpace * ratio).toInt()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val horizontalSpace get() = width - paddingStart - paddingEnd
|
|
||||||
|
|
||||||
private val verticalSpace get() = height - paddingTop - paddingBottom
|
|
||||||
|
|
||||||
private val ratio = 0.8f // change to 0.7f for 70%
|
|
||||||
}
|
|
|
@ -82,6 +82,7 @@ class LockScreenActivity : AbsMusicServiceActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Suppress("Deprecation")
|
||||||
private fun lockScreenInit() {
|
private fun lockScreenInit() {
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
||||||
setShowWhenLocked(true)
|
setShowWhenLocked(true)
|
||||||
|
|
|
@ -132,7 +132,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
|
||||||
permissionDeniedMessage!!,
|
permissionDeniedMessage!!,
|
||||||
Snackbar.LENGTH_INDEFINITE
|
Snackbar.LENGTH_INDEFINITE
|
||||||
)
|
)
|
||||||
.setAction(code.name.monkey.retromusic.R.string.action_grant) { requestPermissions() }
|
.setAction(R.string.action_grant) { requestPermissions() }
|
||||||
.setActionTextColor(ThemeStore.accentColor(this)).show()
|
.setActionTextColor(ThemeStore.accentColor(this)).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
|
||||||
|
@ -140,7 +140,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
|
||||||
snackBarContainer,
|
snackBarContainer,
|
||||||
permissionDeniedMessage!!,
|
permissionDeniedMessage!!,
|
||||||
Snackbar.LENGTH_INDEFINITE
|
Snackbar.LENGTH_INDEFINITE
|
||||||
).setAction(code.name.monkey.retromusic.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(
|
||||||
|
@ -172,7 +172,7 @@ 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()
|
||||||
val imm = getSystemService<InputMethodManager>()?.hideSoftInputFromWindow(v.windowToken, 0)
|
getSystemService<InputMethodManager>()?.hideSoftInputFromWindow(v.windowToken, 0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,8 @@ import android.view.WindowManager
|
||||||
import androidx.annotation.ColorInt
|
import androidx.annotation.ColorInt
|
||||||
import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode
|
import androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode
|
||||||
import androidx.core.os.ConfigurationCompat
|
import androidx.core.os.ConfigurationCompat
|
||||||
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
import code.name.monkey.appthemehelper.ATH
|
import code.name.monkey.appthemehelper.ATH
|
||||||
import code.name.monkey.appthemehelper.ThemeStore
|
import code.name.monkey.appthemehelper.ThemeStore
|
||||||
import code.name.monkey.appthemehelper.common.ATHToolbarActivity
|
import code.name.monkey.appthemehelper.common.ATHToolbarActivity
|
||||||
|
@ -118,12 +120,11 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
|
||||||
if (statusBar != null) {
|
if (statusBar != null) {
|
||||||
when {
|
when {
|
||||||
VersionUtils.hasMarshmallow() -> statusBar.setBackgroundColor(color)
|
VersionUtils.hasMarshmallow() -> statusBar.setBackgroundColor(color)
|
||||||
VersionUtils.hasLollipop() -> statusBar.setBackgroundColor(
|
else -> statusBar.setBackgroundColor(
|
||||||
ColorUtil.darkenColor(
|
ColorUtil.darkenColor(
|
||||||
color
|
color
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
else -> statusBar.setBackgroundColor(color)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
when {
|
when {
|
||||||
|
@ -193,16 +194,20 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setImmersiveFullscreen() {
|
private fun setImmersiveFullscreen() {
|
||||||
val flags =
|
|
||||||
(View.SYSTEM_UI_FLAG_LAYOUT_STABLE or View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or View.SYSTEM_UI_FLAG_FULLSCREEN or View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY)
|
|
||||||
|
|
||||||
if (PreferenceUtil.isFullScreenMode) {
|
if (PreferenceUtil.isFullScreenMode) {
|
||||||
window.decorView.systemUiVisibility = flags
|
WindowInsetsControllerCompat(window, window.decorView).apply {
|
||||||
|
systemBarsBehavior =
|
||||||
|
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||||
|
hide(WindowInsetsCompat.Type.systemBars())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun exitFullscreen() {
|
private fun exitFullscreen() {
|
||||||
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_VISIBLE
|
WindowInsetsControllerCompat(window, window.decorView).apply {
|
||||||
|
systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||||
|
show(WindowInsetsCompat.Type.systemBars())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun run() {
|
override fun run() {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import android.content.pm.PackageManager;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
|
|
||||||
import androidx.annotation.IntRange;
|
import androidx.annotation.IntRange;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
@ -16,19 +17,16 @@ import code.name.monkey.retromusic.util.PreferenceUtil;
|
||||||
public class DeviceInfo {
|
public class DeviceInfo {
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
private final String[] abis =
|
private final String[] abis =
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
|
Build.SUPPORTED_ABIS;
|
||||||
? Build.SUPPORTED_ABIS
|
|
||||||
: new String[] {Build.CPU_ABI, Build.CPU_ABI2};
|
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
private final String[] abis32Bits =
|
private final String[] abis32Bits =
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? Build.SUPPORTED_32_BIT_ABIS : null;
|
Build.SUPPORTED_32_BIT_ABIS;
|
||||||
|
|
||||||
@SuppressLint("NewApi")
|
@SuppressLint("NewApi")
|
||||||
private final String[] abis64Bits =
|
private final String[] abis64Bits =
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP ? Build.SUPPORTED_64_BIT_ABIS : null;
|
Build.SUPPORTED_64_BIT_ABIS;
|
||||||
|
|
||||||
private final String baseTheme;
|
private final String baseTheme;
|
||||||
|
|
||||||
|
@ -138,6 +136,7 @@ public class DeviceInfo {
|
||||||
+ "</table>\n";
|
+ "</table>\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "App version: "
|
return "App version: "
|
||||||
|
|
|
@ -49,9 +49,9 @@ class TagWriter {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun writeTagsToFiles(context: Context, info: AudioTagInfo) =
|
suspend fun writeTagsToFiles(context: Context, info: AudioTagInfo) {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
try {
|
kotlin.runCatching {
|
||||||
var artwork: Artwork? = null
|
var artwork: Artwork? = null
|
||||||
var albumArtFile: File? = null
|
var albumArtFile: File? = null
|
||||||
if (info.artworkInfo?.artwork != null) {
|
if (info.artworkInfo?.artwork != null) {
|
||||||
|
@ -113,18 +113,18 @@ class TagWriter {
|
||||||
deleteAlbumArt(context, info.artworkInfo!!.albumId)
|
deleteAlbumArt(context, info.artworkInfo!!.albumId)
|
||||||
}
|
}
|
||||||
scan(context, info.filePaths)
|
scan(context, info.filePaths)
|
||||||
} catch (e: Exception) {
|
}.onFailure {
|
||||||
e.printStackTrace()
|
it.printStackTrace()
|
||||||
scan(context, null)
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@RequiresApi(Build.VERSION_CODES.R)
|
@RequiresApi(Build.VERSION_CODES.R)
|
||||||
suspend fun writeTagsToFilesR(context: Context, info: AudioTagInfo) =
|
suspend fun writeTagsToFilesR(context: Context, info: AudioTagInfo): List<File> =
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
val cacheFiles = mutableListOf<File>()
|
val cacheFiles = mutableListOf<File>()
|
||||||
try {
|
kotlin.runCatching {
|
||||||
var artwork: Artwork? = null
|
var artwork: Artwork? = null
|
||||||
var albumArtFile: File? = null
|
var albumArtFile: File? = null
|
||||||
if (info.artworkInfo?.artwork != null) {
|
if (info.artworkInfo?.artwork != null) {
|
||||||
|
@ -193,11 +193,10 @@ class TagWriter {
|
||||||
} else if (deletedArtwork) {
|
} else if (deletedArtwork) {
|
||||||
deleteAlbumArt(context, info.artworkInfo!!.albumId)
|
deleteAlbumArt(context, info.artworkInfo!!.albumId)
|
||||||
}
|
}
|
||||||
cacheFiles
|
}.onFailure {
|
||||||
} catch (e: Exception) {
|
it.printStackTrace()
|
||||||
e.printStackTrace()
|
|
||||||
listOf()
|
|
||||||
}
|
}
|
||||||
|
cacheFiles
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -14,6 +14,7 @@
|
||||||
*/
|
*/
|
||||||
package code.name.monkey.retromusic.adapter
|
package code.name.monkey.retromusic.adapter
|
||||||
|
|
||||||
|
import android.os.SystemClock
|
||||||
import android.view.LayoutInflater
|
import android.view.LayoutInflater
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
|
@ -51,6 +52,8 @@ class HomeAdapter(
|
||||||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), IArtistClickListener, IAlbumClickListener,
|
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), IArtistClickListener, IAlbumClickListener,
|
||||||
IGenreClickListener {
|
IGenreClickListener {
|
||||||
|
|
||||||
|
private var mLastClickTime: Long = 0
|
||||||
|
|
||||||
private var list = listOf<Home>()
|
private var list = listOf<Home>()
|
||||||
|
|
||||||
override fun getItemViewType(position: Int): Int {
|
override fun getItemViewType(position: Int): Int {
|
||||||
|
@ -194,6 +197,10 @@ class HomeAdapter(
|
||||||
itemView.findViewById<TextView>(R.id.message).apply {
|
itemView.findViewById<TextView>(R.id.message).apply {
|
||||||
setTextColor(color)
|
setTextColor(color)
|
||||||
setOnClickListener {
|
setOnClickListener {
|
||||||
|
if (SystemClock.elapsedRealtime() - mLastClickTime < 1000){
|
||||||
|
return@setOnClickListener
|
||||||
|
}
|
||||||
|
mLastClickTime = SystemClock.elapsedRealtime()
|
||||||
MusicPlayerRemote.playNext((home.arrayList as List<Song>).subList(0, 8))
|
MusicPlayerRemote.playNext((home.arrayList as List<Song>).subList(0, 8))
|
||||||
if (!MusicPlayerRemote.isPlaying) {
|
if (!MusicPlayerRemote.isPlaying) {
|
||||||
MusicPlayerRemote.playNextSong()
|
MusicPlayerRemote.playNextSong()
|
||||||
|
|
|
@ -137,16 +137,6 @@ class SearchAdapter(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSongs(playlist: Playlist): List<Song> {
|
|
||||||
val songs = mutableListOf<Song>()
|
|
||||||
if (playlist is AbsSmartPlaylist) {
|
|
||||||
songs.addAll(playlist.getSongs())
|
|
||||||
} else {
|
|
||||||
songs.addAll(PlaylistSongsLoader.getPlaylistSongList(activity, playlist.id))
|
|
||||||
}
|
|
||||||
return songs
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
override fun getItemCount(): Int {
|
||||||
return dataSet.size
|
return dataSet.size
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,66 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 Hemanth Savarla.
|
|
||||||
*
|
|
||||||
* Licensed under the GNU General Public License v3
|
|
||||||
*
|
|
||||||
* This is free software: you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package code.name.monkey.retromusic.adapter
|
|
||||||
|
|
||||||
import android.app.Activity
|
|
||||||
import android.view.LayoutInflater
|
|
||||||
import android.view.View
|
|
||||||
import android.view.ViewGroup
|
|
||||||
import android.widget.TextView
|
|
||||||
import androidx.recyclerview.widget.RecyclerView
|
|
||||||
import code.name.monkey.retromusic.R
|
|
||||||
import code.name.monkey.retromusic.extensions.hide
|
|
||||||
import code.name.monkey.retromusic.model.Contributor
|
|
||||||
import code.name.monkey.retromusic.util.RetroUtil
|
|
||||||
import code.name.monkey.retromusic.views.RetroShapeableImageView
|
|
||||||
|
|
||||||
class TranslatorsAdapter(
|
|
||||||
private var contributors: List<Contributor>
|
|
||||||
) : RecyclerView.Adapter<TranslatorsAdapter.ViewHolder>() {
|
|
||||||
|
|
||||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
|
||||||
return ViewHolder(
|
|
||||||
LayoutInflater.from(parent.context).inflate(
|
|
||||||
R.layout.item_contributor,
|
|
||||||
parent,
|
|
||||||
false
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
|
||||||
val contributor = contributors[position]
|
|
||||||
holder.bindData(contributor)
|
|
||||||
holder.itemView.setOnClickListener {
|
|
||||||
RetroUtil.openUrl(it?.context as Activity, contributors[position].link)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getItemCount(): Int {
|
|
||||||
return contributors.size
|
|
||||||
}
|
|
||||||
|
|
||||||
inner class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
|
|
||||||
val title: TextView = itemView.findViewById(R.id.title)
|
|
||||||
val text: TextView = itemView.findViewById(R.id.text)
|
|
||||||
val image: RetroShapeableImageView = itemView.findViewById(R.id.icon)
|
|
||||||
|
|
||||||
internal fun bindData(contributor: Contributor) {
|
|
||||||
title.text = contributor.name
|
|
||||||
text.text = contributor.summary
|
|
||||||
image.hide()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -27,13 +27,13 @@ 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.fragments.AlbumCoverStyle
|
import code.name.monkey.retromusic.fragments.AlbumCoverStyle
|
||||||
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
|
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
|
||||||
|
import code.name.monkey.retromusic.fragments.base.goToLyrics
|
||||||
import code.name.monkey.retromusic.glide.GlideApp
|
import code.name.monkey.retromusic.glide.GlideApp
|
||||||
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
import code.name.monkey.retromusic.glide.RetroGlideExtension
|
||||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
||||||
import code.name.monkey.retromusic.misc.CustomFragmentStatePagerAdapter
|
import code.name.monkey.retromusic.misc.CustomFragmentStatePagerAdapter
|
||||||
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 code.name.monkey.retromusic.util.NavigationUtil
|
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
|
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
|
||||||
|
@ -127,7 +127,8 @@ class AlbumCoverPagerAdapter(
|
||||||
setTitle(song.title)
|
setTitle(song.title)
|
||||||
setMessage(if (data.isNullOrEmpty()) "No lyrics found" else data)
|
setMessage(if (data.isNullOrEmpty()) "No lyrics found" else data)
|
||||||
setNegativeButton(R.string.synced_lyrics) { _, _ ->
|
setNegativeButton(R.string.synced_lyrics) { _, _ ->
|
||||||
NavigationUtil.goToLyrics(requireActivity())
|
|
||||||
|
goToLyrics(requireActivity())
|
||||||
}
|
}
|
||||||
show()
|
show()
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ import android.view.View
|
||||||
import android.view.ViewGroup
|
import android.view.ViewGroup
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.setPadding
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
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
|
||||||
|
@ -29,6 +30,7 @@ import code.name.monkey.retromusic.adapter.base.MediaEntryViewHolder
|
||||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||||
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
||||||
import code.name.monkey.retromusic.db.toSongs
|
import code.name.monkey.retromusic.db.toSongs
|
||||||
|
import code.name.monkey.retromusic.extensions.dipToPix
|
||||||
import code.name.monkey.retromusic.extensions.hide
|
import code.name.monkey.retromusic.extensions.hide
|
||||||
import code.name.monkey.retromusic.extensions.show
|
import code.name.monkey.retromusic.extensions.show
|
||||||
import code.name.monkey.retromusic.glide.GlideApp
|
import code.name.monkey.retromusic.glide.GlideApp
|
||||||
|
@ -42,7 +44,7 @@ import code.name.monkey.retromusic.util.MusicUtil
|
||||||
|
|
||||||
class PlaylistAdapter(
|
class PlaylistAdapter(
|
||||||
override val activity: FragmentActivity,
|
override val activity: FragmentActivity,
|
||||||
private var dataSet: List<PlaylistWithSongs>,
|
var dataSet: List<PlaylistWithSongs>,
|
||||||
private var itemLayoutRes: Int,
|
private var itemLayoutRes: Int,
|
||||||
ICabHolder: ICabHolder?,
|
ICabHolder: ICabHolder?,
|
||||||
private val listener: IPlaylistClickListener
|
private val listener: IPlaylistClickListener
|
||||||
|
@ -94,7 +96,12 @@ class PlaylistAdapter(
|
||||||
holder.menu?.show()
|
holder.menu?.show()
|
||||||
}
|
}
|
||||||
GlideApp.with(activity)
|
GlideApp.with(activity)
|
||||||
.load(PlaylistPreview(playlist))
|
.load(
|
||||||
|
if (itemLayoutRes == R.layout.item_list) {
|
||||||
|
holder.image?.setPadding(activity.dipToPix(8F).toInt())
|
||||||
|
R.drawable.ic_playlist_play
|
||||||
|
} else PlaylistPreview(playlist)
|
||||||
|
)
|
||||||
.playlistOptions()
|
.playlistOptions()
|
||||||
.into(holder.image!!)
|
.into(holder.image!!)
|
||||||
}
|
}
|
||||||
|
|
|
@ -188,7 +188,7 @@ class PlayingQueueAdapter(
|
||||||
private const val UP_NEXT = 2
|
private const val UP_NEXT = 2
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onSwipeItem(holder: ViewHolder, position: Int, result: Int): SwipeResultAction? {
|
override fun onSwipeItem(holder: ViewHolder, position: Int, result: Int): SwipeResultAction {
|
||||||
return if (result == SwipeableItemConstants.RESULT_CANCELED) {
|
return if (result == SwipeableItemConstants.RESULT_CANCELED) {
|
||||||
SwipeResultActionDefault()
|
SwipeResultActionDefault()
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -1,62 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2020 Hemanth Savarla.
|
|
||||||
*
|
|
||||||
* Licensed under the GNU General Public License v3
|
|
||||||
*
|
|
||||||
* This is free software: you can redistribute it and/or modify it
|
|
||||||
* under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
package code.name.monkey.retromusic.adapter.song
|
|
||||||
|
|
||||||
import android.view.MenuItem
|
|
||||||
import android.view.View
|
|
||||||
import androidx.fragment.app.FragmentActivity
|
|
||||||
import code.name.monkey.retromusic.R
|
|
||||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
|
||||||
import code.name.monkey.retromusic.db.toSongEntity
|
|
||||||
import code.name.monkey.retromusic.dialogs.RemoveSongFromPlaylistDialog
|
|
||||||
import code.name.monkey.retromusic.interfaces.ICabHolder
|
|
||||||
import code.name.monkey.retromusic.model.Song
|
|
||||||
|
|
||||||
class PlaylistSongAdapter(
|
|
||||||
private val playlist: PlaylistEntity,
|
|
||||||
activity: FragmentActivity,
|
|
||||||
dataSet: MutableList<Song>,
|
|
||||||
itemLayoutRes: Int,
|
|
||||||
iCabHolder: ICabHolder?
|
|
||||||
) : SongAdapter(activity, dataSet, itemLayoutRes, iCabHolder) {
|
|
||||||
|
|
||||||
init {
|
|
||||||
this.setMultiSelectMenuRes(R.menu.menu_cannot_delete_single_songs_playlist_songs_selection)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun createViewHolder(view: View): SongAdapter.ViewHolder {
|
|
||||||
return ViewHolder(view)
|
|
||||||
}
|
|
||||||
|
|
||||||
open inner class ViewHolder(itemView: View) : SongAdapter.ViewHolder(itemView) {
|
|
||||||
|
|
||||||
override var songMenuRes: Int
|
|
||||||
get() = R.menu.menu_item_playlist_song
|
|
||||||
set(value) {
|
|
||||||
super.songMenuRes = value
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onSongMenuItemClick(item: MenuItem): Boolean {
|
|
||||||
when (item.itemId) {
|
|
||||||
R.id.action_remove_from_playlist -> {
|
|
||||||
RemoveSongFromPlaylistDialog.create(song.toSongEntity(playlist.playListId))
|
|
||||||
.show(activity.supportFragmentManager, "REMOVE_FROM_PLAYLIST")
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return super.onSongMenuItemClick(item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -42,6 +42,6 @@ class LastAddedShortcutType(context: Context) : BaseShortcutType(context) {
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val id: String
|
val id: String
|
||||||
get() = BaseShortcutType.ID_PREFIX + "last_added"
|
get() = ID_PREFIX + "last_added"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -40,6 +40,6 @@ class TopTracksShortcutType(context: Context) : BaseShortcutType(context) {
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
val id: String
|
val id: String
|
||||||
get() = BaseShortcutType.ID_PREFIX + "top_tracks"
|
get() = ID_PREFIX + "top_tracks"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,6 +24,7 @@ import android.text.TextUtils
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
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.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
|
||||||
|
@ -61,7 +62,7 @@ class AppWidgetBig : BaseAppWidget() {
|
||||||
context,
|
context,
|
||||||
R.drawable.ic_skip_next,
|
R.drawable.ic_skip_next,
|
||||||
MaterialValueHelper.getPrimaryTextColor(context, false)
|
MaterialValueHelper.getPrimaryTextColor(context, false)
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
appWidgetView.setImageViewBitmap(
|
appWidgetView.setImageViewBitmap(
|
||||||
|
@ -70,16 +71,16 @@ class AppWidgetBig : BaseAppWidget() {
|
||||||
context,
|
context,
|
||||||
R.drawable.ic_skip_previous,
|
R.drawable.ic_skip_previous,
|
||||||
MaterialValueHelper.getPrimaryTextColor(context, false)
|
MaterialValueHelper.getPrimaryTextColor(context, false)
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
appWidgetView.setImageViewBitmap(
|
appWidgetView.setImageViewBitmap(
|
||||||
R.id.button_toggle_play_pause, BaseAppWidget.createBitmap(
|
R.id.button_toggle_play_pause, createBitmap(
|
||||||
RetroUtil.getTintedVectorDrawable(
|
RetroUtil.getTintedVectorDrawable(
|
||||||
context,
|
context,
|
||||||
R.drawable.ic_play_arrow_white_32dp,
|
R.drawable.ic_play_arrow_white_32dp,
|
||||||
MaterialValueHelper.getPrimaryTextColor(context, false)
|
MaterialValueHelper.getPrimaryTextColor(context, false)
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -126,7 +127,7 @@ class AppWidgetBig : BaseAppWidget() {
|
||||||
service,
|
service,
|
||||||
playPauseRes,
|
playPauseRes,
|
||||||
primaryColor
|
primaryColor
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -137,7 +138,7 @@ class AppWidgetBig : BaseAppWidget() {
|
||||||
service,
|
service,
|
||||||
R.drawable.ic_skip_next,
|
R.drawable.ic_skip_next,
|
||||||
primaryColor
|
primaryColor
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
appWidgetView.setImageViewBitmap(
|
appWidgetView.setImageViewBitmap(
|
||||||
|
@ -146,7 +147,7 @@ class AppWidgetBig : BaseAppWidget() {
|
||||||
service,
|
service,
|
||||||
R.drawable.ic_skip_previous,
|
R.drawable.ic_skip_previous,
|
||||||
primaryColor
|
primaryColor
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -155,7 +156,7 @@ class AppWidgetBig : BaseAppWidget() {
|
||||||
|
|
||||||
// Load the album cover async and push the update on completion
|
// Load the album cover async and push the update on completion
|
||||||
val p = RetroUtil.getScreenSize(service)
|
val p = RetroUtil.getScreenSize(service)
|
||||||
val widgetImageSize = Math.min(p.x, p.y)
|
val widgetImageSize = p.x.coerceAtMost(p.y)
|
||||||
val appContext = service.applicationContext
|
val appContext = service.applicationContext
|
||||||
service.runOnUiThread {
|
service.runOnUiThread {
|
||||||
if (target != null) {
|
if (target != null) {
|
||||||
|
@ -208,7 +209,11 @@ class AppWidgetBig : BaseAppWidget() {
|
||||||
// Home
|
// Home
|
||||||
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
var pendingIntent =
|
var pendingIntent =
|
||||||
PendingIntent.getActivity(context, 0, action, PendingIntent.FLAG_IMMUTABLE)
|
PendingIntent.getActivity(
|
||||||
|
context, 0, action, if (VersionUtils.hasMarshmallow())
|
||||||
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
|
else 0
|
||||||
|
)
|
||||||
views.setOnClickPendingIntent(R.id.clickable_area, pendingIntent)
|
views.setOnClickPendingIntent(R.id.clickable_area, pendingIntent)
|
||||||
|
|
||||||
// Previous track
|
// Previous track
|
||||||
|
|
|
@ -24,6 +24,7 @@ import android.text.TextUtils
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
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.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
|
||||||
|
@ -59,7 +60,7 @@ class AppWidgetCard : BaseAppWidget() {
|
||||||
context,
|
context,
|
||||||
R.drawable.ic_skip_next,
|
R.drawable.ic_skip_next,
|
||||||
secondaryColor
|
secondaryColor
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
appWidgetView.setImageViewBitmap(
|
appWidgetView.setImageViewBitmap(
|
||||||
|
@ -68,7 +69,7 @@ class AppWidgetCard : BaseAppWidget() {
|
||||||
context,
|
context,
|
||||||
R.drawable.ic_skip_previous,
|
R.drawable.ic_skip_previous,
|
||||||
secondaryColor
|
secondaryColor
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
appWidgetView.setImageViewBitmap(
|
appWidgetView.setImageViewBitmap(
|
||||||
|
@ -77,7 +78,7 @@ class AppWidgetCard : BaseAppWidget() {
|
||||||
context,
|
context,
|
||||||
R.drawable.ic_play_arrow_white_32dp,
|
R.drawable.ic_play_arrow_white_32dp,
|
||||||
secondaryColor
|
secondaryColor
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -112,7 +113,7 @@ class AppWidgetCard : BaseAppWidget() {
|
||||||
service,
|
service,
|
||||||
playPauseRes,
|
playPauseRes,
|
||||||
MaterialValueHelper.getSecondaryTextColor(service, true)
|
MaterialValueHelper.getSecondaryTextColor(service, true)
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -123,7 +124,7 @@ class AppWidgetCard : BaseAppWidget() {
|
||||||
service,
|
service,
|
||||||
R.drawable.ic_skip_next,
|
R.drawable.ic_skip_next,
|
||||||
MaterialValueHelper.getSecondaryTextColor(service, true)
|
MaterialValueHelper.getSecondaryTextColor(service, true)
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
appWidgetView.setImageViewBitmap(
|
appWidgetView.setImageViewBitmap(
|
||||||
|
@ -132,7 +133,7 @@ class AppWidgetCard : BaseAppWidget() {
|
||||||
service,
|
service,
|
||||||
R.drawable.ic_skip_previous,
|
R.drawable.ic_skip_previous,
|
||||||
MaterialValueHelper.getSecondaryTextColor(service, true)
|
MaterialValueHelper.getSecondaryTextColor(service, true)
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -231,7 +232,11 @@ class AppWidgetCard : BaseAppWidget() {
|
||||||
// Home
|
// Home
|
||||||
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
var pendingIntent =
|
var pendingIntent =
|
||||||
PendingIntent.getActivity(context, 0, action, PendingIntent.FLAG_IMMUTABLE)
|
PendingIntent.getActivity(
|
||||||
|
context, 0, action, if (VersionUtils.hasMarshmallow())
|
||||||
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
|
else 0
|
||||||
|
)
|
||||||
views.setOnClickPendingIntent(R.id.image, pendingIntent)
|
views.setOnClickPendingIntent(R.id.image, pendingIntent)
|
||||||
views.setOnClickPendingIntent(R.id.media_titles, pendingIntent)
|
views.setOnClickPendingIntent(R.id.media_titles, pendingIntent)
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,7 @@ import android.text.TextUtils
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
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.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
|
||||||
|
@ -60,7 +61,7 @@ class AppWidgetClassic : BaseAppWidget() {
|
||||||
context,
|
context,
|
||||||
R.drawable.ic_skip_next,
|
R.drawable.ic_skip_next,
|
||||||
MaterialValueHelper.getSecondaryTextColor(context, true)
|
MaterialValueHelper.getSecondaryTextColor(context, true)
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
appWidgetView.setImageViewBitmap(
|
appWidgetView.setImageViewBitmap(
|
||||||
|
@ -70,7 +71,7 @@ class AppWidgetClassic : BaseAppWidget() {
|
||||||
context,
|
context,
|
||||||
R.drawable.ic_skip_previous,
|
R.drawable.ic_skip_previous,
|
||||||
MaterialValueHelper.getSecondaryTextColor(context, true)
|
MaterialValueHelper.getSecondaryTextColor(context, true)
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
appWidgetView.setImageViewBitmap(
|
appWidgetView.setImageViewBitmap(
|
||||||
|
@ -80,7 +81,7 @@ class AppWidgetClassic : BaseAppWidget() {
|
||||||
context,
|
context,
|
||||||
R.drawable.ic_play_arrow_white_32dp,
|
R.drawable.ic_play_arrow_white_32dp,
|
||||||
MaterialValueHelper.getSecondaryTextColor(context, true)
|
MaterialValueHelper.getSecondaryTextColor(context, true)
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -221,7 +222,11 @@ class AppWidgetClassic : BaseAppWidget() {
|
||||||
|
|
||||||
// Home
|
// Home
|
||||||
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
var pendingIntent = PendingIntent.getActivity(context, 0, action, PendingIntent.FLAG_IMMUTABLE)
|
var pendingIntent = PendingIntent.getActivity(
|
||||||
|
context, 0, action, if (VersionUtils.hasMarshmallow())
|
||||||
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
|
else 0
|
||||||
|
)
|
||||||
views.setOnClickPendingIntent(R.id.image, pendingIntent)
|
views.setOnClickPendingIntent(R.id.image, pendingIntent)
|
||||||
views.setOnClickPendingIntent(R.id.media_titles, pendingIntent)
|
views.setOnClickPendingIntent(R.id.media_titles, pendingIntent)
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@ import android.text.TextUtils
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
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.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
|
||||||
|
@ -58,7 +59,7 @@ class AppWidgetSmall : BaseAppWidget() {
|
||||||
context,
|
context,
|
||||||
R.drawable.ic_skip_next,
|
R.drawable.ic_skip_next,
|
||||||
MaterialValueHelper.getSecondaryTextColor(context, true)
|
MaterialValueHelper.getSecondaryTextColor(context, true)
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
appWidgetView.setImageViewBitmap(
|
appWidgetView.setImageViewBitmap(
|
||||||
|
@ -68,7 +69,7 @@ class AppWidgetSmall : BaseAppWidget() {
|
||||||
context,
|
context,
|
||||||
R.drawable.ic_skip_previous,
|
R.drawable.ic_skip_previous,
|
||||||
MaterialValueHelper.getSecondaryTextColor(context, true)
|
MaterialValueHelper.getSecondaryTextColor(context, true)
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
appWidgetView.setImageViewBitmap(
|
appWidgetView.setImageViewBitmap(
|
||||||
|
@ -78,7 +79,7 @@ class AppWidgetSmall : BaseAppWidget() {
|
||||||
context,
|
context,
|
||||||
R.drawable.ic_play_arrow_white_32dp,
|
R.drawable.ic_play_arrow_white_32dp,
|
||||||
MaterialValueHelper.getSecondaryTextColor(context, true)
|
MaterialValueHelper.getSecondaryTextColor(context, true)
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -160,7 +161,7 @@ class AppWidgetSmall : BaseAppWidget() {
|
||||||
R.id.button_toggle_play_pause, createBitmap(
|
R.id.button_toggle_play_pause, createBitmap(
|
||||||
RetroUtil.getTintedVectorDrawable(
|
RetroUtil.getTintedVectorDrawable(
|
||||||
service, playPauseRes, color
|
service, playPauseRes, color
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -169,14 +170,14 @@ class AppWidgetSmall : BaseAppWidget() {
|
||||||
R.id.button_next, createBitmap(
|
R.id.button_next, createBitmap(
|
||||||
RetroUtil.getTintedVectorDrawable(
|
RetroUtil.getTintedVectorDrawable(
|
||||||
service, R.drawable.ic_skip_next, color
|
service, R.drawable.ic_skip_next, color
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
appWidgetView.setImageViewBitmap(
|
appWidgetView.setImageViewBitmap(
|
||||||
R.id.button_prev, createBitmap(
|
R.id.button_prev, createBitmap(
|
||||||
RetroUtil.getTintedVectorDrawable(
|
RetroUtil.getTintedVectorDrawable(
|
||||||
service, R.drawable.ic_skip_previous, color
|
service, R.drawable.ic_skip_previous, color
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -207,7 +208,11 @@ class AppWidgetSmall : BaseAppWidget() {
|
||||||
// Home
|
// Home
|
||||||
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
var pendingIntent =
|
var pendingIntent =
|
||||||
PendingIntent.getActivity(context, 0, action, PendingIntent.FLAG_IMMUTABLE)
|
PendingIntent.getActivity(
|
||||||
|
context, 0, action, if (VersionUtils.hasMarshmallow())
|
||||||
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
|
else 0
|
||||||
|
)
|
||||||
views.setOnClickPendingIntent(R.id.image, pendingIntent)
|
views.setOnClickPendingIntent(R.id.image, pendingIntent)
|
||||||
views.setOnClickPendingIntent(R.id.media_titles, pendingIntent)
|
views.setOnClickPendingIntent(R.id.media_titles, pendingIntent)
|
||||||
|
|
||||||
|
|
|
@ -18,11 +18,11 @@ import android.app.PendingIntent
|
||||||
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.provider.MediaStore
|
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
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 code.name.monkey.appthemehelper.util.VersionUtils
|
||||||
import code.name.monkey.retromusic.App
|
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
|
||||||
|
@ -42,7 +42,7 @@ class AppWidgetText : BaseAppWidget() {
|
||||||
context, 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
|
||||||
)
|
)
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
appWidgetView.setImageViewBitmap(
|
appWidgetView.setImageViewBitmap(
|
||||||
|
@ -51,7 +51,7 @@ class AppWidgetText : BaseAppWidget() {
|
||||||
context, 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
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
appWidgetView.setImageViewBitmap(
|
appWidgetView.setImageViewBitmap(
|
||||||
|
@ -60,7 +60,7 @@ class AppWidgetText : BaseAppWidget() {
|
||||||
context, 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
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -89,7 +89,11 @@ class AppWidgetText : BaseAppWidget() {
|
||||||
|
|
||||||
// Home
|
// Home
|
||||||
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
var pendingIntent = PendingIntent.getActivity(context, 0, action, PendingIntent.FLAG_IMMUTABLE)
|
var pendingIntent = PendingIntent.getActivity(
|
||||||
|
context, 0, action, if (VersionUtils.hasMarshmallow())
|
||||||
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
|
else 0
|
||||||
|
)
|
||||||
views.setOnClickPendingIntent(R.id.image, pendingIntent)
|
views.setOnClickPendingIntent(R.id.image, pendingIntent)
|
||||||
views.setOnClickPendingIntent(R.id.media_titles, pendingIntent)
|
views.setOnClickPendingIntent(R.id.media_titles, pendingIntent)
|
||||||
|
|
||||||
|
@ -132,7 +136,7 @@ class AppWidgetText : BaseAppWidget() {
|
||||||
App.getContext(), playPauseRes, ContextCompat.getColor(
|
App.getContext(), playPauseRes, ContextCompat.getColor(
|
||||||
App.getContext(), R.color.md_white_1000
|
App.getContext(), R.color.md_white_1000
|
||||||
)
|
)
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
appWidgetView.setImageViewBitmap(
|
appWidgetView.setImageViewBitmap(
|
||||||
|
@ -143,7 +147,7 @@ class AppWidgetText : BaseAppWidget() {
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
App.getContext(), R.color.md_white_1000
|
App.getContext(), R.color.md_white_1000
|
||||||
)
|
)
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
appWidgetView.setImageViewBitmap(
|
appWidgetView.setImageViewBitmap(
|
||||||
|
@ -154,7 +158,7 @@ class AppWidgetText : BaseAppWidget() {
|
||||||
ContextCompat.getColor(
|
ContextCompat.getColor(
|
||||||
App.getContext(), R.color.md_white_1000
|
App.getContext(), R.color.md_white_1000
|
||||||
)
|
)
|
||||||
)!!, 1f
|
), 1f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ import android.os.Build
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.widget.RemoteViews
|
import android.widget.RemoteViews
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||||
import code.name.monkey.retromusic.App
|
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
|
||||||
|
@ -99,7 +100,11 @@ abstract class BaseAppWidget : AppWidgetProvider() {
|
||||||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||||
PendingIntent.getForegroundService(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
PendingIntent.getForegroundService(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
||||||
} else {
|
} else {
|
||||||
PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
PendingIntent.getService(
|
||||||
|
context, 0, intent, if (VersionUtils.hasMarshmallow())
|
||||||
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
|
else 0
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,6 +11,7 @@ import com.google.android.gms.cast.MediaInfo.STREAM_TYPE_BUFFERED
|
||||||
import com.google.android.gms.cast.MediaMetadata.*
|
import com.google.android.gms.cast.MediaMetadata.*
|
||||||
import com.google.android.gms.cast.framework.CastSession
|
import com.google.android.gms.cast.framework.CastSession
|
||||||
import com.google.android.gms.common.images.WebImage
|
import com.google.android.gms.common.images.WebImage
|
||||||
|
import org.json.JSONObject
|
||||||
import java.net.MalformedURLException
|
import java.net.MalformedURLException
|
||||||
import java.net.URL
|
import java.net.URL
|
||||||
|
|
||||||
|
@ -41,7 +42,7 @@ object CastHelper {
|
||||||
position,
|
position,
|
||||||
MediaStatus.REPEAT_MODE_REPEAT_OFF,
|
MediaStatus.REPEAT_MODE_REPEAT_OFF,
|
||||||
progress,
|
progress,
|
||||||
null
|
JSONObject()
|
||||||
)
|
)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
e.printStackTrace()
|
e.printStackTrace()
|
||||||
|
|
|
@ -13,7 +13,7 @@ class ExpandedControlsActivity : ExpandedControllerActivity() {
|
||||||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||||
super.onCreateOptionsMenu(menu)
|
super.onCreateOptionsMenu(menu)
|
||||||
menuInflater.inflate(R.menu.menu_cast, menu)
|
menuInflater.inflate(R.menu.menu_cast, menu)
|
||||||
CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.action_cast)
|
CastButtonFactory.setUpMediaRouteButton(this, menu!!, R.id.action_cast)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,7 +17,7 @@ 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"
|
||||||
var mRetroWebServer: RetroWebServer? = null
|
private var mRetroWebServer: RetroWebServer? = null
|
||||||
fun getInstance(context: Context): RetroWebServer {
|
fun getInstance(context: Context): RetroWebServer {
|
||||||
if (mRetroWebServer == null) {
|
if (mRetroWebServer == null) {
|
||||||
mRetroWebServer = RetroWebServer(context)
|
mRetroWebServer = RetroWebServer(context)
|
||||||
|
|
|
@ -26,6 +26,8 @@ interface HistoryDao {
|
||||||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||||
suspend fun insertSongInHistory(historyEntity: HistoryEntity)
|
suspend fun insertSongInHistory(historyEntity: HistoryEntity)
|
||||||
|
|
||||||
|
@Query("DELETE FROM HistoryEntity WHERE id= :songId")
|
||||||
|
fun deleteSongInHistory(songId: Long)
|
||||||
@Query("SELECT * FROM HistoryEntity WHERE id = :songId LIMIT 1")
|
@Query("SELECT * FROM HistoryEntity WHERE id = :songId LIMIT 1")
|
||||||
suspend fun isSongPresentInHistory(songId: Long): HistoryEntity?
|
suspend fun isSongPresentInHistory(songId: Long): HistoryEntity?
|
||||||
|
|
||||||
|
|
|
@ -28,12 +28,6 @@ fun List<SongEntity>.toSongs(): List<Song> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun List<Song>.toSongs(playlistId: Long): List<SongEntity> {
|
|
||||||
return map {
|
|
||||||
it.toSongEntity(playlistId)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Song.toHistoryEntity(timePlayed: Long): HistoryEntity {
|
fun Song.toHistoryEntity(timePlayed: Long): HistoryEntity {
|
||||||
return HistoryEntity(
|
return HistoryEntity(
|
||||||
id = id,
|
id = id,
|
||||||
|
|
|
@ -60,6 +60,11 @@ class DeleteSongsDialog : DialogFragment() {
|
||||||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||||
libraryViewModel = activity?.getViewModel() as LibraryViewModel
|
libraryViewModel = activity?.getViewModel() as LibraryViewModel
|
||||||
val songs = extraNotNull<List<Song>>(EXTRA_SONG).value
|
val songs = extraNotNull<List<Song>>(EXTRA_SONG).value
|
||||||
|
if (VersionUtils.hasR()) {
|
||||||
|
dismiss()
|
||||||
|
MusicUtil.deleteTracksR(requireActivity(), songs)
|
||||||
|
reloadTabs()
|
||||||
|
}
|
||||||
val pair = if (songs.size > 1) {
|
val pair = if (songs.size > 1) {
|
||||||
Pair(
|
Pair(
|
||||||
R.string.delete_songs_title,
|
R.string.delete_songs_title,
|
||||||
|
@ -90,11 +95,7 @@ class DeleteSongsDialog : DialogFragment() {
|
||||||
if ((songs.size == 1) && MusicPlayerRemote.isPlaying(songs[0])) {
|
if ((songs.size == 1) && MusicPlayerRemote.isPlaying(songs[0])) {
|
||||||
MusicPlayerRemote.playNextSong()
|
MusicPlayerRemote.playNextSong()
|
||||||
}
|
}
|
||||||
if (VersionUtils.hasR()) {
|
if (!SAFUtil.isSAFRequiredForSongs(songs)) {
|
||||||
dismiss()
|
|
||||||
MusicUtil.deleteTracksR(requireActivity(), songs)
|
|
||||||
reloadTabs()
|
|
||||||
} else if (!SAFUtil.isSAFRequiredForSongs(songs)) {
|
|
||||||
CoroutineScope(Dispatchers.IO).launch {
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
dismiss()
|
dismiss()
|
||||||
MusicUtil.deleteTracks(requireContext(), songs)
|
MusicUtil.deleteTracks(requireContext(), songs)
|
||||||
|
@ -138,7 +139,7 @@ class DeleteSongsDialog : DialogFragment() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reloadTabs() {
|
private fun reloadTabs() {
|
||||||
libraryViewModel.forceReload(ReloadType.Songs)
|
libraryViewModel.forceReload(ReloadType.Songs)
|
||||||
libraryViewModel.forceReload(ReloadType.HomeSections)
|
libraryViewModel.forceReload(ReloadType.HomeSections)
|
||||||
libraryViewModel.forceReload(ReloadType.Artists)
|
libraryViewModel.forceReload(ReloadType.Artists)
|
||||||
|
|
|
@ -29,6 +29,7 @@ import android.widget.SeekBar
|
||||||
import android.widget.TextView
|
import android.widget.TextView
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.fragment.app.DialogFragment
|
import androidx.fragment.app.DialogFragment
|
||||||
|
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.addAccentColor
|
import code.name.monkey.retromusic.extensions.addAccentColor
|
||||||
import code.name.monkey.retromusic.extensions.colorButtons
|
import code.name.monkey.retromusic.extensions.colorButtons
|
||||||
|
@ -138,7 +139,11 @@ class SleepTimerDialog : DialogFragment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun makeTimerPendingIntent(flag: Int): PendingIntent? {
|
private fun makeTimerPendingIntent(flag: Int): PendingIntent? {
|
||||||
return PendingIntent.getService(requireActivity(), 0, makeTimerIntent(), flag or PendingIntent.FLAG_IMMUTABLE)
|
return PendingIntent.getService(
|
||||||
|
requireActivity(), 0, makeTimerIntent(), flag or if (VersionUtils.hasMarshmallow())
|
||||||
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
|
else 0
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun makeTimerIntent(): Intent {
|
private fun makeTimerIntent(): Intent {
|
||||||
|
|
|
@ -3,13 +3,9 @@ package code.name.monkey.retromusic.extensions
|
||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import android.os.Environment
|
|
||||||
import android.provider.DocumentsContract
|
|
||||||
import androidx.activity.result.ActivityResult
|
import androidx.activity.result.ActivityResult
|
||||||
import androidx.activity.result.contract.ActivityResultContracts
|
import androidx.activity.result.contract.ActivityResultContracts
|
||||||
import androidx.documentfile.provider.DocumentFile
|
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import java.io.File
|
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
fun Fragment.createNewFile(
|
fun Fragment.createNewFile(
|
||||||
|
|
|
@ -78,7 +78,7 @@ fun isBlack(fArr: FloatArray): Boolean {
|
||||||
|
|
||||||
fun isNearRedLine(fArr: FloatArray): Boolean {
|
fun isNearRedLine(fArr: FloatArray): Boolean {
|
||||||
val f = fArr[0]
|
val f = fArr[0]
|
||||||
return f >= 10.0f && f <= 37.0f && fArr[1] <= 0.82f
|
return f in 10.0f..37.0f && fArr[1] <= 0.82f
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isDark(@ColorInt i: Int): Boolean {
|
fun isDark(@ColorInt i: Int): Boolean {
|
||||||
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
package code.name.monkey.retromusic.fragments
|
||||||
|
|
||||||
|
import androidx.annotation.LayoutRes
|
||||||
|
import code.name.monkey.retromusic.R
|
||||||
|
|
||||||
|
enum class GridStyle constructor(
|
||||||
|
@param:LayoutRes @field:LayoutRes val layoutResId: Int,
|
||||||
|
val id: Int
|
||||||
|
) {
|
||||||
|
Grid(R.layout.item_grid, 0),
|
||||||
|
Card(R.layout.item_card, 1),
|
||||||
|
ColoredCard(R.layout.item_card_color, 2),
|
||||||
|
Circular(R.layout.item_grid_circle, 3),
|
||||||
|
Image(R.layout.image, 4),
|
||||||
|
GradientImage(R.layout.item_image_gradient, 5)
|
||||||
|
}
|
|
@ -29,6 +29,7 @@ import code.name.monkey.retromusic.util.DensityUtil
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import kotlinx.coroutines.Dispatchers.IO
|
import kotlinx.coroutines.Dispatchers.IO
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
class LibraryViewModel(
|
class LibraryViewModel(
|
||||||
private val repository: RealRepository
|
private val repository: RealRepository
|
||||||
|
@ -43,7 +44,7 @@ class LibraryViewModel(
|
||||||
private val legacyPlaylists = MutableLiveData<List<Playlist>>()
|
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<Int>(0)
|
private val fabMargin = MutableLiveData(0)
|
||||||
val paletteColor: LiveData<Int> = _paletteColor
|
val paletteColor: LiveData<Int> = _paletteColor
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
@ -227,7 +228,7 @@ class LibraryViewModel(
|
||||||
repository.deleteRoomPlaylist(playlists)
|
repository.deleteRoomPlaylist(playlists)
|
||||||
}
|
}
|
||||||
|
|
||||||
suspend fun albumById(id: Long) = repository.albumById(id)
|
fun albumById(id: Long) = repository.albumById(id)
|
||||||
suspend fun artistById(id: Long) = repository.artistById(id)
|
suspend fun artistById(id: Long) = repository.artistById(id)
|
||||||
suspend fun favoritePlaylist() = repository.favoritePlaylist()
|
suspend fun favoritePlaylist() = repository.favoritePlaylist()
|
||||||
suspend fun isFavoriteSong(song: SongEntity) = repository.isFavoriteSong(song)
|
suspend fun isFavoriteSong(song: SongEntity) = repository.isFavoriteSong(song)
|
||||||
|
@ -272,6 +273,16 @@ class LibraryViewModel(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun playCountSongs(): LiveData<List<Song>> = liveData {
|
fun playCountSongs(): LiveData<List<Song>> = liveData {
|
||||||
|
val songs = repository.playCountSongs().map {
|
||||||
|
it.toSong()
|
||||||
|
}
|
||||||
|
emit(songs)
|
||||||
|
// Cleaning up deleted or moved songs
|
||||||
|
songs.forEach { song ->
|
||||||
|
if (!File(song.data).exists() || song.id == -1L) {
|
||||||
|
repository.deleteSongInPlayCount(song.toPlayCount())
|
||||||
|
}
|
||||||
|
}
|
||||||
emit(repository.playCountSongs().map {
|
emit(repository.playCountSongs().map {
|
||||||
it.toSong()
|
it.toSong()
|
||||||
})
|
})
|
||||||
|
@ -303,7 +314,21 @@ class LibraryViewModel(
|
||||||
emit(repository.contributor())
|
emit(repository.contributor())
|
||||||
}
|
}
|
||||||
|
|
||||||
fun observableHistorySongs() = repository.observableHistorySongs()
|
fun observableHistorySongs(): LiveData<List<Song>> = liveData {
|
||||||
|
val songs = repository.historySong().map {
|
||||||
|
it.toSong()
|
||||||
|
}
|
||||||
|
emit(songs)
|
||||||
|
// Cleaning up deleted or moved songs
|
||||||
|
songs.forEach { song ->
|
||||||
|
if (!File(song.data).exists() || song.id == -1L) {
|
||||||
|
repository.deleteSongInHistory(song.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emit(repository.historySong().map {
|
||||||
|
it.toSong()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fun favorites() = repository.favorites()
|
fun favorites() = repository.favorites()
|
||||||
|
|
||||||
|
|
|
@ -405,9 +405,8 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
||||||
binding.albumCoverContainer,
|
binding.albumCoverContainer,
|
||||||
"${getString(R.string.transition_album_art)}_${album.id}"
|
"${getString(R.string.transition_album_art)}_${album.id}"
|
||||||
)
|
)
|
||||||
startActivityForResult(
|
startActivity(
|
||||||
intent,
|
intent, options.toBundle()
|
||||||
TAG_EDITOR_REQUEST, options.toBundle()
|
|
||||||
)
|
)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
@ -499,8 +498,4 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
||||||
super.onDestroyView()
|
super.onDestroyView()
|
||||||
_binding = null
|
_binding = null
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
|
||||||
const val TAG_EDITOR_REQUEST = 9002
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.album.AlbumAdapter
|
import code.name.monkey.retromusic.adapter.album.AlbumAdapter
|
||||||
import code.name.monkey.retromusic.extensions.navigate
|
import code.name.monkey.retromusic.extensions.navigate
|
||||||
import code.name.monkey.retromusic.extensions.surfaceColor
|
import code.name.monkey.retromusic.extensions.surfaceColor
|
||||||
|
import code.name.monkey.retromusic.fragments.GridStyle
|
||||||
import code.name.monkey.retromusic.fragments.ReloadType
|
import code.name.monkey.retromusic.fragments.ReloadType
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
|
@ -131,11 +132,13 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadLayoutRes(): Int {
|
override fun loadLayoutRes(): Int {
|
||||||
return PreferenceUtil.albumGridStyle
|
return PreferenceUtil.albumGridStyle.layoutResId
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun saveLayoutRes(layoutRes: Int) {
|
override fun saveLayoutRes(layoutRes: Int) {
|
||||||
PreferenceUtil.albumGridStyle = layoutRes
|
PreferenceUtil.albumGridStyle = GridStyle.values().first { gridStyle ->
|
||||||
|
gridStyle.layoutResId == layoutRes
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -307,9 +310,9 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
|
||||||
R.id.action_layout_circular -> R.layout.item_grid_circle
|
R.id.action_layout_circular -> R.layout.item_grid_circle
|
||||||
R.id.action_layout_image -> R.layout.image
|
R.id.action_layout_image -> R.layout.image
|
||||||
R.id.action_layout_gradient_image -> R.layout.item_image_gradient
|
R.id.action_layout_gradient_image -> R.layout.item_image_gradient
|
||||||
else -> PreferenceUtil.albumGridStyle
|
else -> PreferenceUtil.albumGridStyle.layoutResId
|
||||||
}
|
}
|
||||||
if (layoutRes != PreferenceUtil.albumGridStyle) {
|
if (layoutRes != PreferenceUtil.albumGridStyle.layoutResId) {
|
||||||
item.isChecked = true
|
item.isChecked = true
|
||||||
setAndSaveLayoutRes(layoutRes)
|
setAndSaveLayoutRes(layoutRes)
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -25,8 +25,8 @@ import code.name.monkey.retromusic.EXTRA_ARTIST_ID
|
||||||
import code.name.monkey.retromusic.EXTRA_ARTIST_NAME
|
import code.name.monkey.retromusic.EXTRA_ARTIST_NAME
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.artist.ArtistAdapter
|
import code.name.monkey.retromusic.adapter.artist.ArtistAdapter
|
||||||
import code.name.monkey.retromusic.extensions.navigate
|
|
||||||
import code.name.monkey.retromusic.extensions.surfaceColor
|
import code.name.monkey.retromusic.extensions.surfaceColor
|
||||||
|
import code.name.monkey.retromusic.fragments.GridStyle
|
||||||
import code.name.monkey.retromusic.fragments.ReloadType
|
import code.name.monkey.retromusic.fragments.ReloadType
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
|
@ -132,11 +132,13 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadLayoutRes(): Int {
|
override fun loadLayoutRes(): Int {
|
||||||
return PreferenceUtil.artistGridStyle
|
return PreferenceUtil.artistGridStyle.layoutResId
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun saveLayoutRes(layoutRes: Int) {
|
override fun saveLayoutRes(layoutRes: Int) {
|
||||||
PreferenceUtil.artistGridStyle = layoutRes
|
PreferenceUtil.artistGridStyle = GridStyle.values().first { gridStyle ->
|
||||||
|
gridStyle.layoutResId == layoutRes
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -312,9 +314,9 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
|
||||||
R.id.action_layout_circular -> R.layout.item_grid_circle
|
R.id.action_layout_circular -> R.layout.item_grid_circle
|
||||||
R.id.action_layout_image -> R.layout.image
|
R.id.action_layout_image -> R.layout.image
|
||||||
R.id.action_layout_gradient_image -> R.layout.item_image_gradient
|
R.id.action_layout_gradient_image -> R.layout.item_image_gradient
|
||||||
else -> PreferenceUtil.artistGridStyle
|
else -> PreferenceUtil.artistGridStyle.layoutResId
|
||||||
}
|
}
|
||||||
if (layoutRes != PreferenceUtil.artistGridStyle) {
|
if (layoutRes != PreferenceUtil.artistGridStyle.layoutResId) {
|
||||||
item.isChecked = true
|
item.isChecked = true
|
||||||
setAndSaveLayoutRes(layoutRes)
|
setAndSaveLayoutRes(layoutRes)
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -48,9 +48,11 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
|
||||||
backupViewModel.loadBackups()
|
backupViewModel.loadBackups()
|
||||||
val openFilePicker = registerForActivityResult(ActivityResultContracts.OpenDocument()) {
|
val openFilePicker = registerForActivityResult(ActivityResultContracts.OpenDocument()) {
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
|
it?.let {
|
||||||
backupViewModel.restoreBackup(requireActivity(), requireContext().contentResolver.openInputStream(it))
|
backupViewModel.restoreBackup(requireActivity(), requireContext().contentResolver.openInputStream(it))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
binding.createBackup.setOnClickListener {
|
binding.createBackup.setOnClickListener {
|
||||||
showCreateBackupDialog()
|
showCreateBackupDialog()
|
||||||
}
|
}
|
||||||
|
@ -70,7 +72,7 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkIsEmpty() {
|
private fun checkIsEmpty() {
|
||||||
val isEmpty = backupAdapter!!.itemCount == 0
|
val isEmpty = backupAdapter?.itemCount == 0
|
||||||
binding.backupTitle.isVisible = !isEmpty
|
binding.backupTitle.isVisible = !isEmpty
|
||||||
binding.backupRecyclerview.isVisible = !isEmpty
|
binding.backupRecyclerview.isVisible = !isEmpty
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,6 +37,7 @@ import androidx.appcompat.widget.Toolbar
|
||||||
import androidx.core.os.bundleOf
|
import androidx.core.os.bundleOf
|
||||||
import androidx.lifecycle.lifecycleScope
|
import androidx.lifecycle.lifecycleScope
|
||||||
import androidx.navigation.findNavController
|
import androidx.navigation.findNavController
|
||||||
|
import androidx.navigation.navOptions
|
||||||
import androidx.viewpager.widget.ViewPager
|
import androidx.viewpager.widget.ViewPager
|
||||||
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
|
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
|
||||||
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
|
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
|
||||||
|
@ -151,7 +152,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_show_lyrics -> {
|
R.id.action_show_lyrics -> {
|
||||||
NavigationUtil.goToLyrics(requireActivity())
|
goToLyrics(requireActivity())
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
R.id.action_equalizer -> {
|
R.id.action_equalizer -> {
|
||||||
|
@ -193,7 +194,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: Drawable = RetroUtil.getTintedVectorDrawable(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
icon,
|
icon,
|
||||||
toolbarIconColor()
|
toolbarIconColor()
|
||||||
|
@ -255,7 +256,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: Drawable = RetroUtil.getTintedVectorDrawable(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
icon,
|
icon,
|
||||||
toolbarIconColor()
|
toolbarIconColor()
|
||||||
|
@ -394,7 +395,11 @@ fun goToArtist(activity: Activity) {
|
||||||
|
|
||||||
findNavController(R.id.fragment_container).navigate(
|
findNavController(R.id.fragment_container).navigate(
|
||||||
R.id.artistDetailsFragment,
|
R.id.artistDetailsFragment,
|
||||||
bundleOf(EXTRA_ARTIST_ID to song.artistId)
|
bundleOf(EXTRA_ARTIST_ID to song.artistId),
|
||||||
|
navOptions {
|
||||||
|
launchSingleTop = true
|
||||||
|
},
|
||||||
|
null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -413,7 +418,29 @@ fun goToAlbum(activity: Activity) {
|
||||||
|
|
||||||
findNavController(R.id.fragment_container).navigate(
|
findNavController(R.id.fragment_container).navigate(
|
||||||
R.id.albumDetailsFragment,
|
R.id.albumDetailsFragment,
|
||||||
bundleOf(EXTRA_ALBUM_ID to song.albumId)
|
bundleOf(EXTRA_ALBUM_ID to song.albumId),
|
||||||
|
navOptions {
|
||||||
|
launchSingleTop = true
|
||||||
|
},
|
||||||
|
null
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun goToLyrics(activity: Activity) {
|
||||||
|
if (activity !is MainActivity) return
|
||||||
|
activity.apply {
|
||||||
|
//Hide Bottom Bar First, else Bottom Sheet doesn't collapse fully
|
||||||
|
setBottomNavVisibility(false)
|
||||||
|
if (getBottomSheetBehavior().state == BottomSheetBehavior.STATE_EXPANDED) {
|
||||||
|
collapsePanel()
|
||||||
|
}
|
||||||
|
|
||||||
|
findNavController(R.id.fragment_container).navigate(
|
||||||
|
R.id.lyrics_fragment,
|
||||||
|
null,
|
||||||
|
navOptions { launchSingleTop = true },
|
||||||
|
null
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -41,7 +41,6 @@ import code.name.monkey.retromusic.adapter.StorageAdapter
|
||||||
import code.name.monkey.retromusic.adapter.StorageClickListener
|
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.drawNextToNavbar
|
import code.name.monkey.retromusic.extensions.drawNextToNavbar
|
||||||
import code.name.monkey.retromusic.extensions.navigate
|
|
||||||
import code.name.monkey.retromusic.extensions.surfaceColor
|
import code.name.monkey.retromusic.extensions.surfaceColor
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
import code.name.monkey.retromusic.fragments.base.AbsMainActivityFragment
|
||||||
import code.name.monkey.retromusic.fragments.folder.FoldersFragment.ListPathsAsyncTask.OnPathsListedCallback
|
import code.name.monkey.retromusic.fragments.folder.FoldersFragment.ListPathsAsyncTask.OnPathsListedCallback
|
||||||
|
@ -725,9 +724,10 @@ class FoldersFragment : AbsMainActivityFragment(R.layout.fragment_folder),
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
abstract class ListingFilesDialogAsyncTask<Params, Progress, Result> :
|
abstract class ListingFilesDialogAsyncTask<Params, Progress, Result> internal constructor(
|
||||||
DialogAsyncTask<Params, Progress, Result> {
|
context: Context?
|
||||||
internal constructor(context: Context?) : super(context)
|
) :
|
||||||
|
DialogAsyncTask<Params, Progress, Result>(context) {
|
||||||
|
|
||||||
override fun createDialog(context: Context): Dialog {
|
override fun createDialog(context: Context): Dialog {
|
||||||
return MaterialAlertDialogBuilder(context)
|
return MaterialAlertDialogBuilder(context)
|
||||||
|
|
|
@ -162,10 +162,7 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(R.layout.fragment_mini_p
|
||||||
|
|
||||||
class FlingPlayBackController(context: Context) : View.OnTouchListener {
|
class FlingPlayBackController(context: Context) : View.OnTouchListener {
|
||||||
|
|
||||||
private var flingPlayBackController: GestureDetector
|
private var flingPlayBackController = GestureDetector(context,
|
||||||
|
|
||||||
init {
|
|
||||||
flingPlayBackController = GestureDetector(context,
|
|
||||||
object : GestureDetector.SimpleOnGestureListener() {
|
object : GestureDetector.SimpleOnGestureListener() {
|
||||||
override fun onFling(
|
override fun onFling(
|
||||||
e1: MotionEvent,
|
e1: MotionEvent,
|
||||||
|
@ -185,7 +182,6 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(R.layout.fragment_mini_p
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressLint("ClickableViewAccessibility")
|
@SuppressLint("ClickableViewAccessibility")
|
||||||
override fun onTouch(v: View, event: MotionEvent): Boolean {
|
override fun onTouch(v: View, event: MotionEvent): Boolean {
|
||||||
|
|
|
@ -61,7 +61,6 @@ import org.koin.androidx.viewmodel.ext.android.sharedViewModel
|
||||||
import java.io.BufferedOutputStream
|
import java.io.BufferedOutputStream
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import java.io.FileOutputStream
|
import java.io.FileOutputStream
|
||||||
import java.io.IOException
|
|
||||||
|
|
||||||
class UserInfoFragment : Fragment() {
|
class UserInfoFragment : Fragment() {
|
||||||
|
|
||||||
|
@ -218,13 +217,13 @@ class UserInfoFragment : Fragment() {
|
||||||
val appDir = requireContext().filesDir
|
val appDir = requireContext().filesDir
|
||||||
val file = File(appDir, fileName)
|
val file = File(appDir, fileName)
|
||||||
var successful = false
|
var successful = false
|
||||||
try {
|
kotlin.runCatching {
|
||||||
val os = BufferedOutputStream(FileOutputStream(file))
|
val os = BufferedOutputStream(FileOutputStream(file))
|
||||||
successful = ImageUtil.resizeBitmap(bitmap, 2048)
|
successful = ImageUtil.resizeBitmap(bitmap, 2048)
|
||||||
.compress(Bitmap.CompressFormat.WEBP, 100, os)
|
.compress(Bitmap.CompressFormat.WEBP, 100, os)
|
||||||
withContext(Dispatchers.IO) { os.close() }
|
withContext(Dispatchers.IO) { os.close() }
|
||||||
} catch (e: IOException) {
|
}.onFailure {
|
||||||
e.printStackTrace()
|
it.printStackTrace()
|
||||||
}
|
}
|
||||||
if (successful) {
|
if (successful) {
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
|
|
|
@ -32,6 +32,7 @@ import code.name.monkey.retromusic.databinding.FragmentPlayerAlbumCoverBinding
|
||||||
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
|
import code.name.monkey.retromusic.fragments.NowPlayingScreen.*
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
|
import code.name.monkey.retromusic.fragments.base.AbsMusicServiceFragment
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
import code.name.monkey.retromusic.fragments.base.AbsPlayerFragment
|
||||||
|
import code.name.monkey.retromusic.fragments.base.goToLyrics
|
||||||
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
|
||||||
import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics
|
import code.name.monkey.retromusic.model.lyrics.AbsSynchronizedLyrics
|
||||||
|
@ -39,7 +40,6 @@ import code.name.monkey.retromusic.model.lyrics.Lyrics
|
||||||
import code.name.monkey.retromusic.transform.CarousalPagerTransformer
|
import code.name.monkey.retromusic.transform.CarousalPagerTransformer
|
||||||
import code.name.monkey.retromusic.transform.ParallaxPagerTransformer
|
import code.name.monkey.retromusic.transform.ParallaxPagerTransformer
|
||||||
import code.name.monkey.retromusic.util.LyricUtil
|
import code.name.monkey.retromusic.util.LyricUtil
|
||||||
import code.name.monkey.retromusic.util.NavigationUtil
|
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
import code.name.monkey.retromusic.util.color.MediaNotificationProcessor
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -214,7 +214,7 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
||||||
}
|
}
|
||||||
// Go to lyrics activity when clicked lyrics
|
// Go to lyrics activity when clicked lyrics
|
||||||
binding.playerLyricsLine2.setOnClickListener {
|
binding.playerLyricsLine2.setOnClickListener {
|
||||||
NavigationUtil.goToLyrics(requireActivity())
|
goToLyrics(requireActivity())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
||||||
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
|
private lateinit var progressViewUpdateHelper: MusicProgressViewUpdateHelper
|
||||||
private var audioVolumeObserver: AudioVolumeObserver? = null
|
private var audioVolumeObserver: AudioVolumeObserver? = null
|
||||||
|
|
||||||
private val audioManager: AudioManager?
|
private val audioManager: AudioManager
|
||||||
get() = requireContext().getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
get() = requireContext().getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||||
|
|
||||||
private var _binding: FragmentCirclePlayerBinding? = null
|
private var _binding: FragmentCirclePlayerBinding? = null
|
||||||
|
@ -239,7 +239,7 @@ class CirclePlayerFragment : AbsPlayerFragment(R.layout.fragment_circle_player),
|
||||||
|
|
||||||
override fun onProgressChanged(seekArc: SeekArc?, progress: Int, fromUser: Boolean) {
|
override fun onProgressChanged(seekArc: SeekArc?, progress: Int, fromUser: Boolean) {
|
||||||
val audioManager = audioManager
|
val audioManager = audioManager
|
||||||
audioManager?.setStreamVolume(AudioManager.STREAM_MUSIC, progress, 0)
|
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, progress, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStartTrackingTouch(seekArc: SeekArc?) {
|
override fun onStartTrackingTouch(seekArc: SeekArc?) {
|
||||||
|
|
|
@ -247,7 +247,7 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
|
||||||
updateQueue()
|
updateQueue()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun playerToolbar(): Toolbar? {
|
override fun playerToolbar(): Toolbar {
|
||||||
return binding.playerToolbar
|
return binding.playerToolbar
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -316,7 +316,7 @@ class FullPlaybackControlsFragment :
|
||||||
|
|
||||||
fun updateIsFavorite(animate: Boolean = false) {
|
fun updateIsFavorite(animate: Boolean = false) {
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist()
|
val playlist: PlaylistEntity = libraryViewModel.favoritePlaylist()
|
||||||
if (playlist != null) {
|
if (playlist != null) {
|
||||||
val song: SongEntity =
|
val song: SongEntity =
|
||||||
MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId)
|
MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId)
|
||||||
|
@ -327,7 +327,7 @@ class FullPlaybackControlsFragment :
|
||||||
} 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: Drawable = RetroUtil.getTintedVectorDrawable(
|
||||||
requireContext(),
|
requireContext(),
|
||||||
icon,
|
icon,
|
||||||
Color.WHITE
|
Color.WHITE
|
||||||
|
@ -347,7 +347,7 @@ class FullPlaybackControlsFragment :
|
||||||
|
|
||||||
private fun toggleFavorite(song: Song) {
|
private fun toggleFavorite(song: Song) {
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist()
|
val playlist: PlaylistEntity = libraryViewModel.favoritePlaylist()
|
||||||
if (playlist != null) {
|
if (playlist != null) {
|
||||||
val songEntity = song.toSongEntity(playlist.playListId)
|
val songEntity = song.toSongEntity(playlist.playListId)
|
||||||
val isFavorite = libraryViewModel.isFavoriteSong(songEntity).isNotEmpty()
|
val isFavorite = libraryViewModel.isFavoriteSong(songEntity).isNotEmpty()
|
||||||
|
|
|
@ -281,7 +281,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
||||||
|
|
||||||
private fun updateIsFavoriteIcon(animate: Boolean = false) {
|
private fun updateIsFavoriteIcon(animate: Boolean = false) {
|
||||||
lifecycleScope.launch(Dispatchers.IO) {
|
lifecycleScope.launch(Dispatchers.IO) {
|
||||||
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist()
|
val playlist: PlaylistEntity = libraryViewModel.favoritePlaylist()
|
||||||
if (playlist != null) {
|
if (playlist != null) {
|
||||||
val song: SongEntity =
|
val song: SongEntity =
|
||||||
MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId)
|
MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId)
|
||||||
|
|
|
@ -25,12 +25,12 @@ import code.name.monkey.retromusic.EXTRA_PLAYLIST
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.playlist.PlaylistAdapter
|
import code.name.monkey.retromusic.adapter.playlist.PlaylistAdapter
|
||||||
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
import code.name.monkey.retromusic.db.PlaylistWithSongs
|
||||||
import code.name.monkey.retromusic.extensions.navigate
|
|
||||||
import code.name.monkey.retromusic.fragments.ReloadType
|
import code.name.monkey.retromusic.fragments.ReloadType
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||||
import code.name.monkey.retromusic.helper.SortOrder.PlaylistSortOrder
|
import code.name.monkey.retromusic.helper.SortOrder.PlaylistSortOrder
|
||||||
import code.name.monkey.retromusic.interfaces.IPlaylistClickListener
|
import code.name.monkey.retromusic.interfaces.IPlaylistClickListener
|
||||||
import code.name.monkey.retromusic.util.PreferenceUtil
|
import code.name.monkey.retromusic.util.PreferenceUtil
|
||||||
|
import code.name.monkey.retromusic.util.RetroUtil
|
||||||
import com.google.android.gms.cast.framework.CastButtonFactory
|
import com.google.android.gms.cast.framework.CastButtonFactory
|
||||||
import com.google.android.material.transition.MaterialSharedAxis
|
import com.google.android.material.transition.MaterialSharedAxis
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ class PlaylistsFragment :
|
||||||
super.onViewCreated(view, savedInstanceState)
|
super.onViewCreated(view, savedInstanceState)
|
||||||
libraryViewModel.getPlaylists().observe(viewLifecycleOwner, {
|
libraryViewModel.getPlaylists().observe(viewLifecycleOwner, {
|
||||||
if (it.isNotEmpty())
|
if (it.isNotEmpty())
|
||||||
adapter?.swapDataSet(it)
|
adapter?.swapDataSet(it.filter { playlistWithSongs-> playlistWithSongs.songs.isNotEmpty() })
|
||||||
else
|
else
|
||||||
adapter?.swapDataSet(listOf())
|
adapter?.swapDataSet(listOf())
|
||||||
})
|
})
|
||||||
|
@ -66,9 +66,10 @@ class PlaylistsFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createAdapter(): PlaylistAdapter {
|
override fun createAdapter(): PlaylistAdapter {
|
||||||
|
val dataSet = if (adapter == null) mutableListOf() else adapter!!.dataSet
|
||||||
return PlaylistAdapter(
|
return PlaylistAdapter(
|
||||||
requireActivity(),
|
requireActivity(),
|
||||||
ArrayList(),
|
dataSet,
|
||||||
itemLayoutRes(),
|
itemLayoutRes(),
|
||||||
null,
|
null,
|
||||||
this
|
this
|
||||||
|
@ -77,7 +78,11 @@ class PlaylistsFragment :
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||||
super.onCreateOptionsMenu(menu, inflater)
|
super.onCreateOptionsMenu(menu, inflater)
|
||||||
menu.removeItem(R.id.action_grid_size)
|
val gridSizeItem: MenuItem = menu.findItem(R.id.action_grid_size)
|
||||||
|
if (RetroUtil.isLandscape()) {
|
||||||
|
gridSizeItem.setTitle(R.string.action_grid_size_land)
|
||||||
|
}
|
||||||
|
setupGridSizeMenu(gridSizeItem.subMenu)
|
||||||
menu.removeItem(R.id.action_layout_type)
|
menu.removeItem(R.id.action_layout_type)
|
||||||
menu.add(0, R.id.action_add_to_playlist, 0, R.string.new_playlist_title)
|
menu.add(0, R.id.action_add_to_playlist, 0, R.string.new_playlist_title)
|
||||||
menu.add(0, R.id.action_import_playlist, 0, R.string.import_playlist)
|
menu.add(0, R.id.action_import_playlist, 0, R.string.import_playlist)
|
||||||
|
@ -89,12 +94,46 @@ class PlaylistsFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||||
|
if (handleGridSizeMenuItem(item)) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
if (handleSortOrderMenuItem(item)) {
|
if (handleSortOrderMenuItem(item)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
return super.onOptionsItemSelected(item)
|
return super.onOptionsItemSelected(item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun setupGridSizeMenu(gridSizeMenu: SubMenu) {
|
||||||
|
when (getGridSize()) {
|
||||||
|
1 -> gridSizeMenu.findItem(R.id.action_grid_size_1).isChecked = true
|
||||||
|
2 -> gridSizeMenu.findItem(R.id.action_grid_size_2).isChecked = true
|
||||||
|
3 -> gridSizeMenu.findItem(R.id.action_grid_size_3).isChecked = true
|
||||||
|
4 -> gridSizeMenu.findItem(R.id.action_grid_size_4).isChecked = true
|
||||||
|
5 -> gridSizeMenu.findItem(R.id.action_grid_size_5).isChecked = true
|
||||||
|
6 -> gridSizeMenu.findItem(R.id.action_grid_size_6).isChecked = true
|
||||||
|
7 -> gridSizeMenu.findItem(R.id.action_grid_size_7).isChecked = true
|
||||||
|
8 -> gridSizeMenu.findItem(R.id.action_grid_size_8).isChecked = true
|
||||||
|
}
|
||||||
|
val gridSize = if (RetroUtil.isLandscape()) 4 else 2
|
||||||
|
if (gridSize < 8) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_8).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 7) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_7).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 6) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_6).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 5) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_5).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 4) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_4).isVisible = false
|
||||||
|
}
|
||||||
|
if (gridSize < 3) {
|
||||||
|
gridSizeMenu.findItem(R.id.action_grid_size_3).isVisible = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun setUpSortOrderMenu(subMenu: SubMenu) {
|
private fun setUpSortOrderMenu(subMenu: SubMenu) {
|
||||||
val order: String? = getSortOrder()
|
val order: String? = getSortOrder()
|
||||||
|
@ -142,13 +181,32 @@ class PlaylistsFragment :
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun handleGridSizeMenuItem(item: MenuItem): Boolean {
|
||||||
|
val gridSize = when (item.itemId) {
|
||||||
|
R.id.action_grid_size_1 -> 1
|
||||||
|
R.id.action_grid_size_2 -> 2
|
||||||
|
R.id.action_grid_size_3 -> 3
|
||||||
|
R.id.action_grid_size_4 -> 4
|
||||||
|
R.id.action_grid_size_5 -> 5
|
||||||
|
R.id.action_grid_size_6 -> 6
|
||||||
|
R.id.action_grid_size_7 -> 7
|
||||||
|
R.id.action_grid_size_8 -> 8
|
||||||
|
else -> 0
|
||||||
|
}
|
||||||
|
if (gridSize > 0) {
|
||||||
|
item.isChecked = true
|
||||||
|
setAndSaveGridSize(gridSize)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
private fun createId(menu: SubMenu, id: Int, title: Int, checked: Boolean) {
|
private fun createId(menu: SubMenu, id: Int, title: Int, checked: Boolean) {
|
||||||
menu.add(0, id, 0, title).isChecked = checked
|
menu.add(0, id, 0, title).isChecked = checked
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
override fun setGridSize(gridSize: Int) {
|
override fun setGridSize(gridSize: Int) {
|
||||||
TODO("Not yet implemented")
|
adapter?.notifyDataSetChanged()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setSortOrder(sortOrder: String) {
|
override fun setSortOrder(sortOrder: String) {
|
||||||
|
@ -164,23 +222,23 @@ class PlaylistsFragment :
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadGridSize(): Int {
|
override fun loadGridSize(): Int {
|
||||||
return 2
|
return PreferenceUtil.playlistGridSize
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun saveGridSize(gridColumns: Int) {
|
override fun saveGridSize(gridColumns: Int) {
|
||||||
//Add grid save
|
PreferenceUtil.playlistGridSize = gridColumns
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadGridSizeLand(): Int {
|
override fun loadGridSizeLand(): Int {
|
||||||
return 4
|
return PreferenceUtil.playlistGridSizeLand
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun saveGridSizeLand(gridColumns: Int) {
|
override fun saveGridSizeLand(gridColumns: Int) {
|
||||||
//Add land grid save
|
PreferenceUtil.playlistGridSizeLand = gridColumns
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun loadLayoutRes(): Int {
|
override fun loadLayoutRes(): Int {
|
||||||
return R.layout.item_card
|
return R.layout.item_grid
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun saveLayoutRes(layoutRes: Int) {
|
override fun saveLayoutRes(layoutRes: Int) {
|
||||||
|
|
|
@ -21,8 +21,8 @@ import androidx.annotation.LayoutRes
|
||||||
import androidx.recyclerview.widget.GridLayoutManager
|
import androidx.recyclerview.widget.GridLayoutManager
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.adapter.song.SongAdapter
|
import code.name.monkey.retromusic.adapter.song.SongAdapter
|
||||||
import code.name.monkey.retromusic.extensions.navigate
|
|
||||||
import code.name.monkey.retromusic.extensions.surfaceColor
|
import code.name.monkey.retromusic.extensions.surfaceColor
|
||||||
|
import code.name.monkey.retromusic.fragments.GridStyle
|
||||||
import code.name.monkey.retromusic.fragments.ReloadType
|
import code.name.monkey.retromusic.fragments.ReloadType
|
||||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||||
|
@ -114,11 +114,13 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLay
|
||||||
|
|
||||||
@LayoutRes
|
@LayoutRes
|
||||||
override fun loadLayoutRes(): Int {
|
override fun loadLayoutRes(): Int {
|
||||||
return PreferenceUtil.songGridStyle
|
return PreferenceUtil.songGridStyle.layoutResId
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun saveLayoutRes(@LayoutRes layoutRes: Int) {
|
override fun saveLayoutRes(@LayoutRes layoutRes: Int) {
|
||||||
PreferenceUtil.songGridStyle = layoutRes
|
PreferenceUtil.songGridStyle = GridStyle.values().first { gridStyle ->
|
||||||
|
gridStyle.layoutResId == layoutRes
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setSortOrder(sortOrder: String) {
|
override fun setSortOrder(sortOrder: String) {
|
||||||
|
@ -307,9 +309,9 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLay
|
||||||
R.id.action_layout_circular -> R.layout.item_grid_circle
|
R.id.action_layout_circular -> R.layout.item_grid_circle
|
||||||
R.id.action_layout_image -> R.layout.image
|
R.id.action_layout_image -> R.layout.image
|
||||||
R.id.action_layout_gradient_image -> R.layout.item_image_gradient
|
R.id.action_layout_gradient_image -> R.layout.item_image_gradient
|
||||||
else -> PreferenceUtil.songGridStyle
|
else -> PreferenceUtil.songGridStyle.layoutResId
|
||||||
}
|
}
|
||||||
if (layoutRes != PreferenceUtil.songGridStyle) {
|
if (layoutRes != PreferenceUtil.songGridStyle.layoutResId) {
|
||||||
item.isChecked = true
|
item.isChecked = true
|
||||||
setAndSaveLayoutRes(layoutRes)
|
setAndSaveLayoutRes(layoutRes)
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -17,9 +17,7 @@ class PlaylistPreviewFetcher(val context: Context, private val playlistPreview:
|
||||||
val bitmap =
|
val bitmap =
|
||||||
AutoGeneratedPlaylistBitmap.getBitmap(
|
AutoGeneratedPlaylistBitmap.getBitmap(
|
||||||
context,
|
context,
|
||||||
playlistPreview.songs.shuffled(),
|
playlistPreview.songs.shuffled()
|
||||||
true,
|
|
||||||
false
|
|
||||||
)
|
)
|
||||||
callback.onDataReady(bitmap)
|
callback.onDataReady(bitmap)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
|
|
|
@ -23,13 +23,13 @@ object BackupHelper {
|
||||||
zipItems.addAll(getDatabaseZipItems(context))
|
zipItems.addAll(getDatabaseZipItems(context))
|
||||||
zipItems.addAll(getSettingsZipItems(context))
|
zipItems.addAll(getSettingsZipItems(context))
|
||||||
getUserImageZipItems(context)?.let { zipItems.addAll(it) }
|
getUserImageZipItems(context)?.let { zipItems.addAll(it) }
|
||||||
withContext(Dispatchers.IO) {
|
zipItems.addAll(getCustomArtistZipItems(context))
|
||||||
zipAll(zipItems, backupFile)
|
zipAll(zipItems, backupFile)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private suspend fun zipAll(zipItems: List<ZipItem>, backupFile: File) {
|
private suspend fun zipAll(zipItems: List<ZipItem>, backupFile: File) {
|
||||||
try {
|
withContext(Dispatchers.IO) {
|
||||||
|
kotlin.runCatching {
|
||||||
ZipOutputStream(BufferedOutputStream(FileOutputStream(backupFile))).use { out ->
|
ZipOutputStream(BufferedOutputStream(FileOutputStream(backupFile))).use { out ->
|
||||||
for (zipItem in zipItems) {
|
for (zipItem in zipItems) {
|
||||||
FileInputStream(zipItem.filePath).use { fi ->
|
FileInputStream(zipItem.filePath).use { fi ->
|
||||||
|
@ -41,13 +41,18 @@ object BackupHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (exception: FileNotFoundException) {
|
}.onFailure {
|
||||||
exception.printStackTrace()
|
it.printStackTrace()
|
||||||
withContext(Dispatchers.Main) {
|
withContext(Dispatchers.Main) {
|
||||||
Toast.makeText(App.getContext(), "Couldn't create backup", Toast.LENGTH_SHORT)
|
Toast.makeText(App.getContext(), "Couldn't create backup", Toast.LENGTH_SHORT)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
withContext(Dispatchers.Main) {
|
||||||
|
Toast.makeText(App.getContext(), "Backup created successfully", Toast.LENGTH_SHORT)
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getDatabaseZipItems(context: Context): List<ZipItem> {
|
private fun getDatabaseZipItems(context: Context): List<ZipItem> {
|
||||||
|
@ -76,6 +81,28 @@ object BackupHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun getCustomArtistZipItems(context: Context): List<ZipItem> {
|
||||||
|
val zipItemList = mutableListOf<ZipItem>()
|
||||||
|
val sharedPrefPath = context.filesDir.parentFile?.absolutePath + "/shared_prefs/"
|
||||||
|
|
||||||
|
zipItemList.addAll(
|
||||||
|
File(context.filesDir, "custom_artist_images")
|
||||||
|
.listFiles()?.map {
|
||||||
|
ZipItem(
|
||||||
|
it.absolutePath,
|
||||||
|
"$CUSTOM_ARTISTS_PATH${File.separator}custom_artist_images${File.separator}${it.name}"
|
||||||
|
)
|
||||||
|
}?.toList() ?: listOf()
|
||||||
|
)
|
||||||
|
zipItemList.add(
|
||||||
|
ZipItem(
|
||||||
|
sharedPrefPath + File.separator + "custom_artist_image.xml",
|
||||||
|
"$CUSTOM_ARTISTS_PATH${File.separator}prefs${File.separator}custom_artist_image.xml"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return zipItemList
|
||||||
|
}
|
||||||
|
|
||||||
suspend fun restoreBackup(context: Context, inputStream: InputStream?) {
|
suspend fun restoreBackup(context: Context, inputStream: InputStream?) {
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
ZipInputStream(inputStream).use {
|
ZipInputStream(inputStream).use {
|
||||||
|
@ -84,6 +111,16 @@ object BackupHelper {
|
||||||
if (entry.isDatabaseEntry()) restoreDatabase(context, it, entry)
|
if (entry.isDatabaseEntry()) restoreDatabase(context, it, entry)
|
||||||
if (entry.isPreferenceEntry()) restorePreferences(context, it, entry)
|
if (entry.isPreferenceEntry()) restorePreferences(context, it, entry)
|
||||||
if (entry.isImageEntry()) restoreImages(context, it, entry)
|
if (entry.isImageEntry()) restoreImages(context, it, entry)
|
||||||
|
if (entry.isCustomArtistImageEntry()) restoreCustomArtistImages(
|
||||||
|
context,
|
||||||
|
it,
|
||||||
|
entry
|
||||||
|
)
|
||||||
|
if (entry.isCustomArtistPrefEntry()) restoreCustomArtistPrefs(
|
||||||
|
context,
|
||||||
|
it,
|
||||||
|
entry
|
||||||
|
)
|
||||||
entry = it.nextEntry
|
entry = it.nextEntry
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,6 +170,48 @@ object BackupHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun restoreCustomArtistImages(
|
||||||
|
context: Context,
|
||||||
|
zipIn: ZipInputStream,
|
||||||
|
zipEntry: ZipEntry
|
||||||
|
) {
|
||||||
|
val parentFolder = File(context.filesDir, "custom_artist_images")
|
||||||
|
|
||||||
|
if (!parentFolder.exists()) {
|
||||||
|
parentFolder.mkdirs()
|
||||||
|
}
|
||||||
|
BufferedOutputStream(
|
||||||
|
FileOutputStream(
|
||||||
|
File(
|
||||||
|
parentFolder,
|
||||||
|
zipEntry.getFileName()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).use { bos ->
|
||||||
|
val bytesIn = ByteArray(DEFAULT_BUFFER_SIZE)
|
||||||
|
var read: Int
|
||||||
|
while (zipIn.read(bytesIn).also { read = it } != -1) {
|
||||||
|
bos.write(bytesIn, 0, read)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun restoreCustomArtistPrefs(
|
||||||
|
context: Context,
|
||||||
|
zipIn: ZipInputStream,
|
||||||
|
zipEntry: ZipEntry
|
||||||
|
) {
|
||||||
|
val filePath =
|
||||||
|
context.filesDir.parentFile?.absolutePath + "/shared_prefs/" + zipEntry.getFileName()
|
||||||
|
BufferedOutputStream(FileOutputStream(filePath)).use { bos ->
|
||||||
|
val bytesIn = ByteArray(DEFAULT_BUFFER_SIZE)
|
||||||
|
var read: Int
|
||||||
|
while (zipIn.read(bytesIn).also { read = it } != -1) {
|
||||||
|
bos.write(bytesIn, 0, read)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val backupRootPath =
|
val backupRootPath =
|
||||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
|
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
|
||||||
.toString() + "/RetroMusic/Backups/"
|
.toString() + "/RetroMusic/Backups/"
|
||||||
|
@ -141,6 +220,7 @@ object BackupHelper {
|
||||||
private const val DATABASES_PATH = "databases"
|
private const val DATABASES_PATH = "databases"
|
||||||
private const val SETTINGS_PATH = "prefs"
|
private const val SETTINGS_PATH = "prefs"
|
||||||
private const val IMAGES_PATH = "userImages"
|
private const val IMAGES_PATH = "userImages"
|
||||||
|
private const val CUSTOM_ARTISTS_PATH = "artistImages"
|
||||||
private const val THEME_PREFS_KEY_DEFAULT = "[[kabouzeid_app-theme-helper]]"
|
private const val THEME_PREFS_KEY_DEFAULT = "[[kabouzeid_app-theme-helper]]"
|
||||||
|
|
||||||
private fun ZipEntry.isDatabaseEntry(): Boolean {
|
private fun ZipEntry.isDatabaseEntry(): Boolean {
|
||||||
|
@ -155,6 +235,14 @@ object BackupHelper {
|
||||||
return name.startsWith(IMAGES_PATH)
|
return name.startsWith(IMAGES_PATH)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun ZipEntry.isCustomArtistImageEntry(): Boolean {
|
||||||
|
return name.startsWith(CUSTOM_ARTISTS_PATH) && name.contains("custom_artist_images")
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun ZipEntry.isCustomArtistPrefEntry(): Boolean {
|
||||||
|
return name.startsWith(CUSTOM_ARTISTS_PATH) && name.contains("prefs")
|
||||||
|
}
|
||||||
|
|
||||||
private fun ZipEntry.getFileName(): String {
|
private fun ZipEntry.getFileName(): String {
|
||||||
return name.substring(name.lastIndexOf(File.separator))
|
return name.substring(name.lastIndexOf(File.separator))
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,7 @@ object M3UWriter : M3UConstants {
|
||||||
fun write(
|
fun write(
|
||||||
dir: File,
|
dir: File,
|
||||||
playlist: Playlist
|
playlist: Playlist
|
||||||
): File? {
|
): File {
|
||||||
if (!dir.exists()) dir.mkdirs()
|
if (!dir.exists()) dir.mkdirs()
|
||||||
val file = File(dir, playlist.name + "." + M3UConstants.EXTENSION)
|
val file = File(dir, playlist.name + "." + M3UConstants.EXTENSION)
|
||||||
val songs = playlist.getSongs()
|
val songs = playlist.getSongs()
|
||||||
|
|
|
@ -16,6 +16,7 @@ package code.name.monkey.retromusic.helper
|
||||||
|
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Message
|
import android.os.Message
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
class MusicProgressViewUpdateHelper : Handler {
|
class MusicProgressViewUpdateHelper : Handler {
|
||||||
|
|
||||||
|
@ -62,7 +63,7 @@ class MusicProgressViewUpdateHelper : Handler {
|
||||||
|
|
||||||
val remainingMillis = intervalPlaying - progressMillis % intervalPlaying
|
val remainingMillis = intervalPlaying - progressMillis % intervalPlaying
|
||||||
|
|
||||||
return Math.max(MIN_INTERVAL, remainingMillis)
|
return max(MIN_INTERVAL, remainingMillis)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun queueNextRefresh(delay: Long) {
|
private fun queueNextRefresh(delay: Long) {
|
||||||
|
|
|
@ -134,7 +134,7 @@ class SortOrder {
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
/* Artist song sort order A-Z */
|
/* Artist song sort order A-Z */
|
||||||
const val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER
|
private const val SONG_A_Z = MediaStore.Audio.Media.DEFAULT_SORT_ORDER
|
||||||
|
|
||||||
/* Artist song sort order Z-A */
|
/* Artist song sort order Z-A */
|
||||||
const val SONG_Z_A = "$SONG_A_Z DESC"
|
const val SONG_Z_A = "$SONG_A_Z DESC"
|
||||||
|
|
|
@ -76,8 +76,8 @@ public class StackBlur {
|
||||||
original.getPixels(currentPixels, 0, w, 0, 0, w, h);
|
original.getPixels(currentPixels, 0, w, 0, 0, w, h);
|
||||||
int cores = EXECUTOR_THREADS;
|
int cores = EXECUTOR_THREADS;
|
||||||
|
|
||||||
ArrayList<BlurTask> horizontal = new ArrayList<BlurTask>(cores);
|
ArrayList<BlurTask> horizontal = new ArrayList<>(cores);
|
||||||
ArrayList<BlurTask> vertical = new ArrayList<BlurTask>(cores);
|
ArrayList<BlurTask> vertical = new ArrayList<>(cores);
|
||||||
for (int i = 0; i < cores; i++) {
|
for (int i = 0; i < cores; i++) {
|
||||||
horizontal.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 1));
|
horizontal.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 1));
|
||||||
vertical.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 2));
|
vertical.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 2));
|
||||||
|
@ -158,7 +158,7 @@ public class StackBlur {
|
||||||
for (x = 0; x < w; x++) {
|
for (x = 0; x < w; x++) {
|
||||||
src[dst_i] =
|
src[dst_i] =
|
||||||
(int)
|
(int)
|
||||||
((src[dst_i] & 0xFFFFFFFF)
|
((src[dst_i])
|
||||||
| ((((sum_r * mul_sum) >>> shr_sum) & 0xff) << 16)
|
| ((((sum_r * mul_sum) >>> shr_sum) & 0xff) << 16)
|
||||||
| ((((sum_g * mul_sum) >>> shr_sum) & 0xff) << 8)
|
| ((((sum_g * mul_sum) >>> shr_sum) & 0xff) << 8)
|
||||||
| ((((sum_b * mul_sum) >>> shr_sum) & 0xff)));
|
| ((((sum_b * mul_sum) >>> shr_sum) & 0xff)));
|
||||||
|
@ -245,7 +245,7 @@ public class StackBlur {
|
||||||
for (y = 0; y < h; y++) {
|
for (y = 0; y < h; y++) {
|
||||||
src[dst_i] =
|
src[dst_i] =
|
||||||
(int)
|
(int)
|
||||||
((src[dst_i] & 0xFFFFFFFF)
|
((src[dst_i])
|
||||||
| ((((sum_r * mul_sum) >>> shr_sum) & 0xff) << 16)
|
| ((((sum_r * mul_sum) >>> shr_sum) & 0xff) << 16)
|
||||||
| ((((sum_g * mul_sum) >>> shr_sum) & 0xff) << 8)
|
| ((((sum_g * mul_sum) >>> shr_sum) & 0xff) << 8)
|
||||||
| ((((sum_b * mul_sum) >>> shr_sum) & 0xff)));
|
| ((((sum_b * mul_sum) >>> shr_sum) & 0xff)));
|
||||||
|
|
|
@ -1,138 +0,0 @@
|
||||||
package code.name.monkey.retromusic.lyrics;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
|
|
||||||
import java.io.BufferedReader;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.FileNotFoundException;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.InputStreamReader;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Desc : 歌词解析 Author : Lauzy Date : 2017/10/13 Blog : http://www.jianshu.com/u/e76853f863a9 Email :
|
|
||||||
* freedompaladin@gmail.com
|
|
||||||
*/
|
|
||||||
public class LrcHelper {
|
|
||||||
|
|
||||||
private static final String CHARSET = "utf-8";
|
|
||||||
// [03:56.00][03:18.00][02:06.00][01:07.00]原谅我这一生不羁放纵爱自由
|
|
||||||
private static final String LINE_REGEX = "((\\[\\d{2}:\\d{2}\\.\\d{2}])+)(.*)";
|
|
||||||
private static final String TIME_REGEX = "\\[(\\d{2}):(\\d{2})\\.(\\d{2})]";
|
|
||||||
|
|
||||||
public static List<Lrc> parseLrcFromAssets(Context context, String fileName) {
|
|
||||||
try {
|
|
||||||
return parseInputStream(context.getResources().getAssets().open(fileName));
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static List<Lrc> parseLrcFromFile(File file) {
|
|
||||||
try {
|
|
||||||
return parseInputStream(new FileInputStream(file));
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<Lrc> parseInputStream(InputStream inputStream) {
|
|
||||||
List<Lrc> lrcs = new ArrayList<>();
|
|
||||||
InputStreamReader isr = null;
|
|
||||||
BufferedReader br = null;
|
|
||||||
try {
|
|
||||||
isr = new InputStreamReader(inputStream, CHARSET);
|
|
||||||
br = new BufferedReader(isr);
|
|
||||||
String line;
|
|
||||||
while ((line = br.readLine()) != null) {
|
|
||||||
List<Lrc> lrcList = parseLrc(line);
|
|
||||||
if (lrcList != null && lrcList.size() != 0) {
|
|
||||||
lrcs.addAll(lrcList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sortLrcs(lrcs);
|
|
||||||
return lrcs;
|
|
||||||
} catch (UnsupportedEncodingException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (isr != null) {
|
|
||||||
isr.close();
|
|
||||||
}
|
|
||||||
if (br != null) {
|
|
||||||
br.close();
|
|
||||||
}
|
|
||||||
} catch (IOException e1) {
|
|
||||||
e1.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lrcs;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void sortLrcs(List<Lrc> lrcs) {
|
|
||||||
Collections.sort(
|
|
||||||
lrcs,
|
|
||||||
new Comparator<Lrc>() {
|
|
||||||
@Override
|
|
||||||
public int compare(Lrc o1, Lrc o2) {
|
|
||||||
return (int) (o1.getTime() - o2.getTime());
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private static List<Lrc> parseLrc(String lrcLine) {
|
|
||||||
if (lrcLine.trim().isEmpty()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
List<Lrc> lrcs = new ArrayList<>();
|
|
||||||
Matcher matcher = Pattern.compile(LINE_REGEX).matcher(lrcLine);
|
|
||||||
if (!matcher.matches()) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
String time = matcher.group(1);
|
|
||||||
String content = matcher.group(3);
|
|
||||||
Matcher timeMatcher = Pattern.compile(TIME_REGEX).matcher(time);
|
|
||||||
|
|
||||||
while (timeMatcher.find()) {
|
|
||||||
String min = timeMatcher.group(1);
|
|
||||||
String sec = timeMatcher.group(2);
|
|
||||||
String mil = timeMatcher.group(3);
|
|
||||||
Lrc lrc = new Lrc();
|
|
||||||
if (content != null && content.length() != 0) {
|
|
||||||
lrc.setTime(
|
|
||||||
Long.parseLong(min) * 60 * 1000
|
|
||||||
+ Long.parseLong(sec) * 1000
|
|
||||||
+ Long.parseLong(mil) * 10);
|
|
||||||
lrc.setText(content);
|
|
||||||
lrcs.add(lrc);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lrcs;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static String formatTime(long time) {
|
|
||||||
int min = (int) (time / 60000);
|
|
||||||
int sec = (int) (time / 1000 % 60);
|
|
||||||
return adjustFormat(min) + ":" + adjustFormat(sec);
|
|
||||||
}
|
|
||||||
|
|
||||||
private static String adjustFormat(int time) {
|
|
||||||
if (time < 10) {
|
|
||||||
return "0" + time;
|
|
||||||
}
|
|
||||||
return time + "";
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,59 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2019 Hemanth Savarala.
|
|
||||||
*
|
|
||||||
* Licensed under the GNU General Public License v3
|
|
||||||
*
|
|
||||||
* This is free software: you can redistribute it and/or modify it under
|
|
||||||
* the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation either version 3 of the License, or (at your option) any later version.
|
|
||||||
*
|
|
||||||
* This software is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
||||||
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the GNU General Public License for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package code.name.monkey.retromusic.misc
|
|
||||||
|
|
||||||
import com.google.android.material.appbar.AppBarLayout
|
|
||||||
import kotlin.math.abs
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author Hemanth S (h4h13).
|
|
||||||
* https://stackoverflow.com/a/33891727
|
|
||||||
*/
|
|
||||||
|
|
||||||
abstract class AppBarStateChangeListener : AppBarLayout.OnOffsetChangedListener {
|
|
||||||
|
|
||||||
private var mCurrentState = State.IDLE
|
|
||||||
|
|
||||||
override fun onOffsetChanged(appBarLayout: AppBarLayout, i: Int) {
|
|
||||||
when {
|
|
||||||
i == 0 -> {
|
|
||||||
if (mCurrentState != State.EXPANDED) {
|
|
||||||
onStateChanged(appBarLayout, State.EXPANDED)
|
|
||||||
}
|
|
||||||
mCurrentState = State.EXPANDED
|
|
||||||
}
|
|
||||||
abs(i) >= appBarLayout.totalScrollRange -> {
|
|
||||||
if (mCurrentState != State.COLLAPSED) {
|
|
||||||
onStateChanged(appBarLayout, State.COLLAPSED)
|
|
||||||
}
|
|
||||||
mCurrentState = State.COLLAPSED
|
|
||||||
}
|
|
||||||
else -> {
|
|
||||||
if (mCurrentState != State.IDLE) {
|
|
||||||
onStateChanged(appBarLayout, State.IDLE)
|
|
||||||
}
|
|
||||||
mCurrentState = State.IDLE
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract fun onStateChanged(appBarLayout: AppBarLayout, state: State)
|
|
||||||
|
|
||||||
enum class State {
|
|
||||||
EXPANDED,
|
|
||||||
COLLAPSED,
|
|
||||||
IDLE
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -78,8 +78,8 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
|
||||||
private final FragmentManager mFragmentManager;
|
private final FragmentManager mFragmentManager;
|
||||||
private FragmentTransaction mCurTransaction = null;
|
private FragmentTransaction mCurTransaction = null;
|
||||||
|
|
||||||
private final ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
|
private final ArrayList<Fragment.SavedState> mSavedState = new ArrayList<>();
|
||||||
private final ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
|
private final ArrayList<Fragment> mFragments = new ArrayList<>();
|
||||||
private Fragment mCurrentPrimaryItem = null;
|
private Fragment mCurrentPrimaryItem = null;
|
||||||
|
|
||||||
public CustomFragmentStatePagerAdapter(FragmentManager fm) {
|
public CustomFragmentStatePagerAdapter(FragmentManager fm) {
|
||||||
|
@ -92,11 +92,11 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
|
||||||
public abstract Fragment getItem(int position);
|
public abstract Fragment getItem(int position);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void startUpdate(ViewGroup container) {}
|
public void startUpdate(@NonNull ViewGroup container) {}
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public Object instantiateItem(ViewGroup container, int position) {
|
public Object instantiateItem(@NonNull ViewGroup container, int position) {
|
||||||
// If we already have this item instantiated, there is nothing
|
// If we already have this item instantiated, there is nothing
|
||||||
// to do. This can happen when we are restoring the entire pager
|
// to do. This can happen when we are restoring the entire pager
|
||||||
// from its saved state, where the fragment manager has already
|
// from its saved state, where the fragment manager has already
|
||||||
|
@ -132,7 +132,7 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void destroyItem(ViewGroup container, int position, Object object) {
|
public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
|
||||||
Fragment fragment = (Fragment) object;
|
Fragment fragment = (Fragment) object;
|
||||||
|
|
||||||
if (mCurTransaction == null) {
|
if (mCurTransaction == null) {
|
||||||
|
@ -152,23 +152,21 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setPrimaryItem(ViewGroup container, int position, Object object) {
|
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
|
||||||
Fragment fragment = (Fragment) object;
|
Fragment fragment = (Fragment) object;
|
||||||
if (fragment != mCurrentPrimaryItem) {
|
if (fragment != mCurrentPrimaryItem) {
|
||||||
if (mCurrentPrimaryItem != null) {
|
if (mCurrentPrimaryItem != null) {
|
||||||
mCurrentPrimaryItem.setMenuVisibility(false);
|
mCurrentPrimaryItem.setMenuVisibility(false);
|
||||||
mCurrentPrimaryItem.setUserVisibleHint(false);
|
mCurrentPrimaryItem.setUserVisibleHint(false);
|
||||||
}
|
}
|
||||||
if (fragment != null) {
|
|
||||||
fragment.setMenuVisibility(true);
|
fragment.setMenuVisibility(true);
|
||||||
fragment.setUserVisibleHint(true);
|
fragment.setUserVisibleHint(true);
|
||||||
}
|
|
||||||
mCurrentPrimaryItem = fragment;
|
mCurrentPrimaryItem = fragment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void finishUpdate(ViewGroup container) {
|
public void finishUpdate(@NonNull ViewGroup container) {
|
||||||
if (mCurTransaction != null) {
|
if (mCurTransaction != null) {
|
||||||
mCurTransaction.commitAllowingStateLoss();
|
mCurTransaction.commitAllowingStateLoss();
|
||||||
mCurTransaction = null;
|
mCurTransaction = null;
|
||||||
|
@ -177,7 +175,7 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isViewFromObject(View view, Object object) {
|
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
|
||||||
return ((Fragment) object).getView() == view;
|
return ((Fragment) object).getView() == view;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -212,8 +210,8 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
|
||||||
mSavedState.clear();
|
mSavedState.clear();
|
||||||
mFragments.clear();
|
mFragments.clear();
|
||||||
if (fss != null) {
|
if (fss != null) {
|
||||||
for (int i = 0; i < fss.length; i++) {
|
for (Parcelable parcelable : fss) {
|
||||||
mSavedState.add((Fragment.SavedState) fss[i]);
|
mSavedState.add((Fragment.SavedState) parcelable);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Iterable<String> keys = bundle.keySet();
|
Iterable<String> keys = bundle.keySet();
|
||||||
|
|
|
@ -40,8 +40,6 @@ abstract class WrappedAsyncTaskLoader<D>
|
||||||
if (!isReset) {
|
if (!isReset) {
|
||||||
this.mData = data
|
this.mData = data
|
||||||
super.deliverResult(data)
|
super.deliverResult(data)
|
||||||
} else {
|
|
||||||
// An asynchronous query came in while the loader is stopped
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -148,7 +148,7 @@ class AlbumCoverStylePreferenceDialog : DialogFragment(),
|
||||||
return view === instace
|
return view === instace
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPageTitle(position: Int): CharSequence? {
|
override fun getPageTitle(position: Int): CharSequence {
|
||||||
return context.getString(values()[position].titleRes)
|
return context.getString(values()[position].titleRes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ import android.app.Dialog
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
import android.os.Bundle
|
import android.os.Bundle
|
||||||
import android.util.AttributeSet
|
import android.util.AttributeSet
|
||||||
|
import androidx.appcompat.app.AlertDialog
|
||||||
import androidx.core.graphics.BlendModeColorFilterCompat
|
import androidx.core.graphics.BlendModeColorFilterCompat
|
||||||
import androidx.core.graphics.BlendModeCompat.SRC_IN
|
import androidx.core.graphics.BlendModeCompat.SRC_IN
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
|
@ -26,6 +27,7 @@ import code.name.monkey.appthemehelper.common.prefs.supportv7.ATEDialogPreferenc
|
||||||
import code.name.monkey.retromusic.App
|
import code.name.monkey.retromusic.App
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.dialogs.BlacklistFolderChooserDialog
|
import code.name.monkey.retromusic.dialogs.BlacklistFolderChooserDialog
|
||||||
|
import code.name.monkey.retromusic.extensions.accentTextColor
|
||||||
import code.name.monkey.retromusic.extensions.colorButtons
|
import code.name.monkey.retromusic.extensions.colorButtons
|
||||||
import code.name.monkey.retromusic.extensions.colorControlNormal
|
import code.name.monkey.retromusic.extensions.colorControlNormal
|
||||||
import code.name.monkey.retromusic.extensions.materialDialog
|
import code.name.monkey.retromusic.extensions.materialDialog
|
||||||
|
@ -69,11 +71,7 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
|
||||||
.setNeutralButton(R.string.clear_action) { _, _ ->
|
.setNeutralButton(R.string.clear_action) { _, _ ->
|
||||||
materialDialog(R.string.clear_blacklist)
|
materialDialog(R.string.clear_blacklist)
|
||||||
.setMessage(R.string.do_you_want_to_clear_the_blacklist)
|
.setMessage(R.string.do_you_want_to_clear_the_blacklist)
|
||||||
.setPositiveButton(R.string.clear_action) { _, _ ->
|
.setPositiveButton(R.string.clear_action, null)
|
||||||
BlacklistStore.getInstance(
|
|
||||||
requireContext()
|
|
||||||
).clear()
|
|
||||||
}
|
|
||||||
.setNegativeButton(android.R.string.cancel, null)
|
.setNegativeButton(android.R.string.cancel, null)
|
||||||
.create()
|
.create()
|
||||||
.colorButtons()
|
.colorButtons()
|
||||||
|
@ -107,7 +105,21 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
|
||||||
.colorButtons()
|
.colorButtons()
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
.create().colorButtons()
|
.create().apply {
|
||||||
|
setOnShowListener {
|
||||||
|
getButton(AlertDialog.BUTTON_POSITIVE).accentTextColor()
|
||||||
|
getButton(AlertDialog.BUTTON_NEGATIVE).accentTextColor()
|
||||||
|
getButton(AlertDialog.BUTTON_NEUTRAL).apply {
|
||||||
|
accentTextColor()
|
||||||
|
setOnClickListener {
|
||||||
|
BlacklistStore.getInstance(
|
||||||
|
requireContext()
|
||||||
|
).clear()
|
||||||
|
dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private lateinit var paths: ArrayList<String>
|
private lateinit var paths: ArrayList<String>
|
||||||
|
|
|
@ -153,7 +153,7 @@ private class NowPlayingScreenAdapter(private val context: Context) : PagerAdapt
|
||||||
return view === instance
|
return view === instance
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getPageTitle(position: Int): CharSequence? {
|
override fun getPageTitle(position: Int): CharSequence {
|
||||||
return context.getString(values()[position].titleRes)
|
return context.getString(values()[position].titleRes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,17 +84,14 @@ public class HistoryStore extends SQLiteOpenHelper {
|
||||||
database.insert(RecentStoreColumns.NAME, null, values);
|
database.insert(RecentStoreColumns.NAME, null, values);
|
||||||
|
|
||||||
// if our db is too large, delete the extra items
|
// if our db is too large, delete the extra items
|
||||||
Cursor oldest = null;
|
try (Cursor oldest = database.query(
|
||||||
try {
|
|
||||||
oldest =
|
|
||||||
database.query(
|
|
||||||
RecentStoreColumns.NAME,
|
RecentStoreColumns.NAME,
|
||||||
new String[] {RecentStoreColumns.TIME_PLAYED},
|
new String[]{RecentStoreColumns.TIME_PLAYED},
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
RecentStoreColumns.TIME_PLAYED + " ASC");
|
RecentStoreColumns.TIME_PLAYED + " ASC")) {
|
||||||
|
|
||||||
if (oldest != null && oldest.getCount() > MAX_ITEMS_IN_DB) {
|
if (oldest != null && oldest.getCount() > MAX_ITEMS_IN_DB) {
|
||||||
oldest.moveToPosition(oldest.getCount() - MAX_ITEMS_IN_DB);
|
oldest.moveToPosition(oldest.getCount() - MAX_ITEMS_IN_DB);
|
||||||
|
@ -103,11 +100,7 @@ public class HistoryStore extends SQLiteOpenHelper {
|
||||||
database.delete(
|
database.delete(
|
||||||
RecentStoreColumns.NAME,
|
RecentStoreColumns.NAME,
|
||||||
RecentStoreColumns.TIME_PLAYED + " < ?",
|
RecentStoreColumns.TIME_PLAYED + " < ?",
|
||||||
new String[] {String.valueOf(timeOfRecordToKeep)});
|
new String[]{String.valueOf(timeOfRecordToKeep)});
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (oldest != null) {
|
|
||||||
oldest.close();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
|
|
|
@ -40,14 +40,11 @@ public class SongPlayCountStore extends SQLiteOpenHelper {
|
||||||
@NonNull
|
@NonNull
|
||||||
private static final Interpolator sInterpolator = new AccelerateInterpolator(1.5f);
|
private static final Interpolator sInterpolator = new AccelerateInterpolator(1.5f);
|
||||||
// how high to multiply the interpolation curve
|
// how high to multiply the interpolation curve
|
||||||
@SuppressWarnings("FieldCanBeLocal")
|
|
||||||
private static final int INTERPOLATOR_HEIGHT = 50;
|
private static final int INTERPOLATOR_HEIGHT = 50;
|
||||||
|
|
||||||
// how high the base value is. The ratio of the Height to Base is what really matters
|
// how high the base value is. The ratio of the Height to Base is what really matters
|
||||||
@SuppressWarnings("FieldCanBeLocal")
|
|
||||||
private static final int INTERPOLATOR_BASE = 25;
|
private static final int INTERPOLATOR_BASE = 25;
|
||||||
|
|
||||||
@SuppressWarnings("FieldCanBeLocal")
|
|
||||||
private static final int ONE_WEEK_IN_MS = 1000 * 60 * 60 * 24 * 7;
|
private static final int ONE_WEEK_IN_MS = 1000 * 60 * 60 * 24 * 7;
|
||||||
|
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -257,7 +254,7 @@ public class SongPlayCountStore extends SQLiteOpenHelper {
|
||||||
for (int i = 0; i < NUM_WEEKS - weekDiff; i++) {
|
for (int i = 0; i < NUM_WEEKS - weekDiff; i++) {
|
||||||
playCounts[i + weekDiff] = cursor.getInt(getColumnIndexForWeek(i));
|
playCounts[i + weekDiff] = cursor.getInt(getColumnIndexForWeek(i));
|
||||||
}
|
}
|
||||||
} else if (weekDiff < 0) {
|
} else {
|
||||||
// time is shifted backwards (by user) - nor typical behavior but we
|
// time is shifted backwards (by user) - nor typical behavior but we
|
||||||
// will still handle it
|
// will still handle it
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
package code.name.monkey.retromusic.repository
|
package code.name.monkey.retromusic.repository
|
||||||
|
|
||||||
import android.provider.MediaStore.Audio.AudioColumns
|
import android.provider.MediaStore.Audio.AudioColumns
|
||||||
|
import code.name.monkey.retromusic.ALBUM_ARTIST
|
||||||
import code.name.monkey.retromusic.helper.SortOrder
|
import code.name.monkey.retromusic.helper.SortOrder
|
||||||
import code.name.monkey.retromusic.model.Album
|
import code.name.monkey.retromusic.model.Album
|
||||||
import code.name.monkey.retromusic.model.Artist
|
import code.name.monkey.retromusic.model.Artist
|
||||||
|
@ -110,7 +111,8 @@ class RealArtistRepository(
|
||||||
songRepository.makeSongCursor(
|
songRepository.makeSongCursor(
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
getSongLoaderSortOrder()
|
"lower($ALBUM_ARTIST)" +
|
||||||
|
if (PreferenceUtil.artistSortOrder == SortOrder.ArtistSortOrder.ARTIST_A_Z) "" else " DESC"
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
return splitIntoAlbumArtists(albumRepository.splitIntoAlbums(songs))
|
return splitIntoAlbumArtists(albumRepository.splitIntoAlbums(songs))
|
||||||
|
@ -155,12 +157,6 @@ class RealArtistRepository(
|
||||||
} else {
|
} else {
|
||||||
Artist.empty
|
Artist.empty
|
||||||
}
|
}
|
||||||
}.apply {
|
|
||||||
if (PreferenceUtil.artistSortOrder == SortOrder.ArtistSortOrder.ARTIST_A_Z) {
|
|
||||||
sortedBy { it.name.lowercase() }
|
|
||||||
} else {
|
|
||||||
sortedByDescending { it.name.lowercase() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,7 @@ interface Repository {
|
||||||
suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
|
suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||||
suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
|
suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||||
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||||
|
suspend fun deleteSongInHistory(songId: Long)
|
||||||
suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity>
|
suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity>
|
||||||
suspend fun playCountSongs(): List<PlayCountEntity>
|
suspend fun playCountSongs(): List<PlayCountEntity>
|
||||||
suspend fun blackListPaths(): List<BlackListStoreEntity>
|
suspend fun blackListPaths(): List<BlackListStoreEntity>
|
||||||
|
@ -323,6 +324,9 @@ class RealRepository(
|
||||||
override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) =
|
override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) =
|
||||||
roomRepository.deleteSongInPlayCount(playCountEntity)
|
roomRepository.deleteSongInPlayCount(playCountEntity)
|
||||||
|
|
||||||
|
override suspend fun deleteSongInHistory(songId: Long) =
|
||||||
|
roomRepository.deleteSongInHistory(songId)
|
||||||
|
|
||||||
override suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity> =
|
override suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity> =
|
||||||
roomRepository.checkSongExistInPlayCount(songId)
|
roomRepository.checkSongExistInPlayCount(songId)
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ interface RoomRepository {
|
||||||
suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
|
suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||||
suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
|
suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||||
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||||
|
suspend fun deleteSongInHistory(songId: Long)
|
||||||
suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity>
|
suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity>
|
||||||
suspend fun playCountSongs(): List<PlayCountEntity>
|
suspend fun playCountSongs(): List<PlayCountEntity>
|
||||||
suspend fun insertBlacklistPath(blackListStoreEntities: List<BlackListStoreEntity>)
|
suspend fun insertBlacklistPath(blackListStoreEntities: List<BlackListStoreEntity>)
|
||||||
|
@ -161,6 +162,10 @@ class RealRoomRepository(
|
||||||
override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) =
|
override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) =
|
||||||
playCountDao.deleteSongInPlayCount(playCountEntity)
|
playCountDao.deleteSongInPlayCount(playCountEntity)
|
||||||
|
|
||||||
|
override suspend fun deleteSongInHistory(songId: Long) {
|
||||||
|
historyDao.deleteSongInHistory(songId)
|
||||||
|
}
|
||||||
|
|
||||||
override suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity> =
|
override suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity> =
|
||||||
playCountDao.checkSongExistInPlayCount(songId)
|
playCountDao.checkSongExistInPlayCount(songId)
|
||||||
|
|
||||||
|
|
|
@ -75,7 +75,7 @@ class RealTopPlayedRepository(
|
||||||
val notRecentlyPlayedSongs = songRepository.songs(
|
val notRecentlyPlayedSongs = songRepository.songs(
|
||||||
makeNotRecentTracksCursorAndClearUpDatabase()
|
makeNotRecentTracksCursorAndClearUpDatabase()
|
||||||
)
|
)
|
||||||
allSongs.removeAll(playedSongs)
|
allSongs.removeAll(playedSongs.toSet())
|
||||||
allSongs.addAll(notRecentlyPlayedSongs)
|
allSongs.addAll(notRecentlyPlayedSongs)
|
||||||
return allSongs
|
return allSongs
|
||||||
}
|
}
|
||||||
|
|
|
@ -75,6 +75,7 @@ import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
|
||||||
|
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.LockScreenActivity;
|
import code.name.monkey.retromusic.activities.LockScreenActivity;
|
||||||
import code.name.monkey.retromusic.appwidgets.AppWidgetBig;
|
import code.name.monkey.retromusic.appwidgets.AppWidgetBig;
|
||||||
|
@ -245,7 +246,6 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
private List<Song> originalPlayingQueue = new ArrayList<>();
|
private List<Song> originalPlayingQueue = new ArrayList<>();
|
||||||
private List<Song> playingQueue = new ArrayList<>();
|
private List<Song> playingQueue = new ArrayList<>();
|
||||||
private boolean pausedByTransientLossOfFocus;
|
private boolean pausedByTransientLossOfFocus;
|
||||||
private AudioVolumeObserver audioVolumeObserver = null;
|
|
||||||
|
|
||||||
private final BroadcastReceiver becomingNoisyReceiver =
|
private final BroadcastReceiver becomingNoisyReceiver =
|
||||||
new BroadcastReceiver() {
|
new BroadcastReceiver() {
|
||||||
|
@ -453,7 +453,7 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
.registerContentObserver(
|
.registerContentObserver(
|
||||||
MediaStore.Audio.Playlists.INTERNAL_CONTENT_URI, true, mediaStoreObserver);
|
MediaStore.Audio.Playlists.INTERNAL_CONTENT_URI, true, mediaStoreObserver);
|
||||||
|
|
||||||
audioVolumeObserver = new AudioVolumeObserver(this);
|
AudioVolumeObserver audioVolumeObserver = new AudioVolumeObserver(this);
|
||||||
audioVolumeObserver.register(AudioManager.STREAM_MUSIC, this);
|
audioVolumeObserver.register(AudioManager.STREAM_MUSIC, this);
|
||||||
|
|
||||||
PreferenceUtil.INSTANCE.registerOnSharedPreferenceChangedListener(this);
|
PreferenceUtil.INSTANCE.registerOnSharedPreferenceChangedListener(this);
|
||||||
|
@ -837,8 +837,7 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
// Request from an untrusted package: return an empty browser root
|
// Request from an untrusted package: return an empty browser root
|
||||||
return new BrowserRoot(AutoMediaIDHelper.MEDIA_ID_EMPTY_ROOT, null);
|
return new BrowserRoot(AutoMediaIDHelper.MEDIA_ID_EMPTY_ROOT, null);
|
||||||
} else {
|
} else {
|
||||||
/**
|
/** By default return the browsable root. Treat the EXTRA_RECENT flag as a special case
|
||||||
* By default return the browsable root. Treat the EXTRA_RECENT flag as a special case
|
|
||||||
* and return the recent root instead.
|
* and return the recent root instead.
|
||||||
*/
|
*/
|
||||||
boolean isRecentRequest = false;
|
boolean isRecentRequest = false;
|
||||||
|
@ -1157,7 +1156,7 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
playback.setNextDataSource(getTrackUri(Objects.requireNonNull(getSongAt(nextPosition))));
|
playback.setNextDataSource(getTrackUri(Objects.requireNonNull(getSongAt(nextPosition))));
|
||||||
}
|
}
|
||||||
this.nextPosition = nextPosition;
|
this.nextPosition = nextPosition;
|
||||||
} catch (Exception e) {
|
} catch (Exception ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1350,9 +1349,7 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
.putLong(MediaMetadataCompat.METADATA_KEY_YEAR, song.getYear())
|
.putLong(MediaMetadataCompat.METADATA_KEY_YEAR, song.getYear())
|
||||||
.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, null);
|
.putBitmap(MediaMetadataCompat.METADATA_KEY_ALBUM_ART, null);
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
metaData.putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, getPlayingQueue().size());
|
metaData.putLong(MediaMetadataCompat.METADATA_KEY_NUM_TRACKS, getPlayingQueue().size());
|
||||||
}
|
|
||||||
|
|
||||||
if (PreferenceUtil.INSTANCE.isAlbumArtOnLockScreen()) {
|
if (PreferenceUtil.INSTANCE.isAlbumArtOnLockScreen()) {
|
||||||
final Point screenSize = RetroUtil.getScreenSize(MusicService.this);
|
final Point screenSize = RetroUtil.getScreenSize(MusicService.this);
|
||||||
|
@ -1595,11 +1592,8 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
mediaButtonIntent.setComponent(mediaButtonReceiverComponentName);
|
mediaButtonIntent.setComponent(mediaButtonReceiverComponentName);
|
||||||
|
|
||||||
PendingIntent mediaButtonReceiverPendingIntent;
|
PendingIntent mediaButtonReceiverPendingIntent;
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
|
mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent,
|
||||||
mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, PendingIntent.FLAG_MUTABLE);
|
VersionUtils.INSTANCE.hasMarshmallow() ? PendingIntent.FLAG_IMMUTABLE : 0);
|
||||||
} else {
|
|
||||||
mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
mediaSession = new MediaSessionCompat(
|
mediaSession = new MediaSessionCompat(
|
||||||
this,
|
this,
|
||||||
|
@ -1608,9 +1602,6 @@ public class MusicService extends MediaBrowserServiceCompat
|
||||||
mediaButtonReceiverPendingIntent);
|
mediaButtonReceiverPendingIntent);
|
||||||
MediaSessionCallback mediasessionCallback =
|
MediaSessionCallback mediasessionCallback =
|
||||||
new MediaSessionCallback(getApplicationContext(), this);
|
new MediaSessionCallback(getApplicationContext(), this);
|
||||||
mediaSession.setFlags(
|
|
||||||
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
|
|
||||||
| MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
|
|
||||||
mediaSession.setCallback(mediasessionCallback);
|
mediaSession.setCallback(mediasessionCallback);
|
||||||
mediaSession.setActive(true);
|
mediaSession.setActive(true);
|
||||||
mediaSession.setMediaButtonReceiver(mediaButtonReceiverPendingIntent);
|
mediaSession.setMediaButtonReceiver(mediaButtonReceiverPendingIntent);
|
||||||
|
|
|
@ -38,6 +38,6 @@ class ThrottledSeekHandler(
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// milliseconds to throttle before calling run() to aggregate events
|
// milliseconds to throttle before calling run() to aggregate events
|
||||||
private val THROTTLE: Long = 500
|
private const val THROTTLE: Long = 500
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -19,6 +19,7 @@ import android.app.Notification
|
||||||
import android.app.NotificationChannel
|
import android.app.NotificationChannel
|
||||||
import android.app.NotificationManager
|
import android.app.NotificationManager
|
||||||
import android.content.Context.NOTIFICATION_SERVICE
|
import android.content.Context.NOTIFICATION_SERVICE
|
||||||
|
import android.content.pm.ServiceInfo
|
||||||
import android.os.Build
|
import android.os.Build
|
||||||
import androidx.annotation.RequiresApi
|
import androidx.annotation.RequiresApi
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
|
@ -62,7 +63,15 @@ abstract class PlayingNotification {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newNotifyMode == NOTIFY_MODE_FOREGROUND) {
|
if (newNotifyMode == NOTIFY_MODE_FOREGROUND) {
|
||||||
service.startForeground(NOTIFICATION_ID, notification)
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
|
service.startForeground(
|
||||||
|
NOTIFICATION_ID,
|
||||||
|
notification,
|
||||||
|
ServiceInfo.FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACK
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
service.startForeground(NOTIFICATION_ID,notification)
|
||||||
|
}
|
||||||
} else if (newNotifyMode == NOTIFY_MODE_BACKGROUND) {
|
} else if (newNotifyMode == NOTIFY_MODE_BACKGROUND) {
|
||||||
notificationManager!!.notify(NOTIFICATION_ID, notification)
|
notificationManager!!.notify(NOTIFICATION_ID, notification)
|
||||||
}
|
}
|
||||||
|
|
|
@ -25,6 +25,7 @@ import android.os.Build
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.text.HtmlCompat
|
import androidx.core.text.HtmlCompat
|
||||||
import androidx.media.app.NotificationCompat.MediaStyle
|
import androidx.media.app.NotificationCompat.MediaStyle
|
||||||
|
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.db.PlaylistEntity
|
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||||
|
@ -53,7 +54,7 @@ class PlayingNotificationImpl : PlayingNotification(), KoinComponent {
|
||||||
stopped = false
|
stopped = false
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
val song = service.currentSong
|
val song = service.currentSong
|
||||||
val playlist: PlaylistEntity? = MusicUtil.repository.favoritePlaylist()
|
val playlist: PlaylistEntity = MusicUtil.repository.favoritePlaylist()
|
||||||
val isPlaying = service.isPlaying
|
val isPlaying = service.isPlaying
|
||||||
val isFavorite = if (playlist != null) {
|
val isFavorite = if (playlist != null) {
|
||||||
val songEntity = song.toSongEntity(playlist.playListId)
|
val songEntity = song.toSongEntity(playlist.playListId)
|
||||||
|
@ -69,11 +70,11 @@ class PlayingNotificationImpl : PlayingNotification(), KoinComponent {
|
||||||
action.putExtra(MainActivity.EXPAND_PANEL, PreferenceUtil.isExpandPanel)
|
action.putExtra(MainActivity.EXPAND_PANEL, PreferenceUtil.isExpandPanel)
|
||||||
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||||
val clickIntent =
|
val clickIntent =
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
PendingIntent.getActivity(
|
||||||
PendingIntent.getActivity(service, 0, action, PendingIntent.FLAG_IMMUTABLE)
|
service, 0, action, if (VersionUtils.hasMarshmallow())
|
||||||
} else {
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
PendingIntent.getActivity(service, 0, action, PendingIntent.FLAG_UPDATE_CURRENT)
|
else 0 or PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
}
|
)
|
||||||
|
|
||||||
val serviceName = ComponentName(service, MusicService::class.java)
|
val serviceName = ComponentName(service, MusicService::class.java)
|
||||||
val intent = Intent(ACTION_QUIT)
|
val intent = Intent(ACTION_QUIT)
|
||||||
|
@ -82,7 +83,9 @@ class PlayingNotificationImpl : PlayingNotification(), KoinComponent {
|
||||||
service,
|
service,
|
||||||
0,
|
0,
|
||||||
intent,
|
intent,
|
||||||
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
|
if (VersionUtils.hasMarshmallow())
|
||||||
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
|
else 0 or PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
)
|
)
|
||||||
val bigNotificationImageSize = service.resources
|
val bigNotificationImageSize = service.resources
|
||||||
.getDimensionPixelSize(R.dimen.notification_big_image_size)
|
.getDimensionPixelSize(R.dimen.notification_big_image_size)
|
||||||
|
@ -171,7 +174,6 @@ class PlayingNotificationImpl : PlayingNotification(), KoinComponent {
|
||||||
.addAction(playPauseAction)
|
.addAction(playPauseAction)
|
||||||
.addAction(nextAction)
|
.addAction(nextAction)
|
||||||
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
|
||||||
builder.setStyle(
|
builder.setStyle(
|
||||||
MediaStyle()
|
MediaStyle()
|
||||||
.setMediaSession(service.mediaSession.sessionToken)
|
.setMediaSession(service.mediaSession.sessionToken)
|
||||||
|
@ -183,7 +185,6 @@ class PlayingNotificationImpl : PlayingNotification(), KoinComponent {
|
||||||
) {
|
) {
|
||||||
builder.color = color
|
builder.color = color
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (stopped) {
|
if (stopped) {
|
||||||
return // notification has been stopped before loading was finished
|
return // notification has been stopped before loading was finished
|
||||||
|
@ -199,6 +200,10 @@ class PlayingNotificationImpl : PlayingNotification(), KoinComponent {
|
||||||
val serviceName = ComponentName(service, MusicService::class.java)
|
val serviceName = ComponentName(service, MusicService::class.java)
|
||||||
val intent = Intent(action)
|
val intent = Intent(action)
|
||||||
intent.component = serviceName
|
intent.component = serviceName
|
||||||
return PendingIntent.getService(service, 0, intent, PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT)
|
return PendingIntent.getService(
|
||||||
|
service, 0, intent,
|
||||||
|
if (VersionUtils.hasMarshmallow()) PendingIntent.FLAG_IMMUTABLE
|
||||||
|
else 0 or PendingIntent.FLAG_UPDATE_CURRENT
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -83,7 +83,9 @@ class PlayingNotificationOreo : PlayingNotification() {
|
||||||
service,
|
service,
|
||||||
0,
|
0,
|
||||||
action,
|
action,
|
||||||
PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_IMMUTABLE
|
PendingIntent.FLAG_UPDATE_CURRENT or if (VersionUtils.hasMarshmallow())
|
||||||
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
|
else 0
|
||||||
)
|
)
|
||||||
val deleteIntent = buildPendingIntent(service, ACTION_QUIT, null)
|
val deleteIntent = buildPendingIntent(service, ACTION_QUIT, null)
|
||||||
|
|
||||||
|
@ -181,21 +183,21 @@ class PlayingNotificationOreo : PlayingNotification() {
|
||||||
service,
|
service,
|
||||||
R.drawable.ic_close,
|
R.drawable.ic_close,
|
||||||
primary
|
primary
|
||||||
)!!, NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
||||||
)
|
)
|
||||||
val prev = createBitmap(
|
val prev = createBitmap(
|
||||||
RetroUtil.getTintedVectorDrawable(
|
RetroUtil.getTintedVectorDrawable(
|
||||||
service,
|
service,
|
||||||
R.drawable.ic_skip_previous_round_white_32dp,
|
R.drawable.ic_skip_previous_round_white_32dp,
|
||||||
primary
|
primary
|
||||||
)!!, NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
||||||
)
|
)
|
||||||
val next = createBitmap(
|
val next = createBitmap(
|
||||||
RetroUtil.getTintedVectorDrawable(
|
RetroUtil.getTintedVectorDrawable(
|
||||||
service,
|
service,
|
||||||
R.drawable.ic_skip_next_round_white_32dp,
|
R.drawable.ic_skip_next_round_white_32dp,
|
||||||
primary
|
primary
|
||||||
)!!, NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
||||||
)
|
)
|
||||||
val playPause = createBitmap(
|
val playPause = createBitmap(
|
||||||
RetroUtil.getTintedVectorDrawable(
|
RetroUtil.getTintedVectorDrawable(
|
||||||
|
@ -204,7 +206,7 @@ class PlayingNotificationOreo : PlayingNotification() {
|
||||||
R.drawable.ic_pause_white_48dp
|
R.drawable.ic_pause_white_48dp
|
||||||
else
|
else
|
||||||
R.drawable.ic_play_arrow_white_48dp, primary
|
R.drawable.ic_play_arrow_white_48dp, primary
|
||||||
)!!, NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
||||||
)
|
)
|
||||||
|
|
||||||
notificationLayout.setTextColor(R.id.title, primary)
|
notificationLayout.setTextColor(R.id.title, primary)
|
||||||
|
@ -231,7 +233,7 @@ class PlayingNotificationOreo : PlayingNotification() {
|
||||||
service,
|
service,
|
||||||
R.drawable.ic_notification,
|
R.drawable.ic_notification,
|
||||||
secondary
|
secondary
|
||||||
)!!, 0.6f
|
), 0.6f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
notificationLayoutBig.setImageViewBitmap(
|
notificationLayoutBig.setImageViewBitmap(
|
||||||
|
@ -241,7 +243,7 @@ class PlayingNotificationOreo : PlayingNotification() {
|
||||||
service,
|
service,
|
||||||
R.drawable.ic_notification,
|
R.drawable.ic_notification,
|
||||||
secondary
|
secondary
|
||||||
)!!, 0.6f
|
), 0.6f
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -262,7 +264,11 @@ class PlayingNotificationOreo : PlayingNotification() {
|
||||||
): PendingIntent {
|
): PendingIntent {
|
||||||
val intent = Intent(action)
|
val intent = Intent(action)
|
||||||
intent.component = serviceName
|
intent.component = serviceName
|
||||||
return PendingIntent.getService(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
return PendingIntent.getService(
|
||||||
|
context, 0, intent, if (VersionUtils.hasMarshmallow())
|
||||||
|
PendingIntent.FLAG_IMMUTABLE
|
||||||
|
else 0
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,8 +0,0 @@
|
||||||
package code.name.monkey.retromusic.state
|
|
||||||
|
|
||||||
enum class NowPlayingPanelState {
|
|
||||||
EXPAND,
|
|
||||||
COLLAPSED_WITH,
|
|
||||||
COLLAPSED_WITHOUT,
|
|
||||||
HIDE,
|
|
||||||
}
|
|
|
@ -16,26 +16,32 @@ package code.name.monkey.retromusic.transform
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.viewpager.widget.ViewPager
|
import androidx.viewpager.widget.ViewPager
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
class DepthTransformation : ViewPager.PageTransformer {
|
class DepthTransformation : ViewPager.PageTransformer {
|
||||||
override fun transformPage(page: View, position: Float) {
|
override fun transformPage(page: View, position: Float) {
|
||||||
if (position < -1) { // [-Infinity,-1)
|
when {
|
||||||
|
position < -1 -> { // [-Infinity,-1)
|
||||||
// This page is way off-screen to the left.
|
// This page is way off-screen to the left.
|
||||||
page.alpha = 0f
|
page.alpha = 0f
|
||||||
} else if (position <= 0) { // [-1,0]
|
}
|
||||||
|
position <= 0 -> { // [-1,0]
|
||||||
page.alpha = 1f
|
page.alpha = 1f
|
||||||
page.translationX = 0f
|
page.translationX = 0f
|
||||||
page.scaleX = 1f
|
page.scaleX = 1f
|
||||||
page.scaleY = 1f
|
page.scaleY = 1f
|
||||||
} else if (position <= 1) { // (0,1]
|
}
|
||||||
|
position <= 1 -> { // (0,1]
|
||||||
page.translationX = -position * page.width
|
page.translationX = -position * page.width
|
||||||
page.alpha = 1 - Math.abs(position)
|
page.alpha = 1 - abs(position)
|
||||||
page.scaleX = 1 - Math.abs(position)
|
page.scaleX = 1 - abs(position)
|
||||||
page.scaleY = 1 - Math.abs(position)
|
page.scaleY = 1 - abs(position)
|
||||||
} else { // (1,+Infinity]
|
}
|
||||||
|
else -> { // (1,+Infinity]
|
||||||
// This page is way off-screen to the right.
|
// This page is way off-screen to the right.
|
||||||
page.alpha = 0f
|
page.alpha = 0f
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -16,6 +16,7 @@ package code.name.monkey.retromusic.transform
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.viewpager.widget.ViewPager
|
import androidx.viewpager.widget.ViewPager
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
class HorizontalFlipTransformation : ViewPager.PageTransformer {
|
class HorizontalFlipTransformation : ViewPager.PageTransformer {
|
||||||
override fun transformPage(page: View, position: Float) {
|
override fun transformPage(page: View, position: Float) {
|
||||||
|
@ -30,21 +31,23 @@ class HorizontalFlipTransformation : ViewPager.PageTransformer {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (position < -1) { // [-Infinity,-1)
|
when {
|
||||||
|
position < -1 -> { // [-Infinity,-1)
|
||||||
// This page is way off-screen to the left.
|
// This page is way off-screen to the left.
|
||||||
page.alpha = 0f
|
page.alpha = 0f
|
||||||
|
}
|
||||||
} else if (position <= 0) { // [-1,0]
|
position <= 0 -> { // [-1,0]
|
||||||
page.alpha = 1f
|
page.alpha = 1f
|
||||||
page.rotationX = 180 * (1 - Math.abs(position) + 1)
|
page.rotationX = 180 * (1 - abs(position) + 1)
|
||||||
|
}
|
||||||
} else if (position <= 1) { // (0,1]
|
position <= 1 -> { // (0,1]
|
||||||
page.alpha = 1f
|
page.alpha = 1f
|
||||||
page.rotationX = -180 * (1 - Math.abs(position) + 1)
|
page.rotationX = -180 * (1 - abs(position) + 1)
|
||||||
|
}
|
||||||
} else { // (1,+Infinity]
|
else -> { // (1,+Infinity]
|
||||||
// This page is way off-screen to the right.
|
// This page is way off-screen to the right.
|
||||||
page.alpha = 0f
|
page.alpha = 0f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -16,6 +16,8 @@ package code.name.monkey.retromusic.transform
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.viewpager.widget.ViewPager
|
import androidx.viewpager.widget.ViewPager
|
||||||
|
import kotlin.math.abs
|
||||||
|
import kotlin.math.max
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Hemanth S (h4h13).
|
* @author Hemanth S (h4h13).
|
||||||
|
@ -27,13 +29,15 @@ class NormalPageTransformer : ViewPager.PageTransformer {
|
||||||
val pageWidth = view.width
|
val pageWidth = view.width
|
||||||
val pageHeight = view.height
|
val pageHeight = view.height
|
||||||
|
|
||||||
if (position < -1) { // [-Infinity,-1)
|
when {
|
||||||
|
position < -1 -> { // [-Infinity,-1)
|
||||||
// This page is way off-screen to the left.
|
// This page is way off-screen to the left.
|
||||||
view.alpha = 1f
|
view.alpha = 1f
|
||||||
view.scaleY = 0.7f
|
view.scaleY = 0.7f
|
||||||
} else if (position <= 1) { // [-1,1]
|
}
|
||||||
|
position <= 1 -> { // [-1,1]
|
||||||
// Modify the default slide transition to shrink the page as well
|
// Modify the default slide transition to shrink the page as well
|
||||||
val scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position))
|
val scaleFactor = max(MIN_SCALE, 1 - abs(position))
|
||||||
val vertMargin = pageHeight * (1 - scaleFactor) / 2
|
val vertMargin = pageHeight * (1 - scaleFactor) / 2
|
||||||
val horzMargin = pageWidth * (1 - scaleFactor) / 2
|
val horzMargin = pageWidth * (1 - scaleFactor) / 2
|
||||||
if (position < 0) {
|
if (position < 0) {
|
||||||
|
@ -49,15 +53,17 @@ class NormalPageTransformer : ViewPager.PageTransformer {
|
||||||
// Fade the page relative to its size.
|
// Fade the page relative to its size.
|
||||||
//view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
|
//view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
|
||||||
|
|
||||||
} else { // (1,+Infinity]
|
}
|
||||||
|
else -> { // (1,+Infinity]
|
||||||
// This page is way off-screen to the right.
|
// This page is way off-screen to the right.
|
||||||
view.alpha = 1f
|
view.alpha = 1f
|
||||||
view.scaleY = 0.7f
|
view.scaleY = 0.7f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private val MIN_SCALE = 0.85f
|
private const val MIN_SCALE = 0.85f
|
||||||
private val MIN_ALPHA = 0.5f
|
private const val MIN_ALPHA = 0.5f
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,7 @@ package code.name.monkey.retromusic.transform
|
||||||
|
|
||||||
import android.view.View
|
import android.view.View
|
||||||
import androidx.viewpager.widget.ViewPager
|
import androidx.viewpager.widget.ViewPager
|
||||||
|
import kotlin.math.abs
|
||||||
|
|
||||||
class VerticalFlipTransformation : ViewPager.PageTransformer {
|
class VerticalFlipTransformation : ViewPager.PageTransformer {
|
||||||
override fun transformPage(page: View, position: Float) {
|
override fun transformPage(page: View, position: Float) {
|
||||||
|
@ -30,23 +31,25 @@ class VerticalFlipTransformation : ViewPager.PageTransformer {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (position < -1) { // [-Infinity,-1)
|
when {
|
||||||
|
position < -1 -> { // [-Infinity,-1)
|
||||||
// This page is way off-screen to the left.
|
// This page is way off-screen to the left.
|
||||||
page.alpha = 0f
|
page.alpha = 0f
|
||||||
|
}
|
||||||
} else if (position <= 0) { // [-1,0]
|
position <= 0 -> { // [-1,0]
|
||||||
page.alpha = 1f
|
page.alpha = 1f
|
||||||
page.rotationY = 180 * (1 - Math.abs(position) + 1)
|
page.rotationY = 180 * (1 - abs(position) + 1)
|
||||||
|
}
|
||||||
} else if (position <= 1) { // (0,1]
|
position <= 1 -> { // (0,1]
|
||||||
page.alpha = 1f
|
page.alpha = 1f
|
||||||
page.rotationY = -180 * (1 - Math.abs(position) + 1)
|
page.rotationY = -180 * (1 - abs(position) + 1)
|
||||||
|
}
|
||||||
} else { // (1,+Infinity]
|
else -> { // (1,+Infinity]
|
||||||
// This page is way off-screen to the right.
|
// This page is way off-screen to the right.
|
||||||
page.alpha = 0f
|
page.alpha = 0f
|
||||||
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -79,26 +79,4 @@ object AppRater {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun showRateDialog(context: Context, editor: SharedPreferences.Editor) {
|
|
||||||
MaterialAlertDialogBuilder(context)
|
|
||||||
.setTitle("Rate this App")
|
|
||||||
.setMessage("If you enjoy using Retro Music, please take a moment to rate it. Thanks for your support!")
|
|
||||||
.setPositiveButton(R.string.app_name) { _, _ ->
|
|
||||||
context.startActivity(
|
|
||||||
Intent(
|
|
||||||
Intent.ACTION_VIEW,
|
|
||||||
Uri.parse("market://details?id=${context.packageName}")
|
|
||||||
)
|
|
||||||
)
|
|
||||||
editor.putBoolean(DO_NOT_SHOW_AGAIN, true)
|
|
||||||
editor.commit()
|
|
||||||
}
|
|
||||||
.setNeutralButton("Not now", null)
|
|
||||||
.setNegativeButton("No thanks") { _, _ ->
|
|
||||||
editor.putBoolean(DO_NOT_SHOW_AGAIN, true)
|
|
||||||
editor.commit()
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -3,11 +3,6 @@ package code.name.monkey.retromusic.util;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.Bitmap;
|
import android.graphics.Bitmap;
|
||||||
import android.graphics.BitmapFactory;
|
import android.graphics.BitmapFactory;
|
||||||
import android.graphics.Canvas;
|
|
||||||
import android.graphics.Paint;
|
|
||||||
import android.graphics.Rect;
|
|
||||||
import android.graphics.RectF;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
@ -20,19 +15,12 @@ import code.name.monkey.retromusic.R;
|
||||||
import code.name.monkey.retromusic.model.Song;
|
import code.name.monkey.retromusic.model.Song;
|
||||||
|
|
||||||
public class AutoGeneratedPlaylistBitmap {
|
public class AutoGeneratedPlaylistBitmap {
|
||||||
private static final String TAG = "AutoGeneratedPB";
|
|
||||||
|
|
||||||
/*
|
|
||||||
public static Bitmap getBitmapWithCollectionFrame(Context context, List<Song> songPlaylist, boolean round, boolean blur) {
|
|
||||||
Bitmap bitmap = getBitmap(context,songPlaylist,round,blur);
|
|
||||||
int w = bitmap.getWidth();
|
|
||||||
Bitmap ret = Bitmap.createBitmap(w,w,Bitmap.Config.ARGB_8888);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
public static Bitmap getBitmap(
|
public static Bitmap getBitmap(
|
||||||
Context context, List<Song> songPlaylist, boolean round, boolean blur) {
|
Context context, List<Song> songPlaylist) {
|
||||||
if (songPlaylist == null || songPlaylist.isEmpty()) return getDefaultBitmap(context, round);
|
if (songPlaylist == null || songPlaylist.isEmpty()) return getDefaultBitmap(context);
|
||||||
if (songPlaylist.size() == 1) return getBitmapWithAlbumId(context, songPlaylist.get(0).getAlbumId());
|
if (songPlaylist.size() == 1)
|
||||||
|
return getBitmapWithAlbumId(context, songPlaylist.get(0).getAlbumId());
|
||||||
List<Long> albumID = new ArrayList<>();
|
List<Long> albumID = new ArrayList<>();
|
||||||
for (Song song : songPlaylist) {
|
for (Song song : songPlaylist) {
|
||||||
if (!albumID.contains(song.getAlbumId())) albumID.add(song.getAlbumId());
|
if (!albumID.contains(song.getAlbumId())) albumID.add(song.getAlbumId());
|
||||||
|
@ -40,108 +28,12 @@ public class AutoGeneratedPlaylistBitmap {
|
||||||
List<Bitmap> art = new ArrayList<>();
|
List<Bitmap> art = new ArrayList<>();
|
||||||
for (Long id : albumID) {
|
for (Long id : albumID) {
|
||||||
Bitmap bitmap = getBitmapWithAlbumId(context, id);
|
Bitmap bitmap = getBitmapWithAlbumId(context, id);
|
||||||
if (bitmap != null) art.add(bitmap);
|
if (bitmap != null) art.add(BitmapEditor.getRoundedCornerBitmap(bitmap, 20));
|
||||||
if (art.size() == 9) break;
|
if (art.size() == 9) break;
|
||||||
}
|
}
|
||||||
return MergedImageUtils.INSTANCE.joinImages(art);
|
return MergedImageUtils.INSTANCE.joinImages(art);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Bitmap getBitmapCollection(ArrayList<Bitmap> art, boolean round) {
|
|
||||||
long start = System.currentTimeMillis();
|
|
||||||
// lấy kích thước là kích thước của bitmap lớn nhất
|
|
||||||
int max_width = art.get(0).getWidth();
|
|
||||||
for (Bitmap b : art) if (max_width < b.getWidth()) max_width = b.getWidth();
|
|
||||||
Bitmap bitmap = Bitmap.createBitmap(max_width, max_width, Bitmap.Config.ARGB_8888);
|
|
||||||
Canvas canvas = new Canvas(bitmap);
|
|
||||||
Paint paint = new Paint();
|
|
||||||
paint.setAntiAlias(false);
|
|
||||||
paint.setStyle(Paint.Style.STROKE);
|
|
||||||
paint.setStrokeWidth(max_width / 100);
|
|
||||||
paint.setColor(0xffffffff);
|
|
||||||
switch (art.size()) {
|
|
||||||
case 2:
|
|
||||||
canvas.drawBitmap(art.get(1), null, new Rect(0, 0, max_width, max_width), null);
|
|
||||||
canvas.drawBitmap(
|
|
||||||
art.get(0), null, new Rect(-max_width / 2, 0, max_width / 2, max_width), null);
|
|
||||||
canvas.drawLine(max_width / 2, 0, max_width / 2, max_width, paint);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
canvas.drawBitmap(
|
|
||||||
art.get(0), null, new Rect(-max_width / 4, 0, 3 * max_width / 4, max_width), null);
|
|
||||||
canvas.drawBitmap(
|
|
||||||
art.get(1), null, new Rect(max_width / 2, 0, max_width, max_width / 2), null);
|
|
||||||
canvas.drawBitmap(
|
|
||||||
art.get(2), null, new Rect(max_width / 2, max_width / 2, max_width, max_width), null);
|
|
||||||
canvas.drawLine(max_width / 2, 0, max_width / 2, max_width, paint);
|
|
||||||
canvas.drawLine(max_width / 2, max_width / 2, max_width, max_width / 2, paint);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
canvas.drawBitmap(art.get(0), null, new Rect(0, 0, max_width / 2, max_width / 2), null);
|
|
||||||
canvas.drawBitmap(
|
|
||||||
art.get(1), null, new Rect(max_width / 2, 0, max_width, max_width / 2), null);
|
|
||||||
canvas.drawBitmap(
|
|
||||||
art.get(2), null, new Rect(0, max_width / 2, max_width / 2, max_width), null);
|
|
||||||
canvas.drawBitmap(
|
|
||||||
art.get(3), null, new Rect(max_width / 2, max_width / 2, max_width, max_width), null);
|
|
||||||
canvas.drawLine(max_width / 2, 0, max_width / 2, max_width, paint);
|
|
||||||
canvas.drawLine(0, max_width / 2, max_width, max_width / 2, paint);
|
|
||||||
break;
|
|
||||||
// default: canvas.drawBitmap(art.get(0),null,new Rect(0,0,max_width,max_width),null);
|
|
||||||
default:
|
|
||||||
|
|
||||||
// độ rộng của des bitmap
|
|
||||||
float w = (float) (Math.sqrt(2) / 2 * max_width);
|
|
||||||
float b = (float) (max_width / Math.sqrt(5));
|
|
||||||
// khoảng cách định nghĩa, dùng để tính vị trí tâm của 4 bức hình xung quanh
|
|
||||||
float d = (float) (max_width * (0.5f - 1 / Math.sqrt(10)));
|
|
||||||
float deg = 45;
|
|
||||||
|
|
||||||
for (int i = 0; i < 5; i++) {
|
|
||||||
canvas.save();
|
|
||||||
switch (i) {
|
|
||||||
case 0:
|
|
||||||
canvas.translate(max_width / 2, max_width / 2);
|
|
||||||
canvas.rotate(deg);
|
|
||||||
// b = (float) (max_width*Math.sqrt(2/5f));
|
|
||||||
canvas.drawBitmap(art.get(0), null, new RectF(-b / 2, -b / 2, b / 2, b / 2), null);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
canvas.translate(d, 0);
|
|
||||||
canvas.rotate(deg);
|
|
||||||
canvas.drawBitmap(art.get(i), null, new RectF(-w / 2, -w / 2, w / 2, w / 2), null);
|
|
||||||
paint.setAntiAlias(true);
|
|
||||||
canvas.drawLine(w / 2, -w / 2, w / 2, w / 2, paint);
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
canvas.translate(max_width, d);
|
|
||||||
canvas.rotate(deg);
|
|
||||||
canvas.drawBitmap(art.get(i), null, new RectF(-w / 2, -w / 2, w / 2, w / 2), null);
|
|
||||||
paint.setAntiAlias(true);
|
|
||||||
canvas.drawLine(-w / 2, w / 2, w / 2, w / 2, paint);
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
canvas.translate(max_width - d, max_width);
|
|
||||||
canvas.rotate(deg);
|
|
||||||
canvas.drawBitmap(art.get(i), null, new RectF(-w / 2, -w / 2, w / 2, w / 2), null);
|
|
||||||
paint.setAntiAlias(true);
|
|
||||||
canvas.drawLine(-w / 2, -w / 2, -w / 2, w / 2, paint);
|
|
||||||
break;
|
|
||||||
case 4:
|
|
||||||
canvas.translate(0, max_width - d);
|
|
||||||
canvas.rotate(deg);
|
|
||||||
canvas.drawBitmap(art.get(i), null, new RectF(-w / 2, -w / 2, w / 2, w / 2), null);
|
|
||||||
paint.setAntiAlias(true);
|
|
||||||
canvas.drawLine(-w / 2, -w / 2, w / 2, -w / 2, paint);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
canvas.restore();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Log.d(TAG, "getBitmapCollection: smalltime = " + (System.currentTimeMillis() - start));
|
|
||||||
if (round) return BitmapEditor.getRoundedCornerBitmap(bitmap, bitmap.getWidth() / 40);
|
|
||||||
else return bitmap;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Bitmap getBitmapWithAlbumId(@NonNull Context context, Long id) {
|
private static Bitmap getBitmapWithAlbumId(@NonNull Context context, Long id) {
|
||||||
try {
|
try {
|
||||||
return Glide.with(context)
|
return Glide.with(context)
|
||||||
|
@ -154,7 +46,7 @@ public class AutoGeneratedPlaylistBitmap {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bitmap getDefaultBitmap(@NonNull Context context, boolean round) {
|
public static Bitmap getDefaultBitmap(@NonNull Context context) {
|
||||||
return BitmapFactory.decodeResource(context.getResources(), R.drawable.default_album_art);
|
return BitmapFactory.decodeResource(context.getResources(), R.drawable.default_album_art);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -594,7 +594,7 @@ public final class BitmapEditor {
|
||||||
/**
|
/**
|
||||||
* getResizedBitmap method is used to Resized the Image according to custom width and height
|
* getResizedBitmap method is used to Resized the Image according to custom width and height
|
||||||
*
|
*
|
||||||
* @param image
|
* @param image image to be resized
|
||||||
* @param newHeight (new desired height)
|
* @param newHeight (new desired height)
|
||||||
* @param newWidth (new desired Width)
|
* @param newWidth (new desired Width)
|
||||||
* @return image (new resized image)
|
* @return image (new resized image)
|
||||||
|
@ -609,22 +609,21 @@ public final class BitmapEditor {
|
||||||
// onTap the bit map
|
// onTap the bit map
|
||||||
matrix.postScale(scaleWidth, scaleHeight);
|
matrix.postScale(scaleWidth, scaleHeight);
|
||||||
// recreate the new Bitmap
|
// recreate the new Bitmap
|
||||||
Bitmap resizedBitmap = Bitmap.createBitmap(image, 0, 0, width, height, matrix, false);
|
return Bitmap.createBitmap(image, 0, 0, width, height, matrix, false);
|
||||||
return resizedBitmap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean TrueIfBitmapBigger(Bitmap bitmap, int size) {
|
public static boolean TrueIfBitmapBigger(Bitmap bitmap, int size) {
|
||||||
int sizeBitmap =
|
int sizeBitmap =
|
||||||
(bitmap.getHeight() > bitmap.getWidth()) ? bitmap.getHeight() : bitmap.getWidth();
|
Math.max(bitmap.getHeight(), bitmap.getWidth());
|
||||||
return sizeBitmap > size;
|
return sizeBitmap > size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Bitmap GetRoundedBitmapWithBlurShadow(
|
public static Bitmap getRoundedBitmapWithBlurShadow(
|
||||||
Bitmap original, int paddingTop, int paddingBottom, int paddingLeft, int paddingRight) {
|
Bitmap original, int paddingTop, int paddingBottom, int paddingLeft, int paddingRight) {
|
||||||
int original_width = original.getWidth();
|
int original_width = original.getWidth();
|
||||||
int orginal_height = original.getHeight();
|
int original_height = original.getHeight();
|
||||||
int bitmap_width = original_width + paddingLeft + paddingRight;
|
int bitmap_width = original_width + paddingLeft + paddingRight;
|
||||||
int bitmap_height = orginal_height + paddingTop + paddingBottom;
|
int bitmap_height = original_height + paddingTop + paddingBottom;
|
||||||
Bitmap bitmap = Bitmap.createBitmap(bitmap_width, bitmap_height, Bitmap.Config.ARGB_8888);
|
Bitmap bitmap = Bitmap.createBitmap(bitmap_width, bitmap_height, Bitmap.Config.ARGB_8888);
|
||||||
Canvas canvas = new Canvas(bitmap);
|
Canvas canvas = new Canvas(bitmap);
|
||||||
Paint paint = new Paint();
|
Paint paint = new Paint();
|
||||||
|
|
|
@ -25,13 +25,11 @@ import android.graphics.PorterDuff;
|
||||||
import android.graphics.PorterDuffColorFilter;
|
import android.graphics.PorterDuffColorFilter;
|
||||||
import android.graphics.drawable.Drawable;
|
import android.graphics.drawable.Drawable;
|
||||||
import android.media.ExifInterface;
|
import android.media.ExifInterface;
|
||||||
import android.os.Build;
|
|
||||||
|
|
||||||
import androidx.annotation.ColorInt;
|
import androidx.annotation.ColorInt;
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
|
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
|
@ -102,11 +100,8 @@ public class ImageUtil {
|
||||||
|
|
||||||
public static Drawable getVectorDrawable(
|
public static Drawable getVectorDrawable(
|
||||||
@NonNull Resources res, @DrawableRes int resId, @Nullable Resources.Theme theme) {
|
@NonNull Resources res, @DrawableRes int resId, @Nullable Resources.Theme theme) {
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
|
||||||
return res.getDrawable(resId, theme);
|
return res.getDrawable(resId, theme);
|
||||||
}
|
}
|
||||||
return VectorDrawableCompat.create(res, resId, theme);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Makes sure that {@code mTempBuffer} has at least length {@code size}. */
|
/** Makes sure that {@code mTempBuffer} has at least length {@code size}. */
|
||||||
private static void ensureBufferSize(int size) {
|
private static void ensureBufferSize(int size) {
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
package code.name.monkey.retromusic.util
|
package code.name.monkey.retromusic.util
|
||||||
|
|
||||||
import android.graphics.*
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.Canvas
|
||||||
|
import android.graphics.Matrix
|
||||||
|
import android.graphics.Paint
|
||||||
import com.bumptech.glide.util.Util.assertBackgroundThread
|
import com.bumptech.glide.util.Util.assertBackgroundThread
|
||||||
|
|
||||||
|
|
||||||
|
@ -75,25 +78,12 @@ internal object MergedImageUtils {
|
||||||
val bit = Bitmap.createScaledBitmap(bitmap, onePartSize, onePartSize, true)
|
val bit = Bitmap.createScaledBitmap(bitmap, onePartSize, onePartSize, true)
|
||||||
canvas.drawBitmap(
|
canvas.drawBitmap(
|
||||||
bit,
|
bit,
|
||||||
(onePartSize * (i % parts)).toFloat(),
|
(onePartSize * (i % parts)).toFloat() + (i % 3) * 50,
|
||||||
(onePartSize * (i / parts)).toFloat(),
|
(onePartSize * (i / parts)).toFloat() + (i / 3) * 50,
|
||||||
paint
|
paint
|
||||||
)
|
)
|
||||||
bit.recycle()
|
bit.recycle()
|
||||||
}
|
}
|
||||||
|
|
||||||
paint.color = Color.WHITE
|
|
||||||
paint.strokeWidth = 10f
|
|
||||||
|
|
||||||
val oneThirdSize = (IMAGE_SIZE / 3).toFloat()
|
|
||||||
val twoThirdSize = (IMAGE_SIZE / 3 * 2).toFloat()
|
|
||||||
// vertical lines
|
|
||||||
canvas.drawLine(oneThirdSize, 0f, oneThirdSize, imageSize.toFloat(), paint)
|
|
||||||
canvas.drawLine(twoThirdSize, 0f, twoThirdSize, imageSize.toFloat(), paint)
|
|
||||||
// horizontal lines
|
|
||||||
canvas.drawLine(0f, oneThirdSize, imageSize.toFloat(), oneThirdSize, paint)
|
|
||||||
canvas.drawLine(0f, twoThirdSize, imageSize.toFloat(), twoThirdSize, paint)
|
|
||||||
|
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -348,7 +348,7 @@ object MusicUtil : KoinComponent {
|
||||||
val repository = get<Repository>()
|
val repository = get<Repository>()
|
||||||
fun toggleFavorite(context: Context, song: Song) {
|
fun toggleFavorite(context: Context, song: Song) {
|
||||||
GlobalScope.launch {
|
GlobalScope.launch {
|
||||||
val playlist: PlaylistEntity? = repository.favoritePlaylist()
|
val playlist: PlaylistEntity = repository.favoritePlaylist()
|
||||||
if (playlist != null) {
|
if (playlist != null) {
|
||||||
val songEntity = song.toSongEntity(playlist.playListId)
|
val songEntity = song.toSongEntity(playlist.playListId)
|
||||||
val isFavorite = repository.isFavoriteSong(songEntity).isNotEmpty()
|
val isFavorite = repository.isFavoriteSong(songEntity).isNotEmpty()
|
||||||
|
@ -529,7 +529,7 @@ object MusicUtil : KoinComponent {
|
||||||
val pendingIntent = MediaStore.createDeleteRequest(activity.contentResolver, songs.map {
|
val pendingIntent = MediaStore.createDeleteRequest(activity.contentResolver, songs.map {
|
||||||
getSongFileUri(it.id)
|
getSongFileUri(it.id)
|
||||||
})
|
})
|
||||||
activity.startIntentSenderForResult(pendingIntent.intentSender, 45, null, 0, 0, 0, null);
|
activity.startIntentSenderForResult(pendingIntent.intentSender, 45, null, 0, 0, 0, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun songByGenre(genreId: Long): Song {
|
fun songByGenre(genreId: Long): Song {
|
||||||
|
|
|
@ -20,12 +20,10 @@ import android.content.Intent
|
||||||
import android.media.audiofx.AudioEffect
|
import android.media.audiofx.AudioEffect
|
||||||
import android.widget.Toast
|
import android.widget.Toast
|
||||||
import androidx.core.app.ActivityCompat
|
import androidx.core.app.ActivityCompat
|
||||||
import androidx.navigation.findNavController
|
|
||||||
import code.name.monkey.retromusic.R
|
import code.name.monkey.retromusic.R
|
||||||
import code.name.monkey.retromusic.activities.*
|
import code.name.monkey.retromusic.activities.*
|
||||||
import code.name.monkey.retromusic.activities.bugreport.BugReportActivity
|
import code.name.monkey.retromusic.activities.bugreport.BugReportActivity
|
||||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote.audioSessionId
|
import code.name.monkey.retromusic.helper.MusicPlayerRemote.audioSessionId
|
||||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
|
||||||
|
|
||||||
object NavigationUtil {
|
object NavigationUtil {
|
||||||
fun bugReport(activity: Activity) {
|
fun bugReport(activity: Activity) {
|
||||||
|
@ -40,21 +38,6 @@ object NavigationUtil {
|
||||||
ActivityCompat.startActivity(activity, Intent(activity, LicenseActivity::class.java), null)
|
ActivityCompat.startActivity(activity, Intent(activity, LicenseActivity::class.java), null)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun goToLyrics(activity: Activity) {
|
|
||||||
if (activity !is MainActivity) return
|
|
||||||
activity.apply {
|
|
||||||
//Hide Bottom Bar First, else Bottom Sheet doesn't collapse fully
|
|
||||||
setBottomNavVisibility(false)
|
|
||||||
if (getBottomSheetBehavior().state == BottomSheetBehavior.STATE_EXPANDED) {
|
|
||||||
collapsePanel()
|
|
||||||
}
|
|
||||||
|
|
||||||
findNavController(R.id.fragment_container).navigate(
|
|
||||||
R.id.lyrics_fragment
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun goToProVersion(context: Context) {
|
fun goToProVersion(context: Context) {
|
||||||
ActivityCompat.startActivity(context, Intent(context, PurchaseActivity::class.java), null)
|
ActivityCompat.startActivity(context, Intent(context, PurchaseActivity::class.java), null)
|
||||||
}
|
}
|
||||||
|
|
|
@ -191,6 +191,7 @@ class PackageValidator(
|
||||||
*
|
*
|
||||||
* @return [PackageInfo] for the package name or null if it's not found.
|
* @return [PackageInfo] for the package name or null if it's not found.
|
||||||
*/
|
*/
|
||||||
|
@Suppress("Deprecation")
|
||||||
@SuppressLint("PackageManagerGetSignatures")
|
@SuppressLint("PackageManagerGetSignatures")
|
||||||
private fun getPackageInfo(callingPackage: String): PackageInfo? =
|
private fun getPackageInfo(callingPackage: String): PackageInfo? =
|
||||||
packageManager.getPackageInfo(callingPackage,
|
packageManager.getPackageInfo(callingPackage,
|
||||||
|
@ -208,11 +209,11 @@ class PackageValidator(
|
||||||
private fun getSignature(packageInfo: PackageInfo): String? {
|
private fun getSignature(packageInfo: PackageInfo): String? {
|
||||||
// Security best practices dictate that an app should be signed with exactly one (1)
|
// Security best practices dictate that an app should be signed with exactly one (1)
|
||||||
// signature. Because of this, if there are multiple signatures, reject it.
|
// signature. Because of this, if there are multiple signatures, reject it.
|
||||||
if (packageInfo.signatures == null || packageInfo.signatures.size != 1) {
|
return if (packageInfo.signatures == null || packageInfo.signatures.size != 1) {
|
||||||
return null
|
null
|
||||||
} else {
|
} else {
|
||||||
val certificate = packageInfo.signatures[0].toByteArray()
|
val certificate = packageInfo.signatures[0].toByteArray()
|
||||||
return getSignatureSha256(certificate)
|
getSignatureSha256(certificate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,6 @@ import java.util.List;
|
||||||
|
|
||||||
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.helper.M3UConstants;
|
|
||||||
import code.name.monkey.retromusic.helper.M3UWriter;
|
import code.name.monkey.retromusic.helper.M3UWriter;
|
||||||
import code.name.monkey.retromusic.model.Playlist;
|
import code.name.monkey.retromusic.model.Playlist;
|
||||||
import code.name.monkey.retromusic.model.PlaylistSong;
|
import code.name.monkey.retromusic.model.PlaylistSong;
|
||||||
|
@ -167,8 +166,8 @@ public class PlaylistsUtil {
|
||||||
Toast.LENGTH_SHORT)
|
Toast.LENGTH_SHORT)
|
||||||
.show();
|
.show();
|
||||||
}
|
}
|
||||||
} catch (SecurityException ignored) {
|
} catch (SecurityException exception) {
|
||||||
ignored.printStackTrace();
|
exception.printStackTrace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,13 +234,13 @@ public class PlaylistsUtil {
|
||||||
for (int i = 0; i < selectionArgs.length; i++) {
|
for (int i = 0; i < selectionArgs.length; i++) {
|
||||||
selectionArgs[i] = String.valueOf(songs.get(i).getIdInPlayList());
|
selectionArgs[i] = String.valueOf(songs.get(i).getIdInPlayList());
|
||||||
}
|
}
|
||||||
String selection = MediaStore.Audio.Playlists.Members._ID + " in (";
|
StringBuilder selection = new StringBuilder(MediaStore.Audio.Playlists.Members._ID + " in (");
|
||||||
//noinspection unused
|
|
||||||
for (String selectionArg : selectionArgs) selection += "?, ";
|
for (String selectionArg : selectionArgs) selection.append("?, ");
|
||||||
selection = selection.substring(0, selection.length() - 2) + ")";
|
selection = new StringBuilder(selection.substring(0, selection.length() - 2) + ")");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
context.getContentResolver().delete(uri, selection, selectionArgs);
|
context.getContentResolver().delete(uri, selection.toString(), selectionArgs);
|
||||||
} catch (SecurityException ignored) {
|
} catch (SecurityException ignored) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import code.name.monkey.retromusic.*
|
||||||
import code.name.monkey.retromusic.extensions.getIntRes
|
import code.name.monkey.retromusic.extensions.getIntRes
|
||||||
import code.name.monkey.retromusic.extensions.getStringOrDefault
|
import code.name.monkey.retromusic.extensions.getStringOrDefault
|
||||||
import code.name.monkey.retromusic.fragments.AlbumCoverStyle
|
import code.name.monkey.retromusic.fragments.AlbumCoverStyle
|
||||||
|
import code.name.monkey.retromusic.fragments.GridStyle
|
||||||
import code.name.monkey.retromusic.fragments.NowPlayingScreen
|
import code.name.monkey.retromusic.fragments.NowPlayingScreen
|
||||||
import code.name.monkey.retromusic.fragments.folder.FoldersFragment
|
import code.name.monkey.retromusic.fragments.folder.FoldersFragment
|
||||||
import code.name.monkey.retromusic.helper.SortOrder.*
|
import code.name.monkey.retromusic.helper.SortOrder.*
|
||||||
|
@ -344,22 +345,40 @@ object PreferenceUtil {
|
||||||
putInt(LYRICS_OPTIONS, value)
|
putInt(LYRICS_OPTIONS, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
var songGridStyle
|
var songGridStyle: GridStyle
|
||||||
get() = sharedPreferences.getInt(SONG_GRID_STYLE, R.layout.item_grid)
|
get() {
|
||||||
|
val id: Int = sharedPreferences.getInt(SONG_GRID_STYLE, 0)
|
||||||
|
// We can directly use "first" kotlin extension function here but
|
||||||
|
// there maybe layout id stored in this so to avoid a crash we use
|
||||||
|
// "firstOrNull"
|
||||||
|
return GridStyle.values().firstOrNull { gridStyle ->
|
||||||
|
gridStyle.id == id
|
||||||
|
} ?: GridStyle.Grid
|
||||||
|
}
|
||||||
set(value) = sharedPreferences.edit {
|
set(value) = sharedPreferences.edit {
|
||||||
putInt(SONG_GRID_STYLE, value)
|
putInt(SONG_GRID_STYLE, value.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
var albumGridStyle
|
var albumGridStyle: GridStyle
|
||||||
get() = sharedPreferences.getInt(ALBUM_GRID_STYLE, R.layout.item_grid)
|
get() {
|
||||||
|
val id: Int = sharedPreferences.getInt(ALBUM_GRID_STYLE, 0)
|
||||||
|
return GridStyle.values().firstOrNull { gridStyle ->
|
||||||
|
gridStyle.id == id
|
||||||
|
} ?: GridStyle.Grid
|
||||||
|
}
|
||||||
set(value) = sharedPreferences.edit {
|
set(value) = sharedPreferences.edit {
|
||||||
putInt(ALBUM_GRID_STYLE, value)
|
putInt(ALBUM_GRID_STYLE, value.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
var artistGridStyle
|
var artistGridStyle: GridStyle
|
||||||
get() = sharedPreferences.getInt(ARTIST_GRID_STYLE, R.layout.item_grid_circle)
|
get() {
|
||||||
|
val id: Int = sharedPreferences.getInt(ARTIST_GRID_STYLE, 4)
|
||||||
|
return GridStyle.values().firstOrNull { gridStyle ->
|
||||||
|
gridStyle.id == id
|
||||||
|
} ?: GridStyle.Circular
|
||||||
|
}
|
||||||
set(value) = sharedPreferences.edit {
|
set(value) = sharedPreferences.edit {
|
||||||
putInt(ARTIST_GRID_STYLE, value)
|
putInt(ARTIST_GRID_STYLE, value.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
val filterLength get() = sharedPreferences.getInt(FILTER_SONG, 20)
|
val filterLength get() = sharedPreferences.getInt(FILTER_SONG, 20)
|
||||||
|
@ -498,6 +517,25 @@ object PreferenceUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var playlistGridSize
|
||||||
|
get() = sharedPreferences.getInt(
|
||||||
|
PLAYLIST_GRID_SIZE,
|
||||||
|
App.getContext().getIntRes(R.integer.default_grid_columns)
|
||||||
|
)
|
||||||
|
set(value) = sharedPreferences.edit {
|
||||||
|
putInt(PLAYLIST_GRID_SIZE, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var playlistGridSizeLand
|
||||||
|
get() = sharedPreferences.getInt(
|
||||||
|
PLAYLIST_GRID_SIZE_LAND,
|
||||||
|
App.getContext().getIntRes(R.integer.default_grid_columns_land)
|
||||||
|
)
|
||||||
|
set(value) = sharedPreferences.edit {
|
||||||
|
putInt(PLAYLIST_GRID_SIZE, value)
|
||||||
|
}
|
||||||
|
|
||||||
var albumCoverStyle: AlbumCoverStyle
|
var albumCoverStyle: AlbumCoverStyle
|
||||||
get() {
|
get() {
|
||||||
val id: Int = sharedPreferences.getInt(ALBUM_COVER_STYLE, 0)
|
val id: Int = sharedPreferences.getInt(ALBUM_COVER_STYLE, 0)
|
||||||
|
|
|
@ -42,7 +42,7 @@ public class RetroColorUtil {
|
||||||
float[] hsv = new float[3];
|
float[] hsv = new float[3];
|
||||||
Color.colorToHSV(color, hsv);
|
Color.colorToHSV(color, hsv);
|
||||||
|
|
||||||
hsv[1] = (hsv[1] / 1 * ratio) + (0.2f * (1.0f - ratio));
|
hsv[1] = (hsv[1] * ratio) + (0.2f * (1.0f - ratio));
|
||||||
|
|
||||||
return Color.HSVToColor(hsv);
|
return Color.HSVToColor(hsv);
|
||||||
}
|
}
|
||||||
|
@ -188,7 +188,7 @@ public class RetroColorUtil {
|
||||||
|
|
||||||
public static int getDominantColor(Bitmap bitmap, int defaultFooterColor) {
|
public static int getDominantColor(Bitmap bitmap, int defaultFooterColor) {
|
||||||
List<Palette.Swatch> swatchesTemp = Palette.from(bitmap).generate().getSwatches();
|
List<Palette.Swatch> swatchesTemp = Palette.from(bitmap).generate().getSwatches();
|
||||||
List<Palette.Swatch> swatches = new ArrayList<Palette.Swatch>(swatchesTemp);
|
List<Palette.Swatch> swatches = new ArrayList<>(swatchesTemp);
|
||||||
Collections.sort(
|
Collections.sort(
|
||||||
swatches, (swatch1, swatch2) -> swatch2.getPopulation() - swatch1.getPopulation());
|
swatches, (swatch1, swatch2) -> swatch2.getPopulation() - swatch1.getPopulation());
|
||||||
return swatches.size() > 0 ? swatches.get(0).getRgb() : defaultFooterColor;
|
return swatches.size() > 0 ? swatches.get(0).getRgb() : defaultFooterColor;
|
||||||
|
|
|
@ -40,7 +40,7 @@ import androidx.annotation.ColorInt;
|
||||||
import androidx.annotation.DrawableRes;
|
import androidx.annotation.DrawableRes;
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
|
import androidx.core.content.res.ResourcesCompat;
|
||||||
|
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.NetworkInterface;
|
import java.net.NetworkInterface;
|
||||||
|
@ -127,14 +127,14 @@ public class RetroUtil {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@NonNull
|
||||||
public static Drawable getTintedVectorDrawable(
|
public static Drawable getTintedVectorDrawable(
|
||||||
@NonNull Context context, @DrawableRes int id, @ColorInt int color) {
|
@NonNull Context context, @DrawableRes int id, @ColorInt int color) {
|
||||||
return TintHelper.createTintedDrawable(
|
return TintHelper.createTintedDrawable(
|
||||||
getVectorDrawable(context.getResources(), id, context.getTheme()), color);
|
getVectorDrawable(context.getResources(), id, context.getTheme()), color);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@NonNull
|
||||||
public static Drawable getTintedVectorDrawable(
|
public static Drawable getTintedVectorDrawable(
|
||||||
@NonNull Resources res,
|
@NonNull Resources res,
|
||||||
@DrawableRes int resId,
|
@DrawableRes int resId,
|
||||||
|
@ -146,10 +146,7 @@ public class RetroUtil {
|
||||||
@Nullable
|
@Nullable
|
||||||
public static Drawable getVectorDrawable(
|
public static Drawable getVectorDrawable(
|
||||||
@NonNull Resources res, @DrawableRes int resId, @Nullable Resources.Theme theme) {
|
@NonNull Resources res, @DrawableRes int resId, @Nullable Resources.Theme theme) {
|
||||||
if (Build.VERSION.SDK_INT >= 21) {
|
return ResourcesCompat.getDrawable(res, resId, theme);
|
||||||
return res.getDrawable(resId, theme);
|
|
||||||
}
|
|
||||||
return VectorDrawableCompat.create(res, resId, theme);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void hideSoftKeyboard(@Nullable Activity activity) {
|
public static void hideSoftKeyboard(@Nullable Activity activity) {
|
||||||
|
|
|
@ -1,147 +0,0 @@
|
||||||
package code.name.monkey.retromusic.util;
|
|
||||||
|
|
||||||
import android.annotation.TargetApi;
|
|
||||||
import android.content.res.ColorStateList;
|
|
||||||
import android.graphics.Color;
|
|
||||||
import android.os.Build;
|
|
||||||
import android.util.StateSet;
|
|
||||||
|
|
||||||
import androidx.annotation.ColorInt;
|
|
||||||
import androidx.annotation.Nullable;
|
|
||||||
import androidx.core.graphics.ColorUtils;
|
|
||||||
|
|
||||||
public class RippleUtils {
|
|
||||||
public static final boolean USE_FRAMEWORK_RIPPLE =
|
|
||||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP;
|
|
||||||
private static final int[] PRESSED_STATE_SET = {
|
|
||||||
android.R.attr.state_pressed,
|
|
||||||
};
|
|
||||||
private static final int[] HOVERED_FOCUSED_STATE_SET = {
|
|
||||||
android.R.attr.state_hovered, android.R.attr.state_focused,
|
|
||||||
};
|
|
||||||
private static final int[] FOCUSED_STATE_SET = {
|
|
||||||
android.R.attr.state_focused,
|
|
||||||
};
|
|
||||||
private static final int[] HOVERED_STATE_SET = {
|
|
||||||
android.R.attr.state_hovered,
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final int[] SELECTED_PRESSED_STATE_SET = {
|
|
||||||
android.R.attr.state_selected, android.R.attr.state_pressed,
|
|
||||||
};
|
|
||||||
private static final int[] SELECTED_HOVERED_FOCUSED_STATE_SET = {
|
|
||||||
android.R.attr.state_selected, android.R.attr.state_hovered, android.R.attr.state_focused,
|
|
||||||
};
|
|
||||||
private static final int[] SELECTED_FOCUSED_STATE_SET = {
|
|
||||||
android.R.attr.state_selected, android.R.attr.state_focused,
|
|
||||||
};
|
|
||||||
private static final int[] SELECTED_HOVERED_STATE_SET = {
|
|
||||||
android.R.attr.state_selected, android.R.attr.state_hovered,
|
|
||||||
};
|
|
||||||
private static final int[] SELECTED_STATE_SET = {
|
|
||||||
android.R.attr.state_selected,
|
|
||||||
};
|
|
||||||
|
|
||||||
private static final int[] ENABLED_PRESSED_STATE_SET = {
|
|
||||||
android.R.attr.state_enabled, android.R.attr.state_pressed
|
|
||||||
};
|
|
||||||
|
|
||||||
public static ColorStateList convertToRippleDrawableColor(@Nullable ColorStateList rippleColor) {
|
|
||||||
if (USE_FRAMEWORK_RIPPLE) {
|
|
||||||
int size = 2;
|
|
||||||
|
|
||||||
final int[][] states = new int[size][];
|
|
||||||
final int[] colors = new int[size];
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
// Ideally we would define a different composite color for each state, but that causes the
|
|
||||||
// ripple animation to abort prematurely.
|
|
||||||
// So we only allow two base states: selected, and non-selected. For each base state, we only
|
|
||||||
// base the ripple composite on its pressed state.
|
|
||||||
|
|
||||||
// Selected base state.
|
|
||||||
states[i] = SELECTED_STATE_SET;
|
|
||||||
colors[i] = getColorForState(rippleColor, SELECTED_PRESSED_STATE_SET);
|
|
||||||
i++;
|
|
||||||
|
|
||||||
// Non-selected base state.
|
|
||||||
states[i] = StateSet.NOTHING;
|
|
||||||
colors[i] = getColorForState(rippleColor, PRESSED_STATE_SET);
|
|
||||||
i++;
|
|
||||||
|
|
||||||
return new ColorStateList(states, colors);
|
|
||||||
} else {
|
|
||||||
int size = 10;
|
|
||||||
|
|
||||||
final int[][] states = new int[size][];
|
|
||||||
final int[] colors = new int[size];
|
|
||||||
int i = 0;
|
|
||||||
|
|
||||||
states[i] = SELECTED_PRESSED_STATE_SET;
|
|
||||||
colors[i] = getColorForState(rippleColor, SELECTED_PRESSED_STATE_SET);
|
|
||||||
i++;
|
|
||||||
|
|
||||||
states[i] = SELECTED_HOVERED_FOCUSED_STATE_SET;
|
|
||||||
colors[i] = getColorForState(rippleColor, SELECTED_HOVERED_FOCUSED_STATE_SET);
|
|
||||||
i++;
|
|
||||||
|
|
||||||
states[i] = SELECTED_FOCUSED_STATE_SET;
|
|
||||||
colors[i] = getColorForState(rippleColor, SELECTED_FOCUSED_STATE_SET);
|
|
||||||
i++;
|
|
||||||
|
|
||||||
states[i] = SELECTED_HOVERED_STATE_SET;
|
|
||||||
colors[i] = getColorForState(rippleColor, SELECTED_HOVERED_STATE_SET);
|
|
||||||
i++;
|
|
||||||
|
|
||||||
// Checked state.
|
|
||||||
states[i] = SELECTED_STATE_SET;
|
|
||||||
colors[i] = Color.TRANSPARENT;
|
|
||||||
i++;
|
|
||||||
|
|
||||||
states[i] = PRESSED_STATE_SET;
|
|
||||||
colors[i] = getColorForState(rippleColor, PRESSED_STATE_SET);
|
|
||||||
i++;
|
|
||||||
|
|
||||||
states[i] = HOVERED_FOCUSED_STATE_SET;
|
|
||||||
colors[i] = getColorForState(rippleColor, HOVERED_FOCUSED_STATE_SET);
|
|
||||||
i++;
|
|
||||||
|
|
||||||
states[i] = FOCUSED_STATE_SET;
|
|
||||||
colors[i] = getColorForState(rippleColor, FOCUSED_STATE_SET);
|
|
||||||
i++;
|
|
||||||
|
|
||||||
states[i] = HOVERED_STATE_SET;
|
|
||||||
colors[i] = getColorForState(rippleColor, HOVERED_STATE_SET);
|
|
||||||
i++;
|
|
||||||
|
|
||||||
// Default state.
|
|
||||||
states[i] = StateSet.NOTHING;
|
|
||||||
colors[i] = Color.TRANSPARENT;
|
|
||||||
i++;
|
|
||||||
|
|
||||||
return new ColorStateList(states, colors);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@ColorInt
|
|
||||||
private static int getColorForState(@Nullable ColorStateList rippleColor, int[] state) {
|
|
||||||
int color;
|
|
||||||
if (rippleColor != null) {
|
|
||||||
color = rippleColor.getColorForState(state, rippleColor.getDefaultColor());
|
|
||||||
} else {
|
|
||||||
color = Color.TRANSPARENT;
|
|
||||||
}
|
|
||||||
return USE_FRAMEWORK_RIPPLE ? doubleAlpha(color) : color;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* On API 21+, the framework composites a ripple color onto the display at about 50% opacity.
|
|
||||||
* Since we are providing precise ripple colors, cancel that out by doubling the opacity here.
|
|
||||||
*/
|
|
||||||
@ColorInt
|
|
||||||
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
|
|
||||||
private static int doubleAlpha(@ColorInt int color) {
|
|
||||||
int alpha = Math.min(2 * Color.alpha(color), 255);
|
|
||||||
return ColorUtils.setAlphaComponent(color, alpha);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -54,7 +54,7 @@ public class SAFUtil {
|
||||||
public static final int REQUEST_SAF_PICK_TREE = 43;
|
public static final int REQUEST_SAF_PICK_TREE = 43;
|
||||||
|
|
||||||
public static boolean isSAFRequired(File file) {
|
public static boolean isSAFRequired(File file) {
|
||||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && !file.canWrite();
|
return !file.canWrite();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isSAFRequired(String path) {
|
public static boolean isSAFRequired(String path) {
|
||||||
|
|
|
@ -29,14 +29,14 @@ public class SwipeAndDragHelper extends ItemTouchHelper.Callback {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMovementFlags(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder) {
|
public int getMovementFlags(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder) {
|
||||||
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
|
int dragFlags = ItemTouchHelper.UP | ItemTouchHelper.DOWN;
|
||||||
return makeMovementFlags(dragFlags, 0);
|
return makeMovementFlags(dragFlags, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean onMove(
|
public boolean onMove(
|
||||||
RecyclerView recyclerView,
|
@NonNull RecyclerView recyclerView,
|
||||||
RecyclerView.ViewHolder viewHolder,
|
RecyclerView.ViewHolder viewHolder,
|
||||||
RecyclerView.ViewHolder target) {
|
RecyclerView.ViewHolder target) {
|
||||||
contract.onViewMoved(viewHolder.getLayoutPosition(), target.getLayoutPosition());
|
contract.onViewMoved(viewHolder.getLayoutPosition(), target.getLayoutPosition());
|
||||||
|
@ -44,7 +44,7 @@ public class SwipeAndDragHelper extends ItemTouchHelper.Callback {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {}
|
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLongPressDragEnabled() {
|
public boolean isLongPressDragEnabled() {
|
||||||
|
@ -53,9 +53,9 @@ public class SwipeAndDragHelper extends ItemTouchHelper.Callback {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onChildDraw(
|
public void onChildDraw(
|
||||||
Canvas c,
|
@NonNull Canvas c,
|
||||||
RecyclerView recyclerView,
|
@NonNull RecyclerView recyclerView,
|
||||||
RecyclerView.ViewHolder viewHolder,
|
@NonNull RecyclerView.ViewHolder viewHolder,
|
||||||
float dX,
|
float dX,
|
||||||
float dY,
|
float dY,
|
||||||
int actionState,
|
int actionState,
|
||||||
|
|
|
@ -76,11 +76,6 @@ object ViewUtil {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun setProgressDrawable(indicator: CircularProgressIndicator, newColor: Int) {
|
|
||||||
indicator.setIndicatorColor(newColor)
|
|
||||||
indicator.trackColor = ColorUtil.withAlpha(newColor, 0.2f)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun hitTest(v: View, x: Int, y: Int): Boolean {
|
fun hitTest(v: View, x: Int, y: Int): Boolean {
|
||||||
val tx = (v.translationX + 0.5f).toInt()
|
val tx = (v.translationX + 0.5f).toInt()
|
||||||
val ty = (v.translationY + 0.5f).toInt()
|
val ty = (v.translationY + 0.5f).toInt()
|
||||||
|
|
|
@ -75,11 +75,9 @@ public class MediaNotificationProcessor {
|
||||||
*/
|
*/
|
||||||
private static final int LIGHTNESS_TEXT_DIFFERENCE_DARK = -10;
|
private static final int LIGHTNESS_TEXT_DIFFERENCE_DARK = -10;
|
||||||
|
|
||||||
private static final String TAG = "ColorPicking";
|
|
||||||
private float[] mFilteredBackgroundHsl = null;
|
private float[] mFilteredBackgroundHsl = null;
|
||||||
private final Palette.Filter mBlackWhiteFilter =
|
private final Palette.Filter mBlackWhiteFilter =
|
||||||
(rgb, hsl) -> !isWhiteOrBlack(hsl);
|
(rgb, hsl) -> !isWhiteOrBlack(hsl);
|
||||||
private boolean mIsLowPriority;
|
|
||||||
private int backgroundColor;
|
private int backgroundColor;
|
||||||
private int secondaryTextColor;
|
private int secondaryTextColor;
|
||||||
private int primaryTextColor;
|
private int primaryTextColor;
|
||||||
|
@ -376,10 +374,6 @@ public class MediaNotificationProcessor {
|
||||||
return hslColor[2] >= WHITE_MIN_LIGHTNESS;
|
return hslColor[2] >= WHITE_MIN_LIGHTNESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setIsLowPriority(boolean isLowPriority) {
|
|
||||||
mIsLowPriority = isLowPriority;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ensureColors(int backgroundColor, int mForegroundColor) {
|
private void ensureColors(int backgroundColor, int mForegroundColor) {
|
||||||
{
|
{
|
||||||
double backLum = NotificationColorUtil.calculateLuminance(backgroundColor);
|
double backLum = NotificationColorUtil.calculateLuminance(backgroundColor);
|
||||||
|
|
|
@ -55,7 +55,7 @@ public class NotificationColorUtil {
|
||||||
|
|
||||||
private final ImageUtils mImageUtils = new ImageUtils();
|
private final ImageUtils mImageUtils = new ImageUtils();
|
||||||
private final WeakHashMap<Bitmap, Pair<Boolean, Integer>> mGrayscaleBitmapCache =
|
private final WeakHashMap<Bitmap, Pair<Boolean, Integer>> mGrayscaleBitmapCache =
|
||||||
new WeakHashMap<Bitmap, Pair<Boolean, Integer>>();
|
new WeakHashMap<>();
|
||||||
|
|
||||||
private final int mGrayscaleIconMaxSize; // @dimen/notification_large_icon_width (64dp)
|
private final int mGrayscaleIconMaxSize; // @dimen/notification_large_icon_width (64dp)
|
||||||
|
|
||||||
|
@ -353,11 +353,7 @@ public class NotificationColorUtil {
|
||||||
|
|
||||||
public static int resolvePrimaryColor(Context context, int backgroundColor) {
|
public static int resolvePrimaryColor(Context context, int backgroundColor) {
|
||||||
boolean useDark = shouldUseDark(backgroundColor);
|
boolean useDark = shouldUseDark(backgroundColor);
|
||||||
if (useDark) {
|
|
||||||
return ContextCompat.getColor(context, android.R.color.primary_text_light);
|
return ContextCompat.getColor(context, android.R.color.primary_text_light);
|
||||||
} else {
|
|
||||||
return ContextCompat.getColor(context, android.R.color.primary_text_light);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int resolveSecondaryColor(Context context, int backgroundColor) {
|
public static int resolveSecondaryColor(Context context, int backgroundColor) {
|
||||||
|
@ -831,11 +827,11 @@ public class NotificationColorUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int constrain(int amount, int low, int high) {
|
private static int constrain(int amount, int low, int high) {
|
||||||
return amount < low ? low : (amount > high ? high : amount);
|
return amount < low ? low : (Math.min(amount, high));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static float constrain(float amount, float low, float high) {
|
private static float constrain(float amount, float low, float high) {
|
||||||
return amount < low ? low : (amount > high ? high : amount);
|
return amount < low ? low : (Math.min(amount, high));
|
||||||
}
|
}
|
||||||
|
|
||||||
private static double pivotXyzComponent(double component) {
|
private static double pivotXyzComponent(double component) {
|
||||||
|
|
|
@ -399,6 +399,7 @@ public class BreadCrumbLayout extends HorizontalScrollView implements View.OnCli
|
||||||
return file.getPath().equals("/") ? "root" : file.getName();
|
return file.getPath().equals("/") ? "root" : file.getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return "Crumb{" + "file=" + file + ", scrollPos=" + scrollPos + '}';
|
return "Crumb{" + "file=" + file + ", scrollPos=" + scrollPos + '}';
|
||||||
|
|
|
@ -209,9 +209,7 @@ public class CircularImageView extends AppCompatImageView {
|
||||||
private void drawShadow(float shadowRadius, int shadowColor) {
|
private void drawShadow(float shadowRadius, int shadowColor) {
|
||||||
this.shadowRadius = shadowRadius;
|
this.shadowRadius = shadowRadius;
|
||||||
this.shadowColor = shadowColor;
|
this.shadowColor = shadowColor;
|
||||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
|
|
||||||
setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
|
setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
|
||||||
}
|
|
||||||
paintBorder.setShadowLayer(shadowRadius, 0.0f, shadowRadius / 2, shadowColor);
|
paintBorder.setShadowLayer(shadowRadius, 0.0f, shadowRadius / 2, shadowColor);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue