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 {
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 30
|
||||
targetSdkVersion 31
|
||||
|
||||
renderscriptTargetApi 29//must match target sdk and build tools
|
||||
vectorDrawables.useSupportLibrary = true
|
||||
|
@ -126,7 +126,7 @@ dependencies {
|
|||
def retrofit_version = '2.9.0'
|
||||
implementation "com.squareup.retrofit2:retrofit:$retrofit_version"
|
||||
implementation "com.squareup.retrofit2:converter-gson:$retrofit_version"
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.2'
|
||||
implementation 'com.squareup.okhttp3:logging-interceptor:5.0.0-alpha.3'
|
||||
|
||||
def material_dialog_version = "3.3.0"
|
||||
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-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-android:$koin_version"
|
||||
|
||||
|
@ -157,7 +157,7 @@ dependencies {
|
|||
implementation 'com.anjlab.android.iab.v3:library:2.0.3'
|
||||
implementation 'com.r0adkll:slidableactivity:2.1.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 'cat.ereza:customactivityoncrash:2.3.0'
|
||||
debugImplementation 'com.github.amitshekhariitbhu:Android-Debug-Database:1.0.6'
|
||||
|
|
|
@ -262,6 +262,7 @@
|
|||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:label="@string/app_name"
|
||||
android:foregroundServiceType="mediaPlayback"
|
||||
tools:ignore="ExportedService">
|
||||
<intent-filter>
|
||||
<action android:name="android.media.browse.MediaBrowserService" />
|
||||
|
|
|
@ -37,6 +37,7 @@ object Constants {
|
|||
const val IS_MUSIC =
|
||||
MediaStore.Audio.AudioColumns.IS_MUSIC + "=1" + " AND " + MediaStore.Audio.AudioColumns.TITLE + " != ''"
|
||||
|
||||
@Suppress("Deprecation")
|
||||
val baseProjection = arrayOf(
|
||||
BaseColumns._ID, // 0
|
||||
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 ARTIST_GRID_SIZE = "artist_grid_size"
|
||||
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 AUDIO_DUCKING = "audio_ducking"
|
||||
const val LAST_ADDED_CUTOFF = "last_added_interval"
|
||||
|
|
|
@ -29,18 +29,10 @@ public class LanguageContextWrapper extends ContextWrapper {
|
|||
LocaleList localeList = new LocaleList(newLocale);
|
||||
LocaleList.setDefault(localeList);
|
||||
configuration.setLocales(localeList);
|
||||
|
||||
context = context.createConfigurationContext(configuration);
|
||||
|
||||
} else if (VersionUtils.INSTANCE.hasLollipop()) {
|
||||
configuration.setLocale(newLocale);
|
||||
context = context.createConfigurationContext(configuration);
|
||||
|
||||
} else {
|
||||
configuration.locale = newLocale;
|
||||
res.updateConfiguration(configuration, res.getDisplayMetrics());
|
||||
configuration.setLocale(newLocale);
|
||||
}
|
||||
|
||||
context = context.createConfigurationContext(configuration);
|
||||
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() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {
|
||||
setShowWhenLocked(true)
|
||||
|
|
|
@ -132,7 +132,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
|
|||
permissionDeniedMessage!!,
|
||||
Snackbar.LENGTH_INDEFINITE
|
||||
)
|
||||
.setAction(code.name.monkey.retromusic.R.string.action_grant) { requestPermissions() }
|
||||
.setAction(R.string.action_grant) { requestPermissions() }
|
||||
.setActionTextColor(ThemeStore.accentColor(this)).show()
|
||||
} else {
|
||||
// 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,
|
||||
permissionDeniedMessage!!,
|
||||
Snackbar.LENGTH_INDEFINITE
|
||||
).setAction(code.name.monkey.retromusic.R.string.action_settings) {
|
||||
).setAction(R.string.action_settings) {
|
||||
val intent = Intent()
|
||||
intent.action = Settings.ACTION_APPLICATION_DETAILS_SETTINGS
|
||||
val uri = Uri.fromParts(
|
||||
|
@ -172,7 +172,7 @@ abstract class AbsBaseActivity : AbsThemeActivity() {
|
|||
v.getGlobalVisibleRect(outRect)
|
||||
if (!outRect.contains(event.rawX.toInt(), event.rawY.toInt())) {
|
||||
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.appcompat.app.AppCompatDelegate.setDefaultNightMode
|
||||
import androidx.core.os.ConfigurationCompat
|
||||
import androidx.core.view.WindowInsetsCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat
|
||||
import code.name.monkey.appthemehelper.ATH
|
||||
import code.name.monkey.appthemehelper.ThemeStore
|
||||
import code.name.monkey.appthemehelper.common.ATHToolbarActivity
|
||||
|
@ -118,12 +120,11 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
|
|||
if (statusBar != null) {
|
||||
when {
|
||||
VersionUtils.hasMarshmallow() -> statusBar.setBackgroundColor(color)
|
||||
VersionUtils.hasLollipop() -> statusBar.setBackgroundColor(
|
||||
else -> statusBar.setBackgroundColor(
|
||||
ColorUtil.darkenColor(
|
||||
color
|
||||
)
|
||||
)
|
||||
else -> statusBar.setBackgroundColor(color)
|
||||
}
|
||||
} else {
|
||||
when {
|
||||
|
@ -193,16 +194,20 @@ abstract class AbsThemeActivity : ATHToolbarActivity(), Runnable {
|
|||
}
|
||||
|
||||
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) {
|
||||
window.decorView.systemUiVisibility = flags
|
||||
WindowInsetsControllerCompat(window, window.decorView).apply {
|
||||
systemBarsBehavior =
|
||||
WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||
hide(WindowInsetsCompat.Type.systemBars())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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() {
|
||||
|
|
|
@ -7,6 +7,7 @@ import android.content.pm.PackageManager;
|
|||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.IntRange;
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.Locale;
|
||||
|
@ -16,19 +17,16 @@ import code.name.monkey.retromusic.util.PreferenceUtil;
|
|||
public class DeviceInfo {
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
@SuppressWarnings("deprecation")
|
||||
private final String[] abis =
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP
|
||||
? Build.SUPPORTED_ABIS
|
||||
: new String[] {Build.CPU_ABI, Build.CPU_ABI2};
|
||||
Build.SUPPORTED_ABIS;
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
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")
|
||||
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;
|
||||
|
||||
|
@ -138,6 +136,7 @@ public class DeviceInfo {
|
|||
+ "</table>\n";
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
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) {
|
||||
try {
|
||||
kotlin.runCatching {
|
||||
var artwork: Artwork? = null
|
||||
var albumArtFile: File? = null
|
||||
if (info.artworkInfo?.artwork != null) {
|
||||
|
@ -113,18 +113,18 @@ class TagWriter {
|
|||
deleteAlbumArt(context, info.artworkInfo!!.albumId)
|
||||
}
|
||||
scan(context, info.filePaths)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
scan(context, null)
|
||||
}.onFailure {
|
||||
it.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@RequiresApi(Build.VERSION_CODES.R)
|
||||
suspend fun writeTagsToFilesR(context: Context, info: AudioTagInfo) =
|
||||
suspend fun writeTagsToFilesR(context: Context, info: AudioTagInfo): List<File> =
|
||||
withContext(Dispatchers.IO) {
|
||||
val cacheFiles = mutableListOf<File>()
|
||||
try {
|
||||
kotlin.runCatching {
|
||||
var artwork: Artwork? = null
|
||||
var albumArtFile: File? = null
|
||||
if (info.artworkInfo?.artwork != null) {
|
||||
|
@ -193,11 +193,10 @@ class TagWriter {
|
|||
} else if (deletedArtwork) {
|
||||
deleteAlbumArt(context, info.artworkInfo!!.albumId)
|
||||
}
|
||||
cacheFiles
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
listOf()
|
||||
}.onFailure {
|
||||
it.printStackTrace()
|
||||
}
|
||||
cacheFiles
|
||||
}
|
||||
}
|
||||
}
|
|
@ -14,6 +14,7 @@
|
|||
*/
|
||||
package code.name.monkey.retromusic.adapter
|
||||
|
||||
import android.os.SystemClock
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
|
@ -51,6 +52,8 @@ class HomeAdapter(
|
|||
) : RecyclerView.Adapter<RecyclerView.ViewHolder>(), IArtistClickListener, IAlbumClickListener,
|
||||
IGenreClickListener {
|
||||
|
||||
private var mLastClickTime: Long = 0
|
||||
|
||||
private var list = listOf<Home>()
|
||||
|
||||
override fun getItemViewType(position: Int): Int {
|
||||
|
@ -194,6 +197,10 @@ class HomeAdapter(
|
|||
itemView.findViewById<TextView>(R.id.message).apply {
|
||||
setTextColor(color)
|
||||
setOnClickListener {
|
||||
if (SystemClock.elapsedRealtime() - mLastClickTime < 1000){
|
||||
return@setOnClickListener
|
||||
}
|
||||
mLastClickTime = SystemClock.elapsedRealtime()
|
||||
MusicPlayerRemote.playNext((home.arrayList as List<Song>).subList(0, 8))
|
||||
if (!MusicPlayerRemote.isPlaying) {
|
||||
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 {
|
||||
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.fragments.AlbumCoverStyle
|
||||
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.RetroGlideExtension
|
||||
import code.name.monkey.retromusic.glide.RetroMusicColoredTarget
|
||||
import code.name.monkey.retromusic.misc.CustomFragmentStatePagerAdapter
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
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.color.MediaNotificationProcessor
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior.STATE_EXPANDED
|
||||
|
@ -127,7 +127,8 @@ class AlbumCoverPagerAdapter(
|
|||
setTitle(song.title)
|
||||
setMessage(if (data.isNullOrEmpty()) "No lyrics found" else data)
|
||||
setNegativeButton(R.string.synced_lyrics) { _, _ ->
|
||||
NavigationUtil.goToLyrics(requireActivity())
|
||||
|
||||
goToLyrics(requireActivity())
|
||||
}
|
||||
show()
|
||||
}
|
||||
|
|
|
@ -22,6 +22,7 @@ import android.view.View
|
|||
import android.view.ViewGroup
|
||||
import androidx.appcompat.widget.PopupMenu
|
||||
import androidx.core.view.ViewCompat
|
||||
import androidx.core.view.setPadding
|
||||
import androidx.fragment.app.FragmentActivity
|
||||
import code.name.monkey.retromusic.R
|
||||
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.PlaylistWithSongs
|
||||
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.show
|
||||
import code.name.monkey.retromusic.glide.GlideApp
|
||||
|
@ -42,7 +44,7 @@ import code.name.monkey.retromusic.util.MusicUtil
|
|||
|
||||
class PlaylistAdapter(
|
||||
override val activity: FragmentActivity,
|
||||
private var dataSet: List<PlaylistWithSongs>,
|
||||
var dataSet: List<PlaylistWithSongs>,
|
||||
private var itemLayoutRes: Int,
|
||||
ICabHolder: ICabHolder?,
|
||||
private val listener: IPlaylistClickListener
|
||||
|
@ -94,7 +96,12 @@ class PlaylistAdapter(
|
|||
holder.menu?.show()
|
||||
}
|
||||
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()
|
||||
.into(holder.image!!)
|
||||
}
|
||||
|
|
|
@ -188,7 +188,7 @@ class PlayingQueueAdapter(
|
|||
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) {
|
||||
SwipeResultActionDefault()
|
||||
} 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 {
|
||||
|
||||
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 {
|
||||
|
||||
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.widget.RemoteViews
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.activities.MainActivity
|
||||
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget
|
||||
|
@ -61,7 +62,7 @@ class AppWidgetBig : BaseAppWidget() {
|
|||
context,
|
||||
R.drawable.ic_skip_next,
|
||||
MaterialValueHelper.getPrimaryTextColor(context, false)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
appWidgetView.setImageViewBitmap(
|
||||
|
@ -70,16 +71,16 @@ class AppWidgetBig : BaseAppWidget() {
|
|||
context,
|
||||
R.drawable.ic_skip_previous,
|
||||
MaterialValueHelper.getPrimaryTextColor(context, false)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
appWidgetView.setImageViewBitmap(
|
||||
R.id.button_toggle_play_pause, BaseAppWidget.createBitmap(
|
||||
R.id.button_toggle_play_pause, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(
|
||||
context,
|
||||
R.drawable.ic_play_arrow_white_32dp,
|
||||
MaterialValueHelper.getPrimaryTextColor(context, false)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -126,7 +127,7 @@ class AppWidgetBig : BaseAppWidget() {
|
|||
service,
|
||||
playPauseRes,
|
||||
primaryColor
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -137,7 +138,7 @@ class AppWidgetBig : BaseAppWidget() {
|
|||
service,
|
||||
R.drawable.ic_skip_next,
|
||||
primaryColor
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
appWidgetView.setImageViewBitmap(
|
||||
|
@ -146,7 +147,7 @@ class AppWidgetBig : BaseAppWidget() {
|
|||
service,
|
||||
R.drawable.ic_skip_previous,
|
||||
primaryColor
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -155,7 +156,7 @@ class AppWidgetBig : BaseAppWidget() {
|
|||
|
||||
// Load the album cover async and push the update on completion
|
||||
val p = RetroUtil.getScreenSize(service)
|
||||
val widgetImageSize = Math.min(p.x, p.y)
|
||||
val widgetImageSize = p.x.coerceAtMost(p.y)
|
||||
val appContext = service.applicationContext
|
||||
service.runOnUiThread {
|
||||
if (target != null) {
|
||||
|
@ -208,7 +209,11 @@ class AppWidgetBig : BaseAppWidget() {
|
|||
// Home
|
||||
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
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)
|
||||
|
||||
// Previous track
|
||||
|
|
|
@ -24,6 +24,7 @@ import android.text.TextUtils
|
|||
import android.view.View
|
||||
import android.widget.RemoteViews
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.activities.MainActivity
|
||||
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget
|
||||
|
@ -59,7 +60,7 @@ class AppWidgetCard : BaseAppWidget() {
|
|||
context,
|
||||
R.drawable.ic_skip_next,
|
||||
secondaryColor
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
appWidgetView.setImageViewBitmap(
|
||||
|
@ -68,7 +69,7 @@ class AppWidgetCard : BaseAppWidget() {
|
|||
context,
|
||||
R.drawable.ic_skip_previous,
|
||||
secondaryColor
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
appWidgetView.setImageViewBitmap(
|
||||
|
@ -77,7 +78,7 @@ class AppWidgetCard : BaseAppWidget() {
|
|||
context,
|
||||
R.drawable.ic_play_arrow_white_32dp,
|
||||
secondaryColor
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -112,7 +113,7 @@ class AppWidgetCard : BaseAppWidget() {
|
|||
service,
|
||||
playPauseRes,
|
||||
MaterialValueHelper.getSecondaryTextColor(service, true)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -123,7 +124,7 @@ class AppWidgetCard : BaseAppWidget() {
|
|||
service,
|
||||
R.drawable.ic_skip_next,
|
||||
MaterialValueHelper.getSecondaryTextColor(service, true)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
appWidgetView.setImageViewBitmap(
|
||||
|
@ -132,7 +133,7 @@ class AppWidgetCard : BaseAppWidget() {
|
|||
service,
|
||||
R.drawable.ic_skip_previous,
|
||||
MaterialValueHelper.getSecondaryTextColor(service, true)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -231,7 +232,11 @@ class AppWidgetCard : BaseAppWidget() {
|
|||
// Home
|
||||
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
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.media_titles, pendingIntent)
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ import android.text.TextUtils
|
|||
import android.view.View
|
||||
import android.widget.RemoteViews
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.activities.MainActivity
|
||||
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget
|
||||
|
@ -60,7 +61,7 @@ class AppWidgetClassic : BaseAppWidget() {
|
|||
context,
|
||||
R.drawable.ic_skip_next,
|
||||
MaterialValueHelper.getSecondaryTextColor(context, true)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
appWidgetView.setImageViewBitmap(
|
||||
|
@ -70,7 +71,7 @@ class AppWidgetClassic : BaseAppWidget() {
|
|||
context,
|
||||
R.drawable.ic_skip_previous,
|
||||
MaterialValueHelper.getSecondaryTextColor(context, true)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
appWidgetView.setImageViewBitmap(
|
||||
|
@ -80,7 +81,7 @@ class AppWidgetClassic : BaseAppWidget() {
|
|||
context,
|
||||
R.drawable.ic_play_arrow_white_32dp,
|
||||
MaterialValueHelper.getSecondaryTextColor(context, true)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -221,7 +222,11 @@ class AppWidgetClassic : BaseAppWidget() {
|
|||
|
||||
// Home
|
||||
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.media_titles, pendingIntent)
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import android.text.TextUtils
|
|||
import android.view.View
|
||||
import android.widget.RemoteViews
|
||||
import code.name.monkey.appthemehelper.util.MaterialValueHelper
|
||||
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.activities.MainActivity
|
||||
import code.name.monkey.retromusic.appwidgets.base.BaseAppWidget
|
||||
|
@ -58,7 +59,7 @@ class AppWidgetSmall : BaseAppWidget() {
|
|||
context,
|
||||
R.drawable.ic_skip_next,
|
||||
MaterialValueHelper.getSecondaryTextColor(context, true)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
appWidgetView.setImageViewBitmap(
|
||||
|
@ -68,7 +69,7 @@ class AppWidgetSmall : BaseAppWidget() {
|
|||
context,
|
||||
R.drawable.ic_skip_previous,
|
||||
MaterialValueHelper.getSecondaryTextColor(context, true)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
appWidgetView.setImageViewBitmap(
|
||||
|
@ -78,7 +79,7 @@ class AppWidgetSmall : BaseAppWidget() {
|
|||
context,
|
||||
R.drawable.ic_play_arrow_white_32dp,
|
||||
MaterialValueHelper.getSecondaryTextColor(context, true)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -160,7 +161,7 @@ class AppWidgetSmall : BaseAppWidget() {
|
|||
R.id.button_toggle_play_pause, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(
|
||||
service, playPauseRes, color
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -169,14 +170,14 @@ class AppWidgetSmall : BaseAppWidget() {
|
|||
R.id.button_next, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(
|
||||
service, R.drawable.ic_skip_next, color
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
appWidgetView.setImageViewBitmap(
|
||||
R.id.button_prev, createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(
|
||||
service, R.drawable.ic_skip_previous, color
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -207,7 +208,11 @@ class AppWidgetSmall : BaseAppWidget() {
|
|||
// Home
|
||||
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
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.media_titles, pendingIntent)
|
||||
|
||||
|
|
|
@ -18,11 +18,11 @@ import android.app.PendingIntent
|
|||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.provider.MediaStore
|
||||
import android.text.TextUtils
|
||||
import android.view.View
|
||||
import android.widget.RemoteViews
|
||||
import androidx.core.content.ContextCompat
|
||||
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||
import code.name.monkey.retromusic.App
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.activities.MainActivity
|
||||
|
@ -42,7 +42,7 @@ class AppWidgetText : BaseAppWidget() {
|
|||
context, R.drawable.ic_skip_next, ContextCompat.getColor(
|
||||
context, R.color.md_white_1000
|
||||
)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
appWidgetView.setImageViewBitmap(
|
||||
|
@ -51,7 +51,7 @@ class AppWidgetText : BaseAppWidget() {
|
|||
context, R.drawable.ic_skip_previous, ContextCompat.getColor(
|
||||
context, R.color.md_white_1000
|
||||
)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
appWidgetView.setImageViewBitmap(
|
||||
|
@ -60,7 +60,7 @@ class AppWidgetText : BaseAppWidget() {
|
|||
context, R.drawable.ic_play_arrow_white_32dp, ContextCompat.getColor(
|
||||
context, R.color.md_white_1000
|
||||
)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -89,7 +89,11 @@ class AppWidgetText : BaseAppWidget() {
|
|||
|
||||
// Home
|
||||
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.media_titles, pendingIntent)
|
||||
|
||||
|
@ -132,7 +136,7 @@ class AppWidgetText : BaseAppWidget() {
|
|||
App.getContext(), playPauseRes, ContextCompat.getColor(
|
||||
App.getContext(), R.color.md_white_1000
|
||||
)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
appWidgetView.setImageViewBitmap(
|
||||
|
@ -143,7 +147,7 @@ class AppWidgetText : BaseAppWidget() {
|
|||
ContextCompat.getColor(
|
||||
App.getContext(), R.color.md_white_1000
|
||||
)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
appWidgetView.setImageViewBitmap(
|
||||
|
@ -154,7 +158,7 @@ class AppWidgetText : BaseAppWidget() {
|
|||
ContextCompat.getColor(
|
||||
App.getContext(), R.color.md_white_1000
|
||||
)
|
||||
)!!, 1f
|
||||
), 1f
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import android.os.Build
|
|||
import android.text.TextUtils
|
||||
import android.widget.RemoteViews
|
||||
import androidx.core.content.ContextCompat
|
||||
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||
import code.name.monkey.retromusic.App
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.model.Song
|
||||
|
@ -99,7 +100,11 @@ abstract class BaseAppWidget : AppWidgetProvider() {
|
|||
return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
PendingIntent.getForegroundService(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)
|
||||
} 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.framework.CastSession
|
||||
import com.google.android.gms.common.images.WebImage
|
||||
import org.json.JSONObject
|
||||
import java.net.MalformedURLException
|
||||
import java.net.URL
|
||||
|
||||
|
@ -41,7 +42,7 @@ object CastHelper {
|
|||
position,
|
||||
MediaStatus.REPEAT_MODE_REPEAT_OFF,
|
||||
progress,
|
||||
null
|
||||
JSONObject()
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
|
|
|
@ -13,7 +13,7 @@ class ExpandedControlsActivity : ExpandedControllerActivity() {
|
|||
override fun onCreateOptionsMenu(menu: Menu?): Boolean {
|
||||
super.onCreateOptionsMenu(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
|
||||
}
|
||||
}
|
|
@ -17,7 +17,7 @@ class RetroWebServer(val context: Context) : NanoHTTPD(SERVER_PORT) {
|
|||
const val PART_COVER_ART = "coverart"
|
||||
const val PART_SONG = "song"
|
||||
const val PARAM_ID = "id"
|
||||
var mRetroWebServer: RetroWebServer? = null
|
||||
private var mRetroWebServer: RetroWebServer? = null
|
||||
fun getInstance(context: Context): RetroWebServer {
|
||||
if (mRetroWebServer == null) {
|
||||
mRetroWebServer = RetroWebServer(context)
|
||||
|
|
|
@ -26,6 +26,8 @@ interface HistoryDao {
|
|||
@Insert(onConflict = OnConflictStrategy.REPLACE)
|
||||
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")
|
||||
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 {
|
||||
return HistoryEntity(
|
||||
id = id,
|
||||
|
|
|
@ -60,6 +60,11 @@ class DeleteSongsDialog : DialogFragment() {
|
|||
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
|
||||
libraryViewModel = activity?.getViewModel() as LibraryViewModel
|
||||
val songs = extraNotNull<List<Song>>(EXTRA_SONG).value
|
||||
if (VersionUtils.hasR()) {
|
||||
dismiss()
|
||||
MusicUtil.deleteTracksR(requireActivity(), songs)
|
||||
reloadTabs()
|
||||
}
|
||||
val pair = if (songs.size > 1) {
|
||||
Pair(
|
||||
R.string.delete_songs_title,
|
||||
|
@ -90,11 +95,7 @@ class DeleteSongsDialog : DialogFragment() {
|
|||
if ((songs.size == 1) && MusicPlayerRemote.isPlaying(songs[0])) {
|
||||
MusicPlayerRemote.playNextSong()
|
||||
}
|
||||
if (VersionUtils.hasR()) {
|
||||
dismiss()
|
||||
MusicUtil.deleteTracksR(requireActivity(), songs)
|
||||
reloadTabs()
|
||||
} else if (!SAFUtil.isSAFRequiredForSongs(songs)) {
|
||||
if (!SAFUtil.isSAFRequiredForSongs(songs)) {
|
||||
CoroutineScope(Dispatchers.IO).launch {
|
||||
dismiss()
|
||||
MusicUtil.deleteTracks(requireContext(), songs)
|
||||
|
@ -138,7 +139,7 @@ class DeleteSongsDialog : DialogFragment() {
|
|||
}
|
||||
}
|
||||
|
||||
fun reloadTabs() {
|
||||
private fun reloadTabs() {
|
||||
libraryViewModel.forceReload(ReloadType.Songs)
|
||||
libraryViewModel.forceReload(ReloadType.HomeSections)
|
||||
libraryViewModel.forceReload(ReloadType.Artists)
|
||||
|
|
|
@ -29,6 +29,7 @@ import android.widget.SeekBar
|
|||
import android.widget.TextView
|
||||
import android.widget.Toast
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.extensions.addAccentColor
|
||||
import code.name.monkey.retromusic.extensions.colorButtons
|
||||
|
@ -138,7 +139,11 @@ class SleepTimerDialog : DialogFragment() {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
|
|
@ -3,13 +3,9 @@ package code.name.monkey.retromusic.extensions
|
|||
import android.app.Activity
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.os.Environment
|
||||
import android.provider.DocumentsContract
|
||||
import androidx.activity.result.ActivityResult
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.documentfile.provider.DocumentFile
|
||||
import androidx.fragment.app.Fragment
|
||||
import java.io.File
|
||||
import java.io.OutputStream
|
||||
|
||||
fun Fragment.createNewFile(
|
||||
|
|
|
@ -78,7 +78,7 @@ fun isBlack(fArr: FloatArray): Boolean {
|
|||
|
||||
fun isNearRedLine(fArr: FloatArray): Boolean {
|
||||
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 {
|
||||
|
|
|
@ -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 kotlinx.coroutines.Dispatchers.IO
|
||||
import kotlinx.coroutines.launch
|
||||
import java.io.File
|
||||
|
||||
class LibraryViewModel(
|
||||
private val repository: RealRepository
|
||||
|
@ -43,7 +44,7 @@ class LibraryViewModel(
|
|||
private val legacyPlaylists = MutableLiveData<List<Playlist>>()
|
||||
private val genres = MutableLiveData<List<Genre>>()
|
||||
private val searchResults = MutableLiveData<List<Any>>()
|
||||
private val fabMargin = MutableLiveData<Int>(0)
|
||||
private val fabMargin = MutableLiveData(0)
|
||||
val paletteColor: LiveData<Int> = _paletteColor
|
||||
|
||||
init {
|
||||
|
@ -227,7 +228,7 @@ class LibraryViewModel(
|
|||
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 favoritePlaylist() = repository.favoritePlaylist()
|
||||
suspend fun isFavoriteSong(song: SongEntity) = repository.isFavoriteSong(song)
|
||||
|
@ -272,6 +273,16 @@ class LibraryViewModel(
|
|||
}
|
||||
|
||||
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 {
|
||||
it.toSong()
|
||||
})
|
||||
|
@ -303,7 +314,21 @@ class LibraryViewModel(
|
|||
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()
|
||||
|
||||
|
|
|
@ -405,9 +405,8 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
|||
binding.albumCoverContainer,
|
||||
"${getString(R.string.transition_album_art)}_${album.id}"
|
||||
)
|
||||
startActivityForResult(
|
||||
intent,
|
||||
TAG_EDITOR_REQUEST, options.toBundle()
|
||||
startActivity(
|
||||
intent, options.toBundle()
|
||||
)
|
||||
return true
|
||||
}
|
||||
|
@ -499,8 +498,4 @@ class AlbumDetailsFragment : AbsMainActivityFragment(R.layout.fragment_album_det
|
|||
super.onDestroyView()
|
||||
_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.extensions.navigate
|
||||
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.base.AbsRecyclerViewCustomGridSizeFragment
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
|
@ -131,11 +132,13 @@ class AlbumsFragment : AbsRecyclerViewCustomGridSizeFragment<AlbumAdapter, GridL
|
|||
}
|
||||
|
||||
override fun loadLayoutRes(): Int {
|
||||
return PreferenceUtil.albumGridStyle
|
||||
return PreferenceUtil.albumGridStyle.layoutResId
|
||||
}
|
||||
|
||||
override fun saveLayoutRes(layoutRes: Int) {
|
||||
PreferenceUtil.albumGridStyle = layoutRes
|
||||
PreferenceUtil.albumGridStyle = GridStyle.values().first { gridStyle ->
|
||||
gridStyle.layoutResId == layoutRes
|
||||
}
|
||||
}
|
||||
|
||||
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_image -> R.layout.image
|
||||
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
|
||||
setAndSaveLayoutRes(layoutRes)
|
||||
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.R
|
||||
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.fragments.GridStyle
|
||||
import code.name.monkey.retromusic.fragments.ReloadType
|
||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
|
@ -132,11 +132,13 @@ class ArtistsFragment : AbsRecyclerViewCustomGridSizeFragment<ArtistAdapter, Gri
|
|||
}
|
||||
|
||||
override fun loadLayoutRes(): Int {
|
||||
return PreferenceUtil.artistGridStyle
|
||||
return PreferenceUtil.artistGridStyle.layoutResId
|
||||
}
|
||||
|
||||
override fun saveLayoutRes(layoutRes: Int) {
|
||||
PreferenceUtil.artistGridStyle = layoutRes
|
||||
PreferenceUtil.artistGridStyle = GridStyle.values().first { gridStyle ->
|
||||
gridStyle.layoutResId == layoutRes
|
||||
}
|
||||
}
|
||||
|
||||
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_image -> R.layout.image
|
||||
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
|
||||
setAndSaveLayoutRes(layoutRes)
|
||||
return true
|
||||
|
|
|
@ -48,7 +48,9 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
|
|||
backupViewModel.loadBackups()
|
||||
val openFilePicker = registerForActivityResult(ActivityResultContracts.OpenDocument()) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
backupViewModel.restoreBackup(requireActivity(), requireContext().contentResolver.openInputStream(it))
|
||||
it?.let {
|
||||
backupViewModel.restoreBackup(requireActivity(), requireContext().contentResolver.openInputStream(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
binding.createBackup.setOnClickListener {
|
||||
|
@ -70,7 +72,7 @@ class BackupFragment : Fragment(R.layout.fragment_backup), BackupAdapter.BackupC
|
|||
}
|
||||
|
||||
private fun checkIsEmpty() {
|
||||
val isEmpty = backupAdapter!!.itemCount == 0
|
||||
val isEmpty = backupAdapter?.itemCount == 0
|
||||
binding.backupTitle.isVisible = !isEmpty
|
||||
binding.backupRecyclerview.isVisible = !isEmpty
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@ import androidx.appcompat.widget.Toolbar
|
|||
import androidx.core.os.bundleOf
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.navigation.findNavController
|
||||
import androidx.navigation.navOptions
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import code.name.monkey.retromusic.EXTRA_ALBUM_ID
|
||||
import code.name.monkey.retromusic.EXTRA_ARTIST_ID
|
||||
|
@ -151,7 +152,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
|||
return true
|
||||
}
|
||||
R.id.action_show_lyrics -> {
|
||||
NavigationUtil.goToLyrics(requireActivity())
|
||||
goToLyrics(requireActivity())
|
||||
return true
|
||||
}
|
||||
R.id.action_equalizer -> {
|
||||
|
@ -193,7 +194,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
|||
private fun showLyricsIcon(item: MenuItem) {
|
||||
val icon =
|
||||
if (PreferenceUtil.showLyrics) R.drawable.ic_lyrics else R.drawable.ic_lyrics_outline
|
||||
val drawable: Drawable? = RetroUtil.getTintedVectorDrawable(
|
||||
val drawable: Drawable = RetroUtil.getTintedVectorDrawable(
|
||||
requireContext(),
|
||||
icon,
|
||||
toolbarIconColor()
|
||||
|
@ -255,7 +256,7 @@ abstract class AbsPlayerFragment(@LayoutRes layout: Int) : AbsMainActivityFragme
|
|||
} else {
|
||||
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
|
||||
}
|
||||
val drawable: Drawable? = RetroUtil.getTintedVectorDrawable(
|
||||
val drawable: Drawable = RetroUtil.getTintedVectorDrawable(
|
||||
requireContext(),
|
||||
icon,
|
||||
toolbarIconColor()
|
||||
|
@ -394,7 +395,11 @@ fun goToArtist(activity: Activity) {
|
|||
|
||||
findNavController(R.id.fragment_container).navigate(
|
||||
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(
|
||||
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.databinding.FragmentFolderBinding
|
||||
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.fragments.base.AbsMainActivityFragment
|
||||
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> :
|
||||
DialogAsyncTask<Params, Progress, Result> {
|
||||
internal constructor(context: Context?) : super(context)
|
||||
abstract class ListingFilesDialogAsyncTask<Params, Progress, Result> internal constructor(
|
||||
context: Context?
|
||||
) :
|
||||
DialogAsyncTask<Params, Progress, Result>(context) {
|
||||
|
||||
override fun createDialog(context: Context): Dialog {
|
||||
return MaterialAlertDialogBuilder(context)
|
||||
|
|
|
@ -162,30 +162,26 @@ open class MiniPlayerFragment : AbsMusicServiceFragment(R.layout.fragment_mini_p
|
|||
|
||||
class FlingPlayBackController(context: Context) : View.OnTouchListener {
|
||||
|
||||
private var flingPlayBackController: GestureDetector
|
||||
|
||||
init {
|
||||
flingPlayBackController = GestureDetector(context,
|
||||
object : GestureDetector.SimpleOnGestureListener() {
|
||||
override fun onFling(
|
||||
e1: MotionEvent,
|
||||
e2: MotionEvent,
|
||||
velocityX: Float,
|
||||
velocityY: Float
|
||||
): Boolean {
|
||||
if (abs(velocityX) > abs(velocityY)) {
|
||||
if (velocityX < 0) {
|
||||
MusicPlayerRemote.playNextSong()
|
||||
return true
|
||||
} else if (velocityX > 0) {
|
||||
MusicPlayerRemote.playPreviousSong()
|
||||
return true
|
||||
}
|
||||
private var flingPlayBackController = GestureDetector(context,
|
||||
object : GestureDetector.SimpleOnGestureListener() {
|
||||
override fun onFling(
|
||||
e1: MotionEvent,
|
||||
e2: MotionEvent,
|
||||
velocityX: Float,
|
||||
velocityY: Float
|
||||
): Boolean {
|
||||
if (abs(velocityX) > abs(velocityY)) {
|
||||
if (velocityX < 0) {
|
||||
MusicPlayerRemote.playNextSong()
|
||||
return true
|
||||
} else if (velocityX > 0) {
|
||||
MusicPlayerRemote.playPreviousSong()
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
})
|
||||
}
|
||||
return false
|
||||
}
|
||||
})
|
||||
|
||||
@SuppressLint("ClickableViewAccessibility")
|
||||
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.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
|
||||
class UserInfoFragment : Fragment() {
|
||||
|
||||
|
@ -218,13 +217,13 @@ class UserInfoFragment : Fragment() {
|
|||
val appDir = requireContext().filesDir
|
||||
val file = File(appDir, fileName)
|
||||
var successful = false
|
||||
try {
|
||||
kotlin.runCatching {
|
||||
val os = BufferedOutputStream(FileOutputStream(file))
|
||||
successful = ImageUtil.resizeBitmap(bitmap, 2048)
|
||||
.compress(Bitmap.CompressFormat.WEBP, 100, os)
|
||||
withContext(Dispatchers.IO) { os.close() }
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}.onFailure {
|
||||
it.printStackTrace()
|
||||
}
|
||||
if (successful) {
|
||||
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.base.AbsMusicServiceFragment
|
||||
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.MusicProgressViewUpdateHelper
|
||||
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.ParallaxPagerTransformer
|
||||
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.color.MediaNotificationProcessor
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
|
@ -214,7 +214,7 @@ class PlayerAlbumCoverFragment : AbsMusicServiceFragment(R.layout.fragment_playe
|
|||
}
|
||||
// Go to lyrics activity when clicked lyrics
|
||||
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 var audioVolumeObserver: AudioVolumeObserver? = null
|
||||
|
||||
private val audioManager: AudioManager?
|
||||
private val audioManager: AudioManager
|
||||
get() = requireContext().getSystemService(Context.AUDIO_SERVICE) as AudioManager
|
||||
|
||||
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) {
|
||||
val audioManager = audioManager
|
||||
audioManager?.setStreamVolume(AudioManager.STREAM_MUSIC, progress, 0)
|
||||
audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, progress, 0)
|
||||
}
|
||||
|
||||
override fun onStartTrackingTouch(seekArc: SeekArc?) {
|
||||
|
|
|
@ -247,7 +247,7 @@ class ClassicPlayerFragment : AbsPlayerFragment(R.layout.fragment_classic_player
|
|||
updateQueue()
|
||||
}
|
||||
|
||||
override fun playerToolbar(): Toolbar? {
|
||||
override fun playerToolbar(): Toolbar {
|
||||
return binding.playerToolbar
|
||||
}
|
||||
|
||||
|
|
|
@ -316,7 +316,7 @@ class FullPlaybackControlsFragment :
|
|||
|
||||
fun updateIsFavorite(animate: Boolean = false) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist()
|
||||
val playlist: PlaylistEntity = libraryViewModel.favoritePlaylist()
|
||||
if (playlist != null) {
|
||||
val song: SongEntity =
|
||||
MusicPlayerRemote.currentSong.toSongEntity(playlist.playListId)
|
||||
|
@ -327,7 +327,7 @@ class FullPlaybackControlsFragment :
|
|||
} else {
|
||||
if (isFavorite) R.drawable.ic_favorite else R.drawable.ic_favorite_border
|
||||
}
|
||||
val drawable: Drawable? = RetroUtil.getTintedVectorDrawable(
|
||||
val drawable: Drawable = RetroUtil.getTintedVectorDrawable(
|
||||
requireContext(),
|
||||
icon,
|
||||
Color.WHITE
|
||||
|
@ -347,7 +347,7 @@ class FullPlaybackControlsFragment :
|
|||
|
||||
private fun toggleFavorite(song: Song) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist()
|
||||
val playlist: PlaylistEntity = libraryViewModel.favoritePlaylist()
|
||||
if (playlist != null) {
|
||||
val songEntity = song.toSongEntity(playlist.playListId)
|
||||
val isFavorite = libraryViewModel.isFavoriteSong(songEntity).isNotEmpty()
|
||||
|
|
|
@ -281,7 +281,7 @@ class GradientPlayerFragment : AbsPlayerFragment(R.layout.fragment_gradient_play
|
|||
|
||||
private fun updateIsFavoriteIcon(animate: Boolean = false) {
|
||||
lifecycleScope.launch(Dispatchers.IO) {
|
||||
val playlist: PlaylistEntity? = libraryViewModel.favoritePlaylist()
|
||||
val playlist: PlaylistEntity = libraryViewModel.favoritePlaylist()
|
||||
if (playlist != null) {
|
||||
val song: SongEntity =
|
||||
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.adapter.playlist.PlaylistAdapter
|
||||
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.base.AbsRecyclerViewCustomGridSizeFragment
|
||||
import code.name.monkey.retromusic.helper.SortOrder.PlaylistSortOrder
|
||||
import code.name.monkey.retromusic.interfaces.IPlaylistClickListener
|
||||
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.material.transition.MaterialSharedAxis
|
||||
|
||||
|
@ -42,7 +42,7 @@ class PlaylistsFragment :
|
|||
super.onViewCreated(view, savedInstanceState)
|
||||
libraryViewModel.getPlaylists().observe(viewLifecycleOwner, {
|
||||
if (it.isNotEmpty())
|
||||
adapter?.swapDataSet(it)
|
||||
adapter?.swapDataSet(it.filter { playlistWithSongs-> playlistWithSongs.songs.isNotEmpty() })
|
||||
else
|
||||
adapter?.swapDataSet(listOf())
|
||||
})
|
||||
|
@ -66,9 +66,10 @@ class PlaylistsFragment :
|
|||
}
|
||||
|
||||
override fun createAdapter(): PlaylistAdapter {
|
||||
val dataSet = if (adapter == null) mutableListOf() else adapter!!.dataSet
|
||||
return PlaylistAdapter(
|
||||
requireActivity(),
|
||||
ArrayList(),
|
||||
dataSet,
|
||||
itemLayoutRes(),
|
||||
null,
|
||||
this
|
||||
|
@ -77,7 +78,11 @@ class PlaylistsFragment :
|
|||
|
||||
override fun onCreateOptionsMenu(menu: Menu, inflater: MenuInflater) {
|
||||
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.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)
|
||||
|
@ -89,12 +94,46 @@ class PlaylistsFragment :
|
|||
}
|
||||
|
||||
override fun onOptionsItemSelected(item: MenuItem): Boolean {
|
||||
if (handleGridSizeMenuItem(item)) {
|
||||
return true
|
||||
}
|
||||
if (handleSortOrderMenuItem(item)) {
|
||||
return true
|
||||
}
|
||||
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) {
|
||||
val order: String? = getSortOrder()
|
||||
|
@ -142,13 +181,32 @@ class PlaylistsFragment :
|
|||
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) {
|
||||
menu.add(0, id, 0, title).isChecked = checked
|
||||
}
|
||||
|
||||
|
||||
override fun setGridSize(gridSize: Int) {
|
||||
TODO("Not yet implemented")
|
||||
adapter?.notifyDataSetChanged()
|
||||
}
|
||||
|
||||
override fun setSortOrder(sortOrder: String) {
|
||||
|
@ -164,23 +222,23 @@ class PlaylistsFragment :
|
|||
}
|
||||
|
||||
override fun loadGridSize(): Int {
|
||||
return 2
|
||||
return PreferenceUtil.playlistGridSize
|
||||
}
|
||||
|
||||
override fun saveGridSize(gridColumns: Int) {
|
||||
//Add grid save
|
||||
PreferenceUtil.playlistGridSize = gridColumns
|
||||
}
|
||||
|
||||
override fun loadGridSizeLand(): Int {
|
||||
return 4
|
||||
return PreferenceUtil.playlistGridSizeLand
|
||||
}
|
||||
|
||||
override fun saveGridSizeLand(gridColumns: Int) {
|
||||
//Add land grid save
|
||||
PreferenceUtil.playlistGridSizeLand = gridColumns
|
||||
}
|
||||
|
||||
override fun loadLayoutRes(): Int {
|
||||
return R.layout.item_card
|
||||
return R.layout.item_grid
|
||||
}
|
||||
|
||||
override fun saveLayoutRes(layoutRes: Int) {
|
||||
|
|
|
@ -21,8 +21,8 @@ import androidx.annotation.LayoutRes
|
|||
import androidx.recyclerview.widget.GridLayoutManager
|
||||
import code.name.monkey.retromusic.R
|
||||
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.fragments.GridStyle
|
||||
import code.name.monkey.retromusic.fragments.ReloadType
|
||||
import code.name.monkey.retromusic.fragments.base.AbsRecyclerViewCustomGridSizeFragment
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote
|
||||
|
@ -114,11 +114,13 @@ class SongsFragment : AbsRecyclerViewCustomGridSizeFragment<SongAdapter, GridLay
|
|||
|
||||
@LayoutRes
|
||||
override fun loadLayoutRes(): Int {
|
||||
return PreferenceUtil.songGridStyle
|
||||
return PreferenceUtil.songGridStyle.layoutResId
|
||||
}
|
||||
|
||||
override fun saveLayoutRes(@LayoutRes layoutRes: Int) {
|
||||
PreferenceUtil.songGridStyle = layoutRes
|
||||
PreferenceUtil.songGridStyle = GridStyle.values().first { gridStyle ->
|
||||
gridStyle.layoutResId == layoutRes
|
||||
}
|
||||
}
|
||||
|
||||
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_image -> R.layout.image
|
||||
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
|
||||
setAndSaveLayoutRes(layoutRes)
|
||||
return true
|
||||
|
|
|
@ -17,9 +17,7 @@ class PlaylistPreviewFetcher(val context: Context, private val playlistPreview:
|
|||
val bitmap =
|
||||
AutoGeneratedPlaylistBitmap.getBitmap(
|
||||
context,
|
||||
playlistPreview.songs.shuffled(),
|
||||
true,
|
||||
false
|
||||
playlistPreview.songs.shuffled()
|
||||
)
|
||||
callback.onDataReady(bitmap)
|
||||
} catch (e: Exception) {
|
||||
|
|
|
@ -23,28 +23,33 @@ object BackupHelper {
|
|||
zipItems.addAll(getDatabaseZipItems(context))
|
||||
zipItems.addAll(getSettingsZipItems(context))
|
||||
getUserImageZipItems(context)?.let { zipItems.addAll(it) }
|
||||
withContext(Dispatchers.IO) {
|
||||
zipAll(zipItems, backupFile)
|
||||
}
|
||||
zipItems.addAll(getCustomArtistZipItems(context))
|
||||
zipAll(zipItems, backupFile)
|
||||
}
|
||||
|
||||
private suspend fun zipAll(zipItems: List<ZipItem>, backupFile: File) {
|
||||
try {
|
||||
ZipOutputStream(BufferedOutputStream(FileOutputStream(backupFile))).use { out ->
|
||||
for (zipItem in zipItems) {
|
||||
FileInputStream(zipItem.filePath).use { fi ->
|
||||
BufferedInputStream(fi).use { origin ->
|
||||
val entry = ZipEntry(zipItem.zipPath)
|
||||
out.putNextEntry(entry)
|
||||
origin.copyTo(out)
|
||||
withContext(Dispatchers.IO) {
|
||||
kotlin.runCatching {
|
||||
ZipOutputStream(BufferedOutputStream(FileOutputStream(backupFile))).use { out ->
|
||||
for (zipItem in zipItems) {
|
||||
FileInputStream(zipItem.filePath).use { fi ->
|
||||
BufferedInputStream(fi).use { origin ->
|
||||
val entry = ZipEntry(zipItem.zipPath)
|
||||
out.putNextEntry(entry)
|
||||
origin.copyTo(out)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}.onFailure {
|
||||
it.printStackTrace()
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(App.getContext(), "Couldn't create backup", Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
} catch (exception: FileNotFoundException) {
|
||||
exception.printStackTrace()
|
||||
withContext(Dispatchers.Main) {
|
||||
Toast.makeText(App.getContext(), "Couldn't create backup", Toast.LENGTH_SHORT)
|
||||
Toast.makeText(App.getContext(), "Backup created successfully", Toast.LENGTH_SHORT)
|
||||
.show()
|
||||
}
|
||||
}
|
||||
|
@ -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?) {
|
||||
withContext(Dispatchers.IO) {
|
||||
ZipInputStream(inputStream).use {
|
||||
|
@ -84,6 +111,16 @@ object BackupHelper {
|
|||
if (entry.isDatabaseEntry()) restoreDatabase(context, it, entry)
|
||||
if (entry.isPreferenceEntry()) restorePreferences(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
|
||||
}
|
||||
}
|
||||
|
@ -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 =
|
||||
Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOCUMENTS)
|
||||
.toString() + "/RetroMusic/Backups/"
|
||||
|
@ -141,6 +220,7 @@ object BackupHelper {
|
|||
private const val DATABASES_PATH = "databases"
|
||||
private const val SETTINGS_PATH = "prefs"
|
||||
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 fun ZipEntry.isDatabaseEntry(): Boolean {
|
||||
|
@ -155,6 +235,14 @@ object BackupHelper {
|
|||
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 {
|
||||
return name.substring(name.lastIndexOf(File.separator))
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ object M3UWriter : M3UConstants {
|
|||
fun write(
|
||||
dir: File,
|
||||
playlist: Playlist
|
||||
): File? {
|
||||
): File {
|
||||
if (!dir.exists()) dir.mkdirs()
|
||||
val file = File(dir, playlist.name + "." + M3UConstants.EXTENSION)
|
||||
val songs = playlist.getSongs()
|
||||
|
|
|
@ -16,6 +16,7 @@ package code.name.monkey.retromusic.helper
|
|||
|
||||
import android.os.Handler
|
||||
import android.os.Message
|
||||
import kotlin.math.max
|
||||
|
||||
class MusicProgressViewUpdateHelper : Handler {
|
||||
|
||||
|
@ -62,7 +63,7 @@ class MusicProgressViewUpdateHelper : Handler {
|
|||
|
||||
val remainingMillis = intervalPlaying - progressMillis % intervalPlaying
|
||||
|
||||
return Math.max(MIN_INTERVAL, remainingMillis)
|
||||
return max(MIN_INTERVAL, remainingMillis)
|
||||
}
|
||||
|
||||
private fun queueNextRefresh(delay: Long) {
|
||||
|
|
|
@ -134,7 +134,7 @@ class SortOrder {
|
|||
companion object {
|
||||
|
||||
/* 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 */
|
||||
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);
|
||||
int cores = EXECUTOR_THREADS;
|
||||
|
||||
ArrayList<BlurTask> horizontal = new ArrayList<BlurTask>(cores);
|
||||
ArrayList<BlurTask> vertical = new ArrayList<BlurTask>(cores);
|
||||
ArrayList<BlurTask> horizontal = new ArrayList<>(cores);
|
||||
ArrayList<BlurTask> vertical = new ArrayList<>(cores);
|
||||
for (int i = 0; i < cores; i++) {
|
||||
horizontal.add(new BlurTask(currentPixels, w, h, (int) radius, cores, i, 1));
|
||||
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++) {
|
||||
src[dst_i] =
|
||||
(int)
|
||||
((src[dst_i] & 0xFFFFFFFF)
|
||||
((src[dst_i])
|
||||
| ((((sum_r * mul_sum) >>> shr_sum) & 0xff) << 16)
|
||||
| ((((sum_g * mul_sum) >>> shr_sum) & 0xff) << 8)
|
||||
| ((((sum_b * mul_sum) >>> shr_sum) & 0xff)));
|
||||
|
@ -245,7 +245,7 @@ public class StackBlur {
|
|||
for (y = 0; y < h; y++) {
|
||||
src[dst_i] =
|
||||
(int)
|
||||
((src[dst_i] & 0xFFFFFFFF)
|
||||
((src[dst_i])
|
||||
| ((((sum_r * mul_sum) >>> shr_sum) & 0xff) << 16)
|
||||
| ((((sum_g * mul_sum) >>> shr_sum) & 0xff) << 8)
|
||||
| ((((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 FragmentTransaction mCurTransaction = null;
|
||||
|
||||
private final ArrayList<Fragment.SavedState> mSavedState = new ArrayList<Fragment.SavedState>();
|
||||
private final ArrayList<Fragment> mFragments = new ArrayList<Fragment>();
|
||||
private final ArrayList<Fragment.SavedState> mSavedState = new ArrayList<>();
|
||||
private final ArrayList<Fragment> mFragments = new ArrayList<>();
|
||||
private Fragment mCurrentPrimaryItem = null;
|
||||
|
||||
public CustomFragmentStatePagerAdapter(FragmentManager fm) {
|
||||
|
@ -92,11 +92,11 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
|
|||
public abstract Fragment getItem(int position);
|
||||
|
||||
@Override
|
||||
public void startUpdate(ViewGroup container) {}
|
||||
public void startUpdate(@NonNull ViewGroup container) {}
|
||||
|
||||
@NonNull
|
||||
@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
|
||||
// to do. This can happen when we are restoring the entire pager
|
||||
// from its saved state, where the fragment manager has already
|
||||
|
@ -132,7 +132,7 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
|
|||
}
|
||||
|
||||
@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;
|
||||
|
||||
if (mCurTransaction == null) {
|
||||
|
@ -152,23 +152,21 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
|
|||
}
|
||||
|
||||
@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;
|
||||
if (fragment != mCurrentPrimaryItem) {
|
||||
if (mCurrentPrimaryItem != null) {
|
||||
mCurrentPrimaryItem.setMenuVisibility(false);
|
||||
mCurrentPrimaryItem.setUserVisibleHint(false);
|
||||
}
|
||||
if (fragment != null) {
|
||||
fragment.setMenuVisibility(true);
|
||||
fragment.setUserVisibleHint(true);
|
||||
}
|
||||
fragment.setMenuVisibility(true);
|
||||
fragment.setUserVisibleHint(true);
|
||||
mCurrentPrimaryItem = fragment;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finishUpdate(ViewGroup container) {
|
||||
public void finishUpdate(@NonNull ViewGroup container) {
|
||||
if (mCurTransaction != null) {
|
||||
mCurTransaction.commitAllowingStateLoss();
|
||||
mCurTransaction = null;
|
||||
|
@ -177,7 +175,7 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
|
|||
}
|
||||
|
||||
@Override
|
||||
public boolean isViewFromObject(View view, Object object) {
|
||||
public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
|
||||
return ((Fragment) object).getView() == view;
|
||||
}
|
||||
|
||||
|
@ -212,8 +210,8 @@ public abstract class CustomFragmentStatePagerAdapter extends PagerAdapter {
|
|||
mSavedState.clear();
|
||||
mFragments.clear();
|
||||
if (fss != null) {
|
||||
for (int i = 0; i < fss.length; i++) {
|
||||
mSavedState.add((Fragment.SavedState) fss[i]);
|
||||
for (Parcelable parcelable : fss) {
|
||||
mSavedState.add((Fragment.SavedState) parcelable);
|
||||
}
|
||||
}
|
||||
Iterable<String> keys = bundle.keySet();
|
||||
|
|
|
@ -40,8 +40,6 @@ abstract class WrappedAsyncTaskLoader<D>
|
|||
if (!isReset) {
|
||||
this.mData = 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
|
||||
}
|
||||
|
||||
override fun getPageTitle(position: Int): CharSequence? {
|
||||
override fun getPageTitle(position: Int): CharSequence {
|
||||
return context.getString(values()[position].titleRes)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ import android.app.Dialog
|
|||
import android.content.Context
|
||||
import android.os.Bundle
|
||||
import android.util.AttributeSet
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.core.graphics.BlendModeColorFilterCompat
|
||||
import androidx.core.graphics.BlendModeCompat.SRC_IN
|
||||
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.R
|
||||
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.colorControlNormal
|
||||
import code.name.monkey.retromusic.extensions.materialDialog
|
||||
|
@ -69,11 +71,7 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
|
|||
.setNeutralButton(R.string.clear_action) { _, _ ->
|
||||
materialDialog(R.string.clear_blacklist)
|
||||
.setMessage(R.string.do_you_want_to_clear_the_blacklist)
|
||||
.setPositiveButton(R.string.clear_action) { _, _ ->
|
||||
BlacklistStore.getInstance(
|
||||
requireContext()
|
||||
).clear()
|
||||
}
|
||||
.setPositiveButton(R.string.clear_action, null)
|
||||
.setNegativeButton(android.R.string.cancel, null)
|
||||
.create()
|
||||
.colorButtons()
|
||||
|
@ -107,7 +105,21 @@ class BlacklistPreferenceDialog : DialogFragment(), BlacklistFolderChooserDialog
|
|||
.colorButtons()
|
||||
.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>
|
||||
|
|
|
@ -153,7 +153,7 @@ private class NowPlayingScreenAdapter(private val context: Context) : PagerAdapt
|
|||
return view === instance
|
||||
}
|
||||
|
||||
override fun getPageTitle(position: Int): CharSequence? {
|
||||
override fun getPageTitle(position: Int): CharSequence {
|
||||
return context.getString(values()[position].titleRes)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -84,30 +84,23 @@ public class HistoryStore extends SQLiteOpenHelper {
|
|||
database.insert(RecentStoreColumns.NAME, null, values);
|
||||
|
||||
// if our db is too large, delete the extra items
|
||||
Cursor oldest = null;
|
||||
try {
|
||||
oldest =
|
||||
database.query(
|
||||
RecentStoreColumns.NAME,
|
||||
new String[] {RecentStoreColumns.TIME_PLAYED},
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
RecentStoreColumns.TIME_PLAYED + " ASC");
|
||||
try (Cursor oldest = database.query(
|
||||
RecentStoreColumns.NAME,
|
||||
new String[]{RecentStoreColumns.TIME_PLAYED},
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
null,
|
||||
RecentStoreColumns.TIME_PLAYED + " ASC")) {
|
||||
|
||||
if (oldest != null && oldest.getCount() > MAX_ITEMS_IN_DB) {
|
||||
oldest.moveToPosition(oldest.getCount() - MAX_ITEMS_IN_DB);
|
||||
long timeOfRecordToKeep = oldest.getLong(0);
|
||||
|
||||
database.delete(
|
||||
RecentStoreColumns.NAME,
|
||||
RecentStoreColumns.TIME_PLAYED + " < ?",
|
||||
new String[] {String.valueOf(timeOfRecordToKeep)});
|
||||
}
|
||||
} finally {
|
||||
if (oldest != null) {
|
||||
oldest.close();
|
||||
RecentStoreColumns.NAME,
|
||||
RecentStoreColumns.TIME_PLAYED + " < ?",
|
||||
new String[]{String.valueOf(timeOfRecordToKeep)});
|
||||
}
|
||||
}
|
||||
} finally {
|
||||
|
|
|
@ -40,14 +40,11 @@ public class SongPlayCountStore extends SQLiteOpenHelper {
|
|||
@NonNull
|
||||
private static final Interpolator sInterpolator = new AccelerateInterpolator(1.5f);
|
||||
// how high to multiply the interpolation curve
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
private static final int INTERPOLATOR_HEIGHT = 50;
|
||||
|
||||
// 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;
|
||||
|
||||
@SuppressWarnings("FieldCanBeLocal")
|
||||
private static final int ONE_WEEK_IN_MS = 1000 * 60 * 60 * 24 * 7;
|
||||
|
||||
@NonNull
|
||||
|
@ -257,7 +254,7 @@ public class SongPlayCountStore extends SQLiteOpenHelper {
|
|||
for (int i = 0; i < NUM_WEEKS - weekDiff; i++) {
|
||||
playCounts[i + weekDiff] = cursor.getInt(getColumnIndexForWeek(i));
|
||||
}
|
||||
} else if (weekDiff < 0) {
|
||||
} else {
|
||||
// time is shifted backwards (by user) - nor typical behavior but we
|
||||
// will still handle it
|
||||
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
package code.name.monkey.retromusic.repository
|
||||
|
||||
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.model.Album
|
||||
import code.name.monkey.retromusic.model.Artist
|
||||
|
@ -110,7 +111,8 @@ class RealArtistRepository(
|
|||
songRepository.makeSongCursor(
|
||||
null,
|
||||
null,
|
||||
getSongLoaderSortOrder()
|
||||
"lower($ALBUM_ARTIST)" +
|
||||
if (PreferenceUtil.artistSortOrder == SortOrder.ArtistSortOrder.ARTIST_A_Z) "" else " DESC"
|
||||
)
|
||||
)
|
||||
return splitIntoAlbumArtists(albumRepository.splitIntoAlbums(songs))
|
||||
|
@ -155,12 +157,6 @@ class RealArtistRepository(
|
|||
} else {
|
||||
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 updateSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
suspend fun deleteSongInHistory(songId: Long)
|
||||
suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity>
|
||||
suspend fun playCountSongs(): List<PlayCountEntity>
|
||||
suspend fun blackListPaths(): List<BlackListStoreEntity>
|
||||
|
@ -323,6 +324,9 @@ class RealRepository(
|
|||
override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) =
|
||||
roomRepository.deleteSongInPlayCount(playCountEntity)
|
||||
|
||||
override suspend fun deleteSongInHistory(songId: Long) =
|
||||
roomRepository.deleteSongInHistory(songId)
|
||||
|
||||
override suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity> =
|
||||
roomRepository.checkSongExistInPlayCount(songId)
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ interface RoomRepository {
|
|||
suspend fun insertSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
suspend fun updateSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity)
|
||||
suspend fun deleteSongInHistory(songId: Long)
|
||||
suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity>
|
||||
suspend fun playCountSongs(): List<PlayCountEntity>
|
||||
suspend fun insertBlacklistPath(blackListStoreEntities: List<BlackListStoreEntity>)
|
||||
|
@ -161,6 +162,10 @@ class RealRoomRepository(
|
|||
override suspend fun deleteSongInPlayCount(playCountEntity: PlayCountEntity) =
|
||||
playCountDao.deleteSongInPlayCount(playCountEntity)
|
||||
|
||||
override suspend fun deleteSongInHistory(songId: Long) {
|
||||
historyDao.deleteSongInHistory(songId)
|
||||
}
|
||||
|
||||
override suspend fun checkSongExistInPlayCount(songId: Long): List<PlayCountEntity> =
|
||||
playCountDao.checkSongExistInPlayCount(songId)
|
||||
|
||||
|
|
|
@ -75,7 +75,7 @@ class RealTopPlayedRepository(
|
|||
val notRecentlyPlayedSongs = songRepository.songs(
|
||||
makeNotRecentTracksCursorAndClearUpDatabase()
|
||||
)
|
||||
allSongs.removeAll(playedSongs)
|
||||
allSongs.removeAll(playedSongs.toSet())
|
||||
allSongs.addAll(notRecentlyPlayedSongs)
|
||||
return allSongs
|
||||
}
|
||||
|
|
|
@ -75,6 +75,7 @@ import java.util.List;
|
|||
import java.util.Objects;
|
||||
import java.util.Random;
|
||||
|
||||
import code.name.monkey.appthemehelper.util.VersionUtils;
|
||||
import code.name.monkey.retromusic.R;
|
||||
import code.name.monkey.retromusic.activities.LockScreenActivity;
|
||||
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> playingQueue = new ArrayList<>();
|
||||
private boolean pausedByTransientLossOfFocus;
|
||||
private AudioVolumeObserver audioVolumeObserver = null;
|
||||
|
||||
private final BroadcastReceiver becomingNoisyReceiver =
|
||||
new BroadcastReceiver() {
|
||||
|
@ -453,7 +453,7 @@ public class MusicService extends MediaBrowserServiceCompat
|
|||
.registerContentObserver(
|
||||
MediaStore.Audio.Playlists.INTERNAL_CONTENT_URI, true, mediaStoreObserver);
|
||||
|
||||
audioVolumeObserver = new AudioVolumeObserver(this);
|
||||
AudioVolumeObserver audioVolumeObserver = new AudioVolumeObserver(this);
|
||||
audioVolumeObserver.register(AudioManager.STREAM_MUSIC, this);
|
||||
|
||||
PreferenceUtil.INSTANCE.registerOnSharedPreferenceChangedListener(this);
|
||||
|
@ -837,8 +837,7 @@ public class MusicService extends MediaBrowserServiceCompat
|
|||
// Request from an untrusted package: return an empty browser root
|
||||
return new BrowserRoot(AutoMediaIDHelper.MEDIA_ID_EMPTY_ROOT, null);
|
||||
} 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.
|
||||
*/
|
||||
boolean isRecentRequest = false;
|
||||
|
@ -1157,7 +1156,7 @@ public class MusicService extends MediaBrowserServiceCompat
|
|||
playback.setNextDataSource(getTrackUri(Objects.requireNonNull(getSongAt(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())
|
||||
.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()) {
|
||||
final Point screenSize = RetroUtil.getScreenSize(MusicService.this);
|
||||
|
@ -1595,11 +1592,8 @@ public class MusicService extends MediaBrowserServiceCompat
|
|||
mediaButtonIntent.setComponent(mediaButtonReceiverComponentName);
|
||||
|
||||
PendingIntent mediaButtonReceiverPendingIntent;
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.S) {
|
||||
mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, PendingIntent.FLAG_MUTABLE);
|
||||
} else {
|
||||
mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent, 0);
|
||||
}
|
||||
mediaButtonReceiverPendingIntent = PendingIntent.getBroadcast(getApplicationContext(), 0, mediaButtonIntent,
|
||||
VersionUtils.INSTANCE.hasMarshmallow() ? PendingIntent.FLAG_IMMUTABLE : 0);
|
||||
|
||||
mediaSession = new MediaSessionCompat(
|
||||
this,
|
||||
|
@ -1608,9 +1602,6 @@ public class MusicService extends MediaBrowserServiceCompat
|
|||
mediaButtonReceiverPendingIntent);
|
||||
MediaSessionCallback mediasessionCallback =
|
||||
new MediaSessionCallback(getApplicationContext(), this);
|
||||
mediaSession.setFlags(
|
||||
MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS
|
||||
| MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS);
|
||||
mediaSession.setCallback(mediasessionCallback);
|
||||
mediaSession.setActive(true);
|
||||
mediaSession.setMediaButtonReceiver(mediaButtonReceiverPendingIntent);
|
||||
|
|
|
@ -38,6 +38,6 @@ class ThrottledSeekHandler(
|
|||
|
||||
companion object {
|
||||
// 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.NotificationManager
|
||||
import android.content.Context.NOTIFICATION_SERVICE
|
||||
import android.content.pm.ServiceInfo
|
||||
import android.os.Build
|
||||
import androidx.annotation.RequiresApi
|
||||
import code.name.monkey.retromusic.R
|
||||
|
@ -62,7 +63,15 @@ abstract class PlayingNotification {
|
|||
}
|
||||
|
||||
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) {
|
||||
notificationManager!!.notify(NOTIFICATION_ID, notification)
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import android.os.Build
|
|||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.text.HtmlCompat
|
||||
import androidx.media.app.NotificationCompat.MediaStyle
|
||||
import code.name.monkey.appthemehelper.util.VersionUtils
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.activities.MainActivity
|
||||
import code.name.monkey.retromusic.db.PlaylistEntity
|
||||
|
@ -53,7 +54,7 @@ class PlayingNotificationImpl : PlayingNotification(), KoinComponent {
|
|||
stopped = false
|
||||
GlobalScope.launch {
|
||||
val song = service.currentSong
|
||||
val playlist: PlaylistEntity? = MusicUtil.repository.favoritePlaylist()
|
||||
val playlist: PlaylistEntity = MusicUtil.repository.favoritePlaylist()
|
||||
val isPlaying = service.isPlaying
|
||||
val isFavorite = if (playlist != null) {
|
||||
val songEntity = song.toSongEntity(playlist.playListId)
|
||||
|
@ -69,11 +70,11 @@ class PlayingNotificationImpl : PlayingNotification(), KoinComponent {
|
|||
action.putExtra(MainActivity.EXPAND_PANEL, PreferenceUtil.isExpandPanel)
|
||||
action.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TOP
|
||||
val clickIntent =
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
PendingIntent.getActivity(service, 0, action, PendingIntent.FLAG_IMMUTABLE)
|
||||
} else {
|
||||
PendingIntent.getActivity(service, 0, action, PendingIntent.FLAG_UPDATE_CURRENT)
|
||||
}
|
||||
PendingIntent.getActivity(
|
||||
service, 0, action, if (VersionUtils.hasMarshmallow())
|
||||
PendingIntent.FLAG_IMMUTABLE
|
||||
else 0 or PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
|
||||
val serviceName = ComponentName(service, MusicService::class.java)
|
||||
val intent = Intent(ACTION_QUIT)
|
||||
|
@ -82,7 +83,9 @@ class PlayingNotificationImpl : PlayingNotification(), KoinComponent {
|
|||
service,
|
||||
0,
|
||||
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
|
||||
.getDimensionPixelSize(R.dimen.notification_big_image_size)
|
||||
|
@ -171,18 +174,16 @@ class PlayingNotificationImpl : PlayingNotification(), KoinComponent {
|
|||
.addAction(playPauseAction)
|
||||
.addAction(nextAction)
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||
builder.setStyle(
|
||||
MediaStyle()
|
||||
.setMediaSession(service.mediaSession.sessionToken)
|
||||
.setShowActionsInCompactView(1, 2, 3)
|
||||
)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
if (Build.VERSION.SDK_INT <=
|
||||
Build.VERSION_CODES.O && PreferenceUtil.isColoredNotification
|
||||
) {
|
||||
builder.color = color
|
||||
}
|
||||
builder.setStyle(
|
||||
MediaStyle()
|
||||
.setMediaSession(service.mediaSession.sessionToken)
|
||||
.setShowActionsInCompactView(1, 2, 3)
|
||||
)
|
||||
.setVisibility(NotificationCompat.VISIBILITY_PUBLIC)
|
||||
if (Build.VERSION.SDK_INT <=
|
||||
Build.VERSION_CODES.O && PreferenceUtil.isColoredNotification
|
||||
) {
|
||||
builder.color = color
|
||||
}
|
||||
|
||||
if (stopped) {
|
||||
|
@ -199,6 +200,10 @@ class PlayingNotificationImpl : PlayingNotification(), KoinComponent {
|
|||
val serviceName = ComponentName(service, MusicService::class.java)
|
||||
val intent = Intent(action)
|
||||
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,
|
||||
0,
|
||||
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)
|
||||
|
||||
|
@ -181,21 +183,21 @@ class PlayingNotificationOreo : PlayingNotification() {
|
|||
service,
|
||||
R.drawable.ic_close,
|
||||
primary
|
||||
)!!, NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
||||
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
||||
)
|
||||
val prev = createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(
|
||||
service,
|
||||
R.drawable.ic_skip_previous_round_white_32dp,
|
||||
primary
|
||||
)!!, NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
||||
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
||||
)
|
||||
val next = createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(
|
||||
service,
|
||||
R.drawable.ic_skip_next_round_white_32dp,
|
||||
primary
|
||||
)!!, NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
||||
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
||||
)
|
||||
val playPause = createBitmap(
|
||||
RetroUtil.getTintedVectorDrawable(
|
||||
|
@ -204,7 +206,7 @@ class PlayingNotificationOreo : PlayingNotification() {
|
|||
R.drawable.ic_pause_white_48dp
|
||||
else
|
||||
R.drawable.ic_play_arrow_white_48dp, primary
|
||||
)!!, NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
||||
), NOTIFICATION_CONTROLS_SIZE_MULTIPLIER
|
||||
)
|
||||
|
||||
notificationLayout.setTextColor(R.id.title, primary)
|
||||
|
@ -231,7 +233,7 @@ class PlayingNotificationOreo : PlayingNotification() {
|
|||
service,
|
||||
R.drawable.ic_notification,
|
||||
secondary
|
||||
)!!, 0.6f
|
||||
), 0.6f
|
||||
)
|
||||
)
|
||||
notificationLayoutBig.setImageViewBitmap(
|
||||
|
@ -241,7 +243,7 @@ class PlayingNotificationOreo : PlayingNotification() {
|
|||
service,
|
||||
R.drawable.ic_notification,
|
||||
secondary
|
||||
)!!, 0.6f
|
||||
), 0.6f
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -262,7 +264,11 @@ class PlayingNotificationOreo : PlayingNotification() {
|
|||
): PendingIntent {
|
||||
val intent = Intent(action)
|
||||
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 androidx.viewpager.widget.ViewPager
|
||||
import kotlin.math.abs
|
||||
|
||||
class DepthTransformation : ViewPager.PageTransformer {
|
||||
override fun transformPage(page: View, position: Float) {
|
||||
if (position < -1) { // [-Infinity,-1)
|
||||
// This page is way off-screen to the left.
|
||||
page.alpha = 0f
|
||||
} else if (position <= 0) { // [-1,0]
|
||||
page.alpha = 1f
|
||||
page.translationX = 0f
|
||||
page.scaleX = 1f
|
||||
page.scaleY = 1f
|
||||
} else if (position <= 1) { // (0,1]
|
||||
page.translationX = -position * page.width
|
||||
page.alpha = 1 - Math.abs(position)
|
||||
page.scaleX = 1 - Math.abs(position)
|
||||
page.scaleY = 1 - Math.abs(position)
|
||||
} else { // (1,+Infinity]
|
||||
// This page is way off-screen to the right.
|
||||
page.alpha = 0f
|
||||
when {
|
||||
position < -1 -> { // [-Infinity,-1)
|
||||
// This page is way off-screen to the left.
|
||||
page.alpha = 0f
|
||||
}
|
||||
position <= 0 -> { // [-1,0]
|
||||
page.alpha = 1f
|
||||
page.translationX = 0f
|
||||
page.scaleX = 1f
|
||||
page.scaleY = 1f
|
||||
}
|
||||
position <= 1 -> { // (0,1]
|
||||
page.translationX = -position * page.width
|
||||
page.alpha = 1 - abs(position)
|
||||
page.scaleX = 1 - abs(position)
|
||||
page.scaleY = 1 - abs(position)
|
||||
}
|
||||
else -> { // (1,+Infinity]
|
||||
// This page is way off-screen to the right.
|
||||
page.alpha = 0f
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ package code.name.monkey.retromusic.transform
|
|||
|
||||
import android.view.View
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import kotlin.math.abs
|
||||
|
||||
class HorizontalFlipTransformation : ViewPager.PageTransformer {
|
||||
override fun transformPage(page: View, position: Float) {
|
||||
|
@ -30,21 +31,23 @@ class HorizontalFlipTransformation : ViewPager.PageTransformer {
|
|||
}
|
||||
|
||||
|
||||
if (position < -1) { // [-Infinity,-1)
|
||||
// This page is way off-screen to the left.
|
||||
page.alpha = 0f
|
||||
|
||||
} else if (position <= 0) { // [-1,0]
|
||||
page.alpha = 1f
|
||||
page.rotationX = 180 * (1 - Math.abs(position) + 1)
|
||||
|
||||
} else if (position <= 1) { // (0,1]
|
||||
page.alpha = 1f
|
||||
page.rotationX = -180 * (1 - Math.abs(position) + 1)
|
||||
|
||||
} else { // (1,+Infinity]
|
||||
// This page is way off-screen to the right.
|
||||
page.alpha = 0f
|
||||
when {
|
||||
position < -1 -> { // [-Infinity,-1)
|
||||
// This page is way off-screen to the left.
|
||||
page.alpha = 0f
|
||||
}
|
||||
position <= 0 -> { // [-1,0]
|
||||
page.alpha = 1f
|
||||
page.rotationX = 180 * (1 - abs(position) + 1)
|
||||
}
|
||||
position <= 1 -> { // (0,1]
|
||||
page.alpha = 1f
|
||||
page.rotationX = -180 * (1 - abs(position) + 1)
|
||||
}
|
||||
else -> { // (1,+Infinity]
|
||||
// This page is way off-screen to the right.
|
||||
page.alpha = 0f
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,6 +16,8 @@ package code.name.monkey.retromusic.transform
|
|||
|
||||
import android.view.View
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import kotlin.math.abs
|
||||
import kotlin.math.max
|
||||
|
||||
/**
|
||||
* @author Hemanth S (h4h13).
|
||||
|
@ -27,37 +29,41 @@ class NormalPageTransformer : ViewPager.PageTransformer {
|
|||
val pageWidth = view.width
|
||||
val pageHeight = view.height
|
||||
|
||||
if (position < -1) { // [-Infinity,-1)
|
||||
// This page is way off-screen to the left.
|
||||
view.alpha = 1f
|
||||
view.scaleY = 0.7f
|
||||
} else if (position <= 1) { // [-1,1]
|
||||
// Modify the default slide transition to shrink the page as well
|
||||
val scaleFactor = Math.max(MIN_SCALE, 1 - Math.abs(position))
|
||||
val vertMargin = pageHeight * (1 - scaleFactor) / 2
|
||||
val horzMargin = pageWidth * (1 - scaleFactor) / 2
|
||||
if (position < 0) {
|
||||
view.translationX = horzMargin - vertMargin / 2
|
||||
} else {
|
||||
view.translationX = -horzMargin + vertMargin / 2
|
||||
when {
|
||||
position < -1 -> { // [-Infinity,-1)
|
||||
// This page is way off-screen to the left.
|
||||
view.alpha = 1f
|
||||
view.scaleY = 0.7f
|
||||
}
|
||||
position <= 1 -> { // [-1,1]
|
||||
// Modify the default slide transition to shrink the page as well
|
||||
val scaleFactor = max(MIN_SCALE, 1 - abs(position))
|
||||
val vertMargin = pageHeight * (1 - scaleFactor) / 2
|
||||
val horzMargin = pageWidth * (1 - scaleFactor) / 2
|
||||
if (position < 0) {
|
||||
view.translationX = horzMargin - vertMargin / 2
|
||||
} else {
|
||||
view.translationX = -horzMargin + vertMargin / 2
|
||||
}
|
||||
|
||||
// Scale the page down (between MIN_SCALE and 1)
|
||||
view.scaleX = scaleFactor
|
||||
view.scaleY = scaleFactor
|
||||
// Scale the page down (between MIN_SCALE and 1)
|
||||
view.scaleX = scaleFactor
|
||||
view.scaleY = scaleFactor
|
||||
|
||||
// Fade the page relative to its size.
|
||||
//view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
|
||||
// Fade the page relative to its size.
|
||||
//view.setAlpha(MIN_ALPHA + (scaleFactor - MIN_SCALE) / (1 - MIN_SCALE) * (1 - MIN_ALPHA));
|
||||
|
||||
} else { // (1,+Infinity]
|
||||
// This page is way off-screen to the right.
|
||||
view.alpha = 1f
|
||||
view.scaleY = 0.7f
|
||||
}
|
||||
else -> { // (1,+Infinity]
|
||||
// This page is way off-screen to the right.
|
||||
view.alpha = 1f
|
||||
view.scaleY = 0.7f
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val MIN_SCALE = 0.85f
|
||||
private val MIN_ALPHA = 0.5f
|
||||
private const val MIN_SCALE = 0.85f
|
||||
private const val MIN_ALPHA = 0.5f
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@ package code.name.monkey.retromusic.transform
|
|||
|
||||
import android.view.View
|
||||
import androidx.viewpager.widget.ViewPager
|
||||
import kotlin.math.abs
|
||||
|
||||
class VerticalFlipTransformation : ViewPager.PageTransformer {
|
||||
override fun transformPage(page: View, position: Float) {
|
||||
|
@ -30,22 +31,24 @@ class VerticalFlipTransformation : ViewPager.PageTransformer {
|
|||
}
|
||||
|
||||
|
||||
if (position < -1) { // [-Infinity,-1)
|
||||
// This page is way off-screen to the left.
|
||||
page.alpha = 0f
|
||||
|
||||
} else if (position <= 0) { // [-1,0]
|
||||
page.alpha = 1f
|
||||
page.rotationY = 180 * (1 - Math.abs(position) + 1)
|
||||
|
||||
} else if (position <= 1) { // (0,1]
|
||||
page.alpha = 1f
|
||||
page.rotationY = -180 * (1 - Math.abs(position) + 1)
|
||||
|
||||
} else { // (1,+Infinity]
|
||||
// This page is way off-screen to the right.
|
||||
page.alpha = 0f
|
||||
when {
|
||||
position < -1 -> { // [-Infinity,-1)
|
||||
// This page is way off-screen to the left.
|
||||
page.alpha = 0f
|
||||
}
|
||||
position <= 0 -> { // [-1,0]
|
||||
page.alpha = 1f
|
||||
page.rotationY = 180 * (1 - abs(position) + 1)
|
||||
}
|
||||
position <= 1 -> { // (0,1]
|
||||
page.alpha = 1f
|
||||
page.rotationY = -180 * (1 - abs(position) + 1)
|
||||
}
|
||||
else -> { // (1,+Infinity]
|
||||
// This page is way off-screen to the right.
|
||||
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.graphics.Bitmap;
|
||||
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;
|
||||
|
||||
|
@ -20,19 +15,12 @@ import code.name.monkey.retromusic.R;
|
|||
import code.name.monkey.retromusic.model.Song;
|
||||
|
||||
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(
|
||||
Context context, List<Song> songPlaylist, boolean round, boolean blur) {
|
||||
if (songPlaylist == null || songPlaylist.isEmpty()) return getDefaultBitmap(context, round);
|
||||
if (songPlaylist.size() == 1) return getBitmapWithAlbumId(context, songPlaylist.get(0).getAlbumId());
|
||||
Context context, List<Song> songPlaylist) {
|
||||
if (songPlaylist == null || songPlaylist.isEmpty()) return getDefaultBitmap(context);
|
||||
if (songPlaylist.size() == 1)
|
||||
return getBitmapWithAlbumId(context, songPlaylist.get(0).getAlbumId());
|
||||
List<Long> albumID = new ArrayList<>();
|
||||
for (Song song : songPlaylist) {
|
||||
if (!albumID.contains(song.getAlbumId())) albumID.add(song.getAlbumId());
|
||||
|
@ -40,108 +28,12 @@ public class AutoGeneratedPlaylistBitmap {
|
|||
List<Bitmap> art = new ArrayList<>();
|
||||
for (Long id : albumID) {
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
try {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -594,7 +594,7 @@ public final class BitmapEditor {
|
|||
/**
|
||||
* 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 newWidth (new desired Width)
|
||||
* @return image (new resized image)
|
||||
|
@ -609,22 +609,21 @@ public final class BitmapEditor {
|
|||
// onTap the bit map
|
||||
matrix.postScale(scaleWidth, scaleHeight);
|
||||
// recreate the new Bitmap
|
||||
Bitmap resizedBitmap = Bitmap.createBitmap(image, 0, 0, width, height, matrix, false);
|
||||
return resizedBitmap;
|
||||
return Bitmap.createBitmap(image, 0, 0, width, height, matrix, false);
|
||||
}
|
||||
|
||||
public static boolean TrueIfBitmapBigger(Bitmap bitmap, int size) {
|
||||
int sizeBitmap =
|
||||
(bitmap.getHeight() > bitmap.getWidth()) ? bitmap.getHeight() : bitmap.getWidth();
|
||||
Math.max(bitmap.getHeight(), bitmap.getWidth());
|
||||
return sizeBitmap > size;
|
||||
}
|
||||
|
||||
public static Bitmap GetRoundedBitmapWithBlurShadow(
|
||||
public static Bitmap getRoundedBitmapWithBlurShadow(
|
||||
Bitmap original, int paddingTop, int paddingBottom, int paddingLeft, int paddingRight) {
|
||||
int original_width = original.getWidth();
|
||||
int orginal_height = original.getHeight();
|
||||
int original_height = original.getHeight();
|
||||
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);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
Paint paint = new Paint();
|
||||
|
|
|
@ -25,13 +25,11 @@ import android.graphics.PorterDuff;
|
|||
import android.graphics.PorterDuffColorFilter;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.media.ExifInterface;
|
||||
import android.os.Build;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
|
@ -102,10 +100,7 @@ public class ImageUtil {
|
|||
|
||||
public static Drawable getVectorDrawable(
|
||||
@NonNull Resources res, @DrawableRes int resId, @Nullable Resources.Theme theme) {
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
return res.getDrawable(resId, theme);
|
||||
}
|
||||
return VectorDrawableCompat.create(res, resId, theme);
|
||||
return res.getDrawable(resId, theme);
|
||||
}
|
||||
|
||||
/** Makes sure that {@code mTempBuffer} has at least length {@code size}. */
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
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
|
||||
|
||||
|
||||
|
@ -75,25 +78,12 @@ internal object MergedImageUtils {
|
|||
val bit = Bitmap.createScaledBitmap(bitmap, onePartSize, onePartSize, true)
|
||||
canvas.drawBitmap(
|
||||
bit,
|
||||
(onePartSize * (i % parts)).toFloat(),
|
||||
(onePartSize * (i / parts)).toFloat(),
|
||||
(onePartSize * (i % parts)).toFloat() + (i % 3) * 50,
|
||||
(onePartSize * (i / parts)).toFloat() + (i / 3) * 50,
|
||||
paint
|
||||
)
|
||||
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
|
||||
}
|
||||
|
||||
|
|
|
@ -348,7 +348,7 @@ object MusicUtil : KoinComponent {
|
|||
val repository = get<Repository>()
|
||||
fun toggleFavorite(context: Context, song: Song) {
|
||||
GlobalScope.launch {
|
||||
val playlist: PlaylistEntity? = repository.favoritePlaylist()
|
||||
val playlist: PlaylistEntity = repository.favoritePlaylist()
|
||||
if (playlist != null) {
|
||||
val songEntity = song.toSongEntity(playlist.playListId)
|
||||
val isFavorite = repository.isFavoriteSong(songEntity).isNotEmpty()
|
||||
|
@ -529,7 +529,7 @@ object MusicUtil : KoinComponent {
|
|||
val pendingIntent = MediaStore.createDeleteRequest(activity.contentResolver, songs.map {
|
||||
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 {
|
||||
|
|
|
@ -20,12 +20,10 @@ import android.content.Intent
|
|||
import android.media.audiofx.AudioEffect
|
||||
import android.widget.Toast
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.navigation.findNavController
|
||||
import code.name.monkey.retromusic.R
|
||||
import code.name.monkey.retromusic.activities.*
|
||||
import code.name.monkey.retromusic.activities.bugreport.BugReportActivity
|
||||
import code.name.monkey.retromusic.helper.MusicPlayerRemote.audioSessionId
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior
|
||||
|
||||
object NavigationUtil {
|
||||
fun bugReport(activity: Activity) {
|
||||
|
@ -40,21 +38,6 @@ object NavigationUtil {
|
|||
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) {
|
||||
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.
|
||||
*/
|
||||
@Suppress("Deprecation")
|
||||
@SuppressLint("PackageManagerGetSignatures")
|
||||
private fun getPackageInfo(callingPackage: String): PackageInfo? =
|
||||
packageManager.getPackageInfo(callingPackage,
|
||||
|
@ -208,11 +209,11 @@ class PackageValidator(
|
|||
private fun getSignature(packageInfo: PackageInfo): String? {
|
||||
// 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.
|
||||
if (packageInfo.signatures == null || packageInfo.signatures.size != 1) {
|
||||
return null
|
||||
return if (packageInfo.signatures == null || packageInfo.signatures.size != 1) {
|
||||
null
|
||||
} else {
|
||||
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.db.PlaylistWithSongs;
|
||||
import code.name.monkey.retromusic.helper.M3UConstants;
|
||||
import code.name.monkey.retromusic.helper.M3UWriter;
|
||||
import code.name.monkey.retromusic.model.Playlist;
|
||||
import code.name.monkey.retromusic.model.PlaylistSong;
|
||||
|
@ -167,8 +166,8 @@ public class PlaylistsUtil {
|
|||
Toast.LENGTH_SHORT)
|
||||
.show();
|
||||
}
|
||||
} catch (SecurityException ignored) {
|
||||
ignored.printStackTrace();
|
||||
} catch (SecurityException exception) {
|
||||
exception.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -235,13 +234,13 @@ public class PlaylistsUtil {
|
|||
for (int i = 0; i < selectionArgs.length; i++) {
|
||||
selectionArgs[i] = String.valueOf(songs.get(i).getIdInPlayList());
|
||||
}
|
||||
String selection = MediaStore.Audio.Playlists.Members._ID + " in (";
|
||||
//noinspection unused
|
||||
for (String selectionArg : selectionArgs) selection += "?, ";
|
||||
selection = selection.substring(0, selection.length() - 2) + ")";
|
||||
StringBuilder selection = new StringBuilder(MediaStore.Audio.Playlists.Members._ID + " in (");
|
||||
|
||||
for (String selectionArg : selectionArgs) selection.append("?, ");
|
||||
selection = new StringBuilder(selection.substring(0, selection.length() - 2) + ")");
|
||||
|
||||
try {
|
||||
context.getContentResolver().delete(uri, selection, selectionArgs);
|
||||
context.getContentResolver().delete(uri, selection.toString(), selectionArgs);
|
||||
} 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.getStringOrDefault
|
||||
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.folder.FoldersFragment
|
||||
import code.name.monkey.retromusic.helper.SortOrder.*
|
||||
|
@ -344,22 +345,40 @@ object PreferenceUtil {
|
|||
putInt(LYRICS_OPTIONS, value)
|
||||
}
|
||||
|
||||
var songGridStyle
|
||||
get() = sharedPreferences.getInt(SONG_GRID_STYLE, R.layout.item_grid)
|
||||
var songGridStyle: GridStyle
|
||||
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 {
|
||||
putInt(SONG_GRID_STYLE, value)
|
||||
putInt(SONG_GRID_STYLE, value.id)
|
||||
}
|
||||
|
||||
var albumGridStyle
|
||||
get() = sharedPreferences.getInt(ALBUM_GRID_STYLE, R.layout.item_grid)
|
||||
var albumGridStyle: GridStyle
|
||||
get() {
|
||||
val id: Int = sharedPreferences.getInt(ALBUM_GRID_STYLE, 0)
|
||||
return GridStyle.values().firstOrNull { gridStyle ->
|
||||
gridStyle.id == id
|
||||
} ?: GridStyle.Grid
|
||||
}
|
||||
set(value) = sharedPreferences.edit {
|
||||
putInt(ALBUM_GRID_STYLE, value)
|
||||
putInt(ALBUM_GRID_STYLE, value.id)
|
||||
}
|
||||
|
||||
var artistGridStyle
|
||||
get() = sharedPreferences.getInt(ARTIST_GRID_STYLE, R.layout.item_grid_circle)
|
||||
var artistGridStyle: GridStyle
|
||||
get() {
|
||||
val id: Int = sharedPreferences.getInt(ARTIST_GRID_STYLE, 4)
|
||||
return GridStyle.values().firstOrNull { gridStyle ->
|
||||
gridStyle.id == id
|
||||
} ?: GridStyle.Circular
|
||||
}
|
||||
set(value) = sharedPreferences.edit {
|
||||
putInt(ARTIST_GRID_STYLE, value)
|
||||
putInt(ARTIST_GRID_STYLE, value.id)
|
||||
}
|
||||
|
||||
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
|
||||
get() {
|
||||
val id: Int = sharedPreferences.getInt(ALBUM_COVER_STYLE, 0)
|
||||
|
|
|
@ -42,7 +42,7 @@ public class RetroColorUtil {
|
|||
float[] hsv = new float[3];
|
||||
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);
|
||||
}
|
||||
|
@ -188,7 +188,7 @@ public class RetroColorUtil {
|
|||
|
||||
public static int getDominantColor(Bitmap bitmap, int defaultFooterColor) {
|
||||
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(
|
||||
swatches, (swatch1, swatch2) -> swatch2.getPopulation() - swatch1.getPopulation());
|
||||
return swatches.size() > 0 ? swatches.get(0).getRgb() : defaultFooterColor;
|
||||
|
|
|
@ -40,7 +40,7 @@ import androidx.annotation.ColorInt;
|
|||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.vectordrawable.graphics.drawable.VectorDrawableCompat;
|
||||
import androidx.core.content.res.ResourcesCompat;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.NetworkInterface;
|
||||
|
@ -127,14 +127,14 @@ public class RetroUtil {
|
|||
return result;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NonNull
|
||||
public static Drawable getTintedVectorDrawable(
|
||||
@NonNull Context context, @DrawableRes int id, @ColorInt int color) {
|
||||
return TintHelper.createTintedDrawable(
|
||||
getVectorDrawable(context.getResources(), id, context.getTheme()), color);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@NonNull
|
||||
public static Drawable getTintedVectorDrawable(
|
||||
@NonNull Resources res,
|
||||
@DrawableRes int resId,
|
||||
|
@ -146,10 +146,7 @@ public class RetroUtil {
|
|||
@Nullable
|
||||
public static Drawable getVectorDrawable(
|
||||
@NonNull Resources res, @DrawableRes int resId, @Nullable Resources.Theme theme) {
|
||||
if (Build.VERSION.SDK_INT >= 21) {
|
||||
return res.getDrawable(resId, theme);
|
||||
}
|
||||
return VectorDrawableCompat.create(res, resId, theme);
|
||||
return ResourcesCompat.getDrawable(res, resId, theme);
|
||||
}
|
||||
|
||||
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 boolean isSAFRequired(File file) {
|
||||
return Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT && !file.canWrite();
|
||||
return !file.canWrite();
|
||||
}
|
||||
|
||||
public static boolean isSAFRequired(String path) {
|
||||
|
|
|
@ -29,22 +29,22 @@ public class SwipeAndDragHelper extends ItemTouchHelper.Callback {
|
|||
}
|
||||
|
||||
@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;
|
||||
return makeMovementFlags(dragFlags, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(
|
||||
RecyclerView recyclerView,
|
||||
RecyclerView.ViewHolder viewHolder,
|
||||
RecyclerView.ViewHolder target) {
|
||||
@NonNull RecyclerView recyclerView,
|
||||
RecyclerView.ViewHolder viewHolder,
|
||||
RecyclerView.ViewHolder target) {
|
||||
contract.onViewMoved(viewHolder.getLayoutPosition(), target.getLayoutPosition());
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {}
|
||||
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {}
|
||||
|
||||
@Override
|
||||
public boolean isLongPressDragEnabled() {
|
||||
|
@ -53,13 +53,13 @@ public class SwipeAndDragHelper extends ItemTouchHelper.Callback {
|
|||
|
||||
@Override
|
||||
public void onChildDraw(
|
||||
Canvas c,
|
||||
RecyclerView recyclerView,
|
||||
RecyclerView.ViewHolder viewHolder,
|
||||
float dX,
|
||||
float dY,
|
||||
int actionState,
|
||||
boolean isCurrentlyActive) {
|
||||
@NonNull Canvas c,
|
||||
@NonNull RecyclerView recyclerView,
|
||||
@NonNull RecyclerView.ViewHolder viewHolder,
|
||||
float dX,
|
||||
float dY,
|
||||
int actionState,
|
||||
boolean isCurrentlyActive) {
|
||||
if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
|
||||
float alpha = 1 - (Math.abs(dX) / recyclerView.getWidth());
|
||||
viewHolder.itemView.setAlpha(alpha);
|
||||
|
|
|
@ -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 {
|
||||
val tx = (v.translationX + 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 String TAG = "ColorPicking";
|
||||
private float[] mFilteredBackgroundHsl = null;
|
||||
private final Palette.Filter mBlackWhiteFilter =
|
||||
(rgb, hsl) -> !isWhiteOrBlack(hsl);
|
||||
private boolean mIsLowPriority;
|
||||
private int backgroundColor;
|
||||
private int secondaryTextColor;
|
||||
private int primaryTextColor;
|
||||
|
@ -376,10 +374,6 @@ public class MediaNotificationProcessor {
|
|||
return hslColor[2] >= WHITE_MIN_LIGHTNESS;
|
||||
}
|
||||
|
||||
public void setIsLowPriority(boolean isLowPriority) {
|
||||
mIsLowPriority = isLowPriority;
|
||||
}
|
||||
|
||||
private void ensureColors(int backgroundColor, int mForegroundColor) {
|
||||
{
|
||||
double backLum = NotificationColorUtil.calculateLuminance(backgroundColor);
|
||||
|
|
|
@ -55,7 +55,7 @@ public class NotificationColorUtil {
|
|||
|
||||
private final ImageUtils mImageUtils = new ImageUtils();
|
||||
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)
|
||||
|
||||
|
@ -353,11 +353,7 @@ public class NotificationColorUtil {
|
|||
|
||||
public static int resolvePrimaryColor(Context context, int backgroundColor) {
|
||||
boolean useDark = shouldUseDark(backgroundColor);
|
||||
if (useDark) {
|
||||
return ContextCompat.getColor(context, android.R.color.primary_text_light);
|
||||
} else {
|
||||
return ContextCompat.getColor(context, android.R.color.primary_text_light);
|
||||
}
|
||||
return ContextCompat.getColor(context, android.R.color.primary_text_light);
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
return amount < low ? low : (amount > high ? high : amount);
|
||||
return amount < low ? low : (Math.min(amount, high));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Crumb{" + "file=" + file + ", scrollPos=" + scrollPos + '}';
|
||||
|
|
|
@ -209,10 +209,8 @@ public class CircularImageView extends AppCompatImageView {
|
|||
private void drawShadow(float shadowRadius, int shadowColor) {
|
||||
this.shadowRadius = shadowRadius;
|
||||
this.shadowColor = shadowColor;
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
|
||||
setLayerType(LAYER_TYPE_SOFTWARE, paintBorder);
|
||||
}
|
||||
paintBorder.setShadowLayer(shadowRadius, 0.0f, shadowRadius / 2, shadowColor);
|
||||
paintBorder.setShadowLayer(shadowRadius, 0.0f, shadowRadius / 2, shadowColor);
|
||||
}
|
||||
|
||||
private void updateShader() {
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue